ionbase-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -0
  3. package/dist/Icon.d.ts +72 -0
  4. package/dist/Icon.d.ts.map +1 -0
  5. package/dist/Icon.js +50 -0
  6. package/dist/Icon.js.map +1 -0
  7. package/dist/components/Avatar.d.ts +52 -0
  8. package/dist/components/Avatar.d.ts.map +1 -0
  9. package/dist/components/Avatar.js +59 -0
  10. package/dist/components/Avatar.js.map +1 -0
  11. package/dist/components/Badge.d.ts +26 -0
  12. package/dist/components/Badge.d.ts.map +1 -0
  13. package/dist/components/Badge.js +17 -0
  14. package/dist/components/Badge.js.map +1 -0
  15. package/dist/components/Button.d.ts +18 -0
  16. package/dist/components/Button.d.ts.map +1 -0
  17. package/dist/components/Button.js +43 -0
  18. package/dist/components/Button.js.map +1 -0
  19. package/dist/components/Checkbox.d.ts +30 -0
  20. package/dist/components/Checkbox.d.ts.map +1 -0
  21. package/dist/components/Checkbox.js +39 -0
  22. package/dist/components/Checkbox.js.map +1 -0
  23. package/dist/components/Divider.d.ts +17 -0
  24. package/dist/components/Divider.d.ts.map +1 -0
  25. package/dist/components/Divider.js +16 -0
  26. package/dist/components/Divider.js.map +1 -0
  27. package/dist/components/Header.d.ts +25 -0
  28. package/dist/components/Header.d.ts.map +1 -0
  29. package/dist/components/Header.js +18 -0
  30. package/dist/components/Header.js.map +1 -0
  31. package/dist/components/Input.d.ts +32 -0
  32. package/dist/components/Input.d.ts.map +1 -0
  33. package/dist/components/Input.js +66 -0
  34. package/dist/components/Input.js.map +1 -0
  35. package/dist/components/Logo.d.ts +41 -0
  36. package/dist/components/Logo.d.ts.map +1 -0
  37. package/dist/components/Logo.js +70 -0
  38. package/dist/components/Logo.js.map +1 -0
  39. package/dist/components/Menu.d.ts +29 -0
  40. package/dist/components/Menu.d.ts.map +1 -0
  41. package/dist/components/Menu.js +31 -0
  42. package/dist/components/Menu.js.map +1 -0
  43. package/dist/components/NavItem.d.ts +30 -0
  44. package/dist/components/NavItem.d.ts.map +1 -0
  45. package/dist/components/NavItem.js +45 -0
  46. package/dist/components/NavItem.js.map +1 -0
  47. package/dist/components/Radio.d.ts +30 -0
  48. package/dist/components/Radio.d.ts.map +1 -0
  49. package/dist/components/Radio.js +61 -0
  50. package/dist/components/Radio.js.map +1 -0
  51. package/dist/components/ScrollProgress.d.ts +33 -0
  52. package/dist/components/ScrollProgress.d.ts.map +1 -0
  53. package/dist/components/ScrollProgress.js +115 -0
  54. package/dist/components/ScrollProgress.js.map +1 -0
  55. package/dist/components/Select.d.ts +43 -0
  56. package/dist/components/Select.d.ts.map +1 -0
  57. package/dist/components/Select.js +80 -0
  58. package/dist/components/Select.js.map +1 -0
  59. package/dist/components/Table.d.ts +71 -0
  60. package/dist/components/Table.d.ts.map +1 -0
  61. package/dist/components/Table.js +60 -0
  62. package/dist/components/Table.js.map +1 -0
  63. package/dist/components/Tabs.d.ts +23 -0
  64. package/dist/components/Tabs.d.ts.map +1 -0
  65. package/dist/components/Tabs.js +47 -0
  66. package/dist/components/Tabs.js.map +1 -0
  67. package/dist/components/Toggle.d.ts +25 -0
  68. package/dist/components/Toggle.d.ts.map +1 -0
  69. package/dist/components/Toggle.js +32 -0
  70. package/dist/components/Toggle.js.map +1 -0
  71. package/dist/components/index.d.ts +33 -0
  72. package/dist/components/index.d.ts.map +1 -0
  73. package/dist/components/index.js +17 -0
  74. package/dist/components/index.js.map +1 -0
  75. package/dist/index.d.ts +25 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +24 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/styles/avatar.css +138 -0
  80. package/dist/styles/badge.css +125 -0
  81. package/dist/styles/button.css +331 -0
  82. package/dist/styles/checkbox.css +229 -0
  83. package/dist/styles/divider.css +31 -0
  84. package/dist/styles/header.css +95 -0
  85. package/dist/styles/index.css +44 -0
  86. package/dist/styles/input.css +264 -0
  87. package/dist/styles/logo.css +63 -0
  88. package/dist/styles/menu.css +150 -0
  89. package/dist/styles/nav-item.css +120 -0
  90. package/dist/styles/radio.css +200 -0
  91. package/dist/styles/scroll-progress.css +171 -0
  92. package/dist/styles/select.css +162 -0
  93. package/dist/styles/table.css +192 -0
  94. package/dist/styles/tabs.css +219 -0
  95. package/dist/styles/toggle.css +184 -0
  96. package/dist/styles/tokens/base.css +386 -0
  97. package/dist/styles/tokens/breakpoint-mobile.css +34 -0
  98. package/dist/styles/tokens/breakpoint-tablet.css +25 -0
  99. package/dist/styles/tokens/elevation.css +112 -0
  100. package/dist/styles/tokens/index.css +6 -0
  101. package/dist/styles/tokens/theme-dark.css +106 -0
  102. package/dist/styles/tokens/typography.css +124 -0
  103. package/dist/tokens/index.d.ts +2097 -0
  104. package/dist/tokens/index.d.ts.map +1 -0
  105. package/dist/tokens/index.js +1702 -0
  106. package/dist/tokens/index.js.map +1 -0
  107. package/package.json +70 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 IonBase
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # ionbase-ui
2
+
3
+ The IonBase Design System: accessible React components, their stylesheets, and
4
+ the design tokens they are built on — in one package.
5
+
6
+ ```bash
7
+ npm i ionbase-ui
8
+ ```
9
+
10
+ React 18 or 19 is a peer dependency.
11
+
12
+ ## Usage
13
+
14
+ Import the stylesheet once, at your app entry:
15
+
16
+ ```tsx
17
+ import 'ionbase-ui/styles';
18
+ import { Button } from 'ionbase-ui';
19
+
20
+ export function App() {
21
+ return <Button intent="primary">Save</Button>;
22
+ }
23
+ ```
24
+
25
+ That single import pulls in the design tokens, the typography (Host Grotesk,
26
+ Merriweather, Space Mono), and every component stylesheet. Dark mode is
27
+ `data-theme="dark"` on any ancestor — no separate import, no JS.
28
+
29
+ ## Icons
30
+
31
+ The system does not ship an icon set. `Icon` takes the icon as a prop, so any
32
+ SVG component works — [lucide-react](https://lucide.dev), heroicons,
33
+ react-icons, or your own:
34
+
35
+ ```tsx
36
+ import { Icon } from 'ionbase-ui';
37
+ import { Plus } from 'lucide-react';
38
+
39
+ <Icon as={Plus} size="sm" />
40
+ <Icon as={Plus} label="Add item" /> // meaningful icon, gets an a11y name
41
+ ```
42
+
43
+ Omit `label` for decorative icons and they are hidden from assistive tech
44
+ instead of announced twice. `size` picks a rung on the `icon-size` ladder —
45
+ `xs` 12, `sm` 16, `md` 20, `lg` 24, `xl` 32 — or takes any CSS length. Omit it
46
+ and the icon inherits the surrounding font size, which is what lets an icon sit
47
+ correctly inside a Button.
48
+
49
+ ## Entry points
50
+
51
+ | Import | What it is |
52
+ | --------------------- | ---------------------------------------------- |
53
+ | `ionbase-ui` | Components, `Icon`, and the `tokens` object |
54
+ | `ionbase-ui/styles` | Everything: tokens + typography + components |
55
+ | `ionbase-ui/styles/*` | One component stylesheet, e.g. `button.css` |
56
+ | `ionbase-ui/tokens` | Token custom properties only, no component CSS |
57
+ | `ionbase-ui/tokens/*` | One token layer, e.g. `theme-dark.css` |
58
+
59
+ Token values are also available as JavaScript, as `var(--…)` references:
60
+
61
+ ```ts
62
+ import { tokens } from 'ionbase-ui';
63
+ ```
64
+
65
+ ## Tokens come from Figma
66
+
67
+ Every token name and value in this package is generated from the IonBase Figma
68
+ file. They are not authored here and should not be edited here — see
69
+ [the repo](https://github.com/raza-ahmed/ionbase-design-system) for the
70
+ pipeline and its gates.
71
+
72
+ ## License
73
+
74
+ MIT
package/dist/Icon.d.ts ADDED
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ /**
3
+ * Any component that renders an SVG element and accepts SVG props.
4
+ *
5
+ * Typed structurally rather than as lucide-react's `LucideIcon`, so the icon
6
+ * set is the consumer's choice: lucide, heroicons, react-icons, a hand-rolled
7
+ * SVG component. Naming one library in the type would have made it a
8
+ * dependency of every install for the sake of a type that is erased at build
9
+ * time.
10
+ */
11
+ export type IconComponent = React.ComponentType<React.SVGProps<SVGSVGElement> & React.RefAttributes<SVGSVGElement>>;
12
+ /**
13
+ * The `icon-size` ladder, verbatim.
14
+ *
15
+ * These map one-to-one onto the Semantics tokens `icon-size/xs...xl`, so `md`
16
+ * here and `icon-size/md` in Figma are the same 20px. There is no separate
17
+ * decision being made in this file.
18
+ *
19
+ * BREAKING, AND DELIBERATELY SO
20
+ *
21
+ * This used to be two sizes where `sm` was 16 and `md` was **24**. That made
22
+ * `md` mean `icon-size/lg`, so the one word meant two different things
23
+ * depending on whether you were reading code or Figma — the exact ambiguity the
24
+ * ladder exists to remove. Callers who want the old `md` now ask for `lg`.
25
+ *
26
+ * Nothing inside the system depended on it: Button and Tabs size their icons in
27
+ * CSS from `--icon-size-*`, never through this prop.
28
+ */
29
+ declare const SIZE_TOKENS: {
30
+ readonly xs: "var(--icon-size-xs)";
31
+ readonly sm: "var(--icon-size-sm)";
32
+ readonly md: "var(--icon-size-md)";
33
+ readonly lg: "var(--icon-size-lg)";
34
+ readonly xl: "var(--icon-size-xl)";
35
+ };
36
+ export type IconSize = keyof typeof SIZE_TOKENS;
37
+ export interface IconProps extends Omit<React.SVGProps<SVGSVGElement>, 'ref'> {
38
+ /**
39
+ * The icon component to render, e.g. `import { Plus } from 'lucide-react'`.
40
+ * Any SVG component works — the design system does not ship an icon set.
41
+ */
42
+ as: IconComponent;
43
+ /**
44
+ * A rung on the `icon-size` ladder — `xs` 12, `sm` 16, `md` 20, `lg` 24,
45
+ * `xl` 32 — or any CSS length for a one-off. Omit to inherit the surrounding
46
+ * font size, which is what lets an icon sit correctly inside a Button without
47
+ * the Button having to know anything about this component.
48
+ */
49
+ size?: IconSize | (string & {});
50
+ /**
51
+ * Accessible name. Provide it when the icon carries meaning on its own — an
52
+ * icon-only button, a status marker. Omit it for decoration next to a visible
53
+ * label, and the icon is hidden from assistive tech instead of read out twice.
54
+ */
55
+ label?: string;
56
+ }
57
+ /**
58
+ * Wrapper that applies the design system's icon sizing and accessibility
59
+ * defaults to whatever icon component you hand it.
60
+ *
61
+ * import { Plus } from 'lucide-react';
62
+ * <Icon as={Plus} size="sm" />
63
+ * <Icon as={Plus} label="Add item" /> // meaningful, gets an a11y name
64
+ *
65
+ * Takes the icon as a prop rather than re-exporting a set: a barrel of a
66
+ * thousand-plus icons defeats tree-shaking in several bundlers, and pinning one
67
+ * icon library would force it on every consumer. You import the one icon you
68
+ * need, from whichever library you use, and it is the only one bundled.
69
+ */
70
+ export declare const Icon: React.ForwardRefExoticComponent<IconProps & React.RefAttributes<SVGSVGElement>>;
71
+ export {};
72
+ //# sourceMappingURL=Icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../src/Icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,CAC7C,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,CACnE,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,WAAW;;;;;;CAMP,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,WAAW,CAAC;AAEhD,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;IAC3E;;;OAGG;IACH,EAAE,EAAE,aAAa,CAAC;IAClB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAChC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,IAAI,iFAqBhB,CAAC"}
package/dist/Icon.js ADDED
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ /**
4
+ * The `icon-size` ladder, verbatim.
5
+ *
6
+ * These map one-to-one onto the Semantics tokens `icon-size/xs...xl`, so `md`
7
+ * here and `icon-size/md` in Figma are the same 20px. There is no separate
8
+ * decision being made in this file.
9
+ *
10
+ * BREAKING, AND DELIBERATELY SO
11
+ *
12
+ * This used to be two sizes where `sm` was 16 and `md` was **24**. That made
13
+ * `md` mean `icon-size/lg`, so the one word meant two different things
14
+ * depending on whether you were reading code or Figma — the exact ambiguity the
15
+ * ladder exists to remove. Callers who want the old `md` now ask for `lg`.
16
+ *
17
+ * Nothing inside the system depended on it: Button and Tabs size their icons in
18
+ * CSS from `--icon-size-*`, never through this prop.
19
+ */
20
+ const SIZE_TOKENS = {
21
+ xs: 'var(--icon-size-xs)',
22
+ sm: 'var(--icon-size-sm)',
23
+ md: 'var(--icon-size-md)',
24
+ lg: 'var(--icon-size-lg)',
25
+ xl: 'var(--icon-size-xl)',
26
+ };
27
+ /**
28
+ * Wrapper that applies the design system's icon sizing and accessibility
29
+ * defaults to whatever icon component you hand it.
30
+ *
31
+ * import { Plus } from 'lucide-react';
32
+ * <Icon as={Plus} size="sm" />
33
+ * <Icon as={Plus} label="Add item" /> // meaningful, gets an a11y name
34
+ *
35
+ * Takes the icon as a prop rather than re-exporting a set: a barrel of a
36
+ * thousand-plus icons defeats tree-shaking in several bundlers, and pinning one
37
+ * icon library would force it on every consumer. You import the one icon you
38
+ * need, from whichever library you use, and it is the only one bundled.
39
+ */
40
+ export const Icon = forwardRef(({ as: Component, size, label, className, ...rest }, ref) => {
41
+ const resolved = size === undefined ? '1em' : (SIZE_TOKENS[size] ?? size);
42
+ return (_jsx(Component, { ref: ref, width: resolved, height: resolved,
43
+ // Lucide strokes scale with the box; currentColor keeps the icon tied to
44
+ // whatever text colour it sits in, so it themes for free.
45
+ color: "currentColor", className: ['ion-icon', className].filter(Boolean).join(' '), ...(label
46
+ ? { role: 'img', 'aria-label': label }
47
+ : { 'aria-hidden': true, focusable: false }), ...rest }));
48
+ });
49
+ Icon.displayName = 'Icon';
50
+ //# sourceMappingURL=Icon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Icon.js","sourceRoot":"","sources":["../src/Icon.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAe1C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,qBAAqB;IACzB,EAAE,EAAE,qBAAqB;IACzB,EAAE,EAAE,qBAAqB;IACzB,EAAE,EAAE,qBAAqB;IACzB,EAAE,EAAE,qBAAqB;CACjB,CAAC;AAyBX;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAC5B,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE;IAC1D,MAAM,QAAQ,GACZ,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAgB,CAAC,IAAI,IAAI,CAAC,CAAC;IAEvE,OAAO,CACL,KAAC,SAAS,IACR,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,QAAQ;QAChB,yEAAyE;QACzE,0DAA0D;QAC1D,KAAK,EAAC,cAAc,EACpB,SAAS,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KACxD,CAAC,KAAK;YACR,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE;YACtC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,KAC1C,IAAI,GACR,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC"}
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ export type AvatarSize = 'mini' | 'sm' | 'md' | 'lg';
3
+ export type AvatarShape = 'circle' | 'square';
4
+ export interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {
5
+ /** Matches the Figma `Size` variant: Mini 24, Small 32, Medium 40, Large 48. */
6
+ size?: AvatarSize;
7
+ /** Matches the Figma `Shape` variant. */
8
+ shape?: AvatarShape;
9
+ /** Image source. Figma's `Type=Image`. */
10
+ src?: string;
11
+ /**
12
+ * Describes the person, not the picture. Falls back to `initials` so the
13
+ * avatar is never announced as an unlabelled image.
14
+ */
15
+ alt?: string;
16
+ /** Figma's `Type=Character`. Rendered when there is no `src`. */
17
+ initials?: string;
18
+ /** Figma's `Type=Icon`. Rendered when there is neither `src` nor `initials`. */
19
+ icon?: React.ReactNode;
20
+ }
21
+ /**
22
+ * Avatar picks its content the way Figma's `Type` variant does, but by
23
+ * precedence rather than by a prop: image, then initials, then icon. A caller
24
+ * passing `src` and `initials` gets the image with the initials as its alt
25
+ * fallback, which is what you want when the image 404s.
26
+ *
27
+ * It is a `<span>`, not a `<div>`, so it can sit inline beside text without the
28
+ * caller fighting a block element.
29
+ */
30
+ export declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLSpanElement>>;
31
+ export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
32
+ size?: AvatarSize;
33
+ /** Cap on avatars shown; the remainder becomes a `+N` overflow avatar. */
34
+ max?: number;
35
+ shape?: AvatarShape;
36
+ children?: React.ReactNode;
37
+ }
38
+ /**
39
+ * AvatarGroup overlaps its children by a quarter of the avatar size, matching
40
+ * Figma's -6 / -8 / -10 / -12 gaps at Mini / Small / Medium / Large.
41
+ *
42
+ * It passes `size` and `shape` down rather than trusting the caller to set them
43
+ * on every child: the overlap is computed from the size, so a mismatched child
44
+ * would overlap by the wrong amount and the error would look like a design bug
45
+ * rather than a wiring one.
46
+ *
47
+ * Children render in source order because that is Figma's stacking: each avatar
48
+ * paints over the one before it, so the `+N` overflow ends up on top. Later
49
+ * siblings paint later, so this needs no z-index.
50
+ */
51
+ export declare const AvatarGroup: React.ForwardRefExoticComponent<AvatarGroupProps & React.RefAttributes<HTMLDivElement>>;
52
+ //# sourceMappingURL=Avatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/components/Avatar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACrD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,WAAW,WAAY,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;IACxE,gFAAgF;IAChF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,yCAAyC;IACzC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM,qFA8ClB,CAAC;AAIF,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5E,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,yFA6CvB,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { forwardRef } from 'react';
3
+ /**
4
+ * Avatar picks its content the way Figma's `Type` variant does, but by
5
+ * precedence rather than by a prop: image, then initials, then icon. A caller
6
+ * passing `src` and `initials` gets the image with the initials as its alt
7
+ * fallback, which is what you want when the image 404s.
8
+ *
9
+ * It is a `<span>`, not a `<div>`, so it can sit inline beside text without the
10
+ * caller fighting a block element.
11
+ */
12
+ export const Avatar = forwardRef(({ size = 'md', shape = 'circle', src, alt, initials, icon, className, ...rest }, ref) => {
13
+ const classNames = [
14
+ 'ion-avatar',
15
+ size !== 'md' ? `ion-avatar--${size}` : '',
16
+ shape === 'circle' ? 'ion-avatar--circle' : '',
17
+ className || '',
18
+ ]
19
+ .filter(Boolean)
20
+ .join(' ');
21
+ const label = alt ?? initials;
22
+ return (_jsx("span", { ...rest, ref: ref, className: classNames, ...(!src && label ? { role: 'img', 'aria-label': label } : {}), children: src ? (_jsx("img", { className: "ion-avatar__image", src: src, alt: label ?? '' })) : initials ? (_jsx("span", { "aria-hidden": "true", children: initials })) : icon ? (_jsx("span", { className: "ion-avatar__icon", "aria-hidden": "true", children: icon })) : null }));
23
+ });
24
+ Avatar.displayName = 'Avatar';
25
+ /**
26
+ * AvatarGroup overlaps its children by a quarter of the avatar size, matching
27
+ * Figma's -6 / -8 / -10 / -12 gaps at Mini / Small / Medium / Large.
28
+ *
29
+ * It passes `size` and `shape` down rather than trusting the caller to set them
30
+ * on every child: the overlap is computed from the size, so a mismatched child
31
+ * would overlap by the wrong amount and the error would look like a design bug
32
+ * rather than a wiring one.
33
+ *
34
+ * Children render in source order because that is Figma's stacking: each avatar
35
+ * paints over the one before it, so the `+N` overflow ends up on top. Later
36
+ * siblings paint later, so this needs no z-index.
37
+ */
38
+ export const AvatarGroup = forwardRef(({ size = 'md', shape = 'circle', max, className, children, ...rest }, ref) => {
39
+ const items = React.Children.toArray(children).filter(React.isValidElement);
40
+ const shown = max !== undefined ? items.slice(0, max) : items;
41
+ const overflow = items.length - shown.length;
42
+ const sized = shown.map((child, i) => React.cloneElement(child, {
43
+ size,
44
+ shape,
45
+ key: child.key ?? i,
46
+ }));
47
+ if (overflow > 0) {
48
+ sized.push(_jsx(Avatar, { size: size, shape: shape, initials: `+${overflow}`, alt: `${overflow} more` }, "__overflow"));
49
+ }
50
+ return (_jsx("div", { ...rest, ref: ref, className: [
51
+ 'ion-avatar-group',
52
+ `ion-avatar-group--${size}`,
53
+ className || '',
54
+ ]
55
+ .filter(Boolean)
56
+ .join(' '), children: sized }));
57
+ });
58
+ AvatarGroup.displayName = 'AvatarGroup';
59
+ //# sourceMappingURL=Avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.js","sourceRoot":"","sources":["../../src/components/Avatar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ export type BadgeIntent = 'neutral' | 'primary' | 'success' | 'warning' | 'error' | 'information';
3
+ export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
4
+ /** Matches the Figma `Intent` variant. */
5
+ intent?: BadgeIntent;
6
+ /**
7
+ * Show the leading dot marker. Figma's `Show Dot` boolean.
8
+ * The dot inherits the intent's foreground colour, so it needs no prop.
9
+ */
10
+ dot?: boolean;
11
+ /** Leading icon. Figma's `Show Icon` + `Icon` swap. Mutually exclusive with `dot`. */
12
+ icon?: React.ReactNode;
13
+ children?: React.ReactNode;
14
+ }
15
+ /**
16
+ * Badge is presentational — no role, no interaction. React Aria has nothing to
17
+ * offer here, so this is a plain span rather than a hook wrapper for its own
18
+ * sake.
19
+ *
20
+ * It carries no `status` or `alert` role on purpose: a badge is a label on
21
+ * something else, and announcing it as a live region would interrupt screen
22
+ * reader users on every render. Wrap it yourself if the value genuinely changes
23
+ * and matters.
24
+ */
25
+ export declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>;
26
+ //# sourceMappingURL=Badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../src/components/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,MAAM,MAAM,WAAW,GACrB,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAE1E,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;IACvE,0CAA0C;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sFAAsF;IACtF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,oFAcjB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ /**
4
+ * Badge is presentational — no role, no interaction. React Aria has nothing to
5
+ * offer here, so this is a plain span rather than a hook wrapper for its own
6
+ * sake.
7
+ *
8
+ * It carries no `status` or `alert` role on purpose: a badge is a label on
9
+ * something else, and announcing it as a live region would interrupt screen
10
+ * reader users on every render. Wrap it yourself if the value genuinely changes
11
+ * and matters.
12
+ */
13
+ export const Badge = forwardRef(({ intent = 'neutral', dot, icon, className, children, ...rest }, ref) => (_jsxs("span", { ...rest, ref: ref, className: ['ion-badge', `ion-badge--${intent}`, className]
14
+ .filter(Boolean)
15
+ .join(' '), children: [dot && _jsx("span", { className: "ion-badge__dot", "aria-hidden": "true" }), !dot && icon, children] })));
16
+ Badge.displayName = 'Badge';
17
+ //# sourceMappingURL=Badge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../src/components/Badge.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAkB1C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAC7B,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CACxE,mBACM,IAAI,EACR,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,CAAC,WAAW,EAAE,cAAc,MAAM,EAAE,EAAE,SAAS,CAAC;SACxD,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,aAEX,GAAG,IAAI,eAAM,SAAS,EAAC,gBAAgB,iBAAa,MAAM,GAAG,EAC7D,CAAC,GAAG,IAAI,IAAI,EACZ,QAAQ,IACJ,CACR,CACF,CAAC;AAEF,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC"}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { type AriaButtonProps } from 'react-aria';
3
+ export interface ButtonProps extends AriaButtonProps<'button'> {
4
+ /** The visual style variant of the button. */
5
+ variant?: 'primary-brand' | 'primary-neutral' | 'secondary' | 'tertiary' | 'destructive';
6
+ /** The size of the button. */
7
+ size?: 'sm' | 'md' | 'lg';
8
+ /** Optional icon to render before the label. */
9
+ startIcon?: React.ReactNode;
10
+ /** Optional icon to render after the label. */
11
+ endIcon?: React.ReactNode;
12
+ /** Additional CSS class names. */
13
+ className?: string;
14
+ /** Children element to render inside the button. */
15
+ children?: React.ReactNode;
16
+ }
17
+ export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
18
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAC;AACvE,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,WAAY,SAAQ,eAAe,CAAC,QAAQ,CAAC;IAC5D,8CAA8C;IAC9C,OAAO,CAAC,EACJ,eAAe,GACf,iBAAiB,GACjB,WAAW,GACX,UAAU,GACV,aAAa,CAAC;IAClB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,MAAM,uFAoElB,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useRef, useImperativeHandle } from 'react';
3
+ import { useButton, useHover, useFocusRing, mergeProps, } from 'react-aria';
4
+ export const Button = forwardRef((props, forwardedRef) => {
5
+ const { variant = 'primary-brand', size = 'md', startIcon, endIcon, className: customClassName, children, isDisabled, ...restProps } = props;
6
+ const domRef = useRef(null);
7
+ useImperativeHandle(forwardedRef, () => domRef.current);
8
+ const { buttonProps, isPressed } = useButton(props, domRef);
9
+ /*
10
+ * Interaction state comes from React Aria rather than CSS pseudo-classes.
11
+ *
12
+ * `useHover` is pointer-aware: native `:hover` latches on touch devices, so
13
+ * a tapped button stays visually hovered until you tap elsewhere.
14
+ * `useFocusRing` distinguishes keyboard focus from a mouse click, so the
15
+ * ring appears when navigating but not when clicking.
16
+ *
17
+ * The CSS keeps its `:hover` / `:focus-visible` rules so the stylesheet
18
+ * still works without React — these attributes refine that, they do not
19
+ * replace it.
20
+ */
21
+ const { hoverProps, isHovered } = useHover({ isDisabled });
22
+ const { focusProps, isFocusVisible } = useFocusRing();
23
+ const classNames = [
24
+ 'ion-button',
25
+ `ion-button--${variant}`,
26
+ size !== 'md' ? `ion-button--${size}` : '',
27
+ customClassName || '',
28
+ ]
29
+ .filter(Boolean)
30
+ .join(' ');
31
+ // `undefined` rather than `false` so the attribute is omitted entirely
32
+ // instead of rendering data-hovered="false", which would still match
33
+ // an `[data-hovered]` selector.
34
+ const stateAttributes = {
35
+ 'data-hovered': isHovered || undefined,
36
+ 'data-pressed': isPressed || undefined,
37
+ 'data-focused': isFocusVisible || undefined,
38
+ 'data-disabled': isDisabled || undefined,
39
+ };
40
+ return (_jsxs("button", { ...restProps, ...mergeProps(buttonProps, hoverProps, focusProps), ...stateAttributes, ref: domRef, className: classNames, children: [startIcon && (_jsx("span", { className: "ion-button__icon-start", children: startIcon })), children && _jsx("span", { className: "ion-button__label", children: children }), endIcon && _jsx("span", { className: "ion-button__icon-end", children: endIcon })] }));
41
+ });
42
+ Button.displayName = 'Button';
43
+ //# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,UAAU,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AACvE,OAAO,EACL,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,UAAU,GAEX,MAAM,YAAY,CAAC;AAsBpB,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAC9B,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE;IACtB,MAAM,EACJ,OAAO,GAAG,eAAe,EACzB,IAAI,GAAG,IAAI,EACX,SAAS,EACT,OAAO,EACP,SAAS,EAAE,eAAe,EAC1B,QAAQ,EACR,UAAU,EACV,GAAG,SAAS,EACb,GAAG,KAAK,CAAC;IAEV,MAAM,MAAM,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAC/C,mBAAmB,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAQ,CAAC,CAAC;IAEzD,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAE5D;;;;;;;;;;;OAWG;IACH,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3D,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,YAAY,EAAE,CAAC;IAEtD,MAAM,UAAU,GAAG;QACjB,YAAY;QACZ,eAAe,OAAO,EAAE;QACxB,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;QAC1C,eAAe,IAAI,EAAE;KACtB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,uEAAuE;IACvE,qEAAqE;IACrE,gCAAgC;IAChC,MAAM,eAAe,GAAG;QACtB,cAAc,EAAE,SAAS,IAAI,SAAS;QACtC,cAAc,EAAE,SAAS,IAAI,SAAS;QACtC,cAAc,EAAE,cAAc,IAAI,SAAS;QAC3C,eAAe,EAAE,UAAU,IAAI,SAAS;KACzC,CAAC;IAEF,OAAO,CACL,qBACM,SAAS,KACT,UAAU,CAAC,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,KAC/C,eAAe,EACnB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,UAAU,aAEpB,SAAS,IAAI,CACZ,eAAM,SAAS,EAAC,wBAAwB,YAAE,SAAS,GAAQ,CAC5D,EACA,QAAQ,IAAI,eAAM,SAAS,EAAC,mBAAmB,YAAE,QAAQ,GAAQ,EACjE,OAAO,IAAI,eAAM,SAAS,EAAC,sBAAsB,YAAE,OAAO,GAAQ,IAC5D,CACV,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC"}
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ export type CheckboxSize = 'sm' | 'md' | 'lg';
3
+ export type CheckboxIntent = 'brand' | 'neutral' | 'danger';
4
+ export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {
5
+ /** Matches the Figma `Size` variant: Small, Medium, Large. */
6
+ size?: CheckboxSize;
7
+ /** Matches the Figma `Color` variant: Brand, Neutral, Danger. */
8
+ intent?: CheckboxIntent;
9
+ /**
10
+ * Figma's `Indeterminate` state. Not an HTML attribute — `indeterminate` is a
11
+ * DOM property only, so it has to be assigned after render.
12
+ */
13
+ isIndeterminate?: boolean;
14
+ /** Figma's `Show Label` + `Label`. Omit for a bare box. */
15
+ children?: React.ReactNode;
16
+ }
17
+ /**
18
+ * Checkbox wraps a native `<input type="checkbox">` and hides it.
19
+ *
20
+ * The native input is kept rather than replaced by a div with `role=checkbox`
21
+ * because it brings form association, the indeterminate property, label
22
+ * clicking, and correct announcement — none of which are free to reimplement,
23
+ * and all of which are easy to get subtly wrong.
24
+ *
25
+ * `indeterminate` is the reason for the effect below: HTML has no
26
+ * `indeterminate` attribute, only a DOM property, so React cannot set it
27
+ * declaratively and it must be written after every render.
28
+ */
29
+ export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
30
+ //# sourceMappingURL=Checkbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../src/components/Checkbox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAKN,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC9C,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,aAAc,SAAQ,IAAI,CACzC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAC3C,MAAM,GAAG,MAAM,CAChB;IACC,8DAA8D;IAC9D,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,iEAAiE;IACjE,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AA2BD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,wFA+CpB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useRef, useImperativeHandle, useEffect, } from 'react';
3
+ /** Figma's check glyph. Inlined for the same reason as Select's chevron: it is
4
+ * part of the control, not a slot a caller fills. */
5
+ const CheckMark = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "m5 13 4 4L19 7", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" }) }));
6
+ const DashMark = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M6 12h12", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" }) }));
7
+ /**
8
+ * Checkbox wraps a native `<input type="checkbox">` and hides it.
9
+ *
10
+ * The native input is kept rather than replaced by a div with `role=checkbox`
11
+ * because it brings form association, the indeterminate property, label
12
+ * clicking, and correct announcement — none of which are free to reimplement,
13
+ * and all of which are easy to get subtly wrong.
14
+ *
15
+ * `indeterminate` is the reason for the effect below: HTML has no
16
+ * `indeterminate` attribute, only a DOM property, so React cannot set it
17
+ * declaratively and it must be written after every render.
18
+ */
19
+ export const Checkbox = forwardRef((props, forwardedRef) => {
20
+ const { size = 'md', intent = 'brand', isIndeterminate = false, className, children, disabled, ...rest } = props;
21
+ const domRef = useRef(null);
22
+ useImperativeHandle(forwardedRef, () => domRef.current);
23
+ useEffect(() => {
24
+ if (domRef.current)
25
+ domRef.current.indeterminate = isIndeterminate;
26
+ }, [isIndeterminate]);
27
+ const classNames = [
28
+ 'ion-checkbox',
29
+ size !== 'md' ? `ion-checkbox--${size}` : '',
30
+ intent !== 'brand' ? `ion-checkbox--${intent}` : '',
31
+ disabled ? 'ion-checkbox--disabled' : '',
32
+ className || '',
33
+ ]
34
+ .filter(Boolean)
35
+ .join(' ');
36
+ return (_jsxs("label", { className: classNames, children: [_jsx("input", { ...rest, ref: domRef, type: "checkbox", disabled: disabled, className: "ion-checkbox__input" }), _jsx("span", { className: "ion-checkbox__indicator", "aria-hidden": "true", children: _jsx("span", { className: "ion-checkbox__mark", children: isIndeterminate ? _jsx(DashMark, {}) : _jsx(CheckMark, {}) }) }), children && _jsx("span", { className: "ion-checkbox__label", children: children })] }));
37
+ });
38
+ Checkbox.displayName = 'Checkbox';
39
+ //# sourceMappingURL=Checkbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../src/components/Checkbox.tsx"],"names":[],"mappings":";AAAA,OAAc,EACZ,UAAU,EACV,MAAM,EACN,mBAAmB,EACnB,SAAS,GACV,MAAM,OAAO,CAAC;AAsBf;sDACsD;AACtD,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,CACtB,cAAK,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,iBAAa,MAAM,EAAC,SAAS,EAAC,OAAO,YACvE,eACE,CAAC,EAAC,gBAAgB,EAClB,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,GACtB,GACE,CACP,CAAC;AAEF,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,CACrB,cAAK,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,iBAAa,MAAM,EAAC,SAAS,EAAC,OAAO,YACvE,eACE,CAAC,EAAC,UAAU,EACZ,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,GACrB,GACE,CACP,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAChC,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE;IACtB,MAAM,EACJ,IAAI,GAAG,IAAI,EACX,MAAM,GAAG,OAAO,EAChB,eAAe,GAAG,KAAK,EACvB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,GAAG,IAAI,EACR,GAAG,KAAK,CAAC;IAEV,MAAM,MAAM,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAC9C,mBAAmB,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAQ,CAAC,CAAC;IAEzD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,CAAC,OAAO;YAAE,MAAM,CAAC,OAAO,CAAC,aAAa,GAAG,eAAe,CAAC;IACrE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,MAAM,UAAU,GAAG;QACjB,cAAc;QACd,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;QAC5C,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,iBAAiB,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE;QACnD,QAAQ,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE;QACxC,SAAS,IAAI,EAAE;KAChB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,CACL,iBAAO,SAAS,EAAE,UAAU,aAC1B,mBACM,IAAI,EACR,GAAG,EAAE,MAAM,EACX,IAAI,EAAC,UAAU,EACf,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAC,qBAAqB,GAC/B,EACF,eAAM,SAAS,EAAC,yBAAyB,iBAAa,MAAM,YAC1D,eAAM,SAAS,EAAC,oBAAoB,YACjC,eAAe,CAAC,CAAC,CAAC,KAAC,QAAQ,KAAG,CAAC,CAAC,CAAC,KAAC,SAAS,KAAG,GAC1C,GACF,EACN,QAAQ,IAAI,eAAM,SAAS,EAAC,qBAAqB,YAAE,QAAQ,GAAQ,IAC9D,CACT,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC"}
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ export type DividerOrientation = 'horizontal' | 'vertical';
3
+ export interface DividerProps extends React.HTMLAttributes<HTMLHRElement> {
4
+ /** Matches Figma's `Style` variant. */
5
+ orientation?: DividerOrientation;
6
+ }
7
+ /**
8
+ * A single `<hr>`, matching Figma's `Border` (70:22153).
9
+ *
10
+ * `<hr>` rather than a styled `<div>`: it is a semantic thematic break, so a
11
+ * screen reader announces it as one, and it needs no `role` to get there.
12
+ * `aria-orientation` is set for the vertical case, since a vertical rule
13
+ * inside a horizontal toolbar is the one shape a screen reader cannot infer
14
+ * from the element alone.
15
+ */
16
+ export declare const Divider: React.ForwardRefExoticComponent<DividerProps & React.RefAttributes<HTMLHRElement>>;
17
+ //# sourceMappingURL=Divider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Divider.d.ts","sourceRoot":"","sources":["../../src/components/Divider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAE1C,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,UAAU,CAAC;AAE3D,MAAM,WAAW,YAAa,SAAQ,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC;IACvE,uCAAuC;IACvC,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,oFAWnB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ /**
4
+ * A single `<hr>`, matching Figma's `Border` (70:22153).
5
+ *
6
+ * `<hr>` rather than a styled `<div>`: it is a semantic thematic break, so a
7
+ * screen reader announces it as one, and it needs no `role` to get there.
8
+ * `aria-orientation` is set for the vertical case, since a vertical rule
9
+ * inside a horizontal toolbar is the one shape a screen reader cannot infer
10
+ * from the element alone.
11
+ */
12
+ export const Divider = forwardRef(({ orientation = 'horizontal', className, ...rest }, ref) => (_jsx("hr", { ...rest, ref: ref, "aria-orientation": orientation === 'vertical' ? 'vertical' : undefined, className: ['ion-divider', `ion-divider--${orientation}`, className]
13
+ .filter(Boolean)
14
+ .join(' ') })));
15
+ Divider.displayName = 'Divider';
16
+ //# sourceMappingURL=Divider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Divider.js","sourceRoot":"","sources":["../../src/components/Divider.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAS1C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,UAAU,CAC/B,CAAC,EAAE,WAAW,GAAG,YAAY,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAC3D,gBACM,IAAI,EACR,GAAG,EAAE,GAAG,sBACU,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EACrE,SAAS,EAAE,CAAC,aAAa,EAAE,gBAAgB,WAAW,EAAE,EAAE,SAAS,CAAC;SACjE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,GACZ,CACH,CACF,CAAC;AAEF,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC"}
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ export interface HeaderProps extends React.HTMLAttributes<HTMLElement> {
3
+ /** Figma's Logo slot. Rendered at the start, never shrinks. */
4
+ brand?: React.ReactNode;
5
+ /** Figma's `Center Slot`. Hidden below 1216px, as in the Tablet and Mobile variants. */
6
+ center?: React.ReactNode;
7
+ /** Figma's `End Slot`. */
8
+ end?: React.ReactNode;
9
+ children?: React.ReactNode;
10
+ }
11
+ /**
12
+ * Header renders Figma's three Device variants through media queries, not a
13
+ * prop.
14
+ *
15
+ * Device is the one variant axis in the system the browser already knows the
16
+ * answer to. Every other component takes its variant from the caller because
17
+ * the caller is the only one who knows; a header is Mobile because the viewport
18
+ * is narrow, and having React duplicate that judgement is how the two drift
19
+ * apart. Breakpoints match the Breakpoint collection's container widths.
20
+ *
21
+ * A `<header>` element with no explicit role: it is a landmark already when it
22
+ * is a direct child of body, which is where a page header sits.
23
+ */
24
+ export declare const Header: React.ForwardRefExoticComponent<HeaderProps & React.RefAttributes<HTMLElement>>;
25
+ //# sourceMappingURL=Header.d.ts.map