@namroodinc/liquid-editorial 0.1.1 → 0.1.4
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.
- package/AGENTS.md +11 -0
- package/README.md +8 -0
- package/UPGRADING.md +56 -0
- package/dist/chunks/{EntryEditor-cjDk4vdH.cjs → EntryEditor-C32lKKnV.cjs} +2 -2
- package/dist/chunks/{EntryEditor-cjDk4vdH.cjs.map → EntryEditor-C32lKKnV.cjs.map} +1 -1
- package/dist/chunks/EntryEditor-xVuiqtFo.js +181 -0
- package/dist/chunks/{EntryEditor-BF808OZR.js.map → EntryEditor-xVuiqtFo.js.map} +1 -1
- package/dist/chunks/RichTextEditor-CSpjsL1z.js +357 -0
- package/dist/chunks/RichTextEditor-CSpjsL1z.js.map +1 -0
- package/dist/chunks/RichTextEditor-DC_0oN1s.cjs +2 -0
- package/dist/chunks/RichTextEditor-DC_0oN1s.cjs.map +1 -0
- package/dist/components/AssetGrid/index.js.map +1 -1
- package/dist/components/EntryEditor/index.cjs +1 -1
- package/dist/components/EntryEditor/index.js +3 -3
- package/dist/components/EntryPicker/index.cjs +1 -1
- package/dist/components/EntryPicker/index.cjs.map +1 -1
- package/dist/components/EntryPicker/index.js +4 -4
- package/dist/components/EntryPicker/index.js.map +1 -1
- package/dist/components/Field/index.js.map +1 -1
- package/dist/components/ImageCropper/index.js.map +1 -1
- package/dist/components/Modal/index.cjs +1 -1
- package/dist/components/Modal/index.cjs.map +1 -1
- package/dist/components/Modal/index.js +2 -2
- package/dist/components/Modal/index.js.map +1 -1
- package/dist/components/Modal/style.css +1 -0
- package/dist/components/RichTextEditor/index.cjs +1 -1
- package/dist/components/RichTextEditor/index.d.cts.map +1 -1
- package/dist/components/RichTextEditor/index.d.ts.map +1 -1
- package/dist/components/RichTextEditor/index.js +3 -1
- package/dist/components/SortableList/index.cjs +1 -1
- package/dist/components/SortableList/index.cjs.map +1 -1
- package/dist/components/SortableList/index.d.cts +4 -3
- package/dist/components/SortableList/index.d.cts.map +1 -1
- package/dist/components/SortableList/index.d.ts +4 -3
- package/dist/components/SortableList/index.d.ts.map +1 -1
- package/dist/components/SortableList/index.js +55 -48
- package/dist/components/SortableList/index.js.map +1 -1
- package/dist/components/Table/index.cjs +1 -1
- package/dist/components/Table/index.cjs.map +1 -1
- package/dist/components/Table/index.d.cts +5 -1
- package/dist/components/Table/index.d.cts.map +1 -1
- package/dist/components/Table/index.d.ts +5 -1
- package/dist/components/Table/index.d.ts.map +1 -1
- package/dist/components/Table/index.js +74 -55
- package/dist/components/Table/index.js.map +1 -1
- package/dist/components/Table/style.css +4 -0
- package/dist/components/Time/index.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +13 -13
- package/package.json +3 -1
- package/dist/chunks/EntryEditor-BF808OZR.js +0 -181
- package/dist/chunks/RichTextEditor-DRt-kibg.js +0 -248
- package/dist/chunks/RichTextEditor-DRt-kibg.js.map +0 -1
- package/dist/chunks/RichTextEditor-tFkISOvq.cjs +0 -2
- package/dist/chunks/RichTextEditor-tFkISOvq.cjs.map +0 -1
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { Button as e } from "../components/Button/index.js";
|
|
2
|
+
import { ButtonGroup as t } from "../components/ButtonGroup/index.js";
|
|
3
|
+
/* empty css */
|
|
4
|
+
import { Field as n } from "../components/Field/index.js";
|
|
5
|
+
import { Modal as r } from "../components/Modal/index.js";
|
|
6
|
+
import { TextField as i } from "../components/TextField/index.js";
|
|
7
|
+
import { forwardRef as a, useCallback as o, useEffect as s, useId as c, useMemo as l, useState as u } from "react";
|
|
8
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
9
|
+
import { EditorContent as m, createDocument as h, getMarkRange as g, getSchema as _, useEditor as v, useEditorState as y } from "@tiptap/react";
|
|
10
|
+
import { Placeholder as b } from "@tiptap/extension-placeholder";
|
|
11
|
+
import { StarterKit as x } from "@tiptap/starter-kit";
|
|
12
|
+
import { Link as S } from "@tiptap/extension-link";
|
|
13
|
+
//#region src/components/RichTextEditor/document.ts
|
|
14
|
+
var C = {
|
|
15
|
+
type: "doc",
|
|
16
|
+
content: [{ type: "paragraph" }]
|
|
17
|
+
};
|
|
18
|
+
function w() {
|
|
19
|
+
return [x.configure({ link: !1 }), S.configure({
|
|
20
|
+
openOnClick: !1,
|
|
21
|
+
autolink: !0
|
|
22
|
+
})];
|
|
23
|
+
}
|
|
24
|
+
var T = _(w());
|
|
25
|
+
function E(e) {
|
|
26
|
+
return e.content?.length ? e : {
|
|
27
|
+
...e,
|
|
28
|
+
content: C.content
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function D(e) {
|
|
32
|
+
try {
|
|
33
|
+
if (!e || typeof e != "object" || !("type" in e) || e.type !== "doc") throw Error();
|
|
34
|
+
let t = (e) => {
|
|
35
|
+
let n = T.nodes[e.type ?? ""];
|
|
36
|
+
if (!n || Object.keys(e).some((e) => ![
|
|
37
|
+
"type",
|
|
38
|
+
"attrs",
|
|
39
|
+
"content",
|
|
40
|
+
"marks",
|
|
41
|
+
"text"
|
|
42
|
+
].includes(e)) || e.text !== void 0 && e.type !== "text" || e.attrs && Object.keys(e.attrs).some((e) => !Object.hasOwn(n.spec.attrs ?? {}, e))) throw Error();
|
|
43
|
+
for (let t of e.marks ?? []) {
|
|
44
|
+
let e = T.marks[t.type];
|
|
45
|
+
if (!e || Object.keys(t).some((e) => !["type", "attrs"].includes(e)) || Object.keys(t.attrs ?? {}).some((t) => !Object.hasOwn(e.spec.attrs ?? {}, t))) throw Error();
|
|
46
|
+
}
|
|
47
|
+
e.content?.forEach(t);
|
|
48
|
+
}, n = e;
|
|
49
|
+
t(n), T.nodeFromJSON(E(n)).check();
|
|
50
|
+
} catch {
|
|
51
|
+
return "Unsupported or invalid rich-text document.";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/components/RichTextEditor/index.tsx
|
|
56
|
+
function O({ editor: t, selection: a, onClose: o }) {
|
|
57
|
+
let [l, m] = u(a.href), [h, g] = u(), _ = c();
|
|
58
|
+
s(() => {
|
|
59
|
+
let e = () => {
|
|
60
|
+
t.state.doc.eq(a.document) || o();
|
|
61
|
+
};
|
|
62
|
+
return t.on("transaction", e), () => {
|
|
63
|
+
t.off("transaction", e);
|
|
64
|
+
};
|
|
65
|
+
}, [
|
|
66
|
+
t,
|
|
67
|
+
a,
|
|
68
|
+
o
|
|
69
|
+
]);
|
|
70
|
+
let v = () => !t.isDestroyed && t.isEditable && t.state.doc.eq(a.document), y = () => {
|
|
71
|
+
if (!v()) {
|
|
72
|
+
o();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
let e = l.trim();
|
|
76
|
+
if (!e || !t.can().setLink({ href: e })) {
|
|
77
|
+
g(e ? "Enter a valid link URL." : "Enter a link URL.");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
let n = t.chain().focus().setTextSelection({
|
|
81
|
+
from: a.from,
|
|
82
|
+
to: a.to
|
|
83
|
+
});
|
|
84
|
+
a.from === a.to && !a.isEditing ? n.setLink({ href: e }).insertContent({
|
|
85
|
+
type: "text",
|
|
86
|
+
text: e,
|
|
87
|
+
marks: [{
|
|
88
|
+
type: "link",
|
|
89
|
+
attrs: { href: e }
|
|
90
|
+
}]
|
|
91
|
+
}).run() : n.setLink({ href: e }).run(), o();
|
|
92
|
+
};
|
|
93
|
+
return /* @__PURE__ */ f(r, {
|
|
94
|
+
isOpen: !0,
|
|
95
|
+
title: a.isEditing ? "Edit link" : "Add link",
|
|
96
|
+
size: "dialog",
|
|
97
|
+
onClose: o,
|
|
98
|
+
footer: /* @__PURE__ */ p(d, { children: [
|
|
99
|
+
a.isEditing && /* @__PURE__ */ f(e, {
|
|
100
|
+
variant: "danger",
|
|
101
|
+
onClick: () => {
|
|
102
|
+
v() && t.chain().focus().setTextSelection({
|
|
103
|
+
from: a.from,
|
|
104
|
+
to: a.to
|
|
105
|
+
}).unsetLink().run(), o();
|
|
106
|
+
},
|
|
107
|
+
children: "Remove link"
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ f(e, {
|
|
110
|
+
onClick: o,
|
|
111
|
+
children: "Cancel"
|
|
112
|
+
}),
|
|
113
|
+
/* @__PURE__ */ f(e, {
|
|
114
|
+
variant: "primary",
|
|
115
|
+
type: "submit",
|
|
116
|
+
form: _,
|
|
117
|
+
children: "Save"
|
|
118
|
+
})
|
|
119
|
+
] }),
|
|
120
|
+
children: /* @__PURE__ */ f("form", {
|
|
121
|
+
id: _,
|
|
122
|
+
noValidate: !0,
|
|
123
|
+
onSubmit: (e) => {
|
|
124
|
+
e.preventDefault(), e.stopPropagation(), y();
|
|
125
|
+
},
|
|
126
|
+
children: /* @__PURE__ */ f(n, {
|
|
127
|
+
label: "URL",
|
|
128
|
+
isRequired: !0,
|
|
129
|
+
error: h,
|
|
130
|
+
children: (e) => /* @__PURE__ */ f(i, {
|
|
131
|
+
...e,
|
|
132
|
+
value: l,
|
|
133
|
+
inputMode: "url",
|
|
134
|
+
autoComplete: "url",
|
|
135
|
+
placeholder: "https://example.com",
|
|
136
|
+
onChange: (e) => {
|
|
137
|
+
m(e.target.value), g(void 0);
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
var k = [
|
|
145
|
+
[
|
|
146
|
+
{
|
|
147
|
+
id: "bold",
|
|
148
|
+
icon: "bold",
|
|
149
|
+
label: "Bold",
|
|
150
|
+
run: (e) => e.chain().focus().toggleBold().run(),
|
|
151
|
+
active: (e) => e.isActive("bold")
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "italic",
|
|
155
|
+
icon: "italic",
|
|
156
|
+
label: "Italic",
|
|
157
|
+
run: (e) => e.chain().focus().toggleItalic().run(),
|
|
158
|
+
active: (e) => e.isActive("italic")
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "strike",
|
|
162
|
+
icon: "strikethrough",
|
|
163
|
+
label: "Strikethrough",
|
|
164
|
+
run: (e) => e.chain().focus().toggleStrike().run(),
|
|
165
|
+
active: (e) => e.isActive("strike")
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "code",
|
|
169
|
+
icon: "code",
|
|
170
|
+
label: "Inline code",
|
|
171
|
+
run: (e) => e.chain().focus().toggleCode().run(),
|
|
172
|
+
active: (e) => e.isActive("code")
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
[
|
|
176
|
+
{
|
|
177
|
+
id: "h2",
|
|
178
|
+
icon: "heading-2",
|
|
179
|
+
label: "Heading",
|
|
180
|
+
run: (e) => e.chain().focus().toggleHeading({ level: 2 }).run(),
|
|
181
|
+
active: (e) => e.isActive("heading", { level: 2 })
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: "h3",
|
|
185
|
+
icon: "heading-3",
|
|
186
|
+
label: "Subheading",
|
|
187
|
+
run: (e) => e.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
188
|
+
active: (e) => e.isActive("heading", { level: 3 })
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "quote",
|
|
192
|
+
icon: "quote",
|
|
193
|
+
label: "Quote",
|
|
194
|
+
run: (e) => e.chain().focus().toggleBlockquote().run(),
|
|
195
|
+
active: (e) => e.isActive("blockquote")
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
[{
|
|
199
|
+
id: "ul",
|
|
200
|
+
icon: "list",
|
|
201
|
+
label: "Bulleted list",
|
|
202
|
+
run: (e) => e.chain().focus().toggleBulletList().run(),
|
|
203
|
+
active: (e) => e.isActive("bulletList")
|
|
204
|
+
}, {
|
|
205
|
+
id: "ol",
|
|
206
|
+
icon: "list-ordered",
|
|
207
|
+
label: "Numbered list",
|
|
208
|
+
run: (e) => e.chain().focus().toggleOrderedList().run(),
|
|
209
|
+
active: (e) => e.isActive("orderedList")
|
|
210
|
+
}],
|
|
211
|
+
[{
|
|
212
|
+
id: "undo",
|
|
213
|
+
icon: "undo",
|
|
214
|
+
label: "Undo",
|
|
215
|
+
run: (e) => e.chain().focus().undo().run()
|
|
216
|
+
}, {
|
|
217
|
+
id: "redo",
|
|
218
|
+
icon: "redo",
|
|
219
|
+
label: "Redo",
|
|
220
|
+
run: (e) => e.chain().focus().redo().run()
|
|
221
|
+
}]
|
|
222
|
+
], A = a(function(n, r) {
|
|
223
|
+
let { placeholder: i = "Write something…", size: a = "md", isDisabled: d = !1, isInvalid: _ = !1, label: x = "Rich text editor", className: S, toolbarExtra: T, id: A, isRequired: j, "aria-labelledby": M, "aria-describedby": N, "aria-invalid": P } = n, [F, I] = u(!1), [L, R] = u(null), z = o(() => R(null), []), [B] = u(() => n.defaultValue ?? (n.format === "json" ? C : "")), V = n.value === void 0 ? B : n.value, H = l(() => n.format === "json" ? D(V) : void 0, [n.format, V]), U = c(), W = _ || !!H || P, G = d || !!H;
|
|
224
|
+
G && L && R(null);
|
|
225
|
+
let K = o((e, t) => {
|
|
226
|
+
if (G) return;
|
|
227
|
+
let n = t === void 0 ? void 0 : g(e.doc.resolve(t), e.schema.marks.link), r = n && e.doc.nodeAt(n.from)?.marks.find((t) => t.type === e.schema.marks.link);
|
|
228
|
+
R({
|
|
229
|
+
from: n?.from ?? e.selection.from,
|
|
230
|
+
to: n?.to ?? e.selection.to,
|
|
231
|
+
href: r?.attrs.href ?? "",
|
|
232
|
+
isEditing: !!r,
|
|
233
|
+
document: e.doc
|
|
234
|
+
});
|
|
235
|
+
}, [G]), q = l(() => ({
|
|
236
|
+
role: "textbox",
|
|
237
|
+
"aria-label": x,
|
|
238
|
+
"aria-multiline": "true",
|
|
239
|
+
...A ? { id: A } : {},
|
|
240
|
+
...M ? { "aria-labelledby": M } : {},
|
|
241
|
+
...N ? { "aria-describedby": N } : {},
|
|
242
|
+
...W ? { "aria-invalid": String(W) } : {},
|
|
243
|
+
...j ? { "aria-required": "true" } : {}
|
|
244
|
+
}), [
|
|
245
|
+
x,
|
|
246
|
+
A,
|
|
247
|
+
M,
|
|
248
|
+
N,
|
|
249
|
+
W,
|
|
250
|
+
j
|
|
251
|
+
]), J = l(() => ({
|
|
252
|
+
attributes: q,
|
|
253
|
+
handleDOMEvents: { click: (e, t) => {
|
|
254
|
+
let n = t.target instanceof Element ? t.target.closest("a") : null;
|
|
255
|
+
return !n || !e.dom.contains(n) ? !1 : (t.preventDefault(), e.editable && K(e.state, e.posAtDOM(n, 0)), !0);
|
|
256
|
+
} }
|
|
257
|
+
}), [q, K]), Y = v({
|
|
258
|
+
immediatelyRender: !1,
|
|
259
|
+
editable: !G,
|
|
260
|
+
content: H ? C : typeof V == "string" ? V : E(V),
|
|
261
|
+
extensions: [...w(), b.configure({ placeholder: i })],
|
|
262
|
+
editorProps: J,
|
|
263
|
+
onFocus: () => I(!0),
|
|
264
|
+
onBlur: () => I(!1),
|
|
265
|
+
onUpdate: ({ editor: e }) => {
|
|
266
|
+
G || (n.format === "json" ? n.onChange?.(e.getJSON()) : n.onChange?.(e.getHTML()));
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
s(() => {
|
|
270
|
+
Y && (Y.setEditable(!G, !1), Y.setOptions({ editorProps: J }));
|
|
271
|
+
}, [
|
|
272
|
+
Y,
|
|
273
|
+
G,
|
|
274
|
+
J
|
|
275
|
+
]), s(() => {
|
|
276
|
+
if (!Y || n.value === void 0 || H) return;
|
|
277
|
+
let e = typeof n.value == "string" ? h(n.value, Y.schema) : Y.schema.nodeFromJSON(E(n.value));
|
|
278
|
+
e.eq(Y.state.doc) || Y.commands.setContent(e, { emitUpdate: !1 });
|
|
279
|
+
}, [
|
|
280
|
+
Y,
|
|
281
|
+
n.value,
|
|
282
|
+
H
|
|
283
|
+
]);
|
|
284
|
+
let X = y({
|
|
285
|
+
editor: Y,
|
|
286
|
+
selector: ({ editor: e }) => e ? {
|
|
287
|
+
active: Object.fromEntries(k.flat().map((t) => [t.id, t.active?.(e) ?? !1])),
|
|
288
|
+
linkActive: e.isActive("link")
|
|
289
|
+
} : null
|
|
290
|
+
});
|
|
291
|
+
return /* @__PURE__ */ p("div", {
|
|
292
|
+
ref: r,
|
|
293
|
+
className: ["ds-rte", S].filter(Boolean).join(" "),
|
|
294
|
+
"data-focused": F || void 0,
|
|
295
|
+
"data-disabled": G || void 0,
|
|
296
|
+
"aria-invalid": W || void 0,
|
|
297
|
+
children: [
|
|
298
|
+
H && /* @__PURE__ */ f("p", {
|
|
299
|
+
id: U,
|
|
300
|
+
role: "alert",
|
|
301
|
+
className: "ds-field__error",
|
|
302
|
+
children: H
|
|
303
|
+
}),
|
|
304
|
+
/* @__PURE__ */ p("div", {
|
|
305
|
+
hidden: !!H,
|
|
306
|
+
children: [/* @__PURE__ */ p("div", {
|
|
307
|
+
className: "ds-rte__toolbar",
|
|
308
|
+
role: "toolbar",
|
|
309
|
+
"aria-label": `${x} formatting`,
|
|
310
|
+
children: [
|
|
311
|
+
k.map((n, r) => /* @__PURE__ */ f(t, {
|
|
312
|
+
"aria-label": `Formatting ${r + 1}`,
|
|
313
|
+
children: n.map((t) => /* @__PURE__ */ f(e, {
|
|
314
|
+
size: "sm",
|
|
315
|
+
isIconOnly: !0,
|
|
316
|
+
iconStart: t.icon,
|
|
317
|
+
"aria-label": t.label,
|
|
318
|
+
title: t.label,
|
|
319
|
+
"aria-pressed": t.active ? X?.active[t.id] : void 0,
|
|
320
|
+
variant: X?.active[t.id] ? "active" : "neutral",
|
|
321
|
+
isDisabled: G || !Y,
|
|
322
|
+
onClick: () => Y && t.run(Y)
|
|
323
|
+
}, t.id))
|
|
324
|
+
}, r)),
|
|
325
|
+
/* @__PURE__ */ f(t, {
|
|
326
|
+
"aria-label": "Link",
|
|
327
|
+
children: /* @__PURE__ */ f(e, {
|
|
328
|
+
size: "sm",
|
|
329
|
+
isIconOnly: !0,
|
|
330
|
+
iconStart: "link",
|
|
331
|
+
"aria-label": X?.linkActive ? "Edit link" : "Add link",
|
|
332
|
+
title: X?.linkActive ? "Edit link" : "Add link",
|
|
333
|
+
variant: X?.linkActive ? "active" : "neutral",
|
|
334
|
+
isDisabled: G || !Y,
|
|
335
|
+
onClick: () => Y && K(Y.state, Y.isActive("link") ? Y.state.selection.from : void 0)
|
|
336
|
+
})
|
|
337
|
+
}),
|
|
338
|
+
T
|
|
339
|
+
]
|
|
340
|
+
}), /* @__PURE__ */ f("div", {
|
|
341
|
+
className: "ds-rte__content",
|
|
342
|
+
"data-size": a,
|
|
343
|
+
children: /* @__PURE__ */ f(m, { editor: Y })
|
|
344
|
+
})]
|
|
345
|
+
}),
|
|
346
|
+
Y && L && !G && /* @__PURE__ */ f(O, {
|
|
347
|
+
editor: Y,
|
|
348
|
+
selection: L,
|
|
349
|
+
onClose: z
|
|
350
|
+
})
|
|
351
|
+
]
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
//#endregion
|
|
355
|
+
export { D as n, C as r, A as t };
|
|
356
|
+
|
|
357
|
+
//# sourceMappingURL=RichTextEditor-CSpjsL1z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../components/Button/index.cjs"),t=require("../components/ButtonGroup/index.cjs");;/* empty css */const n=require("../components/Field/index.cjs"),r=require("../components/Modal/index.cjs"),i=require("../components/TextField/index.cjs");let a=require("react"),o=require("react/jsx-runtime"),s=require("@tiptap/react"),c=require("@tiptap/extension-placeholder"),l=require("@tiptap/starter-kit"),u=require("@tiptap/extension-link");var d={type:`doc`,content:[{type:`paragraph`}]};function f(){return[l.StarterKit.configure({link:!1}),u.Link.configure({openOnClick:!1,autolink:!0})]}var p=(0,s.getSchema)(f());function m(e){return e.content?.length?e:{...e,content:d.content}}function h(e){try{if(!e||typeof e!=`object`||!(`type`in e)||e.type!==`doc`)throw Error();let t=e=>{let n=p.nodes[e.type??``];if(!n||Object.keys(e).some(e=>![`type`,`attrs`,`content`,`marks`,`text`].includes(e))||e.text!==void 0&&e.type!==`text`||e.attrs&&Object.keys(e.attrs).some(e=>!Object.hasOwn(n.spec.attrs??{},e)))throw Error();for(let t of e.marks??[]){let e=p.marks[t.type];if(!e||Object.keys(t).some(e=>![`type`,`attrs`].includes(e))||Object.keys(t.attrs??{}).some(t=>!Object.hasOwn(e.spec.attrs??{},t)))throw Error()}e.content?.forEach(t)},n=e;t(n),p.nodeFromJSON(m(n)).check()}catch{return`Unsupported or invalid rich-text document.`}}function g({editor:t,selection:s,onClose:c}){let[l,u]=(0,a.useState)(s.href),[d,f]=(0,a.useState)(),p=(0,a.useId)();(0,a.useEffect)(()=>{let e=()=>{t.state.doc.eq(s.document)||c()};return t.on(`transaction`,e),()=>{t.off(`transaction`,e)}},[t,s,c]);let m=()=>!t.isDestroyed&&t.isEditable&&t.state.doc.eq(s.document),h=()=>{if(!m()){c();return}let e=l.trim();if(!e||!t.can().setLink({href:e})){f(e?`Enter a valid link URL.`:`Enter a link URL.`);return}let n=t.chain().focus().setTextSelection({from:s.from,to:s.to});s.from===s.to&&!s.isEditing?n.setLink({href:e}).insertContent({type:`text`,text:e,marks:[{type:`link`,attrs:{href:e}}]}).run():n.setLink({href:e}).run(),c()};return(0,o.jsx)(r.Modal,{isOpen:!0,title:s.isEditing?`Edit link`:`Add link`,size:`dialog`,onClose:c,footer:(0,o.jsxs)(o.Fragment,{children:[s.isEditing&&(0,o.jsx)(e.Button,{variant:`danger`,onClick:()=>{m()&&t.chain().focus().setTextSelection({from:s.from,to:s.to}).unsetLink().run(),c()},children:`Remove link`}),(0,o.jsx)(e.Button,{onClick:c,children:`Cancel`}),(0,o.jsx)(e.Button,{variant:`primary`,type:`submit`,form:p,children:`Save`})]}),children:(0,o.jsx)(`form`,{id:p,noValidate:!0,onSubmit:e=>{e.preventDefault(),e.stopPropagation(),h()},children:(0,o.jsx)(n.Field,{label:`URL`,isRequired:!0,error:d,children:e=>(0,o.jsx)(i.TextField,{...e,value:l,inputMode:`url`,autoComplete:`url`,placeholder:`https://example.com`,onChange:e=>{u(e.target.value),f(void 0)}})})})})}var _=[[{id:`bold`,icon:`bold`,label:`Bold`,run:e=>e.chain().focus().toggleBold().run(),active:e=>e.isActive(`bold`)},{id:`italic`,icon:`italic`,label:`Italic`,run:e=>e.chain().focus().toggleItalic().run(),active:e=>e.isActive(`italic`)},{id:`strike`,icon:`strikethrough`,label:`Strikethrough`,run:e=>e.chain().focus().toggleStrike().run(),active:e=>e.isActive(`strike`)},{id:`code`,icon:`code`,label:`Inline code`,run:e=>e.chain().focus().toggleCode().run(),active:e=>e.isActive(`code`)}],[{id:`h2`,icon:`heading-2`,label:`Heading`,run:e=>e.chain().focus().toggleHeading({level:2}).run(),active:e=>e.isActive(`heading`,{level:2})},{id:`h3`,icon:`heading-3`,label:`Subheading`,run:e=>e.chain().focus().toggleHeading({level:3}).run(),active:e=>e.isActive(`heading`,{level:3})},{id:`quote`,icon:`quote`,label:`Quote`,run:e=>e.chain().focus().toggleBlockquote().run(),active:e=>e.isActive(`blockquote`)}],[{id:`ul`,icon:`list`,label:`Bulleted list`,run:e=>e.chain().focus().toggleBulletList().run(),active:e=>e.isActive(`bulletList`)},{id:`ol`,icon:`list-ordered`,label:`Numbered list`,run:e=>e.chain().focus().toggleOrderedList().run(),active:e=>e.isActive(`orderedList`)}],[{id:`undo`,icon:`undo`,label:`Undo`,run:e=>e.chain().focus().undo().run()},{id:`redo`,icon:`redo`,label:`Redo`,run:e=>e.chain().focus().redo().run()}]],v=(0,a.forwardRef)(function(n,r){let{placeholder:i=`Write something…`,size:l=`md`,isDisabled:u=!1,isInvalid:p=!1,label:v=`Rich text editor`,className:y,toolbarExtra:b,id:x,isRequired:S,"aria-labelledby":C,"aria-describedby":w,"aria-invalid":T}=n,[E,D]=(0,a.useState)(!1),[O,k]=(0,a.useState)(null),A=(0,a.useCallback)(()=>k(null),[]),[j]=(0,a.useState)(()=>n.defaultValue??(n.format===`json`?d:``)),M=n.value===void 0?j:n.value,N=(0,a.useMemo)(()=>n.format===`json`?h(M):void 0,[n.format,M]),P=(0,a.useId)(),F=p||!!N||T,I=u||!!N;I&&O&&k(null);let L=(0,a.useCallback)((e,t)=>{if(I)return;let n=t===void 0?void 0:(0,s.getMarkRange)(e.doc.resolve(t),e.schema.marks.link),r=n&&e.doc.nodeAt(n.from)?.marks.find(t=>t.type===e.schema.marks.link);k({from:n?.from??e.selection.from,to:n?.to??e.selection.to,href:r?.attrs.href??``,isEditing:!!r,document:e.doc})},[I]),R=(0,a.useMemo)(()=>({role:`textbox`,"aria-label":v,"aria-multiline":`true`,...x?{id:x}:{},...C?{"aria-labelledby":C}:{},...w?{"aria-describedby":w}:{},...F?{"aria-invalid":String(F)}:{},...S?{"aria-required":`true`}:{}}),[v,x,C,w,F,S]),z=(0,a.useMemo)(()=>({attributes:R,handleDOMEvents:{click:(e,t)=>{let n=t.target instanceof Element?t.target.closest(`a`):null;return!n||!e.dom.contains(n)?!1:(t.preventDefault(),e.editable&&L(e.state,e.posAtDOM(n,0)),!0)}}}),[R,L]),B=(0,s.useEditor)({immediatelyRender:!1,editable:!I,content:N?d:typeof M==`string`?M:m(M),extensions:[...f(),c.Placeholder.configure({placeholder:i})],editorProps:z,onFocus:()=>D(!0),onBlur:()=>D(!1),onUpdate:({editor:e})=>{I||(n.format===`json`?n.onChange?.(e.getJSON()):n.onChange?.(e.getHTML()))}});(0,a.useEffect)(()=>{B&&(B.setEditable(!I,!1),B.setOptions({editorProps:z}))},[B,I,z]),(0,a.useEffect)(()=>{if(!B||n.value===void 0||N)return;let e=typeof n.value==`string`?(0,s.createDocument)(n.value,B.schema):B.schema.nodeFromJSON(m(n.value));e.eq(B.state.doc)||B.commands.setContent(e,{emitUpdate:!1})},[B,n.value,N]);let V=(0,s.useEditorState)({editor:B,selector:({editor:e})=>e?{active:Object.fromEntries(_.flat().map(t=>[t.id,t.active?.(e)??!1])),linkActive:e.isActive(`link`)}:null});return(0,o.jsxs)(`div`,{ref:r,className:[`ds-rte`,y].filter(Boolean).join(` `),"data-focused":E||void 0,"data-disabled":I||void 0,"aria-invalid":F||void 0,children:[N&&(0,o.jsx)(`p`,{id:P,role:`alert`,className:`ds-field__error`,children:N}),(0,o.jsxs)(`div`,{hidden:!!N,children:[(0,o.jsxs)(`div`,{className:`ds-rte__toolbar`,role:`toolbar`,"aria-label":`${v} formatting`,children:[_.map((n,r)=>(0,o.jsx)(t.ButtonGroup,{"aria-label":`Formatting ${r+1}`,children:n.map(t=>(0,o.jsx)(e.Button,{size:`sm`,isIconOnly:!0,iconStart:t.icon,"aria-label":t.label,title:t.label,"aria-pressed":t.active?V?.active[t.id]:void 0,variant:V?.active[t.id]?`active`:`neutral`,isDisabled:I||!B,onClick:()=>B&&t.run(B)},t.id))},r)),(0,o.jsx)(t.ButtonGroup,{"aria-label":`Link`,children:(0,o.jsx)(e.Button,{size:`sm`,isIconOnly:!0,iconStart:`link`,"aria-label":V?.linkActive?`Edit link`:`Add link`,title:V?.linkActive?`Edit link`:`Add link`,variant:V?.linkActive?`active`:`neutral`,isDisabled:I||!B,onClick:()=>B&&L(B.state,B.isActive(`link`)?B.state.selection.from:void 0)})}),b]}),(0,o.jsx)(`div`,{className:`ds-rte__content`,"data-size":l,children:(0,o.jsx)(s.EditorContent,{editor:B})})]}),B&&O&&!I&&(0,o.jsx)(g,{editor:B,selection:O,onClose:A})]})});Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return v}});
|
|
2
|
+
//# sourceMappingURL=RichTextEditor-DC_0oN1s.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_Fragment","Icon","cx","parts","AssetGrid","forwardRef","rest","Grid","className","isLoading","loadingCount","AssetTileSkeleton","i","children","delay","index","Skeleton","AssetTile","hasFailed","setHasFailed","useState","isLoaded","setIsLoaded","showImage","src","isSelected","isPending","
|
|
1
|
+
{"version":3,"file":"index.js","names":["_Fragment","Icon","Fragment$1","cx","parts","AssetGrid","forwardRef","rest","Grid","className","isLoading","loadingCount","AssetTileSkeleton","i","children","delay","index","Skeleton","AssetTile","hasFailed","setHasFailed","useState","isLoaded","setIsLoaded","showImage","src","isSelected","isPending","icon","actions","onSelect","name","meta","AssetGridEmpty","title","description","action"],"sources":["../../../src/components/AssetGrid/index.tsx"],"sourcesContent":["import {\n forwardRef,\n useState,\n type HTMLAttributes,\n type ReactNode,\n} from \"react\";\nimport { Grid } from \"../Grid\";\nimport { Icon } from \"../Icon\";\nimport type { IconName } from \"../Icon/icons\";\nimport { Skeleton } from \"../Skeleton\";\nimport \"./style.css\";\n\nfunction cx(...parts: (string | undefined | false)[]) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport interface AssetGridProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Renders placeholder tiles instead of children. The grid keeps its\n * geometry, so nothing moves when the real assets arrive.\n */\n isLoading?: boolean;\n /** How many placeholder tiles to show while loading. */\n loadingCount?: number;\n children?: ReactNode;\n}\n\n/**\n * The media library surface: an auto-filling grid of asset tiles. Sits inside\n * a `TableFrame` when it is the page's collection, bare inside a drawer.\n */\nexport const AssetGrid = forwardRef<HTMLDivElement, AssetGridProps>(function AssetGrid(\n { isLoading = false, loadingCount = 8, className, children, ...rest },\n ref,\n) {\n return (\n <Grid\n ref={ref}\n columns=\"auto\"\n gap=\"md\"\n minColumnWidth=\"var(--asset-tile-min-width)\"\n className={cx(\"ds-asset-grid\", className)}\n aria-busy={isLoading || undefined}\n {...rest}\n >\n {isLoading\n ? Array.from({ length: loadingCount }, (_, i) => <AssetTileSkeleton key={i} index={i} />)\n : children}\n </Grid>\n );\n});\n\nexport interface AssetTileSkeletonProps {\n /** Position in the grid — drives the stagger, nothing else. */\n index?: number;\n}\n\n/** One loading tile: thumbnail block, name line, meta line. */\nexport function AssetTileSkeleton({ index = 0 }: AssetTileSkeletonProps) {\n const delay = { animationDelay: `calc(var(--skeleton-stagger) * ${index})` };\n return (\n <div className=\"ds-asset-tile\" data-loading=\"true\" aria-hidden=\"true\">\n <Skeleton shape=\"block\" className=\"ds-asset-tile__thumb\" style={delay} />\n <div className=\"ds-asset-tile__text\">\n <Skeleton shape=\"text\" width=\"80%\" style={delay} />\n <Skeleton shape=\"text\" width=\"45%\" style={delay} />\n </div>\n </div>\n );\n}\n\nexport interface AssetTileProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\" | \"title\"> {\n /** File name, shown in full — asset names are how people find things again. */\n name: string;\n /** Thumbnail source. Omit for a non-image asset and pass an `icon` instead. */\n src?: string;\n /** Glyph shown when there is no thumbnail, or while one fails to load. */\n icon?: IconName;\n /** Second line: dimensions, size, date — whatever the library sorts by. */\n meta?: ReactNode;\n /** Paints the soft fill and the solid rail. Never changes the tile's size. */\n isSelected?: boolean;\n /** The asset is still uploading or processing: dimmed, with a spinner. */\n isPending?: boolean;\n /** Makes the whole tile a selection target. */\n onSelect?: () => void;\n /** Badges or a menu, pinned to the top of the thumbnail. */\n actions?: ReactNode;\n}\n\n/**\n * One asset in the library. Selection paints a fill and a rail exactly like a\n * table row, so a grid and a list read as the same collection in two shapes.\n */\nexport const AssetTile = forwardRef<HTMLDivElement, AssetTileProps>(function AssetTile(\n {\n name,\n src,\n icon = \"image\",\n meta,\n isSelected = false,\n isPending = false,\n onSelect,\n actions,\n className,\n ...rest\n },\n ref,\n) {\n const [hasFailed, setHasFailed] = useState(false);\n const [isLoaded, setIsLoaded] = useState(false);\n const showImage = Boolean(src) && !hasFailed;\n\n return (\n <div\n ref={ref}\n className={cx(\"ds-asset-tile\", className)}\n data-selected={isSelected || undefined}\n data-pending={isPending || undefined}\n {...rest}\n >\n <div className=\"ds-asset-tile__thumb\">\n {showImage ? (\n <>\n {!isLoaded && <Skeleton shape=\"block\" className=\"ds-asset-tile__thumb-skeleton\" />}\n <img\n src={src}\n alt=\"\"\n loading=\"lazy\"\n data-loaded={isLoaded || undefined}\n onLoad={() => setIsLoaded(true)}\n onError={() => setHasFailed(true)}\n />\n </>\n ) : (\n <span className=\"ds-asset-tile__placeholder\">\n <Icon name={hasFailed ? \"alert-triangle\" : icon} size={24} />\n </span>\n )}\n\n {isPending && (\n <span className=\"ds-asset-tile__pending\" role=\"status\">\n <Icon name=\"spinner\" size={20} className=\"ds-asset-tile__spinner\" />\n <span className=\"ds-asset-tile__pending-label\">Uploading</span>\n </span>\n )}\n\n {actions && <div className=\"ds-asset-tile__actions\">{actions}</div>}\n\n {onSelect && (\n <button\n type=\"button\"\n className=\"ds-asset-tile__hit\"\n aria-pressed={isSelected}\n disabled={isPending}\n onClick={onSelect}\n >\n <span className=\"ds-asset-tile__hit-label\">{name}</span>\n </button>\n )}\n </div>\n\n <div className=\"ds-asset-tile__text\">\n <span className=\"ds-asset-tile__name\">{name}</span>\n {meta && <span className=\"ds-asset-tile__meta\">{meta}</span>}\n </div>\n </div>\n );\n});\n\nexport interface AssetGridEmptyProps {\n title: string;\n description?: ReactNode;\n action?: ReactNode;\n}\n\n/** Nothing in the library yet — one action, the one that fills it. */\nexport function AssetGridEmpty({ title, description, action }: AssetGridEmptyProps) {\n return (\n <div className=\"ds-asset-empty\">\n <Icon name=\"image\" size={24} />\n <span className=\"ds-asset-empty__title\">{title}</span>\n {description && <span className=\"ds-asset-empty__description\">{description}</span>}\n {action}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require("../
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require("../Field/index.cjs"),require("../TextField/index.cjs"),require("../EntryPicker/index.cjs"),require("../NumberField/index.cjs"),require("../Switch/index.cjs");const e=require("../../chunks/EntryEditor-C32lKKnV.cjs");exports.EntryEditor=e.t,exports.validateEntryValues=e.n;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import "../EntryPicker/index.js";
|
|
2
1
|
import "../Field/index.js";
|
|
2
|
+
import "../TextField/index.js";
|
|
3
|
+
import "../EntryPicker/index.js";
|
|
3
4
|
import "../NumberField/index.js";
|
|
4
5
|
import "../Switch/index.js";
|
|
5
|
-
|
|
6
|
-
export { t as EntryEditor, n as validateEntryValues } from "../../chunks/EntryEditor-BF808OZR.js";
|
|
6
|
+
export { t as EntryEditor, n as validateEntryValues } from "../../chunks/EntryEditor-xVuiqtFo.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/Icon-CWsA1W83.cjs"),t=require("../Button/index.cjs"),n=require("../
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../chunks/Icon-CWsA1W83.cjs"),t=require("../Button/index.cjs"),n=require("../Modal/index.cjs"),r=require("../Badge/index.cjs"),i=require("../SearchField/index.cjs"),a=require("../SortableList/index.cjs");let o=require("react"),s=require("react/jsx-runtime");function c(...e){return e.filter(Boolean).join(` `)}function l(e,t){return!t||[e.title,e.subtitle,...e.keywords??[]].filter(Boolean).join(` `).toLowerCase().includes(t.toLowerCase())}function u({item:t}){return(0,s.jsx)(`span`,{className:`ds-entry__thumb`,children:t.imageUrl?(0,s.jsx)(`img`,{src:t.imageUrl,alt:``,loading:`lazy`}):(0,s.jsx)(e.t,{name:`file-text`,size:20})})}function d({items:d,value:f,defaultValue:p=[],onValueChange:m,mode:h=`multiple`,max:g,label:_=`Entries`,emptyLabel:v=`Nothing selected yet.`,addLabel:y=`Choose entries`,isReorderable:b=!0,isDisabled:x=!1,className:S}){let[C,w]=(0,o.useState)(p),T=f??C,[E,D]=(0,o.useState)(!1),[O,k]=(0,o.useState)(``),A=(0,o.useMemo)(()=>new Map(d.map(e=>[e.id,e])),[d]),j=(0,o.useMemo)(()=>d.filter(e=>l(e,O)),[d,O]),M=h===`multiple`&&g!==void 0&&T.length>=g,N=e=>{x||(f===void 0&&w(e),m?.(e))},P=e=>{h===`single`?(N(T[0]===e?[]:[e]),D(!1)):T.includes(e)?N(T.filter(t=>t!==e)):M||N([...T,e])},F=T.map(e=>A.get(e)??{id:e,title:e}),I=!x&&b&&h===`multiple`&&F.length>1,L=e=>(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(u,{item:e}),(0,s.jsxs)(`span`,{className:`ds-entry__body`,children:[(0,s.jsx)(`span`,{className:`ds-entry__title`,children:e.title}),e.subtitle&&(0,s.jsx)(`span`,{className:`ds-entry__subtitle`,children:e.subtitle})]})]});return(0,s.jsxs)(`div`,{className:c(`ds-entry-picker`,S),children:[(0,s.jsxs)(`div`,{className:`ds-entry-picker__head`,children:[(0,s.jsx)(`span`,{className:`ds-entry-picker__label`,children:_}),(0,s.jsx)(r.Badge,{shape:`count`,children:T.length})]}),F.length===0?(0,s.jsx)(`p`,{className:`ds-entry-picker__empty`,children:v}):I?(0,s.jsx)(a.SortableList,{items:T,onReorder:N,renderDragOverlay:e=>{let t=A.get(e);return t?(0,s.jsx)(`div`,{className:`ds-entry`,children:L(t)}):null},children:F.map(e=>(0,s.jsx)(a.SortableListItem,{id:e.id,label:e.title,action:(0,s.jsx)(t.Button,{variant:`simple`,size:`sm`,isIconOnly:!0,iconStart:`x`,"aria-label":`Remove ${e.title}`,isDisabled:x,onClick:()=>N(T.filter(t=>t!==e.id))}),children:(0,s.jsx)(`div`,{className:`ds-entry`,children:L(e)})},e.id))}):(0,s.jsx)(`ul`,{className:`ds-entry-picker__list`,children:F.map(e=>(0,s.jsxs)(`li`,{className:`ds-entry-picker__row`,children:[(0,s.jsx)(`div`,{className:`ds-entry`,children:L(e)}),(0,s.jsx)(t.Button,{variant:`simple`,size:`sm`,isIconOnly:!0,iconStart:`x`,"aria-label":`Remove ${e.title}`,isDisabled:x,onClick:()=>N(T.filter(t=>t!==e.id))})]},e.id))}),(0,s.jsxs)(`div`,{className:`ds-entry-picker__actions`,children:[(0,s.jsx)(t.Button,{variant:`neutral`,size:`sm`,iconStart:`plus`,isDisabled:x,onClick:()=>D(!0),children:y}),T.length>0&&(0,s.jsx)(t.Button,{variant:`simple`,size:`sm`,isDisabled:x,onClick:()=>N([]),children:`Clear`})]}),(0,s.jsxs)(n.Modal,{isOpen:E,onClose:()=>D(!1),title:y,description:h===`single`?`Choose one entry.`:g===void 0?`Choose as many entries as you need.`:`Choose up to ${g} entries.`,footer:(0,s.jsx)(t.Button,{variant:`primary`,onClick:()=>D(!1),children:`Done`}),children:[(0,s.jsx)(`div`,{className:`ds-entry-picker__search`,children:(0,s.jsx)(i.SearchField,{value:O,placeholder:`Search entries`,onChange:e=>k(e.target.value),onClear:()=>k(``)})}),(0,s.jsxs)(`ul`,{className:`ds-entry-picker__results`,children:[j.map(t=>{let n=T.includes(t.id),r=x||t.isDisabled||!n&&M;return(0,s.jsx)(`li`,{children:(0,s.jsxs)(`button`,{type:`button`,className:`ds-entry-picker__result`,"aria-pressed":n,disabled:r||void 0,onClick:()=>P(t.id),children:[(0,s.jsx)(`div`,{className:`ds-entry`,children:L(t)}),n&&(0,s.jsx)(e.t,{name:`check`,size:20})]})},t.id)}),j.length===0&&(0,s.jsxs)(`li`,{className:`ds-entry-picker__no-results`,children:[`No entries match “`,O,`”.`]})]})]})]})}exports.EntryPicker=d;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|