@zvoove/unity-ui 2.21.0 → 2.22.1

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/dist/llms.txt CHANGED
@@ -1075,6 +1075,264 @@ useClickOutside(ref, () => setOpen(false), isOpen);
1075
1075
 
1076
1076
  ---
1077
1077
 
1078
+ ## STYLING
1079
+
1080
+ When a UI element has no matching Unity UI component, use **Tailwind CSS v4** with the Unity UI design tokens. **Never use inline styles or arbitrary CSS values.**
1081
+
1082
+ ### Setup
1083
+
1084
+ ```bash
1085
+ npm install tailwindcss tailwind-variants tailwind-merge
1086
+ ```
1087
+
1088
+ In your Tailwind CSS entry file:
1089
+ ```css
1090
+ @import 'tailwindcss';
1091
+ @import '@zvoove/unity-ui/theme.css'; /* registers all design tokens as Tailwind utilities */
1092
+ ```
1093
+
1094
+ ### Design Tokens as Tailwind Classes
1095
+
1096
+ All tokens from `theme.css` are available as Tailwind utilities. Use **semantic** tokens, not raw palette tokens.
1097
+
1098
+ **Colors (semantic — always prefer these)**
1099
+ | Token | Tailwind utility | Use for |
1100
+ |-------|-----------------|---------|
1101
+ | `--color-primary` | `bg-primary` / `text-primary` / `border-primary` | Primary brand color |
1102
+ | `--color-on-primary` | `text-on-primary` | Text on primary backgrounds |
1103
+ | `--color-surface` | `bg-surface` | Card/panel backgrounds |
1104
+ | `--color-surface-container` | `bg-surface-container` | Nested container backgrounds |
1105
+ | `--color-on-surface` | `text-on-surface` | Body text |
1106
+ | `--color-on-surface-variant` | `text-on-surface-variant` | Secondary/muted text |
1107
+ | `--color-outline` | `border-outline` | Default borders |
1108
+ | `--color-outline-variant` | `border-outline-variant` | Subtle dividers |
1109
+ | `--color-outline-variant-low` | `border-outline-variant-low` | Very subtle dividers/borders |
1110
+ | `--color-error` | `bg-error` / `text-error` | Error states |
1111
+ | `--color-background` | `bg-background` | Page background |
1112
+
1113
+ **Spacing** (for gap, padding, margin, width, height)
1114
+ `none`(0) • `xs2`(4px) • `xs`(8px) • `sm`(12px) • `md`(16px) • `lg`(20px) • `xl`(24px) • `xl2`(32px) • `xl3`(40px) • `xl4`(48px) • `xl5`(64px) • `xl6`(80px) • `xl7`(96px)
1115
+
1116
+ Examples: `p-md`, `gap-lg`, `mx-xl`, `w-xl4`
1117
+
1118
+ **Typography**
1119
+ `text-body-small` • `text-body-medium` • `text-body-large`
1120
+ `text-label-small` • `text-label-medium` • `text-label-large`
1121
+ `text-title-small` • `text-title-medium` • `text-title-large`
1122
+ `text-headline-small` • `text-headline-medium` • `text-headline-large`
1123
+ `text-display-small` • `text-display-medium` • `text-display-large`
1124
+
1125
+ **Border radius**: `rounded-none` • `rounded-xs` • `rounded-sm` • `rounded-md` • `rounded-lg` • `rounded-xl` • `rounded-full`
1126
+
1127
+ **Shadows**: `shadow-elevation1` • `shadow-elevation2` • `shadow-elevation3` • `shadow-elevation4` • `shadow-elevation5`
1128
+ Dark mode shadows: `dark:shadow-elevation1-dark` (replace `elevation1` with the level you need)
1129
+
1130
+ **Dark mode**: use `dark:` Tailwind prefix. Activated by `data-theme="dark"` on a parent element — not via `prefers-color-scheme`.
1131
+
1132
+ ### tailwind-variants for Component Variants
1133
+
1134
+ Use `tailwind-variants` when a custom UI element has multiple visual variants.
1135
+
1136
+ Configure `tv` with Unity UI spacing tokens so class merging works correctly:
1137
+ ```ts
1138
+ import { createTV } from 'tailwind-variants';
1139
+
1140
+ export const tv = createTV({
1141
+ twMergeConfig: {
1142
+ theme: {
1143
+ spacing: ['none', 'xs2', 'xs', 'sm', 'md', 'lg', 'xl', 'xl2', 'xl3', 'xl4', 'xl5', 'xl6', 'xl7'],
1144
+ borderRadius: ['none', 'xs', 'sm', 'md', 'lg', 'xl', 'full'],
1145
+ },
1146
+ },
1147
+ });
1148
+ ```
1149
+
1150
+ Usage:
1151
+ ```ts
1152
+ const badge = tv({
1153
+ base: ['inline-flex', 'items-center', 'rounded-full', 'px-sm', 'py-xs2', 'text-label-small'],
1154
+ variants: {
1155
+ tone: {
1156
+ primary: ['bg-primary-container', 'text-on-primary-container'],
1157
+ error: ['bg-error-container', 'text-on-error-container'],
1158
+ surface: ['bg-surface-container', 'text-on-surface'],
1159
+ },
1160
+ },
1161
+ defaultVariants: { tone: 'surface' },
1162
+ });
1163
+
1164
+ // Apply:
1165
+ <div className={badge({ tone: 'primary' })}>Label</div>
1166
+ ```
1167
+
1168
+ ### Class Merging
1169
+
1170
+ Use `tailwind-merge` for ad-hoc merging (e.g. accepting a `className` prop):
1171
+ ```ts
1172
+ import { twMerge } from 'tailwind-merge';
1173
+
1174
+ const className = twMerge('p-md bg-surface', props.className);
1175
+ ```
1176
+
1177
+ ### Rules
1178
+
1179
+ - NEVER use inline styles: `style={{ color: '#ff0000', padding: '13px' }}`
1180
+ - NEVER use arbitrary Tailwind values: `p-[13px]`, `text-[#ff0000]`, `bg-[rgba(0,0,0,0.5)]`
1181
+ - NEVER use generic Tailwind size utilities for spacing — use design tokens: `p-md` not `p-4`
1182
+ - NEVER use generic Tailwind text utilities for typography — use design tokens: `text-body-medium` not `text-sm`
1183
+ - ALWAYS use semantic color tokens (`bg-primary`, `text-on-surface`) not palette tokens (`bg-primary-40`)
1184
+ - Use `tv()` from `tailwind-variants` when a custom element has multiple visual variants
1185
+ - Use `dark:` prefix for dark mode — never hard-code colors per theme in two separate class sets
1186
+
1187
+ ---
1188
+
1189
+ ## CUSTOM COMPONENT
1190
+
1191
+ When you need UI that no existing Unity UI component covers, create a custom component that follows the same conventions so it stays consistent with the design system.
1192
+
1193
+ ### File Structure
1194
+
1195
+ ```
1196
+ src/components/MyComponent/
1197
+ MyComponent.tsx # Component implementation
1198
+ MyComponent.styled.ts # tailwind-variants styles
1199
+ MyComponent.types.ts # TypeScript props interface
1200
+ MyComponent.test.tsx # Vitest + RTL tests (optional but recommended)
1201
+ index.ts # Re-exports
1202
+ ```
1203
+
1204
+ ### `MyComponent.types.ts`
1205
+
1206
+ ```ts
1207
+ import { ReactNode } from 'react';
1208
+
1209
+ export interface MyComponentProps {
1210
+ /**
1211
+ * Content to render inside the component.
1212
+ */
1213
+ children?: ReactNode;
1214
+
1215
+ /**
1216
+ * Visual variant.
1217
+ * @default 'primary'
1218
+ */
1219
+ variant?: 'primary' | 'secondary';
1220
+ }
1221
+ ```
1222
+
1223
+ Rules:
1224
+ - JSDoc on every prop; `@default` on every defaulted prop
1225
+ - Named export only
1226
+
1227
+ ### `MyComponent.styled.ts`
1228
+
1229
+ ```ts
1230
+ import { createTV } from 'tailwind-variants';
1231
+
1232
+ // Configure tv with Unity UI spacing/radius tokens for correct class merging
1233
+ const tv = createTV({
1234
+ twMergeConfig: {
1235
+ theme: {
1236
+ spacing: ['none', 'xs2', 'xs', 'sm', 'md', 'lg', 'xl', 'xl2', 'xl3', 'xl4', 'xl5', 'xl6', 'xl7'],
1237
+ borderRadius: ['none', 'xs', 'sm', 'md', 'lg', 'xl', 'full'],
1238
+ },
1239
+ },
1240
+ });
1241
+
1242
+ export const myComponentStyles = tv({
1243
+ base: ['text-body-medium', 'rounded-sm'],
1244
+ variants: {
1245
+ variant: {
1246
+ primary: ['bg-primary', 'text-on-primary'],
1247
+ secondary: ['bg-surface-container', 'text-on-surface'],
1248
+ },
1249
+ },
1250
+ defaultVariants: {
1251
+ variant: 'primary',
1252
+ },
1253
+ });
1254
+ ```
1255
+
1256
+ 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.
1257
+
1258
+ ### `MyComponent.tsx` — Simple
1259
+
1260
+ ```tsx
1261
+ import { myComponentStyles } from './MyComponent.styled';
1262
+ import { MyComponentProps } from './MyComponent.types';
1263
+
1264
+ const MyComponent = ({
1265
+ children,
1266
+ variant = 'primary',
1267
+ }: MyComponentProps) => {
1268
+ return (
1269
+ <div className={myComponentStyles({ variant })}>
1270
+ {children}
1271
+ </div>
1272
+ );
1273
+ };
1274
+
1275
+ MyComponent.displayName = 'MyComponent';
1276
+
1277
+ export default MyComponent;
1278
+ ```
1279
+
1280
+ ### `MyComponent.tsx` — With `forwardRef`
1281
+
1282
+ Use when the root is a DOM element consumers may need a ref for:
1283
+
1284
+ ```tsx
1285
+ import { forwardRef } from 'react';
1286
+
1287
+ import { myComponentStyles } from './MyComponent.styled';
1288
+ import { MyComponentProps } from './MyComponent.types';
1289
+
1290
+ const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>(
1291
+ ({ children, variant = 'primary', ...props }, ref) => {
1292
+ return (
1293
+ <div
1294
+ ref={ref}
1295
+ className={myComponentStyles({ variant })}
1296
+ {...props}
1297
+ >
1298
+ {children}
1299
+ </div>
1300
+ );
1301
+ }
1302
+ );
1303
+
1304
+ MyComponent.displayName = 'MyComponent';
1305
+
1306
+ export default MyComponent;
1307
+ ```
1308
+
1309
+ ### `index.ts`
1310
+
1311
+ ```ts
1312
+ export { default as MyComponent } from './MyComponent';
1313
+ export type { MyComponentProps } from './MyComponent.types';
1314
+ ```
1315
+
1316
+ ### Using Unity UI Components Inside Custom Components
1317
+
1318
+ ```tsx
1319
+ import { Icon, Stack, Typography } from '@zvoove/unity-ui';
1320
+ ```
1321
+
1322
+ Always compose with existing Unity UI components rather than re-implementing their functionality.
1323
+
1324
+ ### Rules
1325
+
1326
+ - Always set `ComponentName.displayName = 'ComponentName'`
1327
+ - Always JSDoc every prop with `@default` on defaulted props
1328
+ - Use `tv()` from `tailwind-variants` (configured with Unity UI tokens — see `unity-ui-styling` skill)
1329
+ - Use design tokens as Tailwind utilities — no arbitrary values, no inline styles
1330
+ - Use `forwardRef` when the root is a DOM element that callers may need to reference
1331
+ - Import Unity UI components from `@zvoove/unity-ui`
1332
+ - Never recreate what an existing Unity UI component already does
1333
+
1334
+ ---
1335
+
1078
1336
  ## SPACING SCALE
1079
1337
 
1080
1338
  Use these values for gap, padding, and margin props:
package/dist/theme.css CHANGED
@@ -278,6 +278,7 @@
278
278
  --color-on-surface-variant: var(--color-neutral-variant-40);
279
279
  --color-outline: var(--color-neutral-variant-70);
280
280
  --color-outline-variant: var(--color-neutral-variant-90);
281
+ --color-outline-variant-low: var(--color-neutral-variant-50);
281
282
  --color-error: var(--color-error-40);
282
283
  --color-error-hover: var(--color-error-50);
283
284
  --color-on-error: var(--color-error-100);
@@ -498,6 +499,7 @@
498
499
  --color-on-surface-variant: var(--color-neutral-70);
499
500
  --color-outline: var(--color-neutral-50);
500
501
  --color-outline-variant: var(--color-neutral-30);
502
+ --color-outline-variant-low: var(--color-neutral-variant-60);
501
503
  --color-error: var(--color-error-80);
502
504
  --color-error-hover: var(--color-error-70);
503
505
  --color-on-error: var(--color-error-20);