@zvoove/unity-ui 2.21.0 → 2.22.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/dist/llms.txt CHANGED
@@ -1075,6 +1075,263 @@ 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-error` | `bg-error` / `text-error` | Error states |
1110
+ | `--color-background` | `bg-background` | Page background |
1111
+
1112
+ **Spacing** (for gap, padding, margin, width, height)
1113
+ `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)
1114
+
1115
+ Examples: `p-md`, `gap-lg`, `mx-xl`, `w-xl4`
1116
+
1117
+ **Typography**
1118
+ `text-body-small` • `text-body-medium` • `text-body-large`
1119
+ `text-label-small` • `text-label-medium` • `text-label-large`
1120
+ `text-title-small` • `text-title-medium` • `text-title-large`
1121
+ `text-headline-small` • `text-headline-medium` • `text-headline-large`
1122
+ `text-display-small` • `text-display-medium` • `text-display-large`
1123
+
1124
+ **Border radius**: `rounded-none` • `rounded-xs` • `rounded-sm` • `rounded-md` • `rounded-lg` • `rounded-xl` • `rounded-full`
1125
+
1126
+ **Shadows**: `shadow-elevation1` • `shadow-elevation2` • `shadow-elevation3` • `shadow-elevation4` • `shadow-elevation5`
1127
+ Dark mode shadows: `dark:shadow-elevation1-dark` (replace `elevation1` with the level you need)
1128
+
1129
+ **Dark mode**: use `dark:` Tailwind prefix. Activated by `data-theme="dark"` on a parent element — not via `prefers-color-scheme`.
1130
+
1131
+ ### tailwind-variants for Component Variants
1132
+
1133
+ Use `tailwind-variants` when a custom UI element has multiple visual variants.
1134
+
1135
+ Configure `tv` with Unity UI spacing tokens so class merging works correctly:
1136
+ ```ts
1137
+ import { createTV } from 'tailwind-variants';
1138
+
1139
+ export const tv = createTV({
1140
+ twMergeConfig: {
1141
+ theme: {
1142
+ spacing: ['none', 'xs2', 'xs', 'sm', 'md', 'lg', 'xl', 'xl2', 'xl3', 'xl4', 'xl5', 'xl6', 'xl7'],
1143
+ borderRadius: ['none', 'xs', 'sm', 'md', 'lg', 'xl', 'full'],
1144
+ },
1145
+ },
1146
+ });
1147
+ ```
1148
+
1149
+ Usage:
1150
+ ```ts
1151
+ const badge = tv({
1152
+ base: ['inline-flex', 'items-center', 'rounded-full', 'px-sm', 'py-xs2', 'text-label-small'],
1153
+ variants: {
1154
+ tone: {
1155
+ primary: ['bg-primary-container', 'text-on-primary-container'],
1156
+ error: ['bg-error-container', 'text-on-error-container'],
1157
+ surface: ['bg-surface-container', 'text-on-surface'],
1158
+ },
1159
+ },
1160
+ defaultVariants: { tone: 'surface' },
1161
+ });
1162
+
1163
+ // Apply:
1164
+ <div className={badge({ tone: 'primary' })}>Label</div>
1165
+ ```
1166
+
1167
+ ### Class Merging
1168
+
1169
+ Use `tailwind-merge` for ad-hoc merging (e.g. accepting a `className` prop):
1170
+ ```ts
1171
+ import { twMerge } from 'tailwind-merge';
1172
+
1173
+ const className = twMerge('p-md bg-surface', props.className);
1174
+ ```
1175
+
1176
+ ### Rules
1177
+
1178
+ - NEVER use inline styles: `style={{ color: '#ff0000', padding: '13px' }}`
1179
+ - NEVER use arbitrary Tailwind values: `p-[13px]`, `text-[#ff0000]`, `bg-[rgba(0,0,0,0.5)]`
1180
+ - NEVER use generic Tailwind size utilities for spacing — use design tokens: `p-md` not `p-4`
1181
+ - NEVER use generic Tailwind text utilities for typography — use design tokens: `text-body-medium` not `text-sm`
1182
+ - ALWAYS use semantic color tokens (`bg-primary`, `text-on-surface`) not palette tokens (`bg-primary-40`)
1183
+ - Use `tv()` from `tailwind-variants` when a custom element has multiple visual variants
1184
+ - Use `dark:` prefix for dark mode — never hard-code colors per theme in two separate class sets
1185
+
1186
+ ---
1187
+
1188
+ ## CUSTOM COMPONENT
1189
+
1190
+ 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.
1191
+
1192
+ ### File Structure
1193
+
1194
+ ```
1195
+ src/components/MyComponent/
1196
+ MyComponent.tsx # Component implementation
1197
+ MyComponent.styled.ts # tailwind-variants styles
1198
+ MyComponent.types.ts # TypeScript props interface
1199
+ MyComponent.test.tsx # Vitest + RTL tests (optional but recommended)
1200
+ index.ts # Re-exports
1201
+ ```
1202
+
1203
+ ### `MyComponent.types.ts`
1204
+
1205
+ ```ts
1206
+ import { ReactNode } from 'react';
1207
+
1208
+ export interface MyComponentProps {
1209
+ /**
1210
+ * Content to render inside the component.
1211
+ */
1212
+ children?: ReactNode;
1213
+
1214
+ /**
1215
+ * Visual variant.
1216
+ * @default 'primary'
1217
+ */
1218
+ variant?: 'primary' | 'secondary';
1219
+ }
1220
+ ```
1221
+
1222
+ Rules:
1223
+ - JSDoc on every prop; `@default` on every defaulted prop
1224
+ - Named export only
1225
+
1226
+ ### `MyComponent.styled.ts`
1227
+
1228
+ ```ts
1229
+ import { createTV } from 'tailwind-variants';
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
+ });
1240
+
1241
+ export const myComponentStyles = tv({
1242
+ base: ['text-body-medium', 'rounded-sm'],
1243
+ variants: {
1244
+ variant: {
1245
+ primary: ['bg-primary', 'text-on-primary'],
1246
+ secondary: ['bg-surface-container', 'text-on-surface'],
1247
+ },
1248
+ },
1249
+ defaultVariants: {
1250
+ variant: 'primary',
1251
+ },
1252
+ });
1253
+ ```
1254
+
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
+ ### `MyComponent.tsx` — Simple
1258
+
1259
+ ```tsx
1260
+ import { myComponentStyles } from './MyComponent.styled';
1261
+ import { MyComponentProps } from './MyComponent.types';
1262
+
1263
+ const MyComponent = ({
1264
+ children,
1265
+ variant = 'primary',
1266
+ }: MyComponentProps) => {
1267
+ return (
1268
+ <div className={myComponentStyles({ variant })}>
1269
+ {children}
1270
+ </div>
1271
+ );
1272
+ };
1273
+
1274
+ MyComponent.displayName = 'MyComponent';
1275
+
1276
+ export default MyComponent;
1277
+ ```
1278
+
1279
+ ### `MyComponent.tsx` — With `forwardRef`
1280
+
1281
+ Use when the root is a DOM element consumers may need a ref for:
1282
+
1283
+ ```tsx
1284
+ import { forwardRef } from 'react';
1285
+
1286
+ import { myComponentStyles } from './MyComponent.styled';
1287
+ import { MyComponentProps } from './MyComponent.types';
1288
+
1289
+ const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>(
1290
+ ({ children, variant = 'primary', ...props }, ref) => {
1291
+ return (
1292
+ <div
1293
+ ref={ref}
1294
+ className={myComponentStyles({ variant })}
1295
+ {...props}
1296
+ >
1297
+ {children}
1298
+ </div>
1299
+ );
1300
+ }
1301
+ );
1302
+
1303
+ MyComponent.displayName = 'MyComponent';
1304
+
1305
+ export default MyComponent;
1306
+ ```
1307
+
1308
+ ### `index.ts`
1309
+
1310
+ ```ts
1311
+ export { default as MyComponent } from './MyComponent';
1312
+ export type { MyComponentProps } from './MyComponent.types';
1313
+ ```
1314
+
1315
+ ### Using Unity UI Components Inside Custom Components
1316
+
1317
+ ```tsx
1318
+ import { Icon, Stack, Typography } from '@zvoove/unity-ui';
1319
+ ```
1320
+
1321
+ Always compose with existing Unity UI components rather than re-implementing their functionality.
1322
+
1323
+ ### Rules
1324
+
1325
+ - Always set `ComponentName.displayName = 'ComponentName'`
1326
+ - Always JSDoc every prop with `@default` on defaulted props
1327
+ - Use `tv()` from `tailwind-variants` (configured with Unity UI tokens — see `unity-ui-styling` skill)
1328
+ - Use design tokens as Tailwind utilities — no arbitrary values, no inline styles
1329
+ - Use `forwardRef` when the root is a DOM element that callers may need to reference
1330
+ - Import Unity UI components from `@zvoove/unity-ui`
1331
+ - Never recreate what an existing Unity UI component already does
1332
+
1333
+ ---
1334
+
1078
1335
  ## SPACING SCALE
1079
1336
 
1080
1337
  Use these values for gap, padding, and margin props: