@eifi1/ui-kit 0.22.0 → 0.23.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 (205) hide show
  1. package/README.md +42 -25
  2. package/dist/chart.d.ts +11 -8
  3. package/dist/components/amount-input.d.ts +28 -8
  4. package/dist/components/amount-input.js +3 -1
  5. package/dist/components/amount-input.js.map +1 -1
  6. package/dist/components/autocomplete.d.ts +21 -0
  7. package/dist/components/autocomplete.js +128 -103
  8. package/dist/components/autocomplete.js.map +1 -1
  9. package/dist/components/button-group.d.ts +11 -8
  10. package/dist/components/calculator.d.ts +11 -8
  11. package/dist/components/column-mapper.d.ts +182 -0
  12. package/dist/components/column-mapper.js +375 -0
  13. package/dist/components/column-mapper.js.map +1 -0
  14. package/dist/components/combobox-core.d.ts +39 -2
  15. package/dist/components/combobox-core.js +29 -6
  16. package/dist/components/combobox-core.js.map +1 -1
  17. package/dist/components/combobox.d.ts +80 -2
  18. package/dist/components/combobox.js +448 -311
  19. package/dist/components/combobox.js.map +1 -1
  20. package/dist/components/confirm-dialog.d.ts +11 -8
  21. package/dist/components/confirm-dialog.js +7 -8
  22. package/dist/components/confirm-dialog.js.map +1 -1
  23. package/dist/components/copy-button.d.ts +8 -5
  24. package/dist/components/country-select.d.ts +50 -7
  25. package/dist/components/country-select.js +65 -9
  26. package/dist/components/country-select.js.map +1 -1
  27. package/dist/components/danger-confirm.d.ts +11 -8
  28. package/dist/components/danger-confirm.js +13 -3
  29. package/dist/components/danger-confirm.js.map +1 -1
  30. package/dist/components/date-picker.d.ts +41 -0
  31. package/dist/components/date-picker.js +269 -8
  32. package/dist/components/date-picker.js.map +1 -1
  33. package/dist/components/entity-combobox.d.ts +35 -1
  34. package/dist/components/entity-combobox.js +148 -112
  35. package/dist/components/entity-combobox.js.map +1 -1
  36. package/dist/components/facing-pair.d.ts +11 -8
  37. package/dist/components/field-parts.d.ts +116 -6
  38. package/dist/components/field-parts.js +84 -0
  39. package/dist/components/field-parts.js.map +1 -1
  40. package/dist/components/field-strip.d.ts +105 -0
  41. package/dist/components/field-strip.js +46 -0
  42. package/dist/components/field-strip.js.map +1 -0
  43. package/dist/components/file-button.d.ts +11 -8
  44. package/dist/components/file-dropzone.d.ts +11 -8
  45. package/dist/components/form-actions.d.ts +10 -7
  46. package/dist/components/form-actions.js +8 -2
  47. package/dist/components/form-actions.js.map +1 -1
  48. package/dist/components/iban-input.d.ts +11 -8
  49. package/dist/components/icon-picker.d.ts +10 -1
  50. package/dist/components/icon-picker.js +12 -4
  51. package/dist/components/icon-picker.js.map +1 -1
  52. package/dist/components/language-select.d.ts +11 -8
  53. package/dist/components/money-field.d.ts +14 -8
  54. package/dist/components/money-field.js.map +1 -1
  55. package/dist/components/month-picker.js +2 -1
  56. package/dist/components/month-picker.js.map +1 -1
  57. package/dist/components/multi-entity-combobox.d.ts +26 -1
  58. package/dist/components/multi-entity-combobox.js +143 -102
  59. package/dist/components/multi-entity-combobox.js.map +1 -1
  60. package/dist/components/number-field.d.ts +11 -8
  61. package/dist/components/number-input.d.ts +11 -8
  62. package/dist/components/numpad-sheet.d.ts +11 -8
  63. package/dist/components/phone-input.d.ts +11 -8
  64. package/dist/components/reauth-dialog.d.ts +2 -2
  65. package/dist/components/reauth-dialog.js +6 -8
  66. package/dist/components/reauth-dialog.js.map +1 -1
  67. package/dist/components/series-chart.d.ts +11 -8
  68. package/dist/components/settings-fields.d.ts +11 -8
  69. package/dist/components/share-card.d.ts +10 -7
  70. package/dist/components/swatch-picker.d.ts +17 -1
  71. package/dist/components/swatch-picker.js +10 -4
  72. package/dist/components/swatch-picker.js.map +1 -1
  73. package/dist/components/text-link.d.ts +10 -7
  74. package/dist/components/tile-radio.d.ts +20 -0
  75. package/dist/components/tile-radio.js +25 -8
  76. package/dist/components/tile-radio.js.map +1 -1
  77. package/dist/components/time-input.d.ts +11 -8
  78. package/dist/components/toggle-group.js +2 -2
  79. package/dist/components/toggle-group.js.map +1 -1
  80. package/dist/components/trigger-aria.d.ts +3 -0
  81. package/dist/components/trigger-aria.js +3 -1
  82. package/dist/components/trigger-aria.js.map +1 -1
  83. package/dist/components/ui.d.ts +8 -5
  84. package/dist/components/ui.js +5 -11
  85. package/dist/components/ui.js.map +1 -1
  86. package/dist/feedback/feedback-attachment.d.ts +1 -1
  87. package/dist/feedback/feedback-attachment.js +156 -56
  88. package/dist/feedback/feedback-attachment.js.map +1 -1
  89. package/dist/feedback/feedback-dialog.d.ts +1 -1
  90. package/dist/feedback/feedback-dialog.js.map +1 -1
  91. package/dist/feedback/feedback-inbox.d.ts +3 -2
  92. package/dist/feedback/feedback-inbox.js.map +1 -1
  93. package/dist/feedback/feedback-thread.d.ts +68 -287
  94. package/dist/feedback/feedback-thread.js +8 -1
  95. package/dist/feedback/feedback-thread.js.map +1 -1
  96. package/dist/{kit-labels-R8mIAc9N.d.ts → feedback-BxeQVzwq.d.ts} +405 -22
  97. package/dist/{feedback-attachment-NhUm7Zga.d.ts → feedback-attachment-fGAzZPf0.d.ts} +112 -10
  98. package/dist/feedback.d.ts +66 -2
  99. package/dist/hooks/use-file-drop.d.ts +11 -8
  100. package/dist/i18n/defaults.d.ts +11 -8
  101. package/dist/i18n/defaults.js +3 -1
  102. package/dist/i18n/defaults.js.map +1 -1
  103. package/dist/i18n/german.d.ts +11 -8
  104. package/dist/i18n/german.js +36 -2
  105. package/dist/i18n/german.js.map +1 -1
  106. package/dist/i18n/kit-labels.d.ts +7 -4
  107. package/dist/i18n/kit-labels.js.map +1 -1
  108. package/dist/i18n/languages.d.ts +11 -8
  109. package/dist/i18n/locales/de-CH.d.ts +11 -8
  110. package/dist/i18n/locales/en.d.ts +11 -8
  111. package/dist/i18n/locales/en.js +7 -0
  112. package/dist/i18n/locales/en.js.map +1 -1
  113. package/dist/i18n/locales/es.d.ts +11 -8
  114. package/dist/i18n/locales/es.js +37 -2
  115. package/dist/i18n/locales/es.js.map +1 -1
  116. package/dist/i18n/locales/fr.d.ts +11 -8
  117. package/dist/i18n/locales/fr.js +36 -2
  118. package/dist/i18n/locales/fr.js.map +1 -1
  119. package/dist/i18n/locales/hu.d.ts +11 -8
  120. package/dist/i18n/locales/hu.js +38 -2
  121. package/dist/i18n/locales/hu.js.map +1 -1
  122. package/dist/i18n/locales/it.d.ts +11 -8
  123. package/dist/i18n/locales/it.js +37 -2
  124. package/dist/i18n/locales/it.js.map +1 -1
  125. package/dist/i18n/locales/zh.d.ts +11 -8
  126. package/dist/i18n/locales/zh.js +34 -2
  127. package/dist/i18n/locales/zh.js.map +1 -1
  128. package/dist/i18n/review.d.ts +11 -8
  129. package/dist/i18n/review.js +20 -1
  130. package/dist/i18n/review.js.map +1 -1
  131. package/dist/index.d.ts +7 -3
  132. package/dist/index.js +16 -0
  133. package/dist/index.js.map +1 -1
  134. package/dist/lib/column-mapping.d.ts +81 -0
  135. package/dist/lib/column-mapping.js +108 -0
  136. package/dist/lib/column-mapping.js.map +1 -0
  137. package/dist/lib/table-text.d.ts +109 -1
  138. package/dist/lib/table-text.js +122 -1
  139. package/dist/lib/table-text.js.map +1 -1
  140. package/dist/rhf/fields.d.ts +89 -11
  141. package/dist/rhf/fields.js +124 -0
  142. package/dist/rhf/fields.js.map +1 -1
  143. package/dist/rhf/form.d.ts +11 -8
  144. package/dist/rhf.d.ts +12 -9
  145. package/dist/rhf.js.map +1 -1
  146. package/dist/shell/app-shell.d.ts +10 -7
  147. package/dist/shell/top-bar-brand.d.ts +11 -8
  148. package/dist/shell/topbar-action-menu.d.ts +36 -3
  149. package/dist/shell/topbar-action-menu.js +74 -33
  150. package/dist/shell/topbar-action-menu.js.map +1 -1
  151. package/dist/shell.d.ts +10 -7
  152. package/dist/table-text.d.ts +1 -1
  153. package/dist/wizard/stepper-nav.d.ts +41 -10
  154. package/dist/wizard/stepper-nav.js +4 -0
  155. package/dist/wizard/stepper-nav.js.map +1 -1
  156. package/dist/wizard.d.ts +11 -8
  157. package/package.json +1 -1
  158. package/src/components/amount-input.tsx +20 -1
  159. package/src/components/autocomplete.tsx +172 -111
  160. package/src/components/column-mapper.tsx +666 -0
  161. package/src/components/combobox-core.tsx +82 -9
  162. package/src/components/combobox.tsx +614 -332
  163. package/src/components/confirm-dialog.tsx +12 -8
  164. package/src/components/country-select.tsx +135 -22
  165. package/src/components/danger-confirm.tsx +91 -12
  166. package/src/components/date-picker.tsx +423 -10
  167. package/src/components/entity-combobox.tsx +217 -126
  168. package/src/components/field-parts.tsx +224 -5
  169. package/src/components/field-strip.tsx +149 -0
  170. package/src/components/form-actions.tsx +32 -4
  171. package/src/components/icon-picker.tsx +23 -4
  172. package/src/components/money-field.tsx +3 -0
  173. package/src/components/month-picker.tsx +2 -1
  174. package/src/components/multi-entity-combobox.tsx +207 -120
  175. package/src/components/reauth-dialog.tsx +17 -18
  176. package/src/components/swatch-picker.tsx +29 -5
  177. package/src/components/tile-radio.tsx +74 -13
  178. package/src/components/toggle-group.tsx +2 -2
  179. package/src/components/trigger-aria.ts +5 -0
  180. package/src/components/ui.tsx +7 -33
  181. package/src/feedback/feedback-attachment.tsx +308 -61
  182. package/src/feedback/feedback-dialog.tsx +7 -3
  183. package/src/feedback/feedback-inbox.tsx +3 -2
  184. package/src/feedback/feedback-thread.tsx +47 -4
  185. package/src/i18n/defaults.ts +2 -0
  186. package/src/i18n/german.ts +42 -0
  187. package/src/i18n/kit-labels.tsx +4 -0
  188. package/src/i18n/locales/en.ts +27 -5
  189. package/src/i18n/locales/es.ts +41 -0
  190. package/src/i18n/locales/fr.ts +42 -0
  191. package/src/i18n/locales/hu.ts +37 -0
  192. package/src/i18n/locales/it.ts +41 -0
  193. package/src/i18n/locales/zh.ts +32 -0
  194. package/src/i18n/review.ts +19 -0
  195. package/src/index.ts +18 -0
  196. package/src/lib/column-mapping.ts +234 -0
  197. package/src/lib/table-text.ts +271 -0
  198. package/src/rhf/fields.tsx +254 -0
  199. package/src/rhf.ts +2 -1
  200. package/src/shell/topbar-action-menu.tsx +134 -38
  201. package/src/wizard/stepper-nav.tsx +35 -1
  202. package/dist/components/field-anatomy.d.ts +0 -95
  203. package/dist/components/field-anatomy.js +0 -84
  204. package/dist/components/field-anatomy.js.map +0 -1
  205. package/src/components/field-anatomy.tsx +0 -190
@@ -1,84 +0,0 @@
1
- "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { useId } from "react";
4
- import { cn } from "../lib/cn.js";
5
- import { FieldLabel } from "./ui.js";
6
- function hasContent(node) {
7
- return node !== void 0 && node !== null && node !== false && node !== "";
8
- }
9
- function isTextHint(hint) {
10
- return typeof hint === "string" && hint !== "" || typeof hint === "number";
11
- }
12
- const FIELD_CAPTION_CLASS = "mt-1 text-[11px] leading-tight text-[var(--text-muted)]";
13
- const FIELD_ERROR_CLASS = "mt-1 text-[11px] leading-tight text-[var(--danger)]";
14
- function useFieldMessages({
15
- hint,
16
- error,
17
- invalid,
18
- describedBy,
19
- ariaInvalid
20
- }) {
21
- const hintId = useId();
22
- const errorId = useId();
23
- const textHint = isTextHint(hint);
24
- const hasError = hasContent(error);
25
- return {
26
- isInvalid: Boolean(invalid) || hasError || ariaInvalid === true || ariaInvalid === "true",
27
- describedBy: [describedBy, textHint && hintId, hasError && errorId].filter(Boolean).join(" ") || void 0,
28
- below: textHint || hasError ? /* @__PURE__ */ jsxs(Fragment, { children: [
29
- textHint && /* @__PURE__ */ jsx("p", { id: hintId, className: FIELD_CAPTION_CLASS, children: hint }),
30
- hasError && /* @__PURE__ */ jsx("p", { id: errorId, className: FIELD_ERROR_CLASS, children: error })
31
- ] }) : null,
32
- labelHint: !textHint && hasContent(hint) ? hint : void 0
33
- };
34
- }
35
- function FieldBox({
36
- below,
37
- reserve,
38
- children
39
- }) {
40
- if (below === null && !reserve) return /* @__PURE__ */ jsx(Fragment, { children });
41
- return /* @__PURE__ */ jsxs("div", { children: [
42
- children,
43
- below
44
- ] });
45
- }
46
- function FieldLabelLine({ label, hint }) {
47
- if (!hasContent(hint)) return /* @__PURE__ */ jsx(FieldLabel, { children: label });
48
- return (
49
- // `z-10` as FieldLabel has it: the trigger after it is `relative` and would paint
50
- // over the row (and take the "?"'s hover) otherwise.
51
- /* @__PURE__ */ jsxs("div", { className: "pointer-events-none absolute start-3 end-9 top-1 z-10 flex items-center gap-1", children: [
52
- /* @__PURE__ */ jsx(FieldLabel, { className: "static min-w-0 max-w-full", children: label }),
53
- /* @__PURE__ */ jsx("span", { className: "pointer-events-auto flex shrink-0 items-center", children: hint })
54
- ] })
55
- );
56
- }
57
- const LABEL_STRIP_PAD = { toggle: "pt-4", tiles: "pt-5" };
58
- function LabelStrip({
59
- labelId,
60
- label,
61
- hint,
62
- disabled,
63
- pad,
64
- className,
65
- children
66
- }) {
67
- return /* @__PURE__ */ jsxs("div", { className: cn("relative min-w-0", LABEL_STRIP_PAD[pad], className), children: [
68
- /* @__PURE__ */ jsxs("div", { className: "pointer-events-none absolute inset-x-3 top-1 flex items-center gap-1", children: [
69
- /* @__PURE__ */ jsx(FieldLabel, { id: labelId, className: cn("static min-w-0 max-w-full", disabled && "opacity-50"), children: label }),
70
- hasContent(hint) && /* @__PURE__ */ jsx("span", { className: "pointer-events-auto flex shrink-0 items-center", children: hint })
71
- ] }),
72
- children
73
- ] });
74
- }
75
- export {
76
- FieldBox,
77
- FieldLabelLine,
78
- LABEL_STRIP_PAD,
79
- LabelStrip,
80
- hasContent,
81
- isTextHint,
82
- useFieldMessages
83
- };
84
- //# sourceMappingURL=field-anatomy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/field-anatomy.tsx"],"sourcesContent":["// Internal — not re-exported from the barrel. The pieces of a field's anatomy (its\n// label line, the caption and the error under it, the label STRIP over a bare group)\n// for the controls that are not built on `FloatingField`: the date and month pickers,\n// whose trigger is a button in a wrapper of their own, and the groups (ToggleGroup,\n// SwatchPicker, IconPicker), which have no field box at all.\n//\n// `Input` and `Select` keep their own copies in ui.tsx; these follow them class for\n// class, so a DatePicker's caption and a Select's caption are the same 11px line in\n// the same place (keksdose K4: \"uniform field anatomy … today it is a patchwork\").\n\nimport { useId } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { FieldLabel } from \"./ui\";\n\n/** `undefined`, `null`, `false` and `\"\"` are what a caller's `cond && \"…\"` evaluates to\n * when there is nothing to say; none of them is content. A numeric `0` is. */\nexport function hasContent(node: ReactNode): boolean {\n return node !== undefined && node !== null && node !== false && node !== \"\";\n}\n\n/**\n * A `hint` that is plain TEXT is a caption under the field; anything else (a\n * `FieldHint` \"?\") rides the label line — the rule `Select` set in 0.15: the label\n * line is 11px of strip shared with the label, and a sentence placed there was set on\n * top of both the label and the value.\n */\nexport function isTextHint(hint: ReactNode): boolean {\n return (typeof hint === \"string\" && hint !== \"\") || typeof hint === \"number\";\n}\n\nconst FIELD_CAPTION_CLASS = \"mt-1 text-[11px] leading-tight text-[var(--text-muted)]\";\nconst FIELD_ERROR_CLASS = \"mt-1 text-[11px] leading-tight text-[var(--danger)]\";\n\nexport interface FieldMessages {\n /** `invalid`, a message, or an `aria-invalid` from outside (a form library). */\n isInvalid: boolean;\n /** The caller's description, then the caption, then the error — the standing\n * advice before the news, as `useFieldError` in ui.tsx orders them. */\n describedBy: string | undefined;\n /** The caption and the error, for under the field; `null` when there is neither. */\n below: ReactNode;\n /** The hint for the LABEL line (a `FieldHint`), or `undefined` when the hint is a\n * caption or there is none. */\n labelHint: ReactNode;\n}\n\n/** `hint` / `error` / `invalid` resolved the way `Select` resolves them. */\nexport function useFieldMessages({\n hint,\n error,\n invalid,\n describedBy,\n ariaInvalid,\n}: {\n hint?: ReactNode;\n error?: ReactNode;\n invalid?: boolean;\n describedBy?: string;\n ariaInvalid?: unknown;\n}): FieldMessages {\n const hintId = useId();\n const errorId = useId();\n const textHint = isTextHint(hint);\n const hasError = hasContent(error);\n return {\n isInvalid: Boolean(invalid) || hasError || ariaInvalid === true || ariaInvalid === \"true\",\n describedBy:\n [describedBy, textHint && hintId, hasError && errorId].filter(Boolean).join(\" \") || undefined,\n below:\n textHint || hasError ? (\n <>\n {textHint && (\n <p id={hintId} className={FIELD_CAPTION_CLASS}>\n {hint}\n </p>\n )}\n {hasError && (\n <p id={errorId} className={FIELD_ERROR_CLASS}>\n {error}\n </p>\n )}\n </>\n ) : null,\n labelHint: !textHint && hasContent(hint) ? hint : undefined,\n };\n}\n\n/**\n * The field and what is under it, as one box — `FieldGroup` in ui.tsx, for the same\n * reasons written there. Nothing of its own while there is nothing under the field and\n * the caller passed no `error` key (the DOM is exactly what it was before these props);\n * once `error` is passed the box is kept even with no message, so the trigger is never\n * reparented — and remounted, losing focus — as the message comes and goes.\n */\nexport function FieldBox({\n below,\n reserve,\n children,\n}: {\n below: ReactNode;\n reserve: boolean;\n children: ReactNode;\n}) {\n if (below === null && !reserve) return <>{children}</>;\n return (\n <div>\n {children}\n {below}\n </div>\n );\n}\n\n/**\n * The static label in a trigger field's top strip — a {@link FieldLabel}, or, with a\n * `FieldHint`, the label and its \"?\" laid out on ONE flex row (dev#468: two absolute\n * offsets guessing at the same baseline put the \"?\" three pixels above its word).\n * `FloatingField`'s static-label row, except that it stops at `end-9`: the date and\n * month triggers keep that column (`pe-9`) for the calendar glyph or the clear ×, and a\n * long label truncates before it rather than putting the \"?\" on top of it.\n */\nexport function FieldLabelLine({ label, hint }: { label: ReactNode; hint?: ReactNode }) {\n if (!hasContent(hint)) return <FieldLabel>{label}</FieldLabel>;\n return (\n // `z-10` as FieldLabel has it: the trigger after it is `relative` and would paint\n // over the row (and take the \"?\"'s hover) otherwise.\n <div className=\"pointer-events-none absolute start-3 end-9 top-1 z-10 flex items-center gap-1\">\n <FieldLabel className=\"static min-w-0 max-w-full\">{label}</FieldLabel>\n <span className=\"pointer-events-auto flex shrink-0 items-center\">{hint}</span>\n </div>\n );\n}\n\n/**\n * How tall the strip over a bare group is.\n *\n * - `\"toggle\"` — 16px. keksdose's `ClearedStatusPicker` (live #288 rework, #431,\n * measured): *\"16px of label strip plus a 26px group is exactly a labelled Input\"*,\n * so a status group in a row of 42px fields ends where they end. The label's line\n * box runs into the group's top hairline, but the ACTIVE fill — the thing feedback\n * #117 was about — starts at 19px, below the label's 17.75px.\n * - `\"tiles\"` — 20px, keksdose's `FlagPicker` and location field (`pt-5`). A tile has\n * no inset fill: its selection IS its frame, a 2px dark border-and-ring from the\n * tile's top edge, so the tile has to start below the whole label line.\n */\nexport const LABEL_STRIP_PAD = { toggle: \"pt-4\", tiles: \"pt-5\" } as const;\n\n/**\n * The 11px label (and its `FieldHint`) over a group that is NOT a field — keksdose K2:\n * a segmented control or a row of swatches standing in a form row beside labelled\n * inputs, whose label must sit on the same line as theirs (`top-1`, `inset-x-3`, the\n * type of a field's static label) without the group growing a field's border round\n * it. `id` goes on the label so the group can be `aria-labelledby` it.\n *\n * `relative` is load-bearing twice over: the row is positioned against it, and a\n * caller's `sr-only` label cannot escape it (sr-only-containment).\n */\nexport function LabelStrip({\n labelId,\n label,\n hint,\n disabled,\n pad,\n className,\n children,\n}: {\n labelId: string;\n label: ReactNode;\n hint?: ReactNode;\n /** Dim the label with its group, as `peer-disabled:` dims a field's own. */\n disabled?: boolean;\n pad: keyof typeof LABEL_STRIP_PAD;\n className?: string;\n children: ReactNode;\n}) {\n return (\n <div className={cn(\"relative min-w-0\", LABEL_STRIP_PAD[pad], className)}>\n <div className=\"pointer-events-none absolute inset-x-3 top-1 flex items-center gap-1\">\n {/* `static`: FieldLabel positions itself absolutely; here the ROW is\n positioned, so the label and its \"?\" are centred on one line by the flex\n layout (dev#468). */}\n <FieldLabel id={labelId} className={cn(\"static min-w-0 max-w-full\", disabled && \"opacity-50\")}>\n {label}\n </FieldLabel>\n {hasContent(hint) && <span className=\"pointer-events-auto flex shrink-0 items-center\">{hint}</span>}\n </div>\n {children}\n </div>\n );\n}\n"],"mappings":";AAuEQ,mBAEI,KAFJ;AA7DR,SAAS,aAAa;AAEtB,SAAS,UAAU;AACnB,SAAS,kBAAkB;AAIpB,SAAS,WAAW,MAA0B;AACnD,SAAO,SAAS,UAAa,SAAS,QAAQ,SAAS,SAAS,SAAS;AAC3E;AAQO,SAAS,WAAW,MAA0B;AACnD,SAAQ,OAAO,SAAS,YAAY,SAAS,MAAO,OAAO,SAAS;AACtE;AAEA,MAAM,sBAAsB;AAC5B,MAAM,oBAAoB;AAgBnB,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMkB;AAChB,QAAM,SAAS,MAAM;AACrB,QAAM,UAAU,MAAM;AACtB,QAAM,WAAW,WAAW,IAAI;AAChC,QAAM,WAAW,WAAW,KAAK;AACjC,SAAO;AAAA,IACL,WAAW,QAAQ,OAAO,KAAK,YAAY,gBAAgB,QAAQ,gBAAgB;AAAA,IACnF,aACE,CAAC,aAAa,YAAY,QAAQ,YAAY,OAAO,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KAAK;AAAA,IACtF,OACE,YAAY,WACV,iCACG;AAAA,kBACC,oBAAC,OAAE,IAAI,QAAQ,WAAW,qBACvB,gBACH;AAAA,MAED,YACC,oBAAC,OAAE,IAAI,SAAS,WAAW,mBACxB,iBACH;AAAA,OAEJ,IACE;AAAA,IACN,WAAW,CAAC,YAAY,WAAW,IAAI,IAAI,OAAO;AAAA,EACpD;AACF;AASO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,UAAU,QAAQ,CAAC,QAAS,QAAO,gCAAG,UAAS;AACnD,SACE,qBAAC,SACE;AAAA;AAAA,IACA;AAAA,KACH;AAEJ;AAUO,SAAS,eAAe,EAAE,OAAO,KAAK,GAA2C;AACtF,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO,oBAAC,cAAY,iBAAM;AACjD;AAAA;AAAA;AAAA,IAGE,qBAAC,SAAI,WAAU,iFACb;AAAA,0BAAC,cAAW,WAAU,6BAA6B,iBAAM;AAAA,MACzD,oBAAC,UAAK,WAAU,kDAAkD,gBAAK;AAAA,OACzE;AAAA;AAEJ;AAcO,MAAM,kBAAkB,EAAE,QAAQ,QAAQ,OAAO,OAAO;AAYxD,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,SACE,qBAAC,SAAI,WAAW,GAAG,oBAAoB,gBAAgB,GAAG,GAAG,SAAS,GACpE;AAAA,yBAAC,SAAI,WAAU,wEAIb;AAAA,0BAAC,cAAW,IAAI,SAAS,WAAW,GAAG,6BAA6B,YAAY,YAAY,GACzF,iBACH;AAAA,MACC,WAAW,IAAI,KAAK,oBAAC,UAAK,WAAU,kDAAkD,gBAAK;AAAA,OAC9F;AAAA,IACC;AAAA,KACH;AAEJ;","names":[]}
@@ -1,190 +0,0 @@
1
- // Internal — not re-exported from the barrel. The pieces of a field's anatomy (its
2
- // label line, the caption and the error under it, the label STRIP over a bare group)
3
- // for the controls that are not built on `FloatingField`: the date and month pickers,
4
- // whose trigger is a button in a wrapper of their own, and the groups (ToggleGroup,
5
- // SwatchPicker, IconPicker), which have no field box at all.
6
- //
7
- // `Input` and `Select` keep their own copies in ui.tsx; these follow them class for
8
- // class, so a DatePicker's caption and a Select's caption are the same 11px line in
9
- // the same place (keksdose K4: "uniform field anatomy … today it is a patchwork").
10
-
11
- import { useId } from "react";
12
- import type { ReactNode } from "react";
13
- import { cn } from "../lib/cn";
14
- import { FieldLabel } from "./ui";
15
-
16
- /** `undefined`, `null`, `false` and `""` are what a caller's `cond && "…"` evaluates to
17
- * when there is nothing to say; none of them is content. A numeric `0` is. */
18
- export function hasContent(node: ReactNode): boolean {
19
- return node !== undefined && node !== null && node !== false && node !== "";
20
- }
21
-
22
- /**
23
- * A `hint` that is plain TEXT is a caption under the field; anything else (a
24
- * `FieldHint` "?") rides the label line — the rule `Select` set in 0.15: the label
25
- * line is 11px of strip shared with the label, and a sentence placed there was set on
26
- * top of both the label and the value.
27
- */
28
- export function isTextHint(hint: ReactNode): boolean {
29
- return (typeof hint === "string" && hint !== "") || typeof hint === "number";
30
- }
31
-
32
- const FIELD_CAPTION_CLASS = "mt-1 text-[11px] leading-tight text-[var(--text-muted)]";
33
- const FIELD_ERROR_CLASS = "mt-1 text-[11px] leading-tight text-[var(--danger)]";
34
-
35
- export interface FieldMessages {
36
- /** `invalid`, a message, or an `aria-invalid` from outside (a form library). */
37
- isInvalid: boolean;
38
- /** The caller's description, then the caption, then the error — the standing
39
- * advice before the news, as `useFieldError` in ui.tsx orders them. */
40
- describedBy: string | undefined;
41
- /** The caption and the error, for under the field; `null` when there is neither. */
42
- below: ReactNode;
43
- /** The hint for the LABEL line (a `FieldHint`), or `undefined` when the hint is a
44
- * caption or there is none. */
45
- labelHint: ReactNode;
46
- }
47
-
48
- /** `hint` / `error` / `invalid` resolved the way `Select` resolves them. */
49
- export function useFieldMessages({
50
- hint,
51
- error,
52
- invalid,
53
- describedBy,
54
- ariaInvalid,
55
- }: {
56
- hint?: ReactNode;
57
- error?: ReactNode;
58
- invalid?: boolean;
59
- describedBy?: string;
60
- ariaInvalid?: unknown;
61
- }): FieldMessages {
62
- const hintId = useId();
63
- const errorId = useId();
64
- const textHint = isTextHint(hint);
65
- const hasError = hasContent(error);
66
- return {
67
- isInvalid: Boolean(invalid) || hasError || ariaInvalid === true || ariaInvalid === "true",
68
- describedBy:
69
- [describedBy, textHint && hintId, hasError && errorId].filter(Boolean).join(" ") || undefined,
70
- below:
71
- textHint || hasError ? (
72
- <>
73
- {textHint && (
74
- <p id={hintId} className={FIELD_CAPTION_CLASS}>
75
- {hint}
76
- </p>
77
- )}
78
- {hasError && (
79
- <p id={errorId} className={FIELD_ERROR_CLASS}>
80
- {error}
81
- </p>
82
- )}
83
- </>
84
- ) : null,
85
- labelHint: !textHint && hasContent(hint) ? hint : undefined,
86
- };
87
- }
88
-
89
- /**
90
- * The field and what is under it, as one box — `FieldGroup` in ui.tsx, for the same
91
- * reasons written there. Nothing of its own while there is nothing under the field and
92
- * the caller passed no `error` key (the DOM is exactly what it was before these props);
93
- * once `error` is passed the box is kept even with no message, so the trigger is never
94
- * reparented — and remounted, losing focus — as the message comes and goes.
95
- */
96
- export function FieldBox({
97
- below,
98
- reserve,
99
- children,
100
- }: {
101
- below: ReactNode;
102
- reserve: boolean;
103
- children: ReactNode;
104
- }) {
105
- if (below === null && !reserve) return <>{children}</>;
106
- return (
107
- <div>
108
- {children}
109
- {below}
110
- </div>
111
- );
112
- }
113
-
114
- /**
115
- * The static label in a trigger field's top strip — a {@link FieldLabel}, or, with a
116
- * `FieldHint`, the label and its "?" laid out on ONE flex row (dev#468: two absolute
117
- * offsets guessing at the same baseline put the "?" three pixels above its word).
118
- * `FloatingField`'s static-label row, except that it stops at `end-9`: the date and
119
- * month triggers keep that column (`pe-9`) for the calendar glyph or the clear ×, and a
120
- * long label truncates before it rather than putting the "?" on top of it.
121
- */
122
- export function FieldLabelLine({ label, hint }: { label: ReactNode; hint?: ReactNode }) {
123
- if (!hasContent(hint)) return <FieldLabel>{label}</FieldLabel>;
124
- return (
125
- // `z-10` as FieldLabel has it: the trigger after it is `relative` and would paint
126
- // over the row (and take the "?"'s hover) otherwise.
127
- <div className="pointer-events-none absolute start-3 end-9 top-1 z-10 flex items-center gap-1">
128
- <FieldLabel className="static min-w-0 max-w-full">{label}</FieldLabel>
129
- <span className="pointer-events-auto flex shrink-0 items-center">{hint}</span>
130
- </div>
131
- );
132
- }
133
-
134
- /**
135
- * How tall the strip over a bare group is.
136
- *
137
- * - `"toggle"` — 16px. keksdose's `ClearedStatusPicker` (live #288 rework, #431,
138
- * measured): *"16px of label strip plus a 26px group is exactly a labelled Input"*,
139
- * so a status group in a row of 42px fields ends where they end. The label's line
140
- * box runs into the group's top hairline, but the ACTIVE fill — the thing feedback
141
- * #117 was about — starts at 19px, below the label's 17.75px.
142
- * - `"tiles"` — 20px, keksdose's `FlagPicker` and location field (`pt-5`). A tile has
143
- * no inset fill: its selection IS its frame, a 2px dark border-and-ring from the
144
- * tile's top edge, so the tile has to start below the whole label line.
145
- */
146
- export const LABEL_STRIP_PAD = { toggle: "pt-4", tiles: "pt-5" } as const;
147
-
148
- /**
149
- * The 11px label (and its `FieldHint`) over a group that is NOT a field — keksdose K2:
150
- * a segmented control or a row of swatches standing in a form row beside labelled
151
- * inputs, whose label must sit on the same line as theirs (`top-1`, `inset-x-3`, the
152
- * type of a field's static label) without the group growing a field's border round
153
- * it. `id` goes on the label so the group can be `aria-labelledby` it.
154
- *
155
- * `relative` is load-bearing twice over: the row is positioned against it, and a
156
- * caller's `sr-only` label cannot escape it (sr-only-containment).
157
- */
158
- export function LabelStrip({
159
- labelId,
160
- label,
161
- hint,
162
- disabled,
163
- pad,
164
- className,
165
- children,
166
- }: {
167
- labelId: string;
168
- label: ReactNode;
169
- hint?: ReactNode;
170
- /** Dim the label with its group, as `peer-disabled:` dims a field's own. */
171
- disabled?: boolean;
172
- pad: keyof typeof LABEL_STRIP_PAD;
173
- className?: string;
174
- children: ReactNode;
175
- }) {
176
- return (
177
- <div className={cn("relative min-w-0", LABEL_STRIP_PAD[pad], className)}>
178
- <div className="pointer-events-none absolute inset-x-3 top-1 flex items-center gap-1">
179
- {/* `static`: FieldLabel positions itself absolutely; here the ROW is
180
- positioned, so the label and its "?" are centred on one line by the flex
181
- layout (dev#468). */}
182
- <FieldLabel id={labelId} className={cn("static min-w-0 max-w-full", disabled && "opacity-50")}>
183
- {label}
184
- </FieldLabel>
185
- {hasContent(hint) && <span className="pointer-events-auto flex shrink-0 items-center">{hint}</span>}
186
- </div>
187
- {children}
188
- </div>
189
- );
190
- }