@krizaka/ui 2.0.0-beta.2 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +30 -0
  2. package/dist/alert.d.ts +2 -0
  3. package/dist/alert.js.map +1 -1
  4. package/dist/avatar.d.ts +5 -0
  5. package/dist/avatar.js.map +1 -1
  6. package/dist/badge.d.ts +12 -0
  7. package/dist/badge.js.map +1 -1
  8. package/dist/{button-G5qY4qSY.d.ts → button-8La7l0V4.d.ts} +15 -0
  9. package/dist/button.d.ts +19 -0
  10. package/dist/button.js.map +1 -1
  11. package/dist/card.d.ts +24 -1
  12. package/dist/card.js.map +1 -1
  13. package/dist/chip.d.ts +23 -0
  14. package/dist/chip.js.map +1 -1
  15. package/dist/{chunk-5FRYKFTO.js → chunk-3X5MVH54.js} +2 -2
  16. package/dist/chunk-3X5MVH54.js.map +1 -0
  17. package/dist/{chunk-QRG5RYEI.js → chunk-ZUD4U22H.js} +1 -1
  18. package/dist/chunk-ZUD4U22H.js.map +1 -0
  19. package/dist/command.d.ts +4 -1
  20. package/dist/command.js +2 -2
  21. package/dist/command.js.map +1 -1
  22. package/dist/confirm-button.d.ts +1 -1
  23. package/dist/confirm-button.js +1 -1
  24. package/dist/countdown.d.ts +3 -0
  25. package/dist/countdown.js.map +1 -1
  26. package/dist/{dialog-DGBY2grk.d.ts → dialog-GQ4Nvuyf.d.ts} +10 -0
  27. package/dist/dialog.d.ts +9 -1
  28. package/dist/dialog.js +2 -2
  29. package/dist/dialog.js.map +1 -1
  30. package/dist/dropdown-menu.d.ts +1 -0
  31. package/dist/dropdown-menu.js.map +1 -1
  32. package/dist/empty-state.d.ts +2 -0
  33. package/dist/empty-state.js.map +1 -1
  34. package/dist/kbd.d.ts +7 -1
  35. package/dist/kbd.js.map +1 -1
  36. package/dist/page-header.d.ts +2 -0
  37. package/dist/page-header.js.map +1 -1
  38. package/dist/progress.d.ts +5 -0
  39. package/dist/progress.js.map +1 -1
  40. package/dist/skeleton.d.ts +7 -1
  41. package/dist/skeleton.js.map +1 -1
  42. package/dist/slider.d.ts +2 -0
  43. package/dist/slider.js.map +1 -1
  44. package/dist/spinner.d.ts +5 -0
  45. package/dist/spinner.js.map +1 -1
  46. package/dist/stat.d.ts +2 -0
  47. package/dist/stat.js.map +1 -1
  48. package/dist/switch.d.ts +7 -3
  49. package/dist/switch.js.map +1 -1
  50. package/dist/tabs.d.ts +4 -1
  51. package/dist/tabs.js.map +1 -1
  52. package/dist/theme.d.ts +10 -2
  53. package/dist/theme.js +4 -2
  54. package/dist/theme.js.map +1 -1
  55. package/dist/tooltip.d.ts +3 -0
  56. package/dist/tooltip.js.map +1 -1
  57. package/package.json +14 -3
  58. package/registry/alert.json +59 -0
  59. package/registry/avatar.json +114 -0
  60. package/registry/badge.json +59 -0
  61. package/registry/button.json +115 -0
  62. package/registry/card.json +154 -0
  63. package/registry/checkbox.json +46 -0
  64. package/registry/chip.json +164 -0
  65. package/registry/cn.json +21 -0
  66. package/registry/command.json +162 -0
  67. package/registry/confirm-button.json +104 -0
  68. package/registry/countdown.json +84 -0
  69. package/registry/demos/alert.d.ts +5 -0
  70. package/registry/demos/alert.js +12 -0
  71. package/registry/demos/alert.tsx +15 -0
  72. package/registry/demos/avatar.d.ts +5 -0
  73. package/registry/demos/avatar.js +14 -0
  74. package/registry/demos/avatar.tsx +13 -0
  75. package/registry/demos/badge.d.ts +5 -0
  76. package/registry/demos/badge.js +11 -0
  77. package/registry/demos/badge.tsx +5 -0
  78. package/registry/demos/button.d.ts +5 -0
  79. package/registry/demos/button.js +11 -0
  80. package/registry/demos/button.tsx +5 -0
  81. package/registry/demos/card.d.ts +5 -0
  82. package/registry/demos/card.js +30 -0
  83. package/registry/demos/card.tsx +37 -0
  84. package/registry/demos/checkbox.d.ts +5 -0
  85. package/registry/demos/checkbox.js +11 -0
  86. package/registry/demos/checkbox.tsx +5 -0
  87. package/registry/demos/chip.d.ts +5 -0
  88. package/registry/demos/chip.js +15 -0
  89. package/registry/demos/chip.tsx +11 -0
  90. package/registry/demos/cn.d.ts +7 -0
  91. package/registry/demos/cn.js +17 -0
  92. package/registry/demos/cn.tsx +9 -0
  93. package/registry/demos/command.d.ts +5 -0
  94. package/registry/demos/command.js +32 -0
  95. package/registry/demos/command.tsx +28 -0
  96. package/registry/demos/confirm-button.d.ts +5 -0
  97. package/registry/demos/confirm-button.js +12 -0
  98. package/registry/demos/confirm-button.tsx +13 -0
  99. package/registry/demos/countdown.d.ts +5 -0
  100. package/registry/demos/countdown.js +13 -0
  101. package/registry/demos/countdown.tsx +10 -0
  102. package/registry/demos/dialog.d.ts +7 -0
  103. package/registry/demos/dialog.js +29 -0
  104. package/registry/demos/dialog.tsx +31 -0
  105. package/registry/demos/dropdown-menu.d.ts +7 -0
  106. package/registry/demos/dropdown-menu.js +36 -0
  107. package/registry/demos/dropdown-menu.tsx +27 -0
  108. package/registry/demos/empty-state.d.ts +5 -0
  109. package/registry/demos/empty-state.js +15 -0
  110. package/registry/demos/empty-state.tsx +12 -0
  111. package/registry/demos/field.d.ts +5 -0
  112. package/registry/demos/field.js +15 -0
  113. package/registry/demos/field.tsx +11 -0
  114. package/registry/demos/kbd.d.ts +5 -0
  115. package/registry/demos/kbd.js +11 -0
  116. package/registry/demos/kbd.tsx +5 -0
  117. package/registry/demos/page-header.d.ts +5 -0
  118. package/registry/demos/page-header.js +11 -0
  119. package/registry/demos/page-header.tsx +5 -0
  120. package/registry/demos/popover.d.ts +7 -0
  121. package/registry/demos/popover.js +25 -0
  122. package/registry/demos/popover.tsx +31 -0
  123. package/registry/demos/progress.d.ts +5 -0
  124. package/registry/demos/progress.js +11 -0
  125. package/registry/demos/progress.tsx +5 -0
  126. package/registry/demos/radio-group.d.ts +5 -0
  127. package/registry/demos/radio-group.js +16 -0
  128. package/registry/demos/radio-group.tsx +14 -0
  129. package/registry/demos/separator.d.ts +5 -0
  130. package/registry/demos/separator.js +15 -0
  131. package/registry/demos/separator.tsx +11 -0
  132. package/registry/demos/skeleton.d.ts +5 -0
  133. package/registry/demos/skeleton.js +20 -0
  134. package/registry/demos/skeleton.tsx +16 -0
  135. package/registry/demos/slider.d.ts +5 -0
  136. package/registry/demos/slider.js +11 -0
  137. package/registry/demos/slider.tsx +5 -0
  138. package/registry/demos/slot.d.ts +5 -0
  139. package/registry/demos/slot.js +14 -0
  140. package/registry/demos/slot.tsx +13 -0
  141. package/registry/demos/spinner.d.ts +5 -0
  142. package/registry/demos/spinner.js +11 -0
  143. package/registry/demos/spinner.tsx +5 -0
  144. package/registry/demos/stat.d.ts +5 -0
  145. package/registry/demos/stat.js +11 -0
  146. package/registry/demos/stat.tsx +5 -0
  147. package/registry/demos/switch.d.ts +5 -0
  148. package/registry/demos/switch.js +11 -0
  149. package/registry/demos/switch.tsx +5 -0
  150. package/registry/demos/tabs.d.ts +5 -0
  151. package/registry/demos/tabs.js +22 -0
  152. package/registry/demos/tabs.tsx +28 -0
  153. package/registry/demos/theme.d.ts +5 -0
  154. package/registry/demos/theme.js +11 -0
  155. package/registry/demos/theme.tsx +9 -0
  156. package/registry/demos/toast.d.ts +8 -0
  157. package/registry/demos/toast.js +29 -0
  158. package/registry/demos/toast.tsx +31 -0
  159. package/registry/demos/tooltip.d.ts +7 -0
  160. package/registry/demos/tooltip.js +15 -0
  161. package/registry/demos/tooltip.tsx +15 -0
  162. package/registry/dialog.json +218 -0
  163. package/registry/dropdown-menu.json +63 -0
  164. package/registry/empty-state.json +59 -0
  165. package/registry/field.json +66 -0
  166. package/registry/index.json +320 -0
  167. package/registry/kbd.json +38 -0
  168. package/registry/page-header.json +66 -0
  169. package/registry/popover.json +44 -0
  170. package/registry/progress.json +80 -0
  171. package/registry/radio-group.json +64 -0
  172. package/registry/separator.json +25 -0
  173. package/registry/skeleton.json +38 -0
  174. package/registry/slider.json +95 -0
  175. package/registry/slot.json +31 -0
  176. package/registry/spinner.json +45 -0
  177. package/registry/stat.json +66 -0
  178. package/registry/switch.json +53 -0
  179. package/registry/tabs.json +44 -0
  180. package/registry/theme.json +78 -0
  181. package/registry/toast.json +54 -0
  182. package/registry/tooltip.json +91 -0
  183. package/dist/chunk-5FRYKFTO.js.map +0 -1
  184. package/dist/chunk-QRG5RYEI.js.map +0 -1
package/README.md CHANGED
@@ -152,6 +152,7 @@ Colours are roles of the preset (`bg-surface-2`, `text-fg-secondary`, `border-bo
152
152
  | `@krizaka/ui` | the marks, `MotionObserver`, `RotatingWord`, `cx` (unchanged) | client |
153
153
  | `@krizaka/ui/native` | the marks for React Native (unchanged) | native |
154
154
  | `@krizaka/ui/motion.css`, `@krizaka/ui/tailwind.css` | the motion signature; the `@source` of the primitives' classes | CSS |
155
+ | `@krizaka/ui/registry/<name>`, `@krizaka/ui/registry/demos/<name>` | the registry (JSON) and the demos — see [Registry](#registry) | data · client |
155
156
 
156
157
  The theme is one mechanism for every product: dark by default, `html.light` for light, `html.theme-<name>` for a named
157
158
  theme, persisted as `kz-theme` (and `kz-theme-name`).
@@ -166,6 +167,35 @@ theme, persisted as `kz-theme` (and `kz-theme-name`).
166
167
  <ThemeToggle label={(mode) => t(`theme.${mode}`)} />
167
168
  ```
168
169
 
170
+ ## Registry
171
+
172
+ Every primitive is also published as data, for documentation sites (krizaka.com's `/docs/ui`: live preview, copyable
173
+ code, props table) and, later, a `npx @krizaka/cli add <name>` that copies a primitive into a product which forks it
174
+ knowingly. Built by `scripts/build-registry.mjs` after tsup, from `src/<name>/` (all primitives; not the marks, the
175
+ motion or `native`):
176
+
177
+ | Path | What |
178
+ | :-- | :-- |
179
+ | `@krizaka/ui/registry/index` | `{ name, version, items: [{ name, type, description, dependencies, registryDependencies }] }` |
180
+ | `@krizaka/ui/registry/<name>` | `{ name, type: "primitive", description, files: [{ path, content }], dependencies, registryDependencies, demo: { path, content }, props }` |
181
+ | `@krizaka/ui/registry/demos/<name>` | the demo, compiled (ESM, `"use client"`, `default` export) — its source ships beside it as `registry/demos/<name>.tsx` |
182
+
183
+ - `files` are the sources (paths from `src/`); `dependencies` are npm `name@range` (React aside); `registryDependencies`
184
+ are the other primitives it imports (`cn`, `button`…).
185
+ - `props` is one entry per exported component — `{ component, description, props: [{ name, type, default, description,
186
+ required }] }` — read by `react-docgen-typescript` from the JSDoc of the props types: the component's own props,
187
+ its variants included; inherited DOM and Radix props are left out. A test fails on a prop without a description.
188
+ - A demo is ≤ 40 lines, imports the primitives as a product does (`@krizaka/ui/<name>`) and is the default story of
189
+ the primitive: Storybook and the docs show the same code. A demo that opens over the page takes `defaultOpen` (the
190
+ story opens it for the screenshot; the docs leave it closed).
191
+
192
+ ```ts
193
+ import card from "@krizaka/ui/registry/card" with { type: "json" };
194
+ import CardDemo from "@krizaka/ui/registry/demos/card";
195
+ ```
196
+
197
+ A site that renders the demos adds them to Tailwind's sources: `@source "../node_modules/@krizaka/ui/registry/demos";`.
198
+
169
199
  ## React Native
170
200
 
171
201
  The marks have one geometry; `@krizaka/ui/native` draws it with `react-native-svg` for the apps
package/dist/alert.d.ts CHANGED
@@ -83,9 +83,11 @@ declare const alertVariants: tailwind_variants.TVReturnType<{
83
83
  }>>;
84
84
  type AlertTone = NonNullable<VariantProps<typeof alertVariants>["tone"]>;
85
85
  type AlertProps = Omit<React.ComponentProps<"div">, "title"> & {
86
+ /** The tone: `danger` and `warning` are announced at once (`role="alert"`), `info` and `success` politely. */
86
87
  tone?: AlertTone;
87
88
  /** A decorative icon (hidden from assistive technology). */
88
89
  icon?: React.ReactNode;
90
+ /** The headline, in bold above the text. */
89
91
  title?: React.ReactNode;
90
92
  /** What to do: a Button, a link. */
91
93
  action?: React.ReactNode;
package/dist/alert.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/alert/alert.tsx"],"sourcesContent":["// Server-safe. A message in the flow of the page (not a toast): a tone, an icon, a title, a text, an action.\n// danger and warning are announced at once (role=\"alert\"); info and success politely (role=\"status\").\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\n// Soft tones (a tint, a tinted border, a coloured icon): the text stays a text role — the invariant status tokens are\n// too light for small text on a light surface (WCAG AA).\nexport const alertVariants = tv({\n slots: {\n root: \"relative flex w-full items-start gap-3 rounded-xl border p-4 text-sm text-fg\",\n icon: \"mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n content: \"flex min-w-0 flex-1 flex-col gap-1\",\n title: \"font-semibold text-fg\",\n description: \"text-fg-secondary\",\n action: \"flex shrink-0 items-center gap-2 self-center\",\n },\n variants: {\n tone: {\n info: { root: \"border-info/40 bg-info/10\", icon: \"text-info\" },\n success: { root: \"border-success/40 bg-success/10\", icon: \"text-success\" },\n warning: { root: \"border-warning/50 bg-warning/10\", icon: \"text-warning\" },\n danger: { root: \"border-danger/50 bg-danger/10\", icon: \"text-danger\" },\n },\n },\n defaultVariants: { tone: \"info\" },\n});\n\nexport type AlertTone = NonNullable<VariantProps<typeof alertVariants>[\"tone\"]>;\n\nexport type AlertProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n tone?: AlertTone;\n /** A decorative icon (hidden from assistive technology). */\n icon?: React.ReactNode;\n title?: React.ReactNode;\n /** What to do: a Button, a link. */\n action?: React.ReactNode;\n};\n\nexport function Alert({ tone = \"info\", icon, title, action, className, children, ...props }: AlertProps) {\n const s = alertVariants({ tone });\n return (\n <div role={tone === \"danger\" || tone === \"warning\" ? \"alert\" : \"status\"} data-tone={tone} className={s.root({ className })} {...props}>\n {icon && (\n <span aria-hidden className={s.icon()}>\n {icon}\n </span>\n )}\n <div className={s.content()}>\n {title && <p className={s.title()}>{title}</p>}\n {children && <div className={s.description()}>{children}</div>}\n </div>\n {action && <div className={s.action()}>{action}</div>}\n </div>\n );\n}\n"],"mappings":";AAGA,SAAS,UAA6B;AAwC9B,cAIF,YAJE;AApCD,IAAM,gBAAgB,GAAG;AAAA,EAC9B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,EACV;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,MAAM,EAAE,MAAM,6BAA6B,MAAM,YAAY;AAAA,MAC7D,SAAS,EAAE,MAAM,mCAAmC,MAAM,eAAe;AAAA,MACzE,SAAS,EAAE,MAAM,mCAAmC,MAAM,eAAe;AAAA,MACzE,QAAQ,EAAE,MAAM,iCAAiC,MAAM,cAAc;AAAA,IACvE;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,OAAO;AAClC,CAAC;AAaM,SAAS,MAAM,EAAE,OAAO,QAAQ,MAAM,OAAO,QAAQ,WAAW,UAAU,GAAG,MAAM,GAAe;AACvG,QAAM,IAAI,cAAc,EAAE,KAAK,CAAC;AAChC,SACE,qBAAC,SAAI,MAAM,SAAS,YAAY,SAAS,YAAY,UAAU,UAAU,aAAW,MAAM,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC7H;AAAA,YACC,oBAAC,UAAK,eAAW,MAAC,WAAW,EAAE,KAAK,GACjC,gBACH;AAAA,IAEF,qBAAC,SAAI,WAAW,EAAE,QAAQ,GACvB;AAAA,eAAS,oBAAC,OAAE,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,MACzC,YAAY,oBAAC,SAAI,WAAW,EAAE,YAAY,GAAI,UAAS;AAAA,OAC1D;AAAA,IACC,UAAU,oBAAC,SAAI,WAAW,EAAE,OAAO,GAAI,kBAAO;AAAA,KACjD;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/alert/alert.tsx"],"sourcesContent":["// Server-safe. A message in the flow of the page (not a toast): a tone, an icon, a title, a text, an action.\n// danger and warning are announced at once (role=\"alert\"); info and success politely (role=\"status\").\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\n// Soft tones (a tint, a tinted border, a coloured icon): the text stays a text role — the invariant status tokens are\n// too light for small text on a light surface (WCAG AA).\nexport const alertVariants = tv({\n slots: {\n root: \"relative flex w-full items-start gap-3 rounded-xl border p-4 text-sm text-fg\",\n icon: \"mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n content: \"flex min-w-0 flex-1 flex-col gap-1\",\n title: \"font-semibold text-fg\",\n description: \"text-fg-secondary\",\n action: \"flex shrink-0 items-center gap-2 self-center\",\n },\n variants: {\n tone: {\n info: { root: \"border-info/40 bg-info/10\", icon: \"text-info\" },\n success: { root: \"border-success/40 bg-success/10\", icon: \"text-success\" },\n warning: { root: \"border-warning/50 bg-warning/10\", icon: \"text-warning\" },\n danger: { root: \"border-danger/50 bg-danger/10\", icon: \"text-danger\" },\n },\n },\n defaultVariants: { tone: \"info\" },\n});\n\nexport type AlertTone = NonNullable<VariantProps<typeof alertVariants>[\"tone\"]>;\n\nexport type AlertProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The tone: `danger` and `warning` are announced at once (`role=\"alert\"`), `info` and `success` politely. */\n tone?: AlertTone;\n /** A decorative icon (hidden from assistive technology). */\n icon?: React.ReactNode;\n /** The headline, in bold above the text. */\n title?: React.ReactNode;\n /** What to do: a Button, a link. */\n action?: React.ReactNode;\n};\n\nexport function Alert({ tone = \"info\", icon, title, action, className, children, ...props }: AlertProps) {\n const s = alertVariants({ tone });\n return (\n <div role={tone === \"danger\" || tone === \"warning\" ? \"alert\" : \"status\"} data-tone={tone} className={s.root({ className })} {...props}>\n {icon && (\n <span aria-hidden className={s.icon()}>\n {icon}\n </span>\n )}\n <div className={s.content()}>\n {title && <p className={s.title()}>{title}</p>}\n {children && <div className={s.description()}>{children}</div>}\n </div>\n {action && <div className={s.action()}>{action}</div>}\n </div>\n );\n}\n"],"mappings":";AAGA,SAAS,UAA6B;AA0C9B,cAIF,YAJE;AAtCD,IAAM,gBAAgB,GAAG;AAAA,EAC9B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,EACV;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,MAAM,EAAE,MAAM,6BAA6B,MAAM,YAAY;AAAA,MAC7D,SAAS,EAAE,MAAM,mCAAmC,MAAM,eAAe;AAAA,MACzE,SAAS,EAAE,MAAM,mCAAmC,MAAM,eAAe;AAAA,MACzE,QAAQ,EAAE,MAAM,iCAAiC,MAAM,cAAc;AAAA,IACvE;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,OAAO;AAClC,CAAC;AAeM,SAAS,MAAM,EAAE,OAAO,QAAQ,MAAM,OAAO,QAAQ,WAAW,UAAU,GAAG,MAAM,GAAe;AACvG,QAAM,IAAI,cAAc,EAAE,KAAK,CAAC;AAChC,SACE,qBAAC,SAAI,MAAM,SAAS,YAAY,SAAS,YAAY,UAAU,UAAU,aAAW,MAAM,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC7H;AAAA,YACC,oBAAC,UAAK,eAAW,MAAC,WAAW,EAAE,KAAK,GACjC,gBACH;AAAA,IAEF,qBAAC,SAAI,WAAW,EAAE,QAAQ,GACvB;AAAA,eAAS,oBAAC,OAAE,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,MACzC,YAAY,oBAAC,SAAI,WAAW,EAAE,YAAY,GAAI,UAAS;AAAA,OAC1D;AAAA,IACC,UAAU,oBAAC,SAAI,WAAW,EAAE,OAAO,GAAI,kBAAO;AAAA,KACjD;AAEJ;","names":[]}
package/dist/avatar.d.ts CHANGED
@@ -74,11 +74,16 @@ declare const avatar: tailwind_variants.TVReturnType<{
74
74
  }>>;
75
75
  type AvatarSize = NonNullable<VariantProps<typeof avatar>["size"]>;
76
76
  type AvatarProps = Omit<React.ComponentProps<"span">, "children"> & {
77
+ /** The image's URL; `null` or nothing shows the `fallback`. */
77
78
  src?: string | null;
78
79
  /** The image's text alternative (the person's name); empty when a visible name sits next to the avatar. */
79
80
  alt?: string;
80
81
  /** Shown while the image loads, when it fails or when there is none: initials, an icon. */
81
82
  fallback?: React.ReactNode;
83
+ /**
84
+ * xs · sm · md · lg · xl.
85
+ * @default "md"
86
+ */
82
87
  size?: AvatarSize;
83
88
  };
84
89
  declare function AvatarRoot({ src, alt, fallback, size, className, ...props }: AvatarProps): React.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/avatar/avatar.tsx"],"sourcesContent":["// Client: Radix tracks the image's loading state and shows the fallback until it has loaded (or when it fails).\nimport { Avatar as AvatarPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nconst avatar = tv({\n slots: {\n root: \"relative inline-flex shrink-0 overflow-hidden rounded-full bg-surface-3 align-middle\",\n image: \"h-full w-full object-cover\",\n fallback: \"flex h-full w-full items-center justify-center font-semibold uppercase text-fg-secondary\",\n group: \"flex items-center -space-x-2 [&>*]:ring-2 [&>*]:ring-surface-0\",\n },\n variants: {\n size: {\n xs: { root: \"h-5 w-5 text-[9px]\" },\n sm: { root: \"h-8 w-8 text-xs\" },\n md: { root: \"h-10 w-10 text-sm\" },\n lg: { root: \"h-14 w-14 text-base\" },\n xl: { root: \"h-20 w-20 text-lg\" },\n },\n },\n defaultVariants: { size: \"md\" },\n});\n\nexport type AvatarSize = NonNullable<VariantProps<typeof avatar>[\"size\"]>;\n\nexport type AvatarProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n src?: string | null;\n /** The image's text alternative (the person's name); empty when a visible name sits next to the avatar. */\n alt?: string;\n /** Shown while the image loads, when it fails or when there is none: initials, an icon. */\n fallback?: React.ReactNode;\n size?: AvatarSize;\n};\n\nexport function AvatarRoot({ src, alt = \"\", fallback, size, className, ...props }: AvatarProps) {\n const s = avatar({ size });\n return (\n <AvatarPrimitive.Root data-size={size ?? \"md\"} className={s.root({ className })} {...props}>\n {src && <AvatarPrimitive.Image src={src} alt={alt} className={s.image()} />}\n <AvatarPrimitive.Fallback delayMs={src ? 300 : 0} className={s.fallback()}>\n {fallback}\n </AvatarPrimitive.Fallback>\n </AvatarPrimitive.Root>\n );\n}\n\nexport type AvatarGroupProps = React.ComponentProps<\"div\"> & {\n /** How many avatars are shown; the rest becomes a `+n` avatar. */\n max?: number;\n /** The size of the `+n` avatar (match the avatars of the group). */\n size?: AvatarSize;\n};\n\n/** Overlapping avatars; past `max`, a `+n` avatar counts the rest. */\nexport function AvatarGroup({ max, size, className, children, ...props }: AvatarGroupProps) {\n const items = React.Children.toArray(children);\n const shown = max === undefined ? items : items.slice(0, max);\n const rest = items.length - shown.length;\n return (\n <div className={avatar().group({ className })} {...props}>\n {shown}\n {rest > 0 && <AvatarRoot size={size} fallback={`+${rest}`} />}\n </div>\n );\n}\n\n/** `Avatar` (an image with a fallback) and `Avatar.Group`. */\nexport const Avatar = Object.assign(AvatarRoot, { Group: AvatarGroup });\n"],"mappings":";;;AACA,SAAS,UAAU,uBAAuB;AAC1C,YAAY,WAAW;AACvB,SAAS,UAA6B;AAmClC,SACU,KADV;AAjCJ,IAAM,SAAS,GAAG;AAAA,EAChB,OAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,IAAI,EAAE,MAAM,qBAAqB;AAAA,MACjC,IAAI,EAAE,MAAM,kBAAkB;AAAA,MAC9B,IAAI,EAAE,MAAM,oBAAoB;AAAA,MAChC,IAAI,EAAE,MAAM,sBAAsB;AAAA,MAClC,IAAI,EAAE,MAAM,oBAAoB;AAAA,IAClC;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CAAC;AAaM,SAAS,WAAW,EAAE,KAAK,MAAM,IAAI,UAAU,MAAM,WAAW,GAAG,MAAM,GAAgB;AAC9F,QAAM,IAAI,OAAO,EAAE,KAAK,CAAC;AACzB,SACE,qBAAC,gBAAgB,MAAhB,EAAqB,aAAW,QAAQ,MAAM,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAClF;AAAA,WAAO,oBAAC,gBAAgB,OAAhB,EAAsB,KAAU,KAAU,WAAW,EAAE,MAAM,GAAG;AAAA,IACzE,oBAAC,gBAAgB,UAAhB,EAAyB,SAAS,MAAM,MAAM,GAAG,WAAW,EAAE,SAAS,GACrE,oBACH;AAAA,KACF;AAEJ;AAUO,SAAS,YAAY,EAAE,KAAK,MAAM,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC1F,QAAM,QAAc,eAAS,QAAQ,QAAQ;AAC7C,QAAM,QAAQ,QAAQ,SAAY,QAAQ,MAAM,MAAM,GAAG,GAAG;AAC5D,QAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SACE,qBAAC,SAAI,WAAW,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,GAAI,GAAG,OAChD;AAAA;AAAA,IACA,OAAO,KAAK,oBAAC,cAAW,MAAY,UAAU,IAAI,IAAI,IAAI;AAAA,KAC7D;AAEJ;AAGO,IAAM,SAAS,OAAO,OAAO,YAAY,EAAE,OAAO,YAAY,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/avatar/avatar.tsx"],"sourcesContent":["// Client: Radix tracks the image's loading state and shows the fallback until it has loaded (or when it fails).\nimport { Avatar as AvatarPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nconst avatar = tv({\n slots: {\n root: \"relative inline-flex shrink-0 overflow-hidden rounded-full bg-surface-3 align-middle\",\n image: \"h-full w-full object-cover\",\n fallback: \"flex h-full w-full items-center justify-center font-semibold uppercase text-fg-secondary\",\n group: \"flex items-center -space-x-2 [&>*]:ring-2 [&>*]:ring-surface-0\",\n },\n variants: {\n size: {\n xs: { root: \"h-5 w-5 text-[9px]\" },\n sm: { root: \"h-8 w-8 text-xs\" },\n md: { root: \"h-10 w-10 text-sm\" },\n lg: { root: \"h-14 w-14 text-base\" },\n xl: { root: \"h-20 w-20 text-lg\" },\n },\n },\n defaultVariants: { size: \"md\" },\n});\n\nexport type AvatarSize = NonNullable<VariantProps<typeof avatar>[\"size\"]>;\n\nexport type AvatarProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n /** The image's URL; `null` or nothing shows the `fallback`. */\n src?: string | null;\n /** The image's text alternative (the person's name); empty when a visible name sits next to the avatar. */\n alt?: string;\n /** Shown while the image loads, when it fails or when there is none: initials, an icon. */\n fallback?: React.ReactNode;\n /**\n * xs · sm · md · lg · xl.\n * @default \"md\"\n */\n size?: AvatarSize;\n};\n\nexport function AvatarRoot({ src, alt = \"\", fallback, size, className, ...props }: AvatarProps) {\n const s = avatar({ size });\n return (\n <AvatarPrimitive.Root data-size={size ?? \"md\"} className={s.root({ className })} {...props}>\n {src && <AvatarPrimitive.Image src={src} alt={alt} className={s.image()} />}\n <AvatarPrimitive.Fallback delayMs={src ? 300 : 0} className={s.fallback()}>\n {fallback}\n </AvatarPrimitive.Fallback>\n </AvatarPrimitive.Root>\n );\n}\n\nexport type AvatarGroupProps = React.ComponentProps<\"div\"> & {\n /** How many avatars are shown; the rest becomes a `+n` avatar. */\n max?: number;\n /** The size of the `+n` avatar (match the avatars of the group). */\n size?: AvatarSize;\n};\n\n/** Overlapping avatars; past `max`, a `+n` avatar counts the rest. */\nexport function AvatarGroup({ max, size, className, children, ...props }: AvatarGroupProps) {\n const items = React.Children.toArray(children);\n const shown = max === undefined ? items : items.slice(0, max);\n const rest = items.length - shown.length;\n return (\n <div className={avatar().group({ className })} {...props}>\n {shown}\n {rest > 0 && <AvatarRoot size={size} fallback={`+${rest}`} />}\n </div>\n );\n}\n\n/** `Avatar` (an image with a fallback) and `Avatar.Group`. */\nexport const Avatar = Object.assign(AvatarRoot, { Group: AvatarGroup });\n"],"mappings":";;;AACA,SAAS,UAAU,uBAAuB;AAC1C,YAAY,WAAW;AACvB,SAAS,UAA6B;AAwClC,SACU,KADV;AAtCJ,IAAM,SAAS,GAAG;AAAA,EAChB,OAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,IAAI,EAAE,MAAM,qBAAqB;AAAA,MACjC,IAAI,EAAE,MAAM,kBAAkB;AAAA,MAC9B,IAAI,EAAE,MAAM,oBAAoB;AAAA,MAChC,IAAI,EAAE,MAAM,sBAAsB;AAAA,MAClC,IAAI,EAAE,MAAM,oBAAoB;AAAA,IAClC;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CAAC;AAkBM,SAAS,WAAW,EAAE,KAAK,MAAM,IAAI,UAAU,MAAM,WAAW,GAAG,MAAM,GAAgB;AAC9F,QAAM,IAAI,OAAO,EAAE,KAAK,CAAC;AACzB,SACE,qBAAC,gBAAgB,MAAhB,EAAqB,aAAW,QAAQ,MAAM,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAClF;AAAA,WAAO,oBAAC,gBAAgB,OAAhB,EAAsB,KAAU,KAAU,WAAW,EAAE,MAAM,GAAG;AAAA,IACzE,oBAAC,gBAAgB,UAAhB,EAAyB,SAAS,MAAM,MAAM,GAAG,WAAW,EAAE,SAAS,GACrE,oBACH;AAAA,KACF;AAEJ;AAUO,SAAS,YAAY,EAAE,KAAK,MAAM,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC1F,QAAM,QAAc,eAAS,QAAQ,QAAQ;AAC7C,QAAM,QAAQ,QAAQ,SAAY,QAAQ,MAAM,MAAM,GAAG,GAAG;AAC5D,QAAM,OAAO,MAAM,SAAS,MAAM;AAClC,SACE,qBAAC,SAAI,WAAW,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,GAAI,GAAG,OAChD;AAAA;AAAA,IACA,OAAO,KAAK,oBAAC,cAAW,MAAY,UAAU,IAAI,IAAI,IAAI;AAAA,KAC7D;AAEJ;AAGO,IAAM,SAAS,OAAO,OAAO,YAAY,EAAE,OAAO,YAAY,CAAC;","names":[]}
package/dist/badge.d.ts CHANGED
@@ -56,6 +56,18 @@ declare const badgeVariants: tailwind_variants.TVReturnType<{
56
56
  }, undefined>>;
57
57
  type BadgeVariants = VariantProps<typeof badgeVariants>;
58
58
  type BadgeProps = React.ComponentProps<"span"> & BadgeVariants & {
59
+ /**
60
+ * neutral · accent · success · warning · danger (soft tints, the text stays a text role) · scrim (on a media).
61
+ * @default "neutral"
62
+ */
63
+ tone?: BadgeVariants["tone"];
64
+ /**
65
+ * sm · md.
66
+ * @default "sm"
67
+ */
68
+ size?: BadgeVariants["size"];
69
+ /** Makes the `dot` pulse (stopped under reduced motion). */
70
+ pulse?: BadgeVariants["pulse"];
59
71
  /** A small dot before the text, in the tone's colour (pulsing with `pulse`). */
60
72
  dot?: boolean;
61
73
  };
package/dist/badge.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/badge/badge.tsx"],"sourcesContent":["// Server-safe: no hook, no context.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\n// Status tones are soft (a tint, a coloured dot, a text role): the invariant status tokens are too light to carry\n// small text on a light surface, or to sit under white text (WCAG AA).\nexport const badgeVariants = tv({\n base: \"inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full font-semibold uppercase tracking-wider\",\n variants: {\n tone: {\n neutral: \"bg-surface-3 text-fg-secondary\",\n accent: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40 [&>[data-dot]]:bg-accent\",\n success: \"bg-success/15 text-fg ring-1 ring-inset ring-success/40 [&>[data-dot]]:bg-success\",\n warning: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40 [&>[data-dot]]:bg-warning\",\n danger: \"bg-danger/15 text-fg ring-1 ring-inset ring-danger/40 [&>[data-dot]]:bg-danger\",\n /** On a media: veil and text invariant, identical in both themes. */\n scrim: \"bg-scrim text-fg-on-media backdrop-blur-md\",\n },\n size: { sm: \"px-2 py-0.5 text-[10px]\", md: \"px-2.5 py-1 text-[11px]\" },\n pulse: { true: \"[&>[data-dot]]:motion-safe:animate-pulse\" },\n },\n defaultVariants: { tone: \"neutral\", size: \"sm\" },\n});\n\nexport type BadgeVariants = VariantProps<typeof badgeVariants>;\n\nexport type BadgeProps = React.ComponentProps<\"span\"> &\n BadgeVariants & {\n /** A small dot before the text, in the tone's colour (pulsing with `pulse`). */\n dot?: boolean;\n };\n\nexport function Badge({ tone, size, pulse, dot, className, children, ...props }: BadgeProps) {\n return (\n <span data-tone={tone ?? \"neutral\"} className={badgeVariants({ tone, size, pulse, className })} {...props}>\n {dot && <span data-dot=\"\" aria-hidden className=\"h-1.5 w-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n"],"mappings":";AAEA,SAAS,UAA6B;AAgClC,SACU,KADV;AA5BG,IAAM,gBAAgB,GAAG;AAAA,EAC9B,MAAM;AAAA,EACN,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA;AAAA,MAER,OAAO;AAAA,IACT;AAAA,IACA,MAAM,EAAE,IAAI,2BAA2B,IAAI,0BAA0B;AAAA,IACrE,OAAO,EAAE,MAAM,2CAA2C;AAAA,EAC5D;AAAA,EACA,iBAAiB,EAAE,MAAM,WAAW,MAAM,KAAK;AACjD,CAAC;AAUM,SAAS,MAAM,EAAE,MAAM,MAAM,OAAO,KAAK,WAAW,UAAU,GAAG,MAAM,GAAe;AAC3F,SACE,qBAAC,UAAK,aAAW,QAAQ,WAAW,WAAW,cAAc,EAAE,MAAM,MAAM,OAAO,UAAU,CAAC,GAAI,GAAG,OACjG;AAAA,WAAO,oBAAC,UAAK,YAAS,IAAG,eAAW,MAAC,WAAU,uCAAsC;AAAA,IACrF;AAAA,KACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/badge/badge.tsx"],"sourcesContent":["// Server-safe: no hook, no context.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\n// Status tones are soft (a tint, a coloured dot, a text role): the invariant status tokens are too light to carry\n// small text on a light surface, or to sit under white text (WCAG AA).\nexport const badgeVariants = tv({\n base: \"inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full font-semibold uppercase tracking-wider\",\n variants: {\n tone: {\n neutral: \"bg-surface-3 text-fg-secondary\",\n accent: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40 [&>[data-dot]]:bg-accent\",\n success: \"bg-success/15 text-fg ring-1 ring-inset ring-success/40 [&>[data-dot]]:bg-success\",\n warning: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40 [&>[data-dot]]:bg-warning\",\n danger: \"bg-danger/15 text-fg ring-1 ring-inset ring-danger/40 [&>[data-dot]]:bg-danger\",\n /** On a media: veil and text invariant, identical in both themes. */\n scrim: \"bg-scrim text-fg-on-media backdrop-blur-md\",\n },\n size: { sm: \"px-2 py-0.5 text-[10px]\", md: \"px-2.5 py-1 text-[11px]\" },\n pulse: { true: \"[&>[data-dot]]:motion-safe:animate-pulse\" },\n },\n defaultVariants: { tone: \"neutral\", size: \"sm\" },\n});\n\nexport type BadgeVariants = VariantProps<typeof badgeVariants>;\n\nexport type BadgeProps = React.ComponentProps<\"span\"> &\n BadgeVariants & {\n /**\n * neutral · accent · success · warning · danger (soft tints, the text stays a text role) · scrim (on a media).\n * @default \"neutral\"\n */\n tone?: BadgeVariants[\"tone\"];\n /**\n * sm · md.\n * @default \"sm\"\n */\n size?: BadgeVariants[\"size\"];\n /** Makes the `dot` pulse (stopped under reduced motion). */\n pulse?: BadgeVariants[\"pulse\"];\n /** A small dot before the text, in the tone's colour (pulsing with `pulse`). */\n dot?: boolean;\n };\n\nexport function Badge({ tone, size, pulse, dot, className, children, ...props }: BadgeProps) {\n return (\n <span data-tone={tone ?? \"neutral\"} className={badgeVariants({ tone, size, pulse, className })} {...props}>\n {dot && <span data-dot=\"\" aria-hidden className=\"h-1.5 w-1.5 rounded-full bg-current\" />}\n {children}\n </span>\n );\n}\n"],"mappings":";AAEA,SAAS,UAA6B;AA4ClC,SACU,KADV;AAxCG,IAAM,gBAAgB,GAAG;AAAA,EAC9B,MAAM;AAAA,EACN,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA;AAAA,MAER,OAAO;AAAA,IACT;AAAA,IACA,MAAM,EAAE,IAAI,2BAA2B,IAAI,0BAA0B;AAAA,IACrE,OAAO,EAAE,MAAM,2CAA2C;AAAA,EAC5D;AAAA,EACA,iBAAiB,EAAE,MAAM,WAAW,MAAM,KAAK;AACjD,CAAC;AAsBM,SAAS,MAAM,EAAE,MAAM,MAAM,OAAO,KAAK,WAAW,UAAU,GAAG,MAAM,GAAe;AAC3F,SACE,qBAAC,UAAK,aAAW,QAAQ,WAAW,WAAW,cAAc,EAAE,MAAM,MAAM,OAAO,UAAU,CAAC,GAAI,GAAG,OACjG;AAAA,WAAO,oBAAC,UAAK,YAAS,IAAG,eAAW,MAAC,WAAU,uCAAsC;AAAA,IACrF;AAAA,KACH;AAEJ;","names":[]}
@@ -59,6 +59,21 @@ declare const buttonVariants: tailwind_variants.TVReturnType<{
59
59
  }, undefined>>;
60
60
  type ButtonVariants = VariantProps<typeof buttonVariants>;
61
61
  type ButtonProps = React.ComponentProps<"button"> & ButtonVariants & {
62
+ /**
63
+ * The look: `primary` (the accent), `secondary` (a raised surface), `outline`, `ghost`, `danger`.
64
+ * @default "secondary"
65
+ */
66
+ variant?: ButtonVariants["variant"];
67
+ /**
68
+ * sm · md · lg, or `icon` (a square).
69
+ * @default "md"
70
+ */
71
+ size?: ButtonVariants["size"];
72
+ /**
73
+ * rounded · pill.
74
+ * @default "rounded"
75
+ */
76
+ shape?: ButtonVariants["shape"];
62
77
  /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */
63
78
  asChild?: boolean;
64
79
  /** Disables and signals the wait (aria-busy, data-loading) — the product adds a spinner if it wants one. */
package/dist/button.d.ts CHANGED
@@ -59,6 +59,21 @@ declare const buttonVariants: tailwind_variants.TVReturnType<{
59
59
  }, undefined>>;
60
60
  type ButtonVariants = VariantProps<typeof buttonVariants>;
61
61
  type ButtonProps = React.ComponentProps<"button"> & ButtonVariants & {
62
+ /**
63
+ * The look: `primary` (the accent), `secondary` (a raised surface), `outline`, `ghost`, `danger`.
64
+ * @default "secondary"
65
+ */
66
+ variant?: ButtonVariants["variant"];
67
+ /**
68
+ * sm · md · lg, or `icon` (a square).
69
+ * @default "md"
70
+ */
71
+ size?: ButtonVariants["size"];
72
+ /**
73
+ * rounded · pill.
74
+ * @default "rounded"
75
+ */
76
+ shape?: ButtonVariants["shape"];
62
77
  /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */
63
78
  asChild?: boolean;
64
79
  /** Disables and signals the wait (aria-busy, data-loading) — the product adds a spinner if it wants one. */
@@ -68,6 +83,10 @@ declare function Button({ asChild, loading, variant, size, shape, className, dis
68
83
  type IconButtonProps = Omit<ButtonProps, "size"> & {
69
84
  /** The accessible name (and tooltip) of the button — required, passed translated. */
70
85
  label: string;
86
+ /**
87
+ * sm · md · lg, or `icon` (a square).
88
+ * @default "icon"
89
+ */
71
90
  size?: ButtonProps["size"];
72
91
  };
73
92
  /** An icon-only button: `label` is required, it is its accessible name. */
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/button/button.tsx"],"sourcesContent":["// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const buttonVariants = tv({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98]\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The danger token is invariant and too light for small text on a light surface (3.6:1): the label stays a\n // text role, the border and the tint carry the danger.\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n shape: { rounded: \"rounded-lg\", pill: \"rounded-full\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /** Disables and signals the wait (aria-busy, data-loading) — the product adds a spinner if it wants one. */\n loading?: boolean;\n };\n\nexport function Button({ asChild, loading, variant, size, shape, className, disabled, ...props }: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n return (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({ variant, size, shape, className })}\n {...props}\n />\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. */\nexport function IconButton({ label, size = \"icon\", ...props }: IconButtonProps) {\n return <Button aria-label={label} title={label} size={size} {...props} />;\n}\n"],"mappings":";AACA,SAAS,YAAY;AAErB,SAAS,UAA6B;AAoClC;AAlCG,IAAM,iBAAiB,GAAG;AAAA,EAC/B,MACE;AAAA,EAGF,UAAU;AAAA,IACR,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA;AAAA;AAAA,MAGP,QAAQ;AAAA,IACV;AAAA,IACA,MAAM,EAAE,IAAI,oBAAoB,IAAI,qBAAqB,IAAI,qBAAqB,MAAM,YAAY;AAAA,IACpG,OAAO,EAAE,SAAS,cAAc,MAAM,eAAe;AAAA,EACvD;AAAA,EACA,iBAAiB,EAAE,SAAS,aAAa,MAAM,MAAM,OAAO,UAAU;AACxE,CAAC;AAYM,SAAS,OAAO,EAAE,SAAS,SAAS,SAAS,MAAM,OAAO,WAAW,UAAU,GAAG,MAAM,GAAgB;AAC7G,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,UAAU,SAAY;AAAA,MAC5B,aAAW,WAAW;AAAA,MACtB,gBAAc,UAAU,KAAK;AAAA,MAC7B,gBAAc,WAAW;AAAA,MACzB,UAAU,UAAU,SAAY,YAAY;AAAA,MAC5C,iBAAe,YAAY,YAAY,WAAW,OAAO;AAAA,MACzD,WAAW,eAAe,EAAE,SAAS,MAAM,OAAO,UAAU,CAAC;AAAA,MAC5D,GAAG;AAAA;AAAA,EACN;AAEJ;AASO,SAAS,WAAW,EAAE,OAAO,OAAO,QAAQ,GAAG,MAAM,GAAoB;AAC9E,SAAO,oBAAC,UAAO,cAAY,OAAO,OAAO,OAAO,MAAa,GAAG,OAAO;AACzE;","names":[]}
1
+ {"version":3,"sources":["../src/button/button.tsx"],"sourcesContent":["// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const buttonVariants = tv({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98]\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The danger token is invariant and too light for small text on a light surface (3.6:1): the label stays a\n // text role, the border and the tint carry the danger.\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n shape: { rounded: \"rounded-lg\", pill: \"rounded-full\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /**\n * The look: `primary` (the accent), `secondary` (a raised surface), `outline`, `ghost`, `danger`.\n * @default \"secondary\"\n */\n variant?: ButtonVariants[\"variant\"];\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"md\"\n */\n size?: ButtonVariants[\"size\"];\n /**\n * rounded · pill.\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /** Disables and signals the wait (aria-busy, data-loading) — the product adds a spinner if it wants one. */\n loading?: boolean;\n };\n\nexport function Button({ asChild, loading, variant, size, shape, className, disabled, ...props }: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n return (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({ variant, size, shape, className })}\n {...props}\n />\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"icon\"\n */\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. */\nexport function IconButton({ label, size = \"icon\", ...props }: IconButtonProps) {\n return <Button aria-label={label} title={label} size={size} {...props} />;\n}\n"],"mappings":";AACA,SAAS,YAAY;AAErB,SAAS,UAA6B;AAmDlC;AAjDG,IAAM,iBAAiB,GAAG;AAAA,EAC/B,MACE;AAAA,EAGF,UAAU;AAAA,IACR,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA;AAAA;AAAA,MAGP,QAAQ;AAAA,IACV;AAAA,IACA,MAAM,EAAE,IAAI,oBAAoB,IAAI,qBAAqB,IAAI,qBAAqB,MAAM,YAAY;AAAA,IACpG,OAAO,EAAE,SAAS,cAAc,MAAM,eAAe;AAAA,EACvD;AAAA,EACA,iBAAiB,EAAE,SAAS,aAAa,MAAM,MAAM,OAAO,UAAU;AACxE,CAAC;AA2BM,SAAS,OAAO,EAAE,SAAS,SAAS,SAAS,MAAM,OAAO,WAAW,UAAU,GAAG,MAAM,GAAgB;AAC7G,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,UAAU,SAAY;AAAA,MAC5B,aAAW,WAAW;AAAA,MACtB,gBAAc,UAAU,KAAK;AAAA,MAC7B,gBAAc,WAAW;AAAA,MACzB,UAAU,UAAU,SAAY,YAAY;AAAA,MAC5C,iBAAe,YAAY,YAAY,WAAW,OAAO;AAAA,MACzD,WAAW,eAAe,EAAE,SAAS,MAAM,OAAO,UAAU,CAAC;AAAA,MAC5D,GAAG;AAAA;AAAA,EACN;AAEJ;AAaO,SAAS,WAAW,EAAE,OAAO,OAAO,QAAQ,GAAG,MAAM,GAAoB;AAC9E,SAAO,oBAAC,UAAO,cAAY,OAAO,OAAO,OAAO,MAAa,GAAG,OAAO;AACzE;","names":[]}
package/dist/card.d.ts CHANGED
@@ -164,6 +164,18 @@ declare const card: tailwind_variants.TVReturnType<{
164
164
  }>>;
165
165
  type CardVariants = VariantProps<typeof card>;
166
166
  type CardRootProps = React.ComponentProps<"div"> & Pick<CardVariants, "radius" | "tone" | "interactive"> & {
167
+ /**
168
+ * md · lg · xl.
169
+ * @default "xl"
170
+ */
171
+ radius?: CardVariants["radius"];
172
+ /**
173
+ * default (the base surface) · elevated (raised, a shadow) · glass (translucent, blurred).
174
+ * @default "default"
175
+ */
176
+ tone?: CardVariants["tone"];
177
+ /** The spotlight that follows the pointer and the lift on hover: for a card that is a link. */
178
+ interactive?: CardVariants["interactive"];
167
179
  /** Renders the child (a link, an article) instead of the <div>, with props, classes and ref merged. */
168
180
  asChild?: boolean;
169
181
  /** Enters on scroll (MotionObserver): the index in the grid becomes the delay (50 ms a step, 8 steps at most). */
@@ -177,10 +189,12 @@ declare const ASPECT: {
177
189
  readonly auto: "";
178
190
  };
179
191
  type CardMediaProps = React.ComponentProps<"div"> & {
192
+ /** The ratio of the media: video (16:9) · square · portrait (3:4) · auto (the content's). */
180
193
  aspect?: keyof typeof ASPECT;
181
194
  };
182
195
  declare function CardMedia({ aspect, className, ...props }: CardMediaProps): React.JSX.Element;
183
196
  type CardImageProps = Omit<React.ComponentProps<"img">, "src"> & {
197
+ /** The image's URL; `null` or nothing shows the `fallback`. */
184
198
  src?: string | null;
185
199
  /** Shown when there is no image: an icon, an illustration (decorative). */
186
200
  fallback?: React.ReactNode;
@@ -194,18 +208,27 @@ declare const CORNER: {
194
208
  readonly "bottom-right": "bottom-2.5 right-2.5";
195
209
  };
196
210
  type CardOverlayProps = React.ComponentProps<"div"> & {
211
+ /** The corner of the media it sits in. */
197
212
  corner?: keyof typeof CORNER;
198
213
  };
199
214
  /** What sits on the media (badges, a caption). `scrim` and `fg-on-media` are invariant: nothing to do for light. */
200
215
  declare function CardOverlay({ corner, className, ...props }: CardOverlayProps): React.JSX.Element;
201
- type CardBodyProps = React.ComponentProps<"div"> & Pick<CardVariants, "padding">;
216
+ type CardBodyProps = React.ComponentProps<"div"> & {
217
+ /**
218
+ * none · sm · md · lg.
219
+ * @default "md"
220
+ */
221
+ padding?: CardVariants["padding"];
222
+ };
202
223
  declare function CardBody({ padding, className, ...props }: CardBodyProps): React.JSX.Element;
203
224
  type CardTitleProps = React.ComponentProps<"h3"> & {
225
+ /** The heading level, to fit the page's outline. */
204
226
  as?: "h2" | "h3" | "h4";
205
227
  };
206
228
  declare function CardTitle({ as: Tag, className, ...props }: CardTitleProps): React.JSX.Element;
207
229
  declare function CardDescription({ className, ...props }: React.ComponentProps<"p">): React.JSX.Element;
208
230
  type CardStatProps = React.ComponentProps<"div"> & {
231
+ /** What the figure is, in small capitals above it (the figure is the children). */
209
232
  label: React.ReactNode;
210
233
  };
211
234
  /** A figure put forward: the label in capitals, the value in tabular digits. */
package/dist/card.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/card/card.tsx"],"sourcesContent":["// Server-safe: no hook, no context. One `tv` definition with slots: each part takes its slot, and a product overrides\n// any part through `className` (merged last by tailwind-merge).\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\n\nexport const card = tv({\n slots: {\n root:\n \"group relative flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n media: \"relative overflow-hidden bg-media\",\n image: \"h-full w-full object-cover transition-transform duration-500 motion-safe:group-hover:scale-105\",\n fallback: \"flex h-full w-full items-center justify-center bg-linear-to-br from-accent/15 via-media to-accent-2/15 text-accent/60\",\n overlay: \"absolute z-10 flex items-center gap-1.5\",\n body: \"relative flex flex-1 flex-col gap-3\",\n title: \"line-clamp-1 text-sm font-semibold text-fg transition-colors group-hover:text-accent\",\n description: \"line-clamp-2 text-xs text-fg-secondary\",\n stat: \"min-w-0\",\n statLabel: \"text-[10px] font-semibold uppercase tracking-wider text-fg-secondary\",\n statValue: \"font-display text-xl font-black tabular-nums text-fg\",\n footer: \"relative mt-auto flex items-center gap-2 border-t border-border-subtle pt-3 text-xs text-fg-secondary\",\n },\n variants: {\n radius: { md: { root: \"rounded-md\" }, lg: { root: \"rounded-lg\" }, xl: { root: \"rounded-xl\" } },\n tone: { default: {}, elevated: { root: \"bg-surface-2 shadow-md\" }, glass: { root: \"bg-surface-1/70 backdrop-blur-md\" } },\n interactive: { true: { root: \"kz-spotlight kz-lift hover:border-accent/50\" } },\n padding: { none: { body: \"p-0\" }, sm: { body: \"p-3\" }, md: { body: \"p-4\" }, lg: { body: \"p-6\" } },\n },\n defaultVariants: { radius: \"xl\", tone: \"default\", padding: \"md\" },\n});\n\ntype CardVariants = VariantProps<typeof card>;\n/** The parts without a variant read the default slots: no context, so server-safe. */\nconst slots = card();\n\nexport type CardRootProps = React.ComponentProps<\"div\"> &\n Pick<CardVariants, \"radius\" | \"tone\" | \"interactive\"> & {\n /** Renders the child (a link, an article) instead of the <div>, with props, classes and ref merged. */\n asChild?: boolean;\n /** Enters on scroll (MotionObserver): the index in the grid becomes the delay (50 ms a step, 8 steps at most). */\n reveal?: number;\n };\n\nexport function CardRoot({ asChild, reveal, radius, tone, interactive, className, style, ...props }: CardRootProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n const revealStyle =\n reveal === undefined ? style : ({ ...style, \"--kz-delay\": `${Math.min(Math.max(reveal, 0), 8) * 50}ms` } as React.CSSProperties);\n return (\n <Comp\n data-reveal={reveal === undefined ? undefined : \"\"}\n data-interactive={interactive ? \"\" : undefined}\n style={revealStyle}\n className={card({ radius, tone, interactive }).root({ className })}\n {...props}\n />\n );\n}\n\nconst ASPECT = { video: \"aspect-video\", square: \"aspect-square\", portrait: \"aspect-[3/4]\", auto: \"\" } as const;\nexport type CardMediaProps = React.ComponentProps<\"div\"> & { aspect?: keyof typeof ASPECT };\n\nexport function CardMedia({ aspect = \"video\", className, ...props }: CardMediaProps) {\n return <div data-aspect={aspect} className={slots.media({ className: cn(ASPECT[aspect], className) })} {...props} />;\n}\n\nexport type CardImageProps = Omit<React.ComponentProps<\"img\">, \"src\"> & {\n src?: string | null;\n /** Shown when there is no image: an icon, an illustration (decorative). */\n fallback?: React.ReactNode;\n};\n\n/** The image of a media, or its `fallback` when there is none. `alt` is empty by default: the title names the card. */\nexport function CardImage({ src, alt = \"\", fallback, className, ...props }: CardImageProps) {\n if (!src) {\n return (\n <div data-fallback=\"\" aria-hidden className={slots.fallback({ className })}>\n {fallback}\n </div>\n );\n }\n return <img src={src} alt={alt} loading=\"lazy\" decoding=\"async\" className={slots.image({ className })} {...props} />;\n}\n\nconst CORNER = {\n \"top-left\": \"left-2.5 top-2.5\",\n \"top-right\": \"right-2.5 top-2.5\",\n \"bottom-left\": \"bottom-2.5 left-2.5\",\n \"bottom-right\": \"bottom-2.5 right-2.5\",\n} as const;\nexport type CardOverlayProps = React.ComponentProps<\"div\"> & { corner?: keyof typeof CORNER };\n\n/** What sits on the media (badges, a caption). `scrim` and `fg-on-media` are invariant: nothing to do for light. */\nexport function CardOverlay({ corner = \"top-left\", className, ...props }: CardOverlayProps) {\n return <div data-corner={corner} className={slots.overlay({ className: cn(CORNER[corner], className) })} {...props} />;\n}\n\nexport type CardBodyProps = React.ComponentProps<\"div\"> & Pick<CardVariants, \"padding\">;\n\nexport function CardBody({ padding, className, ...props }: CardBodyProps) {\n return <div className={card({ padding }).body({ className })} {...props} />;\n}\n\nexport type CardTitleProps = React.ComponentProps<\"h3\"> & { as?: \"h2\" | \"h3\" | \"h4\" };\n\nexport function CardTitle({ as: Tag = \"h3\", className, ...props }: CardTitleProps) {\n return <Tag className={slots.title({ className })} {...props} />;\n}\n\nexport function CardDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return <p className={slots.description({ className })} {...props} />;\n}\n\nexport type CardStatProps = React.ComponentProps<\"div\"> & { label: React.ReactNode };\n\n/** A figure put forward: the label in capitals, the value in tabular digits. */\nexport function CardStat({ label, className, children, ...props }: CardStatProps) {\n return (\n <div className={slots.stat({ className })} {...props}>\n <p className={slots.statLabel()}>{label}</p>\n <p className={slots.statValue()}>{children}</p>\n </div>\n );\n}\n\nexport function CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={slots.footer({ className })} {...props} />;\n}\n\n/** `Card.Root/Media/Image/Overlay/Body/Title/Description/Stat/Footer`. */\nexport const Card = {\n Root: CardRoot,\n Media: CardMedia,\n Image: CardImage,\n Overlay: CardOverlay,\n Body: CardBody,\n Title: CardTitle,\n Description: CardDescription,\n Stat: CardStat,\n Footer: CardFooter,\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/card/card.tsx"],"sourcesContent":["// Server-safe: no hook, no context. One `tv` definition with slots: each part takes its slot, and a product overrides\n// any part through `className` (merged last by tailwind-merge).\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\n\nexport const card = tv({\n slots: {\n root:\n \"group relative flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n media: \"relative overflow-hidden bg-media\",\n image: \"h-full w-full object-cover transition-transform duration-500 motion-safe:group-hover:scale-105\",\n fallback: \"flex h-full w-full items-center justify-center bg-linear-to-br from-accent/15 via-media to-accent-2/15 text-accent/60\",\n overlay: \"absolute z-10 flex items-center gap-1.5\",\n body: \"relative flex flex-1 flex-col gap-3\",\n title: \"line-clamp-1 text-sm font-semibold text-fg transition-colors group-hover:text-accent\",\n description: \"line-clamp-2 text-xs text-fg-secondary\",\n stat: \"min-w-0\",\n statLabel: \"text-[10px] font-semibold uppercase tracking-wider text-fg-secondary\",\n statValue: \"font-display text-xl font-black tabular-nums text-fg\",\n footer: \"relative mt-auto flex items-center gap-2 border-t border-border-subtle pt-3 text-xs text-fg-secondary\",\n },\n variants: {\n radius: { md: { root: \"rounded-md\" }, lg: { root: \"rounded-lg\" }, xl: { root: \"rounded-xl\" } },\n tone: { default: {}, elevated: { root: \"bg-surface-2 shadow-md\" }, glass: { root: \"bg-surface-1/70 backdrop-blur-md\" } },\n interactive: { true: { root: \"kz-spotlight kz-lift hover:border-accent/50\" } },\n padding: { none: { body: \"p-0\" }, sm: { body: \"p-3\" }, md: { body: \"p-4\" }, lg: { body: \"p-6\" } },\n },\n defaultVariants: { radius: \"xl\", tone: \"default\", padding: \"md\" },\n});\n\ntype CardVariants = VariantProps<typeof card>;\n/** The parts without a variant read the default slots: no context, so server-safe. */\nconst slots = card();\n\nexport type CardRootProps = React.ComponentProps<\"div\"> &\n Pick<CardVariants, \"radius\" | \"tone\" | \"interactive\"> & {\n /**\n * md · lg · xl.\n * @default \"xl\"\n */\n radius?: CardVariants[\"radius\"];\n /**\n * default (the base surface) · elevated (raised, a shadow) · glass (translucent, blurred).\n * @default \"default\"\n */\n tone?: CardVariants[\"tone\"];\n /** The spotlight that follows the pointer and the lift on hover: for a card that is a link. */\n interactive?: CardVariants[\"interactive\"];\n /** Renders the child (a link, an article) instead of the <div>, with props, classes and ref merged. */\n asChild?: boolean;\n /** Enters on scroll (MotionObserver): the index in the grid becomes the delay (50 ms a step, 8 steps at most). */\n reveal?: number;\n };\n\nexport function CardRoot({ asChild, reveal, radius, tone, interactive, className, style, ...props }: CardRootProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n const revealStyle =\n reveal === undefined ? style : ({ ...style, \"--kz-delay\": `${Math.min(Math.max(reveal, 0), 8) * 50}ms` } as React.CSSProperties);\n return (\n <Comp\n data-reveal={reveal === undefined ? undefined : \"\"}\n data-interactive={interactive ? \"\" : undefined}\n style={revealStyle}\n className={card({ radius, tone, interactive }).root({ className })}\n {...props}\n />\n );\n}\n\nconst ASPECT = { video: \"aspect-video\", square: \"aspect-square\", portrait: \"aspect-[3/4]\", auto: \"\" } as const;\nexport type CardMediaProps = React.ComponentProps<\"div\"> & {\n /** The ratio of the media: video (16:9) · square · portrait (3:4) · auto (the content's). */\n aspect?: keyof typeof ASPECT;\n};\n\nexport function CardMedia({ aspect = \"video\", className, ...props }: CardMediaProps) {\n return <div data-aspect={aspect} className={slots.media({ className: cn(ASPECT[aspect], className) })} {...props} />;\n}\n\nexport type CardImageProps = Omit<React.ComponentProps<\"img\">, \"src\"> & {\n /** The image's URL; `null` or nothing shows the `fallback`. */\n src?: string | null;\n /** Shown when there is no image: an icon, an illustration (decorative). */\n fallback?: React.ReactNode;\n};\n\n/** The image of a media, or its `fallback` when there is none. `alt` is empty by default: the title names the card. */\nexport function CardImage({ src, alt = \"\", fallback, className, ...props }: CardImageProps) {\n if (!src) {\n return (\n <div data-fallback=\"\" aria-hidden className={slots.fallback({ className })}>\n {fallback}\n </div>\n );\n }\n return <img src={src} alt={alt} loading=\"lazy\" decoding=\"async\" className={slots.image({ className })} {...props} />;\n}\n\nconst CORNER = {\n \"top-left\": \"left-2.5 top-2.5\",\n \"top-right\": \"right-2.5 top-2.5\",\n \"bottom-left\": \"bottom-2.5 left-2.5\",\n \"bottom-right\": \"bottom-2.5 right-2.5\",\n} as const;\nexport type CardOverlayProps = React.ComponentProps<\"div\"> & {\n /** The corner of the media it sits in. */\n corner?: keyof typeof CORNER;\n};\n\n/** What sits on the media (badges, a caption). `scrim` and `fg-on-media` are invariant: nothing to do for light. */\nexport function CardOverlay({ corner = \"top-left\", className, ...props }: CardOverlayProps) {\n return <div data-corner={corner} className={slots.overlay({ className: cn(CORNER[corner], className) })} {...props} />;\n}\n\nexport type CardBodyProps = React.ComponentProps<\"div\"> & {\n /**\n * none · sm · md · lg.\n * @default \"md\"\n */\n padding?: CardVariants[\"padding\"];\n};\n\nexport function CardBody({ padding, className, ...props }: CardBodyProps) {\n return <div className={card({ padding }).body({ className })} {...props} />;\n}\n\nexport type CardTitleProps = React.ComponentProps<\"h3\"> & {\n /** The heading level, to fit the page's outline. */\n as?: \"h2\" | \"h3\" | \"h4\";\n};\n\nexport function CardTitle({ as: Tag = \"h3\", className, ...props }: CardTitleProps) {\n return <Tag className={slots.title({ className })} {...props} />;\n}\n\nexport function CardDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return <p className={slots.description({ className })} {...props} />;\n}\n\nexport type CardStatProps = React.ComponentProps<\"div\"> & {\n /** What the figure is, in small capitals above it (the figure is the children). */\n label: React.ReactNode;\n};\n\n/** A figure put forward: the label in capitals, the value in tabular digits. */\nexport function CardStat({ label, className, children, ...props }: CardStatProps) {\n return (\n <div className={slots.stat({ className })} {...props}>\n <p className={slots.statLabel()}>{label}</p>\n <p className={slots.statValue()}>{children}</p>\n </div>\n );\n}\n\nexport function CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={slots.footer({ className })} {...props} />;\n}\n\n/** `Card.Root/Media/Image/Overlay/Body/Title/Description/Stat/Footer`. */\nexport const Card = {\n Root: CardRoot,\n Media: CardMedia,\n Image: CardImage,\n Overlay: CardOverlay,\n Body: CardBody,\n Title: CardTitle,\n Description: CardDescription,\n Stat: CardStat,\n Footer: CardFooter,\n};\n"],"mappings":"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","names":[]}
package/dist/chip.d.ts CHANGED
@@ -44,12 +44,20 @@ declare const chip: tailwind_variants.TVReturnType<{
44
44
  }>>;
45
45
  type ChipVariants = VariantProps<typeof chip>;
46
46
  type ToggleChipProps = Omit<React.ComponentProps<"button">, "value" | "defaultValue"> & ChipVariants & {
47
+ /**
48
+ * sm · md (inside `Chip.Group`, the group's size by default).
49
+ * @default "md"
50
+ */
51
+ size?: ChipVariants["size"];
47
52
  /** Inside `Chip.Group`: the value this chip stands for (required there, ignored alone). */
48
53
  value?: string;
49
54
  /** Alone: pressed or not (`defaultSelected` uncontrolled), `onSelectedChange` on every press. */
50
55
  selected?: boolean;
56
+ /** Alone: pressed at first, uncontrolled. */
51
57
  defaultSelected?: boolean;
58
+ /** Alone: called with the new state on every press. */
52
59
  onSelectedChange?: (selected: boolean) => void;
60
+ /** A pressable chip (the default); `true` makes it a static chip with a remove button. */
53
61
  removable?: false;
54
62
  };
55
63
  type RemovableChipProps = Omit<React.ComponentProps<"span">, "onSelect"> & ChipVariants & {
@@ -57,33 +65,48 @@ type RemovableChipProps = Omit<React.ComponentProps<"span">, "onSelect"> & ChipV
57
65
  removable: true;
58
66
  /** The accessible name of the remove button — passed translated, e.g. "Remove #night". */
59
67
  removeLabel: string;
68
+ /** Runs when the remove button is pressed. */
60
69
  onRemove: () => void;
70
+ /** Disables the remove button. */
61
71
  disabled?: boolean;
62
72
  };
63
73
  type ChipProps = ToggleChipProps | RemovableChipProps;
64
74
  /** A selectable pill (`selected` / `onSelectedChange`), an item of `Chip.Group` (`value`), or `removable`. */
65
75
  declare function ChipBase(props: ChipProps): React.JSX.Element;
66
76
  type GroupBase = Omit<React.ComponentProps<"div">, "defaultValue" | "dir"> & ChipVariants & {
77
+ /**
78
+ * sm · md: the size of every chip of the group.
79
+ * @default "md"
80
+ */
81
+ size?: ChipVariants["size"];
67
82
  /** The group's accessible name — passed translated ("Filter by format"). */
68
83
  label?: string;
84
+ /** The arrow keys that move: left / right (horizontal, a row) or up / down (vertical, a column). */
69
85
  orientation?: "horizontal" | "vertical";
70
86
  /** Arrow keys wrap from the last chip to the first (default `true`). */
71
87
  loop?: boolean;
88
+ /** Disables every chip of the group. */
72
89
  disabled?: boolean;
73
90
  };
74
91
  type ChipGroupProps = (GroupBase & {
75
92
  /** One choice: the chips behave as radios. */
76
93
  type: "single";
94
+ /** The chosen value (controlled), `""` when none. */
77
95
  value?: string;
96
+ /** The value chosen at first, uncontrolled. */
78
97
  defaultValue?: string;
98
+ /** Called with the new value on every choice. */
79
99
  onValueChange?: (value: string) => void;
80
100
  /** Keeps one chip selected: pressing the selected chip does not clear it (default `false`). */
81
101
  required?: boolean;
82
102
  }) | (GroupBase & {
83
103
  /** Any number of choices: the chips are pressed buttons. */
84
104
  type: "multiple";
105
+ /** The chosen values (controlled). */
85
106
  value?: string[];
107
+ /** The values chosen at first, uncontrolled. */
86
108
  defaultValue?: string[];
109
+ /** Called with the new values on every press. */
87
110
  onValueChange?: (value: string[]) => void;
88
111
  required?: never;
89
112
  });
package/dist/chip.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chip/chip.tsx"],"sourcesContent":["// Client (a context). A chip is a pressable pill: alone it is a Radix Toggle (aria-pressed), inside `Chip.Group` an\n// item of a Radix Toggle Group (roving focus with the arrows; `single` = radio semantics, `multiple` = pressed\n// buttons). A `removable` chip is a static label with its own remove button (two buttons cannot nest).\nimport { Toggle as TogglePrimitive, ToggleGroup as ToggleGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const chip = tv({\n slots: {\n group: \"flex flex-wrap items-center gap-2 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch\",\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-full border font-semibold transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40 \" +\n \"border-border-default bg-surface-1 text-fg-secondary hover:border-border-strong hover:text-fg \" +\n \"data-[state=on]:border-accent data-[state=on]:bg-accent-soft data-[state=on]:text-fg\",\n remove:\n \"-mr-1.5 inline-flex h-6 w-6 items-center justify-center rounded-full text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n variants: {\n size: { sm: { base: \"h-7 px-3 text-xs\" }, md: { base: \"h-9 px-3.5 text-xs\" } },\n },\n defaultVariants: { size: \"md\" },\n});\n\nexport type ChipVariants = VariantProps<typeof chip>;\n\ntype GroupContext = { size: ChipVariants[\"size\"] };\nconst ChipGroupContext = React.createContext<GroupContext | null>(null);\n\nfunction RemoveIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-3.5 w-3.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\ntype ToggleChipProps = Omit<React.ComponentProps<\"button\">, \"value\" | \"defaultValue\"> &\n ChipVariants & {\n /** Inside `Chip.Group`: the value this chip stands for (required there, ignored alone). */\n value?: string;\n /** Alone: pressed or not (`defaultSelected` uncontrolled), `onSelectedChange` on every press. */\n selected?: boolean;\n defaultSelected?: boolean;\n onSelectedChange?: (selected: boolean) => void;\n removable?: false;\n };\n\ntype RemovableChipProps = Omit<React.ComponentProps<\"span\">, \"onSelect\"> &\n ChipVariants & {\n /** A static chip (a chosen tag, an applied filter) with a remove button. */\n removable: true;\n /** The accessible name of the remove button — passed translated, e.g. \"Remove #night\". */\n removeLabel: string;\n onRemove: () => void;\n disabled?: boolean;\n };\n\nexport type ChipProps = ToggleChipProps | RemovableChipProps;\n\n/** A selectable pill (`selected` / `onSelectedChange`), an item of `Chip.Group` (`value`), or `removable`. */\nfunction ChipBase(props: ChipProps) {\n const group = React.useContext(ChipGroupContext);\n if (props.removable) {\n const { removable: _removable, removeLabel, onRemove, disabled, size, className, children, ...rest } = props;\n const s = chip({ size: size ?? group?.size });\n return (\n <span data-removable=\"\" className={s.base({ className })} {...rest}>\n {children}\n <button type=\"button\" aria-label={removeLabel} title={removeLabel} disabled={disabled} onClick={onRemove} className={s.remove()}>\n <RemoveIcon />\n </button>\n </span>\n );\n }\n const { removable: _removable, value, selected, defaultSelected, onSelectedChange, size, className, ...rest } = props;\n const s = chip({ size: size ?? group?.size });\n if (group) {\n if (value === undefined) throw new Error(\"Chip: a chip inside Chip.Group needs a `value`.\");\n return <ToggleGroupPrimitive.Item value={value} className={s.base({ className })} {...rest} />;\n }\n return (\n <TogglePrimitive.Root\n pressed={selected}\n defaultPressed={defaultSelected}\n onPressedChange={onSelectedChange}\n className={s.base({ className })}\n {...rest}\n />\n );\n}\n\ntype GroupBase = Omit<React.ComponentProps<\"div\">, \"defaultValue\" | \"dir\"> &\n ChipVariants & {\n /** The group's accessible name — passed translated (\"Filter by format\"). */\n label?: string;\n orientation?: \"horizontal\" | \"vertical\";\n /** Arrow keys wrap from the last chip to the first (default `true`). */\n loop?: boolean;\n disabled?: boolean;\n };\n\nexport type ChipGroupProps =\n | (GroupBase & {\n /** One choice: the chips behave as radios. */\n type: \"single\";\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n /** Keeps one chip selected: pressing the selected chip does not clear it (default `false`). */\n required?: boolean;\n })\n | (GroupBase & {\n /** Any number of choices: the chips are pressed buttons. */\n type: \"multiple\";\n value?: string[];\n defaultValue?: string[];\n onValueChange?: (value: string[]) => void;\n required?: never;\n });\n\n/** Chips that choose together: `type` single · multiple, `value`/`defaultValue` + `onValueChange`. */\nexport function ChipGroup({ label, size, className, children, ...props }: ChipGroupProps) {\n const s = chip({ size });\n const context = React.useMemo(() => ({ size }), [size]);\n const common = { \"aria-label\": label, className: s.group({ className }) };\n let group: React.ReactNode;\n if (props.type === \"single\") {\n const { type: _type, value, defaultValue, onValueChange, required, ...rest } = props;\n group = <SingleGroup {...rest} {...common} value={value} defaultValue={defaultValue} onValueChange={onValueChange} required={required}>{children}</SingleGroup>;\n } else {\n const { type: _type, required: _required, ...rest } = props;\n group = (\n <ToggleGroupPrimitive.Root type=\"multiple\" {...rest} {...common}>\n {children}\n </ToggleGroupPrimitive.Root>\n );\n }\n return <ChipGroupContext.Provider value={context}>{group}</ChipGroupContext.Provider>;\n}\n\n/** Radix's single group, plus `required`: the value is held here so that an empty change can be refused. */\nfunction SingleGroup({\n value,\n defaultValue,\n onValueChange,\n required,\n ...props\n}: Omit<GroupBase, \"size\" | \"label\"> & {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n required?: boolean;\n}) {\n const [inner, setInner] = React.useState(defaultValue ?? \"\");\n const current = value ?? inner;\n return (\n <ToggleGroupPrimitive.Root\n type=\"single\"\n value={current}\n onValueChange={(next) => {\n if (required && !next) return;\n if (value === undefined) setInner(next);\n onValueChange?.(next);\n }}\n {...props}\n />\n );\n}\n\n/** `Chip` (selectable, removable) and `Chip.Group` (single · multiple). */\nexport const Chip = Object.assign(ChipBase, { Group: ChipGroup });\n"],"mappings":"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","names":["_removable","size","className","rest","s"]}
1
+ {"version":3,"sources":["../src/chip/chip.tsx"],"sourcesContent":["// Client (a context). A chip is a pressable pill: alone it is a Radix Toggle (aria-pressed), inside `Chip.Group` an\n// item of a Radix Toggle Group (roving focus with the arrows; `single` = radio semantics, `multiple` = pressed\n// buttons). A `removable` chip is a static label with its own remove button (two buttons cannot nest).\nimport { Toggle as TogglePrimitive, ToggleGroup as ToggleGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const chip = tv({\n slots: {\n group: \"flex flex-wrap items-center gap-2 data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch\",\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-full border font-semibold transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40 \" +\n \"border-border-default bg-surface-1 text-fg-secondary hover:border-border-strong hover:text-fg \" +\n \"data-[state=on]:border-accent data-[state=on]:bg-accent-soft data-[state=on]:text-fg\",\n remove:\n \"-mr-1.5 inline-flex h-6 w-6 items-center justify-center rounded-full text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n variants: {\n size: { sm: { base: \"h-7 px-3 text-xs\" }, md: { base: \"h-9 px-3.5 text-xs\" } },\n },\n defaultVariants: { size: \"md\" },\n});\n\nexport type ChipVariants = VariantProps<typeof chip>;\n\ntype GroupContext = { size: ChipVariants[\"size\"] };\nconst ChipGroupContext = React.createContext<GroupContext | null>(null);\n\nfunction RemoveIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-3.5 w-3.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\ntype ToggleChipProps = Omit<React.ComponentProps<\"button\">, \"value\" | \"defaultValue\"> &\n ChipVariants & {\n /**\n * sm · md (inside `Chip.Group`, the group's size by default).\n * @default \"md\"\n */\n size?: ChipVariants[\"size\"];\n /** Inside `Chip.Group`: the value this chip stands for (required there, ignored alone). */\n value?: string;\n /** Alone: pressed or not (`defaultSelected` uncontrolled), `onSelectedChange` on every press. */\n selected?: boolean;\n /** Alone: pressed at first, uncontrolled. */\n defaultSelected?: boolean;\n /** Alone: called with the new state on every press. */\n onSelectedChange?: (selected: boolean) => void;\n /** A pressable chip (the default); `true` makes it a static chip with a remove button. */\n removable?: false;\n };\n\ntype RemovableChipProps = Omit<React.ComponentProps<\"span\">, \"onSelect\"> &\n ChipVariants & {\n /** A static chip (a chosen tag, an applied filter) with a remove button. */\n removable: true;\n /** The accessible name of the remove button — passed translated, e.g. \"Remove #night\". */\n removeLabel: string;\n /** Runs when the remove button is pressed. */\n onRemove: () => void;\n /** Disables the remove button. */\n disabled?: boolean;\n };\n\nexport type ChipProps = ToggleChipProps | RemovableChipProps;\n\n/** A selectable pill (`selected` / `onSelectedChange`), an item of `Chip.Group` (`value`), or `removable`. */\nfunction ChipBase(props: ChipProps) {\n const group = React.useContext(ChipGroupContext);\n if (props.removable) {\n const { removable: _removable, removeLabel, onRemove, disabled, size, className, children, ...rest } = props;\n const s = chip({ size: size ?? group?.size });\n return (\n <span data-removable=\"\" className={s.base({ className })} {...rest}>\n {children}\n <button type=\"button\" aria-label={removeLabel} title={removeLabel} disabled={disabled} onClick={onRemove} className={s.remove()}>\n <RemoveIcon />\n </button>\n </span>\n );\n }\n const { removable: _removable, value, selected, defaultSelected, onSelectedChange, size, className, ...rest } = props;\n const s = chip({ size: size ?? group?.size });\n if (group) {\n if (value === undefined) throw new Error(\"Chip: a chip inside Chip.Group needs a `value`.\");\n return <ToggleGroupPrimitive.Item value={value} className={s.base({ className })} {...rest} />;\n }\n return (\n <TogglePrimitive.Root\n pressed={selected}\n defaultPressed={defaultSelected}\n onPressedChange={onSelectedChange}\n className={s.base({ className })}\n {...rest}\n />\n );\n}\n\ntype GroupBase = Omit<React.ComponentProps<\"div\">, \"defaultValue\" | \"dir\"> &\n ChipVariants & {\n /**\n * sm · md: the size of every chip of the group.\n * @default \"md\"\n */\n size?: ChipVariants[\"size\"];\n /** The group's accessible name — passed translated (\"Filter by format\"). */\n label?: string;\n /** The arrow keys that move: left / right (horizontal, a row) or up / down (vertical, a column). */\n orientation?: \"horizontal\" | \"vertical\";\n /** Arrow keys wrap from the last chip to the first (default `true`). */\n loop?: boolean;\n /** Disables every chip of the group. */\n disabled?: boolean;\n };\n\nexport type ChipGroupProps =\n | (GroupBase & {\n /** One choice: the chips behave as radios. */\n type: \"single\";\n /** The chosen value (controlled), `\"\"` when none. */\n value?: string;\n /** The value chosen at first, uncontrolled. */\n defaultValue?: string;\n /** Called with the new value on every choice. */\n onValueChange?: (value: string) => void;\n /** Keeps one chip selected: pressing the selected chip does not clear it (default `false`). */\n required?: boolean;\n })\n | (GroupBase & {\n /** Any number of choices: the chips are pressed buttons. */\n type: \"multiple\";\n /** The chosen values (controlled). */\n value?: string[];\n /** The values chosen at first, uncontrolled. */\n defaultValue?: string[];\n /** Called with the new values on every press. */\n onValueChange?: (value: string[]) => void;\n required?: never;\n });\n\n/** Chips that choose together: `type` single · multiple, `value`/`defaultValue` + `onValueChange`. */\nexport function ChipGroup({ label, size, className, children, ...props }: ChipGroupProps) {\n const s = chip({ size });\n const context = React.useMemo(() => ({ size }), [size]);\n const common = { \"aria-label\": label, className: s.group({ className }) };\n let group: React.ReactNode;\n if (props.type === \"single\") {\n const { type: _type, value, defaultValue, onValueChange, required, ...rest } = props;\n group = <SingleGroup {...rest} {...common} value={value} defaultValue={defaultValue} onValueChange={onValueChange} required={required}>{children}</SingleGroup>;\n } else {\n const { type: _type, required: _required, ...rest } = props;\n group = (\n <ToggleGroupPrimitive.Root type=\"multiple\" {...rest} {...common}>\n {children}\n </ToggleGroupPrimitive.Root>\n );\n }\n return <ChipGroupContext.Provider value={context}>{group}</ChipGroupContext.Provider>;\n}\n\n/** Radix's single group, plus `required`: the value is held here so that an empty change can be refused. */\nfunction SingleGroup({\n value,\n defaultValue,\n onValueChange,\n required,\n ...props\n}: Omit<GroupBase, \"size\" | \"label\"> & {\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n required?: boolean;\n}) {\n const [inner, setInner] = React.useState(defaultValue ?? \"\");\n const current = value ?? inner;\n return (\n <ToggleGroupPrimitive.Root\n type=\"single\"\n value={current}\n onValueChange={(next) => {\n if (required && !next) return;\n if (value === undefined) setInner(next);\n onValueChange?.(next);\n }}\n {...props}\n />\n );\n}\n\n/** `Chip` (selectable, removable) and `Chip.Group` (single · multiple). */\nexport const Chip = Object.assign(ChipBase, { Group: ChipGroup });\n"],"mappings":"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","names":["_removable","size","className","rest","s"]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  IconButton
4
- } from "./chunk-QRG5RYEI.js";
4
+ } from "./chunk-ZUD4U22H.js";
5
5
 
6
6
  // src/dialog/dialog.tsx
7
7
  import { Dialog as DialogPrimitive } from "radix-ui";
@@ -118,4 +118,4 @@ export {
118
118
  Dialog,
119
119
  Sheet
120
120
  };
121
- //# sourceMappingURL=chunk-5FRYKFTO.js.map
121
+ //# sourceMappingURL=chunk-3X5MVH54.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dialog/dialog.tsx"],"sourcesContent":["// Client (a portal). Radix does the focus trap, the scroll lock, Escape, the outside click, aria-modal, the\n// aria-labelledby / aria-describedby wiring and the focus return: this file only holds the shape.\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { IconButton } from \"../button/button\";\n\nexport const dialog = tv({\n slots: {\n overlay: \"kz-overlay fixed inset-0 z-50 bg-overlay backdrop-blur-xs\",\n content:\n \"kz-dialog fixed z-50 flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg shadow-lg focus:outline-hidden\",\n close: \"absolute right-3 top-3 h-9 w-9\",\n header: \"flex flex-col gap-1 px-5 pb-2 pr-14 pt-5\",\n title: \"text-base font-bold text-fg\",\n description: \"text-sm text-fg-secondary\",\n body: \"min-h-0 flex-1 overflow-y-auto px-5 pb-5\",\n footer:\n \"flex flex-wrap items-center justify-end gap-2 border-t border-border-subtle px-5 py-4 pb-[max(1rem,env(safe-area-inset-bottom))]\",\n },\n variants: {\n placement: {\n center: { content: \"left-1/2 top-1/2 max-h-[85dvh] w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl\" },\n /* A sheet: anchored at the bottom on a phone, centred from `sm` up. */\n bottom: {\n content:\n \"inset-x-0 bottom-0 max-h-[92dvh] rounded-t-[1.75rem] sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:w-full \" +\n \"sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-[1.75rem]\",\n },\n right: { content: \"inset-y-0 right-0 h-full w-full max-w-md rounded-none border-y-0 border-r-0\" },\n },\n size: { sm: { content: \"sm:max-w-sm\" }, md: { content: \"sm:max-w-md\" }, lg: { content: \"sm:max-w-2xl\" } },\n },\n defaultVariants: { placement: \"center\", size: \"md\" },\n});\nconst s = dialog();\n\nexport type DialogVariants = VariantProps<typeof dialog>;\n\nfunction CloseIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\ntype CloseButtonProps =\n | {\n /** The accessible name of the close button — passed translated. */\n closeLabel: string;\n /** Leaves the close button out (the content brings its own way out, or none: see `dismissible`). */\n hideClose?: false;\n }\n | { closeLabel?: string; hideClose: true };\n\nexport type DialogContentProps = React.ComponentProps<typeof DialogPrimitive.Content> &\n DialogVariants &\n CloseButtonProps & {\n /**\n * center · bottom (a sheet on a phone, centred from `sm` up) · right (a side panel, full height).\n * @default \"center\"\n */\n placement?: DialogVariants[\"placement\"];\n /**\n * sm · md · lg: the width of the dialog.\n * @default \"md\"\n */\n size?: DialogVariants[\"size\"];\n /**\n * `false`: Escape and a click outside do not close it (a gate the user must answer: age, terms). It still closes\n * through `open` / `onOpenChange` and any `Dialog.Close` inside. Default `true`.\n */\n dismissible?: boolean;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n };\n\nconst prevent = (event: Event) => event.preventDefault();\n\n/** The dialog itself, portalled over a dimmed overlay, with a close button. Give it a `Dialog.Title`. */\nexport function DialogContent({\n placement,\n size,\n closeLabel,\n hideClose,\n dismissible = true,\n container,\n className,\n children,\n onEscapeKeyDown,\n onPointerDownOutside,\n onInteractOutside,\n ...props\n}: DialogContentProps) {\n const v = dialog({ placement, size });\n return (\n <DialogPrimitive.Portal container={container}>\n <DialogPrimitive.Overlay className={v.overlay()} />\n <DialogPrimitive.Content\n data-placement={placement ?? \"center\"}\n data-dismissible={dismissible ? undefined : \"false\"}\n className={v.content({ className })}\n onEscapeKeyDown={dismissible ? onEscapeKeyDown : chain(onEscapeKeyDown, prevent)}\n onPointerDownOutside={dismissible ? onPointerDownOutside : chain(onPointerDownOutside, prevent)}\n onInteractOutside={dismissible ? onInteractOutside : chain(onInteractOutside, prevent)}\n {...props}\n >\n {children}\n {!hideClose && (\n <DialogPrimitive.Close asChild>\n <IconButton label={closeLabel as string} variant=\"ghost\" shape=\"pill\" className={v.close()}>\n <CloseIcon />\n </IconButton>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n}\n\nfunction chain<E extends Event>(handler: ((event: E) => void) | undefined, then: (event: E) => void) {\n return (event: E) => {\n handler?.(event);\n then(event);\n };\n}\n\nexport function DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.header({ className })} {...props} />;\n}\n\nexport function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return <DialogPrimitive.Title className={s.title({ className })} {...props} />;\n}\n\nexport function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return <DialogPrimitive.Description className={s.description({ className })} {...props} />;\n}\n\nexport function DialogBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport function DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.footer({ className })} {...props} />;\n}\n\n/** `Dialog.Root/Trigger/Content/Header/Title/Description/Body/Footer/Close`. `open`/`defaultOpen` + `onOpenChange`. */\nexport const Dialog = {\n Root: DialogPrimitive.Root,\n Trigger: DialogPrimitive.Trigger,\n Close: DialogPrimitive.Close,\n Content: DialogContent,\n Header: DialogHeader,\n Title: DialogTitle,\n Description: DialogDescription,\n Body: DialogBody,\n Footer: DialogFooter,\n};\n\n/** `Omit` that keeps the close-button union (`closeLabel` required unless `hideClose`). */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nexport type SheetProps = DistributiveOmit<DialogContentProps, \"placement\">;\n\n/** A sheet is a dialog anchored at the bottom (centred from `sm` up): `Dialog.Content placement=\"bottom\"`. */\nexport function Sheet(props: SheetProps) {\n return <DialogContent placement=\"bottom\" {...props} />;\n}\n"],"mappings":"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","names":[]}
@@ -46,4 +46,4 @@ export {
46
46
  Button,
47
47
  IconButton
48
48
  };
49
- //# sourceMappingURL=chunk-QRG5RYEI.js.map
49
+ //# sourceMappingURL=chunk-ZUD4U22H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/button/button.tsx"],"sourcesContent":["// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const buttonVariants = tv({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98]\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The danger token is invariant and too light for small text on a light surface (3.6:1): the label stays a\n // text role, the border and the tint carry the danger.\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n shape: { rounded: \"rounded-lg\", pill: \"rounded-full\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /**\n * The look: `primary` (the accent), `secondary` (a raised surface), `outline`, `ghost`, `danger`.\n * @default \"secondary\"\n */\n variant?: ButtonVariants[\"variant\"];\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"md\"\n */\n size?: ButtonVariants[\"size\"];\n /**\n * rounded · pill.\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /** Disables and signals the wait (aria-busy, data-loading) — the product adds a spinner if it wants one. */\n loading?: boolean;\n };\n\nexport function Button({ asChild, loading, variant, size, shape, className, disabled, ...props }: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n return (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({ variant, size, shape, className })}\n {...props}\n />\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"icon\"\n */\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. */\nexport function IconButton({ label, size = \"icon\", ...props }: IconButtonProps) {\n return <Button aria-label={label} title={label} size={size} {...props} />;\n}\n"],"mappings":";;;AACA,SAAS,YAAY;AAErB,SAAS,UAA6B;AAmDlC;AAjDG,IAAM,iBAAiB,GAAG;AAAA,EAC/B,MACE;AAAA,EAGF,UAAU;AAAA,IACR,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA;AAAA;AAAA,MAGP,QAAQ;AAAA,IACV;AAAA,IACA,MAAM,EAAE,IAAI,oBAAoB,IAAI,qBAAqB,IAAI,qBAAqB,MAAM,YAAY;AAAA,IACpG,OAAO,EAAE,SAAS,cAAc,MAAM,eAAe;AAAA,EACvD;AAAA,EACA,iBAAiB,EAAE,SAAS,aAAa,MAAM,MAAM,OAAO,UAAU;AACxE,CAAC;AA2BM,SAAS,OAAO,EAAE,SAAS,SAAS,SAAS,MAAM,OAAO,WAAW,UAAU,GAAG,MAAM,GAAgB;AAC7G,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,UAAU,SAAY;AAAA,MAC5B,aAAW,WAAW;AAAA,MACtB,gBAAc,UAAU,KAAK;AAAA,MAC7B,gBAAc,WAAW;AAAA,MACzB,UAAU,UAAU,SAAY,YAAY;AAAA,MAC5C,iBAAe,YAAY,YAAY,WAAW,OAAO;AAAA,MACzD,WAAW,eAAe,EAAE,SAAS,MAAM,OAAO,UAAU,CAAC;AAAA,MAC5D,GAAG;AAAA;AAAA,EACN;AAEJ;AAaO,SAAS,WAAW,EAAE,OAAO,OAAO,QAAQ,GAAG,MAAM,GAAoB;AAC9E,SAAO,oBAAC,UAAO,cAAY,OAAO,OAAO,OAAO,MAAa,GAAG,OAAO;AACzE;","names":[]}
package/dist/command.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as tailwind_variants from 'tailwind-variants';
2
2
  import { Command as Command$1 } from 'cmdk';
3
3
  import * as React from 'react';
4
- import { D as DialogContentProps } from './dialog-DGBY2grk.js';
4
+ import { D as DialogContentProps } from './dialog-GQ4Nvuyf.js';
5
5
  import 'radix-ui';
6
6
 
7
7
  declare const command: tailwind_variants.TVReturnType<{
@@ -137,8 +137,11 @@ declare const Command: {
137
137
  Shortcut: typeof CommandShortcut;
138
138
  };
139
139
  type CommandDialogProps = Omit<CommandRootProps, "title"> & {
140
+ /** Open or closed (controlled), with `onOpenChange`. */
140
141
  open?: boolean;
142
+ /** Open at first, uncontrolled. */
141
143
  defaultOpen?: boolean;
144
+ /** Called when it opens or closes (Escape, a click outside, a shortcut of the product). */
142
145
  onOpenChange?: (open: boolean) => void;
143
146
  /** Under the palette, inside the dialog: shortcuts, a "see all results" link. */
144
147
  footer?: React.ReactNode;
package/dist/command.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import {
3
3
  DialogContent
4
- } from "./chunk-5FRYKFTO.js";
5
- import "./chunk-QRG5RYEI.js";
4
+ } from "./chunk-3X5MVH54.js";
5
+ import "./chunk-ZUD4U22H.js";
6
6
  import {
7
7
  cn
8
8
  } from "./chunk-5AXLA4LK.js";