@eifi1/ui-kit 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +21 -11
  2. package/dist/components/alert-banner.d.ts +32 -5
  3. package/dist/components/alert-banner.js +57 -14
  4. package/dist/components/alert-banner.js.map +1 -1
  5. package/dist/components/amount-input.d.ts +4 -0
  6. package/dist/components/breadcrumbs.d.ts +60 -0
  7. package/dist/components/breadcrumbs.js +88 -0
  8. package/dist/components/breadcrumbs.js.map +1 -0
  9. package/dist/components/bulk-action-bar.d.ts +66 -0
  10. package/dist/components/bulk-action-bar.js +149 -0
  11. package/dist/components/bulk-action-bar.js.map +1 -0
  12. package/dist/components/calculator.d.ts +4 -0
  13. package/dist/components/chip.d.ts +31 -5
  14. package/dist/components/chip.js +85 -5
  15. package/dist/components/chip.js.map +1 -1
  16. package/dist/components/copy-button.d.ts +13 -4
  17. package/dist/components/copy-button.js +17 -4
  18. package/dist/components/copy-button.js.map +1 -1
  19. package/dist/components/date-picker.d.ts +22 -2
  20. package/dist/components/date-picker.js +11 -3
  21. package/dist/components/date-picker.js.map +1 -1
  22. package/dist/components/description-list.d.ts +43 -6
  23. package/dist/components/description-list.js +91 -11
  24. package/dist/components/description-list.js.map +1 -1
  25. package/dist/components/dialog-frame.d.ts +7 -0
  26. package/dist/components/dialog-frame.js.map +1 -1
  27. package/dist/components/disclosure.d.ts +57 -2
  28. package/dist/components/disclosure.js +24 -12
  29. package/dist/components/disclosure.js.map +1 -1
  30. package/dist/components/file-dropzone.d.ts +3 -4
  31. package/dist/components/file-dropzone.js +2 -1
  32. package/dist/components/file-dropzone.js.map +1 -1
  33. package/dist/components/full-bleed-dialog.d.ts +23 -4
  34. package/dist/components/full-bleed-dialog.js +11 -2
  35. package/dist/components/full-bleed-dialog.js.map +1 -1
  36. package/dist/components/list.d.ts +174 -0
  37. package/dist/components/list.js +215 -0
  38. package/dist/components/list.js.map +1 -0
  39. package/dist/components/menu-item.d.ts +99 -0
  40. package/dist/components/menu-item.js +83 -0
  41. package/dist/components/menu-item.js.map +1 -0
  42. package/dist/components/modal.d.ts +23 -1
  43. package/dist/components/modal.js +36 -10
  44. package/dist/components/modal.js.map +1 -1
  45. package/dist/components/number-field.d.ts +4 -0
  46. package/dist/components/number-input.d.ts +4 -0
  47. package/dist/components/numpad-sheet.d.ts +4 -0
  48. package/dist/components/page-contents.js +1 -2
  49. package/dist/components/page-contents.js.map +1 -1
  50. package/dist/components/page-header.d.ts +37 -0
  51. package/dist/components/page-header.js +36 -0
  52. package/dist/components/page-header.js.map +1 -0
  53. package/dist/components/series-chart-labels.d.ts +3 -0
  54. package/dist/components/series-chart-labels.js +2 -1
  55. package/dist/components/series-chart-labels.js.map +1 -1
  56. package/dist/components/series-chart.d.ts +16 -0
  57. package/dist/components/series-chart.js +137 -3
  58. package/dist/components/series-chart.js.map +1 -1
  59. package/dist/components/status-dot.d.ts +49 -0
  60. package/dist/components/status-dot.js +52 -0
  61. package/dist/components/status-dot.js.map +1 -0
  62. package/dist/components/table.d.ts +39 -6
  63. package/dist/components/table.js +43 -4
  64. package/dist/components/table.js.map +1 -1
  65. package/dist/components/text.d.ts +63 -0
  66. package/dist/components/text.js +23 -0
  67. package/dist/components/text.js.map +1 -0
  68. package/dist/components/toast.d.ts +167 -0
  69. package/dist/components/toast.js +226 -0
  70. package/dist/components/toast.js.map +1 -0
  71. package/dist/components/toggle-group.d.ts +29 -1
  72. package/dist/components/toggle-group.js +52 -3
  73. package/dist/components/toggle-group.js.map +1 -1
  74. package/dist/components/tooltip.d.ts +38 -15
  75. package/dist/components/tooltip.js +85 -47
  76. package/dist/components/tooltip.js.map +1 -1
  77. package/dist/components/ui.d.ts +104 -4
  78. package/dist/components/ui.js +112 -8
  79. package/dist/components/ui.js.map +1 -1
  80. package/dist/hooks/use-close-transition.d.ts +7 -1
  81. package/dist/hooks/use-close-transition.js +5 -2
  82. package/dist/hooks/use-close-transition.js.map +1 -1
  83. package/dist/hooks/use-copy-to-clipboard.js +1 -1
  84. package/dist/hooks/use-copy-to-clipboard.js.map +1 -1
  85. package/dist/i18n/defaults.d.ts +4 -0
  86. package/dist/i18n/defaults.js +9 -1
  87. package/dist/i18n/defaults.js.map +1 -1
  88. package/dist/i18n/kit-labels.d.ts +8 -0
  89. package/dist/i18n/kit-labels.js.map +1 -1
  90. package/dist/i18n/locales/de-CH-informal.d.ts +4 -0
  91. package/dist/i18n/locales/de-CH.d.ts +4 -0
  92. package/dist/i18n/locales/de-informal.d.ts +4 -0
  93. package/dist/i18n/locales/de.d.ts +4 -0
  94. package/dist/i18n/locales/de.js +21 -1
  95. package/dist/i18n/locales/de.js.map +1 -1
  96. package/dist/i18n/locales/es.d.ts +4 -0
  97. package/dist/i18n/locales/es.js +21 -1
  98. package/dist/i18n/locales/es.js.map +1 -1
  99. package/dist/i18n/locales/fr.d.ts +4 -0
  100. package/dist/i18n/locales/fr.js +21 -1
  101. package/dist/i18n/locales/fr.js.map +1 -1
  102. package/dist/i18n/locales/hu.d.ts +4 -0
  103. package/dist/i18n/locales/hu.js +21 -1
  104. package/dist/i18n/locales/hu.js.map +1 -1
  105. package/dist/i18n/locales/it.d.ts +4 -0
  106. package/dist/i18n/locales/it.js +21 -1
  107. package/dist/i18n/locales/it.js.map +1 -1
  108. package/dist/i18n/locales/zh.d.ts +4 -0
  109. package/dist/i18n/locales/zh.js +21 -1
  110. package/dist/i18n/locales/zh.js.map +1 -1
  111. package/dist/index.d.ts +15 -7
  112. package/dist/index.js +12 -0
  113. package/dist/index.js.map +1 -1
  114. package/dist/lib/clipping.d.ts +9 -0
  115. package/dist/lib/clipping.js +14 -0
  116. package/dist/lib/clipping.js.map +1 -0
  117. package/dist/search/command-palette.d.ts +19 -2
  118. package/dist/search/command-palette.js +16 -5
  119. package/dist/search/command-palette.js.map +1 -1
  120. package/dist/search/global-search.d.ts +26 -1
  121. package/dist/search/global-search.js +29 -13
  122. package/dist/search/global-search.js.map +1 -1
  123. package/dist/search.d.ts +1 -1
  124. package/dist/wizard/stepper-nav.js +1 -1
  125. package/dist/wizard/stepper-nav.js.map +1 -1
  126. package/dist/wizard/types.d.ts +2 -2
  127. package/dist/wizard/types.js.map +1 -1
  128. package/dist/wizard/use-wizard.js +1 -1
  129. package/dist/wizard/use-wizard.js.map +1 -1
  130. package/dist/wizard/wizard-summary.js +3 -3
  131. package/dist/wizard/wizard-summary.js.map +1 -1
  132. package/package.json +16 -12
  133. package/src/components/alert-banner.tsx +117 -18
  134. package/src/components/breadcrumbs.tsx +168 -0
  135. package/src/components/bulk-action-bar.tsx +256 -0
  136. package/src/components/chip.tsx +128 -7
  137. package/src/components/copy-button.tsx +29 -7
  138. package/src/components/date-picker.tsx +49 -1
  139. package/src/components/description-list.tsx +168 -15
  140. package/src/components/dialog-frame.tsx +7 -0
  141. package/src/components/disclosure.tsx +93 -21
  142. package/src/components/file-dropzone.tsx +9 -10
  143. package/src/components/full-bleed-dialog.tsx +42 -5
  144. package/src/components/list.tsx +417 -0
  145. package/src/components/menu-item.tsx +214 -0
  146. package/src/components/modal.tsx +80 -17
  147. package/src/components/page-contents.tsx +4 -4
  148. package/src/components/page-header.tsx +68 -0
  149. package/src/components/series-chart-labels.ts +4 -0
  150. package/src/components/series-chart.tsx +253 -3
  151. package/src/components/status-dot.tsx +99 -0
  152. package/src/components/table.tsx +91 -6
  153. package/src/components/text.tsx +89 -0
  154. package/src/components/toast.tsx +441 -0
  155. package/src/components/toggle-group.tsx +82 -3
  156. package/src/components/tooltip.tsx +186 -100
  157. package/src/components/ui.tsx +237 -8
  158. package/src/hooks/use-close-transition.ts +14 -5
  159. package/src/hooks/use-copy-to-clipboard.ts +1 -1
  160. package/src/i18n/defaults.ts +8 -0
  161. package/src/i18n/kit-labels.tsx +8 -0
  162. package/src/i18n/locales/de.ts +20 -0
  163. package/src/i18n/locales/es.ts +20 -0
  164. package/src/i18n/locales/fr.ts +20 -0
  165. package/src/i18n/locales/hu.ts +20 -0
  166. package/src/i18n/locales/it.ts +20 -0
  167. package/src/i18n/locales/zh.ts +20 -0
  168. package/src/index.ts +26 -0
  169. package/src/lib/clipping.ts +16 -0
  170. package/src/search/command-palette.tsx +42 -5
  171. package/src/search/global-search.tsx +59 -18
  172. package/src/wizard/stepper-nav.tsx +2 -1
  173. package/src/wizard/types.ts +2 -2
  174. package/src/wizard/use-wizard.ts +3 -3
  175. package/src/wizard/wizard-summary.tsx +14 -10
  176. package/tokens.css +97 -0
@@ -27,15 +27,48 @@ const buttonVariantClasses = {
27
27
  // ring hugging the word instead of drawing a pill round it.
28
28
  link: "rounded-sm p-0 bg-transparent text-[var(--brand)] underline-offset-4 hover:underline focus:ring-[var(--brand)]"
29
29
  };
30
+ const BUTTON_TONES = {
31
+ muted: "text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:hover:text-[var(--text-secondary)]",
32
+ danger: "text-[var(--text-secondary)] hover:text-[var(--danger)] focus:ring-[var(--danger-border)] disabled:hover:text-[var(--text-secondary)]"
33
+ };
34
+ const TONED_VARIANTS = /* @__PURE__ */ new Set(["link", "ghost"]);
35
+ const BUTTON_LINK_PRESSED = "font-medium text-[var(--brand)] hover:text-[var(--brand)] disabled:hover:text-[var(--brand)]";
30
36
  function buttonClasses(variant = "primary", classNameOrOptions) {
31
37
  const { size = "md", className } = typeof classNameOrOptions === "object" ? classNameOrOptions : { className: classNameOrOptions };
32
38
  return cn(BUTTON_BASE, BUTTON_SIZES[size], buttonVariantClasses[variant], className);
33
39
  }
34
- function Button({ variant = "primary", size = "md", stretch, className, ...rest }) {
35
- return /* @__PURE__ */ jsx(
40
+ function hasContent(node) {
41
+ return node !== void 0 && node !== null && node !== false && node !== "";
42
+ }
43
+ function Button({
44
+ variant = "primary",
45
+ size = "md",
46
+ stretch,
47
+ tone = "default",
48
+ pressed,
49
+ disabledReason,
50
+ className,
51
+ onClick,
52
+ ...rest
53
+ }) {
54
+ const reasonId = useId();
55
+ const locked = hasContent(disabledReason);
56
+ const ownDescribedBy = rest["aria-describedby"];
57
+ const button = /* @__PURE__ */ jsx(
36
58
  "button",
37
59
  {
38
60
  ...rest,
61
+ disabled: locked ? void 0 : rest.disabled,
62
+ "aria-disabled": locked || rest["aria-disabled"],
63
+ "aria-describedby": locked ? ownDescribedBy ? `${ownDescribedBy} ${reasonId}` : reasonId : ownDescribedBy,
64
+ "aria-pressed": pressed ?? rest["aria-pressed"],
65
+ onClick: (e) => {
66
+ if (locked) {
67
+ e.preventDefault();
68
+ return;
69
+ }
70
+ onClick?.(e);
71
+ },
39
72
  className: cn(
40
73
  BUTTON_BASE,
41
74
  BUTTON_SIZES[size],
@@ -44,10 +77,25 @@ function Button({ variant = "primary", size = "md", stretch, className, ...rest
44
77
  // align-items). No effect outside a flex row / when it's already the tallest.
45
78
  stretch && "self-stretch",
46
79
  buttonVariantClasses[variant],
80
+ tone !== "default" && TONED_VARIANTS.has(variant) && BUTTON_TONES[tone],
81
+ pressed && (variant === "link" ? BUTTON_LINK_PRESSED : ICON_BUTTON_PRESSED),
82
+ // The disabled look for the focusable kind of disabled.
83
+ locked && "cursor-not-allowed opacity-50",
47
84
  className
48
85
  )
49
86
  }
50
87
  );
88
+ if (!locked) return button;
89
+ return (
90
+ // The button in a FRAGMENT so Tooltip does not clone its bubble into the
91
+ // description as well — the hidden copy below already describes it, and the same
92
+ // sentence twice would be read on every focus. `stretch` moves to the wrapper,
93
+ // which is now the flex item.
94
+ /* @__PURE__ */ jsx(Tooltip, { label: disabledReason, className: stretch ? "self-stretch" : void 0, children: /* @__PURE__ */ jsxs(Fragment, { children: [
95
+ button,
96
+ /* @__PURE__ */ jsx("span", { id: reasonId, hidden: true, children: disabledReason })
97
+ ] }) })
98
+ );
51
99
  }
52
100
  const ICON_BUTTON_BASE = "inline-flex items-center justify-center rounded-md transition-colors focus:outline-none focus:ring-2 disabled:opacity-50 disabled:cursor-not-allowed";
53
101
  const ICON_BUTTON_SIZES = {
@@ -94,12 +142,28 @@ const ICON_BUTTON_DISABLED_REST = {
94
142
  const ICON_BUTTON_QUIET_DISABLED_REST = "disabled:hover:text-[var(--text-placeholder)]";
95
143
  const ICON_BUTTON_PRESSED = "bg-[var(--brand-bg)] text-[var(--brand)] hover:bg-[var(--brand-bg-hover)] hover:text-[var(--brand)] disabled:hover:bg-[var(--brand-bg)] disabled:hover:text-[var(--brand)]";
96
144
  const ICON_BUTTON_OVERLAY = "rounded-full bg-[color-mix(in_srgb,var(--bg-inverse)_60%,transparent)] text-[var(--text-inverse)] backdrop-blur-sm hover:bg-[color-mix(in_srgb,var(--bg-inverse)_75%,transparent)] focus:ring-[var(--text-inverse)]";
97
- const IconButton = forwardRef(function IconButton2({ variant = "ghost", size = "md", tone = "default", quiet, pressed, stopPropagation, className, onClick, onKeyDown, ...rest }, ref) {
98
- return /* @__PURE__ */ jsx(
145
+ const IconButton = forwardRef(function IconButton2({
146
+ variant = "ghost",
147
+ size = "md",
148
+ tone = "default",
149
+ quiet,
150
+ pressed,
151
+ stopPropagation,
152
+ label,
153
+ tooltip = true,
154
+ tooltipSide,
155
+ tooltipPortal,
156
+ className,
157
+ onClick,
158
+ onKeyDown,
159
+ ...rest
160
+ }, ref) {
161
+ const button = /* @__PURE__ */ jsx(
99
162
  "button",
100
163
  {
101
164
  ref,
102
165
  ...rest,
166
+ "aria-label": rest["aria-label"] ?? label,
103
167
  "aria-pressed": pressed ?? rest["aria-pressed"],
104
168
  onClick: (e) => {
105
169
  if (stopPropagation) e.stopPropagation();
@@ -121,6 +185,12 @@ const IconButton = forwardRef(function IconButton2({ variant = "ghost", size = "
121
185
  )
122
186
  }
123
187
  );
188
+ if (!tooltip || label === void 0 || label === "") return button;
189
+ return (
190
+ // A fragment, so Tooltip leaves the button's description alone: the bubble says
191
+ // exactly what `aria-label` already does.
192
+ /* @__PURE__ */ jsx(Tooltip, { label, side: tooltipSide, portal: tooltipPortal, children: /* @__PURE__ */ jsx(Fragment, { children: button }) })
193
+ );
124
194
  });
125
195
  IconButton.displayName = "IconButton";
126
196
  const FIELD_BASE = "block w-full rounded-md border border-[var(--border)] bg-[var(--bg-surface)] px-3 py-2 text-sm text-[var(--text-primary)] shadow-sm placeholder:text-[var(--text-placeholder)] focus:border-[var(--brand)] focus:ring-[var(--brand)] disabled:cursor-default disabled:bg-[var(--bg-surface-2)] disabled:text-[var(--text-muted)] [&[readonly]]:bg-[var(--bg-surface-2)] [&[readonly]]:text-[var(--text-muted)]";
@@ -581,8 +651,42 @@ function Spinner({ className, label, ...rest }) {
581
651
  " "
582
652
  ] }) });
583
653
  }
584
- function EmptyState({ title, hint, icon, action, headingAs, className, ...rest }) {
654
+ const EMPTY_STATE_TONE = {
655
+ danger: "text-[var(--danger)]",
656
+ success: "text-[var(--success)]"
657
+ };
658
+ function EmptyState({
659
+ title,
660
+ hint,
661
+ icon,
662
+ action,
663
+ headingAs,
664
+ variant = "box",
665
+ tone,
666
+ className,
667
+ ...rest
668
+ }) {
585
669
  const Title = headingAs ?? "div";
670
+ const toneClass = tone ? EMPTY_STATE_TONE[tone] : void 0;
671
+ const hasHint = hint != null && hint !== false && hint !== "";
672
+ if (variant === "inline") {
673
+ return /* @__PURE__ */ jsxs(
674
+ "div",
675
+ {
676
+ ...rest,
677
+ className: cn(
678
+ "flex flex-wrap items-center justify-center gap-x-2 gap-y-1 py-4 text-center text-sm text-[var(--text-muted)]",
679
+ className
680
+ ),
681
+ children: [
682
+ icon != null && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("flex text-[var(--text-placeholder)] [&_svg]:size-4", toneClass), children: icon }),
683
+ /* @__PURE__ */ jsx(Title, { className: cn("text-sm", toneClass), children: title }),
684
+ hasHint && /* @__PURE__ */ jsx("span", { className: "text-xs", children: hint }),
685
+ action != null && /* @__PURE__ */ jsx("span", { className: "flex flex-wrap items-center gap-2", children: action })
686
+ ]
687
+ }
688
+ );
689
+ }
586
690
  return /* @__PURE__ */ jsxs(
587
691
  "div",
588
692
  {
@@ -592,9 +696,9 @@ function EmptyState({ title, hint, icon, action, headingAs, className, ...rest }
592
696
  className
593
697
  ),
594
698
  children: [
595
- icon != null && /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "mb-3 text-[var(--text-placeholder)] [&_svg]:size-8", children: icon }),
596
- /* @__PURE__ */ jsx(Title, { className: "text-sm font-medium text-[var(--text-secondary)]", children: title }),
597
- hint != null && hint !== false && hint !== "" && /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs", children: hint }),
699
+ icon != null && /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: cn("mb-3 text-[var(--text-placeholder)] [&_svg]:size-8", toneClass), children: icon }),
700
+ /* @__PURE__ */ jsx(Title, { className: cn("text-sm font-medium text-[var(--text-secondary)]", toneClass), children: title }),
701
+ hasHint && /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs", children: hint }),
598
702
  action != null && /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap items-center justify-center gap-2", children: action })
599
703
  ]
600
704
  }