@lerianstudio/sindarian-ui 1.3.0-beta.6 → 1.3.0-beta.7

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 (33) hide show
  1. package/README.md +93 -12
  2. package/dist/components/ui/badge/index.d.ts +2 -1
  3. package/dist/components/ui/badge/index.d.ts.map +1 -1
  4. package/dist/components/ui/badge/index.js +15 -3
  5. package/dist/components/ui/card/index.d.ts +10 -2
  6. package/dist/components/ui/card/index.d.ts.map +1 -1
  7. package/dist/components/ui/card/index.js +2 -2
  8. package/dist/components/ui/toast/toaster.d.ts +5 -0
  9. package/dist/components/ui/toast/toaster.d.ts.map +1 -1
  10. package/dist/components/ui/toast/toaster.js +6 -2
  11. package/dist/enterprise/app-shell/index.d.ts +14 -0
  12. package/dist/enterprise/app-shell/index.d.ts.map +1 -1
  13. package/dist/enterprise/app-shell/index.js +2 -2
  14. package/dist/esm/components/ui/badge/index.d.ts +2 -1
  15. package/dist/esm/components/ui/badge/index.d.ts.map +1 -1
  16. package/dist/esm/components/ui/badge/index.js +15 -3
  17. package/dist/esm/components/ui/card/index.d.ts +10 -2
  18. package/dist/esm/components/ui/card/index.d.ts.map +1 -1
  19. package/dist/esm/components/ui/card/index.js +2 -2
  20. package/dist/esm/components/ui/toast/toaster.d.ts +5 -0
  21. package/dist/esm/components/ui/toast/toaster.d.ts.map +1 -1
  22. package/dist/esm/components/ui/toast/toaster.js +6 -2
  23. package/dist/esm/enterprise/app-shell/index.d.ts +14 -0
  24. package/dist/esm/enterprise/app-shell/index.d.ts.map +1 -1
  25. package/dist/esm/enterprise/app-shell/index.js +2 -2
  26. package/dist/esm/theme/theme-provider.d.ts +8 -0
  27. package/dist/esm/theme/theme-provider.d.ts.map +1 -1
  28. package/dist/esm/theme/theme-provider.js +10 -0
  29. package/dist/globals.css +4 -0
  30. package/dist/theme/theme-provider.d.ts +8 -0
  31. package/dist/theme/theme-provider.d.ts.map +1 -1
  32. package/dist/theme/theme-provider.js +11 -0
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -41,18 +41,34 @@ npm install react@>=19.0.0 react-dom@>=19.0.0 react-hook-form@>=7.60.0 lucide-re
41
41
 
42
42
  ### Tailwind CSS Setup
43
43
 
44
- Add the package path to your `tailwind.config.js` to ensure proper styling:
45
-
46
- ```js
47
- module.exports = {
48
- content: [
49
- './src/**/*.{js,ts,jsx,tsx}',
50
- './node_modules/sindarian-ui/**/*.{js,ts,jsx,tsx}' // Add this line
51
- ]
52
- // ... rest of your config
53
- }
44
+ The library is built with Tailwind CSS v4, which is configured from CSS — there
45
+ is no `tailwind.config.js`. Your app needs `tailwindcss@^4` plus
46
+ `@tailwindcss/postcss` (Next.js) or `@tailwindcss/vite` (Vite).
47
+
48
+ Wire the library into your app's entry stylesheet in this order:
49
+
50
+ ```css
51
+ /* Keep the Tailwind import in your app's entry stylesheet — source scanning
52
+ breaks when the only import lives inside node_modules. */
53
+ @import 'tailwindcss';
54
+
55
+ /* The dark variant, matched against a `.dark` class on an ancestor. */
56
+ @custom-variant dark (&:is(.dark *));
57
+
58
+ /* Design tokens, base layer and component styles. */
59
+ @import '@lerianstudio/sindarian-ui/dist/globals.css';
60
+
61
+ /* Scan the library's compiled output so its utility classes survive the
62
+ content purge. The path is relative to this file. */
63
+ @source '../node_modules/@lerianstudio/sindarian-ui/dist';
54
64
  ```
55
65
 
66
+ Adjust the `@source` depth to where your entry stylesheet sits: `../..` from
67
+ `src/app/globals.css` in a Next.js app, `..` from `src/index.css` in a Vite app.
68
+
69
+ Non-Next.js apps must also load Inter themselves — see "Migrating to 1.3+"
70
+ below.
71
+
56
72
  ## 🚀 Quick Start
57
73
 
58
74
  ```tsx
@@ -63,7 +79,7 @@ import {
63
79
  CardContent,
64
80
  CardHeader,
65
81
  CardTitle
66
- } from 'sindarian-ui'
82
+ } from '@lerianstudio/sindarian-ui'
67
83
 
68
84
  function App() {
69
85
  return (
@@ -80,6 +96,71 @@ function App() {
80
96
  }
81
97
  ```
82
98
 
99
+ ## ⬆️ Migrating to 1.3+
100
+
101
+ What every app upgrading from an earlier version has had to work out.
102
+
103
+ ### Remove `tailwindcss-animate`
104
+
105
+ The library imports `tw-animate-css` in its own `globals.css`. An app that still
106
+ registers the v3-era `@plugin 'tailwindcss-animate'` wins the cascade with its
107
+ `.animate-in` rules and pins every library overlay to that plugin's fixed
108
+ duration, silently. Drop the plugin directive and the dependency.
109
+
110
+ ### `CardTitle` accepts a heading level
111
+
112
+ New: `CardTitle` takes an `as` prop to pick the heading level. It has always
113
+ rendered an `<h3>`, so consumer wrappers that existed only to get a real
114
+ heading element can go — and where `h3` would skip a level under a page
115
+ `<h1>`, set the level directly:
116
+
117
+ ```tsx
118
+ <CardTitle as="h2">Accounts</CardTitle>
119
+ ```
120
+
121
+ The omitted case still renders `h3` with the same classes and `data-slot`.
122
+
123
+ The prop types now match the rendered elements: `CardTitle` is typed against
124
+ `h3` (heading), `CardDescription` against `p` — both were typed against `div`.
125
+ A `ref` typed `Ref<HTMLDivElement>` passed to either no longer compiles;
126
+ retype it to the real element (`HTMLHeadingElement` / `HTMLParagraphElement`).
127
+
128
+ ### `Toaster` follows the app theme
129
+
130
+ An unset `<Toaster />` rendered inside the library's `ThemeProvider` now
131
+ follows the provider's resolved theme instead of the OS preference. Outside a
132
+ provider nothing changes (`system`). To keep OS-following inside a provider,
133
+ pass it explicitly:
134
+
135
+ ```tsx
136
+ <Toaster theme="system" />
137
+ ```
138
+
139
+ ### Non-Next.js apps must load Inter
140
+
141
+ `--font-sans` resolves to
142
+ `var(--font-inter, 'Inter'), 'Inter', ui-sans-serif, system-ui, sans-serif`.
143
+ `--font-inter` is a `next/font` slot: Next.js apps fill it, Vite and other
144
+ bundlers do not. The fallback list keeps text readable, but nothing installs
145
+ Inter for you. Install it (`npm install @fontsource-variable/inter`), load it
146
+ and fill the slot:
147
+
148
+ ```css
149
+ @import '@fontsource-variable/inter';
150
+
151
+ :root {
152
+ --font-inter: 'Inter Variable';
153
+ }
154
+ ```
155
+
156
+ ### The preflight is emitted twice
157
+
158
+ The library's `globals.css` opens with `@import 'tailwindcss'`, so an app that
159
+ also imports Tailwind — as the setup above requires — gets the preflight layer
160
+ twice. The rules are identical and the duplication is harmless, costing roughly
161
+ 8 KB pre-gzip. Keep the app's `@import 'tailwindcss'` first; do not drop it to
162
+ avoid the duplicate.
163
+
83
164
  ## 📚 Component Categories
84
165
 
85
166
  ### UI Primitives
@@ -219,7 +300,7 @@ Please ensure your code follows the project's coding standards and includes appr
219
300
 
220
301
  ## 📝 Changelog
221
302
 
222
- See [CHANGELOG.md](../../CHANGELOG.md) for a detailed history of changes.
303
+ See [CHANGELOG.md](./CHANGELOG.md) for a detailed history of changes.
223
304
 
224
305
  ## 📄 License
225
306
 
@@ -9,10 +9,11 @@ import { type VariantProps } from 'class-variance-authority';
9
9
  */
10
10
  declare const badgeVariants: (props?: ({
11
11
  variant?: "default" | "secondary" | "outline" | "destructive" | "alert" | "success" | "active" | "inactive" | "credit" | "error" | "info" | "purple" | null | undefined;
12
+ size?: "default" | "sm" | null | undefined;
12
13
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
14
  export type BadgeProps = React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & {
14
15
  asChild?: boolean;
15
16
  };
16
- declare function Badge({ className, variant, asChild, ...props }: BadgeProps): React.JSX.Element;
17
+ declare function Badge({ className, variant, size, asChild, ...props }: BadgeProps): React.JSX.Element;
17
18
  export { Badge, badgeVariants };
18
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE;;;;;;GAMG;AACH,QAAA,MAAM,aAAa;;8EAiClB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GACnD,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE5D,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAUnE;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE;;;;;;GAMG;AACH,QAAA,MAAM,aAAa;;;8EA6ClB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GACnD,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE5D,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAUzE;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA"}
@@ -28,14 +28,26 @@ const badgeVariants = (0, class_variance_authority_1.cva)('inline-flex items-cen
28
28
  alert: 'border-system-alert-border bg-system-alert-surface text-system-alert-text px-[10px] py-1',
29
29
  purple: 'border-system-purple-border bg-system-purple-surface text-system-purple-text px-[10px] py-1',
30
30
  outline: 'text-foreground'
31
+ },
32
+ /**
33
+ * Font size only. Padding is baked per-variant above, so a `sm` that also
34
+ * shrank the box would fight every variant that sets its own; scoping the
35
+ * axis to type keeps `sm` composable with all of them. 11px is the canon
36
+ * for fine print — the one micro-badge size, replacing the per-consumer
37
+ * 0.7rem/10px/11px anarchy.
38
+ */
39
+ size: {
40
+ default: '',
41
+ sm: 'text-[11px]'
31
42
  }
32
43
  },
33
44
  defaultVariants: {
34
- variant: 'default'
45
+ variant: 'default',
46
+ size: 'default'
35
47
  }
36
48
  });
37
49
  exports.badgeVariants = badgeVariants;
38
- function Badge({ className, variant, asChild, ...props }) {
50
+ function Badge({ className, variant, size, asChild, ...props }) {
39
51
  const Comp = asChild ? react_slot_1.Slot : 'span';
40
- return ((0, jsx_runtime_1.jsx)(Comp, { "data-slot": "badge", className: (0, utils_1.cn)(badgeVariants({ variant }), className), ...props }));
52
+ return ((0, jsx_runtime_1.jsx)(Comp, { "data-slot": "badge", className: (0, utils_1.cn)(badgeVariants({ variant, size }), className), ...props }));
41
53
  }
@@ -1,8 +1,16 @@
1
1
  import * as React from 'react';
2
2
  declare function Card({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
3
3
  declare function CardHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
4
- declare function CardTitle({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
5
- declare function CardDescription({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
4
+ type CardTitleProps = React.ComponentProps<'h3'> & {
5
+ /**
6
+ * Heading level to render. Defaults to `h3`, which is correct for a card
7
+ * nested under a section heading. Set it when the card sits directly under
8
+ * the page `h1` (or deeper), so the document heading order stays valid.
9
+ */
10
+ as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
11
+ };
12
+ declare function CardTitle({ className, as: Comp, ...props }: CardTitleProps): React.JSX.Element;
13
+ declare function CardDescription({ className, ...props }: React.ComponentProps<'p'>): React.JSX.Element;
6
14
  declare function CardAction({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
7
15
  declare function CardContent({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
8
16
  declare function CardFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/card/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWtE;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQ5E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,EACZ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/card/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,KAAK,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG;IACjD;;;;OAIG;IACH,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAC7C,CAAA;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,IAAW,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,qBAW1E;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,qBAQ1E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,EACZ,CAAA"}
@@ -15,8 +15,8 @@ function Card({ className, ...props }) {
15
15
  function CardHeader({ className, ...props }) {
16
16
  return ((0, jsx_runtime_1.jsx)("div", { "data-slot": "card-header", className: (0, utils_1.cn)('flex flex-col space-y-1.5', className), ...props }));
17
17
  }
18
- function CardTitle({ className, ...props }) {
19
- return ((0, jsx_runtime_1.jsx)("h3", { "data-slot": "card-title", className: (0, utils_1.cn)('text-sm leading-none font-medium tracking-tight', className), ...props }));
18
+ function CardTitle({ className, as: Comp = 'h3', ...props }) {
19
+ return ((0, jsx_runtime_1.jsx)(Comp, { "data-slot": "card-title", className: (0, utils_1.cn)('text-sm leading-none font-medium tracking-tight', className), ...props }));
20
20
  }
21
21
  function CardDescription({ className, ...props }) {
22
22
  return ((0, jsx_runtime_1.jsx)("p", { "data-slot": "card-description", className: (0, utils_1.cn)('text-muted-foreground text-sm', className), ...props }));
@@ -1,4 +1,9 @@
1
1
  type ToasterProps = {
2
+ /**
3
+ * Forces the toast theme. Omit it inside a `ThemeProvider` to follow the
4
+ * resolved theme automatically; with no provider the fallback is `'system'`,
5
+ * leaving the light/dark call to sonner's own media query.
6
+ */
2
7
  theme?: 'light' | 'dark' | 'system';
3
8
  };
4
9
  export declare function Toaster({ theme }: ToasterProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAIA,KAAK,YAAY,GAAG;IAClB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAgB,EAAE,EAAE,YAAY,+BAiBzD"}
1
+ {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,+BAqB9C"}
@@ -4,8 +4,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.Toaster = Toaster;
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  const sonner_1 = require("sonner");
7
- function Toaster({ theme = 'system' }) {
8
- return ((0, jsx_runtime_1.jsx)(sonner_1.Toaster, { theme: theme, position: "bottom-right", visibleToasts: 3, duration: 10000, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
7
+ const theme_provider_1 = require("../../../theme/theme-provider");
8
+ function Toaster({ theme }) {
9
+ // Optional read: a Toaster mounted outside any ThemeProvider must still
10
+ // render, so this cannot go through `useTheme`, which throws.
11
+ const themeContext = (0, theme_provider_1.useOptionalTheme)();
12
+ return ((0, jsx_runtime_1.jsx)(sonner_1.Toaster, { theme: theme ?? themeContext?.resolvedTheme ?? 'system', position: "bottom-right", visibleToasts: 3, duration: 10000, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
9
13
  className: 'font-sans !text-sm !font-medium'
10
14
  } }));
11
15
  }
@@ -46,6 +46,20 @@ export type AppShellProps = {
46
46
  * inside <main> and are correctly page content, not a top-level landmark.
47
47
  */
48
48
  header?: React.ReactNode;
49
+ /**
50
+ * Accessible name for the <header> banner landmark, rendered as its
51
+ * `aria-label`. Omit it and the attribute is absent — the single banner is
52
+ * unambiguous on its own, so a name buys nothing and an unlocalized one costs
53
+ * clarity.
54
+ *
55
+ * Name it when the page carries MORE than one banner-role region (the shell's
56
+ * banner plus, say, an embedded app frame), because a screen-reader landmark
57
+ * list then shows two entries called "banner" with nothing to tell them
58
+ * apart. Also name it when an audit rule demands every landmark be named
59
+ * (`landmark-unique` / a house i18n-strict policy). Pass an ALREADY-TRANSLATED
60
+ * string — the shell does no i18n.
61
+ */
62
+ headerLabel?: string;
49
63
  children: React.ReactNode;
50
64
  className?: string;
51
65
  contentClassName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/enterprise/app-shell/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,QAAQ,mFAgEpB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/enterprise/app-shell/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,QAAQ,mFAoEpB,CAAA"}
@@ -72,14 +72,14 @@ const jsx_runtime_1 = require("react/jsx-runtime");
72
72
  const React = __importStar(require("react"));
73
73
  const sidebar_1 = require("../../components/ui/sidebar");
74
74
  const utils_1 = require("../../lib/utils");
75
- exports.AppShell = React.forwardRef(function AppShell({ sidebar, header, children, className, contentClassName, skipToContentLabel }, ref) {
75
+ exports.AppShell = React.forwardRef(function AppShell({ sidebar, header, headerLabel, children, className, contentClassName, skipToContentLabel }, ref) {
76
76
  // The content <main> id — wires the skip link to its target and gives the
77
77
  // <main> a stable, focusable anchor. Internal: no consumer-facing id prop.
78
78
  const mainId = React.useId();
79
79
  // sindarian-ui's SidebarProvider is context-only (it renders no DOM and
80
80
  // takes no className), so the shell owns the flex row itself and `className`
81
81
  // lands on it — the same element the legacy provider's className reached.
82
- return ((0, jsx_runtime_1.jsx)(sidebar_1.SidebarProvider, { children: (0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex h-svh w-full overflow-hidden', className), children: [skipToContentLabel ? ((0, jsx_runtime_1.jsx)("a", { href: `#${mainId}`, className: "focus:bg-background focus:text-foreground sr-only focus:not-sr-only focus:absolute focus:z-50 focus:m-2 focus:rounded focus:px-3 focus:py-2 focus:shadow", children: skipToContentLabel })) : null, sidebar, (0, jsx_runtime_1.jsxs)("div", { "data-slot": "sidebar-inset", className: "bg-background relative flex w-full min-w-0 flex-1 flex-col", children: [header ? ((0, jsx_runtime_1.jsx)("header", { className: "border-border bg-background sticky top-0 z-10 flex items-center gap-3 border-b px-6 py-3", children: header })) : null, (0, jsx_runtime_1.jsx)("main", { id: mainId, ref: ref, tabIndex: -1,
82
+ return ((0, jsx_runtime_1.jsx)(sidebar_1.SidebarProvider, { children: (0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('flex h-svh w-full overflow-hidden', className), children: [skipToContentLabel ? ((0, jsx_runtime_1.jsx)("a", { href: `#${mainId}`, className: "focus:bg-background focus:text-foreground sr-only focus:not-sr-only focus:absolute focus:z-50 focus:m-2 focus:rounded focus:px-3 focus:py-2 focus:shadow", children: skipToContentLabel })) : null, sidebar, (0, jsx_runtime_1.jsxs)("div", { "data-slot": "sidebar-inset", className: "bg-background relative flex w-full min-w-0 flex-1 flex-col", children: [header ? ((0, jsx_runtime_1.jsx)("header", { "aria-label": headerLabel, className: "border-border bg-background sticky top-0 z-10 flex items-center gap-3 border-b px-6 py-3", children: header })) : null, (0, jsx_runtime_1.jsx)("main", { id: mainId, ref: ref, tabIndex: -1,
83
83
  // min-h-0 lets this flex child shrink below its content height —
84
84
  // without it `flex-1` keeps min-height:auto and nothing scrolls.
85
85
  className: "min-h-0 flex-1 overflow-y-auto outline-none", children: (0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('mx-auto w-full max-w-7xl px-6 py-8 lg:px-8', contentClassName), children: children }) })] })] }) }));
@@ -9,10 +9,11 @@ import { type VariantProps } from 'class-variance-authority';
9
9
  */
10
10
  declare const badgeVariants: (props?: ({
11
11
  variant?: "default" | "secondary" | "outline" | "destructive" | "alert" | "success" | "active" | "inactive" | "credit" | "error" | "info" | "purple" | null | undefined;
12
+ size?: "default" | "sm" | null | undefined;
12
13
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
14
  export type BadgeProps = React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & {
14
15
  asChild?: boolean;
15
16
  };
16
- declare function Badge({ className, variant, asChild, ...props }: BadgeProps): React.JSX.Element;
17
+ declare function Badge({ className, variant, size, asChild, ...props }: BadgeProps): React.JSX.Element;
17
18
  export { Badge, badgeVariants };
18
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE;;;;;;GAMG;AACH,QAAA,MAAM,aAAa;;8EAiClB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GACnD,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE5D,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAUnE;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/badge/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE;;;;;;GAMG;AACH,QAAA,MAAM,aAAa;;;8EA6ClB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GACnD,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE5D,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAUzE;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA"}
@@ -24,14 +24,26 @@ const badgeVariants = cva('inline-flex items-center rounded-full border border-b
24
24
  alert: 'border-system-alert-border bg-system-alert-surface text-system-alert-text px-[10px] py-1',
25
25
  purple: 'border-system-purple-border bg-system-purple-surface text-system-purple-text px-[10px] py-1',
26
26
  outline: 'text-foreground'
27
+ },
28
+ /**
29
+ * Font size only. Padding is baked per-variant above, so a `sm` that also
30
+ * shrank the box would fight every variant that sets its own; scoping the
31
+ * axis to type keeps `sm` composable with all of them. 11px is the canon
32
+ * for fine print — the one micro-badge size, replacing the per-consumer
33
+ * 0.7rem/10px/11px anarchy.
34
+ */
35
+ size: {
36
+ default: '',
37
+ sm: 'text-[11px]'
27
38
  }
28
39
  },
29
40
  defaultVariants: {
30
- variant: 'default'
41
+ variant: 'default',
42
+ size: 'default'
31
43
  }
32
44
  });
33
- function Badge({ className, variant, asChild, ...props }) {
45
+ function Badge({ className, variant, size, asChild, ...props }) {
34
46
  const Comp = asChild ? Slot : 'span';
35
- return (_jsx(Comp, { "data-slot": "badge", className: cn(badgeVariants({ variant }), className), ...props }));
47
+ return (_jsx(Comp, { "data-slot": "badge", className: cn(badgeVariants({ variant, size }), className), ...props }));
36
48
  }
37
49
  export { Badge, badgeVariants };
@@ -1,8 +1,16 @@
1
1
  import * as React from 'react';
2
2
  declare function Card({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
3
3
  declare function CardHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
4
- declare function CardTitle({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
5
- declare function CardDescription({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
4
+ type CardTitleProps = React.ComponentProps<'h3'> & {
5
+ /**
6
+ * Heading level to render. Defaults to `h3`, which is correct for a card
7
+ * nested under a section heading. Set it when the card sits directly under
8
+ * the page `h1` (or deeper), so the document heading order stays valid.
9
+ */
10
+ as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
11
+ };
12
+ declare function CardTitle({ className, as: Comp, ...props }: CardTitleProps): React.JSX.Element;
13
+ declare function CardDescription({ className, ...props }: React.ComponentProps<'p'>): React.JSX.Element;
6
14
  declare function CardAction({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
7
15
  declare function CardContent({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
8
16
  declare function CardFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/card/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWtE;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQ5E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,EACZ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/card/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,KAAK,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG;IACjD;;;;OAIG;IACH,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAC7C,CAAA;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,IAAW,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,qBAW1E;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,qBAQ1E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,EACZ,CAAA"}
@@ -6,8 +6,8 @@ function Card({ className, ...props }) {
6
6
  function CardHeader({ className, ...props }) {
7
7
  return (_jsx("div", { "data-slot": "card-header", className: cn('flex flex-col space-y-1.5', className), ...props }));
8
8
  }
9
- function CardTitle({ className, ...props }) {
10
- return (_jsx("h3", { "data-slot": "card-title", className: cn('text-sm leading-none font-medium tracking-tight', className), ...props }));
9
+ function CardTitle({ className, as: Comp = 'h3', ...props }) {
10
+ return (_jsx(Comp, { "data-slot": "card-title", className: cn('text-sm leading-none font-medium tracking-tight', className), ...props }));
11
11
  }
12
12
  function CardDescription({ className, ...props }) {
13
13
  return (_jsx("p", { "data-slot": "card-description", className: cn('text-muted-foreground text-sm', className), ...props }));
@@ -1,4 +1,9 @@
1
1
  type ToasterProps = {
2
+ /**
3
+ * Forces the toast theme. Omit it inside a `ThemeProvider` to follow the
4
+ * resolved theme automatically; with no provider the fallback is `'system'`,
5
+ * leaving the light/dark call to sonner's own media query.
6
+ */
2
7
  theme?: 'light' | 'dark' | 'system';
3
8
  };
4
9
  export declare function Toaster({ theme }: ToasterProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAIA,KAAK,YAAY,GAAG;IAClB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAgB,EAAE,EAAE,YAAY,+BAiBzD"}
1
+ {"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/toast/toaster.tsx"],"names":[],"mappings":"AAMA,KAAK,YAAY,GAAG;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;CACpC,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,+BAqB9C"}
@@ -1,8 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { Toaster as SonnerToaster } from 'sonner';
4
- export function Toaster({ theme = 'system' }) {
5
- return (_jsx(SonnerToaster, { theme: theme, position: "bottom-right", visibleToasts: 3, duration: 10000, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
4
+ import { useOptionalTheme } from '../../../theme/theme-provider.js';
5
+ export function Toaster({ theme }) {
6
+ // Optional read: a Toaster mounted outside any ThemeProvider must still
7
+ // render, so this cannot go through `useTheme`, which throws.
8
+ const themeContext = useOptionalTheme();
9
+ return (_jsx(SonnerToaster, { theme: theme ?? themeContext?.resolvedTheme ?? 'system', position: "bottom-right", visibleToasts: 3, duration: 10000, expand: false, closeButton: true, richColors: false, offset: 16, gap: 8, toastOptions: {
6
10
  className: 'font-sans !text-sm !font-medium'
7
11
  } }));
8
12
  }
@@ -46,6 +46,20 @@ export type AppShellProps = {
46
46
  * inside <main> and are correctly page content, not a top-level landmark.
47
47
  */
48
48
  header?: React.ReactNode;
49
+ /**
50
+ * Accessible name for the <header> banner landmark, rendered as its
51
+ * `aria-label`. Omit it and the attribute is absent — the single banner is
52
+ * unambiguous on its own, so a name buys nothing and an unlocalized one costs
53
+ * clarity.
54
+ *
55
+ * Name it when the page carries MORE than one banner-role region (the shell's
56
+ * banner plus, say, an embedded app frame), because a screen-reader landmark
57
+ * list then shows two entries called "banner" with nothing to tell them
58
+ * apart. Also name it when an audit rule demands every landmark be named
59
+ * (`landmark-unique` / a house i18n-strict policy). Pass an ALREADY-TRANSLATED
60
+ * string — the shell does no i18n.
61
+ */
62
+ headerLabel?: string;
49
63
  children: React.ReactNode;
50
64
  className?: string;
51
65
  contentClassName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/app-shell/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,QAAQ,mFAgEpB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/app-shell/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED,eAAO,MAAM,QAAQ,mFAoEpB,CAAA"}
@@ -36,14 +36,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
36
36
  import * as React from 'react';
37
37
  import { SidebarProvider } from '../../components/ui/sidebar/index.js';
38
38
  import { cn } from '../../lib/utils.js';
39
- export const AppShell = React.forwardRef(function AppShell({ sidebar, header, children, className, contentClassName, skipToContentLabel }, ref) {
39
+ export const AppShell = React.forwardRef(function AppShell({ sidebar, header, headerLabel, children, className, contentClassName, skipToContentLabel }, ref) {
40
40
  // The content <main> id — wires the skip link to its target and gives the
41
41
  // <main> a stable, focusable anchor. Internal: no consumer-facing id prop.
42
42
  const mainId = React.useId();
43
43
  // sindarian-ui's SidebarProvider is context-only (it renders no DOM and
44
44
  // takes no className), so the shell owns the flex row itself and `className`
45
45
  // lands on it — the same element the legacy provider's className reached.
46
- return (_jsx(SidebarProvider, { children: _jsxs("div", { className: cn('flex h-svh w-full overflow-hidden', className), children: [skipToContentLabel ? (_jsx("a", { href: `#${mainId}`, className: "focus:bg-background focus:text-foreground sr-only focus:not-sr-only focus:absolute focus:z-50 focus:m-2 focus:rounded focus:px-3 focus:py-2 focus:shadow", children: skipToContentLabel })) : null, sidebar, _jsxs("div", { "data-slot": "sidebar-inset", className: "bg-background relative flex w-full min-w-0 flex-1 flex-col", children: [header ? (_jsx("header", { className: "border-border bg-background sticky top-0 z-10 flex items-center gap-3 border-b px-6 py-3", children: header })) : null, _jsx("main", { id: mainId, ref: ref, tabIndex: -1,
46
+ return (_jsx(SidebarProvider, { children: _jsxs("div", { className: cn('flex h-svh w-full overflow-hidden', className), children: [skipToContentLabel ? (_jsx("a", { href: `#${mainId}`, className: "focus:bg-background focus:text-foreground sr-only focus:not-sr-only focus:absolute focus:z-50 focus:m-2 focus:rounded focus:px-3 focus:py-2 focus:shadow", children: skipToContentLabel })) : null, sidebar, _jsxs("div", { "data-slot": "sidebar-inset", className: "bg-background relative flex w-full min-w-0 flex-1 flex-col", children: [header ? (_jsx("header", { "aria-label": headerLabel, className: "border-border bg-background sticky top-0 z-10 flex items-center gap-3 border-b px-6 py-3", children: header })) : null, _jsx("main", { id: mainId, ref: ref, tabIndex: -1,
47
47
  // min-h-0 lets this flex child shrink below its content height —
48
48
  // without it `flex-1` keeps min-height:auto and nothing scrolls.
49
49
  className: "min-h-0 flex-1 overflow-y-auto outline-none", children: _jsx("div", { className: cn('mx-auto w-full max-w-7xl px-6 py-8 lg:px-8', contentClassName), children: children }) })] })] }) }));
@@ -34,5 +34,13 @@ export interface ThemeProviderProps {
34
34
  export declare function ThemeProvider({ children, storageKey, defaultTheme }: ThemeProviderProps): React.JSX.Element;
35
35
  /** Reads the theme context. Throws if used outside a ThemeProvider. */
36
36
  export declare function useTheme(): ThemeContextValue;
37
+ /**
38
+ * Reads the theme context without requiring a provider — `undefined` when
39
+ * there is none. For library components that should follow the theme when one
40
+ * exists but must not force every consumer to mount a ThemeProvider (Toaster).
41
+ * Not re-exported from the package barrel: consumers use `useTheme`, whose
42
+ * throw is the intended signal that the provider is missing.
43
+ */
44
+ export declare function useOptionalTheme(): ThemeContextValue | undefined;
37
45
  export {};
38
46
  //# sourceMappingURL=theme-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-provider.d.ts","sourceRoot":"","sources":["../../../src/theme/theme-provider.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAgBzD,KAAK,iBAAiB,GAAG;IACvB,oEAAoE;IACpE,KAAK,EAAE,eAAe,CAAA;IACtB,yEAAyE;IACzE,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACzC,mDAAmD;IACnD,aAAa,EAAE,OAAO,GAAG,MAAM,CAAA;CAChC,CAAA;AAID,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,YAAY,CAAC,EAAE,eAAe,CAAA;CAC/B;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,UAA8B,EAC9B,YAAuB,EACxB,EAAE,kBAAkB,qBAwFpB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C"}
1
+ {"version":3,"file":"theme-provider.d.ts","sourceRoot":"","sources":["../../../src/theme/theme-provider.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAgBzD,KAAK,iBAAiB,GAAG;IACvB,oEAAoE;IACpE,KAAK,EAAE,eAAe,CAAA;IACtB,yEAAyE;IACzE,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACzC,mDAAmD;IACnD,aAAa,EAAE,OAAO,GAAG,MAAM,CAAA;CAChC,CAAA;AAID,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,YAAY,CAAC,EAAE,eAAe,CAAA;CAC/B;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,UAA8B,EAC9B,YAAuB,EACxB,EAAE,kBAAkB,qBAwFpB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,iBAAiB,GAAG,SAAS,CAEhE"}
@@ -110,3 +110,13 @@ export function useTheme() {
110
110
  }
111
111
  return context;
112
112
  }
113
+ /**
114
+ * Reads the theme context without requiring a provider — `undefined` when
115
+ * there is none. For library components that should follow the theme when one
116
+ * exists but must not force every consumer to mount a ThemeProvider (Toaster).
117
+ * Not re-exported from the package barrel: consumers use `useTheme`, whose
118
+ * throw is the intended signal that the provider is missing.
119
+ */
120
+ export function useOptionalTheme() {
121
+ return React.useContext(ThemeContext) ?? undefined;
122
+ }
package/dist/globals.css CHANGED
@@ -212,6 +212,8 @@
212
212
 
213
213
  @layer base {
214
214
  :root {
215
+ color-scheme: light; /* native widgets (form controls, scrollbars) follow the theme */
216
+
215
217
  /* Application tokens (from Figma ring-tokens) */
216
218
  --body-surface: 240 5% 96%; /* base/100 = #F4F4F5 */
217
219
  --body-text: 240 4% 46%; /* base/500 = #71717A */
@@ -320,6 +322,8 @@
320
322
  }
321
323
 
322
324
  .dark {
325
+ color-scheme: dark; /* native widgets (form controls, scrollbars) follow the theme */
326
+
323
327
  /* Custom — Layout */
324
328
  --link-hover: 240 5% 96%; /* #F4F4F5 80% (opacity via /80) */
325
329
  --link-mute: 240 5% 96%; /* #F4F4F5 40% (opacity via /40) */
@@ -34,5 +34,13 @@ export interface ThemeProviderProps {
34
34
  export declare function ThemeProvider({ children, storageKey, defaultTheme }: ThemeProviderProps): React.JSX.Element;
35
35
  /** Reads the theme context. Throws if used outside a ThemeProvider. */
36
36
  export declare function useTheme(): ThemeContextValue;
37
+ /**
38
+ * Reads the theme context without requiring a provider — `undefined` when
39
+ * there is none. For library components that should follow the theme when one
40
+ * exists but must not force every consumer to mount a ThemeProvider (Toaster).
41
+ * Not re-exported from the package barrel: consumers use `useTheme`, whose
42
+ * throw is the intended signal that the provider is missing.
43
+ */
44
+ export declare function useOptionalTheme(): ThemeContextValue | undefined;
37
45
  export {};
38
46
  //# sourceMappingURL=theme-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-provider.d.ts","sourceRoot":"","sources":["../../src/theme/theme-provider.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAgBzD,KAAK,iBAAiB,GAAG;IACvB,oEAAoE;IACpE,KAAK,EAAE,eAAe,CAAA;IACtB,yEAAyE;IACzE,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACzC,mDAAmD;IACnD,aAAa,EAAE,OAAO,GAAG,MAAM,CAAA;CAChC,CAAA;AAID,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,YAAY,CAAC,EAAE,eAAe,CAAA;CAC/B;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,UAA8B,EAC9B,YAAuB,EACxB,EAAE,kBAAkB,qBAwFpB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C"}
1
+ {"version":3,"file":"theme-provider.d.ts","sourceRoot":"","sources":["../../src/theme/theme-provider.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAgBzD,KAAK,iBAAiB,GAAG;IACvB,oEAAoE;IACpE,KAAK,EAAE,eAAe,CAAA;IACtB,yEAAyE;IACzE,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACzC,mDAAmD;IACnD,aAAa,EAAE,OAAO,GAAG,MAAM,CAAA;CAChC,CAAA;AAID,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,YAAY,CAAC,EAAE,eAAe,CAAA;CAC/B;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,UAA8B,EAC9B,YAAuB,EACxB,EAAE,kBAAkB,qBAwFpB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,iBAAiB,GAAG,SAAS,CAEhE"}
@@ -36,6 +36,7 @@ var __importStar = (this && this.__importStar) || (function () {
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  exports.ThemeProvider = ThemeProvider;
38
38
  exports.useTheme = useTheme;
39
+ exports.useOptionalTheme = useOptionalTheme;
39
40
  const jsx_runtime_1 = require("react/jsx-runtime");
40
41
  /**
41
42
  * ThemeProvider — owns theme preference ('light' | 'dark' | 'system'),
@@ -147,3 +148,13 @@ function useTheme() {
147
148
  }
148
149
  return context;
149
150
  }
151
+ /**
152
+ * Reads the theme context without requiring a provider — `undefined` when
153
+ * there is none. For library components that should follow the theme when one
154
+ * exists but must not force every consumer to mount a ThemeProvider (Toaster).
155
+ * Not re-exported from the package barrel: consumers use `useTheme`, whose
156
+ * throw is the intended signal that the provider is missing.
157
+ */
158
+ function useOptionalTheme() {
159
+ return React.useContext(ThemeContext) ?? undefined;
160
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lerianstudio/sindarian-ui",
3
- "version": "1.3.0-beta.6",
3
+ "version": "1.3.0-beta.7",
4
4
  "description": "Sindarian UI - A UI library for Midaz Console",
5
5
  "license": "ISC",
6
6
  "author": {