@zvoove/unity-ui 2.22.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -76
- package/bin/cli.mjs +49 -0
- package/bin/commands/config.mjs +68 -0
- package/bin/commands/create.mjs +163 -0
- package/bin/commands/init.mjs +158 -0
- package/bin/commands/rules.mjs +100 -0
- package/bin/commands/skills.mjs +1883 -0
- package/bin/generate-skills.mjs +19 -1903
- package/bin/templates/component.tsx +15 -0
- package/bin/templates/doc.mdx +36 -0
- package/bin/templates/index.ts +2 -0
- package/bin/templates/stories.tsx +15 -0
- package/bin/templates/styled.ts +14 -0
- package/bin/templates/test.tsx +30 -0
- package/bin/templates/types.ts +13 -0
- package/dist/llms.txt +151 -43
- package/dist/theme.css +46 -0
- package/dist/unity-ui.cjs.js +1 -1
- package/dist/unity-ui.css +1 -1
- package/dist/unity-ui.d.ts +575 -24
- package/dist/unity-ui.es.js +762 -389
- package/package.json +9 -6
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { __STYLES__FUNCTION__Styles } from './__COMPONENT_NAME__.styled';
|
|
2
|
+
import { __COMPONENT_NAME__Props } from './__COMPONENT_NAME__.types';
|
|
3
|
+
|
|
4
|
+
const __COMPONENT_NAME__ = ({
|
|
5
|
+
children,
|
|
6
|
+
variant = 'primary',
|
|
7
|
+
}: __COMPONENT_NAME__Props) => {
|
|
8
|
+
return (
|
|
9
|
+
<div className={__STYLES__FUNCTION__Styles({ variant })}>{children}</div>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
__COMPONENT_NAME__.displayName = '__COMPONENT_NAME__';
|
|
14
|
+
|
|
15
|
+
export default __COMPONENT_NAME__;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Canvas, Controls, Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
import { __COMPONENT_NAME__ } from '.';
|
|
4
|
+
import * as __COMPONENT_NAME__Stories from './__COMPONENT_NAME__.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={__COMPONENT_NAME__Stories} />
|
|
7
|
+
|
|
8
|
+
# **COMPONENT_NAME**
|
|
9
|
+
|
|
10
|
+
The `__COMPONENT_NAME__` component is a auto generated component using the `npm run create <componentName>` script.
|
|
11
|
+
|
|
12
|
+
<Canvas sourceState="none" of={__COMPONENT_NAME__Stories.Default} />
|
|
13
|
+
|
|
14
|
+
<Controls of={__COMPONENT_NAME__Stories.Default} />
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```jsx
|
|
19
|
+
import { __COMPONENT_NAME__ } from '@zvoove/unity-ui';
|
|
20
|
+
|
|
21
|
+
<__COMPONENT_NAME__ />;
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Variants
|
|
25
|
+
|
|
26
|
+
### Default
|
|
27
|
+
|
|
28
|
+
The default `__COMPONENT_NAME__` component has the following features:
|
|
29
|
+
|
|
30
|
+
<Canvas sourceState="none" of={__COMPONENT_NAME__Stories.Default} />
|
|
31
|
+
|
|
32
|
+
```jsx
|
|
33
|
+
import { __COMPONENT_NAME__ } from '@zvoove/unity-ui';
|
|
34
|
+
|
|
35
|
+
<__COMPONENT_NAME__ />;
|
|
36
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
|
|
3
|
+
import __COMPONENT_NAME__ from './__COMPONENT_NAME__';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof __COMPONENT_NAME__> = {
|
|
6
|
+
title: 'Components/__COMPONENT_NAME__',
|
|
7
|
+
component: __COMPONENT_NAME__,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof __COMPONENT_NAME__>;
|
|
12
|
+
|
|
13
|
+
export const Default: Story = {
|
|
14
|
+
args: { children: 'Auto created component' },
|
|
15
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { tv } from '@libs';
|
|
2
|
+
|
|
3
|
+
export const __STYLES__FUNCTION__Styles = tv({
|
|
4
|
+
base: ['text-body-medium'],
|
|
5
|
+
variants: {
|
|
6
|
+
variant: {
|
|
7
|
+
primary: ['bg-primary', 'text-on-primary'],
|
|
8
|
+
secondary: ['bg-secondary', 'text-on-secondary'],
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
defaultVariants: {
|
|
12
|
+
variant: 'primary',
|
|
13
|
+
},
|
|
14
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
|
|
3
|
+
import __COMPONENT_NAME__ from './__COMPONENT_NAME__';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
|
|
6
|
+
describe('__COMPONENT_NAME__', () => {
|
|
7
|
+
it('renders children correctly', () => {
|
|
8
|
+
render(
|
|
9
|
+
<__COMPONENT_NAME__>
|
|
10
|
+
<div>Test Child</div>
|
|
11
|
+
</__COMPONENT_NAME__>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
expect(screen.getByText('Test Child')).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('applies the correct variant class', () => {
|
|
18
|
+
render(<__COMPONENT_NAME__ variant="secondary">Test</__COMPONENT_NAME__>);
|
|
19
|
+
const __COMPONENT_NAME__Element = screen.getByText('Test');
|
|
20
|
+
|
|
21
|
+
expect(__COMPONENT_NAME__Element).toHaveClass('bg-secondary'); // Assuming the class name matches the variant
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('uses the default variant when none is provided', () => {
|
|
25
|
+
render(<__COMPONENT_NAME__>Default Variant</__COMPONENT_NAME__>);
|
|
26
|
+
const __COMPONENT_NAME__Element = screen.getByText('Default Variant');
|
|
27
|
+
|
|
28
|
+
expect(__COMPONENT_NAME__Element).toHaveClass('bg-primary'); // Assuming 'primary' is the default class
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface __COMPONENT_NAME__Props {
|
|
4
|
+
/**
|
|
5
|
+
* The children of the __COMPONENT_NAME__.
|
|
6
|
+
*/
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The variant of the __COMPONENT_NAME__
|
|
11
|
+
*/
|
|
12
|
+
variant?: 'primary' | 'secondary';
|
|
13
|
+
}
|
package/dist/llms.txt
CHANGED
|
@@ -21,10 +21,7 @@ Import components:
|
|
|
21
21
|
import { Button, Card, TextField, Typography } from '@zvoove/unity-ui';
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Font
|
|
25
|
-
```html
|
|
26
|
-
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap" rel="stylesheet" />
|
|
27
|
-
```
|
|
24
|
+
Font: Source Sans 3 is bundled via `@font-face` in `theme.css` — no extra setup needed.
|
|
28
25
|
|
|
29
26
|
Dark mode: add `data-theme="dark"` to a parent element.
|
|
30
27
|
|
|
@@ -196,7 +193,10 @@ Horizontal separator line.
|
|
|
196
193
|
```tsx
|
|
197
194
|
import { Divider } from '@zvoove/unity-ui';
|
|
198
195
|
|
|
199
|
-
<Divider
|
|
196
|
+
<Divider
|
|
197
|
+
variant="fullWidth" // 'fullWidth' | 'inset' | 'middle'
|
|
198
|
+
color="outline-variant" // BackgroundColors — any design token name (default: 'outline-variant')
|
|
199
|
+
/>
|
|
200
200
|
```
|
|
201
201
|
|
|
202
202
|
### Expandable
|
|
@@ -548,15 +548,25 @@ import { SegmentGroup, SegmentButton } from '@zvoove/unity-ui';
|
|
|
548
548
|
### PopUpMenu
|
|
549
549
|
Context menu / dropdown menu.
|
|
550
550
|
```tsx
|
|
551
|
-
import { PopUpMenu } from '@zvoove/unity-ui';
|
|
551
|
+
import { PopUpMenu, type PopUpMenuItem } from '@zvoove/unity-ui';
|
|
552
|
+
|
|
553
|
+
const items: PopUpMenuItem[] = [
|
|
554
|
+
{ id: '1', label: 'Edit', icon: 'edit' },
|
|
555
|
+
{ id: '2', label: 'Delete', icon: 'delete' },
|
|
556
|
+
{ id: 'divider', label: '', isDivider: true, dividerProps: { variant: 'middle' } },
|
|
557
|
+
// Custom non-interactive content (e.g. user header)
|
|
558
|
+
{ id: 'header', label: '', customContent: <MyCustomHeader /> },
|
|
559
|
+
// Item that stays open on click (e.g. theme toggle)
|
|
560
|
+
{ id: 'theme', label: 'Dark Mode', icon: 'dark-mode', keepOpen: true, onClick: toggleTheme },
|
|
561
|
+
// Sub-menu items (opens nested menu on hover)
|
|
562
|
+
{ id: 'language', label: 'Sprache', icon: 'translate', subMenuItems: [
|
|
563
|
+
{ id: 'de', label: 'Deutsch' },
|
|
564
|
+
{ id: 'en', label: 'English' },
|
|
565
|
+
]},
|
|
566
|
+
];
|
|
552
567
|
|
|
553
568
|
<PopUpMenu
|
|
554
|
-
items={
|
|
555
|
-
{ id: '1', label: 'Edit', icon: 'Pencil' },
|
|
556
|
-
{ id: '2', label: 'Delete', icon: 'Trash', variant: 'error' },
|
|
557
|
-
{ id: 'divider', isDivider: true },
|
|
558
|
-
{ id: '3', label: 'Settings' },
|
|
559
|
-
]}
|
|
569
|
+
items={items} // PopUpMenuItem[] (required)
|
|
560
570
|
trigger="click" // 'hover' | 'click' | 'right-click' (default: 'click')
|
|
561
571
|
placement="bottom-left" // PopUpMenuPlacement (default: 'bottom-left')
|
|
562
572
|
selectable="none" // 'single' | 'multiple' | 'none' (default: 'none')
|
|
@@ -564,13 +574,20 @@ import { PopUpMenu } from '@zvoove/unity-ui';
|
|
|
564
574
|
onItemClick={handleClick} // (item, selectedItem?) => void
|
|
565
575
|
density="default" // 'default' | '-2' | '-4'
|
|
566
576
|
showSearch={false} // boolean
|
|
567
|
-
searchPlaceholder="
|
|
577
|
+
searchPlaceholder="Suchen" // string
|
|
568
578
|
disabled={false} // boolean
|
|
579
|
+
height, minHeight, maxHeight // ResponsiveType<number | string> — control popup size
|
|
569
580
|
>
|
|
570
|
-
<Button>
|
|
581
|
+
<Button>Aktionen</Button>
|
|
571
582
|
</PopUpMenu>
|
|
572
583
|
```
|
|
573
584
|
|
|
585
|
+
PopUpMenuItem special props:
|
|
586
|
+
- `customContent?: ReactNode` — non-interactive custom content (no hover effect)
|
|
587
|
+
- `keepOpen?: boolean` — don't close menu on click
|
|
588
|
+
- `subMenuItems?: PopUpMenuItem[]` — nested sub-menu on hover
|
|
589
|
+
- `dividerProps?: DividerProps` — pass props to Divider when `isDivider: true`
|
|
590
|
+
|
|
574
591
|
---
|
|
575
592
|
|
|
576
593
|
## DATA DISPLAY COMPONENTS
|
|
@@ -641,19 +658,22 @@ import { Chip } from '@zvoove/unity-ui';
|
|
|
641
658
|
```
|
|
642
659
|
|
|
643
660
|
### Avatar & AvatarGroup
|
|
644
|
-
User avatar display.
|
|
661
|
+
User avatar display. When `image` is provided and `type` is omitted, type is automatically inferred as `'image'`.
|
|
645
662
|
```tsx
|
|
646
663
|
import { Avatar, AvatarGroup } from '@zvoove/unity-ui';
|
|
647
664
|
|
|
648
665
|
<Avatar
|
|
649
666
|
size="large" // ResponsiveType<'small' | 'medium' | 'large'>
|
|
650
|
-
type="initials" // 'initials' | 'check' | 'avatar' | 'image'
|
|
651
|
-
name="
|
|
652
|
-
image="/path/to/photo.jpg" // string
|
|
667
|
+
type="initials" // 'initials' | 'check' | 'avatar' | 'image' | 'zvoove' — auto-inferred as 'image' when image prop is set
|
|
668
|
+
name="Max Mustermann" // string
|
|
669
|
+
image="/path/to/photo.jpg" // string — when set, type defaults to 'image'
|
|
653
670
|
initialsAmount={2} // 1 | 2
|
|
654
671
|
variant="round" // 'round' | 'square'
|
|
655
672
|
/>
|
|
656
673
|
|
|
674
|
+
// Image avatar — type is inferred, no need to set type="image"
|
|
675
|
+
<Avatar image="https://example.com/avatar.jpg" name="Max Mustermann" />
|
|
676
|
+
|
|
657
677
|
<AvatarGroup maxLength={3} total={10}>
|
|
658
678
|
<Avatar name="Alice" type="initials" />
|
|
659
679
|
<Avatar name="Bob" type="initials" />
|
|
@@ -754,7 +774,7 @@ import { Tabs } from '@zvoove/unity-ui';
|
|
|
754
774
|
```
|
|
755
775
|
|
|
756
776
|
### Breadcrumbs
|
|
757
|
-
Navigation breadcrumb trail.
|
|
777
|
+
Navigation breadcrumb trail. First item renders as an icon (customizable via `homeIcon`).
|
|
758
778
|
```tsx
|
|
759
779
|
import { Breadcrumbs } from '@zvoove/unity-ui';
|
|
760
780
|
|
|
@@ -764,28 +784,76 @@ import { Breadcrumbs } from '@zvoove/unity-ui';
|
|
|
764
784
|
{ label: 'Products', href: '/products' },
|
|
765
785
|
{ label: 'Details' },
|
|
766
786
|
]}
|
|
787
|
+
homeIcon="home" // CommonIconNames (default: 'home') — icon for the first breadcrumb
|
|
767
788
|
linkComponent={Link} // React.ElementType
|
|
768
789
|
/>
|
|
769
790
|
```
|
|
770
791
|
|
|
771
792
|
### SideNavigation
|
|
772
|
-
Collapsible sidebar navigation.
|
|
793
|
+
Collapsible sidebar navigation with user area and mid-sections.
|
|
773
794
|
```tsx
|
|
774
|
-
import { SideNavigation } from '@zvoove/unity-ui';
|
|
795
|
+
import { SideNavigation, type MidSection } from '@zvoove/unity-ui';
|
|
775
796
|
|
|
776
797
|
<SideNavigation
|
|
777
|
-
menuItems={[ //
|
|
778
|
-
{ id: 'home', label: '
|
|
779
|
-
{ id: 'users', label: '
|
|
798
|
+
menuItems={[ // ListMenuItem[] (required)
|
|
799
|
+
{ id: 'home', label: 'Startseite', icon: 'home', href: '/' },
|
|
800
|
+
{ id: 'users', label: 'Personal', icon: 'users', href: '/users' },
|
|
801
|
+
]}
|
|
802
|
+
utilityItems={[ // ListMenuItem[]
|
|
803
|
+
{ id: 'settings', label: 'Einstellungen', icon: 'settings', href: '/settings' },
|
|
780
804
|
]}
|
|
781
|
-
|
|
782
|
-
{
|
|
805
|
+
midSections={[ // MidSection[] — sections between menu and utility items
|
|
806
|
+
{
|
|
807
|
+
title: 'ANGEPINNT',
|
|
808
|
+
replaceWithIconOnClose: 'pin', // collapses to icon when closed, hover shows PopUpMenu
|
|
809
|
+
items: [{ id: 'p1', label: 'Pinned item', href: '#' }],
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
title: 'HEUTE',
|
|
813
|
+
hideOnMenuClosed: true, // fully hidden when menu closed
|
|
814
|
+
items: [{ id: 't1', label: 'Today item', href: '#' }],
|
|
815
|
+
},
|
|
783
816
|
]}
|
|
817
|
+
userArea={{ // UserAreaProps — user info at the bottom
|
|
818
|
+
name: 'Max Mustermann',
|
|
819
|
+
subtitle: 'Company Name',
|
|
820
|
+
avatar: { image: '/avatar.jpg' },
|
|
821
|
+
menuItems: [/* PopUpMenuItem[] */],
|
|
822
|
+
menuMaxHeight: '80dvh', // ResponsiveType<number | string> (default: '80dvh')
|
|
823
|
+
}}
|
|
824
|
+
logo={{ // { icon?: ReactNode; name?: ReactNode } — compact only, defaults to zvoove brand
|
|
825
|
+
icon: <MyIcon />, // shown when collapsed
|
|
826
|
+
name: <MyWordmark />, // shown when expanded (fades in/out)
|
|
827
|
+
}}
|
|
828
|
+
hideUserAreaInMobile={true} // boolean (default: true) — hides user area on mobile
|
|
784
829
|
activeItem="home" // string
|
|
830
|
+
variant="default" // 'default' | 'compact'
|
|
785
831
|
open={true} // boolean
|
|
786
832
|
onToggleOpen={handleToggle} // (open: boolean) => void
|
|
787
|
-
onItemClick={handleClick} // (item:
|
|
833
|
+
onItemClick={handleClick} // (item: ListMenuItem) => void
|
|
834
|
+
linkComponent={Link} // React.ElementType
|
|
835
|
+
/>
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
### ListMenu
|
|
839
|
+
Standalone vertical menu with icon + label items. Used internally by SideNavigation, available standalone.
|
|
840
|
+
```tsx
|
|
841
|
+
import { ListMenu, type ListMenuItem } from '@zvoove/unity-ui';
|
|
842
|
+
|
|
843
|
+
<ListMenu
|
|
844
|
+
items={[ // ListMenuItem[] (required) — icon is optional
|
|
845
|
+
{ id: 'home', label: 'Startseite', icon: 'home', href: '/' },
|
|
846
|
+
{ id: 'chat', label: 'Chat title', href: '#',
|
|
847
|
+
endContent: <Icon name="pin" size="xs" />, // extra content on the right
|
|
848
|
+
endContentVisibility: 'hover', // 'always' (default) | 'hover'
|
|
849
|
+
},
|
|
850
|
+
{ id: 'spacer', label: '', isSpacer: true }, // renders a 16px vertical spacer
|
|
851
|
+
]}
|
|
852
|
+
activeItem="home" // string
|
|
853
|
+
open={true} // boolean — shows/hides labels with animation
|
|
854
|
+
variant="default" // 'default' | 'compact'
|
|
788
855
|
linkComponent={Link} // React.ElementType
|
|
856
|
+
onItemClick={handleClick} // (item: ListMenuItem) => void
|
|
789
857
|
/>
|
|
790
858
|
```
|
|
791
859
|
|
|
@@ -1106,6 +1174,7 @@ All tokens from `theme.css` are available as Tailwind utilities. Use **semantic*
|
|
|
1106
1174
|
| `--color-on-surface-variant` | `text-on-surface-variant` | Secondary/muted text |
|
|
1107
1175
|
| `--color-outline` | `border-outline` | Default borders |
|
|
1108
1176
|
| `--color-outline-variant` | `border-outline-variant` | Subtle dividers |
|
|
1177
|
+
| `--color-outline-variant-low` | `border-outline-variant-low` | Very subtle dividers/borders |
|
|
1109
1178
|
| `--color-error` | `bg-error` / `text-error` | Error states |
|
|
1110
1179
|
| `--color-background` | `bg-background` | Page background |
|
|
1111
1180
|
|
|
@@ -1132,8 +1201,10 @@ Dark mode shadows: `dark:shadow-elevation1-dark` (replace `elevation1` with the
|
|
|
1132
1201
|
|
|
1133
1202
|
Use `tailwind-variants` when a custom UI element has multiple visual variants.
|
|
1134
1203
|
|
|
1135
|
-
Configure `tv`
|
|
1204
|
+
Configure `tv` once in a shared config file (e.g. `lib/tv.ts`) and import it everywhere — do **not** repeat `createTV` in each styled file:
|
|
1205
|
+
|
|
1136
1206
|
```ts
|
|
1207
|
+
// lib/tv.ts (create once, import everywhere)
|
|
1137
1208
|
import { createTV } from 'tailwind-variants';
|
|
1138
1209
|
|
|
1139
1210
|
export const tv = createTV({
|
|
@@ -1146,7 +1217,12 @@ export const tv = createTV({
|
|
|
1146
1217
|
});
|
|
1147
1218
|
```
|
|
1148
1219
|
|
|
1149
|
-
|
|
1220
|
+
Then in styled files:
|
|
1221
|
+
```ts
|
|
1222
|
+
import { tv } from '@/lib/tv'; // import from shared config, NOT from 'tailwind-variants'
|
|
1223
|
+
```
|
|
1224
|
+
|
|
1225
|
+
Basic usage (single element):
|
|
1150
1226
|
```ts
|
|
1151
1227
|
const badge = tv({
|
|
1152
1228
|
base: ['inline-flex', 'items-center', 'rounded-full', 'px-sm', 'py-xs2', 'text-label-small'],
|
|
@@ -1164,6 +1240,39 @@ const badge = tv({
|
|
|
1164
1240
|
<div className={badge({ tone: 'primary' })}>Label</div>
|
|
1165
1241
|
```
|
|
1166
1242
|
|
|
1243
|
+
Slots (multi-element components — use when a component has distinct styled sub-parts):
|
|
1244
|
+
```ts
|
|
1245
|
+
const card = tv({
|
|
1246
|
+
slots: {
|
|
1247
|
+
base: ['rounded-md', 'bg-surface', 'shadow-elevation1'],
|
|
1248
|
+
header: ['px-md', 'py-sm', 'border-b', 'border-outline-variant'],
|
|
1249
|
+
body: ['p-md'],
|
|
1250
|
+
footer: ['px-md', 'py-sm', 'flex', 'justify-end', 'gap-sm'],
|
|
1251
|
+
},
|
|
1252
|
+
variants: {
|
|
1253
|
+
variant: {
|
|
1254
|
+
outlined: { base: ['border', 'border-outline-variant', 'shadow-none'] },
|
|
1255
|
+
elevated: { base: ['shadow-elevation2'] },
|
|
1256
|
+
},
|
|
1257
|
+
compact: {
|
|
1258
|
+
true: { body: ['p-sm'], header: ['px-sm', 'py-xs'] },
|
|
1259
|
+
},
|
|
1260
|
+
},
|
|
1261
|
+
defaultVariants: { variant: 'outlined' },
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
// Apply — destructure slots from the result:
|
|
1265
|
+
const { base, header, body, footer } = card({ variant: 'elevated', compact: true });
|
|
1266
|
+
|
|
1267
|
+
<div className={base()}>
|
|
1268
|
+
<div className={header()}>Title</div>
|
|
1269
|
+
<div className={body()}>Content</div>
|
|
1270
|
+
<div className={footer()}>
|
|
1271
|
+
<Button>Save</Button>
|
|
1272
|
+
</div>
|
|
1273
|
+
</div>
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1167
1276
|
### Class Merging
|
|
1168
1277
|
|
|
1169
1278
|
Use `tailwind-merge` for ad-hoc merging (e.g. accepting a `className` prop):
|
|
@@ -1226,17 +1335,7 @@ Rules:
|
|
|
1226
1335
|
### `MyComponent.styled.ts`
|
|
1227
1336
|
|
|
1228
1337
|
```ts
|
|
1229
|
-
import {
|
|
1230
|
-
|
|
1231
|
-
// Configure tv with Unity UI spacing/radius tokens for correct class merging
|
|
1232
|
-
const tv = createTV({
|
|
1233
|
-
twMergeConfig: {
|
|
1234
|
-
theme: {
|
|
1235
|
-
spacing: ['none', 'xs2', 'xs', 'sm', 'md', 'lg', 'xl', 'xl2', 'xl3', 'xl4', 'xl5', 'xl6', 'xl7'],
|
|
1236
|
-
borderRadius: ['none', 'xs', 'sm', 'md', 'lg', 'xl', 'full'],
|
|
1237
|
-
},
|
|
1238
|
-
},
|
|
1239
|
-
});
|
|
1338
|
+
import { tv } from '@/lib/tv'; // shared tv config — do NOT use createTV here
|
|
1240
1339
|
|
|
1241
1340
|
export const myComponentStyles = tv({
|
|
1242
1341
|
base: ['text-body-medium', 'rounded-sm'],
|
|
@@ -1252,8 +1351,6 @@ export const myComponentStyles = tv({
|
|
|
1252
1351
|
});
|
|
1253
1352
|
```
|
|
1254
1353
|
|
|
1255
|
-
Tip: define the configured `tv` once in a shared `lib/tv.ts` file in your project and import from there instead of re-configuring in every component.
|
|
1256
|
-
|
|
1257
1354
|
### `MyComponent.tsx` — Simple
|
|
1258
1355
|
|
|
1259
1356
|
```tsx
|
|
@@ -1357,7 +1454,18 @@ Unity UI uses its own semantic icon names (not raw Phosphor icon names). Pass th
|
|
|
1357
1454
|
|
|
1358
1455
|
### Common Icons
|
|
1359
1456
|
|
|
1360
|
-
add, add-circle, add-file, agent, airplane, archive, arrow-back, arrow-bend, arrow-down, arrow-forward, arrow-left-right, arrow-up, article, attachment, automate, backspace, bank, bicycle, billing, binoculars, break, bus, calendar, calendar-blank, calendar-check, calendar-dot, calendar-x, camera, car, cart, cash-money, certificate, chat-bubble, chats, check, check-circle, checkbox, checkbox-empty, checkbox-indefinitely, checks, chevron-down, chevron-left, chevron-right, chevron-up, circle-notch, close, close-circle, clock-countdown, clock-person, cloud-download, cloud-upload, columns, copy, dark-mode, deactivate, delete, diagram-view, download, drag, edit, error, exclamation-mark, expand, expenses, face-id, file, filter, filters, first-page, folder, grid-view, hard-hat, help, hide, home, images, info, invoice, job, keyboard, knowledge, language, last-page, light-mode, list-view, location, location-pin, lock, menu, metadata, microphone, minus, more-horizontal, more-vertical, moped, navigation-arrow, note, notches, notifications, numpad, open-in-new-tab, order, organization, pause, phone, piggy-bank, plant, printer, privacy, qr-code, refresh, remark, save, search, send-message, settings, setup-time, shapes, show, sick, sidebar, sign-out, signature, skip-forward, smartphone, sparkle, star, start, stop, table, taxi, text-align-center, text-align-justify, text-align-left, text-align-right, text-t, time, time-sheet-download, time-sheet-upload, timer, train, translate, travel, unfold, upload, user, user-account, users, vacation, wallet, warning, wrench.
|
|
1457
|
+
add, add-circle, add-file, agent, airplane, archive, arrow-back, arrow-bend, arrow-down, arrow-forward, arrow-left-right, arrow-up, article, attachment, automate, backspace, bank, bicycle, billing, binoculars, break, bus, calendar, calendar-blank, calendar-check, calendar-dot, calendar-x, camera, car, cart, cash-money, certificate, chat-bubble, chat-dots, chat-slash, chats, check, check-circle, checkbox, checkbox-empty, checkbox-indefinitely, checks, chevron-down, chevron-left, chevron-right, chevron-up, circle-notch, close, close-circle, clock-countdown, clock-person, cloud-download, cloud-upload, columns, command, control, copy, currency-dollar, currency-dollar-circle, currency-gbp, dark-mode, deactivate, delete, diagram-view, download, drag, edit, error, exclamation-mark, expand, expenses, face-id, file, filter, filters, first-page, flag-de, flag-es, flag-fr, flag-gb, flag-nl, folder, folder-open, grid-view, hard-hat, head-circuit, help, hide, home, images, info, invoice, job, key-return, keyboard, knowledge, language, last-page, light-mode, list-view, location, location-pin, lock, lock-key, lock-key-open, menu, metadata, microphone, minus, more-horizontal, more-vertical, moped, navigation-arrow, note, notches, notifications, numpad, open-in-new-tab, option, order, organization, pause, phone, piggy-bank, pin, pin-simple, pin-simple-slash, pin-slash, plant, printer, privacy, qr-code, refresh, remark, robot, save, search, send-message, settings, setup-time, shapes, show, sick, sidebar, sign-out, signature, skip-forward, smartphone, sparkle, star, start, stop, table, taxi, text-align-center, text-align-justify, text-align-left, text-align-right, text-t, time, time-sheet-download, time-sheet-upload, timer, train, translate, travel, unfold, upload, user, user-account, users, vacation, wallet, warning, wrench.
|
|
1458
|
+
|
|
1459
|
+
### Flag Icons
|
|
1460
|
+
|
|
1461
|
+
Country flag SVGs — work in all components (ListMenu, PopUpMenu, Button, Chip, Select):
|
|
1462
|
+
|
|
1463
|
+
flag-de (Germany), flag-es (Spain), flag-fr (France), flag-gb (United Kingdom), flag-nl (Netherlands).
|
|
1464
|
+
|
|
1465
|
+
```tsx
|
|
1466
|
+
<Icon name="flag-de" size="sm" />
|
|
1467
|
+
<PopUpMenu items={[{ id: 'de', label: 'Deutsch', icon: 'flag-de' }]} />
|
|
1468
|
+
```
|
|
1361
1469
|
|
|
1362
1470
|
### File Type Icons
|
|
1363
1471
|
|
package/dist/theme.css
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
@import 'tailwindcss';
|
|
2
2
|
|
|
3
|
+
@font-face {
|
|
4
|
+
font-family: 'Source Sans 3';
|
|
5
|
+
font-style: normal;
|
|
6
|
+
font-weight: 300;
|
|
7
|
+
src: url('https://d1ciav5yxfbyc5.cloudfront.net/fonts/source-sans-3-variable.woff2')
|
|
8
|
+
format('woff2');
|
|
9
|
+
font-display: swap;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@font-face {
|
|
13
|
+
font-family: 'Source Sans 3';
|
|
14
|
+
font-style: normal;
|
|
15
|
+
font-weight: 400;
|
|
16
|
+
src: url('https://d1ciav5yxfbyc5.cloudfront.net/fonts/source-sans-3-variable.woff2')
|
|
17
|
+
format('woff2');
|
|
18
|
+
font-display: swap;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@font-face {
|
|
22
|
+
font-family: 'Source Sans 3';
|
|
23
|
+
font-style: normal;
|
|
24
|
+
font-weight: 500;
|
|
25
|
+
src: url('https://d1ciav5yxfbyc5.cloudfront.net/fonts/source-sans-3-variable.woff2')
|
|
26
|
+
format('woff2');
|
|
27
|
+
font-display: swap;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@font-face {
|
|
31
|
+
font-family: 'Source Sans 3';
|
|
32
|
+
font-style: normal;
|
|
33
|
+
font-weight: 700;
|
|
34
|
+
src: url('https://d1ciav5yxfbyc5.cloudfront.net/fonts/source-sans-3-variable.woff2')
|
|
35
|
+
format('woff2');
|
|
36
|
+
font-display: swap;
|
|
37
|
+
}
|
|
38
|
+
|
|
3
39
|
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
|
|
4
40
|
@custom-variant child (& > *);
|
|
5
41
|
@theme {
|
|
@@ -276,8 +312,11 @@
|
|
|
276
312
|
--color-surface-container-highest: var(--color-neutral-variant-90);
|
|
277
313
|
--color-on-surface: var(--color-neutral-variant-10);
|
|
278
314
|
--color-on-surface-variant: var(--color-neutral-variant-40);
|
|
315
|
+
--color-on-surface-variant-lowest: var(--color-neutral-variant-70);
|
|
279
316
|
--color-outline: var(--color-neutral-variant-70);
|
|
280
317
|
--color-outline-variant: var(--color-neutral-variant-90);
|
|
318
|
+
--color-outline-low: var(--color-neutral-variant-95);
|
|
319
|
+
--color-outline-variant-low: var(--color-neutral-variant-50);
|
|
281
320
|
--color-error: var(--color-error-40);
|
|
282
321
|
--color-error-hover: var(--color-error-50);
|
|
283
322
|
--color-on-error: var(--color-error-100);
|
|
@@ -496,8 +535,11 @@
|
|
|
496
535
|
--color-surface-container-highest: var(--color-neutral-35);
|
|
497
536
|
--color-on-surface: var(--color-neutral-90);
|
|
498
537
|
--color-on-surface-variant: var(--color-neutral-70);
|
|
538
|
+
--color-on-surface-variant-lowest: var(--color-neutral-50);
|
|
499
539
|
--color-outline: var(--color-neutral-50);
|
|
500
540
|
--color-outline-variant: var(--color-neutral-30);
|
|
541
|
+
--color-outline-low: var(--color-neutral-30);
|
|
542
|
+
--color-outline-variant-low: var(--color-neutral-variant-60);
|
|
501
543
|
--color-error: var(--color-error-80);
|
|
502
544
|
--color-error-hover: var(--color-error-70);
|
|
503
545
|
--color-on-error: var(--color-error-20);
|
|
@@ -625,6 +667,10 @@
|
|
|
625
667
|
animation: circular-indeterminate 1.2s ease-in-out infinite;
|
|
626
668
|
}
|
|
627
669
|
|
|
670
|
+
.animate-circular-indeterminate-slow {
|
|
671
|
+
animation: circular-indeterminate 1.8s ease-in-out infinite;
|
|
672
|
+
}
|
|
673
|
+
|
|
628
674
|
.remove-margin-block-start {
|
|
629
675
|
margin-block-start: 0 !important;
|
|
630
676
|
}
|