@misoto22/design 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/Accordion/Accordion.d.ts +34 -0
  3. package/dist/components/Accordion/Accordion.js +37 -0
  4. package/dist/components/Accordion/Accordion.js.map +1 -0
  5. package/dist/components/Alert/Alert.d.ts +32 -0
  6. package/dist/components/Alert/Alert.js +49 -0
  7. package/dist/components/Alert/Alert.js.map +1 -0
  8. package/dist/components/AppShell/AppShell.d.ts +38 -0
  9. package/dist/components/AppShell/AppShell.js +92 -0
  10. package/dist/components/AppShell/AppShell.js.map +1 -0
  11. package/dist/components/Avatar/Avatar.d.ts +29 -0
  12. package/dist/components/Avatar/Avatar.js +39 -0
  13. package/dist/components/Avatar/Avatar.js.map +1 -0
  14. package/dist/components/Badge/Badge.d.ts +30 -0
  15. package/dist/components/Badge/Badge.js +29 -0
  16. package/dist/components/Badge/Badge.js.map +1 -0
  17. package/dist/components/Breadcrumb/Breadcrumb.d.ts +31 -0
  18. package/dist/components/Breadcrumb/Breadcrumb.js +31 -0
  19. package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -0
  20. package/dist/components/Button/Button.d.ts +70 -0
  21. package/dist/components/Button/Button.js +81 -0
  22. package/dist/components/Button/Button.js.map +1 -0
  23. package/dist/components/Calendar/Calendar.d.ts +28 -0
  24. package/dist/components/Calendar/Calendar.js +87 -0
  25. package/dist/components/Calendar/Calendar.js.map +1 -0
  26. package/dist/components/Card/Card.d.ts +49 -0
  27. package/dist/components/Card/Card.js +64 -0
  28. package/dist/components/Card/Card.js.map +1 -0
  29. package/dist/components/Checkbox/Checkbox.d.ts +23 -0
  30. package/dist/components/Checkbox/Checkbox.js +24 -0
  31. package/dist/components/Checkbox/Checkbox.js.map +1 -0
  32. package/dist/components/Collapsible/Collapsible.d.ts +31 -0
  33. package/dist/components/Collapsible/Collapsible.js +35 -0
  34. package/dist/components/Collapsible/Collapsible.js.map +1 -0
  35. package/dist/components/Combobox/Combobox.d.ts +63 -0
  36. package/dist/components/Combobox/Combobox.js +151 -0
  37. package/dist/components/Combobox/Combobox.js.map +1 -0
  38. package/dist/components/Command/Command.d.ts +98 -0
  39. package/dist/components/Command/Command.js +166 -0
  40. package/dist/components/Command/Command.js.map +1 -0
  41. package/dist/components/ContextMenu/ContextMenu.d.ts +38 -0
  42. package/dist/components/ContextMenu/ContextMenu.js +79 -0
  43. package/dist/components/ContextMenu/ContextMenu.js.map +1 -0
  44. package/dist/components/DatePicker/DatePicker.d.ts +98 -0
  45. package/dist/components/DatePicker/DatePicker.js +214 -0
  46. package/dist/components/DatePicker/DatePicker.js.map +1 -0
  47. package/dist/components/Dialog/Dialog.d.ts +48 -0
  48. package/dist/components/Dialog/Dialog.js +72 -0
  49. package/dist/components/Dialog/Dialog.js.map +1 -0
  50. package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -0
  51. package/dist/components/DropdownMenu/DropdownMenu.js +89 -0
  52. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -0
  53. package/dist/components/EmptyState/EmptyState.d.ts +31 -0
  54. package/dist/components/EmptyState/EmptyState.js +30 -0
  55. package/dist/components/EmptyState/EmptyState.js.map +1 -0
  56. package/dist/components/ErrorState/ErrorState.d.ts +34 -0
  57. package/dist/components/ErrorState/ErrorState.js +32 -0
  58. package/dist/components/ErrorState/ErrorState.js.map +1 -0
  59. package/dist/components/Field/Field.d.ts +44 -0
  60. package/dist/components/Field/Field.js +54 -0
  61. package/dist/components/Field/Field.js.map +1 -0
  62. package/dist/components/FigureBand/FigureBand.d.ts +51 -0
  63. package/dist/components/FigureBand/FigureBand.js +52 -0
  64. package/dist/components/FigureBand/FigureBand.js.map +1 -0
  65. package/dist/components/FloatingIconButton/FloatingIconButton.d.ts +29 -0
  66. package/dist/components/FloatingIconButton/FloatingIconButton.js +32 -0
  67. package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -0
  68. package/dist/components/Input/Input.d.ts +22 -0
  69. package/dist/components/Input/Input.js +21 -0
  70. package/dist/components/Input/Input.js.map +1 -0
  71. package/dist/components/Kbd/Kbd.d.ts +20 -0
  72. package/dist/components/Kbd/Kbd.js +21 -0
  73. package/dist/components/Kbd/Kbd.js.map +1 -0
  74. package/dist/components/LinkArrow/LinkArrow.d.ts +24 -0
  75. package/dist/components/LinkArrow/LinkArrow.js +24 -0
  76. package/dist/components/LinkArrow/LinkArrow.js.map +1 -0
  77. package/dist/components/NativeSelect/NativeSelect.d.ts +27 -0
  78. package/dist/components/NativeSelect/NativeSelect.js +46 -0
  79. package/dist/components/NativeSelect/NativeSelect.js.map +1 -0
  80. package/dist/components/NavItem/NavItem.d.ts +39 -0
  81. package/dist/components/NavItem/NavItem.js +31 -0
  82. package/dist/components/NavItem/NavItem.js.map +1 -0
  83. package/dist/components/Pagination/Pagination.d.ts +44 -0
  84. package/dist/components/Pagination/Pagination.js +109 -0
  85. package/dist/components/Pagination/Pagination.js.map +1 -0
  86. package/dist/components/Popover/Popover.d.ts +39 -0
  87. package/dist/components/Popover/Popover.js +57 -0
  88. package/dist/components/Popover/Popover.js.map +1 -0
  89. package/dist/components/Progress/Progress.d.ts +31 -0
  90. package/dist/components/Progress/Progress.js +45 -0
  91. package/dist/components/Progress/Progress.js.map +1 -0
  92. package/dist/components/RadioGroup/RadioGroup.d.ts +43 -0
  93. package/dist/components/RadioGroup/RadioGroup.js +43 -0
  94. package/dist/components/RadioGroup/RadioGroup.js.map +1 -0
  95. package/dist/components/ScrollArea/ScrollArea.d.ts +31 -0
  96. package/dist/components/ScrollArea/ScrollArea.js +54 -0
  97. package/dist/components/ScrollArea/ScrollArea.js.map +1 -0
  98. package/dist/components/SearchableMenu/SearchableMenu.d.ts +59 -0
  99. package/dist/components/SearchableMenu/SearchableMenu.js +79 -0
  100. package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -0
  101. package/dist/components/Select/Select.d.ts +71 -0
  102. package/dist/components/Select/Select.js +114 -0
  103. package/dist/components/Select/Select.js.map +1 -0
  104. package/dist/components/Separator/Separator.d.ts +30 -0
  105. package/dist/components/Separator/Separator.js +35 -0
  106. package/dist/components/Separator/Separator.js.map +1 -0
  107. package/dist/components/Sheet/Sheet.d.ts +38 -0
  108. package/dist/components/Sheet/Sheet.js +68 -0
  109. package/dist/components/Sheet/Sheet.js.map +1 -0
  110. package/dist/components/Skeleton/Skeleton.d.ts +63 -0
  111. package/dist/components/Skeleton/Skeleton.js +44 -0
  112. package/dist/components/Skeleton/Skeleton.js.map +1 -0
  113. package/dist/components/Slider/Slider.d.ts +35 -0
  114. package/dist/components/Slider/Slider.js +52 -0
  115. package/dist/components/Slider/Slider.js.map +1 -0
  116. package/dist/components/Spinner/Spinner.d.ts +50 -0
  117. package/dist/components/Spinner/Spinner.js +48 -0
  118. package/dist/components/Spinner/Spinner.js.map +1 -0
  119. package/dist/components/StatusDot/StatusDot.d.ts +29 -0
  120. package/dist/components/StatusDot/StatusDot.js +44 -0
  121. package/dist/components/StatusDot/StatusDot.js.map +1 -0
  122. package/dist/components/StatusPill/StatusPill.d.ts +25 -0
  123. package/dist/components/StatusPill/StatusPill.js +31 -0
  124. package/dist/components/StatusPill/StatusPill.js.map +1 -0
  125. package/dist/components/Switch/Switch.d.ts +23 -0
  126. package/dist/components/Switch/Switch.js +23 -0
  127. package/dist/components/Switch/Switch.js.map +1 -0
  128. package/dist/components/Table/Table.d.ts +96 -0
  129. package/dist/components/Table/Table.js +136 -0
  130. package/dist/components/Table/Table.js.map +1 -0
  131. package/dist/components/Tabs/Tabs.d.ts +35 -0
  132. package/dist/components/Tabs/Tabs.js +48 -0
  133. package/dist/components/Tabs/Tabs.js.map +1 -0
  134. package/dist/components/Tag/Tag.d.ts +28 -0
  135. package/dist/components/Tag/Tag.js +22 -0
  136. package/dist/components/Tag/Tag.js.map +1 -0
  137. package/dist/components/Textarea/Textarea.d.ts +20 -0
  138. package/dist/components/Textarea/Textarea.js +32 -0
  139. package/dist/components/Textarea/Textarea.js.map +1 -0
  140. package/dist/components/Toast/Toast.d.ts +24 -0
  141. package/dist/components/Toast/Toast.js +41 -0
  142. package/dist/components/Toast/Toast.js.map +1 -0
  143. package/dist/components/ToggleGroup/ToggleGroup.d.ts +41 -0
  144. package/dist/components/ToggleGroup/ToggleGroup.js +78 -0
  145. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -0
  146. package/dist/components/Tooltip/Tooltip.d.ts +43 -0
  147. package/dist/components/Tooltip/Tooltip.js +40 -0
  148. package/dist/components/Tooltip/Tooltip.js.map +1 -0
  149. package/dist/fonts/hanken-grotesk-300.woff2 +0 -0
  150. package/dist/fonts/hanken-grotesk-400.woff2 +0 -0
  151. package/dist/fonts/hanken-grotesk-500.woff2 +0 -0
  152. package/dist/fonts/hanken-grotesk-600.woff2 +0 -0
  153. package/dist/fonts/hanken-grotesk-700.woff2 +0 -0
  154. package/dist/fonts/ibm-plex-mono-400.woff2 +0 -0
  155. package/dist/fonts/ibm-plex-mono-500.woff2 +0 -0
  156. package/dist/fonts/ibm-plex-mono-600.woff2 +0 -0
  157. package/dist/fonts/newsreader-300.woff2 +0 -0
  158. package/dist/fonts/newsreader-400.woff2 +0 -0
  159. package/dist/fonts/newsreader-500.woff2 +0 -0
  160. package/dist/fonts/newsreader-600.woff2 +0 -0
  161. package/dist/fonts.css +96 -0
  162. package/dist/index.d.ts +77 -0
  163. package/dist/index.js +63 -0
  164. package/dist/index.js.map +1 -0
  165. package/dist/keyframes.css +212 -0
  166. package/dist/lib/cn.d.ts +21 -0
  167. package/dist/lib/cn.js +9 -0
  168. package/dist/lib/cn.js.map +1 -0
  169. package/dist/lib/control.d.ts +31 -0
  170. package/dist/lib/control.js +14 -0
  171. package/dist/lib/control.js.map +1 -0
  172. package/dist/lib/index.d.ts +4 -0
  173. package/dist/lib/index.js +11 -0
  174. package/dist/lib/index.js.map +1 -0
  175. package/dist/lib/overlay-container.d.ts +38 -0
  176. package/dist/lib/overlay-container.js +15 -0
  177. package/dist/lib/overlay-container.js.map +1 -0
  178. package/dist/lib/useSelectionIndicator.d.ts +29 -0
  179. package/dist/lib/useSelectionIndicator.js +45 -0
  180. package/dist/lib/useSelectionIndicator.js.map +1 -0
  181. package/dist/semantic.css +127 -0
  182. package/dist/styles.css +98 -0
  183. package/dist/themes.css +115 -0
  184. package/dist/tokens/brand.d.ts +47 -0
  185. package/dist/tokens/brand.js +38 -0
  186. package/dist/tokens/brand.js.map +1 -0
  187. package/dist/tokens.css +323 -0
  188. package/dist/tokens.d.ts +153 -0
  189. package/dist/tokens.js +766 -0
  190. package/dist/tokens.json +765 -0
  191. package/package.json +130 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Henry Chen
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.
@@ -0,0 +1,34 @@
1
+ import * as react from 'react';
2
+ import { ComponentProps, ReactNode } from 'react';
3
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
4
+
5
+ /**
6
+ * Radix root, re-exported. Pass `type="single" collapsible` for an FAQ and
7
+ * `type="multiple"` for a settings stack; Radix's own discriminated union then
8
+ * types `value` correctly for each.
9
+ */
10
+ declare const Accordion: react.ForwardRefExoticComponent<(AccordionPrimitive.AccordionSingleProps | AccordionPrimitive.AccordionMultipleProps) & react.RefAttributes<HTMLDivElement>>;
11
+ interface AccordionItemProps extends Omit<ComponentProps<typeof AccordionPrimitive.Item>, 'children' | 'title'> {
12
+ /** The row's summary — what the reader clicks. Named `title` rather than
13
+ * inherited from the DOM attribute of the same name, which is a tooltip. */
14
+ title: ReactNode;
15
+ children: ReactNode;
16
+ }
17
+ /**
18
+ * One disclosure row: a hairline-ruled trigger and its panel.
19
+ *
20
+ * The marker is a plus that rotates into a minus, not a chevron. A chevron says
21
+ * "there is more below"; a plus says "this opens" — and in a stack of rows the
22
+ * difference decides whether the reader expects navigation or expansion.
23
+ *
24
+ * The panel animates on Radix's own `--radix-accordion-content-height`, so it
25
+ * opens to its real height without measuring anything at the call site.
26
+ *
27
+ * @example
28
+ * <Accordion type="single" collapsible>
29
+ * <AccordionItem value="ship" title="How do I ship it?">Push to main.</AccordionItem>
30
+ * </Accordion>
31
+ */
32
+ declare function AccordionItem({ title, children, className, ...rest }: AccordionItemProps): react.JSX.Element;
33
+
34
+ export { Accordion, AccordionItem, type AccordionItemProps, Accordion as default };
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
4
+ import { Plus } from "lucide-react";
5
+ import { cn } from "../../lib/cn.js";
6
+ const Accordion = AccordionPrimitive.Root;
7
+ function AccordionItem({ title, children, className, ...rest }) {
8
+ return /* @__PURE__ */ jsxs(
9
+ AccordionPrimitive.Item,
10
+ {
11
+ className: cn("border-b border-(--rule)", className),
12
+ ...rest,
13
+ children: [
14
+ /* @__PURE__ */ jsx(AccordionPrimitive.Header, { className: "m-0", children: /* @__PURE__ */ jsxs(AccordionPrimitive.Trigger, { className: "group flex w-full items-center justify-between gap-4 py-4 text-start font-sans text-sm text-(--ink) transition-colors duration-(--duration-fast) hover:text-(--ink-2)", children: [
15
+ title,
16
+ /* @__PURE__ */ jsx(
17
+ Plus,
18
+ {
19
+ size: 16,
20
+ strokeWidth: 1.5,
21
+ "aria-hidden": true,
22
+ className: "shrink-0 text-(--ink-3-aa) transition-transform duration-(--duration-base) ease-(--ease-out-expo) group-data-[state=open]:rotate-45"
23
+ }
24
+ )
25
+ ] }) }),
26
+ /* @__PURE__ */ jsx(AccordionPrimitive.Content, { className: "overflow-hidden text-sm leading-relaxed text-(--ink-2) data-[state=closed]:animate-[m22-accordion-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-accordion-down_var(--duration-base)_var(--ease)]", children: /* @__PURE__ */ jsx("div", { className: "pb-4 pe-8", children }) })
27
+ ]
28
+ }
29
+ );
30
+ }
31
+ var Accordion_default = Accordion;
32
+ export {
33
+ Accordion,
34
+ AccordionItem,
35
+ Accordion_default as default
36
+ };
37
+ //# sourceMappingURL=Accordion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Accordion/Accordion.tsx"],"sourcesContent":["'use client'\n\nimport * as AccordionPrimitive from '@radix-ui/react-accordion'\nimport { Plus } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/**\n * Radix root, re-exported. Pass `type=\"single\" collapsible` for an FAQ and\n * `type=\"multiple\"` for a settings stack; Radix's own discriminated union then\n * types `value` correctly for each.\n */\nexport const Accordion = AccordionPrimitive.Root\n\nexport interface AccordionItemProps\n extends Omit<ComponentProps<typeof AccordionPrimitive.Item>, 'children' | 'title'> {\n /** The row's summary — what the reader clicks. Named `title` rather than\n * inherited from the DOM attribute of the same name, which is a tooltip. */\n title: ReactNode\n children: ReactNode\n}\n\n/**\n * One disclosure row: a hairline-ruled trigger and its panel.\n *\n * The marker is a plus that rotates into a minus, not a chevron. A chevron says\n * \"there is more below\"; a plus says \"this opens\" — and in a stack of rows the\n * difference decides whether the reader expects navigation or expansion.\n *\n * The panel animates on Radix's own `--radix-accordion-content-height`, so it\n * opens to its real height without measuring anything at the call site.\n *\n * @example\n * <Accordion type=\"single\" collapsible>\n * <AccordionItem value=\"ship\" title=\"How do I ship it?\">Push to main.</AccordionItem>\n * </Accordion>\n */\nexport function AccordionItem({ title, children, className, ...rest }: AccordionItemProps) {\n return (\n <AccordionPrimitive.Item\n className={cn('border-b border-(--rule)', className)}\n {...rest}\n >\n <AccordionPrimitive.Header className=\"m-0\">\n <AccordionPrimitive.Trigger className=\"group flex w-full items-center justify-between gap-4 py-4 text-start font-sans text-sm text-(--ink) transition-colors duration-(--duration-fast) hover:text-(--ink-2)\">\n {title}\n <Plus\n size={16}\n strokeWidth={1.5}\n aria-hidden\n className=\"shrink-0 text-(--ink-3-aa) transition-transform duration-(--duration-base) ease-(--ease-out-expo) group-data-[state=open]:rotate-45\"\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n <AccordionPrimitive.Content className=\"overflow-hidden text-sm leading-relaxed text-(--ink-2) data-[state=closed]:animate-[m22-accordion-up_var(--duration-base)_var(--ease)] data-[state=open]:animate-[m22-accordion-down_var(--duration-base)_var(--ease)]\">\n <div className=\"pb-4 pe-8\">{children}</div>\n </AccordionPrimitive.Content>\n </AccordionPrimitive.Item>\n )\n}\n\nexport default Accordion\n"],"mappings":";AA4CQ,SAEE,KAFF;AA1CR,YAAY,wBAAwB;AACpC,SAAS,YAAY;AAErB,SAAS,UAAU;AAOZ,MAAM,YAAY,mBAAmB;AAyBrC,SAAS,cAAc,EAAE,OAAO,UAAU,WAAW,GAAG,KAAK,GAAuB;AACzF,SACE;AAAA,IAAC,mBAAmB;AAAA,IAAnB;AAAA,MACC,WAAW,GAAG,4BAA4B,SAAS;AAAA,MAClD,GAAG;AAAA,MAEJ;AAAA,4BAAC,mBAAmB,QAAnB,EAA0B,WAAU,OACnC,+BAAC,mBAAmB,SAAnB,EAA2B,WAAU,yKACnC;AAAA;AAAA,UACD;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,aAAa;AAAA,cACb,eAAW;AAAA,cACX,WAAU;AAAA;AAAA,UACZ;AAAA,WACF,GACF;AAAA,QACA,oBAAC,mBAAmB,SAAnB,EAA2B,WAAU,0NACpC,8BAAC,SAAI,WAAU,aAAa,UAAS,GACvC;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,oBAAQ;","names":[]}
@@ -0,0 +1,32 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ type AlertTone = 'info' | 'success' | 'warning' | 'danger';
5
+ interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
6
+ tone?: AlertTone;
7
+ title?: ReactNode;
8
+ children?: ReactNode;
9
+ /** Optional action — a retry, a link to the settings that fix this. */
10
+ action?: ReactNode;
11
+ /** Hides the leading icon for a dense inline notice. */
12
+ hideIcon?: boolean;
13
+ }
14
+ /**
15
+ * A message about the page, in place.
16
+ *
17
+ * Carries `role="alert"` for the danger tone and `role="status"` for the rest,
18
+ * which is the difference between interrupting the reader and waiting for a
19
+ * pause. Getting that backwards is the usual accessibility failure here: a
20
+ * "saved" toast that talks over someone mid-sentence, or a payment error that
21
+ * is never announced at all.
22
+ *
23
+ * The tone is the message's SEVERITY, not its decoration. Colour is doubled by
24
+ * an icon and by the words, so the meaning survives both monochrome printing
25
+ * and colour-blindness.
26
+ *
27
+ * @example
28
+ * <Alert tone="danger" title="Upload failed">The file exceeds 25 MB.</Alert>
29
+ */
30
+ declare function Alert({ tone, title, children, action, hideIcon, className, ...rest }: AlertProps): react.JSX.Element;
31
+
32
+ export { Alert, type AlertProps, type AlertTone, Alert as default };
@@ -0,0 +1,49 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { AlertTriangle, CheckCircle2, Info, XCircle } from "lucide-react";
3
+ import { cn } from "../../lib/cn.js";
4
+ const TONE = {
5
+ info: { surface: "border-(--rule-2) bg-(--paper-2)", mark: "text-(--ink-2)", icon: Info, live: "polite" },
6
+ success: { surface: "border-transparent bg-(--ok-soft)", mark: "text-(--ok)", icon: CheckCircle2, live: "polite" },
7
+ warning: { surface: "border-transparent bg-(--warn-soft)", mark: "text-(--warn)", icon: AlertTriangle, live: "polite" },
8
+ /* Assertive: a danger alert interrupts because whatever the reader is doing
9
+ is already failing. The other three wait for a pause in speech. */
10
+ danger: { surface: "border-transparent bg-(--danger-soft)", mark: "text-(--danger)", icon: XCircle, live: "assertive" }
11
+ };
12
+ function Alert({
13
+ tone = "info",
14
+ title,
15
+ children,
16
+ action,
17
+ hideIcon = false,
18
+ className,
19
+ ...rest
20
+ }) {
21
+ const { surface, mark, icon: Icon, live } = TONE[tone];
22
+ return /* @__PURE__ */ jsxs(
23
+ "div",
24
+ {
25
+ role: tone === "danger" ? "alert" : "status",
26
+ "aria-live": live,
27
+ className: cn(
28
+ "flex gap-3 rounded-(--radius) border p-4 text-sm text-(--ink-2)",
29
+ surface,
30
+ className
31
+ ),
32
+ ...rest,
33
+ children: [
34
+ !hideIcon && /* @__PURE__ */ jsx(Icon, { size: 18, strokeWidth: 1.5, className: cn("mt-px shrink-0", mark), "aria-hidden": true }),
35
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
36
+ title && /* @__PURE__ */ jsx("p", { className: "m-0 font-medium text-(--ink)", children: title }),
37
+ children && /* @__PURE__ */ jsx("div", { className: cn("leading-relaxed", title && "mt-1"), children }),
38
+ action && /* @__PURE__ */ jsx("div", { className: "mt-3", children: action })
39
+ ] })
40
+ ]
41
+ }
42
+ );
43
+ }
44
+ var Alert_default = Alert;
45
+ export {
46
+ Alert,
47
+ Alert_default as default
48
+ };
49
+ //# sourceMappingURL=Alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Alert/Alert.tsx"],"sourcesContent":["import { AlertTriangle, CheckCircle2, Info, XCircle } from 'lucide-react'\nimport type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport type AlertTone = 'info' | 'success' | 'warning' | 'danger'\n\nexport interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n tone?: AlertTone\n title?: ReactNode\n children?: ReactNode\n /** Optional action — a retry, a link to the settings that fix this. */\n action?: ReactNode\n /** Hides the leading icon for a dense inline notice. */\n hideIcon?: boolean\n}\n\nconst TONE: Record<AlertTone, { surface: string; mark: string; icon: typeof Info; live: 'polite' | 'assertive' }> = {\n info: { surface: 'border-(--rule-2) bg-(--paper-2)', mark: 'text-(--ink-2)', icon: Info, live: 'polite' },\n success: { surface: 'border-transparent bg-(--ok-soft)', mark: 'text-(--ok)', icon: CheckCircle2, live: 'polite' },\n warning: { surface: 'border-transparent bg-(--warn-soft)', mark: 'text-(--warn)', icon: AlertTriangle, live: 'polite' },\n /* Assertive: a danger alert interrupts because whatever the reader is doing\n is already failing. The other three wait for a pause in speech. */\n danger: { surface: 'border-transparent bg-(--danger-soft)', mark: 'text-(--danger)', icon: XCircle, live: 'assertive' },\n}\n\n/**\n * A message about the page, in place.\n *\n * Carries `role=\"alert\"` for the danger tone and `role=\"status\"` for the rest,\n * which is the difference between interrupting the reader and waiting for a\n * pause. Getting that backwards is the usual accessibility failure here: a\n * \"saved\" toast that talks over someone mid-sentence, or a payment error that\n * is never announced at all.\n *\n * The tone is the message's SEVERITY, not its decoration. Colour is doubled by\n * an icon and by the words, so the meaning survives both monochrome printing\n * and colour-blindness.\n *\n * @example\n * <Alert tone=\"danger\" title=\"Upload failed\">The file exceeds 25 MB.</Alert>\n */\nexport function Alert({\n tone = 'info',\n title,\n children,\n action,\n hideIcon = false,\n className,\n ...rest\n}: AlertProps) {\n const { surface, mark, icon: Icon, live } = TONE[tone]\n\n return (\n <div\n role={tone === 'danger' ? 'alert' : 'status'}\n aria-live={live}\n className={cn(\n 'flex gap-3 rounded-(--radius) border p-4 text-sm text-(--ink-2)',\n surface,\n className,\n )}\n {...rest}\n >\n {!hideIcon && <Icon size={18} strokeWidth={1.5} className={cn('mt-px shrink-0', mark)} aria-hidden />}\n <div className=\"min-w-0 flex-1\">\n {title && <p className=\"m-0 font-medium text-(--ink)\">{title}</p>}\n {children && <div className={cn('leading-relaxed', title && 'mt-1')}>{children}</div>}\n {action && <div className=\"mt-3\">{action}</div>}\n </div>\n </div>\n )\n}\n\nexport default Alert\n"],"mappings":"AA+DoB,cACd,YADc;AA/DpB,SAAS,eAAe,cAAc,MAAM,eAAe;AAE3D,SAAS,UAAU;AAcnB,MAAM,OAA8G;AAAA,EAClH,MAAM,EAAE,SAAS,oCAAoC,MAAM,kBAAkB,MAAM,MAAM,MAAM,SAAS;AAAA,EACxG,SAAS,EAAE,SAAS,qCAAqC,MAAM,eAAe,MAAM,cAAc,MAAM,SAAS;AAAA,EACjH,SAAS,EAAE,SAAS,uCAAuC,MAAM,iBAAiB,MAAM,eAAe,MAAM,SAAS;AAAA;AAAA;AAAA,EAGtH,QAAQ,EAAE,SAAS,yCAAyC,MAAM,mBAAmB,MAAM,SAAS,MAAM,YAAY;AACxH;AAkBO,SAAS,MAAM;AAAA,EACpB,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,GAAG;AACL,GAAe;AACb,QAAM,EAAE,SAAS,MAAM,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI;AAErD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,SAAS,WAAW,UAAU;AAAA,MACpC,aAAW;AAAA,MACX,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,SAAC,YAAY,oBAAC,QAAK,MAAM,IAAI,aAAa,KAAK,WAAW,GAAG,kBAAkB,IAAI,GAAG,eAAW,MAAC;AAAA,QACnG,qBAAC,SAAI,WAAU,kBACZ;AAAA,mBAAS,oBAAC,OAAE,WAAU,gCAAgC,iBAAM;AAAA,UAC5D,YAAY,oBAAC,SAAI,WAAW,GAAG,mBAAmB,SAAS,MAAM,GAAI,UAAS;AAAA,UAC9E,UAAU,oBAAC,SAAI,WAAU,QAAQ,kBAAO;AAAA,WAC3C;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,gBAAQ;","names":[]}
@@ -0,0 +1,38 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ interface AppShellProps extends HTMLAttributes<HTMLDivElement> {
5
+ /** Navigation content for the sidebar (e.g. a stack of `NavItem`s). */
6
+ sidebar: ReactNode;
7
+ /** Optional content for the sticky topbar, laid out after the mobile toggle. */
8
+ topbar?: ReactNode;
9
+ /** Optional brand lockup pinned to the top of the sidebar. */
10
+ brand?: ReactNode;
11
+ /**
12
+ * Which element the content well renders as.
13
+ *
14
+ * `main` is right for the shell of an application, and is the default. A
15
+ * document may contain exactly one `main` landmark, so an AppShell rendered
16
+ * INSIDE another page — a preview on a documentation site, a screenshot
17
+ * harness — must pass `div`, or the page has two and assistive tech can no
18
+ * longer answer "where is the content".
19
+ */
20
+ contentAs?: 'main' | 'div';
21
+ children: ReactNode;
22
+ }
23
+ /**
24
+ * Two columns on a desktop, one column and a drawer on a phone.
25
+ *
26
+ * The drawer closes on Escape as well as on the scrim, because a drawer that
27
+ * only closes by tapping outside it strands a keyboard user inside a menu they
28
+ * cannot leave. The scrim is a `<button>` for the same reason — a `<div>` with
29
+ * an `onClick` is not reachable by keyboard and not announced as anything.
30
+ *
31
+ * @example
32
+ * <AppShell brand={<Wordmark />} sidebar={<NavItem href="/">Home</NavItem>}>
33
+ * <Card>…</Card>
34
+ * </AppShell>
35
+ */
36
+ declare function AppShell({ sidebar, topbar, brand, contentAs: Content, children, className, ...rest }: AppShellProps): react.JSX.Element;
37
+
38
+ export { AppShell, type AppShellProps, AppShell as default };
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Menu, X } from "lucide-react";
4
+ import { useEffect, useId, useState } from "react";
5
+ import { cn } from "../../lib/cn.js";
6
+ function AppShell({
7
+ sidebar,
8
+ topbar,
9
+ brand,
10
+ contentAs: Content = "main",
11
+ children,
12
+ className,
13
+ ...rest
14
+ }) {
15
+ const [open, setOpen] = useState(false);
16
+ const sidebarId = useId();
17
+ useEffect(() => {
18
+ if (!open) return;
19
+ const onKey = (event) => {
20
+ if (event.key === "Escape") setOpen(false);
21
+ };
22
+ document.addEventListener("keydown", onKey);
23
+ return () => document.removeEventListener("keydown", onKey);
24
+ }, [open]);
25
+ return /* @__PURE__ */ jsxs(
26
+ "div",
27
+ {
28
+ className: cn("min-h-svh bg-(--paper) md:grid md:grid-cols-[15rem_1fr]", className),
29
+ ...rest,
30
+ children: [
31
+ open && /* @__PURE__ */ jsx(
32
+ "button",
33
+ {
34
+ type: "button",
35
+ "aria-label": "Close navigation",
36
+ onClick: () => setOpen(false),
37
+ className: "fixed inset-0 z-(--z-scrim) bg-(--scrim) md:hidden"
38
+ }
39
+ ),
40
+ /* @__PURE__ */ jsxs(
41
+ "aside",
42
+ {
43
+ id: sidebarId,
44
+ "aria-label": "Sidebar",
45
+ className: cn(
46
+ "fixed inset-y-0 start-0 z-(--z-modal) flex w-60 flex-col border-e border-(--rule) bg-(--paper) transition-transform duration-(--duration-slow) ease-(--ease-out-expo)",
47
+ // The drawer slides in from the edge reading STARTS at, so in an
48
+ // right-to-left document it comes from the right.
49
+ open ? "translate-x-0" : "-translate-x-full rtl:translate-x-full",
50
+ "md:static md:z-auto md:translate-x-0"
51
+ ),
52
+ children: [
53
+ brand && /* @__PURE__ */ jsx("div", { className: "flex h-14 items-center border-b border-(--rule) px-5", children: brand }),
54
+ /* @__PURE__ */ jsx(
55
+ "nav",
56
+ {
57
+ "aria-label": "Primary",
58
+ className: "flex flex-1 flex-col gap-1 overflow-y-auto p-3 scroll-slim",
59
+ children: sidebar
60
+ }
61
+ )
62
+ ]
63
+ }
64
+ ),
65
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col", children: [
66
+ /* @__PURE__ */ jsxs("header", { className: "sticky top-0 z-(--z-sticky) flex h-14 items-center gap-3 border-b border-(--rule) bg-(--paper)/85 px-(--page-pad) backdrop-blur", children: [
67
+ /* @__PURE__ */ jsx(
68
+ "button",
69
+ {
70
+ type: "button",
71
+ "aria-label": open ? "Close navigation" : "Open navigation",
72
+ "aria-expanded": open,
73
+ "aria-controls": sidebarId,
74
+ onClick: () => setOpen((previous) => !previous),
75
+ className: "-ms-2.5 grid size-11 place-items-center rounded-(--radius) text-(--ink-2) transition-colors duration-(--duration-fast) hover:text-(--ink) md:hidden",
76
+ children: open ? /* @__PURE__ */ jsx(X, { size: 20, strokeWidth: 1.5, "aria-hidden": true }) : /* @__PURE__ */ jsx(Menu, { size: 20, strokeWidth: 1.5, "aria-hidden": true })
77
+ }
78
+ ),
79
+ topbar
80
+ ] }),
81
+ /* @__PURE__ */ jsx(Content, { className: "mx-auto w-full max-w-(--w-page) px-(--page-pad) py-8", children })
82
+ ] })
83
+ ]
84
+ }
85
+ );
86
+ }
87
+ var AppShell_default = AppShell;
88
+ export {
89
+ AppShell,
90
+ AppShell_default as default
91
+ };
92
+ //# sourceMappingURL=AppShell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/AppShell/AppShell.tsx"],"sourcesContent":["'use client'\n\nimport { Menu, X } from 'lucide-react'\nimport { useEffect, useId, useState } from 'react'\nimport type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface AppShellProps extends HTMLAttributes<HTMLDivElement> {\n /** Navigation content for the sidebar (e.g. a stack of `NavItem`s). */\n sidebar: ReactNode\n /** Optional content for the sticky topbar, laid out after the mobile toggle. */\n topbar?: ReactNode\n /** Optional brand lockup pinned to the top of the sidebar. */\n brand?: ReactNode\n /**\n * Which element the content well renders as.\n *\n * `main` is right for the shell of an application, and is the default. A\n * document may contain exactly one `main` landmark, so an AppShell rendered\n * INSIDE another page — a preview on a documentation site, a screenshot\n * harness — must pass `div`, or the page has two and assistive tech can no\n * longer answer \"where is the content\".\n */\n contentAs?: 'main' | 'div'\n children: ReactNode\n}\n\n/**\n * Two columns on a desktop, one column and a drawer on a phone.\n *\n * The drawer closes on Escape as well as on the scrim, because a drawer that\n * only closes by tapping outside it strands a keyboard user inside a menu they\n * cannot leave. The scrim is a `<button>` for the same reason — a `<div>` with\n * an `onClick` is not reachable by keyboard and not announced as anything.\n *\n * @example\n * <AppShell brand={<Wordmark />} sidebar={<NavItem href=\"/\">Home</NavItem>}>\n * <Card>…</Card>\n * </AppShell>\n */\nexport function AppShell({\n sidebar,\n topbar,\n brand,\n contentAs: Content = 'main',\n children,\n className,\n ...rest\n}: AppShellProps) {\n const [open, setOpen] = useState(false)\n const sidebarId = useId()\n\n useEffect(() => {\n if (!open) return\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false)\n }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [open])\n\n return (\n <div\n className={cn('min-h-svh bg-(--paper) md:grid md:grid-cols-[15rem_1fr]', className)}\n {...rest}\n >\n {open && (\n <button\n type=\"button\"\n aria-label=\"Close navigation\"\n onClick={() => setOpen(false)}\n className=\"fixed inset-0 z-(--z-scrim) bg-(--scrim) md:hidden\"\n />\n )}\n\n <aside\n id={sidebarId}\n aria-label=\"Sidebar\"\n className={cn(\n 'fixed inset-y-0 start-0 z-(--z-modal) flex w-60 flex-col border-e border-(--rule) bg-(--paper) transition-transform duration-(--duration-slow) ease-(--ease-out-expo)',\n // The drawer slides in from the edge reading STARTS at, so in an\n // right-to-left document it comes from the right.\n open ? 'translate-x-0' : '-translate-x-full rtl:translate-x-full',\n 'md:static md:z-auto md:translate-x-0',\n )}\n >\n {brand && (\n <div className=\"flex h-14 items-center border-b border-(--rule) px-5\">{brand}</div>\n )}\n <nav\n aria-label=\"Primary\"\n className=\"flex flex-1 flex-col gap-1 overflow-y-auto p-3 scroll-slim\"\n >\n {sidebar}\n </nav>\n </aside>\n\n <div className=\"flex min-w-0 flex-col\">\n <header className=\"sticky top-0 z-(--z-sticky) flex h-14 items-center gap-3 border-b border-(--rule) bg-(--paper)/85 px-(--page-pad) backdrop-blur\">\n <button\n type=\"button\"\n aria-label={open ? 'Close navigation' : 'Open navigation'}\n aria-expanded={open}\n aria-controls={sidebarId}\n onClick={() => setOpen((previous) => !previous)}\n className=\"-ms-2.5 grid size-11 place-items-center rounded-(--radius) text-(--ink-2) transition-colors duration-(--duration-fast) hover:text-(--ink) md:hidden\"\n >\n {open ? <X size={20} strokeWidth={1.5} aria-hidden /> : <Menu size={20} strokeWidth={1.5} aria-hidden />}\n </button>\n {topbar}\n </header>\n\n <Content className=\"mx-auto w-full max-w-(--w-page) px-(--page-pad) py-8\">{children}</Content>\n </div>\n </div>\n )\n}\n\nexport default AppShell\n"],"mappings":";AAmEQ,cAQF,YARE;AAjER,SAAS,MAAM,SAAS;AACxB,SAAS,WAAW,OAAO,gBAAgB;AAE3C,SAAS,UAAU;AAmCZ,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkB;AAChB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,YAAY,MAAM;AAExB,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,CAAC,UAAyB;AACtC,UAAI,MAAM,QAAQ,SAAU,SAAQ,KAAK;AAAA,IAC3C;AACA,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,MAAM,SAAS,oBAAoB,WAAW,KAAK;AAAA,EAC5D,GAAG,CAAC,IAAI,CAAC;AAET,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,2DAA2D,SAAS;AAAA,MACjF,GAAG;AAAA,MAEH;AAAA,gBACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAW;AAAA,YACX,SAAS,MAAM,QAAQ,KAAK;AAAA,YAC5B,WAAU;AAAA;AAAA,QACZ;AAAA,QAGF;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,YACJ,cAAW;AAAA,YACX,WAAW;AAAA,cACT;AAAA;AAAA;AAAA,cAGA,OAAO,kBAAkB;AAAA,cACzB;AAAA,YACF;AAAA,YAEC;AAAA,uBACC,oBAAC,SAAI,WAAU,wDAAwD,iBAAM;AAAA,cAE/E;AAAA,gBAAC;AAAA;AAAA,kBACC,cAAW;AAAA,kBACX,WAAU;AAAA,kBAET;AAAA;AAAA,cACH;AAAA;AAAA;AAAA,QACF;AAAA,QAEA,qBAAC,SAAI,WAAU,yBACb;AAAA,+BAAC,YAAO,WAAU,mIAChB;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,cAAY,OAAO,qBAAqB;AAAA,gBACxC,iBAAe;AAAA,gBACf,iBAAe;AAAA,gBACf,SAAS,MAAM,QAAQ,CAAC,aAAa,CAAC,QAAQ;AAAA,gBAC9C,WAAU;AAAA,gBAET,iBAAO,oBAAC,KAAE,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,IAAK,oBAAC,QAAK,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC;AAAA;AAAA,YACxG;AAAA,YACC;AAAA,aACH;AAAA,UAEA,oBAAC,WAAQ,WAAU,wDAAwD,UAAS;AAAA,WACtF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,mBAAQ;","names":[]}
@@ -0,0 +1,29 @@
1
+ import * as react from 'react';
2
+ import { ComponentProps } from 'react';
3
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
4
+
5
+ interface AvatarProps extends Omit<ComponentProps<typeof AvatarPrimitive.Root>, 'children'> {
6
+ src?: string;
7
+ /**
8
+ * Describes the person, not the picture. Empty string is correct and
9
+ * deliberate when the name is already printed beside the avatar — repeating
10
+ * it makes a screen reader say it twice.
11
+ */
12
+ alt: string;
13
+ /** Shown while the image loads and if it never does. Usually initials. */
14
+ fallback: string;
15
+ size?: 'sm' | 'md' | 'lg';
16
+ }
17
+ /**
18
+ * A person, as a circle.
19
+ *
20
+ * Wraps Radix so the fallback appears only after the image has actually failed
21
+ * or is still loading — a hand-rolled `onError` swap flashes the initials on
22
+ * every render before the cache answers.
23
+ *
24
+ * @example
25
+ * <Avatar src={user.photo} alt={user.name} fallback="HC" />
26
+ */
27
+ declare function Avatar({ src, alt, fallback, size, className, ...rest }: AvatarProps): react.JSX.Element;
28
+
29
+ export { Avatar, type AvatarProps, Avatar as default };
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
4
+ import { cn } from "../../lib/cn.js";
5
+ const SIZE = {
6
+ sm: "size-7 text-[10px]",
7
+ md: "size-9 text-[11px]",
8
+ lg: "size-12 text-[13px]"
9
+ };
10
+ function Avatar({ src, alt, fallback, size = "md", className, ...rest }) {
11
+ return /* @__PURE__ */ jsxs(
12
+ AvatarPrimitive.Root,
13
+ {
14
+ className: cn(
15
+ "relative inline-flex shrink-0 overflow-hidden rounded-full border border-(--rule) bg-(--stone)",
16
+ SIZE[size],
17
+ className
18
+ ),
19
+ ...rest,
20
+ children: [
21
+ src && /* @__PURE__ */ jsx(AvatarPrimitive.Image, { src, alt, className: "size-full object-cover" }),
22
+ /* @__PURE__ */ jsx(
23
+ AvatarPrimitive.Fallback,
24
+ {
25
+ "aria-hidden": "true",
26
+ className: "grid size-full place-items-center font-mono uppercase tracking-wider text-(--ink-3-aa)",
27
+ children: fallback
28
+ }
29
+ )
30
+ ]
31
+ }
32
+ );
33
+ }
34
+ var Avatar_default = Avatar;
35
+ export {
36
+ Avatar,
37
+ Avatar_default as default
38
+ };
39
+ //# sourceMappingURL=Avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Avatar/Avatar.tsx"],"sourcesContent":["'use client'\n\nimport * as AvatarPrimitive from '@radix-ui/react-avatar'\nimport type { ComponentProps } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface AvatarProps extends Omit<ComponentProps<typeof AvatarPrimitive.Root>, 'children'> {\n src?: string\n /**\n * Describes the person, not the picture. Empty string is correct and\n * deliberate when the name is already printed beside the avatar — repeating\n * it makes a screen reader say it twice.\n */\n alt: string\n /** Shown while the image loads and if it never does. Usually initials. */\n fallback: string\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst SIZE = {\n sm: 'size-7 text-[10px]',\n md: 'size-9 text-[11px]',\n lg: 'size-12 text-[13px]',\n} as const\n\n/**\n * A person, as a circle.\n *\n * Wraps Radix so the fallback appears only after the image has actually failed\n * or is still loading — a hand-rolled `onError` swap flashes the initials on\n * every render before the cache answers.\n *\n * @example\n * <Avatar src={user.photo} alt={user.name} fallback=\"HC\" />\n */\nexport function Avatar({ src, alt, fallback, size = 'md', className, ...rest }: AvatarProps) {\n return (\n <AvatarPrimitive.Root\n className={cn(\n 'relative inline-flex shrink-0 overflow-hidden rounded-full border border-(--rule) bg-(--stone)',\n SIZE[size],\n className,\n )}\n {...rest}\n >\n {src && (\n <AvatarPrimitive.Image src={src} alt={alt} className=\"size-full object-cover\" />\n )}\n <AvatarPrimitive.Fallback\n // Nothing to announce: either the image's alt carries the identity, or\n // the name is printed beside it. Initials read aloud are noise.\n aria-hidden=\"true\"\n className=\"grid size-full place-items-center font-mono uppercase tracking-wider text-(--ink-3-aa)\"\n >\n {fallback}\n </AvatarPrimitive.Fallback>\n </AvatarPrimitive.Root>\n )\n}\n\nexport default Avatar\n"],"mappings":";AAqCI,SASI,KATJ;AAnCJ,YAAY,qBAAqB;AAEjC,SAAS,UAAU;AAenB,MAAM,OAAO;AAAA,EACX,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAYO,SAAS,OAAO,EAAE,KAAK,KAAK,UAAU,OAAO,MAAM,WAAW,GAAG,KAAK,GAAgB;AAC3F,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,KAAK,IAAI;AAAA,QACT;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,eACC,oBAAC,gBAAgB,OAAhB,EAAsB,KAAU,KAAU,WAAU,0BAAyB;AAAA,QAEhF;AAAA,UAAC,gBAAgB;AAAA,UAAhB;AAAA,YAGC,eAAY;AAAA,YACZ,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAO,iBAAQ;","names":[]}
@@ -0,0 +1,30 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ type BadgeTone = 'neutral' | 'success' | 'warning' | 'danger' | 'outline';
5
+ interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
6
+ children: ReactNode;
7
+ /**
8
+ * `neutral` is the default and the right answer nearly always. The three
9
+ * status tones are the system's only chroma and are bound to STATE — a badge
10
+ * that is red because the design wanted a red badge is the thing this scale
11
+ * exists to prevent.
12
+ */
13
+ tone?: BadgeTone;
14
+ }
15
+ /**
16
+ * A count, a state, a small inline marker.
17
+ *
18
+ * Mono and small, so it reads as metadata rather than as content. A badge is
19
+ * not interactive — if it can be clicked or dismissed it is a `Tag` or a
20
+ * button, and giving this one an `onClick` produces a control a keyboard cannot
21
+ * reach.
22
+ *
23
+ * @example
24
+ * <Badge>12</Badge>
25
+ * @example
26
+ * <Badge tone="success">Deployed</Badge>
27
+ */
28
+ declare function Badge({ children, tone, className, ...rest }: BadgeProps): react.JSX.Element;
29
+
30
+ export { Badge, type BadgeProps, type BadgeTone, Badge as default };
@@ -0,0 +1,29 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/cn.js";
3
+ const TONE = {
4
+ neutral: "bg-(--stone) text-(--ink-2) border-transparent",
5
+ success: "bg-(--ok-soft) text-(--ok) border-transparent",
6
+ warning: "bg-(--warn-soft) text-(--warn) border-transparent",
7
+ danger: "bg-(--danger-soft) text-(--danger) border-transparent",
8
+ outline: "bg-transparent text-(--ink-2) border-(--rule-2)"
9
+ };
10
+ function Badge({ children, tone = "neutral", className, ...rest }) {
11
+ return /* @__PURE__ */ jsx(
12
+ "span",
13
+ {
14
+ className: cn(
15
+ "inline-flex items-center gap-1.5 rounded-(--radius-sm) border px-2.5 py-1 font-mono text-xs tracking-wide",
16
+ TONE[tone],
17
+ className
18
+ ),
19
+ ...rest,
20
+ children
21
+ }
22
+ );
23
+ }
24
+ var Badge_default = Badge;
25
+ export {
26
+ Badge,
27
+ Badge_default as default
28
+ };
29
+ //# sourceMappingURL=Badge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Badge/Badge.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport type BadgeTone = 'neutral' | 'success' | 'warning' | 'danger' | 'outline'\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n children: ReactNode\n /**\n * `neutral` is the default and the right answer nearly always. The three\n * status tones are the system's only chroma and are bound to STATE — a badge\n * that is red because the design wanted a red badge is the thing this scale\n * exists to prevent.\n */\n tone?: BadgeTone\n}\n\nconst TONE: Record<BadgeTone, string> = {\n neutral: 'bg-(--stone) text-(--ink-2) border-transparent',\n success: 'bg-(--ok-soft) text-(--ok) border-transparent',\n warning: 'bg-(--warn-soft) text-(--warn) border-transparent',\n danger: 'bg-(--danger-soft) text-(--danger) border-transparent',\n outline: 'bg-transparent text-(--ink-2) border-(--rule-2)',\n}\n\n/**\n * A count, a state, a small inline marker.\n *\n * Mono and small, so it reads as metadata rather than as content. A badge is\n * not interactive — if it can be clicked or dismissed it is a `Tag` or a\n * button, and giving this one an `onClick` produces a control a keyboard cannot\n * reach.\n *\n * @example\n * <Badge>12</Badge>\n * @example\n * <Badge tone=\"success\">Deployed</Badge>\n */\nexport function Badge({ children, tone = 'neutral', className, ...rest }: BadgeProps) {\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-(--radius-sm) border px-2.5 py-1 font-mono text-xs tracking-wide',\n TONE[tone],\n className,\n )}\n {...rest}\n >\n {children}\n </span>\n )\n}\n\nexport default Badge\n"],"mappings":"AAuCI;AAtCJ,SAAS,UAAU;AAenB,MAAM,OAAkC;AAAA,EACtC,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AACX;AAeO,SAAS,MAAM,EAAE,UAAU,OAAO,WAAW,WAAW,GAAG,KAAK,GAAe;AACpF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,KAAK,IAAI;AAAA,QACT;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,gBAAQ;","names":[]}
@@ -0,0 +1,31 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ interface Crumb {
5
+ label: ReactNode;
6
+ /** Omit on the last crumb — the page you are already on is not a link. */
7
+ href?: string;
8
+ }
9
+ interface BreadcrumbProps extends HTMLAttributes<HTMLElement> {
10
+ items: Crumb[];
11
+ /** Names this trail when a page has more than one. */
12
+ label?: string;
13
+ /** Rendered between crumbs. A slash by default; it is decorative either way. */
14
+ separator?: ReactNode;
15
+ }
16
+ /**
17
+ * Where you are, as a path.
18
+ *
19
+ * The last crumb is plain text with `aria-current="page"` rather than a link to
20
+ * itself — a self-link is the most common breadcrumb bug, and it makes a screen
21
+ * reader offer a navigation that goes nowhere.
22
+ *
23
+ * Separators live in `<li aria-hidden>` so the trail is read as its items and
24
+ * not as "home slash work slash".
25
+ *
26
+ * @example
27
+ * <Breadcrumb items={[{ label: 'Components', href: '/components' }, { label: 'Button' }]} />
28
+ */
29
+ declare function Breadcrumb({ items, label, separator, className, ...rest }: BreadcrumbProps): react.JSX.Element;
30
+
31
+ export { Breadcrumb, type BreadcrumbProps, type Crumb, Breadcrumb as default };
@@ -0,0 +1,31 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment } from "react";
3
+ import { cn } from "../../lib/cn.js";
4
+ function Breadcrumb({
5
+ items,
6
+ label = "Breadcrumb",
7
+ separator = "/",
8
+ className,
9
+ ...rest
10
+ }) {
11
+ return /* @__PURE__ */ jsx("nav", { "aria-label": label, className: cn("mono-meta text-(--ink-3-aa)", className), ...rest, children: /* @__PURE__ */ jsx("ol", { className: "m-0 flex list-none flex-wrap items-center gap-2 p-0", children: items.map((item, index) => {
12
+ const last = index === items.length - 1;
13
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
14
+ /* @__PURE__ */ jsx("li", { className: "min-w-0", children: item.href && !last ? /* @__PURE__ */ jsx(
15
+ "a",
16
+ {
17
+ href: item.href,
18
+ className: "text-(--ink-3-aa) underline decoration-transparent underline-offset-4 transition-colors duration-(--duration-fast) hover:text-(--ink) hover:decoration-(--rule-2)",
19
+ children: item.label
20
+ }
21
+ ) : /* @__PURE__ */ jsx("span", { "aria-current": last ? "page" : void 0, className: last ? "text-(--ink)" : void 0, children: item.label }) }),
22
+ !last && /* @__PURE__ */ jsx("li", { "aria-hidden": "true", className: "select-none text-(--rule-2)", children: separator })
23
+ ] }, index);
24
+ }) }) });
25
+ }
26
+ var Breadcrumb_default = Breadcrumb;
27
+ export {
28
+ Breadcrumb,
29
+ Breadcrumb_default as default
30
+ };
31
+ //# sourceMappingURL=Breadcrumb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Breadcrumb/Breadcrumb.tsx"],"sourcesContent":["import { Fragment } from 'react'\nimport type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface Crumb {\n label: ReactNode\n /** Omit on the last crumb — the page you are already on is not a link. */\n href?: string\n}\n\nexport interface BreadcrumbProps extends HTMLAttributes<HTMLElement> {\n items: Crumb[]\n /** Names this trail when a page has more than one. */\n label?: string\n /** Rendered between crumbs. A slash by default; it is decorative either way. */\n separator?: ReactNode\n}\n\n/**\n * Where you are, as a path.\n *\n * The last crumb is plain text with `aria-current=\"page\"` rather than a link to\n * itself — a self-link is the most common breadcrumb bug, and it makes a screen\n * reader offer a navigation that goes nowhere.\n *\n * Separators live in `<li aria-hidden>` so the trail is read as its items and\n * not as \"home slash work slash\".\n *\n * @example\n * <Breadcrumb items={[{ label: 'Components', href: '/components' }, { label: 'Button' }]} />\n */\nexport function Breadcrumb({\n items,\n label = 'Breadcrumb',\n separator = '/',\n className,\n ...rest\n}: BreadcrumbProps) {\n return (\n <nav aria-label={label} className={cn('mono-meta text-(--ink-3-aa)', className)} {...rest}>\n <ol className=\"m-0 flex list-none flex-wrap items-center gap-2 p-0\">\n {items.map((item, index) => {\n const last = index === items.length - 1\n return (\n <Fragment key={index}>\n <li className=\"min-w-0\">\n {item.href && !last ? (\n <a\n href={item.href}\n className=\"text-(--ink-3-aa) underline decoration-transparent underline-offset-4 transition-colors duration-(--duration-fast) hover:text-(--ink) hover:decoration-(--rule-2)\"\n >\n {item.label}\n </a>\n ) : (\n <span aria-current={last ? 'page' : undefined} className={last ? 'text-(--ink)' : undefined}>\n {item.label}\n </span>\n )}\n </li>\n {!last && (\n <li aria-hidden=\"true\" className=\"select-none text-(--rule-2)\">\n {separator}\n </li>\n )}\n </Fragment>\n )\n })}\n </ol>\n </nav>\n )\n}\n\nexport default Breadcrumb\n"],"mappings":"AA4CY,SAGM,KAHN;AA5CZ,SAAS,gBAAgB;AAEzB,SAAS,UAAU;AA6BZ,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ;AAAA,EACA,GAAG;AACL,GAAoB;AAClB,SACE,oBAAC,SAAI,cAAY,OAAO,WAAW,GAAG,+BAA+B,SAAS,GAAI,GAAG,MACnF,8BAAC,QAAG,WAAU,uDACX,gBAAM,IAAI,CAAC,MAAM,UAAU;AAC1B,UAAM,OAAO,UAAU,MAAM,SAAS;AACtC,WACE,qBAAC,YACC;AAAA,0BAAC,QAAG,WAAU,WACX,eAAK,QAAQ,CAAC,OACb;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,KAAK;AAAA,UACX,WAAU;AAAA,UAET,eAAK;AAAA;AAAA,MACR,IAEA,oBAAC,UAAK,gBAAc,OAAO,SAAS,QAAW,WAAW,OAAO,iBAAiB,QAC/E,eAAK,OACR,GAEJ;AAAA,MACC,CAAC,QACA,oBAAC,QAAG,eAAY,QAAO,WAAU,+BAC9B,qBACH;AAAA,SAlBW,KAoBf;AAAA,EAEJ,CAAC,GACH,GACF;AAEJ;AAEA,IAAO,qBAAQ;","names":[]}
@@ -0,0 +1,70 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
3
+
4
+ type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
5
+ type ButtonSize = 'sm' | 'md' | 'lg';
6
+ interface CommonProps {
7
+ children?: ReactNode;
8
+ /**
9
+ * Which action this is. `primary` is the one thing the screen wants you to
10
+ * do, so there is at most one per view; `danger` is reserved for destructive
11
+ * actions and is the only place chroma is allowed on a control.
12
+ */
13
+ variant?: ButtonVariant;
14
+ /** 36 / 44 / 48px tall. `md` meets the pointer-target floor on its own. */
15
+ size?: ButtonSize;
16
+ /** Optional mono keycap glyph rendered after the label (e.g. "P"). */
17
+ keycap?: string;
18
+ /**
19
+ * Swaps the leading content for a spinner and blocks interaction. The label
20
+ * stays put — a button that empties out while it works loses its width, and
21
+ * the page reflows under the pointer that just clicked it.
22
+ */
23
+ loading?: boolean;
24
+ /**
25
+ * Square control with no label. REQUIRES `aria-label`: an icon-only button
26
+ * with no accessible name is invisible to a screen reader, and this is the
27
+ * single most common way a design system ships an unusable control.
28
+ */
29
+ iconOnly?: boolean;
30
+ /**
31
+ * Render the child element instead of a `<button>`, keeping these styles.
32
+ * Use it to hand the styling to a router's `Link` — `asChild` is what keeps
33
+ * this package free of any one router.
34
+ *
35
+ * The decoration slots (`keycap`, `loading`) are not injected into a slotted
36
+ * child; compose them inside it yourself.
37
+ *
38
+ * @example
39
+ * <Button asChild><Link href="/work">Work</Link></Button>
40
+ */
41
+ asChild?: boolean;
42
+ className?: string;
43
+ }
44
+ type ButtonAsLink = CommonProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'children'> & {
45
+ href: string;
46
+ };
47
+ type ButtonAsButton = CommonProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children'> & {
48
+ href?: undefined;
49
+ };
50
+ type ButtonProps = ButtonAsLink | ButtonAsButton;
51
+ /**
52
+ * The system's action.
53
+ *
54
+ * Renders a `<button>`, or an `<a>` when given `href`, or whatever you hand it
55
+ * via `asChild`. No router is imported, so the package stays framework-agnostic
56
+ * and a Next or React Router app wires its own `Link` at the call site.
57
+ *
58
+ * Server-component friendly: there is no client boundary here, so it renders in
59
+ * a static page as well as an interactive one.
60
+ *
61
+ * @example
62
+ * <Button variant="secondary" keycap="P">View projects</Button>
63
+ * @example
64
+ * <Button loading disabled>Saving…</Button>
65
+ * @example
66
+ * <Button iconOnly aria-label="Close"><X size={16} /></Button>
67
+ */
68
+ declare function Button(props: ButtonProps): react.JSX.Element;
69
+
70
+ export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, Button as default };