@charcuterie/ui 0.1.0 → 0.2.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 (106) hide show
  1. package/README.md +9 -0
  2. package/dist/Accordion/Accordion.d.ts +82 -0
  3. package/dist/Accordion/Accordion.d.ts.map +1 -0
  4. package/dist/Accordion/Accordion.js +108 -0
  5. package/dist/Accordion/Accordion.js.map +1 -0
  6. package/dist/Accordion/AccordionSection.d.ts +28 -0
  7. package/dist/Accordion/AccordionSection.d.ts.map +1 -0
  8. package/dist/Accordion/AccordionSection.js +53 -0
  9. package/dist/Accordion/AccordionSection.js.map +1 -0
  10. package/dist/Field/Field.d.ts +69 -0
  11. package/dist/Field/Field.d.ts.map +1 -0
  12. package/dist/Field/Field.js +73 -0
  13. package/dist/Field/Field.js.map +1 -0
  14. package/dist/FileDropZone/FileDropZone.d.ts +63 -0
  15. package/dist/FileDropZone/FileDropZone.d.ts.map +1 -0
  16. package/dist/FileDropZone/FileDropZone.js +122 -0
  17. package/dist/FileDropZone/FileDropZone.js.map +1 -0
  18. package/dist/LogViewer/LogViewer.d.ts +88 -0
  19. package/dist/LogViewer/LogViewer.d.ts.map +1 -0
  20. package/dist/LogViewer/LogViewer.js +104 -0
  21. package/dist/LogViewer/LogViewer.js.map +1 -0
  22. package/dist/Menu/Menu.d.ts +81 -0
  23. package/dist/Menu/Menu.d.ts.map +1 -0
  24. package/dist/Menu/Menu.js +199 -0
  25. package/dist/Menu/Menu.js.map +1 -0
  26. package/dist/Menu/MenuAction.d.ts +24 -0
  27. package/dist/Menu/MenuAction.d.ts.map +1 -0
  28. package/dist/Menu/MenuAction.js +37 -0
  29. package/dist/Menu/MenuAction.js.map +1 -0
  30. package/dist/Select/Select.d.ts +87 -0
  31. package/dist/Select/Select.d.ts.map +1 -0
  32. package/dist/Select/Select.js +51 -0
  33. package/dist/Select/Select.js.map +1 -0
  34. package/dist/SortableTableHeader/SortableTableHeader.d.ts +61 -0
  35. package/dist/SortableTableHeader/SortableTableHeader.d.ts.map +1 -0
  36. package/dist/SortableTableHeader/SortableTableHeader.js +56 -0
  37. package/dist/SortableTableHeader/SortableTableHeader.js.map +1 -0
  38. package/dist/Toast/Toast.d.ts +54 -0
  39. package/dist/Toast/Toast.d.ts.map +1 -0
  40. package/dist/Toast/Toast.js +121 -0
  41. package/dist/Toast/Toast.js.map +1 -0
  42. package/dist/Toast/ToastRegion.d.ts +57 -0
  43. package/dist/Toast/ToastRegion.d.ts.map +1 -0
  44. package/dist/Toast/ToastRegion.js +41 -0
  45. package/dist/Toast/ToastRegion.js.map +1 -0
  46. package/dist/Toast/toastLifecycle.d.ts +34 -0
  47. package/dist/Toast/toastLifecycle.d.ts.map +1 -0
  48. package/dist/Toast/toastLifecycle.js +25 -0
  49. package/dist/Toast/toastLifecycle.js.map +1 -0
  50. package/dist/Tooltip/Tooltip.d.ts +68 -0
  51. package/dist/Tooltip/Tooltip.d.ts.map +1 -0
  52. package/dist/Tooltip/Tooltip.js +104 -0
  53. package/dist/Tooltip/Tooltip.js.map +1 -0
  54. package/dist/index.d.ts +22 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +11 -0
  57. package/dist/index.js.map +1 -1
  58. package/dist/mountStory.testHelpers.d.ts +0 -11
  59. package/dist/mountStory.testHelpers.d.ts.map +1 -1
  60. package/dist/mountStory.testHelpers.js +27 -0
  61. package/dist/mountStory.testHelpers.js.map +1 -1
  62. package/package.json +3 -3
  63. package/src/Accordion/Accordion.mdx +83 -0
  64. package/src/Accordion/Accordion.stories.tsx +146 -0
  65. package/src/Accordion/Accordion.test.tsx +163 -0
  66. package/src/Accordion/Accordion.tsx +182 -0
  67. package/src/Accordion/AccordionSection.tsx +163 -0
  68. package/src/Field/Field.mdx +74 -0
  69. package/src/Field/Field.stories.tsx +144 -0
  70. package/src/Field/Field.test.tsx +142 -0
  71. package/src/Field/Field.tsx +163 -0
  72. package/src/FileDropZone/FileDropZone.mdx +78 -0
  73. package/src/FileDropZone/FileDropZone.stories.tsx +136 -0
  74. package/src/FileDropZone/FileDropZone.test.tsx +230 -0
  75. package/src/FileDropZone/FileDropZone.tsx +234 -0
  76. package/src/LogViewer/LogViewer.mdx +88 -0
  77. package/src/LogViewer/LogViewer.stories.tsx +135 -0
  78. package/src/LogViewer/LogViewer.test.tsx +173 -0
  79. package/src/LogViewer/LogViewer.tsx +195 -0
  80. package/src/Menu/Menu.mdx +103 -0
  81. package/src/Menu/Menu.stories.tsx +161 -0
  82. package/src/Menu/Menu.test.tsx +202 -0
  83. package/src/Menu/Menu.tsx +300 -0
  84. package/src/Menu/MenuAction.tsx +95 -0
  85. package/src/Select/Select.mdx +74 -0
  86. package/src/Select/Select.stories.tsx +126 -0
  87. package/src/Select/Select.test.tsx +129 -0
  88. package/src/Select/Select.tsx +200 -0
  89. package/src/SortableTableHeader/SortableTableHeader.mdx +67 -0
  90. package/src/SortableTableHeader/SortableTableHeader.stories.tsx +207 -0
  91. package/src/SortableTableHeader/SortableTableHeader.test.tsx +180 -0
  92. package/src/SortableTableHeader/SortableTableHeader.tsx +131 -0
  93. package/src/Toast/Toast.mdx +84 -0
  94. package/src/Toast/Toast.stories.tsx +192 -0
  95. package/src/Toast/Toast.test.tsx +217 -0
  96. package/src/Toast/Toast.tsx +224 -0
  97. package/src/Toast/ToastRegion.tsx +98 -0
  98. package/src/Toast/toastLifecycle.ts +45 -0
  99. package/src/Tooltip/Tooltip.mdx +69 -0
  100. package/src/Tooltip/Tooltip.stories.tsx +104 -0
  101. package/src/Tooltip/Tooltip.test.tsx +138 -0
  102. package/src/Tooltip/Tooltip.tsx +169 -0
  103. package/src/index.ts +43 -0
  104. package/src/mountStory.testHelpers.ts +30 -0
  105. package/src/sourceRules.test.ts +221 -30
  106. package/CHANGELOG.md +0 -13
package/README.md CHANGED
@@ -18,6 +18,15 @@ M3 ships the **P0 pure-presentation** set: `Spinner`, `Skeleton`, `Button`, `Ico
18
18
  is a composition that could not be expressed until
19
19
  [`Tabs` moved onto `SinglePicker`](../../docs/decisions/2026-07-30-tab-selection-is-a-single-picker.md).
20
20
 
21
+ **M6a ships the nine P1 components**: `Select`, `Field`, `Accordion`, `LogViewer`, `Menu`,
22
+ `Tooltip`, `SortableTableHeader`, `Toast` (with `ToastRegion`), and `FileDropZone`. Twenty
23
+ five components in all. Four of them changed rules this package had already written down —
24
+ a menu is [named by its trigger](../../docs/decisions/2026-07-31-a-menu-is-named-by-its-trigger.md),
25
+ an accordion panel is [a `group` rather than a landmark](../../docs/decisions/2026-07-31-an-accordion-panel-is-a-group-not-a-landmark.md),
26
+ [`Select` owns no state at all](../../docs/decisions/2026-07-31-select-is-uncontrolled-because-the-platform-owns-the-value.md),
27
+ and [not every boolean is a state kind](../../docs/decisions/2026-07-31-not-every-boolean-is-a-state-kind.md).
28
+ Full write-up: [M6a handoff](../../docs/2026-07-31-m6a-the-p1-components.md).
29
+
21
30
  ## Install and wire
22
31
 
23
32
  ```ts
@@ -0,0 +1,82 @@
1
+ import type { ReactNode } from "react";
2
+ export type AccordionHeadingLevel = 2 | 3 | 4 | 5 | 6;
3
+ export type AccordionItem = {
4
+ content: ReactNode;
5
+ isDisabled?: boolean;
6
+ key: string;
7
+ label: ReactNode;
8
+ };
9
+ export type AccordionProps = {
10
+ className?: string;
11
+ /** **Initial** only. Charcuterie owns it from then on. */
12
+ expandedKeys?: string[];
13
+ /**
14
+ * The heading level the triggers sit at. An accordion inside a
15
+ * `Card` that already has an `<h2>` needs `3`, and getting this
16
+ * wrong is a document-outline break that no gate here can see —
17
+ * it depends entirely on the page.
18
+ */
19
+ headingLevel?: AccordionHeadingLevel;
20
+ /**
21
+ * Several sections open at once. The default is **exclusive**,
22
+ * because that is what every one of the fleet's disclosure groups
23
+ * does today.
24
+ */
25
+ isMultiple?: boolean;
26
+ items: AccordionItem[];
27
+ onChange?: (expandedKeys: string[]) => void;
28
+ };
29
+ /**
30
+ * Eleven sites in the fleet, and the plan called it "nearly free
31
+ * once `Tabs` exists". It is — the exclusive mode is
32
+ * `VisibilityGroup` and nothing else — but the reason it is worth
33
+ * shipping is not the saving.
34
+ *
35
+ * ### The two-owners bug, live, in the app this milestone migrates
36
+ *
37
+ * mux-magic's `JobStepsDisclosure` is built on `<details>`, and
38
+ * `<details>` **owns `open`**. It also wants the state in a Jotai
39
+ * atom so a job can be expanded from elsewhere. Reconciling the two
40
+ * takes three separate mechanisms:
41
+ *
42
+ * ```tsx
43
+ * const detailsRef = useRef<HTMLDetailsElement>(null)
44
+ * const skipNextToggleRef = useRef(isOpen)
45
+ *
46
+ * useEffect(() => {
47
+ * if (detailsRef.current) detailsRef.current.open = isOpen
48
+ * }, [isOpen])
49
+ *
50
+ * const handleToggle = (event) => {
51
+ * if (skipNextToggleRef.current) {
52
+ * skipNextToggleRef.current = false
53
+ * return // ← swallow the toggle our own write just fired
54
+ * }
55
+ * setStepsOpen(…)
56
+ * }
57
+ * ```
58
+ *
59
+ * That is the Radix argument from `Popover` pointed at the platform:
60
+ * a ref to reach past React, an effect to push state into the DOM,
61
+ * and a guard to stop the DOM's echo coming back. Every one of the
62
+ * three exists only because two things hold one fact.
63
+ *
64
+ * So this is a `<button aria-expanded>` and a `role="region"` — the
65
+ * ARIA Authoring Practices accordion — with `VisibilityGroup`
66
+ * holding the state alone. `<details name="…">` is the platform's
67
+ * own exclusive accordion and was rejected for the same reason, plus
68
+ * one it cannot fix: **a `<summary>` cannot be disabled**, and four
69
+ * of the fleet's eleven sites have a section that is unreachable
70
+ * until a job produces it.
71
+ *
72
+ * ### Two kinds, one component, and both hooks always run
73
+ *
74
+ * `isMultiple` picks between `VisibilityGroup` and `MultiplePicker`,
75
+ * and hooks cannot be conditional — so both are created and one is
76
+ * consulted. That is two empty stores and no DOM, which is cheaper
77
+ * than the alternative: reimplementing exclusivity on top of
78
+ * `MultiplePicker` by deselecting the others, which is precisely the
79
+ * logic `VisibilityGroup` exists to own once.
80
+ */
81
+ export declare const Accordion: ({ className, expandedKeys, headingLevel, isMultiple, items, onChange, }: AccordionProps) => ReactNode;
82
+ //# sourceMappingURL=Accordion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Accordion.d.ts","sourceRoot":"","sources":["../../src/Accordion/Accordion.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAErD,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,SAAS,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,SAAS,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAA;IACpC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;CAC5C,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,eAAO,MAAM,SAAS,GAAI,yEAOvB,cAAc,KAAG,SAkFnB,CAAA"}
@@ -0,0 +1,108 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMultiplePicker, useUniqueId, useVisibilityGroup, } from "@charcuterie/logic";
3
+ import { toClassName } from "../toClassName.js";
4
+ import { AccordionSection } from "./AccordionSection.js";
5
+ /**
6
+ * Eleven sites in the fleet, and the plan called it "nearly free
7
+ * once `Tabs` exists". It is — the exclusive mode is
8
+ * `VisibilityGroup` and nothing else — but the reason it is worth
9
+ * shipping is not the saving.
10
+ *
11
+ * ### The two-owners bug, live, in the app this milestone migrates
12
+ *
13
+ * mux-magic's `JobStepsDisclosure` is built on `<details>`, and
14
+ * `<details>` **owns `open`**. It also wants the state in a Jotai
15
+ * atom so a job can be expanded from elsewhere. Reconciling the two
16
+ * takes three separate mechanisms:
17
+ *
18
+ * ```tsx
19
+ * const detailsRef = useRef<HTMLDetailsElement>(null)
20
+ * const skipNextToggleRef = useRef(isOpen)
21
+ *
22
+ * useEffect(() => {
23
+ * if (detailsRef.current) detailsRef.current.open = isOpen
24
+ * }, [isOpen])
25
+ *
26
+ * const handleToggle = (event) => {
27
+ * if (skipNextToggleRef.current) {
28
+ * skipNextToggleRef.current = false
29
+ * return // ← swallow the toggle our own write just fired
30
+ * }
31
+ * setStepsOpen(…)
32
+ * }
33
+ * ```
34
+ *
35
+ * That is the Radix argument from `Popover` pointed at the platform:
36
+ * a ref to reach past React, an effect to push state into the DOM,
37
+ * and a guard to stop the DOM's echo coming back. Every one of the
38
+ * three exists only because two things hold one fact.
39
+ *
40
+ * So this is a `<button aria-expanded>` and a `role="region"` — the
41
+ * ARIA Authoring Practices accordion — with `VisibilityGroup`
42
+ * holding the state alone. `<details name="…">` is the platform's
43
+ * own exclusive accordion and was rejected for the same reason, plus
44
+ * one it cannot fix: **a `<summary>` cannot be disabled**, and four
45
+ * of the fleet's eleven sites have a section that is unreachable
46
+ * until a job produces it.
47
+ *
48
+ * ### Two kinds, one component, and both hooks always run
49
+ *
50
+ * `isMultiple` picks between `VisibilityGroup` and `MultiplePicker`,
51
+ * and hooks cannot be conditional — so both are created and one is
52
+ * consulted. That is two empty stores and no DOM, which is cheaper
53
+ * than the alternative: reimplementing exclusivity on top of
54
+ * `MultiplePicker` by deselecting the others, which is precisely the
55
+ * logic `VisibilityGroup` exists to own once.
56
+ */
57
+ export const Accordion = ({ className, expandedKeys, headingLevel = 3, isMultiple = false, items, onChange, }) => {
58
+ const baseId = useUniqueId();
59
+ const [initialKey] = expandedKeys ?? [];
60
+ const group = useVisibilityGroup({
61
+ onChange: (visibleKey) => {
62
+ if (!isMultiple) {
63
+ onChange?.(visibleKey === null ? [] : [visibleKey]);
64
+ }
65
+ },
66
+ visibleKey: initialKey ?? null,
67
+ });
68
+ const picker = useMultiplePicker({
69
+ onChange: (selectedValues) => {
70
+ if (isMultiple) {
71
+ onChange?.([...selectedValues]);
72
+ }
73
+ },
74
+ selectedValues: expandedKeys,
75
+ });
76
+ /**
77
+ * Visible **or** pending, the same load-bearing fallback `Tabs`
78
+ * needs and for the same reason: members register from an effect,
79
+ * so on the first paint the intent still lives in the pending
80
+ * field. Reading only the settled one renders every section
81
+ * collapsed and corrects itself a frame later — a flash on a
82
+ * desktop and a visible jump on the kiosk Pi.
83
+ *
84
+ * **And only until something registers**, which `Tabs` never had
85
+ * to say because it seeds itself from the first *enabled* tab. A
86
+ * key that can never register — a disabled section's — stays
87
+ * pending forever, so an unqualified fallback renders it expanded
88
+ * permanently and `isDisabled` quietly stops meaning anything.
89
+ * Found by the story that passes a disabled key on purpose.
90
+ *
91
+ * Every member registers in one commit, so this really is "before
92
+ * the first effects ran" rather than a race between them.
93
+ */
94
+ const hasRegistered = isMultiple
95
+ ? picker.registeredValues.length > 0
96
+ : group.registeredKeys.length > 0;
97
+ const expanded = isMultiple
98
+ ? new Set([
99
+ ...picker.selectedValues,
100
+ ...(hasRegistered ? [] : picker.pendingValues),
101
+ ])
102
+ : new Set([
103
+ group.visibleKey ??
104
+ (hasRegistered ? null : group.pendingKey),
105
+ ].filter((key) => key !== null));
106
+ return (_jsx("div", { className: toClassName("flex flex-col divide-y divide-border-subtle overflow-hidden rounded-md border border-border-subtle", className), children: items.map((item, index) => (_jsx(AccordionSection, { headingLevel: headingLevel, id: `${baseId}-trigger-${index}`, isExpanded: expanded.has(item.key), item: item, onToggle: isMultiple ? picker.toggle : group.toggle, panelId: `${baseId}-panel-${index}`, register: isMultiple ? picker.register : group.register }, item.key))) }));
107
+ };
108
+ //# sourceMappingURL=Accordion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Accordion.js","sourceRoot":"","sources":["../../src/Accordion/Accordion.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAwB,CAAA;AAgCzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EACxB,SAAS,EACT,YAAY,EACZ,YAAY,GAAG,CAAC,EAChB,UAAU,GAAG,KAAK,EAClB,KAAK,EACL,QAAQ,GACO,EAAa,EAAE;IAC9B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAA;IAE5B,MAAM,CAAC,UAAU,CAAC,GAAG,YAAY,IAAI,EAAE,CAAA;IAEvC,MAAM,KAAK,GAAG,kBAAkB,CAAS;QACvC,QAAQ,EAAE,CAAC,UAAU,EAAE,EAAE;YACvB,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,QAAQ,EAAE,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;YACrD,CAAC;QACH,CAAC;QACD,UAAU,EAAE,UAAU,IAAI,IAAI;KAC/B,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,iBAAiB,CAAS;QACvC,QAAQ,EAAE,CAAC,cAAc,EAAE,EAAE;YAC3B,IAAI,UAAU,EAAE,CAAC;gBACf,QAAQ,EAAE,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;QACD,cAAc,EAAE,YAAY;KAC7B,CAAC,CAAA;IAEF;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,aAAa,GAAG,UAAU;QAC9B,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC;QACpC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAA;IAEnC,MAAM,QAAQ,GAAG,UAAU;QACzB,CAAC,CAAC,IAAI,GAAG,CAAC;YACN,GAAG,MAAM,CAAC,cAAc;YACxB,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;SAC/C,CAAC;QACJ,CAAC,CAAC,IAAI,GAAG,CACL;YACE,KAAK,CAAC,UAAU;gBACd,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;SAC5C,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAChC,CAAA;IAEL,OAAO,CACL,cACE,SAAS,EAAE,WAAW,CACpB,oGAAoG,EACpG,SAAS,CACV,YAEA,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,KAAC,gBAAgB,IACf,YAAY,EAAE,YAAY,EAC1B,EAAE,EAAE,GAAG,MAAM,YAAY,KAAK,EAAE,EAChC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAClC,IAAI,EAAE,IAAI,EAEV,QAAQ,EACN,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAE3C,OAAO,EAAE,GAAG,MAAM,UAAU,KAAK,EAAE,EACnC,QAAQ,EACN,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,IAN1C,IAAI,CAAC,GAAG,CAQb,CACH,CAAC,GACE,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,28 @@
1
+ import type { ReactNode } from "react";
2
+ import type { AccordionHeadingLevel, AccordionItem } from "./Accordion.tsx";
3
+ export type AccordionSectionProps = {
4
+ headingLevel: AccordionHeadingLevel;
5
+ id: string;
6
+ isExpanded: boolean;
7
+ item: AccordionItem;
8
+ onToggle: (key: string) => void;
9
+ panelId: string;
10
+ /**
11
+ * `VisibilityGroup.register` or `MultiplePicker.register`,
12
+ * whichever kind the accordion is running. Both have this shape,
13
+ * which is the point of the kinds being separate rather than one
14
+ * configurable one.
15
+ */
16
+ register: (key: string) => () => void;
17
+ };
18
+ /**
19
+ * Its own file for the same reason `TabTrigger` is: **registration
20
+ * is an effect**, and an effect cannot run in a loop.
21
+ *
22
+ * A disabled section stays out of the group entirely — it is not a
23
+ * member, so nothing can expand it, including a consumer passing its
24
+ * key in `expandedKeys`. That is registration-as-membership again,
25
+ * and it is the behaviour a `<summary>` cannot have at all.
26
+ */
27
+ export declare const AccordionSection: ({ headingLevel, id, isExpanded, item, onToggle, panelId, register, }: AccordionSectionProps) => ReactNode;
28
+ //# sourceMappingURL=AccordionSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccordionSection.d.ts","sourceRoot":"","sources":["../../src/Accordion/AccordionSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,OAAO,KAAK,EACV,qBAAqB,EACrB,aAAa,EACd,MAAM,iBAAiB,CAAA;AAmBxB,MAAM,MAAM,qBAAqB,GAAG;IAClC,YAAY,EAAE,qBAAqB,CAAA;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,aAAa,CAAA;IACnB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,IAAI,CAAA;CACtC,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAI,sEAQ9B,qBAAqB,KAAG,SAsG1B,CAAA"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { FOCUS_RING_CLASS } from "../intentStyles.js";
4
+ import { toClassName } from "../toClassName.js";
5
+ /**
6
+ * Written out rather than interpolated into a tag name. React
7
+ * accepts `` `h${level}` `` perfectly well; a reader and a grep do
8
+ * not, and "which heading levels does this component emit" should be
9
+ * answerable by looking.
10
+ */
11
+ const HEADING_TAG = {
12
+ 2: "h2",
13
+ 3: "h3",
14
+ 4: "h4",
15
+ 5: "h5",
16
+ 6: "h6",
17
+ };
18
+ /**
19
+ * Its own file for the same reason `TabTrigger` is: **registration
20
+ * is an effect**, and an effect cannot run in a loop.
21
+ *
22
+ * A disabled section stays out of the group entirely — it is not a
23
+ * member, so nothing can expand it, including a consumer passing its
24
+ * key in `expandedKeys`. That is registration-as-membership again,
25
+ * and it is the behaviour a `<summary>` cannot have at all.
26
+ */
27
+ export const AccordionSection = ({ headingLevel, id, isExpanded, item, onToggle, panelId, register, }) => {
28
+ const { isDisabled = false, key, label } = item;
29
+ const Heading = HEADING_TAG[headingLevel];
30
+ useEffect(() => {
31
+ if (isDisabled) {
32
+ return;
33
+ }
34
+ return register(key);
35
+ }, [isDisabled, key, register]);
36
+ return (_jsxs("div", { className: "bg-surface-raised", children: [_jsx(Heading, { className: "m-0 text-md", children: _jsxs("button", { "aria-controls": panelId, "aria-expanded": isExpanded, className: toClassName("flex w-full cursor-pointer items-center justify-between gap-3 bg-transparent px-4 py-3 text-start font-medium text-content-primary text-sm transition-colors duration-(--duration-fast) ease-standard", "hover:bg-intent-neutral-surface", isDisabled &&
37
+ "cursor-not-allowed text-content-disabled hover:bg-transparent", FOCUS_RING_CLASS), disabled: isDisabled, id: id, onClick: () => {
38
+ onToggle(key);
39
+ }, type: "button", children: [label, _jsx("svg", { "aria-hidden": "true", className: toClassName("size-4 shrink-0 text-content-secondary transition-transform duration-(--duration-fast) ease-standard", isExpanded && "rotate-180"), fill: "none", focusable: false, stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.75, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "m6 9 6 6 6-6" }) })] }) }), _jsx("div", { "aria-labelledby": id, className: "px-4 pt-1 pb-4 text-content-secondary text-sm",
40
+ // `hidden` rather than unmounting, matching `Tabs`. A panel
41
+ // that unmounts loses a scroll position, a partially typed
42
+ // form, and any subscription its content opened — and the
43
+ // fleet's log panes are exactly that.
44
+ hidden: !isExpanded, id: panelId,
45
+ // `group`, not `region`. A `group` is explicitly "a set of
46
+ // UI objects **not** intended to be included in a page
47
+ // summary", so it carries `aria-labelledby` and the
48
+ // trigger↔panel relationship without joining the landmark
49
+ // list — which is exactly the distinction the APG's caveat
50
+ // is reaching for and does not have a role for.
51
+ role: "group", children: item.content })] }));
52
+ };
53
+ //# sourceMappingURL=AccordionSection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccordionSection.js","sourceRoot":"","sources":["../../src/Accordion/AccordionSection.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAM/C;;;;;GAKG;AACH,MAAM,WAAW,GAGb;IACF,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;CACR,CAAA;AAkBD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,YAAY,EACZ,EAAE,EACF,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,QAAQ,GACc,EAAa,EAAE;IACrC,MAAM,EAAE,UAAU,GAAG,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;IAE/C,MAAM,OAAO,GAAG,WAAW,CAAC,YAAY,CAAC,CAAA;IAEzC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,EAAE,CAAC;YACf,OAAM;QACR,CAAC;QAED,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE/B,OAAO,CACL,eAAK,SAAS,EAAC,mBAAmB,aAChC,KAAC,OAAO,IAAC,SAAS,EAAC,aAAa,YAC9B,mCACiB,OAAO,mBACP,UAAU,EACzB,SAAS,EAAE,WAAW,CACpB,uMAAuM,EACvM,iCAAiC,EACjC,UAAU;wBACR,+DAA+D,EACjE,gBAAgB,CACjB,EACD,QAAQ,EAAE,UAAU,EACpB,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,GAAG,EAAE;wBACZ,QAAQ,CAAC,GAAG,CAAC,CAAA;oBACf,CAAC,EACD,IAAI,EAAC,QAAQ,aAEZ,KAAK,EAEN,6BAGc,MAAM,EAClB,SAAS,EAAE,WAAW,CACpB,sGAAsG,EACtG,UAAU,IAAI,YAAY,CAC3B,EACD,IAAI,EAAC,MAAM,EACX,SAAS,EAAE,KAAK,EAChB,MAAM,EAAC,cAAc,EACrB,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,WAAW,EAAE,IAAI,EACjB,OAAO,EAAC,WAAW,EACnB,KAAK,EAAC,4BAA4B,YAElC,eAAM,CAAC,EAAC,cAAc,GAAG,GACrB,IACC,GACD,EA0BV,iCACmB,EAAE,EACnB,SAAS,EAAC,+CAA+C;gBACzD,4DAA4D;gBAC5D,2DAA2D;gBAC3D,0DAA0D;gBAC1D,sCAAsC;gBACtC,MAAM,EAAE,CAAC,UAAU,EACnB,EAAE,EAAE,OAAO;gBACX,2DAA2D;gBAC3D,uDAAuD;gBACvD,oDAAoD;gBACpD,0DAA0D;gBAC1D,2DAA2D;gBAC3D,gDAAgD;gBAChD,IAAI,EAAC,OAAO,YAEX,IAAI,CAAC,OAAO,GACT,IACF,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,69 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ export type FieldProps = {
3
+ /**
4
+ * The control. **Cloned, not wrapped** — the same slot contract
5
+ * as `Popover`'s trigger, so a `Field` can go around an `<input>`,
6
+ * a `<textarea>`, a `Select`, or an app's own control without
7
+ * changing that control's layout.
8
+ */
9
+ children: ReactElement;
10
+ className?: string;
11
+ /**
12
+ * Standing help — units, a format, a warning about what the value
13
+ * does. Announced with the control, before any error.
14
+ */
15
+ description?: ReactNode;
16
+ /**
17
+ * Present means invalid. There is no separate `isInvalid`, because
18
+ * two sources for one fact is how a control ends up
19
+ * `aria-invalid="true"` with nothing saying why — which is what
20
+ * `RegexWithFlagsField` does in mux-magic today.
21
+ */
22
+ error?: ReactNode;
23
+ isRequired?: boolean;
24
+ label: ReactNode;
25
+ };
26
+ /**
27
+ * Sixteen files in the fleet spell a label, a control, and a hint,
28
+ * and no two spell the wiring the same way. `FieldLabel` in
29
+ * mux-magic renders a `<label>` with no `htmlFor` at all — which
30
+ * looks correct, reads correctly to a sighted user, and gives a
31
+ * screen reader an unnamed textbox.
32
+ *
33
+ * ### The ids are static, and that is why `createLinkedIds` is not here
34
+ *
35
+ * The plan expected `useLinkedIds` to do this wiring. It does not
36
+ * fit, for the same reason it did not fit `Tabs`: that kind exists
37
+ * for a **dynamic** pairing, where the registration multiset is what
38
+ * stops an `aria-describedby` naming a node React has already
39
+ * removed. A field renders its own description and its own error, so
40
+ * it knows at render which of them exist — the ids come from one
41
+ * `useUniqueId` and a conditional join, and they cannot get out of
42
+ * step at all.
43
+ *
44
+ * That leaves `createLinkedIds` with **no consumer in this package
45
+ * across twenty-five components**, which is worth saying plainly
46
+ * rather than manufacturing a use for. It is the one state kind the
47
+ * component layer has never needed.
48
+ *
49
+ * ### Order matters inside `aria-describedby`
50
+ *
51
+ * Description first, error second. A screen reader reads the list in
52
+ * order, and "millisecondsonly — required" is a different sentence
53
+ * from "required — milliseconds only". Nothing enforces this but the
54
+ * order of the array below, which is why it is not built from an
55
+ * object.
56
+ *
57
+ * ### The error is described, not announced
58
+ *
59
+ * No `role="alert"` and no live region here, deliberately. An error
60
+ * bound through `aria-describedby` is read when the control takes
61
+ * focus, which is when the user can act on it; a live region on the
62
+ * same text announces it a second time, from nowhere, while the
63
+ * caret is elsewhere. A form that fails on submit should say so
64
+ * once, at the top, with the `Alert` this library already ships —
65
+ * and then the user tabs into the field and hears the specific
66
+ * reason.
67
+ */
68
+ export declare const Field: ({ children, className, description, error, isRequired, label, }: FieldProps) => ReactNode;
69
+ //# sourceMappingURL=Field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../../src/Field/Field.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAIpD,MAAM,MAAM,UAAU,GAAG;IACvB;;;;;OAKG;IACH,QAAQ,EAAE,YAAY,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,SAAS,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,KAAK,GAAI,iEAOnB,UAAU,KAAG,SAgFf,CAAA"}
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useClonedChild, useUniqueId, } from "@charcuterie/logic";
3
+ import { toClassName } from "../toClassName.js";
4
+ /**
5
+ * Sixteen files in the fleet spell a label, a control, and a hint,
6
+ * and no two spell the wiring the same way. `FieldLabel` in
7
+ * mux-magic renders a `<label>` with no `htmlFor` at all — which
8
+ * looks correct, reads correctly to a sighted user, and gives a
9
+ * screen reader an unnamed textbox.
10
+ *
11
+ * ### The ids are static, and that is why `createLinkedIds` is not here
12
+ *
13
+ * The plan expected `useLinkedIds` to do this wiring. It does not
14
+ * fit, for the same reason it did not fit `Tabs`: that kind exists
15
+ * for a **dynamic** pairing, where the registration multiset is what
16
+ * stops an `aria-describedby` naming a node React has already
17
+ * removed. A field renders its own description and its own error, so
18
+ * it knows at render which of them exist — the ids come from one
19
+ * `useUniqueId` and a conditional join, and they cannot get out of
20
+ * step at all.
21
+ *
22
+ * That leaves `createLinkedIds` with **no consumer in this package
23
+ * across twenty-five components**, which is worth saying plainly
24
+ * rather than manufacturing a use for. It is the one state kind the
25
+ * component layer has never needed.
26
+ *
27
+ * ### Order matters inside `aria-describedby`
28
+ *
29
+ * Description first, error second. A screen reader reads the list in
30
+ * order, and "millisecondsonly — required" is a different sentence
31
+ * from "required — milliseconds only". Nothing enforces this but the
32
+ * order of the array below, which is why it is not built from an
33
+ * object.
34
+ *
35
+ * ### The error is described, not announced
36
+ *
37
+ * No `role="alert"` and no live region here, deliberately. An error
38
+ * bound through `aria-describedby` is read when the control takes
39
+ * focus, which is when the user can act on it; a live region on the
40
+ * same text announces it a second time, from nowhere, while the
41
+ * caret is elsewhere. A form that fails on submit should say so
42
+ * once, at the top, with the `Alert` this library already ships —
43
+ * and then the user tabs into the field and hears the specific
44
+ * reason.
45
+ */
46
+ export const Field = ({ children, className, description, error, isRequired = false, label, }) => {
47
+ const baseId = useUniqueId();
48
+ const controlId = `${baseId}-control`;
49
+ const descriptionId = `${baseId}-description`;
50
+ const errorId = `${baseId}-error`;
51
+ const describedBy = [
52
+ description === undefined ? null : descriptionId,
53
+ error === undefined ? null : errorId,
54
+ ]
55
+ .filter(Boolean)
56
+ .join(" ");
57
+ const clonedControl = useClonedChild(children, {
58
+ "aria-describedby": describedBy === "" ? undefined : describedBy,
59
+ // `aria-invalid` is derived from the error's presence, never
60
+ // passed. A control marked invalid with no described reason is
61
+ // a screen reader saying "invalid" and stopping.
62
+ "aria-invalid": error === undefined ? undefined : true,
63
+ // Both, and they are not redundant: `required` is the
64
+ // constraint the browser validates and `aria-required` is the
65
+ // one it announces on a control the browser does not validate
66
+ // — a `role="combobox"`, or anything composite.
67
+ "aria-required": isRequired || undefined,
68
+ id: controlId,
69
+ required: isRequired || undefined,
70
+ });
71
+ return (_jsxs("div", { className: toClassName("flex flex-col gap-1.5", className), children: [_jsxs("label", { className: "font-medium text-content-primary text-sm", htmlFor: controlId, children: [label, isRequired ? (_jsx("span", { "aria-hidden": "true", className: "ms-1 text-intent-danger-content", children: "*" })) : null] }), clonedControl, description === undefined ? null : (_jsx("p", { className: "text-content-secondary text-xs", id: descriptionId, children: description })), error === undefined ? null : (_jsx("p", { className: "text-intent-danger-content text-xs", id: errorId, children: error }))] }));
72
+ };
73
+ //# sourceMappingURL=Field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Field.js","sourceRoot":"","sources":["../../src/Field/Field.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,cAAc,EACd,WAAW,GACZ,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA2B/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EACpB,QAAQ,EACR,SAAS,EACT,WAAW,EACX,KAAK,EACL,UAAU,GAAG,KAAK,EAClB,KAAK,GACM,EAAa,EAAE;IAC1B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAA;IAE5B,MAAM,SAAS,GAAG,GAAG,MAAM,UAAU,CAAA;IAErC,MAAM,aAAa,GAAG,GAAG,MAAM,cAAc,CAAA;IAE7C,MAAM,OAAO,GAAG,GAAG,MAAM,QAAQ,CAAA;IAEjC,MAAM,WAAW,GAAG;QAClB,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa;QAChD,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;KACrC;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,EAAE;QAC7C,kBAAkB,EAChB,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;QAC9C,6DAA6D;QAC7D,+DAA+D;QAC/D,iDAAiD;QACjD,cAAc,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;QACtD,sDAAsD;QACtD,8DAA8D;QAC9D,8DAA8D;QAC9D,gDAAgD;QAChD,eAAe,EAAE,UAAU,IAAI,SAAS;QACxC,EAAE,EAAE,SAAS;QACb,QAAQ,EAAE,UAAU,IAAI,SAAS;KAClC,CAAC,CAAA;IAEF,OAAO,CACL,eACE,SAAS,EAAE,WAAW,CACpB,uBAAuB,EACvB,SAAS,CACV,aAED,iBACE,SAAS,EAAC,0CAA0C,EACpD,OAAO,EAAE,SAAS,aAEjB,KAAK,EAEL,UAAU,CAAC,CAAC,CAAC,CACZ,8BAKc,MAAM,EAClB,SAAS,EAAC,iCAAiC,kBAGtC,CACR,CAAC,CAAC,CAAC,IAAI,IACF,EAEP,aAAa,EAEb,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAClC,YACE,SAAS,EAAC,gCAAgC,EAC1C,EAAE,EAAE,aAAa,YAEhB,WAAW,GACV,CACL,EAEA,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC5B,YACE,SAAS,EAAC,oCAAoC,EAC9C,EAAE,EAAE,OAAO,YAEV,KAAK,GACJ,CACL,IACG,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,63 @@
1
+ import type { ReactNode } from "react";
2
+ export type FileDropZoneProps = {
3
+ /** An `accept` list, passed straight to the input. */
4
+ accept?: string;
5
+ className?: string;
6
+ /** Secondary line — the formats taken, a size cap. */
7
+ description?: ReactNode;
8
+ isDisabled?: boolean;
9
+ isMultiple?: boolean;
10
+ /** The control's accessible name, and its visible prompt. */
11
+ label: string;
12
+ onDropFiles: (files: File[]) => void;
13
+ /**
14
+ * Dropped text, when there is any. A browser hands over a dragged
15
+ * link as `text/plain` and no files at all, which is what
16
+ * gallery-downloader's page is built entirely around — it takes
17
+ * `dataTransfer.getData("text")` and never looks at `.files`.
18
+ */
19
+ onDropText?: (text: string) => void;
20
+ };
21
+ /**
22
+ * The one drag target in the fleet is gallery-downloader's, and it
23
+ * gets the hard part right: `dragenter`/`dragleave` fire once per
24
+ * *element* the pointer crosses, not once per zone, so a naive
25
+ * implementation flickers over every child — and that page keeps a
26
+ * `dragDepth` counter, which is the correct fix. It is reproduced
27
+ * below with credit.
28
+ *
29
+ * What it has no answer for is the part that cannot be fixed by
30
+ * counting:
31
+ *
32
+ * ### Dragging is pointer-only, so the zone is a label around an input
33
+ *
34
+ * There is **no keyboard gesture for drag-and-drop**. WCAG 2.5.7
35
+ * (AA since 2.2) requires a single-pointer alternative for any
36
+ * dragging movement, and the honest one has existed since 1995: a
37
+ * real `<input type="file">`. So this component is a `<label>`
38
+ * wrapping a visually-hidden input — the whole zone is the label's
39
+ * click target, Tab reaches the input, Space and Enter open the
40
+ * picker, and the drop handlers are an *enhancement* on top of a
41
+ * control that already works without them.
42
+ *
43
+ * That ordering is the entire design. Building the drop zone first
44
+ * and bolting on a "or browse" link is how the fleet's version ended
45
+ * up with an `alert()` as its error channel and no keyboard path at
46
+ * all.
47
+ *
48
+ * ### `dragover` must be prevented, and the reason is a footgun
49
+ *
50
+ * A browser's default for `dragover` is *reject the drop*. Not
51
+ * preventing it means `drop` never fires — nothing errors, the
52
+ * cursor shows a "no entry" sign, and the zone looks like it has a
53
+ * broken handler when it in fact has no handler running at all.
54
+ *
55
+ * ### It reports text as well as files
56
+ *
57
+ * Dragging a link gives you `text/plain` and an empty `files` list.
58
+ * A zone that only reads `.files` silently ignores the single most
59
+ * common thing a user drags into a downloader, which is why
60
+ * `onDropText` is here rather than being someone's follow-up.
61
+ */
62
+ export declare const FileDropZone: ({ accept, className, description, isDisabled, isMultiple, label, onDropFiles, onDropText, }: FileDropZoneProps) => ReactNode;
63
+ //# sourceMappingURL=FileDropZone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileDropZone.d.ts","sourceRoot":"","sources":["../../src/FileDropZone/FileDropZone.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,OAAO,CAAA;AAKjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAA;IACpC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,YAAY,GAAI,6FAS1B,iBAAiB,KAAG,SA6JtB,CAAA"}