An open API service indexing awesome lists of open source software.

https://github.com/yelbolt/unoff-ui

Unoff UI is a comprehensive library of UI components designed specifically for building Figma, Penpot, Sketch and Framer plugins.
https://github.com/yelbolt/unoff-ui

figma-plugin framer-plugin penpot-plugin sketch-plugin ui-components

Last synced: 3 months ago
JSON representation

Unoff UI is a comprehensive library of UI components designed specifically for building Figma, Penpot, Sketch and Framer plugins.

Awesome Lists containing this project

README

          

![GitHub package.json version](https://img.shields.io/github/package-json/v/yelbolt/unoff-ui?color=informational) ![GitHub last commit](https://img.shields.io/github/last-commit/yelbolt/unoff-ui?color=informational) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/yelbolt/unoff-ui/npm.yml?label=npm) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/yelbolt/unoff-ui/chromatic.yml?label=Chromatic) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/yelbolt/unoff-ui/deploy.yml?label=Deployment)
![GitHub](https://img.shields.io/github/license/yelbolt/unoff-ui?color=informational)

# Unoff UI

Unoff UI is a comprehensive library of UI components designed specifically for building Figma, Penpot, and Sketch plugins. It leverages modern tools and frameworks to ensure a seamless development experience.

image

## Features

- **Built with React**: A popular JavaScript library for building user interfaces
- **Bundled with Vite**: Fast and optimized build tool for modern web projects
- **Tested with Vitest**: Ensures reliability and robustness of components with interaction tests
- **Exposed with Storybook**: Interactive UI component explorer for easy development and testing
- **Design tokens with Terrazzo**: Theme management using design tokens for consistent styling across platforms. [View Terrazzo Guide](./docs/terrazzo-guide.md)
- **Theme Generator**: Create custom themes easily with the [Theme Generator](./docs/theme-generator.md) tool based on Figma theme structure
- **SCSS Builder**: Generate theme-specific SCSS files from tokens using the build-scss script, with support for building components across all themes
- **Interaction Testing**: Automated interaction tests for all components using Storybook play functions.

## Installation

To install Unoff UI, use npm or yarn:

```bash
npm install @unoff/ui
# or
yarn add @unoff/ui
```

## Testing

Unoff UI comes with comprehensive interaction tests for all components:

```bash
# Run only Storybook interaction tests
npm run test:storybook
```

Tests can also be run directly in Storybook UI:

1. Start Storybook: `npm run storybook`
2. Open the Tests panel in the sidebar
3. Click "Run all" to execute all interaction tests

## Theme Development Tools

Unoff UI provides powerful tools for creating and managing custom themes:

### Theme Generator

Create new themes based on existing design systems (Sketch, Figma UI, etc.) with a single command:

```bash
npm run create:theme
```

The Theme Generator automates the creation of all necessary files and configurations:

- Tokens JSON files
- Terrazzo configuration
- Storybook integration
- SCSS imports

[Learn more about the Theme Generator](./docs/theme-generator.md)

### SCSS Builder

Generate theme-specific SCSS files from design tokens with these commands:

```bash
# List available themes and components
npm run scss:list

# Build all SCSS files
npm run scss:build

# Build SCSS for a specific theme
npm run scss:build theme=themeName

# Build SCSS for a specific component across all themes
npm run scss:build component=componentName

# Build SCSS for a specific component within a specific theme
npm run scss:build theme=themeName component=componentName

# Build specific token types across all themes
npm run scss:build text
npm run scss:build color
npm run scss:build icon
npm run scss:build type

# Build specific token types for a specific theme
npm run scss:build theme=themeName text
npm run scss:build theme=themeName color
```

## Usage

### Slots

#### Bar

```tsx
import { Bar } from '@unoff/ui'

function App() {
return (
Left very long text that may be truncated}
rightPartSlot={

Right very long text that may be truncated
}
truncate={['LEFT', 'RIGHT']}
padding="12px"
/>
)
}
```

#### Form Item

```tsx
import { FormItem } from '@unoff/ui'
import { Input } from '@unoff/ui'

function App() {
return (



)
}
```

#### Section

```tsx
import { Section } from '@unoff/ui'

function App() {
return (

Section content goes here


)
}
```

#### Drawer

```tsx
import { Drawer } from '@unoff/ui'

function App() {
return (
console.log('Drawer closed')}
>

Drawer content goes here


)
}
```

### Actions

#### Primary Button

```tsx
import { Button } from '@unoff/ui'

function App() {
return (
console.log('Primary button clicked')}
/>
)
}
```

#### Secondary Button

```tsx
import { Button } from '@unoff/ui'

function App() {
return (
console.log('Secondary button clicked')}
/>
)
}
```

#### Tertiary Button

```tsx
import { Button } from '@unoff/ui'

function App() {
return (
console.log('Tertiary button clicked')}
/>
)
}
```

#### Destructive Button

```tsx
import { Button } from '@unoff/ui'

function App() {
return (
console.log('Destructive button clicked')}
/>
)
}
```

#### Icon Button

```tsx
import { Button } from '@unoff/ui'

function App() {
return (
console.log('Icon button clicked')}
/>
)
}
```

#### Segmented Control

```tsx
import { SegmentedControl } from '@unoff/ui'

function App() {
return (
console.log(e.currentTarget.dataset.feature)}
/>
)
}
```

### Inputs

#### Short Text Input

```tsx
import { Input } from '@unoff/ui'

function App() {
return (
console.log(e.target.value)}
/>
)
}
```

#### Long Text Input

```tsx
import { Input } from '@unoff/ui'

function App() {
return (
console.log(e.target.value)}
/>
)
}
```

#### Color Picker

```tsx
import { Input } from '@unoff/ui'

function App() {
return (
console.log(e.target.value)}
/>
)
}
```

#### Numeric Stepper

```tsx
import { Input } from '@unoff/ui'

function App() {
return (
console.log(e.target.value)}
/>
)
}
```

### Dropdown

#### Single Selection

```tsx
import { Dropdown } from '@unoff/ui'

function App() {
return (
console.log(value)}
/>
)
}
```

#### Multiple Selection

```tsx
import { Dropdown } from '@unoff/ui'

function App() {
return (
console.log(values)}
/>
)
}
```

### Sliders

#### Simple Slider

```tsx
import { SimpleSlider } from '@unoff/ui'

function App() {
return (
console.log(value)}
/>
)
}
```

#### Multiple Slider

```tsx
import { MultipleSlider } from '@unoff/ui'

function App() {
return (
console.log(value)}
/>
)
}
```

### Dialogs

#### Simple Dialog

```tsx
import { Dialog } from '@unoff/ui'

function App() {
return (
console.log('Delete action'),
},
secondary: {
label: 'Cancel',
action: () => console.log('Cancel action'),
},
}}
pin="CENTER"
onClose={() => console.log('Dialog closed')}
>


Deleting this item will remove it permanently.




)
}
```

#### Form Dialog

```tsx
import { Dialog } from '@unoff/ui'
import { Input } from '@unoff/ui'
import { FormItem } from '@unoff/ui'

function App() {
return (
console.log('Submit action'),
},
}}
pin="CENTER"
onClose={() => console.log('Dialog closed')}
>



















)
}
```

#### Loading Dialog

```tsx
import { Dialog } from '@unoff/ui'

function App() {
return (
console.log('Dialog closed')}
/>
)
}
```

### Lists

#### Simple List

```tsx
import { ActionsList } from '@unoff/ui'

function App() {
return (
console.log('Option 1 clicked'),
},
{
label: 'Option 2',
value: 'OPTION_2',
type: 'OPTION',
action: () => console.log('Option 2 clicked'),
},
{
label: 'Option 3',
value: 'OPTION_3',
type: 'OPTION',
action: () => console.log('Option 3 clicked'),
},
{
label: 'Option 4',
value: 'OPTION_4',
type: 'OPTION',
action: () => console.log('Option 4 clicked'),
},
]}
selected="OPTION_1"
/>
)
}
```

#### Grouped List

```tsx
import { ActionsList } from '@unoff/ui'

function App() {
return (
console.log('Option 1 clicked'),
},
{
label: 'Option 2',
value: 'OPTION_2',
type: 'OPTION',
action: () => console.log('Option 2 clicked'),
},
{
type: 'SEPARATOR',
},
{
label: 'Group 2',
type: 'TITLE',
},
{
label: 'Option 3',
value: 'OPTION_3',
type: 'OPTION',
action: () => console.log('Option 3 clicked'),
},
{
label: 'Option 4',
value: 'OPTION_4',
type: 'OPTION',
action: () => console.log('Option 4 clicked'),
},
]}
/>
)
}
```

#### Nested List

```tsx
import { ActionsList } from '@unoff/ui'

function App() {
return (
console.log('Option A.1 clicked'),
},
{
label: 'Option 2',
value: 'OPTION_A_2',
type: 'OPTION',
action: () => console.log('Option A.2 clicked'),
},
],
},
{
label: 'Group 2',
value: 'GROUP_2',
type: 'OPTION',
children: [
{
label: 'Option 1',
value: 'OPTION_B_1',
type: 'OPTION',
action: () => console.log('Option B.1 clicked'),
},
{
label: 'Option 2',
value: 'OPTION_B_2',
type: 'OPTION',
action: () => console.log('Option B.2 clicked'),
},
],
},
]}
/>
)
}
```

### Tags

#### Basic Chip

```tsx
import { Chip } from '@unoff/ui'

function App() {
return New
}
```

#### Chip with Color Indicator

```tsx
import { Chip, ColorChip } from '@unoff/ui'

function App() {
return (

}
rightSlot={

✔︎
}
>
AA

)
}
```

### Assets

#### Icon

```tsx
import { Icon } from '@unoff/ui'

function App() {
return (
<>
{/* Pictogram Icon */}

{/* Letter Icon */}

>
)
}
```

#### Avatar

```tsx
import { Avatar } from '@unoff/ui'

function App() {
return (
<>
{/* Avatar with Image */}

{/* Default Avatar */}

>
)
}
```

#### Thumbnail

```tsx
import { Thumbnail } from '@unoff/ui'

function App() {
return (

)
}
```

## Testing

To run tests:

```bash
npm test
# or
yarn test
```

## License

This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more information.