@aleph-alpha/ui-library 1.15.0 → 1.16.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.
Files changed (29) hide show
  1. package/config.d.ts +40 -1
  2. package/config.js +107 -2
  3. package/dist/system/lib.js +3 -3
  4. package/docs/public-docs/quick-start.md +57 -13
  5. package/package.json +25 -9
  6. package/src/assets/fonts/Saans/Saans-Bold.woff2 +0 -0
  7. package/src/assets/fonts/Saans/Saans-BoldItalic.woff2 +0 -0
  8. package/src/assets/fonts/Saans/Saans-Heavy.woff2 +0 -0
  9. package/src/assets/fonts/Saans/Saans-HeavyItalic.woff2 +0 -0
  10. package/src/assets/fonts/Saans/Saans-Light.woff2 +0 -0
  11. package/src/assets/fonts/Saans/Saans-LightItalic.woff2 +0 -0
  12. package/src/assets/fonts/Saans/Saans-Medium.woff2 +0 -0
  13. package/src/assets/fonts/Saans/Saans-MediumItalic.woff2 +0 -0
  14. package/src/assets/fonts/Saans/Saans-Regular.woff2 +0 -0
  15. package/src/assets/fonts/Saans/Saans-RegularItalic.woff2 +0 -0
  16. package/src/assets/fonts/Saans/Saans-SemiBold.woff2 +0 -0
  17. package/src/assets/fonts/Saans/Saans-SemiBoldItalic.woff2 +0 -0
  18. package/src/assets/fonts/Saans/SaansItalicsVF.woff2 +0 -0
  19. package/src/assets/fonts/Saans/SaansMono-Bold.woff2 +0 -0
  20. package/src/assets/fonts/Saans/SaansMono-Heavy.woff2 +0 -0
  21. package/src/assets/fonts/Saans/SaansMono-Light.woff2 +0 -0
  22. package/src/assets/fonts/Saans/SaansMono-Medium.woff2 +0 -0
  23. package/src/assets/fonts/Saans/SaansMono-Regular.woff2 +0 -0
  24. package/src/assets/fonts/Saans/SaansMono-SemiBold.woff2 +0 -0
  25. package/src/assets/fonts/Saans/SaansMonoUprightsVF.woff2 +0 -0
  26. package/src/assets/fonts/Saans/SaansUprightsVF.woff2 +0 -0
  27. package/src/assets/fonts/Saans/SaansVF.woff2 +0 -0
  28. package/src/components/UiStepper/UiStepper.stories.ts +1 -1
  29. package/src/components/core/button/index.ts +3 -3
package/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Preset } from 'unocss';
1
+ import type { Preset, UserConfig } from 'unocss';
2
2
 
3
3
  /**
4
4
  * UnoCSS content configuration for scanning ui-library components.
@@ -206,3 +206,42 @@ export type UiLibraryTypographyShortcut = [string, string];
206
206
  * ```
207
207
  */
208
208
  export declare const getUiLibraryTypographyShortcuts: () => UiLibraryTypographyShortcut[];
209
+
210
+ /**
211
+ * Options for `defineUiLibraryConfig`.
212
+ * Combines theme customization with additional UnoCSS config.
213
+ */
214
+ export interface UiLibraryConfigOptions extends UiLibraryPresetOptions {
215
+ /** Additional UnoCSS presets to append after the built-in ones */
216
+ presets?: Preset[];
217
+ /** Additional UnoCSS rules */
218
+ rules?: UserConfig['rules'];
219
+ /** Additional UnoCSS shortcuts */
220
+ shortcuts?: UserConfig['shortcuts'];
221
+ /** Any other UnoCSS config fields (safelist, blocklist, etc.) */
222
+ [key: string]: unknown;
223
+ }
224
+
225
+ /**
226
+ * Creates a complete UnoCSS config with all required presets, content scanning,
227
+ * font loading, and theme from design tokens.
228
+ *
229
+ * This is the recommended way to set up UnoCSS with the UI library.
230
+ * It replaces manually importing and composing presetWind, presetAnimations,
231
+ * presetShadcn, presetUiLibraryThemeFromTokens, and presetUiLibraryUtils.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * // uno.config.ts — minimal
236
+ * import { defineUiLibraryConfig } from '@aleph-alpha/ui-library/config'
237
+ * export default defineUiLibraryConfig()
238
+ *
239
+ * // uno.config.ts — with theme customization
240
+ * import { defineUiLibraryConfig } from '@aleph-alpha/ui-library/config'
241
+ * export default defineUiLibraryConfig({
242
+ * extend: { light: { primary: '#ff5500' } },
243
+ * darkSelector: 'html.dark',
244
+ * })
245
+ * ```
246
+ */
247
+ export declare const defineUiLibraryConfig: (options?: UiLibraryConfigOptions) => UserConfig;
package/config.js CHANGED
@@ -1,8 +1,40 @@
1
1
  import { readFileSync } from 'node:fs';
2
- import { definePreset } from 'unocss';
2
+ import { defineConfig, definePreset } from 'unocss';
3
+ import presetWind from '@unocss/preset-wind4';
4
+ import presetAnimations from 'unocss-preset-animations';
5
+ import presetShadcn from 'unocss-preset-shadcn';
3
6
 
4
7
  let tokensCache;
5
8
 
9
+ let saansFontFaceCssCache;
10
+ const getSaansFontFaceCss = () => {
11
+ if (saansFontFaceCssCache) return saansFontFaceCssCache;
12
+
13
+ const fontsDir = new URL('./src/assets/fonts/Saans/', import.meta.url);
14
+ const fonts = [
15
+ { file: 'Saans-Regular.woff2', weight: 400 },
16
+ { file: 'Saans-Medium.woff2', weight: 500 },
17
+ { file: 'Saans-SemiBold.woff2', weight: 600 },
18
+ { file: 'Saans-Bold.woff2', weight: 700 },
19
+ ];
20
+
21
+ saansFontFaceCssCache = fonts
22
+ .map(({ file, weight }) => {
23
+ const buffer = readFileSync(new URL(file, fontsDir));
24
+ const base64 = buffer.toString('base64');
25
+ return `@font-face {
26
+ font-display: swap;
27
+ font-family: 'Saans';
28
+ font-style: normal;
29
+ font-weight: ${weight};
30
+ src: url('data:font/woff2;base64,${base64}') format('woff2');
31
+ }`;
32
+ })
33
+ .join('\n');
34
+
35
+ return saansFontFaceCssCache;
36
+ };
37
+
6
38
  const getTokens = () => {
7
39
  if (tokensCache) return tokensCache;
8
40
  const raw = readFileSync(new URL('./tokens.json', import.meta.url), 'utf8');
@@ -517,10 +549,28 @@ export const presetUiLibraryThemeFromTokens = (options = {}) => {
517
549
  // Typography shortcuts from design tokens
518
550
  const typographyShortcuts = getUiLibraryTypographyShortcuts();
519
551
 
520
- // Return preset with token-related config: CSS variables, token colors, semantic overrides, typography
552
+ // Resolve font families from tokens for --font-sans / --font-heading overrides
553
+ const fontBody = resolveAnyTokenValue('font.font-family.font-body');
554
+ const fontHeading = resolveAnyTokenValue('font.font-family.font-heading');
555
+ const fontVariablesCss = `
556
+ :root, :host {
557
+ --font-sans: '${fontBody}', sans-serif;
558
+ --font-heading: '${fontHeading}', sans-serif;
559
+ }`.trim();
560
+
561
+ // Return preset with token-related config: CSS variables, token colors, semantic overrides, typography, fonts
521
562
  return {
522
563
  ...basePreset,
564
+ preflights: [
565
+ ...(basePreset.preflights || []),
566
+ { getCSS: () => getSaansFontFaceCss() },
567
+ { getCSS: () => fontVariablesCss },
568
+ ],
523
569
  theme: {
570
+ font: {
571
+ sans: `'${fontBody}', sans-serif`,
572
+ heading: `'${fontHeading}', sans-serif`,
573
+ },
524
574
  colors: {
525
575
  ...tokenColors,
526
576
  ...semanticColors,
@@ -552,6 +602,61 @@ export const presetUiLibraryUtils = () =>
552
602
  ],
553
603
  }))();
554
604
 
605
+ /**
606
+ * Creates a complete UnoCSS config with all required presets, content scanning,
607
+ * font loading, and theme from design tokens. Drop-in replacement for manually
608
+ * composing presetWind, presetAnimations, presetShadcn, and the ui-library presets.
609
+ *
610
+ * @example
611
+ * ```ts
612
+ * // uno.config.ts — minimal
613
+ * import { defineUiLibraryConfig } from '@aleph-alpha/ui-library/config'
614
+ * export default defineUiLibraryConfig()
615
+ *
616
+ * // uno.config.ts — with customization
617
+ * import { defineUiLibraryConfig } from '@aleph-alpha/ui-library/config'
618
+ * export default defineUiLibraryConfig({
619
+ * extend: { light: { primary: '#ff5500' } },
620
+ * darkSelector: 'html.dark',
621
+ * })
622
+ * ```
623
+ */
624
+ export const defineUiLibraryConfig = (options = {}) => {
625
+ const {
626
+ darkSelector,
627
+ rootSelector,
628
+ extend,
629
+ theme,
630
+ includeAllTokens,
631
+ presets: extraPresets = [],
632
+ rules: extraRules = [],
633
+ shortcuts: extraShortcuts = [],
634
+ ...restConfig
635
+ } = options;
636
+
637
+ const themeOptions = {};
638
+ if (darkSelector !== undefined) themeOptions.darkSelector = darkSelector;
639
+ if (rootSelector !== undefined) themeOptions.rootSelector = rootSelector;
640
+ if (extend !== undefined) themeOptions.extend = extend;
641
+ if (theme !== undefined) themeOptions.theme = theme;
642
+ if (includeAllTokens !== undefined) themeOptions.includeAllTokens = includeAllTokens;
643
+
644
+ return defineConfig({
645
+ ...getUiLibraryContentConfig(),
646
+ presets: [
647
+ presetWind(),
648
+ presetAnimations(),
649
+ presetShadcn({ color: 'neutral', darkSelector: darkSelector ?? 'html.dark' }),
650
+ presetUiLibraryThemeFromTokens(themeOptions),
651
+ presetUiLibraryUtils(),
652
+ ...extraPresets,
653
+ ],
654
+ rules: [...extraRules],
655
+ shortcuts: [...extraShortcuts],
656
+ ...restConfig,
657
+ });
658
+ };
659
+
555
660
  // Typography utilities
556
661
  const fontWeightMap = {
557
662
  Regular: '400',
@@ -42276,16 +42276,16 @@ const jW = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
42276
42276
  __proto__: null,
42277
42277
  default: dC
42278
42278
  }, Symbol.toStringTag, { value: "Module" })), Yt = Rt(
42279
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
42279
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-transparent text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
42280
42280
  {
42281
42281
  variants: {
42282
42282
  variant: {
42283
42283
  default: "bg-primary text-primary-foreground hover:bg-primary/90",
42284
- destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
42284
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:border-transparent focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
42285
42285
  outline: "border border-input bg-transparent text-foreground shadow-xs hover:bg-hover-default",
42286
42286
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
42287
42287
  ghost: "text-foreground hover:bg-hover-default",
42288
- link: "text-link underline-offset-4 hover:underline focus-visible:border-none"
42288
+ link: "text-link underline-offset-4 hover:underline"
42289
42289
  },
42290
42290
  size: {
42291
42291
  default: "h-9 px-4 py-2 has-[>svg]:px-3",
@@ -41,6 +41,59 @@ npm install -D unocss @unocss/preset-wind4 @unocss/reset unocss-preset-animation
41
41
 
42
42
  Create or update `uno.config.ts` in your project root:
43
43
 
44
+ ```typescript
45
+ // uno.config.ts
46
+ import { defineUiLibraryConfig } from '@aleph-alpha/ui-library/config'
47
+
48
+ export default defineUiLibraryConfig()
49
+ ```
50
+
51
+ This single call sets up everything: `presetWind4`, `presetAnimations`, `presetShadcn`, design token CSS variables (light/dark), token-based theme colors, semantic color overrides, typography classes, font loading, and content scanning.
52
+
53
+ To customize the theme:
54
+
55
+ ```typescript
56
+ // uno.config.ts
57
+ import { defineUiLibraryConfig } from '@aleph-alpha/ui-library/config'
58
+
59
+ export default defineUiLibraryConfig({
60
+ // Override specific theme variables
61
+ extend: { light: { primary: '#ff5500' } },
62
+ // Add your own presets
63
+ presets: [myCustomPreset()],
64
+ })
65
+ ```
66
+
67
+ More complete theme options example:
68
+
69
+ ```typescript
70
+ // uno.config.ts
71
+ import { defineUiLibraryConfig } from '@aleph-alpha/ui-library/config'
72
+
73
+ export default defineUiLibraryConfig({
74
+ // Root and dark selectors used for generated CSS variables
75
+ rootSelector: ':root',
76
+ darkSelector: 'html.dark',
77
+ // Include all token vars like --background-surface-secondary
78
+ includeAllTokens: true,
79
+ // Extend token-derived theme values
80
+ extend: {
81
+ light: {
82
+ primary: '#ff5500',
83
+ 'accent-default': '#b2d9ff',
84
+ },
85
+ dark: {
86
+ primary: '#ff8a3d',
87
+ },
88
+ },
89
+ })
90
+ ```
91
+
92
+ <details>
93
+ <summary>Advanced: manual preset composition</summary>
94
+
95
+ If you need full control over preset ordering, you can compose the presets individually:
96
+
44
97
  ```typescript
45
98
  // uno.config.ts
46
99
  import { defineConfig } from 'unocss'
@@ -59,23 +112,13 @@ export default defineConfig({
59
112
  presetWind(),
60
113
  presetAnimations(),
61
114
  presetShadcn({ color: 'neutral', darkSelector: 'html.dark' }),
62
- // Must come AFTER presetShadcn — bundles token CSS vars, colors, and typography
115
+ // Must come AFTER presetShadcn
63
116
  presetUiLibraryThemeFromTokens(),
64
117
  presetUiLibraryUtils(),
65
118
  ],
66
119
  })
67
120
  ```
68
-
69
- **What each part does:**
70
-
71
- | Config | Purpose |
72
- |--------|---------|
73
- | `getUiLibraryContentConfig()` | Scans `node_modules/@aleph-alpha/ui-library` for class usage so UnoCSS generates the right utilities |
74
- | `presetWind()` | Tailwind-compatible utility classes (must be **wind4**, not wind3) |
75
- | `presetAnimations()` | CSS animation utilities for transitions |
76
- | `presetShadcn()` | Base shadcn CSS variables and color utilities |
77
- | `presetUiLibraryThemeFromTokens()` | Token preset — must come **after** `presetShadcn`. Bundles design token CSS variables (light/dark), token-based theme colors (`bg-background-surface-secondary`, etc.), semantic color overrides (`background`, `foreground`, `modal`, etc.), and typography classes (`heading-48-bold`, `body-14-normal`, `label-12-medium`, etc.) |
78
- | `presetUiLibraryUtils()` | Utility rules required by library components — Tailwind v4 CSS variable syntax (`w-(--var)`, `h-(--var)`, etc.) not yet supported by preset-wind4 |
121
+ </details>
79
122
 
80
123
  ### 3. Vite config
81
124
 
@@ -155,8 +198,9 @@ All config functions are exported from `@aleph-alpha/ui-library/config`:
155
198
 
156
199
  | Export | Description |
157
200
  |--------|-------------|
201
+ | `defineUiLibraryConfig(options?)` | **Recommended.** Complete UnoCSS config with all presets, content scanning, fonts, and tokens. Options: `extend`, `darkSelector`, `presets`, `rules`, `shortcuts`, and any other UnoCSS config |
158
202
  | `getUiLibraryContentConfig()` | UnoCSS content/pipeline config to scan library classes |
159
- | `presetUiLibraryThemeFromTokens(options?)` | **Token preset.** Bundles token CSS variables, theme colors, semantic overrides, and typography classes. Options: `darkSelector` (default: `'html.dark'`), `includeAllTokens` (default: `true`), `extend`, `theme` |
203
+ | `presetUiLibraryThemeFromTokens(options?)` | Token preset. Bundles token CSS variables, theme colors, semantic overrides, and typography classes. Options: `darkSelector` (default: `'html.dark'`), `includeAllTokens` (default: `true`), `extend`, `theme` |
160
204
  | `presetUiLibraryUtils()` | Utility rules required by library components (`w-(--var)`, `h-(--var)`, etc.) |
161
205
  | `presetUiLibraryTheme(theme, options?)` | Low-level preset with manually provided theme variables (for custom themes) |
162
206
  | `getUiLibraryThemeFromTokens()` | Returns the raw theme object derived from `tokens.json` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aleph-alpha/ui-library",
3
- "version": "1.15.0",
3
+ "version": "1.16.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/system/lib.js",
@@ -43,11 +43,11 @@
43
43
  "devDependencies": {
44
44
  "@faker-js/faker": "10.1.0",
45
45
  "@playwright/test": "1.57.0",
46
- "@storybook/addon-a11y": "^10.1.7",
47
- "@storybook/addon-docs": "^10.1.7",
48
- "@storybook/addon-themes": "^10.1.7",
49
- "@storybook/addon-vitest": "^10.1.7",
50
- "@storybook/vue3-vite": "^10.1.7",
46
+ "@storybook/addon-a11y": "10.2.17",
47
+ "@storybook/addon-docs": "10.2.17",
48
+ "@storybook/addon-themes": "10.2.17",
49
+ "@storybook/addon-vitest": "10.2.17",
50
+ "@storybook/vue3-vite": "10.2.17",
51
51
  "@testing-library/jest-dom": "^6.4.6",
52
52
  "@testing-library/vue": "^8.1.0",
53
53
  "@unocss/preset-wind3": "^66.5.10",
@@ -60,7 +60,7 @@
60
60
  "http-server": "14.1.1",
61
61
  "playwright": "^1.57.0",
62
62
  "postcss": "8.5.6",
63
- "storybook": "^10.1.7",
63
+ "storybook": "10.2.17",
64
64
  "typescript": "^5.2.2",
65
65
  "unocss": "66.4.1",
66
66
  "unocss-preset-animations": "1.3.0",
@@ -71,11 +71,27 @@
71
71
  "vitest": "^3.0.0",
72
72
  "vue-tsc": "^2.2.12",
73
73
  "wait-on": "9.0.3",
74
- "@aleph-alpha/config-css": "0.20.0",
75
- "@aleph-alpha/eslint-config-frontend": "0.4.0",
76
74
  "@aleph-alpha/prettier-config-frontend": "0.4.0",
75
+ "@aleph-alpha/eslint-config-frontend": "0.5.0",
77
76
  "@aleph-alpha/tsconfig-frontend": "0.5.0"
78
77
  },
78
+ "peerDependencies": {
79
+ "@unocss/preset-wind4": ">=66.0.0",
80
+ "unocss": ">=66.0.0",
81
+ "unocss-preset-animations": ">=1.0.0",
82
+ "unocss-preset-shadcn": ">=1.0.0"
83
+ },
84
+ "peerDependenciesMeta": {
85
+ "@unocss/preset-wind4": {
86
+ "optional": true
87
+ },
88
+ "unocss-preset-animations": {
89
+ "optional": true
90
+ },
91
+ "unocss-preset-shadcn": {
92
+ "optional": true
93
+ }
94
+ },
79
95
  "dependencies": {
80
96
  "@floating-ui/vue": "1.1.9",
81
97
  "@internationalized/date": "^3.10.1",
@@ -12,7 +12,7 @@ import {
12
12
  import { UiIcon } from '../UiIcon';
13
13
 
14
14
  const meta: Meta<typeof UiStepper> = {
15
- title: 'Primitives/UiStepper',
15
+ title: 'Components/UiStepper',
16
16
  component: UiStepper,
17
17
  tags: ['autodocs'],
18
18
  argTypes: {
@@ -4,18 +4,18 @@ import { cva } from 'class-variance-authority';
4
4
  export { default as Button } from './Button.vue';
5
5
 
6
6
  export const buttonVariants = cva(
7
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
7
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-transparent text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
11
  default: 'bg-primary text-primary-foreground hover:bg-primary/90',
12
12
  destructive:
13
- 'bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40',
13
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:border-transparent focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40',
14
14
  outline:
15
15
  'border border-input bg-transparent text-foreground shadow-xs hover:bg-hover-default',
16
16
  secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
17
17
  ghost: 'text-foreground hover:bg-hover-default',
18
- link: 'text-link underline-offset-4 hover:underline focus-visible:border-none',
18
+ link: 'text-link underline-offset-4 hover:underline',
19
19
  },
20
20
  size: {
21
21
  default: 'h-9 px-4 py-2 has-[>svg]:px-3',