@panneau/ui 5.0.0-alpha.2 → 5.0.0-alpha.3

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 CHANGED
@@ -15,11 +15,12 @@ import { Button, PanneauRoot, TextInput, bootstrapTheme } from '@panneau/ui';
15
15
  </PanneauRoot>;
16
16
  ```
17
17
 
18
- | Export | Content |
19
- | --------------------- | ------------------------------------------------------------------------------------------------------- |
20
- | `@panneau/ui` | `PanneauRoot`, themes, the primitives, `Icon`, `getNamedIcon()`, `useToast()`, `usePanneauIntl()` |
21
- | `@panneau/ui/theme` | Themes as data, without components or CSS, for Node: `defineTheme()`, `checkTheme()`, `bootstrapTheme`… |
22
- | `@panneau/ui/locales` | Deprecated: the UI messages by locale, `en` and `fr`. Use `@panneau/intl` |
18
+ | Export | Content |
19
+ | ------------------------- | ------------------------------------------------------------------------------------------------------- |
20
+ | `@panneau/ui` | `PanneauRoot`, themes, the primitives, `Icon`, `getNamedIcon()`, `useToast()`, `usePanneauIntl()` |
21
+ | `@panneau/ui/named-icons` | `lucideIconLoader`: loads any Lucide icon by name, for `PanneauRoot`'s `iconLoader` |
22
+ | `@panneau/ui/theme` | Themes as data, without components or CSS, for Node: `defineTheme()`, `checkTheme()`, `bootstrapTheme`… |
23
+ | `@panneau/ui/locales` | Deprecated: the UI messages by locale, `en` and `fr`. Use `@panneau/intl` |
23
24
 
24
25
  ## Root, tokens and themes
25
26
 
@@ -299,18 +300,23 @@ The theme model is described in [decision 0024](../../docs/decisions/0024-theme-
299
300
 
300
301
  Components take icons as components: any Lucide icon (`icon={Pencil}`), or a component with the same props.
301
302
 
302
- Definitions name their icons (`"icon": "send"`, a name of [lucide.dev/icons](https://lucide.dev/icons)). `getNamedIcon(name)` turns a name into an icon component that goes wherever an icon component goes:
303
+ Definitions name their icons (`"icon": "send"`, a name of [lucide.dev/icons](https://lucide.dev/icons)). `getNamedIcon(name)` turns a name into an icon component that goes wherever an icon component goes, and loads it with the `iconLoader` of `PanneauRoot`:
303
304
 
304
305
  ```tsx
305
- import { Button, getNamedIcon } from '@panneau/ui';
306
+ import { Button, PanneauRoot, getNamedIcon } from '@panneau/ui';
307
+ import { lucideIconLoader } from '@panneau/ui/named-icons';
306
308
 
307
- <Button icon={getNamedIcon('send')}>Send</Button>;
309
+ <PanneauRoot iconLoader={lucideIconLoader}>
310
+ <Button icon={getNamedIcon('send')}>Send</Button>
311
+ </PanneauRoot>;
308
312
  ```
309
313
 
310
- - It loads that one icon the first time it renders, through Lucide's dynamic imports, and renders an empty space of the same size until then. The list of names is loaded on demand too: the whole set is never in the bundle, but bundlers emit one small chunk per icon.
311
- - It returns the same component for the same name. A name Lucide doesn't have renders nothing, with a warning in the console.
312
- - `loadNamedIcon(name)` loads an icon ahead of time, and resolves with its component (or `null`).
313
- - **Vite apps, in development:** add `optimizeDeps: { exclude: ['lucide-react/dynamicIconImports.mjs'] }` to the Vite config. When Vite optimizes it together with `lucide-react`, it splits `lucide-react` into one chunk per icon (about 1,900 requests on every page load). Production builds are not affected.
314
+ - **Loading icons by name is opt-in.** `lucideIconLoader` loads any Lucide icon, one chunk per icon the first time it renders, but bundlers emit a chunk for every Lucide icon (about 1,900) and the map of them in the runtime of every page. So it lives in its own entry point, `@panneau/ui/named-icons`: apps that only pass icon components (`icon={Send}`, `actionIcons`) don't pay for it.
315
+ - An app can instead load only the icons its definitions use: `iconLoader={(name) => Promise.resolve(({ send: Send, archive: Archive })[name] ?? null)}`.
316
+ - Without a loader, a named icon renders an empty space of the same size, with one warning in the console.
317
+ - `getNamedIcon()` returns the same component for the same name, renders an empty space while the icon loads, and nothing for a name the loader doesn't know (with a warning).
318
+ - `loadNamedIcon(name, loader)` loads an icon ahead of time, and resolves with its component (or `null`).
319
+ - **Vite apps, in development:** with `lucideIconLoader`, add `optimizeDeps: { exclude: ['lucide-react/dynamicIconImports.mjs'] }` to the Vite config. When Vite optimizes it together with `lucide-react`, it splits `lucide-react` into one chunk per icon (about 1,900 requests on every page load). Production builds are not affected.
314
320
 
315
321
  ## Messages
316
322
 
@@ -5,7 +5,7 @@
5
5
  min-width: 0;
6
6
  }
7
7
 
8
- .panneau-checkbox {
8
+ .panneau-checkbox-control {
9
9
  display: inline-flex;
10
10
  align-items: flex-start;
11
11
  gap: var(--panneau-space-2);
@@ -16,7 +16,7 @@
16
16
  -webkit-tap-highlight-color: transparent;
17
17
  }
18
18
 
19
- .panneau-checkbox[data-disabled] {
19
+ .panneau-checkbox-control[data-disabled] {
20
20
  cursor: not-allowed;
21
21
  opacity: 0.55;
22
22
  }
@@ -39,26 +39,26 @@
39
39
  border-color var(--panneau-duration);
40
40
  }
41
41
 
42
- .panneau-checkbox[data-hovered] .panneau-checkbox-box {
42
+ .panneau-checkbox-control[data-hovered] .panneau-checkbox-box {
43
43
  border-color: var(--panneau-color-text-muted);
44
44
  }
45
45
 
46
- .panneau-checkbox[data-selected] .panneau-checkbox-box,
47
- .panneau-checkbox[data-indeterminate] .panneau-checkbox-box {
46
+ .panneau-checkbox-control[data-selected] .panneau-checkbox-box,
47
+ .panneau-checkbox-control[data-indeterminate] .panneau-checkbox-box {
48
48
  background-color: var(--panneau-checkbox-checked-bg, var(--panneau-color-accent));
49
49
  border-color: var(--panneau-checkbox-checked-bg, var(--panneau-color-accent));
50
50
  }
51
51
 
52
- .panneau-checkbox[data-invalid] .panneau-checkbox-box {
52
+ .panneau-checkbox-control[data-invalid] .panneau-checkbox-box {
53
53
  border-color: var(--panneau-color-danger);
54
54
  }
55
55
 
56
- .panneau-checkbox[data-focus-visible] .panneau-checkbox-box {
56
+ .panneau-checkbox-control[data-focus-visible] .panneau-checkbox-box {
57
57
  outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
58
58
  outline-offset: 2px;
59
59
  }
60
60
 
61
- .panneau-checkbox[data-readonly] {
61
+ .panneau-checkbox-control[data-readonly] {
62
62
  cursor: default;
63
63
  }
64
64
 
@@ -69,7 +69,7 @@
69
69
 
70
70
  /* Touch screens: a taller row, so the whole label is an easy target. */
71
71
  @media (pointer: coarse) {
72
- .panneau-checkbox {
72
+ .panneau-checkbox-control {
73
73
  min-height: 2.75rem;
74
74
  align-items: center;
75
75
  }
@@ -20,7 +20,7 @@ function Checkbox$1({ children, description, errors = [], className, checkboxCla
20
20
  "aria-describedby": describedBy,
21
21
  isInvalid: errors.length > 0,
22
22
  validationBehavior: "aria",
23
- className: cx(Checkbox_module_default.checkbox, checkboxClassName),
23
+ className: cx(Checkbox_module_default.control, checkboxClassName),
24
24
  children: ({ isSelected, isIndeterminate }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
25
25
  className: Checkbox_module_default.box,
26
26
  "aria-hidden": "true",
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.js","names":["Checkbox","AriaCheckbox","styles","_Fragment"],"sources":["../../src/checkbox/Checkbox.tsx"],"sourcesContent":["import { Check, Minus } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport {\n Checkbox as AriaCheckbox,\n type CheckboxProps as AriaCheckboxProps,\n} from 'react-aria-components';\n\nimport { Icon } from '../icon/Icon';\nimport { cx } from '../utils/cx';\nimport styles from './Checkbox.module.css';\nimport { ChoiceChrome, type ChoiceChromeProps } from './ChoiceChrome';\n\nexport interface CheckboxProps\n extends\n Omit<AriaCheckboxProps, 'className' | 'style' | 'children' | 'isInvalid' | 'validate'>,\n ChoiceChromeProps {\n /** Label, next to the box. */\n children?: ReactNode;\n checkboxClassName?: string;\n}\n\n/** A checkbox with its label, and optional description and errors under it. */\nexport function Checkbox({\n children,\n description,\n errors = [],\n className,\n checkboxClassName,\n descriptionClassName,\n errorsClassName,\n ...props\n}: CheckboxProps) {\n return (\n <ChoiceChrome\n component=\"checkbox\"\n description={description}\n errors={errors}\n className={className}\n descriptionClassName={descriptionClassName}\n errorsClassName={errorsClassName}\n >\n {(describedBy) => (\n <AriaCheckbox\n {...props}\n aria-describedby={describedBy}\n isInvalid={errors.length > 0}\n validationBehavior=\"aria\"\n className={cx(styles.checkbox, checkboxClassName)}\n >\n {({ isSelected, isIndeterminate }) => (\n <>\n <span className={styles.box} aria-hidden=\"true\">\n {isIndeterminate ? (\n <Icon icon={Minus} size=\"xs\" />\n ) : isSelected ? (\n <Icon icon={Check} size=\"xs\" />\n ) : null}\n </span>\n {children !== undefined ? (\n <span className={styles.label}>{children}</span>\n ) : null}\n </>\n )}\n </AriaCheckbox>\n )}\n </ChoiceChrome>\n );\n}\n"],"mappings":";;;;;;;;;AAsBA,SAAgBA,WAAS,EACrB,UACA,aACA,SAAS,CAAA,GACT,WACA,mBACA,sBACA,iBACA,GAAG,SACW;CACd,OACI,oBAAC,cAAD;EACI,WAAU;EACG;EACL;EACG;EACW;EACL;EAEf,WAAA,gBACE,oBAACC,UAAD;GACI,GAAI;GACJ,oBAAkB;GAClB,WAAW,OAAO,SAAS;GAC3B,oBAAmB;GACnB,WAAW,GAAGC,wBAAO,UAAU,iBAAiB;GAE9C,WAAA,EAAE,YAAY,sBACZ,qBAAAC,UAAA,EAAA,UAAA,CACI,oBAAC,QAAD;IAAM,WAAWD,wBAAO;IAAK,eAAY;IACpC,UAAA,kBACG,oBAAC,MAAD;KAAM,MAAM;KAAO,MAAK;IAAI,CAAA,IAC5B,aACA,oBAAC,MAAD;KAAM,MAAM;KAAO,MAAK;IAAI,CAAA,IAC5B;GACF,CAAA,GACL,aAAa,KAAA,IACV,oBAAC,QAAD;IAAM,WAAWA,wBAAO;IAAQ;GAAe,CAAA,IAC/C,IACR,EAAA,CAAA;EAEM,CAAA;CAER,CAAA;AAEtB"}
1
+ {"version":3,"file":"Checkbox.js","names":["Checkbox","AriaCheckbox","styles","_Fragment"],"sources":["../../src/checkbox/Checkbox.tsx"],"sourcesContent":["import { Check, Minus } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport {\n Checkbox as AriaCheckbox,\n type CheckboxProps as AriaCheckboxProps,\n} from 'react-aria-components';\n\nimport { Icon } from '../icon/Icon';\nimport { cx } from '../utils/cx';\nimport styles from './Checkbox.module.css';\nimport { ChoiceChrome, type ChoiceChromeProps } from './ChoiceChrome';\n\nexport interface CheckboxProps\n extends\n Omit<AriaCheckboxProps, 'className' | 'style' | 'children' | 'isInvalid' | 'validate'>,\n ChoiceChromeProps {\n /** Label, next to the box. */\n children?: ReactNode;\n checkboxClassName?: string;\n}\n\n/** A checkbox with its label, and optional description and errors under it. */\nexport function Checkbox({\n children,\n description,\n errors = [],\n className,\n checkboxClassName,\n descriptionClassName,\n errorsClassName,\n ...props\n}: CheckboxProps) {\n return (\n <ChoiceChrome\n component=\"checkbox\"\n description={description}\n errors={errors}\n className={className}\n descriptionClassName={descriptionClassName}\n errorsClassName={errorsClassName}\n >\n {(describedBy) => (\n <AriaCheckbox\n {...props}\n aria-describedby={describedBy}\n isInvalid={errors.length > 0}\n validationBehavior=\"aria\"\n className={cx(styles.control, checkboxClassName)}\n >\n {({ isSelected, isIndeterminate }) => (\n <>\n <span className={styles.box} aria-hidden=\"true\">\n {isIndeterminate ? (\n <Icon icon={Minus} size=\"xs\" />\n ) : isSelected ? (\n <Icon icon={Check} size=\"xs\" />\n ) : null}\n </span>\n {children !== undefined ? (\n <span className={styles.label}>{children}</span>\n ) : null}\n </>\n )}\n </AriaCheckbox>\n )}\n </ChoiceChrome>\n );\n}\n"],"mappings":";;;;;;;;;AAsBA,SAAgBA,WAAS,EACrB,UACA,aACA,SAAS,CAAA,GACT,WACA,mBACA,sBACA,iBACA,GAAG,SACW;CACd,OACI,oBAAC,cAAD;EACI,WAAU;EACG;EACL;EACG;EACW;EACL;EAEf,WAAA,gBACE,oBAACC,UAAD;GACI,GAAI;GACJ,oBAAkB;GAClB,WAAW,OAAO,SAAS;GAC3B,oBAAmB;GACnB,WAAW,GAAGC,wBAAO,SAAS,iBAAiB;GAE7C,WAAA,EAAE,YAAY,sBACZ,qBAAAC,UAAA,EAAA,UAAA,CACI,oBAAC,QAAD;IAAM,WAAWD,wBAAO;IAAK,eAAY;IACpC,UAAA,kBACG,oBAAC,MAAD;KAAM,MAAM;KAAO,MAAK;IAAI,CAAA,IAC5B,aACA,oBAAC,MAAD;KAAM,MAAM;KAAO,MAAK;IAAI,CAAA,IAC5B;GACF,CAAA,GACL,aAAa,KAAA,IACV,oBAAC,QAAD;IAAM,WAAWA,wBAAO;IAAQ;GAAe,CAAA,IAC/C,IACR,EAAA,CAAA;EAEM,CAAA;CAER,CAAA;AAEtB"}
@@ -1,16 +1,16 @@
1
1
  import "./Checkbox.css";
2
2
  //#region src/checkbox/Checkbox.module.css
3
3
  var field = "panneau-checkbox-field";
4
- var checkbox = "panneau-checkbox";
4
+ var control = "panneau-checkbox-control";
5
5
  var box = "panneau-checkbox-box";
6
6
  var label = "panneau-checkbox-label";
7
7
  var Checkbox_module_default = {
8
8
  field,
9
- checkbox,
9
+ control,
10
10
  box,
11
11
  label
12
12
  };
13
13
  //#endregion
14
- export { box, checkbox, Checkbox_module_default as default, field, label };
14
+ export { box, control, Checkbox_module_default as default, field, label };
15
15
 
16
16
  //# sourceMappingURL=Checkbox.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.module.js","names":[],"sources":["../../src/checkbox/Checkbox.module.css"],"sourcesContent":[".field {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n min-width: 0;\n}\n\n.checkbox {\n display: inline-flex;\n align-items: flex-start;\n gap: var(--panneau-space-2);\n min-height: 1.5rem;\n font-size: var(--panneau-font-size-md);\n color: var(--panneau-color-text);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.checkbox[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.box {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: var(--panneau-checkbox-size, 1.125rem);\n height: var(--panneau-checkbox-size, 1.125rem);\n margin-top: 0.125rem;\n color: var(--panneau-checkbox-checked-color, var(--panneau-color-accent-text));\n background-color: var(--panneau-checkbox-bg, var(--panneau-color-surface));\n border: var(--panneau-border-width) solid\n var(--panneau-checkbox-border-color, var(--panneau-color-border-control));\n border-radius: var(--panneau-checkbox-radius, var(--panneau-radius-sm));\n transition:\n background-color var(--panneau-duration),\n border-color var(--panneau-duration);\n}\n\n.checkbox[data-hovered] .box {\n border-color: var(--panneau-color-text-muted);\n}\n\n.checkbox[data-selected] .box,\n.checkbox[data-indeterminate] .box {\n background-color: var(--panneau-checkbox-checked-bg, var(--panneau-color-accent));\n border-color: var(--panneau-checkbox-checked-bg, var(--panneau-color-accent));\n}\n\n.checkbox[data-invalid] .box {\n border-color: var(--panneau-color-danger);\n}\n\n.checkbox[data-focus-visible] .box {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.checkbox[data-readonly] {\n cursor: default;\n}\n\n.label {\n line-height: var(--panneau-line-height);\n overflow-wrap: anywhere;\n}\n\n/* Touch screens: a taller row, so the whole label is an easy target. */\n@media (pointer: coarse) {\n .checkbox {\n min-height: 2.75rem;\n align-items: center;\n }\n\n .box {\n margin-top: 0;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Checkbox.module.js","names":[],"sources":["../../src/checkbox/Checkbox.module.css"],"sourcesContent":[".field {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n min-width: 0;\n}\n\n.control {\n display: inline-flex;\n align-items: flex-start;\n gap: var(--panneau-space-2);\n min-height: 1.5rem;\n font-size: var(--panneau-font-size-md);\n color: var(--panneau-color-text);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.control[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.box {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: var(--panneau-checkbox-size, 1.125rem);\n height: var(--panneau-checkbox-size, 1.125rem);\n margin-top: 0.125rem;\n color: var(--panneau-checkbox-checked-color, var(--panneau-color-accent-text));\n background-color: var(--panneau-checkbox-bg, var(--panneau-color-surface));\n border: var(--panneau-border-width) solid\n var(--panneau-checkbox-border-color, var(--panneau-color-border-control));\n border-radius: var(--panneau-checkbox-radius, var(--panneau-radius-sm));\n transition:\n background-color var(--panneau-duration),\n border-color var(--panneau-duration);\n}\n\n.control[data-hovered] .box {\n border-color: var(--panneau-color-text-muted);\n}\n\n.control[data-selected] .box,\n.control[data-indeterminate] .box {\n background-color: var(--panneau-checkbox-checked-bg, var(--panneau-color-accent));\n border-color: var(--panneau-checkbox-checked-bg, var(--panneau-color-accent));\n}\n\n.control[data-invalid] .box {\n border-color: var(--panneau-color-danger);\n}\n\n.control[data-focus-visible] .box {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.control[data-readonly] {\n cursor: default;\n}\n\n.label {\n line-height: var(--panneau-line-height);\n overflow-wrap: anywhere;\n}\n\n/* Touch screens: a taller row, so the whole label is an easy target. */\n@media (pointer: coarse) {\n .control {\n min-height: 2.75rem;\n align-items: center;\n }\n\n .box {\n margin-top: 0;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import type { NamedIconLoader } from './namedIcons';
2
+ /**
3
+ * Loads any Lucide icon by its name (the names of lucide.dev/icons). Each icon is its own chunk,
4
+ * and so is the list of names, loaded the first time an icon is named. Bundlers emit a chunk per
5
+ * Lucide icon for it, so it lives in its own entry point: only apps that pass it to `PanneauRoot`
6
+ * pay for it.
7
+ */
8
+ export declare const lucideIconLoader: NamedIconLoader;
9
+ //# sourceMappingURL=lucideIconLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucideIconLoader.d.ts","sourceRoot":"","sources":["../../src/icon/lucideIconLoader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAMpD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAY9B,CAAC"}
@@ -0,0 +1,22 @@
1
+ //#region src/icon/lucideIconLoader.ts
2
+ var imports = null;
3
+ /**
4
+ * Loads any Lucide icon by its name (the names of lucide.dev/icons). Each icon is its own chunk,
5
+ * and so is the list of names, loaded the first time an icon is named. Bundlers emit a chunk per
6
+ * Lucide icon for it, so it lives in its own entry point: only apps that pass it to `PanneauRoot`
7
+ * pay for it.
8
+ */
9
+ var lucideIconLoader = (name) => {
10
+ imports ??= import("lucide-react/dynamicIconImports.mjs").then((module) => module.default, (error) => {
11
+ imports = null;
12
+ throw error;
13
+ });
14
+ return imports.then((all) => {
15
+ const load = Object.hasOwn(all, name) ? all[name] : void 0;
16
+ return load !== void 0 ? load().then((module) => module.default) : null;
17
+ });
18
+ };
19
+ //#endregion
20
+ export { lucideIconLoader };
21
+
22
+ //# sourceMappingURL=lucideIconLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucideIconLoader.js","names":[],"sources":["../../src/icon/lucideIconLoader.ts"],"sourcesContent":["import type { IconComponent } from './Icon';\nimport type { NamedIconLoader } from './namedIcons';\n\ntype IconImports = Readonly<Record<string, () => Promise<{ default: IconComponent }>>>;\n\nlet imports: Promise<IconImports> | null = null;\n\n/**\n * Loads any Lucide icon by its name (the names of lucide.dev/icons). Each icon is its own chunk,\n * and so is the list of names, loaded the first time an icon is named. Bundlers emit a chunk per\n * Lucide icon for it, so it lives in its own entry point: only apps that pass it to `PanneauRoot`\n * pay for it.\n */\nexport const lucideIconLoader: NamedIconLoader = (name) => {\n imports ??= import('lucide-react/dynamicIconImports.mjs').then(\n (module) => module.default as unknown as IconImports,\n (error: unknown) => {\n imports = null;\n throw error;\n },\n );\n return imports.then((all) => {\n const load = Object.hasOwn(all, name) ? all[name] : undefined;\n return load !== undefined ? load().then((module) => module.default) : null;\n });\n};\n"],"mappings":";AAKA,IAAI,UAAuC;;;;;;;AAQ3C,IAAa,oBAAqC,SAAS;CACvD,YAAY,OAAO,sCAAsC,CAAC,MACrD,WAAW,OAAO,UAClB,UAAmB;EAChB,UAAU;EACV,MAAM;CACV,CACJ;CACA,OAAO,QAAQ,MAAM,QAAQ;EACzB,MAAM,OAAO,OAAO,OAAO,KAAK,IAAI,IAAI,IAAI,QAAQ,KAAA;EACpD,OAAO,SAAS,KAAA,IAAY,KAAK,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO,IAAI;CAC1E,CAAC;AACL"}
@@ -1,16 +1,23 @@
1
1
  import type { IconComponent } from './Icon';
2
2
  /**
3
- * Loads a Lucide icon by its name (`send`, `calendar-days`: the names of lucide.dev/icons), and
4
- * resolves with its component, or with `null` for a name Lucide doesn't have. Each icon is its own
5
- * module, and so is the list of names: neither is in the bundle until a named icon is used.
3
+ * Loads an icon component from its name, as definitions name icons (`"icon": "send"`), or
4
+ * resolves with `null` for a name it doesn't know. `lucideIconLoader` of `@panneau/ui/named-icons`
5
+ * loads any Lucide icon; an app can load only the icons its definitions use.
6
6
  */
7
- export declare function loadNamedIcon(name: string): Promise<IconComponent | null>;
7
+ export type NamedIconLoader = (name: string) => Promise<IconComponent | null>;
8
+ /** The loader of named icons, set by `PanneauRoot`'s `iconLoader`. */
9
+ export declare const NamedIconLoaderContext: import("react").Context<NamedIconLoader | null>;
8
10
  /**
9
- * An icon component for a Lucide icon name, as definitions name them (`"icon": "send"`). It goes
11
+ * Loads an icon by its name with a loader, once per loader and name, and resolves with its
12
+ * component, or with `null` for a name the loader doesn't know.
13
+ */
14
+ export declare function loadNamedIcon(name: string, loader: NamedIconLoader): Promise<IconComponent | null>;
15
+ /**
16
+ * An icon component for an icon name, as definitions name them (`"icon": "send"`). It goes
10
17
  * wherever an icon component goes (`<Button icon={getNamedIcon('send')}>`), and is the same
11
- * component for the same name. It loads the icon the first time it renders (`loadNamedIcon()`),
12
- * and renders an empty space of the same size until then. A name Lucide doesn't have renders
13
- * nothing.
18
+ * component for the same name. It loads the icon with the `iconLoader` of `PanneauRoot` the first
19
+ * time it renders, and renders an empty space of the same size until then, or without a loader. A
20
+ * name the loader doesn't know renders nothing.
14
21
  */
15
22
  export declare function getNamedIcon(name: string): IconComponent;
16
23
  //# sourceMappingURL=namedIcons.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"namedIcons.d.ts","sourceRoot":"","sources":["../../src/icon/namedIcons.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAwB5C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAoCzE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAwCxD"}
1
+ {"version":3,"file":"namedIcons.d.ts","sourceRoot":"","sources":["../../src/icon/namedIcons.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;AAU9E,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,iDAA8C,CAAC;AA2BlF;;;GAGG;AACH,wBAAgB,aAAa,CACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,GACxB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CA2B/B;AAID;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAkDxD"}
@@ -1,64 +1,78 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useEffect, useSyncExternalStore } from "react";
2
+ import { createContext, use, useEffect, useSyncExternalStore } from "react";
3
3
  //#region src/icon/namedIcons.tsx
4
- var entries = /* @__PURE__ */ new Map();
4
+ /** Icons by name, for each loader. */
5
+ var caches = /* @__PURE__ */ new WeakMap();
5
6
  var components = /* @__PURE__ */ new Map();
6
7
  var listeners = /* @__PURE__ */ new Set();
7
- var imports = null;
8
+ /** The loader of named icons, set by `PanneauRoot`'s `iconLoader`. */
9
+ var NamedIconLoaderContext = createContext(null);
10
+ function cache(loader) {
11
+ let entries = caches.get(loader);
12
+ if (entries === void 0) {
13
+ entries = /* @__PURE__ */ new Map();
14
+ caches.set(loader, entries);
15
+ }
16
+ return entries;
17
+ }
8
18
  function subscribe(listener) {
9
19
  listeners.add(listener);
10
20
  return () => {
11
21
  listeners.delete(listener);
12
22
  };
13
23
  }
14
- function setEntry(name, entry) {
15
- entries.set(name, entry);
24
+ function setEntry(loader, name, entry) {
25
+ if (entry === void 0) cache(loader).delete(name);
26
+ else cache(loader).set(name, entry);
16
27
  listeners.forEach((listener) => listener());
17
28
  }
18
29
  /**
19
- * Loads a Lucide icon by its name (`send`, `calendar-days`: the names of lucide.dev/icons), and
20
- * resolves with its component, or with `null` for a name Lucide doesn't have. Each icon is its own
21
- * module, and so is the list of names: neither is in the bundle until a named icon is used.
30
+ * Loads an icon by its name with a loader, once per loader and name, and resolves with its
31
+ * component, or with `null` for a name the loader doesn't know.
22
32
  */
23
- function loadNamedIcon(name) {
24
- const entry = entries.get(name);
33
+ function loadNamedIcon(name, loader) {
34
+ const entry = cache(loader).get(name);
25
35
  if (entry?.status === "loaded") return Promise.resolve(entry.icon);
26
36
  if (entry?.status === "missing") return Promise.resolve(null);
27
- if (entry === void 0) setEntry(name, { status: "loading" });
28
- imports ??= import("lucide-react/dynamicIconImports.mjs").then((module) => module.default);
29
- return imports.then((all) => {
30
- const load = Object.hasOwn(all, name) ? all[name] : void 0;
31
- return load !== void 0 ? load().then((module) => module.default) : null;
32
- }).then((icon) => {
37
+ if (entry === void 0) setEntry(loader, name, { status: "loading" });
38
+ return loader(name).then((icon) => {
33
39
  if (icon === null) {
34
- console.warn(`[panneau] Lucide has no icon named "${name}".`);
35
- setEntry(name, { status: "missing" });
36
- } else setEntry(name, {
40
+ console.warn(`[panneau] No icon named "${name}".`);
41
+ setEntry(loader, name, { status: "missing" });
42
+ } else setEntry(loader, name, {
37
43
  status: "loaded",
38
44
  icon
39
45
  });
40
46
  return icon;
41
47
  }, (error) => {
42
- entries.delete(name);
43
- imports = null;
48
+ setEntry(loader, name, void 0);
44
49
  throw error;
45
50
  });
46
51
  }
52
+ var warnedWithoutLoader = false;
47
53
  /**
48
- * An icon component for a Lucide icon name, as definitions name them (`"icon": "send"`). It goes
54
+ * An icon component for an icon name, as definitions name them (`"icon": "send"`). It goes
49
55
  * wherever an icon component goes (`<Button icon={getNamedIcon('send')}>`), and is the same
50
- * component for the same name. It loads the icon the first time it renders (`loadNamedIcon()`),
51
- * and renders an empty space of the same size until then. A name Lucide doesn't have renders
52
- * nothing.
56
+ * component for the same name. It loads the icon with the `iconLoader` of `PanneauRoot` the first
57
+ * time it renders, and renders an empty space of the same size until then, or without a loader. A
58
+ * name the loader doesn't know renders nothing.
53
59
  */
54
60
  function getNamedIcon(name) {
55
61
  const existing = components.get(name);
56
62
  if (existing !== void 0) return existing;
57
63
  const NamedIcon = ({ size = 24, className, ...props }) => {
58
- const entry = useSyncExternalStore(subscribe, () => entries.get(name), () => entries.get(name));
64
+ const loader = use(NamedIconLoaderContext);
65
+ const entry = useSyncExternalStore(subscribe, () => loader !== null ? cache(loader).get(name) : void 0, () => loader !== null ? cache(loader).get(name) : void 0);
59
66
  useEffect(() => {
60
- if (entries.get(name) === void 0) loadNamedIcon(name).catch(() => void 0);
61
- }, []);
67
+ if (loader === null) {
68
+ if (!warnedWithoutLoader) {
69
+ warnedWithoutLoader = true;
70
+ console.warn(`[panneau] The icon "${name}" is named, but PanneauRoot has no iconLoader: pass lucideIconLoader from @panneau/ui/named-icons.`);
71
+ }
72
+ return;
73
+ }
74
+ if (cache(loader).get(name) === void 0) loadNamedIcon(name, loader).catch(() => void 0);
75
+ }, [loader]);
62
76
  if (entry?.status === "loaded") {
63
77
  const Loaded = entry.icon;
64
78
  return /* @__PURE__ */ jsx(Loaded, {
@@ -85,6 +99,6 @@ function getNamedIcon(name) {
85
99
  return NamedIcon;
86
100
  }
87
101
  //#endregion
88
- export { getNamedIcon, loadNamedIcon };
102
+ export { NamedIconLoaderContext, getNamedIcon, loadNamedIcon };
89
103
 
90
104
  //# sourceMappingURL=namedIcons.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"namedIcons.js","names":[],"sources":["../../src/icon/namedIcons.tsx"],"sourcesContent":["import { useEffect, useSyncExternalStore } from 'react';\n\nimport type { IconComponent } from './Icon';\n\ntype IconImports = Readonly<Record<string, () => Promise<{ default: IconComponent }>>>;\n\ntype Entry =\n { status: 'loading' } | { status: 'loaded'; icon: IconComponent } | { status: 'missing' };\n\nconst entries = new Map<string, Entry>();\nconst components = new Map<string, IconComponent>();\nconst listeners = new Set<() => void>();\nlet imports: Promise<IconImports> | null = null;\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nfunction setEntry(name: string, entry: Entry) {\n entries.set(name, entry);\n listeners.forEach((listener) => listener());\n}\n\n/**\n * Loads a Lucide icon by its name (`send`, `calendar-days`: the names of lucide.dev/icons), and\n * resolves with its component, or with `null` for a name Lucide doesn't have. Each icon is its own\n * module, and so is the list of names: neither is in the bundle until a named icon is used.\n */\nexport function loadNamedIcon(name: string): Promise<IconComponent | null> {\n const entry = entries.get(name);\n if (entry?.status === 'loaded') {\n return Promise.resolve(entry.icon);\n }\n if (entry?.status === 'missing') {\n return Promise.resolve(null);\n }\n if (entry === undefined) {\n setEntry(name, { status: 'loading' });\n }\n imports ??= import('lucide-react/dynamicIconImports.mjs').then(\n (module) => module.default as unknown as IconImports,\n );\n return imports\n .then((all) => {\n const load = Object.hasOwn(all, name) ? all[name] : undefined;\n return load !== undefined ? load().then((module) => module.default) : null;\n })\n .then(\n (icon) => {\n if (icon === null) {\n console.warn(`[panneau] Lucide has no icon named \"${name}\".`);\n setEntry(name, { status: 'missing' });\n } else {\n setEntry(name, { status: 'loaded', icon });\n }\n return icon;\n },\n (error: unknown) => {\n // A chunk that failed to load (offline): the icon is loaded again when it mounts.\n entries.delete(name);\n imports = null;\n throw error;\n },\n );\n}\n\n/**\n * An icon component for a Lucide icon name, as definitions name them (`\"icon\": \"send\"`). It goes\n * wherever an icon component goes (`<Button icon={getNamedIcon('send')}>`), and is the same\n * component for the same name. It loads the icon the first time it renders (`loadNamedIcon()`),\n * and renders an empty space of the same size until then. A name Lucide doesn't have renders\n * nothing.\n */\nexport function getNamedIcon(name: string): IconComponent {\n const existing = components.get(name);\n if (existing !== undefined) {\n return existing;\n }\n const NamedIcon: IconComponent = ({ size = 24, className, ...props }) => {\n const entry = useSyncExternalStore(\n subscribe,\n () => entries.get(name),\n () => entries.get(name),\n );\n useEffect(() => {\n if (entries.get(name) === undefined) {\n loadNamedIcon(name).catch(() => undefined);\n }\n }, []);\n if (entry?.status === 'loaded') {\n const Loaded = entry.icon;\n return <Loaded size={size} className={className} {...props} />;\n }\n if (entry?.status === 'missing') {\n return null;\n }\n const { 'aria-hidden': hidden, 'aria-label': label, role } = props;\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n className={className}\n aria-hidden={hidden}\n aria-label={label}\n role={role}\n data-loading=\"\"\n />\n );\n };\n NamedIcon.displayName = `NamedIcon(${name})`;\n components.set(name, NamedIcon);\n return NamedIcon;\n}\n"],"mappings":";;;AASA,IAAM,0BAAU,IAAI,IAAmB;AACvC,IAAM,6BAAa,IAAI,IAA2B;AAClD,IAAM,4BAAY,IAAI,IAAgB;AACtC,IAAI,UAAuC;AAE3C,SAAS,UAAU,UAAkC;CACjD,UAAU,IAAI,QAAQ;CACtB,aAAa;EACT,UAAU,OAAO,QAAQ;CAC7B;AACJ;AAEA,SAAS,SAAS,MAAc,OAAc;CAC1C,QAAQ,IAAI,MAAM,KAAK;CACvB,UAAU,SAAS,aAAa,SAAS,CAAC;AAC9C;;;;;;AAOA,SAAgB,cAAc,MAA6C;CACvE,MAAM,QAAQ,QAAQ,IAAI,IAAI;CAC9B,IAAI,OAAO,WAAW,UAClB,OAAO,QAAQ,QAAQ,MAAM,IAAI;CAErC,IAAI,OAAO,WAAW,WAClB,OAAO,QAAQ,QAAQ,IAAI;CAE/B,IAAI,UAAU,KAAA,GACV,SAAS,MAAM,EAAE,QAAQ,UAAU,CAAC;CAExC,YAAY,OAAO,sCAAsC,CAAC,MACrD,WAAW,OAAO,OACvB;CACA,OAAO,QACF,MAAM,QAAQ;EACX,MAAM,OAAO,OAAO,OAAO,KAAK,IAAI,IAAI,IAAI,QAAQ,KAAA;EACpD,OAAO,SAAS,KAAA,IAAY,KAAK,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO,IAAI;CAC1E,CAAC,CAAC,CACD,MACI,SAAS;EACN,IAAI,SAAS,MAAM;GACf,QAAQ,KAAK,uCAAuC,KAAI,GAAI;GAC5D,SAAS,MAAM,EAAE,QAAQ,UAAU,CAAC;EACxC,OACI,SAAS,MAAM;GAAE,QAAQ;GAAU;EAAK,CAAC;EAE7C,OAAO;CACX,IACC,UAAmB;EAEhB,QAAQ,OAAO,IAAI;EACnB,UAAU;EACV,MAAM;CACV,CACJ;AACR;;;;;;;;AASA,SAAgB,aAAa,MAA6B;CACtD,MAAM,WAAW,WAAW,IAAI,IAAI;CACpC,IAAI,aAAa,KAAA,GACb,OAAO;CAEX,MAAM,aAA4B,EAAE,OAAO,IAAI,WAAW,GAAG,YAAY;EACrE,MAAM,QAAQ,qBACV,iBACM,QAAQ,IAAI,IAAI,SAChB,QAAQ,IAAI,IAAI,CAC1B;EACA,gBAAgB;GACZ,IAAI,QAAQ,IAAI,IAAI,MAAM,KAAA,GACtB,cAAc,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;EAEjD,GAAG,CAAA,CAAE;EACL,IAAI,OAAO,WAAW,UAAU;GAC5B,MAAM,SAAS,MAAM;GACrB,OAAO,oBAAC,QAAD;IAAc;IAAiB;IAAW,GAAI;GAAM,CAAA;EAC/D;EACA,IAAI,OAAO,WAAW,WAClB,OAAO;EAEX,MAAM,EAAE,eAAe,QAAQ,cAAc,OAAO,SAAS;EAC7D,OACI,oBAAC,OAAD;GACI,OAAO;GACP,QAAQ;GACR,SAAQ;GACG;GACX,eAAa;GACb,cAAY;GACN;GACN,gBAAa;EAAE,CAAA;CAG3B;CACA,UAAU,cAAc,aAAa,KAAI;CACzC,WAAW,IAAI,MAAM,SAAS;CAC9B,OAAO;AACX"}
1
+ {"version":3,"file":"namedIcons.js","names":[],"sources":["../../src/icon/namedIcons.tsx"],"sourcesContent":["import { createContext, use, useEffect, useSyncExternalStore } from 'react';\n\nimport type { IconComponent } from './Icon';\n\n/**\n * Loads an icon component from its name, as definitions name icons (`\"icon\": \"send\"`), or\n * resolves with `null` for a name it doesn't know. `lucideIconLoader` of `@panneau/ui/named-icons`\n * loads any Lucide icon; an app can load only the icons its definitions use.\n */\nexport type NamedIconLoader = (name: string) => Promise<IconComponent | null>;\n\ntype Entry =\n { status: 'loading' } | { status: 'loaded'; icon: IconComponent } | { status: 'missing' };\n\n/** Icons by name, for each loader. */\nconst caches = new WeakMap<NamedIconLoader, Map<string, Entry>>();\nconst components = new Map<string, IconComponent>();\nconst listeners = new Set<() => void>();\n\n/** The loader of named icons, set by `PanneauRoot`'s `iconLoader`. */\nexport const NamedIconLoaderContext = createContext<NamedIconLoader | null>(null);\n\nfunction cache(loader: NamedIconLoader): Map<string, Entry> {\n let entries = caches.get(loader);\n if (entries === undefined) {\n entries = new Map();\n caches.set(loader, entries);\n }\n return entries;\n}\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nfunction setEntry(loader: NamedIconLoader, name: string, entry: Entry | undefined) {\n if (entry === undefined) {\n cache(loader).delete(name);\n } else {\n cache(loader).set(name, entry);\n }\n listeners.forEach((listener) => listener());\n}\n\n/**\n * Loads an icon by its name with a loader, once per loader and name, and resolves with its\n * component, or with `null` for a name the loader doesn't know.\n */\nexport function loadNamedIcon(\n name: string,\n loader: NamedIconLoader,\n): Promise<IconComponent | null> {\n const entry = cache(loader).get(name);\n if (entry?.status === 'loaded') {\n return Promise.resolve(entry.icon);\n }\n if (entry?.status === 'missing') {\n return Promise.resolve(null);\n }\n if (entry === undefined) {\n setEntry(loader, name, { status: 'loading' });\n }\n return loader(name).then(\n (icon) => {\n if (icon === null) {\n console.warn(`[panneau] No icon named \"${name}\".`);\n setEntry(loader, name, { status: 'missing' });\n } else {\n setEntry(loader, name, { status: 'loaded', icon });\n }\n return icon;\n },\n (error: unknown) => {\n // A chunk that failed to load (offline): the icon is loaded again when it mounts.\n setEntry(loader, name, undefined);\n throw error;\n },\n );\n}\n\nlet warnedWithoutLoader = false;\n\n/**\n * An icon component for an icon name, as definitions name them (`\"icon\": \"send\"`). It goes\n * wherever an icon component goes (`<Button icon={getNamedIcon('send')}>`), and is the same\n * component for the same name. It loads the icon with the `iconLoader` of `PanneauRoot` the first\n * time it renders, and renders an empty space of the same size until then, or without a loader. A\n * name the loader doesn't know renders nothing.\n */\nexport function getNamedIcon(name: string): IconComponent {\n const existing = components.get(name);\n if (existing !== undefined) {\n return existing;\n }\n const NamedIcon: IconComponent = ({ size = 24, className, ...props }) => {\n const loader = use(NamedIconLoaderContext);\n const entry = useSyncExternalStore(\n subscribe,\n () => (loader !== null ? cache(loader).get(name) : undefined),\n () => (loader !== null ? cache(loader).get(name) : undefined),\n );\n useEffect(() => {\n if (loader === null) {\n if (!warnedWithoutLoader) {\n warnedWithoutLoader = true;\n console.warn(\n `[panneau] The icon \"${name}\" is named, but PanneauRoot has no iconLoader: pass lucideIconLoader from @panneau/ui/named-icons.`,\n );\n }\n return;\n }\n if (cache(loader).get(name) === undefined) {\n loadNamedIcon(name, loader).catch(() => undefined);\n }\n }, [loader]);\n if (entry?.status === 'loaded') {\n const Loaded = entry.icon;\n return <Loaded size={size} className={className} {...props} />;\n }\n if (entry?.status === 'missing') {\n return null;\n }\n const { 'aria-hidden': hidden, 'aria-label': label, role } = props;\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n className={className}\n aria-hidden={hidden}\n aria-label={label}\n role={role}\n data-loading=\"\"\n />\n );\n };\n NamedIcon.displayName = `NamedIcon(${name})`;\n components.set(name, NamedIcon);\n return NamedIcon;\n}\n"],"mappings":";;;;AAeA,IAAM,yBAAS,IAAI,QAA6C;AAChE,IAAM,6BAAa,IAAI,IAA2B;AAClD,IAAM,4BAAY,IAAI,IAAgB;;AAGtC,IAAa,yBAAyB,cAAsC,IAAI;AAEhF,SAAS,MAAM,QAA6C;CACxD,IAAI,UAAU,OAAO,IAAI,MAAM;CAC/B,IAAI,YAAY,KAAA,GAAW;EACvB,0BAAU,IAAI,IAAI;EAClB,OAAO,IAAI,QAAQ,OAAO;CAC9B;CACA,OAAO;AACX;AAEA,SAAS,UAAU,UAAkC;CACjD,UAAU,IAAI,QAAQ;CACtB,aAAa;EACT,UAAU,OAAO,QAAQ;CAC7B;AACJ;AAEA,SAAS,SAAS,QAAyB,MAAc,OAA0B;CAC/E,IAAI,UAAU,KAAA,GACV,MAAM,MAAM,CAAC,CAAC,OAAO,IAAI;MAEzB,MAAM,MAAM,CAAC,CAAC,IAAI,MAAM,KAAK;CAEjC,UAAU,SAAS,aAAa,SAAS,CAAC;AAC9C;;;;;AAMA,SAAgB,cACZ,MACA,QAC6B;CAC7B,MAAM,QAAQ,MAAM,MAAM,CAAC,CAAC,IAAI,IAAI;CACpC,IAAI,OAAO,WAAW,UAClB,OAAO,QAAQ,QAAQ,MAAM,IAAI;CAErC,IAAI,OAAO,WAAW,WAClB,OAAO,QAAQ,QAAQ,IAAI;CAE/B,IAAI,UAAU,KAAA,GACV,SAAS,QAAQ,MAAM,EAAE,QAAQ,UAAU,CAAC;CAEhD,OAAO,OAAO,IAAI,CAAC,CAAC,MACf,SAAS;EACN,IAAI,SAAS,MAAM;GACf,QAAQ,KAAK,4BAA4B,KAAI,GAAI;GACjD,SAAS,QAAQ,MAAM,EAAE,QAAQ,UAAU,CAAC;EAChD,OACI,SAAS,QAAQ,MAAM;GAAE,QAAQ;GAAU;EAAK,CAAC;EAErD,OAAO;CACX,IACC,UAAmB;EAEhB,SAAS,QAAQ,MAAM,KAAA,CAAS;EAChC,MAAM;CACV,CACJ;AACJ;AAEA,IAAI,sBAAsB;;;;;;;;AAS1B,SAAgB,aAAa,MAA6B;CACtD,MAAM,WAAW,WAAW,IAAI,IAAI;CACpC,IAAI,aAAa,KAAA,GACb,OAAO;CAEX,MAAM,aAA4B,EAAE,OAAO,IAAI,WAAW,GAAG,YAAY;EACrE,MAAM,SAAS,IAAI,sBAAsB;EACzC,MAAM,QAAQ,qBACV,iBACO,WAAW,OAAO,MAAM,MAAM,CAAC,CAAC,IAAI,IAAI,IAAI,KAAA,SAC5C,WAAW,OAAO,MAAM,MAAM,CAAC,CAAC,IAAI,IAAI,IAAI,KAAA,CACvD;EACA,gBAAgB;GACZ,IAAI,WAAW,MAAM;IACjB,IAAI,CAAC,qBAAqB;KACtB,sBAAsB;KACtB,QAAQ,KACJ,uBAAuB,KAAI,mGAC/B;IACJ;IACA;GACJ;GACA,IAAI,MAAM,MAAM,CAAC,CAAC,IAAI,IAAI,MAAM,KAAA,GAC5B,cAAc,MAAM,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;EAEzD,GAAG,CAAC,MAAM,CAAC;EACX,IAAI,OAAO,WAAW,UAAU;GAC5B,MAAM,SAAS,MAAM;GACrB,OAAO,oBAAC,QAAD;IAAc;IAAiB;IAAW,GAAI;GAAM,CAAA;EAC/D;EACA,IAAI,OAAO,WAAW,WAClB,OAAO;EAEX,MAAM,EAAE,eAAe,QAAQ,cAAc,OAAO,SAAS;EAC7D,OACI,oBAAC,OAAD;GACI,OAAO;GACP,QAAQ;GACR,SAAQ;GACG;GACX,eAAa;GACb,cAAY;GACN;GACN,gBAAa;EAAE,CAAA;CAG3B;CACA,UAAU,cAAc,aAAa,KAAI;CACzC,WAAW,IAAI,MAAM,SAAS;CAC9B,OAAO;AACX"}
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { Disclosure, type DisclosureProps } from './disclosure/Disclosure';
15
15
  export { type FieldChromeProps } from './field/FieldParts';
16
16
  export { Fieldset, type FieldsetProps } from './field/Fieldset';
17
17
  export { Icon, type IconComponent, type IconProps, type IconSize } from './icon/Icon';
18
- export { getNamedIcon, loadNamedIcon } from './icon/namedIcons';
18
+ export { type NamedIconLoader, getNamedIcon, loadNamedIcon } from './icon/namedIcons';
19
19
  export { IconButton, type IconButtonProps } from './icon-button/IconButton';
20
20
  export { usePanneauIntl } from './intl/usePanneauIntl';
21
21
  export { Menu, MenuItem, type MenuItemProps, type MenuProps, MenuSeparator, MenuTrigger, } from './menu/Menu';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { usePanneauIntl } from "./intl/usePanneauIntl.js";
3
3
  import { Spinner } from "./spinner/Spinner.js";
4
4
  import { BUILT_IN_TONES, deriveTone, toneClassName } from "./theme/tones.js";
5
5
  import { Button } from "./button/Button.js";
6
+ import { getNamedIcon, loadNamedIcon } from "./icon/namedIcons.js";
6
7
  import { useToast } from "./toast/Toast.js";
7
8
  import { PanneauRoot, usePortalContainer } from "./root/PanneauRoot.js";
8
9
  import { Tooltip } from "./tooltip/Tooltip.js";
@@ -22,7 +23,6 @@ import { DatePicker } from "./date-picker/DatePicker.js";
22
23
  import { Dialog, DialogTrigger } from "./dialog/Dialog.js";
23
24
  import { Disclosure } from "./disclosure/Disclosure.js";
24
25
  import { Fieldset } from "./field/Fieldset.js";
25
- import { getNamedIcon, loadNamedIcon } from "./icon/namedIcons.js";
26
26
  import { Menu, MenuItem, MenuSeparator, MenuTrigger } from "./menu/Menu.js";
27
27
  import { NumberInput } from "./number-input/NumberInput.js";
28
28
  import { RadioGroup } from "./radio-group/RadioGroup.js";
@@ -0,0 +1,2 @@
1
+ export { lucideIconLoader } from '../icon/lucideIconLoader';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/named-icons/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1 @@
1
+ export { lucideIconLoader } from "../icon/lucideIconLoader.js";
@@ -1,4 +1,5 @@
1
1
  import { type HTMLAttributes, type ReactNode } from 'react';
2
+ import { type NamedIconLoader } from '../icon/namedIcons';
2
3
  import { type ColorScheme, type Density, type Theme } from '../theme/theme';
3
4
  export interface PanneauRootProps extends HTMLAttributes<HTMLDivElement> {
4
5
  /**
@@ -13,6 +14,12 @@ export interface PanneauRootProps extends HTMLAttributes<HTMLDivElement> {
13
14
  * `auto`: `touch` on touch screens, `comfortable` otherwise.
14
15
  */
15
16
  density?: Density;
17
+ /**
18
+ * Loads the icons that definitions name (`"icon": "send"`), for `getNamedIcon()`: pass
19
+ * `lucideIconLoader` from `@panneau/ui/named-icons`, or a loader of only the icons the app
20
+ * uses. Without it, named icons render an empty space.
21
+ */
22
+ iconLoader?: NamedIconLoader | null;
16
23
  /**
17
24
  * Locale of dates and numbers in React Aria components. Defaults to the react-intl locale, or
18
25
  * to the browser's without an `IntlProvider`.
@@ -54,5 +61,5 @@ export declare function usePortalContainer(): Element | null | undefined;
54
61
  * any token with its own class on the root. Without an `IntlProvider` above it, it provides one
55
62
  * with Panneau's messages in its `locale`.
56
63
  */
57
- export declare function PanneauRoot({ theme, colorScheme, density, locale, className, children, ...props }: PanneauRootProps): import("react").JSX.Element;
64
+ export declare function PanneauRoot({ theme, colorScheme, density, iconLoader, locale, className, children, ...props }: PanneauRootProps): import("react").JSX.Element;
58
65
  //# sourceMappingURL=PanneauRoot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PanneauRoot.d.ts","sourceRoot":"","sources":["../../src/root/PanneauRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAgC,MAAM,OAAO,CAAC;AAO1F,OAAO,EACH,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,KAAK,EAGb,MAAM,gBAAgB,CAAC;AAKxB,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACpE;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAKD,sGAAsG;AACtG,eAAO,MAAM,YAAY;iBAAgC,WAAW;aAAW,OAAO;EAGpF,CAAC;AAEH,iEAAiE;AACjE,eAAO,MAAM,cAAc,sDAAyB,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAwBzF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,GAAG,IAAI,GAAG,SAAS,CAE/D;AA2BD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EACxB,KAAY,EACZ,WAAqB,EACrB,OAAgB,EAChB,MAAM,EACN,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACX,EAAE,gBAAgB,+BAoClB"}
1
+ {"version":3,"file":"PanneauRoot.d.ts","sourceRoot":"","sources":["../../src/root/PanneauRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAgC,MAAM,OAAO,CAAC;AAM1F,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,oBAAoB,CAAC;AAElF,OAAO,EACH,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,KAAK,EAGb,MAAM,gBAAgB,CAAC;AAKxB,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,cAAc,CAAC;IACpE;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAKD,sGAAsG;AACtG,eAAO,MAAM,YAAY;iBAAgC,WAAW;aAAW,OAAO;EAGpF,CAAC;AAEH,iEAAiE;AACjE,eAAO,MAAM,cAAc,sDAAyB,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAwBzF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,GAAG,IAAI,GAAG,SAAS,CAE/D;AA2BD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EACxB,KAAY,EACZ,WAAqB,EACrB,OAAgB,EAChB,UAAiB,EACjB,MAAM,EACN,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACX,EAAE,gBAAgB,+BAsClB"}
@@ -1,4 +1,5 @@
1
1
  import { cx } from "../utils/cx.js";
2
+ import { NamedIconLoaderContext } from "../icon/namedIcons.js";
2
3
  import { getFontFaceCss, getFontStylesheets } from "../theme/fonts.js";
3
4
  import { getThemeCss, hashString } from "../theme/theme.js";
4
5
  import { ToastProvider } from "../toast/Toast.js";
@@ -120,7 +121,7 @@ function PanneauIntlProvider({ locale = "en", children }) {
120
121
  * any token with its own class on the root. Without an `IntlProvider` above it, it provides one
121
122
  * with Panneau's messages in its `locale`.
122
123
  */
123
- function PanneauRoot({ theme = null, colorScheme = "light", density = "auto", locale, className, children, ...props }) {
124
+ function PanneauRoot({ theme = null, colorScheme = "light", density = "auto", iconLoader = null, locale, className, children, ...props }) {
124
125
  const intl = use(IntlContext);
125
126
  const [container, setContainer] = useState(null);
126
127
  const { scope, styles: themeStyles } = useThemeStyles(theme);
@@ -132,21 +133,24 @@ function PanneauRoot({ theme = null, colorScheme = "light", density = "auto", lo
132
133
  "data-panneau-theme": scope,
133
134
  children: [themeStyles, /* @__PURE__ */ jsxs(I18nProvider, {
134
135
  locale: locale ?? intl?.locale,
135
- children: [/* @__PURE__ */ jsx(ScopeContext, {
136
- value: {
137
- colorScheme,
138
- density
139
- },
140
- children: /* @__PURE__ */ jsx(PortalContext, {
141
- value: container,
142
- children: /* @__PURE__ */ jsx(ToastProvider, {
143
- regionClassName: PanneauRoot_module_default.root,
144
- regionProps: {
145
- "data-color-scheme": colorScheme,
146
- "data-density": density,
147
- "data-panneau-theme": scope
148
- },
149
- children
136
+ children: [/* @__PURE__ */ jsx(NamedIconLoaderContext, {
137
+ value: iconLoader,
138
+ children: /* @__PURE__ */ jsx(ScopeContext, {
139
+ value: {
140
+ colorScheme,
141
+ density
142
+ },
143
+ children: /* @__PURE__ */ jsx(PortalContext, {
144
+ value: container,
145
+ children: /* @__PURE__ */ jsx(ToastProvider, {
146
+ regionClassName: PanneauRoot_module_default.root,
147
+ regionProps: {
148
+ "data-color-scheme": colorScheme,
149
+ "data-density": density,
150
+ "data-panneau-theme": scope
151
+ },
152
+ children
153
+ })
150
154
  })
151
155
  })
152
156
  }), /* @__PURE__ */ jsx("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"PanneauRoot.js","names":["scope","fontCss","href","_c","_Fragment","styles"],"sources":["../../src/root/PanneauRoot.tsx"],"sourcesContent":["import { type HTMLAttributes, type ReactNode, createContext, use, useState } from 'react';\nimport { I18nProvider } from 'react-aria-components';\nimport { IntlContext, IntlProvider, type IntlShape } from 'react-intl';\n\nimport { getPanneauMessages } from '@panneau/intl';\n\nimport { getFontFaceCss, getFontStylesheets } from '../theme/fonts';\nimport {\n type ColorScheme,\n type Density,\n type Theme,\n getThemeCss,\n hashString,\n} from '../theme/theme';\nimport { ToastProvider } from '../toast/Toast';\nimport { cx } from '../utils/cx';\nimport styles from './PanneauRoot.module.css';\n\nexport interface PanneauRootProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Tokens, tones, variants and fonts that override the default theme: `bootstrapTheme`, or a\n * project's own (`defineTheme()`).\n */\n theme?: Theme | null;\n /** Defaults to `light`. `auto` follows the system setting. */\n colorScheme?: ColorScheme;\n /**\n * How much room controls and rows take: `compact`, `comfortable` or `touch`. Defaults to\n * `auto`: `touch` on touch screens, `comfortable` otherwise.\n */\n density?: Density;\n /**\n * Locale of dates and numbers in React Aria components. Defaults to the react-intl locale, or\n * to the browser's without an `IntlProvider`.\n *\n * Without an `IntlProvider` above it, the root provides one, with the messages of every Panneau\n * package in this locale (English without a locale, or for a locale Panneau doesn't translate).\n * An app with its own `IntlProvider` adds them with `withPanneauMessages()` from\n * `@panneau/intl`.\n */\n locale?: string;\n children?: ReactNode;\n}\n\n/** `undefined` outside of a root, `null` while the root's container isn't mounted yet. */\nconst PortalContext = createContext<Element | null | undefined>(undefined);\n\n/** The color scheme and density in effect, which a `ThemeScope` inherits when it doesn't set them. */\nexport const ScopeContext = createContext<{ colorScheme: ColorScheme; density: Density }>({\n colorScheme: 'light',\n density: 'auto',\n});\n\n/** Gives overlays a container: that of a root, or of a scope. */\nexport const PortalProvider = PortalContext.Provider;\n\n/**\n * The `<style>` and `<link>` elements of a theme: its CSS, scoped to `data-panneau-theme`, and its\n * fonts. React hoists them to the head and adds each once, however many roots or scopes use it.\n * Returns the scope of the theme too, for `data-panneau-theme`.\n */\nexport function useThemeStyles(theme: Theme | null): { scope?: string; styles: ReactNode } {\n const css = theme !== null ? getThemeCss(theme, '§') : '';\n const scope = css !== '' ? hashString(css) : undefined;\n const fontCss = getFontFaceCss(theme?.fonts);\n return {\n scope,\n styles: (\n <>\n {scope !== undefined ? (\n <style href={`panneau-theme-${scope}`} precedence=\"panneau\">\n {css.replaceAll('§', scope)}\n </style>\n ) : null}\n {fontCss !== '' ? (\n <style href={`panneau-fonts-${hashString(fontCss)}`} precedence=\"panneau\">\n {fontCss}\n </style>\n ) : null}\n {getFontStylesheets(theme?.fonts).map((href) => (\n <link key={href} rel=\"stylesheet\" href={href} precedence=\"panneau\" />\n ))}\n </>\n ),\n };\n}\n\n/**\n * The element overlays render into: the closest `PanneauRoot`'s or `ThemeScope`'s, or `undefined` for the body\n * without a root. It is `null` during the first render of a root: overlays wait for it, since\n * React Aria hides everything outside of a modal from assistive technologies when it opens.\n */\nexport function usePortalContainer(): Element | null | undefined {\n return use(PortalContext);\n}\n\n/**\n * An `IntlProvider` with Panneau's messages in a locale, for a root without one above it. A locale\n * Panneau doesn't translate gets English, so that react-intl doesn't report every message as\n * missing.\n */\nfunction PanneauIntlProvider({\n locale = 'en',\n children,\n}: {\n locale?: string;\n children: ReactNode;\n}) {\n const messages = getPanneauMessages(locale);\n const translated = Object.keys(messages).length > 0;\n return (\n <IntlProvider\n locale={translated ? locale : 'en'}\n defaultLocale=\"en\"\n messages={translated ? messages : getPanneauMessages('en')}\n >\n {children}\n </IntlProvider>\n );\n}\n\n/**\n * The root of every Panneau interface. It scopes the base stylesheet and the design tokens to its\n * element (no global CSS), applies a theme and a color scheme, and hosts overlays and toasts so\n * that they get the tokens too. Panneau components must render inside one. A project can override\n * any token with its own class on the root. Without an `IntlProvider` above it, it provides one\n * with Panneau's messages in its `locale`.\n */\nexport function PanneauRoot({\n theme = null,\n colorScheme = 'light',\n density = 'auto',\n locale,\n className,\n children,\n ...props\n}: PanneauRootProps) {\n const intl = use(IntlContext) as IntlShape | null | undefined;\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const { scope, styles: themeStyles } = useThemeStyles(theme);\n const root = (\n <div\n {...props}\n className={cx('panneau-root', styles.root, styles.container, className)}\n data-color-scheme={colorScheme}\n data-density={density}\n data-panneau-theme={scope}\n >\n {themeStyles}\n <I18nProvider locale={locale ?? intl?.locale}>\n <ScopeContext value={{ colorScheme, density }}>\n <PortalContext value={container}>\n <ToastProvider\n regionClassName={styles.root}\n regionProps={{\n 'data-color-scheme': colorScheme,\n 'data-density': density,\n 'data-panneau-theme': scope,\n }}\n >\n {children}\n </ToastProvider>\n </PortalContext>\n </ScopeContext>\n <div ref={setContainer} className={styles.portal} />\n </I18nProvider>\n </div>\n );\n if (intl === null || intl === undefined) {\n return <PanneauIntlProvider locale={locale}>{root}</PanneauIntlProvider>;\n }\n return root;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PanneauRoot.js","names":["scope","fontCss","href","_c","_Fragment","styles"],"sources":["../../src/root/PanneauRoot.tsx"],"sourcesContent":["import { type HTMLAttributes, type ReactNode, createContext, use, useState } from 'react';\nimport { I18nProvider } from 'react-aria-components';\nimport { IntlContext, IntlProvider, type IntlShape } from 'react-intl';\n\nimport { getPanneauMessages } from '@panneau/intl';\n\nimport { type NamedIconLoader, NamedIconLoaderContext } from '../icon/namedIcons';\nimport { getFontFaceCss, getFontStylesheets } from '../theme/fonts';\nimport {\n type ColorScheme,\n type Density,\n type Theme,\n getThemeCss,\n hashString,\n} from '../theme/theme';\nimport { ToastProvider } from '../toast/Toast';\nimport { cx } from '../utils/cx';\nimport styles from './PanneauRoot.module.css';\n\nexport interface PanneauRootProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Tokens, tones, variants and fonts that override the default theme: `bootstrapTheme`, or a\n * project's own (`defineTheme()`).\n */\n theme?: Theme | null;\n /** Defaults to `light`. `auto` follows the system setting. */\n colorScheme?: ColorScheme;\n /**\n * How much room controls and rows take: `compact`, `comfortable` or `touch`. Defaults to\n * `auto`: `touch` on touch screens, `comfortable` otherwise.\n */\n density?: Density;\n /**\n * Loads the icons that definitions name (`\"icon\": \"send\"`), for `getNamedIcon()`: pass\n * `lucideIconLoader` from `@panneau/ui/named-icons`, or a loader of only the icons the app\n * uses. Without it, named icons render an empty space.\n */\n iconLoader?: NamedIconLoader | null;\n /**\n * Locale of dates and numbers in React Aria components. Defaults to the react-intl locale, or\n * to the browser's without an `IntlProvider`.\n *\n * Without an `IntlProvider` above it, the root provides one, with the messages of every Panneau\n * package in this locale (English without a locale, or for a locale Panneau doesn't translate).\n * An app with its own `IntlProvider` adds them with `withPanneauMessages()` from\n * `@panneau/intl`.\n */\n locale?: string;\n children?: ReactNode;\n}\n\n/** `undefined` outside of a root, `null` while the root's container isn't mounted yet. */\nconst PortalContext = createContext<Element | null | undefined>(undefined);\n\n/** The color scheme and density in effect, which a `ThemeScope` inherits when it doesn't set them. */\nexport const ScopeContext = createContext<{ colorScheme: ColorScheme; density: Density }>({\n colorScheme: 'light',\n density: 'auto',\n});\n\n/** Gives overlays a container: that of a root, or of a scope. */\nexport const PortalProvider = PortalContext.Provider;\n\n/**\n * The `<style>` and `<link>` elements of a theme: its CSS, scoped to `data-panneau-theme`, and its\n * fonts. React hoists them to the head and adds each once, however many roots or scopes use it.\n * Returns the scope of the theme too, for `data-panneau-theme`.\n */\nexport function useThemeStyles(theme: Theme | null): { scope?: string; styles: ReactNode } {\n const css = theme !== null ? getThemeCss(theme, '§') : '';\n const scope = css !== '' ? hashString(css) : undefined;\n const fontCss = getFontFaceCss(theme?.fonts);\n return {\n scope,\n styles: (\n <>\n {scope !== undefined ? (\n <style href={`panneau-theme-${scope}`} precedence=\"panneau\">\n {css.replaceAll('§', scope)}\n </style>\n ) : null}\n {fontCss !== '' ? (\n <style href={`panneau-fonts-${hashString(fontCss)}`} precedence=\"panneau\">\n {fontCss}\n </style>\n ) : null}\n {getFontStylesheets(theme?.fonts).map((href) => (\n <link key={href} rel=\"stylesheet\" href={href} precedence=\"panneau\" />\n ))}\n </>\n ),\n };\n}\n\n/**\n * The element overlays render into: the closest `PanneauRoot`'s or `ThemeScope`'s, or `undefined` for the body\n * without a root. It is `null` during the first render of a root: overlays wait for it, since\n * React Aria hides everything outside of a modal from assistive technologies when it opens.\n */\nexport function usePortalContainer(): Element | null | undefined {\n return use(PortalContext);\n}\n\n/**\n * An `IntlProvider` with Panneau's messages in a locale, for a root without one above it. A locale\n * Panneau doesn't translate gets English, so that react-intl doesn't report every message as\n * missing.\n */\nfunction PanneauIntlProvider({\n locale = 'en',\n children,\n}: {\n locale?: string;\n children: ReactNode;\n}) {\n const messages = getPanneauMessages(locale);\n const translated = Object.keys(messages).length > 0;\n return (\n <IntlProvider\n locale={translated ? locale : 'en'}\n defaultLocale=\"en\"\n messages={translated ? messages : getPanneauMessages('en')}\n >\n {children}\n </IntlProvider>\n );\n}\n\n/**\n * The root of every Panneau interface. It scopes the base stylesheet and the design tokens to its\n * element (no global CSS), applies a theme and a color scheme, and hosts overlays and toasts so\n * that they get the tokens too. Panneau components must render inside one. A project can override\n * any token with its own class on the root. Without an `IntlProvider` above it, it provides one\n * with Panneau's messages in its `locale`.\n */\nexport function PanneauRoot({\n theme = null,\n colorScheme = 'light',\n density = 'auto',\n iconLoader = null,\n locale,\n className,\n children,\n ...props\n}: PanneauRootProps) {\n const intl = use(IntlContext) as IntlShape | null | undefined;\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const { scope, styles: themeStyles } = useThemeStyles(theme);\n const root = (\n <div\n {...props}\n className={cx('panneau-root', styles.root, styles.container, className)}\n data-color-scheme={colorScheme}\n data-density={density}\n data-panneau-theme={scope}\n >\n {themeStyles}\n <I18nProvider locale={locale ?? intl?.locale}>\n <NamedIconLoaderContext value={iconLoader}>\n <ScopeContext value={{ colorScheme, density }}>\n <PortalContext value={container}>\n <ToastProvider\n regionClassName={styles.root}\n regionProps={{\n 'data-color-scheme': colorScheme,\n 'data-density': density,\n 'data-panneau-theme': scope,\n }}\n >\n {children}\n </ToastProvider>\n </PortalContext>\n </ScopeContext>\n </NamedIconLoaderContext>\n <div ref={setContainer} className={styles.portal} />\n </I18nProvider>\n </div>\n );\n if (intl === null || intl === undefined) {\n return <PanneauIntlProvider locale={locale}>{root}</PanneauIntlProvider>;\n }\n return root;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- .panneau-switch {
1
+ .panneau-switch-control {
2
2
  display: inline-flex;
3
3
  align-items: center;
4
4
  gap: var(--panneau-space-2);
@@ -9,12 +9,12 @@
9
9
  -webkit-tap-highlight-color: transparent;
10
10
  }
11
11
 
12
- .panneau-switch[data-disabled] {
12
+ .panneau-switch-control[data-disabled] {
13
13
  cursor: not-allowed;
14
14
  opacity: 0.55;
15
15
  }
16
16
 
17
- .panneau-switch[data-readonly] {
17
+ .panneau-switch-control[data-readonly] {
18
18
  cursor: default;
19
19
  }
20
20
 
@@ -42,11 +42,11 @@
42
42
  transition: transform var(--panneau-duration);
43
43
  }
44
44
 
45
- .panneau-switch[data-selected] .panneau-switch-track {
45
+ .panneau-switch-control[data-selected] .panneau-switch-track {
46
46
  background-color: var(--panneau-switch-checked-bg, var(--panneau-color-accent));
47
47
  }
48
48
 
49
- .panneau-switch[data-selected] .panneau-switch-thumb {
49
+ .panneau-switch-control[data-selected] .panneau-switch-thumb {
50
50
  background-color: var(--panneau-switch-checked-thumb-bg, var(--panneau-color-accent-text));
51
51
  /* The thumb travels the width of the track minus its height (both ends keep the same inset). */
52
52
  transform: translateX(
@@ -54,7 +54,7 @@
54
54
  );
55
55
  }
56
56
 
57
- .panneau-switch[data-selected] .panneau-switch-thumb:dir(rtl) {
57
+ .panneau-switch-control[data-selected] .panneau-switch-thumb:dir(rtl) {
58
58
  transform: translateX(
59
59
  calc(
60
60
  -1 * calc(var(--panneau-switch-width, 2.25rem) - var(--panneau-switch-height, 1.25rem))
@@ -62,7 +62,7 @@
62
62
  );
63
63
  }
64
64
 
65
- .panneau-switch[data-focus-visible] .panneau-switch-track {
65
+ .panneau-switch-control[data-focus-visible] .panneau-switch-track {
66
66
  outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
67
67
  outline-offset: 2px;
68
68
  }
@@ -72,7 +72,7 @@
72
72
  }
73
73
 
74
74
  @media (pointer: coarse) {
75
- .panneau-switch {
75
+ .panneau-switch-control {
76
76
  min-height: 2.75rem;
77
77
  }
78
78
  }
@@ -16,7 +16,7 @@ function Switch$1({ children, description, errors = [], className, switchClassNa
16
16
  children: (describedBy) => /* @__PURE__ */ jsxs(Switch, {
17
17
  ...props,
18
18
  "aria-describedby": describedBy,
19
- className: cx(Switch_module_default.switch, switchClassName),
19
+ className: cx(Switch_module_default.control, switchClassName),
20
20
  children: [/* @__PURE__ */ jsx("span", {
21
21
  className: Switch_module_default.track,
22
22
  "aria-hidden": "true",
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","names":["Switch","AriaSwitch","styles"],"sources":["../../src/switch/Switch.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Switch as AriaSwitch, type SwitchProps as AriaSwitchProps } from 'react-aria-components';\n\nimport { ChoiceChrome, type ChoiceChromeProps } from '../checkbox/ChoiceChrome';\nimport { cx } from '../utils/cx';\nimport styles from './Switch.module.css';\n\nexport interface SwitchProps\n extends Omit<AriaSwitchProps, 'className' | 'style' | 'children'>, ChoiceChromeProps {\n /** Label, next to the switch. */\n children?: ReactNode;\n switchClassName?: string;\n}\n\n/** An on and off switch, for settings that apply at once. */\nexport function Switch({\n children,\n description,\n errors = [],\n className,\n switchClassName,\n descriptionClassName,\n errorsClassName,\n ...props\n}: SwitchProps) {\n return (\n <ChoiceChrome\n component=\"switch\"\n description={description}\n errors={errors}\n className={className}\n descriptionClassName={descriptionClassName}\n errorsClassName={errorsClassName}\n >\n {(describedBy) => (\n <AriaSwitch\n {...props}\n aria-describedby={describedBy}\n className={cx(styles.switch, switchClassName)}\n >\n <span className={styles.track} aria-hidden=\"true\">\n <span className={styles.thumb} />\n </span>\n {children !== undefined ? (\n <span className={styles.label}>{children}</span>\n ) : null}\n </AriaSwitch>\n )}\n </ChoiceChrome>\n );\n}\n"],"mappings":";;;;;;;AAeA,SAAgBA,SAAO,EACnB,UACA,aACA,SAAS,CAAA,GACT,WACA,iBACA,sBACA,iBACA,GAAG,SACS;CACZ,OACI,oBAAC,cAAD;EACI,WAAU;EACG;EACL;EACG;EACW;EACL;EAEf,WAAA,gBACE,qBAACC,QAAD;GACI,GAAI;GACJ,oBAAkB;GAClB,WAAW,GAAGC,sBAAO,QAAQ,eAAe;GAHhD,UAAA,CAKI,oBAAC,QAAD;IAAM,WAAWA,sBAAO;IAAO,eAAY;IACvC,UAAA,oBAAC,QAAD,EAAM,WAAWA,sBAAO,MAAM,CAAA;GAC5B,CAAA,GACL,aAAa,KAAA,IACV,oBAAC,QAAD;IAAM,WAAWA,sBAAO;IAAQ;GAAe,CAAA,IAC/C,IACI;;CAEN,CAAA;AAEtB"}
1
+ {"version":3,"file":"Switch.js","names":["Switch","AriaSwitch","styles"],"sources":["../../src/switch/Switch.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Switch as AriaSwitch, type SwitchProps as AriaSwitchProps } from 'react-aria-components';\n\nimport { ChoiceChrome, type ChoiceChromeProps } from '../checkbox/ChoiceChrome';\nimport { cx } from '../utils/cx';\nimport styles from './Switch.module.css';\n\nexport interface SwitchProps\n extends Omit<AriaSwitchProps, 'className' | 'style' | 'children'>, ChoiceChromeProps {\n /** Label, next to the switch. */\n children?: ReactNode;\n switchClassName?: string;\n}\n\n/** An on and off switch, for settings that apply at once. */\nexport function Switch({\n children,\n description,\n errors = [],\n className,\n switchClassName,\n descriptionClassName,\n errorsClassName,\n ...props\n}: SwitchProps) {\n return (\n <ChoiceChrome\n component=\"switch\"\n description={description}\n errors={errors}\n className={className}\n descriptionClassName={descriptionClassName}\n errorsClassName={errorsClassName}\n >\n {(describedBy) => (\n <AriaSwitch\n {...props}\n aria-describedby={describedBy}\n className={cx(styles.control, switchClassName)}\n >\n <span className={styles.track} aria-hidden=\"true\">\n <span className={styles.thumb} />\n </span>\n {children !== undefined ? (\n <span className={styles.label}>{children}</span>\n ) : null}\n </AriaSwitch>\n )}\n </ChoiceChrome>\n );\n}\n"],"mappings":";;;;;;;AAeA,SAAgBA,SAAO,EACnB,UACA,aACA,SAAS,CAAA,GACT,WACA,iBACA,sBACA,iBACA,GAAG,SACS;CACZ,OACI,oBAAC,cAAD;EACI,WAAU;EACG;EACL;EACG;EACW;EACL;EAEf,WAAA,gBACE,qBAACC,QAAD;GACI,GAAI;GACJ,oBAAkB;GAClB,WAAW,GAAGC,sBAAO,SAAS,eAAe;GAHjD,UAAA,CAKI,oBAAC,QAAD;IAAM,WAAWA,sBAAO;IAAO,eAAY;IACvC,UAAA,oBAAC,QAAD,EAAM,WAAWA,sBAAO,MAAM,CAAA;GAC5B,CAAA,GACL,aAAa,KAAA,IACV,oBAAC,QAAD;IAAM,WAAWA,sBAAO;IAAQ;GAAe,CAAA,IAC/C,IACI;;CAEN,CAAA;AAEtB"}
@@ -1,15 +1,16 @@
1
1
  import "./Switch.css";
2
2
  //#region src/switch/Switch.module.css
3
+ var control = "panneau-switch-control";
3
4
  var track = "panneau-switch-track";
4
5
  var thumb = "panneau-switch-thumb";
5
6
  var label = "panneau-switch-label";
6
7
  var Switch_module_default = {
7
- "switch": "panneau-switch",
8
+ control,
8
9
  track,
9
10
  thumb,
10
11
  label
11
12
  };
12
13
  //#endregion
13
- export { Switch_module_default as default, label, thumb, track };
14
+ export { control, Switch_module_default as default, label, thumb, track };
14
15
 
15
16
  //# sourceMappingURL=Switch.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.module.js","names":[],"sources":["../../src/switch/Switch.module.css"],"sourcesContent":[".switch {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-2);\n min-height: 1.5rem;\n font-size: var(--panneau-font-size-md);\n color: var(--panneau-color-text);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.switch[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.switch[data-readonly] {\n cursor: default;\n}\n\n.track {\n position: relative;\n flex: 0 0 auto;\n width: var(--panneau-switch-width, 2.25rem);\n height: var(--panneau-switch-height, 1.25rem);\n background-color: var(--panneau-switch-track-bg, var(--panneau-color-border-control));\n border-radius: var(--panneau-switch-radius, var(--panneau-radius-full));\n transition: background-color var(--panneau-duration);\n}\n\n.thumb {\n position: absolute;\n top: calc((var(--panneau-switch-height, 1.25rem) - var(--panneau-switch-thumb-size, 1rem)) / 2);\n left: calc(\n (var(--panneau-switch-height, 1.25rem) - var(--panneau-switch-thumb-size, 1rem)) / 2\n );\n width: var(--panneau-switch-thumb-size, 1rem);\n height: var(--panneau-switch-thumb-size, 1rem);\n background-color: var(--panneau-switch-thumb-bg, var(--panneau-color-surface));\n border-radius: var(--panneau-switch-radius, var(--panneau-radius-full));\n box-shadow: var(--panneau-shadow-sm);\n transition: transform var(--panneau-duration);\n}\n\n.switch[data-selected] .track {\n background-color: var(--panneau-switch-checked-bg, var(--panneau-color-accent));\n}\n\n.switch[data-selected] .thumb {\n background-color: var(--panneau-switch-checked-thumb-bg, var(--panneau-color-accent-text));\n /* The thumb travels the width of the track minus its height (both ends keep the same inset). */\n transform: translateX(\n calc(var(--panneau-switch-width, 2.25rem) - var(--panneau-switch-height, 1.25rem))\n );\n}\n\n.switch[data-selected] .thumb:dir(rtl) {\n transform: translateX(\n calc(\n -1 * calc(var(--panneau-switch-width, 2.25rem) - var(--panneau-switch-height, 1.25rem))\n )\n );\n}\n\n.switch[data-focus-visible] .track {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.label {\n overflow-wrap: anywhere;\n}\n\n@media (pointer: coarse) {\n .switch {\n min-height: 2.75rem;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Switch.module.js","names":[],"sources":["../../src/switch/Switch.module.css"],"sourcesContent":[".control {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-2);\n min-height: 1.5rem;\n font-size: var(--panneau-font-size-md);\n color: var(--panneau-color-text);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n}\n\n.control[data-disabled] {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.control[data-readonly] {\n cursor: default;\n}\n\n.track {\n position: relative;\n flex: 0 0 auto;\n width: var(--panneau-switch-width, 2.25rem);\n height: var(--panneau-switch-height, 1.25rem);\n background-color: var(--panneau-switch-track-bg, var(--panneau-color-border-control));\n border-radius: var(--panneau-switch-radius, var(--panneau-radius-full));\n transition: background-color var(--panneau-duration);\n}\n\n.thumb {\n position: absolute;\n top: calc((var(--panneau-switch-height, 1.25rem) - var(--panneau-switch-thumb-size, 1rem)) / 2);\n left: calc(\n (var(--panneau-switch-height, 1.25rem) - var(--panneau-switch-thumb-size, 1rem)) / 2\n );\n width: var(--panneau-switch-thumb-size, 1rem);\n height: var(--panneau-switch-thumb-size, 1rem);\n background-color: var(--panneau-switch-thumb-bg, var(--panneau-color-surface));\n border-radius: var(--panneau-switch-radius, var(--panneau-radius-full));\n box-shadow: var(--panneau-shadow-sm);\n transition: transform var(--panneau-duration);\n}\n\n.control[data-selected] .track {\n background-color: var(--panneau-switch-checked-bg, var(--panneau-color-accent));\n}\n\n.control[data-selected] .thumb {\n background-color: var(--panneau-switch-checked-thumb-bg, var(--panneau-color-accent-text));\n /* The thumb travels the width of the track minus its height (both ends keep the same inset). */\n transform: translateX(\n calc(var(--panneau-switch-width, 2.25rem) - var(--panneau-switch-height, 1.25rem))\n );\n}\n\n.control[data-selected] .thumb:dir(rtl) {\n transform: translateX(\n calc(\n -1 * calc(var(--panneau-switch-width, 2.25rem) - var(--panneau-switch-height, 1.25rem))\n )\n );\n}\n\n.control[data-focus-visible] .track {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n\n.label {\n overflow-wrap: anywhere;\n}\n\n@media (pointer: coarse) {\n .control {\n min-height: 2.75rem;\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  /* Doubled class: overrides the shared control, whatever the CSS order. */
2
- .panneau-text-area.panneau-text-area {
2
+ .panneau-text-area-control.panneau-text-area-control {
3
3
  display: block;
4
4
  min-height: calc(var(--panneau-control-height) * 2);
5
5
  padding: var(--panneau-space-2) var(--panneau-space-3);
@@ -22,7 +22,7 @@ function TextArea$1({ label, description, errors = [], placeholder, rows = 4, cl
22
22
  /* @__PURE__ */ jsx(TextArea, {
23
23
  placeholder,
24
24
  rows,
25
- className: cx(Field_module_default.control, TextArea_module_default.textArea, textAreaClassName)
25
+ className: cx(Field_module_default.control, TextArea_module_default.control, textAreaClassName)
26
26
  }),
27
27
  /* @__PURE__ */ jsx(FieldDescription, {
28
28
  className: descriptionClassName,
@@ -1 +1 @@
1
- {"version":3,"file":"TextArea.js","names":["TextArea","fieldStyles","AriaTextArea","styles"],"sources":["../../src/text-area/TextArea.tsx"],"sourcesContent":["import {\n TextArea as AriaTextArea,\n type TextFieldProps as AriaTextFieldProps,\n TextField,\n} from 'react-aria-components';\n\nimport {\n type FieldChromeProps,\n FieldDescription,\n FieldErrors,\n FieldLabel,\n fieldStyles,\n} from '../field/FieldParts';\nimport { cx } from '../utils/cx';\nimport styles from './TextArea.module.css';\n\nexport interface TextAreaProps\n extends\n Omit<AriaTextFieldProps, 'className' | 'style' | 'children' | 'isInvalid' | 'validate'>,\n FieldChromeProps {\n placeholder?: string;\n /** Visible lines of text. Defaults to 4. */\n rows?: number;\n textAreaClassName?: string;\n}\n\n/** A multi-line text input with its label, description and errors. */\nexport function TextArea({\n label,\n description,\n errors = [],\n placeholder,\n rows = 4,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n textAreaClassName,\n isRequired,\n ...props\n}: TextAreaProps) {\n return (\n <TextField\n {...props}\n isRequired={isRequired}\n isInvalid={errors.length > 0}\n validationBehavior=\"aria\"\n className={cx('panneau-text-area', fieldStyles.field, className)}\n >\n <FieldLabel isRequired={isRequired} className={labelClassName}>\n {label}\n </FieldLabel>\n <AriaTextArea\n placeholder={placeholder}\n rows={rows}\n className={cx(fieldStyles.control, styles.textArea, textAreaClassName)}\n />\n <FieldDescription className={descriptionClassName}>{description}</FieldDescription>\n <FieldErrors errors={errors} className={errorsClassName} />\n </TextField>\n );\n}\n"],"mappings":";;;;;;;;AA2BA,SAAgBA,WAAS,EACrB,OACA,aACA,SAAS,CAAA,GACT,aACA,OAAO,GACP,WACA,gBACA,sBACA,iBACA,mBACA,YACA,GAAG,SACW;CACd,OACI,qBAAC,WAAD;EACI,GAAI;EACQ;EACZ,WAAW,OAAO,SAAS;EAC3B,oBAAmB;EACnB,WAAW,GAAG,qBAAqBC,qBAAY,OAAO,SAAS;EALnE,UAAA;GAOI,oBAAC,YAAD;IAAwB;IAAY,WAAW;IAC1C,UAAA;GACO,CAAA;GACZ,oBAACC,UAAD;IACiB;IACP;IACN,WAAW,GAAGD,qBAAY,SAASE,wBAAO,UAAU,iBAAiB;GAAE,CAAA;GAE3E,oBAAC,kBAAD;IAAkB,WAAW;IAAuB,UAAA;GAA8B,CAAA;GAClF,oBAAC,aAAD;IAAqB;IAAQ,WAAW;GAAgB,CAAA;EACjD;;AAEnB"}
1
+ {"version":3,"file":"TextArea.js","names":["TextArea","fieldStyles","AriaTextArea","styles"],"sources":["../../src/text-area/TextArea.tsx"],"sourcesContent":["import {\n TextArea as AriaTextArea,\n type TextFieldProps as AriaTextFieldProps,\n TextField,\n} from 'react-aria-components';\n\nimport {\n type FieldChromeProps,\n FieldDescription,\n FieldErrors,\n FieldLabel,\n fieldStyles,\n} from '../field/FieldParts';\nimport { cx } from '../utils/cx';\nimport styles from './TextArea.module.css';\n\nexport interface TextAreaProps\n extends\n Omit<AriaTextFieldProps, 'className' | 'style' | 'children' | 'isInvalid' | 'validate'>,\n FieldChromeProps {\n placeholder?: string;\n /** Visible lines of text. Defaults to 4. */\n rows?: number;\n textAreaClassName?: string;\n}\n\n/** A multi-line text input with its label, description and errors. */\nexport function TextArea({\n label,\n description,\n errors = [],\n placeholder,\n rows = 4,\n className,\n labelClassName,\n descriptionClassName,\n errorsClassName,\n textAreaClassName,\n isRequired,\n ...props\n}: TextAreaProps) {\n return (\n <TextField\n {...props}\n isRequired={isRequired}\n isInvalid={errors.length > 0}\n validationBehavior=\"aria\"\n className={cx('panneau-text-area', fieldStyles.field, className)}\n >\n <FieldLabel isRequired={isRequired} className={labelClassName}>\n {label}\n </FieldLabel>\n <AriaTextArea\n placeholder={placeholder}\n rows={rows}\n className={cx(fieldStyles.control, styles.control, textAreaClassName)}\n />\n <FieldDescription className={descriptionClassName}>{description}</FieldDescription>\n <FieldErrors errors={errors} className={errorsClassName} />\n </TextField>\n );\n}\n"],"mappings":";;;;;;;;AA2BA,SAAgBA,WAAS,EACrB,OACA,aACA,SAAS,CAAA,GACT,aACA,OAAO,GACP,WACA,gBACA,sBACA,iBACA,mBACA,YACA,GAAG,SACW;CACd,OACI,qBAAC,WAAD;EACI,GAAI;EACQ;EACZ,WAAW,OAAO,SAAS;EAC3B,oBAAmB;EACnB,WAAW,GAAG,qBAAqBC,qBAAY,OAAO,SAAS;EALnE,UAAA;GAOI,oBAAC,YAAD;IAAwB;IAAY,WAAW;IAC1C,UAAA;GACO,CAAA;GACZ,oBAACC,UAAD;IACiB;IACP;IACN,WAAW,GAAGD,qBAAY,SAASE,wBAAO,SAAS,iBAAiB;GAAE,CAAA;GAE1E,oBAAC,kBAAD;IAAkB,WAAW;IAAuB,UAAA;GAA8B,CAAA;GAClF,oBAAC,aAAD;IAAqB;IAAQ,WAAW;GAAgB,CAAA;EACjD;;AAEnB"}
@@ -1,8 +1,8 @@
1
1
  import "./TextArea.css";
2
2
  //#region src/text-area/TextArea.module.css
3
- var textArea = "panneau-text-area";
4
- var TextArea_module_default = { textArea };
3
+ var control = "panneau-text-area-control";
4
+ var TextArea_module_default = { control };
5
5
  //#endregion
6
- export { TextArea_module_default as default, textArea };
6
+ export { control, TextArea_module_default as default };
7
7
 
8
8
  //# sourceMappingURL=TextArea.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextArea.module.js","names":[],"sources":["../../src/text-area/TextArea.module.css"],"sourcesContent":["/* Doubled class: overrides the shared control, whatever the CSS order. */\n.textArea.textArea {\n display: block;\n min-height: calc(var(--panneau-control-height) * 2);\n padding: var(--panneau-space-2) var(--panneau-space-3);\n line-height: var(--panneau-line-height);\n resize: vertical;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"TextArea.module.js","names":[],"sources":["../../src/text-area/TextArea.module.css"],"sourcesContent":["/* Doubled class: overrides the shared control, whatever the CSS order. */\n.control.control {\n display: block;\n min-height: calc(var(--panneau-control-height) * 2);\n padding: var(--panneau-space-2) var(--panneau-space-3);\n line-height: var(--panneau-line-height);\n resize: vertical;\n}\n"],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panneau/ui",
3
- "version": "5.0.0-alpha.2",
3
+ "version": "5.0.0-alpha.3",
4
4
  "description": "Design tokens, themes and accessible primitives of Panneau, built on React Aria Components.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,6 +23,11 @@
23
23
  "types": "./dist/locales/index.d.ts",
24
24
  "default": "./dist/locales/index.js"
25
25
  },
26
+ "./named-icons": {
27
+ "@panneau/source": "./src/named-icons/index.ts",
28
+ "types": "./dist/named-icons/index.d.ts",
29
+ "default": "./dist/named-icons/index.js"
30
+ },
26
31
  "./theme": {
27
32
  "@panneau/source": "./src/theme/index.ts",
28
33
  "types": "./dist/theme/index.d.ts",
@@ -52,10 +57,10 @@
52
57
  "react-intl": "^12.0.0"
53
58
  },
54
59
  "dependencies": {
55
- "@panneau/intl": "5.0.0-alpha.2",
60
+ "@panneau/intl": "5.0.0-alpha.3",
56
61
  "lucide-react": "^1.57.0"
57
62
  },
58
63
  "devDependencies": {
59
- "@panneau/protocol": "5.0.0-alpha.2"
64
+ "@panneau/protocol": "5.0.0-alpha.3"
60
65
  }
61
66
  }