@namroodinc/liquid-editorial 0.1.7 → 0.1.8

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 (96) hide show
  1. package/AGENTS.md +2 -0
  2. package/UPGRADING.md +25 -0
  3. package/dist/chunks/Board-BLhB5_xx.cjs +2 -0
  4. package/dist/chunks/Board-BLhB5_xx.cjs.map +1 -0
  5. package/dist/chunks/Board-BTFSzn6c.js +239 -0
  6. package/dist/chunks/Board-BTFSzn6c.js.map +1 -0
  7. package/dist/chunks/EntryEditor-CcyYtH74.js +191 -0
  8. package/dist/chunks/EntryEditor-CcyYtH74.js.map +1 -0
  9. package/dist/chunks/EntryEditor-DIpc1iPF.cjs +2 -0
  10. package/dist/chunks/EntryEditor-DIpc1iPF.cjs.map +1 -0
  11. package/dist/chunks/{RichTextEditor-DC_0oN1s.cjs → RichTextEditor-BxtlbjXj.cjs} +2 -2
  12. package/dist/chunks/RichTextEditor-BxtlbjXj.cjs.map +1 -0
  13. package/dist/chunks/{RichTextEditor-CSpjsL1z.js → RichTextEditor-Dnx4i7bQ.js} +104 -93
  14. package/dist/chunks/RichTextEditor-Dnx4i7bQ.js.map +1 -0
  15. package/dist/chunks/mergeRefs-Bc3qS0Tt.cjs +2 -0
  16. package/dist/chunks/mergeRefs-Bc3qS0Tt.cjs.map +1 -0
  17. package/dist/chunks/mergeRefs-DGM402mE.js +10 -0
  18. package/dist/chunks/mergeRefs-DGM402mE.js.map +1 -0
  19. package/dist/components/Board/index.cjs +1 -2
  20. package/dist/components/Board/index.d.cts.map +1 -1
  21. package/dist/components/Board/index.d.ts.map +1 -1
  22. package/dist/components/Board/index.js +1 -231
  23. package/dist/components/Board/keyboard.d.cts +7 -0
  24. package/dist/components/Board/keyboard.d.cts.map +1 -0
  25. package/dist/components/Board/keyboard.d.ts +7 -0
  26. package/dist/components/Board/keyboard.d.ts.map +1 -0
  27. package/dist/components/Board/keyboard.test.d.cts +2 -0
  28. package/dist/components/Board/keyboard.test.d.cts.map +1 -0
  29. package/dist/components/Board/keyboard.test.d.ts +2 -0
  30. package/dist/components/Board/keyboard.test.d.ts.map +1 -0
  31. package/dist/components/Board/moves.d.cts +5 -0
  32. package/dist/components/Board/moves.d.cts.map +1 -0
  33. package/dist/components/Board/moves.d.ts +5 -0
  34. package/dist/components/Board/moves.d.ts.map +1 -0
  35. package/dist/components/Board/moves.test.d.cts +2 -0
  36. package/dist/components/Board/moves.test.d.cts.map +1 -0
  37. package/dist/components/Board/moves.test.d.ts +2 -0
  38. package/dist/components/Board/moves.test.d.ts.map +1 -0
  39. package/dist/components/DatePicker/index.cjs +1 -1
  40. package/dist/components/DatePicker/index.cjs.map +1 -1
  41. package/dist/components/DatePicker/index.d.cts.map +1 -1
  42. package/dist/components/DatePicker/index.d.ts.map +1 -1
  43. package/dist/components/DatePicker/index.js +39 -36
  44. package/dist/components/DatePicker/index.js.map +1 -1
  45. package/dist/components/Drawer/index.cjs +1 -1
  46. package/dist/components/Drawer/index.cjs.map +1 -1
  47. package/dist/components/Drawer/index.d.cts.map +1 -1
  48. package/dist/components/Drawer/index.d.ts.map +1 -1
  49. package/dist/components/Drawer/index.js +69 -62
  50. package/dist/components/Drawer/index.js.map +1 -1
  51. package/dist/components/EntryEditor/index.cjs +1 -1
  52. package/dist/components/EntryEditor/index.d.cts.map +1 -1
  53. package/dist/components/EntryEditor/index.d.ts.map +1 -1
  54. package/dist/components/EntryEditor/index.js +1 -1
  55. package/dist/components/EntryEditor/model.d.cts.map +1 -1
  56. package/dist/components/EntryEditor/model.d.ts.map +1 -1
  57. package/dist/components/Pagination/index.cjs +1 -1
  58. package/dist/components/Pagination/index.cjs.map +1 -1
  59. package/dist/components/Pagination/index.js +1 -1
  60. package/dist/components/Pagination/index.js.map +1 -1
  61. package/dist/components/Pagination/style.css +0 -1
  62. package/dist/components/RichTextEditor/index.cjs +1 -1
  63. package/dist/components/RichTextEditor/index.d.cts.map +1 -1
  64. package/dist/components/RichTextEditor/index.d.ts.map +1 -1
  65. package/dist/components/RichTextEditor/index.js +1 -1
  66. package/dist/components/Select/index.cjs +1 -1
  67. package/dist/components/Select/index.cjs.map +1 -1
  68. package/dist/components/Select/index.d.cts.map +1 -1
  69. package/dist/components/Select/index.d.ts.map +1 -1
  70. package/dist/components/Select/index.js +32 -18
  71. package/dist/components/Select/index.js.map +1 -1
  72. package/dist/components/SortableList/index.cjs +1 -1
  73. package/dist/components/SortableList/index.cjs.map +1 -1
  74. package/dist/components/SortableList/index.d.cts.map +1 -1
  75. package/dist/components/SortableList/index.d.ts.map +1 -1
  76. package/dist/components/SortableList/index.js +49 -50
  77. package/dist/components/SortableList/index.js.map +1 -1
  78. package/dist/index.cjs +1 -1
  79. package/dist/index.js +4 -4
  80. package/dist/internal/mergeRefs.d.cts +4 -0
  81. package/dist/internal/mergeRefs.d.cts.map +1 -0
  82. package/dist/internal/mergeRefs.d.ts +4 -0
  83. package/dist/internal/mergeRefs.d.ts.map +1 -0
  84. package/dist/test/dragEvent.d.cts +3 -0
  85. package/dist/test/dragEvent.d.cts.map +1 -0
  86. package/dist/test/dragEvent.d.ts +3 -0
  87. package/dist/test/dragEvent.d.ts.map +1 -0
  88. package/package.json +2 -2
  89. package/dist/chunks/EntryEditor-C32lKKnV.cjs +0 -2
  90. package/dist/chunks/EntryEditor-C32lKKnV.cjs.map +0 -1
  91. package/dist/chunks/EntryEditor-xVuiqtFo.js +0 -181
  92. package/dist/chunks/EntryEditor-xVuiqtFo.js.map +0 -1
  93. package/dist/chunks/RichTextEditor-CSpjsL1z.js.map +0 -1
  94. package/dist/chunks/RichTextEditor-DC_0oN1s.cjs.map +0 -1
  95. package/dist/components/Board/index.cjs.map +0 -1
  96. package/dist/components/Board/index.js.map +0 -1
@@ -1,181 +0,0 @@
1
- import { Field as e } from "../components/Field/index.js";
2
- import { TextArea as t, TextField as n } from "../components/TextField/index.js";
3
- import { n as r, r as i, t as a } from "./RichTextEditor-CSpjsL1z.js";
4
- import { EntryPicker as o } from "../components/EntryPicker/index.js";
5
- import { NumberField as s } from "../components/NumberField/index.js";
6
- import { Switch as c } from "../components/Switch/index.js";
7
- import { useState as l } from "react";
8
- import { jsx as u } from "react/jsx-runtime";
9
- //#region src/components/EntryEditor/model.ts
10
- var d = /* @__PURE__ */ new Set([
11
- "shortText",
12
- "longText",
13
- "richText",
14
- "number",
15
- "boolean",
16
- "dateTime",
17
- "asset",
18
- "reference"
19
- ]);
20
- function f(e) {
21
- let t = /* @__PURE__ */ new Set();
22
- for (let n of e.fields) {
23
- if (!n.id?.trim() || t.has(n.id)) throw Error("Content model field IDs must be nonempty and unique.");
24
- if (!d.has(n.type)) throw Error(`Unsupported content field type: ${n.type}`);
25
- t.add(n.id);
26
- }
27
- }
28
- function p(e) {
29
- if (typeof e != "string") return;
30
- let t = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?(?:Z|\+00:00)$/.exec(e);
31
- if (!t) return;
32
- let n = `${t[1]}:${t[2] ?? "00"}.${(t[3] ?? "").padEnd(3, "0")}Z`, r = new Date(n);
33
- if (Number.isFinite(r.getTime()) && r.toISOString() === n) return n;
34
- }
35
- function m(e, t) {
36
- return !!e && typeof e == "object" && t in e && typeof e[t] == "string" && e[t].trim().length > 0;
37
- }
38
- function h(e) {
39
- return !!e.text?.trim() || e.type === "horizontalRule" || !!e.content?.some(h);
40
- }
41
- function g(e, t) {
42
- return f(e), Object.fromEntries(e.fields.flatMap((e) => {
43
- let n = Object.hasOwn(t, e.id) ? t[e.id] : void 0, i;
44
- if (n === void 0) e.required && (i = `${e.label} is required.`);
45
- else switch (e.type) {
46
- case "shortText":
47
- case "longText":
48
- typeof n == "string" ? e.required && !n.trim() && (i = `${e.label} is required.`) : i = "Enter text.";
49
- break;
50
- case "richText":
51
- i = r(n), !i && e.required && !h(n) && (i = `${e.label} is required.`);
52
- break;
53
- case "number":
54
- (typeof n != "number" || !Number.isFinite(n)) && (i = "Enter a finite number.");
55
- break;
56
- case "boolean":
57
- typeof n != "boolean" && (i = "Choose a boolean value.");
58
- break;
59
- case "dateTime":
60
- p(n) || (i = "Enter a valid UTC date and time.");
61
- break;
62
- case "asset":
63
- case "reference": {
64
- let t = e.type === "asset" ? "assetId" : "entryId";
65
- (e.multiple ? !Array.isArray(n) || !n.every((e) => m(e, t)) : !m(n, t)) ? i = e.multiple ? `Choose a list of ${e.type === "asset" ? "assets" : "entries"}.` : `Choose an ${e.type === "asset" ? "asset" : "entry"}.` : e.required && Array.isArray(n) && n.length === 0 && (i = `${e.label} is required.`);
66
- break;
67
- }
68
- }
69
- return i ? [[e.id, i]] : [];
70
- }));
71
- }
72
- //#endregion
73
- //#region src/components/EntryEditor/index.tsx
74
- function _(e, t) {
75
- let n = e.type === "asset" ? "assetId" : "entryId";
76
- return (Array.isArray(t) ? t : t === void 0 ? [] : [t]).flatMap((e) => {
77
- if (!e || typeof e != "object" || !(n in e)) return [];
78
- let t = e[n];
79
- return typeof t == "string" ? [t] : [];
80
- });
81
- }
82
- function v({ model: r, value: d, defaultValue: f = {}, onValueChange: m, pickerItems: h = {}, errors: v = {}, isDisabled: y = !1, showAllErrors: b = !1, className: x, ...S }) {
83
- let [C, w] = l(f), [T, E] = l(() => /* @__PURE__ */ new Set()), D = d ?? C, O = g(r, D), k = (e, t) => {
84
- if (y) return;
85
- let n = { ...D };
86
- t === void 0 ? delete n[e] : n[e] = t, d === void 0 && w(n), E((t) => new Set(t).add(e)), m?.(n);
87
- };
88
- return /* @__PURE__ */ u("div", {
89
- className: ["ds-entry-editor", x].filter(Boolean).join(" "),
90
- ...S,
91
- children: r.fields.map((r) => {
92
- let l = Object.hasOwn(D, r.id) ? D[r.id] : void 0, d = r.type === "asset" || r.type === "reference", f = r.type === "dateTime" ? `${r.label} (UTC)` : r.label, m = v[r.id] ?? (b || T.has(r.id) ? O[r.id] : void 0);
93
- return /* @__PURE__ */ u(e, {
94
- label: f,
95
- hint: r.hint,
96
- error: m,
97
- isRequired: r.required,
98
- isGroup: d,
99
- children: ({ required: e, ...d }) => {
100
- switch (r.type) {
101
- case "shortText":
102
- case "longText": {
103
- let i = r.type === "shortText" ? n : t;
104
- return /* @__PURE__ */ u(i, {
105
- ...d,
106
- required: e,
107
- disabled: y,
108
- placeholder: r.placeholder,
109
- value: typeof l == "string" ? l : "",
110
- onChange: (e) => k(r.id, e.target.value)
111
- });
112
- }
113
- case "number": return /* @__PURE__ */ u(s, {
114
- ...d,
115
- required: e,
116
- isDisabled: y,
117
- placeholder: r.placeholder,
118
- step: "any",
119
- hasSteppers: !1,
120
- value: typeof l == "number" && Number.isFinite(l) ? l : "",
121
- onValueChange: (e) => {
122
- (e === "" || Number.isFinite(e)) && k(r.id, e === "" ? void 0 : e);
123
- }
124
- });
125
- case "boolean": return /* @__PURE__ */ u(c, {
126
- ...d,
127
- isDisabled: y,
128
- isSelected: l === !0,
129
- onSelectedChange: (e) => k(r.id, e)
130
- });
131
- case "dateTime": return /* @__PURE__ */ u(n, {
132
- ...d,
133
- required: e,
134
- disabled: y,
135
- type: "datetime-local",
136
- step: "0.001",
137
- value: p(l)?.slice(0, -1) ?? "",
138
- onChange: (e) => k(r.id, p(`${e.target.value}Z`))
139
- });
140
- case "richText": return /* @__PURE__ */ u(a, {
141
- ...d,
142
- label: r.label,
143
- isRequired: e,
144
- isDisabled: y,
145
- placeholder: r.placeholder,
146
- format: "json",
147
- value: l === void 0 ? i : l,
148
- onChange: (e) => k(r.id, e)
149
- });
150
- case "asset":
151
- case "reference": return /* @__PURE__ */ u("div", {
152
- ...d,
153
- role: "group",
154
- children: /* @__PURE__ */ u(o, {
155
- items: h[r.id] ?? [],
156
- value: _(r, l),
157
- label: r.type === "asset" ? "Assets" : "Entries",
158
- addLabel: `Choose ${r.label}`,
159
- mode: r.multiple ? "multiple" : "single",
160
- isDisabled: y,
161
- onValueChange: (e) => {
162
- if (r.type === "asset") {
163
- let t = e.map((e) => ({ assetId: e }));
164
- k(r.id, r.multiple ? t : t[0]);
165
- } else {
166
- let t = e.map((e) => ({ entryId: e }));
167
- k(r.id, r.multiple ? t : t[0]);
168
- }
169
- }
170
- })
171
- });
172
- }
173
- }
174
- }, r.id);
175
- })
176
- });
177
- }
178
- //#endregion
179
- export { g as n, v as t };
180
-
181
- //# sourceMappingURL=EntryEditor-xVuiqtFo.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EntryEditor-xVuiqtFo.js","names":["documentError","emptyDocument","RichTextEditor","fieldTypes","assertModel","ids","field","model","parseUtcDateTime","value","match","canonical","date","isLink","key","hasRichText","node","validateEntryValues","values","error","item","selectedIds","link","id","EntryEditor","rest","internal","setInternal","useState","defaultValue","changed","setChanged","current","validation","commit","isDisabled","next","previous","onValueChange","className","stored","isPicker","label","errors","showAllErrors","Field","accessibility","Control","TextField","TextArea","event","NumberField","Switch","required","EntryPicker","pickerItems","links"],"sources":["../../src/components/EntryEditor/model.ts","../../src/components/EntryEditor/index.tsx"],"sourcesContent":["import type { JSONContent } from \"@tiptap/react\";\nimport { documentError } from \"../RichTextEditor/document\";\nimport type { RichTextDocument } from \"../RichTextEditor\";\n\ninterface ContentFieldBase {\n id: string;\n label: string;\n hint?: string;\n placeholder?: string;\n required?: boolean;\n}\n\nexport type ContentField = ContentFieldBase & (\n | { type: \"shortText\" | \"longText\" | \"richText\" | \"number\" | \"boolean\" | \"dateTime\"; multiple?: never }\n | { type: \"asset\" | \"reference\"; multiple?: boolean }\n);\n\nexport interface ContentModel {\n fields: readonly ContentField[];\n}\n\nexport interface AssetValue { assetId: string }\nexport interface ReferenceValue { entryId: string }\nexport type EntryFieldValue = string | number | boolean | RichTextDocument | AssetValue | ReferenceValue | AssetValue[] | ReferenceValue[];\nexport type EntryValues = Record<string, EntryFieldValue | undefined>;\nexport type EntryErrors = Partial<Record<string, string>>;\n\nconst fieldTypes = new Set([\"shortText\", \"longText\", \"richText\", \"number\", \"boolean\", \"dateTime\", \"asset\", \"reference\"]);\n\nfunction assertModel(model: ContentModel) {\n const ids = new Set<string>();\n for (const field of model.fields) {\n if (!field.id?.trim() || ids.has(field.id)) throw new Error(\"Content model field IDs must be nonempty and unique.\");\n if (!fieldTypes.has(field.type)) throw new Error(`Unsupported content field type: ${field.type}`);\n ids.add(field.id);\n }\n}\n\n/** Accept UTC ISO strings without rolling invalid dates into the next month. */\nexport function parseUtcDateTime(value: unknown): string | undefined {\n if (typeof value !== \"string\") return;\n const match = /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})(?::(\\d{2})(?:\\.(\\d{1,3}))?)?(?:Z|\\+00:00)$/.exec(value);\n if (!match) return;\n const canonical = `${match[1]}:${match[2] ?? \"00\"}.${(match[3] ?? \"\").padEnd(3, \"0\")}Z`;\n const date = new Date(canonical);\n if (Number.isFinite(date.getTime()) && date.toISOString() === canonical) return canonical;\n}\n\nfunction isLink(value: unknown, key: \"assetId\" | \"entryId\"): boolean {\n return !!value && typeof value === \"object\" && key in value &&\n typeof (value as Record<string, unknown>)[key] === \"string\" &&\n ((value as Record<string, string>)[key]).trim().length > 0;\n}\n\nfunction hasRichText(node: JSONContent): boolean {\n return !!node.text?.trim() || node.type === \"horizontalRule\" || !!node.content?.some(hasRichText);\n}\n\n/** Validate data loaded from JSON as well as values emitted by EntryEditor. */\nexport function validateEntryValues(model: ContentModel, values: Record<string, unknown>): EntryErrors {\n assertModel(model);\n return Object.fromEntries(model.fields.flatMap((field): [string, string][] => {\n const value = Object.hasOwn(values, field.id) ? values[field.id] : undefined;\n let error: string | undefined;\n if (value === undefined) {\n if (field.required) error = `${field.label} is required.`;\n } else {\n switch (field.type) {\n case \"shortText\":\n case \"longText\":\n if (typeof value !== \"string\") error = \"Enter text.\";\n else if (field.required && !value.trim()) error = `${field.label} is required.`;\n break;\n case \"richText\":\n error = documentError(value);\n if (!error && field.required && !hasRichText(value as RichTextDocument)) error = `${field.label} is required.`;\n break;\n case \"number\":\n if (typeof value !== \"number\" || !Number.isFinite(value)) error = \"Enter a finite number.\";\n break;\n case \"boolean\":\n if (typeof value !== \"boolean\") error = \"Choose a boolean value.\";\n break;\n case \"dateTime\":\n if (!parseUtcDateTime(value)) error = \"Enter a valid UTC date and time.\";\n break;\n case \"asset\":\n case \"reference\": {\n const key = field.type === \"asset\" ? \"assetId\" : \"entryId\";\n if (field.multiple ? !Array.isArray(value) || !value.every((item) => isLink(item, key)) : !isLink(value, key)) {\n error = field.multiple\n ? `Choose a list of ${field.type === \"asset\" ? \"assets\" : \"entries\"}.`\n : `Choose an ${field.type === \"asset\" ? \"asset\" : \"entry\"}.`;\n } else if (field.required && Array.isArray(value) && value.length === 0) error = `${field.label} is required.`;\n break;\n }\n }\n }\n return error ? [[field.id, error]] : [];\n }));\n}\n","import { useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport { EntryPicker, type EntryItem } from \"../EntryPicker\";\nimport { Field } from \"../Field\";\nimport { NumberField } from \"../NumberField\";\nimport { RichTextEditor, type RichTextDocument } from \"../RichTextEditor\";\nimport { emptyDocument } from \"../RichTextEditor/document\";\nimport { Switch } from \"../Switch\";\nimport { TextArea, TextField } from \"../TextField\";\nimport { parseUtcDateTime, validateEntryValues, type ContentField, type ContentModel, type EntryErrors, type EntryFieldValue, type EntryValues } from \"./model\";\nimport \"./style.css\";\n\nexport { validateEntryValues } from \"./model\";\nexport type { AssetValue, ContentField, ContentModel, EntryErrors, EntryFieldValue, EntryValues, ReferenceValue } from \"./model\";\n\nexport interface EntryEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, \"defaultValue\" | \"onChange\"> {\n model: ContentModel;\n value?: EntryValues;\n defaultValue?: EntryValues;\n onValueChange?: (values: EntryValues) => void;\n /** Available assets or entries, keyed by content field ID. */\n pickerItems?: Record<string, EntryItem[]>;\n /** App-provided messages take precedence over built-in validation. */\n errors?: EntryErrors;\n isDisabled?: boolean;\n /** Reveal validation for untouched fields, for example after a submit attempt. */\n showAllErrors?: boolean;\n}\n\nfunction selectedIds(field: ContentField, value: EntryFieldValue | undefined): string[] {\n const key = field.type === \"asset\" ? \"assetId\" : \"entryId\";\n const links = Array.isArray(value) ? value : value === undefined ? [] : [value];\n return links.flatMap((link) => {\n if (!link || typeof link !== \"object\" || !(key in link)) return [];\n const id = (link as unknown as Record<string, unknown>)[key];\n return typeof id === \"string\" ? [id] : [];\n });\n}\n\n/** An ordered set of content inputs; submission and persistence belong to the app. */\nexport function EntryEditor({\n model,\n value,\n defaultValue = {},\n onValueChange,\n pickerItems = {},\n errors = {},\n isDisabled = false,\n showAllErrors = false,\n className,\n ...rest\n}: EntryEditorProps) {\n const [internal, setInternal] = useState<EntryValues>(defaultValue);\n const [changed, setChanged] = useState<Set<string>>(() => new Set());\n const current = value ?? internal;\n const validation = validateEntryValues(model, current);\n\n const commit = (id: string, next: EntryFieldValue | undefined) => {\n if (isDisabled) return;\n const values = { ...current };\n if (next === undefined) delete values[id];\n else values[id] = next;\n if (value === undefined) setInternal(values);\n setChanged((previous) => new Set(previous).add(id));\n onValueChange?.(values);\n };\n\n return (\n <div className={[\"ds-entry-editor\", className].filter(Boolean).join(\" \")} {...rest}>\n {model.fields.map((field) => {\n const stored = Object.hasOwn(current, field.id) ? current[field.id] : undefined;\n const isPicker = field.type === \"asset\" || field.type === \"reference\";\n const label = field.type === \"dateTime\" ? `${field.label} (UTC)` : field.label;\n const error = errors[field.id] ?? (showAllErrors || changed.has(field.id) ? validation[field.id] : undefined);\n return (\n <Field key={field.id} label={label} hint={field.hint} error={error} isRequired={field.required} isGroup={isPicker}>\n {({ required, ...accessibility }): ReactNode => {\n switch (field.type) {\n case \"shortText\":\n case \"longText\": {\n const Control = field.type === \"shortText\" ? TextField : TextArea;\n return <Control {...accessibility} required={required} disabled={isDisabled} placeholder={field.placeholder}\n value={typeof stored === \"string\" ? stored : \"\"} onChange={(event) => commit(field.id, event.target.value)} />;\n }\n case \"number\":\n return <NumberField {...accessibility} required={required} isDisabled={isDisabled} placeholder={field.placeholder} step=\"any\"\n hasSteppers={false} value={typeof stored === \"number\" && Number.isFinite(stored) ? stored : \"\"}\n onValueChange={(next) => { if (next === \"\" || Number.isFinite(next)) commit(field.id, next === \"\" ? undefined : next); }} />;\n case \"boolean\":\n return <Switch {...accessibility} isDisabled={isDisabled} isSelected={stored === true}\n onSelectedChange={(next) => commit(field.id, next)} />;\n case \"dateTime\":\n return <TextField {...accessibility} required={required} disabled={isDisabled} type=\"datetime-local\" step=\"0.001\"\n value={parseUtcDateTime(stored)?.slice(0, -1) ?? \"\"}\n onChange={(event) => commit(field.id, parseUtcDateTime(`${event.target.value}Z`))} />;\n case \"richText\":\n return <RichTextEditor {...accessibility} label={field.label} isRequired={required} isDisabled={isDisabled}\n placeholder={field.placeholder} format=\"json\" value={stored === undefined ? emptyDocument : stored as RichTextDocument}\n onChange={(next) => commit(field.id, next)} />;\n case \"asset\":\n case \"reference\":\n return <div {...accessibility} role=\"group\">\n <EntryPicker items={pickerItems[field.id] ?? []} value={selectedIds(field, stored)}\n label={field.type === \"asset\" ? \"Assets\" : \"Entries\"} addLabel={`Choose ${field.label}`}\n mode={field.multiple ? \"multiple\" : \"single\"} isDisabled={isDisabled}\n onValueChange={(ids) => {\n if (field.type === \"asset\") {\n const links = ids.map((assetId) => ({ assetId }));\n commit(field.id, field.multiple ? links : links[0]);\n } else {\n const links = ids.map((entryId) => ({ entryId }));\n commit(field.id, field.multiple ? links : links[0]);\n }\n }} />\n </div>;\n }\n }}\n </Field>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"RichTextEditor-CSpjsL1z.js","names":["_Fragment","Fragment$1","emptyDocument","richTextExtensions","StarterKit","Link","schema","getSchema","normalizeDocument","document","documentError","value","check","type","node","key","mark","markType","LinkDialog","href","setHref","useState","selection","error","setError","formId","useId","onTransaction","editor","onClose","canEdit","save","url","chain","Modal","Button","event","Field","TextField","field","GROUPS","RichTextEditor","forwardRef","labelledBy","describedBy","ariaInvalid","props","isFocused","setIsFocused","linkSelection","setLinkSelection","closeLink","useCallback","initialValue","content","contentError","useMemo","errorId","invalid","isInvalid","disabled","isDisabled","openLink","range","position","getMarkRange","state","link","attributes","label","id","isRequired","editorProps","anchor","view","useEditor","Placeholder","useEffect","next","createDocument","useEditorState","className","ButtonGroup","i","group","tool","toolbarExtra","size","EditorContent"],"sources":["../../src/components/RichTextEditor/document.ts","../../src/components/RichTextEditor/index.tsx"],"sourcesContent":["import { getSchema, type JSONContent } from \"@tiptap/react\";\nimport { StarterKit } from \"@tiptap/starter-kit\";\nimport { Link } from \"@tiptap/extension-link\";\n\nexport type RichTextDocument = JSONContent & { type: \"doc\" };\n\nexport const emptyDocument: RichTextDocument = { type: \"doc\", content: [{ type: \"paragraph\" }] };\n\nexport function richTextExtensions() {\n return [StarterKit.configure({ link: false }), Link.configure({ openOnClick: false, autolink: true })];\n}\n\nconst schema = getSchema(richTextExtensions());\n\n/** ProseMirror represents an empty writing surface with one empty paragraph. */\nexport function normalizeDocument(document: RichTextDocument): RichTextDocument {\n return !document.content?.length ? { ...document, content: emptyDocument.content } : document;\n}\n\nexport function documentError(value: unknown): string | undefined {\n try {\n if (!value || typeof value !== \"object\" || !(\"type\" in value) || value.type !== \"doc\") throw new Error();\n const check = (node: JSONContent) => {\n const type = schema.nodes[node.type ?? \"\"];\n if (!type || Object.keys(node).some((key) => ![\"type\", \"attrs\", \"content\", \"marks\", \"text\"].includes(key)) ||\n (node.text !== undefined && node.type !== \"text\") ||\n (node.attrs && Object.keys(node.attrs).some((key) => !Object.hasOwn(type.spec.attrs ?? {}, key)))) {\n throw new Error();\n }\n for (const mark of node.marks ?? []) {\n const markType = schema.marks[mark.type];\n if (!markType || Object.keys(mark).some((key) => ![\"type\", \"attrs\"].includes(key)) ||\n Object.keys(mark.attrs ?? {}).some((key) => !Object.hasOwn(markType.spec.attrs ?? {}, key))) {\n throw new Error();\n }\n }\n node.content?.forEach(check);\n };\n const document = value as RichTextDocument;\n check(document);\n schema.nodeFromJSON(normalizeDocument(document)).check();\n } catch {\n return \"Unsupported or invalid rich-text document.\";\n }\n}\n","import { forwardRef, useCallback, useEffect, useId, useMemo, useState, type AriaAttributes, type ReactNode } from \"react\";\nimport { createDocument, EditorContent, getMarkRange, useEditor, useEditorState, type Editor, type EditorOptions } from \"@tiptap/react\";\nimport { Placeholder } from \"@tiptap/extension-placeholder\";\nimport { Button } from \"../Button\";\nimport { ButtonGroup } from \"../ButtonGroup\";\nimport { Field } from \"../Field\";\nimport { Modal } from \"../Modal\";\nimport { TextField } from \"../TextField\";\nimport type { IconName } from \"../Icon/icons\";\nimport { documentError, emptyDocument, normalizeDocument, richTextExtensions, type RichTextDocument } from \"./document\";\nimport \"../Field/style.css\";\nimport \"./style.css\";\n\nexport type RichTextEditorSize = \"sm\" | \"md\" | \"lg\";\n\nexport type { RichTextDocument } from \"./document\";\n\ninterface RichTextEditorCommonProps {\n placeholder?: string;\n size?: RichTextEditorSize;\n isDisabled?: boolean;\n isInvalid?: boolean;\n /** Accessible name for the editing surface. */\n label?: string;\n className?: string;\n /** Extra controls appended to the toolbar, e.g. a word count. */\n toolbarExtra?: ReactNode;\n /** Applied to the editable surface. */\n id?: string;\n isRequired?: boolean;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: AriaAttributes[\"aria-invalid\"];\n}\n\nexport type RichTextEditorProps = RichTextEditorCommonProps & (\n | { format?: \"html\"; value?: string; defaultValue?: string; onChange?: (html: string) => void }\n | { format: \"json\"; value?: RichTextDocument; defaultValue?: RichTextDocument; onChange?: (document: RichTextDocument) => void }\n);\n\ninterface ToolItem {\n id: string;\n icon: IconName;\n label: string;\n run: (editor: Editor) => void;\n active?: (editor: Editor) => boolean;\n}\n\ninterface LinkSelection {\n from: number;\n to: number;\n href: string;\n isEditing: boolean;\n document: Editor[\"state\"][\"doc\"];\n}\n\nfunction LinkDialog({ editor, selection, onClose }: {\n editor: Editor;\n selection: LinkSelection;\n onClose: () => void;\n}) {\n const [href, setHref] = useState(selection.href);\n const [error, setError] = useState<string>();\n const formId = useId();\n\n useEffect(() => {\n const onTransaction = () => {\n if (!editor.state.doc.eq(selection.document)) onClose();\n };\n editor.on(\"transaction\", onTransaction);\n return () => { editor.off(\"transaction\", onTransaction); };\n }, [editor, selection, onClose]);\n\n const canEdit = () => !editor.isDestroyed && editor.isEditable && editor.state.doc.eq(selection.document);\n const save = () => {\n if (!canEdit()) { onClose(); return; }\n const url = href.trim();\n if (!url || !editor.can().setLink({ href: url })) {\n setError(url ? \"Enter a valid link URL.\" : \"Enter a link URL.\");\n return;\n }\n const chain = editor.chain().focus().setTextSelection({ from: selection.from, to: selection.to });\n if (selection.from === selection.to && !selection.isEditing) {\n chain.setLink({ href: url }).insertContent({ type: \"text\", text: url, marks: [{ type: \"link\", attrs: { href: url } }] }).run();\n } else {\n chain.setLink({ href: url }).run();\n }\n onClose();\n };\n\n return (\n <Modal isOpen title={selection.isEditing ? \"Edit link\" : \"Add link\"} size=\"dialog\" onClose={onClose}\n footer={<>\n {selection.isEditing && <Button variant=\"danger\" onClick={() => {\n if (canEdit()) editor.chain().focus().setTextSelection({ from: selection.from, to: selection.to }).unsetLink().run();\n onClose();\n }}>Remove link</Button>}\n <Button onClick={onClose}>Cancel</Button>\n <Button variant=\"primary\" type=\"submit\" form={formId}>Save</Button>\n </>}>\n <form id={formId} noValidate onSubmit={(event) => { event.preventDefault(); event.stopPropagation(); save(); }}>\n <Field label=\"URL\" isRequired error={error}>\n {(field) => <TextField {...field} value={href} inputMode=\"url\" autoComplete=\"url\"\n placeholder=\"https://example.com\" onChange={(event) => { setHref(event.target.value); setError(undefined); }} />}\n </Field>\n </form>\n </Modal>\n );\n}\n\nconst GROUPS: ToolItem[][] = [\n [\n {\n id: \"bold\",\n icon: \"bold\",\n label: \"Bold\",\n run: (e) => e.chain().focus().toggleBold().run(),\n active: (e) => e.isActive(\"bold\"),\n },\n {\n id: \"italic\",\n icon: \"italic\",\n label: \"Italic\",\n run: (e) => e.chain().focus().toggleItalic().run(),\n active: (e) => e.isActive(\"italic\"),\n },\n {\n id: \"strike\",\n icon: \"strikethrough\",\n label: \"Strikethrough\",\n run: (e) => e.chain().focus().toggleStrike().run(),\n active: (e) => e.isActive(\"strike\"),\n },\n {\n id: \"code\",\n icon: \"code\",\n label: \"Inline code\",\n run: (e) => e.chain().focus().toggleCode().run(),\n active: (e) => e.isActive(\"code\"),\n },\n ],\n [\n {\n id: \"h2\",\n icon: \"heading-2\",\n label: \"Heading\",\n run: (e) => e.chain().focus().toggleHeading({ level: 2 }).run(),\n active: (e) => e.isActive(\"heading\", { level: 2 }),\n },\n {\n id: \"h3\",\n icon: \"heading-3\",\n label: \"Subheading\",\n run: (e) => e.chain().focus().toggleHeading({ level: 3 }).run(),\n active: (e) => e.isActive(\"heading\", { level: 3 }),\n },\n {\n id: \"quote\",\n icon: \"quote\",\n label: \"Quote\",\n run: (e) => e.chain().focus().toggleBlockquote().run(),\n active: (e) => e.isActive(\"blockquote\"),\n },\n ],\n [\n {\n id: \"ul\",\n icon: \"list\",\n label: \"Bulleted list\",\n run: (e) => e.chain().focus().toggleBulletList().run(),\n active: (e) => e.isActive(\"bulletList\"),\n },\n {\n id: \"ol\",\n icon: \"list-ordered\",\n label: \"Numbered list\",\n run: (e) => e.chain().focus().toggleOrderedList().run(),\n active: (e) => e.isActive(\"orderedList\"),\n },\n ],\n [\n {\n id: \"undo\",\n icon: \"undo\",\n label: \"Undo\",\n run: (e) => e.chain().focus().undo().run(),\n },\n {\n id: \"redo\",\n icon: \"redo\",\n label: \"Redo\",\n run: (e) => e.chain().focus().redo().run(),\n },\n ],\n];\n\n/**\n * The editorial writing surface. Rich text plus links — the same field skin,\n * radius and states as `TextField`, with the toolbar inside the frame.\n */\nexport const RichTextEditor = forwardRef<HTMLDivElement, RichTextEditorProps>(\n function RichTextEditor(\n props,\n ref,\n ) {\n const {\n placeholder = \"Write something…\",\n size = \"md\",\n isDisabled = false,\n isInvalid = false,\n label = \"Rich text editor\",\n className,\n toolbarExtra,\n id,\n isRequired,\n \"aria-labelledby\": labelledBy,\n \"aria-describedby\": describedBy,\n \"aria-invalid\": ariaInvalid,\n } = props;\n const [isFocused, setIsFocused] = useState(false);\n const [linkSelection, setLinkSelection] = useState<LinkSelection | null>(null);\n const closeLink = useCallback(() => setLinkSelection(null), []);\n const [initialValue] = useState(() => props.defaultValue ?? (props.format === \"json\" ? emptyDocument : \"\"));\n const content = props.value !== undefined ? props.value : initialValue;\n const contentError = useMemo(() => props.format === \"json\" ? documentError(content) : undefined, [props.format, content]);\n const errorId = useId();\n const invalid = isInvalid || !!contentError || ariaInvalid;\n const disabled = isDisabled || !!contentError;\n if (disabled && linkSelection) setLinkSelection(null);\n const openLink = useCallback((state: Editor[\"state\"], position?: number) => {\n if (disabled) return;\n const range = position === undefined ? undefined : getMarkRange(state.doc.resolve(position), state.schema.marks.link);\n const link = range && state.doc.nodeAt(range.from)?.marks.find((mark) => mark.type === state.schema.marks.link);\n setLinkSelection({\n from: range?.from ?? state.selection.from,\n to: range?.to ?? state.selection.to,\n href: link?.attrs.href ?? \"\",\n isEditing: !!link,\n document: state.doc,\n });\n }, [disabled]);\n const attributes = useMemo(() => ({\n role: \"textbox\",\n \"aria-label\": label,\n \"aria-multiline\": \"true\",\n ...(id ? { id } : {}),\n ...(labelledBy ? { \"aria-labelledby\": labelledBy } : {}),\n ...(describedBy ? { \"aria-describedby\": describedBy } : {}),\n ...(invalid ? { \"aria-invalid\": String(invalid) } : {}),\n ...(isRequired ? { \"aria-required\": \"true\" } : {}),\n }), [label, id, labelledBy, describedBy, invalid, isRequired]);\n const editorProps = useMemo<EditorOptions[\"editorProps\"]>(() => ({\n attributes,\n handleDOMEvents: { click: (view, event) => {\n const anchor = event.target instanceof Element ? event.target.closest(\"a\") : null;\n if (!anchor || !view.dom.contains(anchor)) return false;\n event.preventDefault();\n if (view.editable) openLink(view.state, view.posAtDOM(anchor, 0));\n return true;\n } },\n }), [attributes, openLink]);\n\n const editor = useEditor({\n immediatelyRender: false,\n editable: !disabled,\n content: contentError ? emptyDocument : typeof content === \"string\" ? content : normalizeDocument(content),\n extensions: [\n ...richTextExtensions(),\n Placeholder.configure({ placeholder }),\n ],\n editorProps,\n onFocus: () => setIsFocused(true),\n onBlur: () => setIsFocused(false),\n onUpdate: ({ editor: e }) => {\n if (disabled) return;\n if (props.format === \"json\") props.onChange?.(e.getJSON() as RichTextDocument);\n else props.onChange?.(e.getHTML());\n },\n });\n\n useEffect(() => {\n if (!editor) return;\n editor.setEditable(!disabled, false);\n editor.setOptions({ editorProps });\n }, [editor, disabled, editorProps]);\n\n useEffect(() => {\n if (!editor || props.value === undefined || contentError) return;\n const next = typeof props.value === \"string\"\n ? createDocument(props.value, editor.schema)\n : editor.schema.nodeFromJSON(normalizeDocument(props.value));\n // Parent echoes should preserve the current selection and undo history.\n if (!next.eq(editor.state.doc)) {\n editor.commands.setContent(next, { emitUpdate: false });\n }\n }, [editor, props.value, contentError]);\n\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) =>\n e\n ? {\n active: Object.fromEntries(\n GROUPS.flat().map((t) => [t.id, t.active?.(e) ?? false]),\n ),\n linkActive: e.isActive(\"link\"),\n }\n : null,\n });\n\n return (\n <div\n ref={ref}\n className={[\"ds-rte\", className].filter(Boolean).join(\" \")}\n data-focused={isFocused || undefined}\n data-disabled={disabled || undefined}\n aria-invalid={invalid || undefined}\n >\n {contentError && <p id={errorId} role=\"alert\" className=\"ds-field__error\">{contentError}</p>}\n <div hidden={!!contentError}>\n <div className=\"ds-rte__toolbar\" role=\"toolbar\" aria-label={`${label} formatting`}>\n {GROUPS.map((group, i) => (\n <ButtonGroup key={i} aria-label={`Formatting ${i + 1}`}>\n {group.map((tool) => (\n <Button\n key={tool.id}\n size=\"sm\"\n isIconOnly\n iconStart={tool.icon}\n aria-label={tool.label}\n title={tool.label}\n aria-pressed={tool.active ? state?.active[tool.id] : undefined}\n variant={state?.active[tool.id] ? \"active\" : \"neutral\"}\n isDisabled={disabled || !editor}\n onClick={() => editor && tool.run(editor)}\n />\n ))}\n </ButtonGroup>\n ))}\n <ButtonGroup aria-label=\"Link\">\n <Button\n size=\"sm\"\n isIconOnly\n iconStart=\"link\"\n aria-label={state?.linkActive ? \"Edit link\" : \"Add link\"}\n title={state?.linkActive ? \"Edit link\" : \"Add link\"}\n variant={state?.linkActive ? \"active\" : \"neutral\"}\n isDisabled={disabled || !editor}\n onClick={() => editor && openLink(editor.state, editor.isActive(\"link\") ? editor.state.selection.from : undefined)}\n />\n </ButtonGroup>\n {toolbarExtra}\n </div>\n <div className=\"ds-rte__content\" data-size={size}>\n <EditorContent editor={editor} />\n </div>\n </div>\n {editor && linkSelection && !disabled && <LinkDialog editor={editor} selection={linkSelection} onClose={closeLink} />}\n </div>\n );\n },\n);\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"RichTextEditor-DC_0oN1s.cjs","names":["StarterKit","Link","getSchema","useState","useId","Modal","_Fragment","Button","Field","TextField","forwardRef","useCallback","useMemo","getMarkRange","useEditor","Placeholder","createDocument","useEditorState","ButtonGroup","EditorContent","require_components_Button_index","require_components_ButtonGroup_index","require_components_Field_index","require_components_Modal_index","require_components_TextField_index","react","react_jsx_runtime","_tiptap_react","_tiptap_extension_placeholder","_tiptap_starter_kit","_tiptap_extension_link","emptyDocument","richTextExtensions","schema","normalizeDocument","document","documentError","value","check","type","node","key","mark","markType","LinkDialog","href","setHref","selection","error","setError","formId","onTransaction","editor","onClose","canEdit","save","url","chain","event","field","GROUPS","RichTextEditor","labelledBy","describedBy","ariaInvalid","props","isFocused","setIsFocused","linkSelection","setLinkSelection","closeLink","initialValue","content","contentError","errorId","invalid","isInvalid","disabled","isDisabled","openLink","range","position","state","link","attributes","label","id","isRequired","editorProps","anchor","view","next","className","i","group","tool","toolbarExtra","size"],"sources":["../../src/components/RichTextEditor/document.ts","../../src/components/RichTextEditor/index.tsx"],"sourcesContent":["import { getSchema, type JSONContent } from \"@tiptap/react\";\nimport { StarterKit } from \"@tiptap/starter-kit\";\nimport { Link } from \"@tiptap/extension-link\";\n\nexport type RichTextDocument = JSONContent & { type: \"doc\" };\n\nexport const emptyDocument: RichTextDocument = { type: \"doc\", content: [{ type: \"paragraph\" }] };\n\nexport function richTextExtensions() {\n return [StarterKit.configure({ link: false }), Link.configure({ openOnClick: false, autolink: true })];\n}\n\nconst schema = getSchema(richTextExtensions());\n\n/** ProseMirror represents an empty writing surface with one empty paragraph. */\nexport function normalizeDocument(document: RichTextDocument): RichTextDocument {\n return !document.content?.length ? { ...document, content: emptyDocument.content } : document;\n}\n\nexport function documentError(value: unknown): string | undefined {\n try {\n if (!value || typeof value !== \"object\" || !(\"type\" in value) || value.type !== \"doc\") throw new Error();\n const check = (node: JSONContent) => {\n const type = schema.nodes[node.type ?? \"\"];\n if (!type || Object.keys(node).some((key) => ![\"type\", \"attrs\", \"content\", \"marks\", \"text\"].includes(key)) ||\n (node.text !== undefined && node.type !== \"text\") ||\n (node.attrs && Object.keys(node.attrs).some((key) => !Object.hasOwn(type.spec.attrs ?? {}, key)))) {\n throw new Error();\n }\n for (const mark of node.marks ?? []) {\n const markType = schema.marks[mark.type];\n if (!markType || Object.keys(mark).some((key) => ![\"type\", \"attrs\"].includes(key)) ||\n Object.keys(mark.attrs ?? {}).some((key) => !Object.hasOwn(markType.spec.attrs ?? {}, key))) {\n throw new Error();\n }\n }\n node.content?.forEach(check);\n };\n const document = value as RichTextDocument;\n check(document);\n schema.nodeFromJSON(normalizeDocument(document)).check();\n } catch {\n return \"Unsupported or invalid rich-text document.\";\n }\n}\n","import { forwardRef, useCallback, useEffect, useId, useMemo, useState, type AriaAttributes, type ReactNode } from \"react\";\nimport { createDocument, EditorContent, getMarkRange, useEditor, useEditorState, type Editor, type EditorOptions } from \"@tiptap/react\";\nimport { Placeholder } from \"@tiptap/extension-placeholder\";\nimport { Button } from \"../Button\";\nimport { ButtonGroup } from \"../ButtonGroup\";\nimport { Field } from \"../Field\";\nimport { Modal } from \"../Modal\";\nimport { TextField } from \"../TextField\";\nimport type { IconName } from \"../Icon/icons\";\nimport { documentError, emptyDocument, normalizeDocument, richTextExtensions, type RichTextDocument } from \"./document\";\nimport \"../Field/style.css\";\nimport \"./style.css\";\n\nexport type RichTextEditorSize = \"sm\" | \"md\" | \"lg\";\n\nexport type { RichTextDocument } from \"./document\";\n\ninterface RichTextEditorCommonProps {\n placeholder?: string;\n size?: RichTextEditorSize;\n isDisabled?: boolean;\n isInvalid?: boolean;\n /** Accessible name for the editing surface. */\n label?: string;\n className?: string;\n /** Extra controls appended to the toolbar, e.g. a word count. */\n toolbarExtra?: ReactNode;\n /** Applied to the editable surface. */\n id?: string;\n isRequired?: boolean;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: AriaAttributes[\"aria-invalid\"];\n}\n\nexport type RichTextEditorProps = RichTextEditorCommonProps & (\n | { format?: \"html\"; value?: string; defaultValue?: string; onChange?: (html: string) => void }\n | { format: \"json\"; value?: RichTextDocument; defaultValue?: RichTextDocument; onChange?: (document: RichTextDocument) => void }\n);\n\ninterface ToolItem {\n id: string;\n icon: IconName;\n label: string;\n run: (editor: Editor) => void;\n active?: (editor: Editor) => boolean;\n}\n\ninterface LinkSelection {\n from: number;\n to: number;\n href: string;\n isEditing: boolean;\n document: Editor[\"state\"][\"doc\"];\n}\n\nfunction LinkDialog({ editor, selection, onClose }: {\n editor: Editor;\n selection: LinkSelection;\n onClose: () => void;\n}) {\n const [href, setHref] = useState(selection.href);\n const [error, setError] = useState<string>();\n const formId = useId();\n\n useEffect(() => {\n const onTransaction = () => {\n if (!editor.state.doc.eq(selection.document)) onClose();\n };\n editor.on(\"transaction\", onTransaction);\n return () => { editor.off(\"transaction\", onTransaction); };\n }, [editor, selection, onClose]);\n\n const canEdit = () => !editor.isDestroyed && editor.isEditable && editor.state.doc.eq(selection.document);\n const save = () => {\n if (!canEdit()) { onClose(); return; }\n const url = href.trim();\n if (!url || !editor.can().setLink({ href: url })) {\n setError(url ? \"Enter a valid link URL.\" : \"Enter a link URL.\");\n return;\n }\n const chain = editor.chain().focus().setTextSelection({ from: selection.from, to: selection.to });\n if (selection.from === selection.to && !selection.isEditing) {\n chain.setLink({ href: url }).insertContent({ type: \"text\", text: url, marks: [{ type: \"link\", attrs: { href: url } }] }).run();\n } else {\n chain.setLink({ href: url }).run();\n }\n onClose();\n };\n\n return (\n <Modal isOpen title={selection.isEditing ? \"Edit link\" : \"Add link\"} size=\"dialog\" onClose={onClose}\n footer={<>\n {selection.isEditing && <Button variant=\"danger\" onClick={() => {\n if (canEdit()) editor.chain().focus().setTextSelection({ from: selection.from, to: selection.to }).unsetLink().run();\n onClose();\n }}>Remove link</Button>}\n <Button onClick={onClose}>Cancel</Button>\n <Button variant=\"primary\" type=\"submit\" form={formId}>Save</Button>\n </>}>\n <form id={formId} noValidate onSubmit={(event) => { event.preventDefault(); event.stopPropagation(); save(); }}>\n <Field label=\"URL\" isRequired error={error}>\n {(field) => <TextField {...field} value={href} inputMode=\"url\" autoComplete=\"url\"\n placeholder=\"https://example.com\" onChange={(event) => { setHref(event.target.value); setError(undefined); }} />}\n </Field>\n </form>\n </Modal>\n );\n}\n\nconst GROUPS: ToolItem[][] = [\n [\n {\n id: \"bold\",\n icon: \"bold\",\n label: \"Bold\",\n run: (e) => e.chain().focus().toggleBold().run(),\n active: (e) => e.isActive(\"bold\"),\n },\n {\n id: \"italic\",\n icon: \"italic\",\n label: \"Italic\",\n run: (e) => e.chain().focus().toggleItalic().run(),\n active: (e) => e.isActive(\"italic\"),\n },\n {\n id: \"strike\",\n icon: \"strikethrough\",\n label: \"Strikethrough\",\n run: (e) => e.chain().focus().toggleStrike().run(),\n active: (e) => e.isActive(\"strike\"),\n },\n {\n id: \"code\",\n icon: \"code\",\n label: \"Inline code\",\n run: (e) => e.chain().focus().toggleCode().run(),\n active: (e) => e.isActive(\"code\"),\n },\n ],\n [\n {\n id: \"h2\",\n icon: \"heading-2\",\n label: \"Heading\",\n run: (e) => e.chain().focus().toggleHeading({ level: 2 }).run(),\n active: (e) => e.isActive(\"heading\", { level: 2 }),\n },\n {\n id: \"h3\",\n icon: \"heading-3\",\n label: \"Subheading\",\n run: (e) => e.chain().focus().toggleHeading({ level: 3 }).run(),\n active: (e) => e.isActive(\"heading\", { level: 3 }),\n },\n {\n id: \"quote\",\n icon: \"quote\",\n label: \"Quote\",\n run: (e) => e.chain().focus().toggleBlockquote().run(),\n active: (e) => e.isActive(\"blockquote\"),\n },\n ],\n [\n {\n id: \"ul\",\n icon: \"list\",\n label: \"Bulleted list\",\n run: (e) => e.chain().focus().toggleBulletList().run(),\n active: (e) => e.isActive(\"bulletList\"),\n },\n {\n id: \"ol\",\n icon: \"list-ordered\",\n label: \"Numbered list\",\n run: (e) => e.chain().focus().toggleOrderedList().run(),\n active: (e) => e.isActive(\"orderedList\"),\n },\n ],\n [\n {\n id: \"undo\",\n icon: \"undo\",\n label: \"Undo\",\n run: (e) => e.chain().focus().undo().run(),\n },\n {\n id: \"redo\",\n icon: \"redo\",\n label: \"Redo\",\n run: (e) => e.chain().focus().redo().run(),\n },\n ],\n];\n\n/**\n * The editorial writing surface. Rich text plus links — the same field skin,\n * radius and states as `TextField`, with the toolbar inside the frame.\n */\nexport const RichTextEditor = forwardRef<HTMLDivElement, RichTextEditorProps>(\n function RichTextEditor(\n props,\n ref,\n ) {\n const {\n placeholder = \"Write something…\",\n size = \"md\",\n isDisabled = false,\n isInvalid = false,\n label = \"Rich text editor\",\n className,\n toolbarExtra,\n id,\n isRequired,\n \"aria-labelledby\": labelledBy,\n \"aria-describedby\": describedBy,\n \"aria-invalid\": ariaInvalid,\n } = props;\n const [isFocused, setIsFocused] = useState(false);\n const [linkSelection, setLinkSelection] = useState<LinkSelection | null>(null);\n const closeLink = useCallback(() => setLinkSelection(null), []);\n const [initialValue] = useState(() => props.defaultValue ?? (props.format === \"json\" ? emptyDocument : \"\"));\n const content = props.value !== undefined ? props.value : initialValue;\n const contentError = useMemo(() => props.format === \"json\" ? documentError(content) : undefined, [props.format, content]);\n const errorId = useId();\n const invalid = isInvalid || !!contentError || ariaInvalid;\n const disabled = isDisabled || !!contentError;\n if (disabled && linkSelection) setLinkSelection(null);\n const openLink = useCallback((state: Editor[\"state\"], position?: number) => {\n if (disabled) return;\n const range = position === undefined ? undefined : getMarkRange(state.doc.resolve(position), state.schema.marks.link);\n const link = range && state.doc.nodeAt(range.from)?.marks.find((mark) => mark.type === state.schema.marks.link);\n setLinkSelection({\n from: range?.from ?? state.selection.from,\n to: range?.to ?? state.selection.to,\n href: link?.attrs.href ?? \"\",\n isEditing: !!link,\n document: state.doc,\n });\n }, [disabled]);\n const attributes = useMemo(() => ({\n role: \"textbox\",\n \"aria-label\": label,\n \"aria-multiline\": \"true\",\n ...(id ? { id } : {}),\n ...(labelledBy ? { \"aria-labelledby\": labelledBy } : {}),\n ...(describedBy ? { \"aria-describedby\": describedBy } : {}),\n ...(invalid ? { \"aria-invalid\": String(invalid) } : {}),\n ...(isRequired ? { \"aria-required\": \"true\" } : {}),\n }), [label, id, labelledBy, describedBy, invalid, isRequired]);\n const editorProps = useMemo<EditorOptions[\"editorProps\"]>(() => ({\n attributes,\n handleDOMEvents: { click: (view, event) => {\n const anchor = event.target instanceof Element ? event.target.closest(\"a\") : null;\n if (!anchor || !view.dom.contains(anchor)) return false;\n event.preventDefault();\n if (view.editable) openLink(view.state, view.posAtDOM(anchor, 0));\n return true;\n } },\n }), [attributes, openLink]);\n\n const editor = useEditor({\n immediatelyRender: false,\n editable: !disabled,\n content: contentError ? emptyDocument : typeof content === \"string\" ? content : normalizeDocument(content),\n extensions: [\n ...richTextExtensions(),\n Placeholder.configure({ placeholder }),\n ],\n editorProps,\n onFocus: () => setIsFocused(true),\n onBlur: () => setIsFocused(false),\n onUpdate: ({ editor: e }) => {\n if (disabled) return;\n if (props.format === \"json\") props.onChange?.(e.getJSON() as RichTextDocument);\n else props.onChange?.(e.getHTML());\n },\n });\n\n useEffect(() => {\n if (!editor) return;\n editor.setEditable(!disabled, false);\n editor.setOptions({ editorProps });\n }, [editor, disabled, editorProps]);\n\n useEffect(() => {\n if (!editor || props.value === undefined || contentError) return;\n const next = typeof props.value === \"string\"\n ? createDocument(props.value, editor.schema)\n : editor.schema.nodeFromJSON(normalizeDocument(props.value));\n // Parent echoes should preserve the current selection and undo history.\n if (!next.eq(editor.state.doc)) {\n editor.commands.setContent(next, { emitUpdate: false });\n }\n }, [editor, props.value, contentError]);\n\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) =>\n e\n ? {\n active: Object.fromEntries(\n GROUPS.flat().map((t) => [t.id, t.active?.(e) ?? false]),\n ),\n linkActive: e.isActive(\"link\"),\n }\n : null,\n });\n\n return (\n <div\n ref={ref}\n className={[\"ds-rte\", className].filter(Boolean).join(\" \")}\n data-focused={isFocused || undefined}\n data-disabled={disabled || undefined}\n aria-invalid={invalid || undefined}\n >\n {contentError && <p id={errorId} role=\"alert\" className=\"ds-field__error\">{contentError}</p>}\n <div hidden={!!contentError}>\n <div className=\"ds-rte__toolbar\" role=\"toolbar\" aria-label={`${label} formatting`}>\n {GROUPS.map((group, i) => (\n <ButtonGroup key={i} aria-label={`Formatting ${i + 1}`}>\n {group.map((tool) => (\n <Button\n key={tool.id}\n size=\"sm\"\n isIconOnly\n iconStart={tool.icon}\n aria-label={tool.label}\n title={tool.label}\n aria-pressed={tool.active ? state?.active[tool.id] : undefined}\n variant={state?.active[tool.id] ? \"active\" : \"neutral\"}\n isDisabled={disabled || !editor}\n onClick={() => editor && tool.run(editor)}\n />\n ))}\n </ButtonGroup>\n ))}\n <ButtonGroup aria-label=\"Link\">\n <Button\n size=\"sm\"\n isIconOnly\n iconStart=\"link\"\n aria-label={state?.linkActive ? \"Edit link\" : \"Add link\"}\n title={state?.linkActive ? \"Edit link\" : \"Add link\"}\n variant={state?.linkActive ? \"active\" : \"neutral\"}\n isDisabled={disabled || !editor}\n onClick={() => editor && openLink(editor.state, editor.isActive(\"link\") ? editor.state.selection.from : undefined)}\n />\n </ButtonGroup>\n {toolbarExtra}\n </div>\n <div className=\"ds-rte__content\" data-size={size}>\n <EditorContent editor={editor} />\n </div>\n </div>\n {editor && linkSelection && !disabled && <LinkDialog editor={editor} selection={linkSelection} onClose={closeLink} />}\n </div>\n );\n },\n);\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":["sortableKeyboardCoordinates","closestCorners","pointerWithin","createContext","forwardRef","useId","useState","useSensors","useSensor","PointerSensor","KeyboardSensor","useCallback","useMemo","DndContext","MeasuringStrategy","SortableContext","horizontalListSortingStrategy","DragOverlay","Icon","useContext","useDroppable","useSortable","CSS","Button","verticalListSortingStrategy","require_Icon","require_components_Button_index","react","react_jsx_runtime","_dnd_kit_core","_dnd_kit_sortable","_dnd_kit_utilities","boardCoordinateGetter","args","event","containers","context","c","\"type\"","a","b","activeRect","rect","currentCoordinates","boardCollisionDetection","isColumn","type","container","scoped","within","rank","id","BoardContext","Board","rest","dndId","activeId","setActiveId","activeType","setActiveType","overColumnId","setOverColumnId","sensors","handleStart","handleOver","over","overData","columnId","\"columnId\"","reset","handleEnd","activeData","active","ids","columnIds","toIndex","onColumnMove","fromColumnId","toColumnId","\"sortable\"","\"items\"","onMove","value","board","className","renderDragOverlay","renderColumnDragOverlay","BoardColumn","setBodyRef","itemIds","setColumnRef","isDraggable","node","ref","transform","isDragging","title","attributes","listeners","count","action","BoardCard","setNodeRef","label"],"sources":["../../../src/components/Board/index.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useId,\n useMemo,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from \"react\";\nimport {\n DndContext,\n DragOverlay,\n KeyboardSensor,\n PointerSensor,\n closestCorners,\n pointerWithin,\n MeasuringStrategy,\n\n useDroppable,\n useSensor,\n useSensors,\n type CollisionDetection,\n type DragEndEvent,\n type DragOverEvent,\n type DragStartEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n horizontalListSortingStrategy,\n sortableKeyboardCoordinates,\n useSortable,\n verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport type { KeyboardCoordinateGetter } from \"@dnd-kit/core\";\nimport { Button } from \"../Button\";\nimport { Icon } from \"../Icon\";\nimport \"./style.css\";\n\nexport interface BoardMove {\n cardId: string;\n fromColumnId: string;\n toColumnId: string;\n /** Index the card lands on inside the destination column. */\n toIndex: number;\n}\n\nexport interface BoardColumnMove {\n columnId: string;\n toIndex: number;\n}\n\ninterface BoardContextValue {\n activeId: string | null;\n activeType: \"card\" | \"column\" | null;\n /** The lane the pointer is currently over, whatever it is actually over. */\n overColumnId: string | null;\n}\n\n/**\n * Arrow up/down sorts inside a lane; left/right jumps lanes, which the stock\n * sortable getter does not do.\n */\nconst boardCoordinateGetter: KeyboardCoordinateGetter = (event, args) => {\n const { currentCoordinates, context } = args;\n if (event.code === \"ArrowLeft\" || event.code === \"ArrowRight\") {\n const containers = context.droppableContainers\n .getEnabled()\n .filter((c) => c.data.current?.[\"type\"] === \"column-body\")\n .sort((a, b) => (a.rect.current?.left ?? 0) - (b.rect.current?.left ?? 0));\n const activeRect = context.active?.rect.current.translated;\n if (!activeRect) return undefined;\n const index = containers.findIndex(\n (c) => (c.rect.current?.left ?? 0) <= activeRect.left + 1 &&\n (c.rect.current?.right ?? 0) >= activeRect.left - 1,\n );\n const next = containers[index + (event.code === \"ArrowRight\" ? 1 : -1)];\n const rect = next?.rect.current;\n if (!rect) return undefined;\n event.preventDefault();\n return { x: rect.left + rect.width / 2 - activeRect.width / 2, y: currentCoordinates.y };\n }\n return sortableKeyboardCoordinates(event, args);\n};\n\n/**\n * A lane's body sits inside the lane's frame, so a raw corner-distance\n * strategy lets the body steal the hit from the lane itself — most visibly at\n * the board ends, where the last lane then never shifts aside to open the\n * drop gap. Resolve by what is being dragged: a column only ever hits other\n * columns; a card hits the card under the pointer first, then the lane body\n * under it, then whatever is nearest.\n */\nconst boardCollisionDetection: CollisionDetection = (args) => {\n const isColumn = args.active.data.current?.[\"type\"] === \"column\";\n const containers = args.droppableContainers.filter((container) => {\n const type = container.data.current?.[\"type\"];\n return isColumn ? type === \"column\" : type !== \"column\";\n });\n const scoped = { ...args, droppableContainers: containers };\n if (isColumn) return closestCorners(scoped);\n const within = pointerWithin(scoped);\n if (within.length > 0) {\n const rank = (id: (typeof within)[number][\"id\"]) =>\n containers.find((c) => c.id === id)?.data.current?.[\"type\"] === \"card\" ? 0 : 1;\n return [...within].sort((a, b) => rank(a.id) - rank(b.id));\n }\n return closestCorners(scoped);\n};\n\nconst BoardContext = createContext<BoardContextValue>({\n activeId: null,\n activeType: null,\n overColumnId: null,\n});\n\nexport interface BoardProps extends Omit<HTMLAttributes<HTMLDivElement>, \"onDragEnd\"> {\n /** Column ids in render order. Required for columns to be re-orderable. */\n columnIds?: string[];\n /** Fired once a card is dropped somewhere new. Apply it to your own state. */\n onMove?: (move: BoardMove) => void;\n /** Fired once a column is dropped in a new position. */\n onColumnMove?: (move: BoardColumnMove) => void;\n /** Rendered inside the drag overlay while a card is in the air. */\n renderDragOverlay?: (cardId: string) => ReactNode;\n /** Rendered inside the drag overlay while a column is in the air. */\n renderColumnDragOverlay?: (columnId: string) => ReactNode;\n children?: ReactNode;\n}\n\n/**\n * A column board with pointer and keyboard dragging. The board owns the drag\n * mechanics only — the card data stays yours; react to `onMove`.\n */\nexport const Board = forwardRef<HTMLDivElement, BoardProps>(function Board(\n {\n columnIds,\n onMove,\n onColumnMove,\n renderDragOverlay,\n renderColumnDragOverlay,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const dndId = useId();\n const [activeId, setActiveId] = useState<string | null>(null);\n const [activeType, setActiveType] = useState<\"card\" | \"column\" | null>(null);\n const [overColumnId, setOverColumnId] = useState<string | null>(null);\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),\n useSensor(KeyboardSensor, { coordinateGetter: boardCoordinateGetter }),\n );\n\n const handleStart = useCallback((event: DragStartEvent) => {\n setActiveId(String(event.active.id));\n setActiveType(event.active.data.current?.[\"type\"] === \"column\" ? \"column\" : \"card\");\n }, []);\n\n /* Cards land on cards as often as on empty space, so the lane a drag is over\n * is always resolved back to a column id — one highlight, one meaning. */\n const handleOver = useCallback((event: DragOverEvent) => {\n const over = event.over;\n if (!over) {\n setOverColumnId(null);\n return;\n }\n const overData = over.data.current ?? {};\n const columnId =\n overData[\"type\"] === \"column\" ? String(over.id) : String(overData[\"columnId\"] ?? \"\");\n setOverColumnId(columnId || null);\n }, []);\n\n const reset = useCallback(() => {\n setActiveId(null);\n setActiveType(null);\n setOverColumnId(null);\n }, []);\n\n const handleEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n reset();\n if (!over) return;\n\n const activeData = active.data.current ?? {};\n const overData = over.data.current ?? {};\n\n /* Columns reorder among themselves; a column never lands inside a lane. */\n if (activeData[\"type\"] === \"column\") {\n const ids = columnIds ?? [];\n const overColumnId =\n overData[\"type\"] === \"column\" ? String(over.id) : String(overData[\"columnId\"] ?? \"\");\n const toIndex = ids.indexOf(overColumnId);\n if (toIndex < 0 || overColumnId === String(active.id)) return;\n onColumnMove?.({ columnId: String(active.id), toIndex });\n return;\n }\n\n const fromColumnId = String(activeData[\"columnId\"] ?? \"\");\n let toColumnId = \"\";\n let toIndex = 0;\n\n if (overData[\"type\"] === \"card\") {\n /* Dropped on a card — land exactly where that card sits, in any lane. */\n toColumnId = String(overData[\"columnId\"] ?? \"\");\n toIndex = (overData[\"sortable\"] as { index: number } | undefined)?.index ?? 0;\n } else {\n /* Dropped on empty lane space — land at the end. */\n toColumnId = String(overData[\"columnId\"] ?? over.id);\n toIndex = ((overData[\"items\"] as string[] | undefined) ?? []).length;\n }\n\n if (!toColumnId) return;\n if (fromColumnId === toColumnId && String(active.id) === String(over.id)) return;\n onMove?.({ cardId: String(active.id), fromColumnId, toColumnId, toIndex });\n },\n [columnIds, onColumnMove, onMove, reset],\n );\n\n const value = useMemo(\n () => ({ activeId, activeType, overColumnId }),\n [activeId, activeType, overColumnId],\n );\n\n const board = (\n <div ref={ref} className={[\"ds-board\", className].filter(Boolean).join(\" \")} {...rest}>\n {children}\n </div>\n );\n\n return (\n <BoardContext.Provider value={value}>\n <DndContext\n id={`ds-board-${dndId}`}\n sensors={sensors}\n collisionDetection={boardCollisionDetection}\n /* Lanes scroll and change height mid-drag, so positions are re-read\n * continuously — without this the shift animation misfires. */\n measuring={{ droppable: { strategy: MeasuringStrategy.Always } }}\n\n onDragStart={handleStart}\n onDragOver={handleOver}\n onDragEnd={handleEnd}\n onDragCancel={reset}\n >\n {columnIds ? (\n <SortableContext items={columnIds} strategy={horizontalListSortingStrategy}>\n {board}\n </SortableContext>\n ) : (\n board\n )}\n <DragOverlay>\n {activeId && activeType === \"card\" ? (\n <div className=\"ds-board-card\" data-overlay>\n <span className=\"ds-board-card__handle\" aria-hidden=\"true\">\n <Icon name=\"grip-vertical\" />\n </span>\n <div className=\"ds-board-card__content\">{renderDragOverlay?.(activeId)}</div>\n </div>\n ) : null}\n {activeId && activeType === \"column\" ? (\n <div className=\"ds-board-column\" data-overlay>\n {renderColumnDragOverlay?.(activeId)}\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n </BoardContext.Provider>\n );\n});\n\nexport interface BoardColumnProps extends HTMLAttributes<HTMLDivElement> {\n id: string;\n title: string;\n /** Card ids in render order — the sortable contract for this column. */\n itemIds: string[];\n /** Shown beside the title; defaults to the number of cards. */\n count?: number;\n /** A control in the column head, e.g. an add button or a menu. */\n action?: ReactNode;\n /** Set false to pin a lane in place. */\n isDraggable?: boolean;\n children?: ReactNode;\n}\n\n/**\n * One lane of the board. Heavy frame, hairline head rule, scrolling body, and\n * a grip on top of the head that drags the whole lane sideways.\n */\nexport const BoardColumn = forwardRef<HTMLElement, BoardColumnProps>(\n function BoardColumn(\n { id, title, itemIds, count, action, isDraggable = true, className, children, ...rest },\n ref,\n ) {\n const { activeType, overColumnId } = useContext(BoardContext);\n const { setNodeRef: setBodyRef } = useDroppable({\n id: `${id}::body`,\n data: { type: \"column-body\", columnId: id, items: itemIds },\n });\n const {\n attributes,\n listeners,\n setNodeRef: setColumnRef,\n transform,\n transition,\n isDragging,\n } = useSortable({\n id,\n disabled: !isDraggable,\n data: { type: \"column\", columnId: id, items: itemIds },\n });\n\n return (\n <section\n ref={(node) => {\n setColumnRef(node);\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n style={{ transform: CSS.Translate.toString(transform), transition }}\n className={[\"ds-board-column\", className].filter(Boolean).join(\" \")}\n data-over={(activeType === \"card\" && overColumnId === id) || undefined}\n data-dragging={isDragging || undefined}\n\n aria-label={title}\n {...rest}\n >\n {isDraggable && (\n <Button\n variant=\"simple\"\n size=\"sm\"\n iconStart=\"grip-horizontal\"\n className=\"ds-board-column__grip\"\n aria-label={`Reorder ${title}`}\n {...attributes}\n {...listeners}\n />\n )}\n <header className=\"ds-board-column__head\">\n <span className=\"ds-board-column__title\">{title}</span>\n <span className=\"ds-board-column__count\">{count ?? itemIds.length}</span>\n {action && <span className=\"ds-board-column__action\">{action}</span>}\n </header>\n <div ref={setBodyRef} className=\"ds-board-column__body\">\n <SortableContext items={itemIds} strategy={verticalListSortingStrategy}>\n {children}\n </SortableContext>\n </div>\n </section>\n );\n },\n);\n\nexport interface BoardCardProps extends HTMLAttributes<HTMLDivElement> {\n id: string;\n columnId: string;\n /** Accessible name announced when the card is picked up. */\n label?: string;\n children?: ReactNode;\n}\n\n/**\n * A draggable card. The grip on the left is the handle, so the card body can\n * hold links and buttons; the grip is a real button for keyboard users:\n * space to pick up, arrows to move, space to drop.\n */\nexport const BoardCard = forwardRef<HTMLDivElement, BoardCardProps>(function BoardCard(\n { id, columnId, label, className, children, ...rest },\n ref,\n) {\n const { attributes, listeners, setNodeRef, transform, transition, isDragging } =\n useSortable({ id, data: { type: \"card\", columnId } });\n const { activeId } = useContext(BoardContext);\n\n return (\n <div\n ref={(node) => {\n setNodeRef(node);\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n style={{ transform: CSS.Translate.toString(transform), transition }}\n className={[\"ds-board-card\", className].filter(Boolean).join(\" \")}\n data-dragging={isDragging || undefined}\n data-idle={activeId && activeId !== id ? \"\" : undefined}\n {...rest}\n >\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"grip-vertical\"\n className=\"ds-board-card__handle\"\n aria-label={label ? `Move ${label}` : \"Move card\"}\n {...attributes}\n {...listeners}\n />\n <div className=\"ds-board-card__content\">{children}</div>\n </div>\n );\n});\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["Icon","boardCoordinateGetter","args","event","containers","context","c","\"type\"","a","b","activeRect","rect","currentCoordinates","sortableKeyboardCoordinates","boardCollisionDetection","isColumn","type","container","scoped","closestCorners","within","pointerWithin","rank","id","BoardContext","createContext","Board","forwardRef","rest","dndId","useId","activeId","setActiveId","useState","activeType","setActiveType","overColumnId","setOverColumnId","sensors","useSensors","useSensor","PointerSensor","KeyboardSensor","handleStart","useCallback","handleOver","over","overData","columnId","\"columnId\"","reset","handleEnd","activeData","active","ids","columnIds","toIndex","fromColumnId","toColumnId","\"sortable\"","\"items\"","onMove","onColumnMove","value","useMemo","board","className","DndContext","MeasuringStrategy","SortableContext","horizontalListSortingStrategy","DragOverlay","renderDragOverlay","renderColumnDragOverlay","BoardColumn","useContext","setBodyRef","useDroppable","itemIds","setColumnRef","useSortable","isDraggable","node","ref","CSS","transform","isDragging","title","Button","attributes","listeners","count","action","verticalListSortingStrategy","BoardCard","setNodeRef","label"],"sources":["../../../src/components/Board/index.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useId,\n useMemo,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from \"react\";\nimport {\n DndContext,\n DragOverlay,\n KeyboardSensor,\n PointerSensor,\n closestCorners,\n pointerWithin,\n MeasuringStrategy,\n\n useDroppable,\n useSensor,\n useSensors,\n type CollisionDetection,\n type DragEndEvent,\n type DragOverEvent,\n type DragStartEvent,\n} from \"@dnd-kit/core\";\nimport {\n SortableContext,\n horizontalListSortingStrategy,\n sortableKeyboardCoordinates,\n useSortable,\n verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport type { KeyboardCoordinateGetter } from \"@dnd-kit/core\";\nimport { Button } from \"../Button\";\nimport { Icon } from \"../Icon\";\nimport \"./style.css\";\n\nexport interface BoardMove {\n cardId: string;\n fromColumnId: string;\n toColumnId: string;\n /** Index the card lands on inside the destination column. */\n toIndex: number;\n}\n\nexport interface BoardColumnMove {\n columnId: string;\n toIndex: number;\n}\n\ninterface BoardContextValue {\n activeId: string | null;\n activeType: \"card\" | \"column\" | null;\n /** The lane the pointer is currently over, whatever it is actually over. */\n overColumnId: string | null;\n}\n\n/**\n * Arrow up/down sorts inside a lane; left/right jumps lanes, which the stock\n * sortable getter does not do.\n */\nconst boardCoordinateGetter: KeyboardCoordinateGetter = (event, args) => {\n const { currentCoordinates, context } = args;\n if (event.code === \"ArrowLeft\" || event.code === \"ArrowRight\") {\n const containers = context.droppableContainers\n .getEnabled()\n .filter((c) => c.data.current?.[\"type\"] === \"column-body\")\n .sort((a, b) => (a.rect.current?.left ?? 0) - (b.rect.current?.left ?? 0));\n const activeRect = context.active?.rect.current.translated;\n if (!activeRect) return undefined;\n const index = containers.findIndex(\n (c) => (c.rect.current?.left ?? 0) <= activeRect.left + 1 &&\n (c.rect.current?.right ?? 0) >= activeRect.left - 1,\n );\n const next = containers[index + (event.code === \"ArrowRight\" ? 1 : -1)];\n const rect = next?.rect.current;\n if (!rect) return undefined;\n event.preventDefault();\n return { x: rect.left + rect.width / 2 - activeRect.width / 2, y: currentCoordinates.y };\n }\n return sortableKeyboardCoordinates(event, args);\n};\n\n/**\n * A lane's body sits inside the lane's frame, so a raw corner-distance\n * strategy lets the body steal the hit from the lane itself — most visibly at\n * the board ends, where the last lane then never shifts aside to open the\n * drop gap. Resolve by what is being dragged: a column only ever hits other\n * columns; a card hits the card under the pointer first, then the lane body\n * under it, then whatever is nearest.\n */\nconst boardCollisionDetection: CollisionDetection = (args) => {\n const isColumn = args.active.data.current?.[\"type\"] === \"column\";\n const containers = args.droppableContainers.filter((container) => {\n const type = container.data.current?.[\"type\"];\n return isColumn ? type === \"column\" : type !== \"column\";\n });\n const scoped = { ...args, droppableContainers: containers };\n if (isColumn) return closestCorners(scoped);\n const within = pointerWithin(scoped);\n if (within.length > 0) {\n const rank = (id: (typeof within)[number][\"id\"]) =>\n containers.find((c) => c.id === id)?.data.current?.[\"type\"] === \"card\" ? 0 : 1;\n return [...within].sort((a, b) => rank(a.id) - rank(b.id));\n }\n return closestCorners(scoped);\n};\n\nconst BoardContext = createContext<BoardContextValue>({\n activeId: null,\n activeType: null,\n overColumnId: null,\n});\n\nexport interface BoardProps extends Omit<HTMLAttributes<HTMLDivElement>, \"onDragEnd\"> {\n /** Column ids in render order. Required for columns to be re-orderable. */\n columnIds?: string[];\n /** Fired once a card is dropped somewhere new. Apply it to your own state. */\n onMove?: (move: BoardMove) => void;\n /** Fired once a column is dropped in a new position. */\n onColumnMove?: (move: BoardColumnMove) => void;\n /** Rendered inside the drag overlay while a card is in the air. */\n renderDragOverlay?: (cardId: string) => ReactNode;\n /** Rendered inside the drag overlay while a column is in the air. */\n renderColumnDragOverlay?: (columnId: string) => ReactNode;\n children?: ReactNode;\n}\n\n/**\n * A column board with pointer and keyboard dragging. The board owns the drag\n * mechanics only — the card data stays yours; react to `onMove`.\n */\nexport const Board = forwardRef<HTMLDivElement, BoardProps>(function Board(\n {\n columnIds,\n onMove,\n onColumnMove,\n renderDragOverlay,\n renderColumnDragOverlay,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const dndId = useId();\n const [activeId, setActiveId] = useState<string | null>(null);\n const [activeType, setActiveType] = useState<\"card\" | \"column\" | null>(null);\n const [overColumnId, setOverColumnId] = useState<string | null>(null);\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),\n useSensor(KeyboardSensor, { coordinateGetter: boardCoordinateGetter }),\n );\n\n const handleStart = useCallback((event: DragStartEvent) => {\n setActiveId(String(event.active.id));\n setActiveType(event.active.data.current?.[\"type\"] === \"column\" ? \"column\" : \"card\");\n }, []);\n\n /* Cards land on cards as often as on empty space, so the lane a drag is over\n * is always resolved back to a column id — one highlight, one meaning. */\n const handleOver = useCallback((event: DragOverEvent) => {\n const over = event.over;\n if (!over) {\n setOverColumnId(null);\n return;\n }\n const overData = over.data.current ?? {};\n const columnId =\n overData[\"type\"] === \"column\" ? String(over.id) : String(overData[\"columnId\"] ?? \"\");\n setOverColumnId(columnId || null);\n }, []);\n\n const reset = useCallback(() => {\n setActiveId(null);\n setActiveType(null);\n setOverColumnId(null);\n }, []);\n\n const handleEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n reset();\n if (!over) return;\n\n const activeData = active.data.current ?? {};\n const overData = over.data.current ?? {};\n\n /* Columns reorder among themselves; a column never lands inside a lane. */\n if (activeData[\"type\"] === \"column\") {\n const ids = columnIds ?? [];\n const overColumnId =\n overData[\"type\"] === \"column\" ? String(over.id) : String(overData[\"columnId\"] ?? \"\");\n const toIndex = ids.indexOf(overColumnId);\n if (toIndex < 0 || overColumnId === String(active.id)) return;\n onColumnMove?.({ columnId: String(active.id), toIndex });\n return;\n }\n\n const fromColumnId = String(activeData[\"columnId\"] ?? \"\");\n let toColumnId = \"\";\n let toIndex = 0;\n\n if (overData[\"type\"] === \"card\") {\n /* Dropped on a card — land exactly where that card sits, in any lane. */\n toColumnId = String(overData[\"columnId\"] ?? \"\");\n toIndex = (overData[\"sortable\"] as { index: number } | undefined)?.index ?? 0;\n } else {\n /* Dropped on empty lane space — land at the end. */\n toColumnId = String(overData[\"columnId\"] ?? over.id);\n toIndex = ((overData[\"items\"] as string[] | undefined) ?? []).length;\n }\n\n if (!toColumnId) return;\n if (fromColumnId === toColumnId && String(active.id) === String(over.id)) return;\n onMove?.({ cardId: String(active.id), fromColumnId, toColumnId, toIndex });\n },\n [columnIds, onColumnMove, onMove, reset],\n );\n\n const value = useMemo(\n () => ({ activeId, activeType, overColumnId }),\n [activeId, activeType, overColumnId],\n );\n\n const board = (\n <div ref={ref} className={[\"ds-board\", className].filter(Boolean).join(\" \")} {...rest}>\n {children}\n </div>\n );\n\n return (\n <BoardContext.Provider value={value}>\n <DndContext\n id={`ds-board-${dndId}`}\n sensors={sensors}\n collisionDetection={boardCollisionDetection}\n /* Lanes scroll and change height mid-drag, so positions are re-read\n * continuously — without this the shift animation misfires. */\n measuring={{ droppable: { strategy: MeasuringStrategy.Always } }}\n\n onDragStart={handleStart}\n onDragOver={handleOver}\n onDragEnd={handleEnd}\n onDragCancel={reset}\n >\n {columnIds ? (\n <SortableContext items={columnIds} strategy={horizontalListSortingStrategy}>\n {board}\n </SortableContext>\n ) : (\n board\n )}\n <DragOverlay>\n {activeId && activeType === \"card\" ? (\n <div className=\"ds-board-card\" data-overlay>\n <span className=\"ds-board-card__handle\" aria-hidden=\"true\">\n <Icon name=\"grip-vertical\" />\n </span>\n <div className=\"ds-board-card__content\">{renderDragOverlay?.(activeId)}</div>\n </div>\n ) : null}\n {activeId && activeType === \"column\" ? (\n <div className=\"ds-board-column\" data-overlay>\n {renderColumnDragOverlay?.(activeId)}\n </div>\n ) : null}\n </DragOverlay>\n </DndContext>\n </BoardContext.Provider>\n );\n});\n\nexport interface BoardColumnProps extends HTMLAttributes<HTMLDivElement> {\n id: string;\n title: string;\n /** Card ids in render order — the sortable contract for this column. */\n itemIds: string[];\n /** Shown beside the title; defaults to the number of cards. */\n count?: number;\n /** A control in the column head, e.g. an add button or a menu. */\n action?: ReactNode;\n /** Set false to pin a lane in place. */\n isDraggable?: boolean;\n children?: ReactNode;\n}\n\n/**\n * One lane of the board. Heavy frame, hairline head rule, scrolling body, and\n * a grip on top of the head that drags the whole lane sideways.\n */\nexport const BoardColumn = forwardRef<HTMLElement, BoardColumnProps>(\n function BoardColumn(\n { id, title, itemIds, count, action, isDraggable = true, className, children, ...rest },\n ref,\n ) {\n const { activeType, overColumnId } = useContext(BoardContext);\n const { setNodeRef: setBodyRef } = useDroppable({\n id: `${id}::body`,\n data: { type: \"column-body\", columnId: id, items: itemIds },\n });\n const {\n attributes,\n listeners,\n setNodeRef: setColumnRef,\n transform,\n transition,\n isDragging,\n } = useSortable({\n id,\n disabled: !isDraggable,\n data: { type: \"column\", columnId: id, items: itemIds },\n });\n\n return (\n <section\n ref={(node) => {\n setColumnRef(node);\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n style={{ transform: CSS.Translate.toString(transform), transition }}\n className={[\"ds-board-column\", className].filter(Boolean).join(\" \")}\n data-over={(activeType === \"card\" && overColumnId === id) || undefined}\n data-dragging={isDragging || undefined}\n\n aria-label={title}\n {...rest}\n >\n {isDraggable && (\n <Button\n variant=\"simple\"\n size=\"sm\"\n iconStart=\"grip-horizontal\"\n className=\"ds-board-column__grip\"\n aria-label={`Reorder ${title}`}\n {...attributes}\n {...listeners}\n />\n )}\n <header className=\"ds-board-column__head\">\n <span className=\"ds-board-column__title\">{title}</span>\n <span className=\"ds-board-column__count\">{count ?? itemIds.length}</span>\n {action && <span className=\"ds-board-column__action\">{action}</span>}\n </header>\n <div ref={setBodyRef} className=\"ds-board-column__body\">\n <SortableContext items={itemIds} strategy={verticalListSortingStrategy}>\n {children}\n </SortableContext>\n </div>\n </section>\n );\n },\n);\n\nexport interface BoardCardProps extends HTMLAttributes<HTMLDivElement> {\n id: string;\n columnId: string;\n /** Accessible name announced when the card is picked up. */\n label?: string;\n children?: ReactNode;\n}\n\n/**\n * A draggable card. The grip on the left is the handle, so the card body can\n * hold links and buttons; the grip is a real button for keyboard users:\n * space to pick up, arrows to move, space to drop.\n */\nexport const BoardCard = forwardRef<HTMLDivElement, BoardCardProps>(function BoardCard(\n { id, columnId, label, className, children, ...rest },\n ref,\n) {\n const { attributes, listeners, setNodeRef, transform, transition, isDragging } =\n useSortable({ id, data: { type: \"card\", columnId } });\n const { activeId } = useContext(BoardContext);\n\n return (\n <div\n ref={(node) => {\n setNodeRef(node);\n if (typeof ref === \"function\") ref(node);\n else if (ref) ref.current = node;\n }}\n style={{ transform: CSS.Translate.toString(transform), transition }}\n className={[\"ds-board-card\", className].filter(Boolean).join(\" \")}\n data-dragging={isDragging || undefined}\n data-idle={activeId && activeId !== id ? \"\" : undefined}\n {...rest}\n >\n <Button\n variant=\"simple\"\n size=\"sm\"\n isIconOnly\n iconStart=\"grip-vertical\"\n className=\"ds-board-card__handle\"\n aria-label={label ? `Move ${label}` : \"Move card\"}\n {...attributes}\n {...listeners}\n />\n <div className=\"ds-board-card__content\">{children}</div>\n </div>\n );\n});\n"],"mappings":"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"}