@drawnagency/primitives 0.1.60 → 0.1.61
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/dist/chunk-4OX3Z7SB.js +1421 -0
- package/dist/{chunk-RFZNNCAS.js → chunk-53DKVAB6.js} +1 -61
- package/dist/chunk-677NTHAZ.js +27 -0
- package/dist/chunk-7EOSDFS3.js +10 -0
- package/dist/{chunk-Q5EEYBMJ.js → chunk-AM5LZD6Q.js} +0 -25
- package/dist/chunk-UQ4OYRW7.js +670 -0
- package/dist/chunk-WDSVHKAH.js +54 -0
- package/dist/chunk-WLMJCNU7.js +70 -0
- package/dist/components/editor/index.js +640 -0
- package/dist/components/primitives/index.d.ts +10 -0
- package/dist/components/primitives/index.d.ts.map +1 -0
- package/dist/components/primitives/index.js +166 -0
- package/dist/components/sections/register-schemas.js +350 -2416
- package/dist/index.js +20 -14
- package/dist/lib/index.js +14 -8
- package/dist/schemas/index.js +6 -6
- package/dist/schemas/link.js +13 -0
- package/package.json +9 -1
- package/src/components/primitives/index.ts +11 -0
- /package/dist/{chunk-ZU2MKPTG.js → chunk-3DCG4DNU.js} +0 -0
|
@@ -1,17 +1,51 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
Checkbox,
|
|
3
|
+
DeleteButton,
|
|
4
|
+
DragHandle as DragHandle2,
|
|
5
|
+
FormLabel,
|
|
6
|
+
Input,
|
|
7
|
+
Popover,
|
|
8
|
+
PopoverItem,
|
|
9
|
+
SettingsButton,
|
|
10
|
+
SettingsForm,
|
|
11
|
+
buildBlockDragData,
|
|
12
|
+
buildBlockDropData,
|
|
13
|
+
canDropBlock,
|
|
14
|
+
isBlockDragData
|
|
15
|
+
} from "../../chunk-UQ4OYRW7.js";
|
|
16
|
+
import {
|
|
17
|
+
EditableGrid,
|
|
18
|
+
EditablePlainText,
|
|
19
|
+
EditableRichText,
|
|
20
|
+
MAX_CONTAINER_COLUMNS,
|
|
21
|
+
MediaBlock,
|
|
22
|
+
colSpanClass,
|
|
23
|
+
containerGridClass,
|
|
24
|
+
defineHeadingSection,
|
|
25
|
+
spacerHiddenClass,
|
|
26
|
+
useEditableCollection
|
|
27
|
+
} from "../../chunk-4OX3Z7SB.js";
|
|
28
|
+
import {
|
|
29
|
+
AddIcon,
|
|
30
|
+
DeleteIcon,
|
|
31
|
+
DragHandle,
|
|
32
|
+
IconButton
|
|
33
|
+
} from "../../chunk-WLMJCNU7.js";
|
|
34
|
+
import "../../chunk-CBWK3KPV.js";
|
|
4
35
|
import {
|
|
5
36
|
DEFAULT_LINK,
|
|
6
37
|
LinkValueSchema
|
|
7
|
-
} from "../../chunk-
|
|
38
|
+
} from "../../chunk-3DCG4DNU.js";
|
|
8
39
|
import {
|
|
9
|
-
cn,
|
|
10
40
|
curatedIcons,
|
|
11
|
-
getIcon
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
41
|
+
getIcon
|
|
42
|
+
} from "../../chunk-WDSVHKAH.js";
|
|
43
|
+
import {
|
|
44
|
+
sanitizeHtml
|
|
45
|
+
} from "../../chunk-53DKVAB6.js";
|
|
46
|
+
import {
|
|
47
|
+
cn
|
|
48
|
+
} from "../../chunk-7EOSDFS3.js";
|
|
15
49
|
import "../../chunk-ZGFAYZWB.js";
|
|
16
50
|
import {
|
|
17
51
|
getSectionSchema
|
|
@@ -31,177 +65,11 @@ import "../../chunk-JSBRDJBE.js";
|
|
|
31
65
|
|
|
32
66
|
// src/components/sections/LinkHeading/index.tsx
|
|
33
67
|
import { Heading1 } from "lucide-react";
|
|
34
|
-
|
|
35
|
-
// src/components/primitives/defineHeadingSection.tsx
|
|
36
|
-
import { z } from "zod";
|
|
37
|
-
|
|
38
|
-
// src/components/primitives/EditablePlainText.tsx
|
|
39
|
-
import {
|
|
40
|
-
useRef as useRef2,
|
|
41
|
-
useEffect as useEffect2,
|
|
42
|
-
useCallback as useCallback2,
|
|
43
|
-
createElement
|
|
44
|
-
} from "react";
|
|
45
|
-
|
|
46
|
-
// src/components/primitives/useEditablePlainText.ts
|
|
47
|
-
import { useState, useEffect, useRef, useCallback } from "react";
|
|
48
|
-
function useEditablePlainText({
|
|
49
|
-
value: propValue,
|
|
50
|
-
onChange,
|
|
51
|
-
multiline = false
|
|
52
|
-
}) {
|
|
53
|
-
const [value, setValue] = useState(propValue);
|
|
54
|
-
const lastPropValue = useRef(propValue);
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
if (propValue !== lastPropValue.current) {
|
|
57
|
-
setValue(propValue);
|
|
58
|
-
lastPropValue.current = propValue;
|
|
59
|
-
}
|
|
60
|
-
}, [propValue]);
|
|
61
|
-
const handleInput = useCallback((text) => {
|
|
62
|
-
setValue(text);
|
|
63
|
-
}, []);
|
|
64
|
-
const handleBlur = useCallback(() => {
|
|
65
|
-
if (value !== propValue) {
|
|
66
|
-
onChange(value);
|
|
67
|
-
lastPropValue.current = value;
|
|
68
|
-
}
|
|
69
|
-
}, [value, propValue, onChange]);
|
|
70
|
-
return {
|
|
71
|
-
value,
|
|
72
|
-
handleInput,
|
|
73
|
-
handleBlur,
|
|
74
|
-
shouldPreventEnter: !multiline
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// src/components/primitives/EditablePlainText.tsx
|
|
79
|
-
function EditablePlainText({
|
|
80
|
-
tag,
|
|
81
|
-
value,
|
|
82
|
-
onChange,
|
|
83
|
-
isEditMode,
|
|
84
|
-
multiline = false,
|
|
85
|
-
placeholder,
|
|
86
|
-
className,
|
|
87
|
-
...htmlAttrs
|
|
88
|
-
}) {
|
|
89
|
-
const ref = useRef2(null);
|
|
90
|
-
const {
|
|
91
|
-
value: localValue,
|
|
92
|
-
handleInput,
|
|
93
|
-
handleBlur,
|
|
94
|
-
shouldPreventEnter
|
|
95
|
-
} = useEditablePlainText({ value, onChange, multiline });
|
|
96
|
-
useEffect2(() => {
|
|
97
|
-
if (ref.current && ref.current.textContent !== localValue) {
|
|
98
|
-
ref.current.textContent = localValue;
|
|
99
|
-
}
|
|
100
|
-
}, [localValue]);
|
|
101
|
-
const onInput = useCallback2(() => {
|
|
102
|
-
if (ref.current) {
|
|
103
|
-
handleInput(ref.current.textContent || "");
|
|
104
|
-
}
|
|
105
|
-
}, [handleInput]);
|
|
106
|
-
const onKeyDown = useCallback2(
|
|
107
|
-
(e) => {
|
|
108
|
-
if (e.key === "Enter" && shouldPreventEnter) {
|
|
109
|
-
e.preventDefault();
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
[shouldPreventEnter]
|
|
113
|
-
);
|
|
114
|
-
const onPaste = useCallback2(
|
|
115
|
-
(e) => {
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
const text = e.clipboardData.getData("text/plain");
|
|
118
|
-
const selection = window.getSelection();
|
|
119
|
-
if (selection && selection.rangeCount > 0) {
|
|
120
|
-
const range = selection.getRangeAt(0);
|
|
121
|
-
range.deleteContents();
|
|
122
|
-
range.insertNode(document.createTextNode(text));
|
|
123
|
-
range.collapse(false);
|
|
124
|
-
selection.removeAllRanges();
|
|
125
|
-
selection.addRange(range);
|
|
126
|
-
}
|
|
127
|
-
if (ref.current) {
|
|
128
|
-
handleInput(ref.current.textContent || "");
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
[handleInput]
|
|
132
|
-
);
|
|
133
|
-
return createElement(
|
|
134
|
-
tag,
|
|
135
|
-
{
|
|
136
|
-
ref,
|
|
137
|
-
className: isEditMode && placeholder ? `editable-placeholder ${className ?? ""}` : className,
|
|
138
|
-
contentEditable: isEditMode ? "true" : void 0,
|
|
139
|
-
suppressContentEditableWarning: isEditMode || void 0,
|
|
140
|
-
onInput: isEditMode ? onInput : void 0,
|
|
141
|
-
onBlur: isEditMode ? handleBlur : void 0,
|
|
142
|
-
onKeyDown: isEditMode ? onKeyDown : void 0,
|
|
143
|
-
onPaste: isEditMode ? onPaste : void 0,
|
|
144
|
-
"data-placeholder": isEditMode && placeholder ? placeholder : void 0,
|
|
145
|
-
...htmlAttrs
|
|
146
|
-
},
|
|
147
|
-
value
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/components/primitives/HeadingSection.tsx
|
|
152
68
|
import { jsx } from "react/jsx-runtime";
|
|
153
|
-
function HeadingSection({ heading, tag, placeholder, className, onChange }) {
|
|
154
|
-
return /* @__PURE__ */ jsx(
|
|
155
|
-
EditablePlainText,
|
|
156
|
-
{
|
|
157
|
-
tag,
|
|
158
|
-
value: heading,
|
|
159
|
-
onChange: onChange ?? (() => {
|
|
160
|
-
}),
|
|
161
|
-
isEditMode: !!onChange,
|
|
162
|
-
placeholder,
|
|
163
|
-
id: toSectionId(heading),
|
|
164
|
-
className: cn("scroll-mt-20", className)
|
|
165
|
-
}
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// src/components/primitives/defineHeadingSection.tsx
|
|
170
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
171
|
-
function defineHeadingSection(config) {
|
|
172
|
-
const content = config.navExclusion ? z.object({ heading: z.string(), excludeFromNav: z.boolean().optional() }) : z.object({ heading: z.string() });
|
|
173
|
-
const schema8 = z.object({ type: z.literal(config.type), content });
|
|
174
|
-
return defineSection({
|
|
175
|
-
type: config.type,
|
|
176
|
-
label: config.label,
|
|
177
|
-
icon: config.icon,
|
|
178
|
-
schema: schema8,
|
|
179
|
-
navRole: config.navRole,
|
|
180
|
-
component: ({ content: content2, onChange }) => /* @__PURE__ */ jsx2(
|
|
181
|
-
HeadingSection,
|
|
182
|
-
{
|
|
183
|
-
heading: content2.content.heading,
|
|
184
|
-
tag: config.tag,
|
|
185
|
-
placeholder: config.placeholder,
|
|
186
|
-
onChange: onChange ? (heading) => onChange({ ...content2, content: { ...content2.content, heading } }) : void 0
|
|
187
|
-
}
|
|
188
|
-
),
|
|
189
|
-
defaults: () => ({ type: config.type, content: { heading: config.defaultHeading } }),
|
|
190
|
-
getLabel: (content2) => content2.content.heading,
|
|
191
|
-
...config.navExclusion ? {
|
|
192
|
-
settings: {
|
|
193
|
-
excludeFromNav: { type: "checkbox", label: "Exclude from navigation", default: false, target: "content" }
|
|
194
|
-
}
|
|
195
|
-
} : {}
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// src/components/sections/LinkHeading/index.tsx
|
|
200
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
201
69
|
var LinkHeading_default = defineHeadingSection({
|
|
202
70
|
type: "link_heading",
|
|
203
71
|
label: "Link Heading",
|
|
204
|
-
icon: /* @__PURE__ */
|
|
72
|
+
icon: /* @__PURE__ */ jsx(Heading1, { size: 18 }),
|
|
205
73
|
navRole: "h1",
|
|
206
74
|
tag: "h2",
|
|
207
75
|
placeholder: "Section heading",
|
|
@@ -210,11 +78,11 @@ var LinkHeading_default = defineHeadingSection({
|
|
|
210
78
|
|
|
211
79
|
// src/components/sections/SubHeading/index.tsx
|
|
212
80
|
import { Heading2 } from "lucide-react";
|
|
213
|
-
import { jsx as
|
|
81
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
214
82
|
var SubHeading_default = defineHeadingSection({
|
|
215
83
|
type: "sub_heading",
|
|
216
84
|
label: "Sub Heading",
|
|
217
|
-
icon: /* @__PURE__ */
|
|
85
|
+
icon: /* @__PURE__ */ jsx2(Heading2, { size: 18 }),
|
|
218
86
|
navRole: "h2",
|
|
219
87
|
tag: "h3",
|
|
220
88
|
placeholder: "Sub heading",
|
|
@@ -224,745 +92,27 @@ var SubHeading_default = defineHeadingSection({
|
|
|
224
92
|
|
|
225
93
|
// src/components/sections/SubSubHeading/index.tsx
|
|
226
94
|
import { Heading3 } from "lucide-react";
|
|
227
|
-
import { jsx as
|
|
95
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
228
96
|
var SubSubHeading_default = defineHeadingSection({
|
|
229
97
|
type: "sub_sub_heading",
|
|
230
98
|
label: "Sub Sub Heading",
|
|
231
|
-
icon: /* @__PURE__ */
|
|
99
|
+
icon: /* @__PURE__ */ jsx3(Heading3, { size: 18 }),
|
|
232
100
|
navRole: "h3",
|
|
233
101
|
tag: "h4",
|
|
234
102
|
placeholder: "Sub sub heading",
|
|
235
103
|
defaultHeading: "New Sub Sub Heading",
|
|
236
|
-
navExclusion: true
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
// src/components/sections/Prose/index.tsx
|
|
240
|
-
import { z
|
|
241
|
-
import { AlignLeft } from "lucide-react";
|
|
242
|
-
|
|
243
|
-
// src/components/primitives/EditableRichText.tsx
|
|
244
|
-
import { useRef as useRef4, useCallback as useCallback4, useEffect as useEffect4 } from "react";
|
|
245
|
-
import { EditorContent } from "@tiptap/react";
|
|
246
|
-
import { BubbleMenu } from "@tiptap/react/menus";
|
|
247
|
-
|
|
248
|
-
// src/components/primitives/useEditableRichText.ts
|
|
249
|
-
import { useState as useState2, useRef as useRef3, useCallback as useCallback3, useEffect as useEffect3 } from "react";
|
|
250
|
-
import { Editor } from "@tiptap/core";
|
|
251
|
-
import Placeholder from "@tiptap/extension-placeholder";
|
|
252
|
-
|
|
253
|
-
// src/components/primitives/tiptap-presets.ts
|
|
254
|
-
import StarterKit from "@tiptap/starter-kit";
|
|
255
|
-
import Underline from "@tiptap/extension-underline";
|
|
256
|
-
import Link from "@tiptap/extension-link";
|
|
257
|
-
|
|
258
|
-
// ../../node_modules/.pnpm/@tiptap+extension-paragraph@3.22.4_@tiptap+core@3.22.4_@tiptap+pm@3.22.4_/node_modules/@tiptap/extension-paragraph/dist/index.js
|
|
259
|
-
import { mergeAttributes, Node } from "@tiptap/core";
|
|
260
|
-
var EMPTY_PARAGRAPH_MARKDOWN = " ";
|
|
261
|
-
var NBSP_CHAR = "\xA0";
|
|
262
|
-
var Paragraph = Node.create({
|
|
263
|
-
name: "paragraph",
|
|
264
|
-
priority: 1e3,
|
|
265
|
-
addOptions() {
|
|
266
|
-
return {
|
|
267
|
-
HTMLAttributes: {}
|
|
268
|
-
};
|
|
269
|
-
},
|
|
270
|
-
group: "block",
|
|
271
|
-
content: "inline*",
|
|
272
|
-
parseHTML() {
|
|
273
|
-
return [{ tag: "p" }];
|
|
274
|
-
},
|
|
275
|
-
renderHTML({ HTMLAttributes }) {
|
|
276
|
-
return ["p", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
|
|
277
|
-
},
|
|
278
|
-
parseMarkdown: (token, helpers) => {
|
|
279
|
-
const tokens = token.tokens || [];
|
|
280
|
-
if (tokens.length === 1 && tokens[0].type === "image") {
|
|
281
|
-
return helpers.parseChildren([tokens[0]]);
|
|
282
|
-
}
|
|
283
|
-
const content = helpers.parseInline(tokens);
|
|
284
|
-
const hasExplicitEmptyParagraphMarker = tokens.length === 1 && tokens[0].type === "text" && (tokens[0].raw === EMPTY_PARAGRAPH_MARKDOWN || tokens[0].text === EMPTY_PARAGRAPH_MARKDOWN || tokens[0].raw === NBSP_CHAR || tokens[0].text === NBSP_CHAR);
|
|
285
|
-
if (hasExplicitEmptyParagraphMarker && content.length === 1 && content[0].type === "text" && (content[0].text === EMPTY_PARAGRAPH_MARKDOWN || content[0].text === NBSP_CHAR)) {
|
|
286
|
-
return helpers.createNode("paragraph", void 0, []);
|
|
287
|
-
}
|
|
288
|
-
return helpers.createNode("paragraph", void 0, content);
|
|
289
|
-
},
|
|
290
|
-
renderMarkdown: (node, h, ctx) => {
|
|
291
|
-
var _a, _b;
|
|
292
|
-
if (!node) {
|
|
293
|
-
return "";
|
|
294
|
-
}
|
|
295
|
-
const content = Array.isArray(node.content) ? node.content : [];
|
|
296
|
-
if (content.length === 0) {
|
|
297
|
-
const previousContent = Array.isArray((_a = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _a.content) ? ctx.previousNode.content : [];
|
|
298
|
-
const previousNodeIsEmptyParagraph = ((_b = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _b.type) === "paragraph" && previousContent.length === 0;
|
|
299
|
-
return previousNodeIsEmptyParagraph ? EMPTY_PARAGRAPH_MARKDOWN : "";
|
|
300
|
-
}
|
|
301
|
-
return h.renderChildren(content);
|
|
302
|
-
},
|
|
303
|
-
addCommands() {
|
|
304
|
-
return {
|
|
305
|
-
setParagraph: () => ({ commands }) => {
|
|
306
|
-
return commands.setNode(this.name);
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
},
|
|
310
|
-
addKeyboardShortcuts() {
|
|
311
|
-
return {
|
|
312
|
-
"Mod-Alt-0": () => this.editor.commands.setParagraph()
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
var index_default = Paragraph;
|
|
317
|
-
|
|
318
|
-
// src/components/primitives/CustomParagraph.ts
|
|
319
|
-
var ALLOWED_CLASSES = ["large", "lead-in"];
|
|
320
|
-
var CustomParagraph = index_default.extend({
|
|
321
|
-
addAttributes() {
|
|
322
|
-
return {
|
|
323
|
-
...this.parent?.(),
|
|
324
|
-
class: {
|
|
325
|
-
default: null,
|
|
326
|
-
parseHTML: (element) => {
|
|
327
|
-
const cls = element.getAttribute("class");
|
|
328
|
-
if (cls && ALLOWED_CLASSES.includes(cls)) {
|
|
329
|
-
return cls;
|
|
330
|
-
}
|
|
331
|
-
return null;
|
|
332
|
-
},
|
|
333
|
-
renderHTML: (attributes) => {
|
|
334
|
-
if (!attributes.class) return {};
|
|
335
|
-
return { class: attributes.class };
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// src/components/primitives/tiptap-presets.ts
|
|
343
|
-
var basic = [
|
|
344
|
-
StarterKit.configure({
|
|
345
|
-
paragraph: false,
|
|
346
|
-
heading: false,
|
|
347
|
-
blockquote: false,
|
|
348
|
-
bulletList: false,
|
|
349
|
-
orderedList: false,
|
|
350
|
-
listItem: false,
|
|
351
|
-
codeBlock: false,
|
|
352
|
-
horizontalRule: false,
|
|
353
|
-
code: false,
|
|
354
|
-
strike: false
|
|
355
|
-
}),
|
|
356
|
-
CustomParagraph,
|
|
357
|
-
Underline
|
|
358
|
-
];
|
|
359
|
-
var rich = [
|
|
360
|
-
StarterKit.configure({
|
|
361
|
-
paragraph: false,
|
|
362
|
-
heading: { levels: [3, 4] },
|
|
363
|
-
blockquote: false,
|
|
364
|
-
codeBlock: false,
|
|
365
|
-
horizontalRule: false,
|
|
366
|
-
code: false,
|
|
367
|
-
strike: false
|
|
368
|
-
}),
|
|
369
|
-
CustomParagraph,
|
|
370
|
-
Underline,
|
|
371
|
-
// `page` protocol: stable internal-page hrefs (page://{pageId}#{sectionId})
|
|
372
|
-
// resolved to real routes at SSR — see lib/links.ts.
|
|
373
|
-
Link.configure({ openOnClick: false, protocols: ["page"] })
|
|
374
|
-
];
|
|
375
|
-
var presets = { basic, rich };
|
|
376
|
-
|
|
377
|
-
// src/components/primitives/useEditableRichText.ts
|
|
378
|
-
function useEditableRichText({
|
|
379
|
-
value,
|
|
380
|
-
onChange,
|
|
381
|
-
preset,
|
|
382
|
-
placeholder
|
|
383
|
-
}) {
|
|
384
|
-
const editorRef = useRef3(null);
|
|
385
|
-
const [editor, setEditor] = useState2(null);
|
|
386
|
-
const valueRef = useRef3(value);
|
|
387
|
-
const onChangeRef = useRef3(onChange);
|
|
388
|
-
useEffect3(() => {
|
|
389
|
-
valueRef.current = value;
|
|
390
|
-
}, [value]);
|
|
391
|
-
useEffect3(() => {
|
|
392
|
-
onChangeRef.current = onChange;
|
|
393
|
-
}, [onChange]);
|
|
394
|
-
const activate = useCallback3(() => {
|
|
395
|
-
if (editorRef.current) return;
|
|
396
|
-
const extensions = placeholder ? [...presets[preset], Placeholder.configure({ placeholder })] : presets[preset];
|
|
397
|
-
const ed = new Editor({
|
|
398
|
-
extensions,
|
|
399
|
-
content: valueRef.current,
|
|
400
|
-
// Commit edits to onChange on every transaction, not only on deactivate().
|
|
401
|
-
// Without this, content lives only inside TipTap until blur; clicking a
|
|
402
|
-
// Save button while the editor is still focused flushes persistence before
|
|
403
|
-
// the (150ms-delayed) blur->deactivate commit fires, silently dropping the
|
|
404
|
-
// in-progress edit. Live-committing keeps persistence in sync continuously.
|
|
405
|
-
onUpdate: ({ editor: updated }) => {
|
|
406
|
-
const html = updated.getHTML();
|
|
407
|
-
if (html !== valueRef.current) {
|
|
408
|
-
valueRef.current = html;
|
|
409
|
-
onChangeRef.current(html);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
editorRef.current = ed;
|
|
414
|
-
setEditor(ed);
|
|
415
|
-
}, [preset, placeholder]);
|
|
416
|
-
const deactivate = useCallback3(() => {
|
|
417
|
-
const ed = editorRef.current;
|
|
418
|
-
if (!ed) return;
|
|
419
|
-
const html = ed.getHTML();
|
|
420
|
-
ed.destroy();
|
|
421
|
-
editorRef.current = null;
|
|
422
|
-
setEditor(null);
|
|
423
|
-
if (html !== valueRef.current) {
|
|
424
|
-
onChangeRef.current(html);
|
|
425
|
-
}
|
|
426
|
-
}, []);
|
|
427
|
-
useEffect3(() => {
|
|
428
|
-
return () => {
|
|
429
|
-
editorRef.current?.destroy();
|
|
430
|
-
editorRef.current = null;
|
|
431
|
-
};
|
|
432
|
-
}, []);
|
|
433
|
-
return {
|
|
434
|
-
isEditorActive: editor !== null,
|
|
435
|
-
editor,
|
|
436
|
-
activate,
|
|
437
|
-
deactivate
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// src/components/primitives/RichTextToolbar.tsx
|
|
442
|
-
import { useState as useState4 } from "react";
|
|
443
|
-
import { useEditorState } from "@tiptap/react";
|
|
444
|
-
|
|
445
|
-
// src/components/primitives/LinkPopover.tsx
|
|
446
|
-
import { useState as useState3 } from "react";
|
|
447
|
-
|
|
448
|
-
// src/components/shared/Button.tsx
|
|
449
|
-
import { forwardRef } from "react";
|
|
450
|
-
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
451
|
-
var boxSize = {
|
|
452
|
-
sm: "rounded px-3 py-1.5 text-xs font-medium",
|
|
453
|
-
md: "rounded px-4 py-2 text-sm font-medium"
|
|
454
|
-
};
|
|
455
|
-
var ghostSize = {
|
|
456
|
-
sm: "text-xs font-medium",
|
|
457
|
-
md: "text-sm font-medium"
|
|
458
|
-
};
|
|
459
|
-
var variantClasses = {
|
|
460
|
-
primary: "bg-base-contrast text-base-accent hover:bg-base-contrast/90",
|
|
461
|
-
brand: "bg-primary text-primary-contrast hover:opacity-90",
|
|
462
|
-
secondary: "border border-base-200 text-base-contrast hover:bg-base-accent",
|
|
463
|
-
destructive: "border border-red-600 text-red-600 hover:bg-red-600 hover:text-white"
|
|
464
|
-
};
|
|
465
|
-
var ghostToneClasses = {
|
|
466
|
-
neutral: "text-base-contrast-light hover:text-base-contrast",
|
|
467
|
-
destructive: "text-red-600 hover:text-red-800"
|
|
468
|
-
};
|
|
469
|
-
var Button = forwardRef(function Button2({
|
|
470
|
-
variant = "primary",
|
|
471
|
-
size = "sm",
|
|
472
|
-
tone = "neutral",
|
|
473
|
-
fullWidth = false,
|
|
474
|
-
isLoading = false,
|
|
475
|
-
loadingLabel,
|
|
476
|
-
disabled,
|
|
477
|
-
className,
|
|
478
|
-
children,
|
|
479
|
-
...rest
|
|
480
|
-
}, ref) {
|
|
481
|
-
const isGhost = variant === "ghost";
|
|
482
|
-
const resolvedDisabled = disabled || isLoading;
|
|
483
|
-
const label = isLoading && loadingLabel ? loadingLabel : children;
|
|
484
|
-
return /* @__PURE__ */ jsx6(
|
|
485
|
-
"button",
|
|
486
|
-
{
|
|
487
|
-
ref,
|
|
488
|
-
disabled: resolvedDisabled,
|
|
489
|
-
className: cn(
|
|
490
|
-
"inline-flex items-center justify-center transition-colors",
|
|
491
|
-
isGhost ? ghostSize[size] : boxSize[size],
|
|
492
|
-
isGhost ? ghostToneClasses[tone] : variantClasses[variant],
|
|
493
|
-
fullWidth && "w-full",
|
|
494
|
-
resolvedDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
|
495
|
-
className
|
|
496
|
-
),
|
|
497
|
-
...rest,
|
|
498
|
-
children: label
|
|
499
|
-
}
|
|
500
|
-
);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// src/components/shared/PagesContext.tsx
|
|
504
|
-
import { createContext, useContext } from "react";
|
|
505
|
-
var PagesContext = createContext({ pages: [], getPageHeadings: () => [] });
|
|
506
|
-
function usePages() {
|
|
507
|
-
return useContext(PagesContext);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// src/lib/links.ts
|
|
511
|
-
function internalHref(pageId, anchorSectionId) {
|
|
512
|
-
return `page://${pageId}${anchorSectionId ? `#${anchorSectionId}` : ""}`;
|
|
513
|
-
}
|
|
514
|
-
function parseInternalHref(href) {
|
|
515
|
-
const m = /^page:\/\/([^#]+)(?:#(.+))?$/.exec(href);
|
|
516
|
-
return m ? { pageId: m[1], anchorSectionId: m[2] ?? null } : null;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// src/components/primitives/LinkPopover.tsx
|
|
520
|
-
import { Fragment, jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
521
|
-
var selectClasses = "w-full rounded border border-base-contrast/20 bg-base px-2 py-1 text-sm text-base-contrast focus:outline-none focus:ring-1 focus:ring-primary";
|
|
522
|
-
function LinkPopover({ editor, onClose }) {
|
|
523
|
-
const { pages, getPageHeadings } = usePages();
|
|
524
|
-
const existingAttrs = editor.getAttributes("link");
|
|
525
|
-
const existingInternal = parseInternalHref(existingAttrs.href ?? "");
|
|
526
|
-
const [mode, setMode] = useState3(existingInternal ? "internal" : "external");
|
|
527
|
-
const [url, setUrl] = useState3(existingInternal ? "" : existingAttrs.href ?? "");
|
|
528
|
-
const [pageId, setPageId] = useState3(existingInternal?.pageId ?? "");
|
|
529
|
-
const [anchorId, setAnchorId] = useState3(existingInternal?.anchorSectionId ?? "");
|
|
530
|
-
const [openInNewTab, setOpenInNewTab] = useState3(
|
|
531
|
-
existingAttrs.target === "_blank"
|
|
532
|
-
);
|
|
533
|
-
const hasLink = Boolean(existingAttrs.href);
|
|
534
|
-
const headings = pageId ? getPageHeadings(pageId) : [];
|
|
535
|
-
const handleApply = () => {
|
|
536
|
-
if (mode === "internal") {
|
|
537
|
-
if (pageId) {
|
|
538
|
-
editor.chain().focus().extendMarkRange("link").setLink({ href: internalHref(pageId, anchorId || null), target: null }).run();
|
|
539
|
-
}
|
|
540
|
-
} else if (url.trim()) {
|
|
541
|
-
editor.chain().focus().extendMarkRange("link").setLink({ href: url.trim(), target: openInNewTab ? "_blank" : null }).run();
|
|
542
|
-
}
|
|
543
|
-
onClose();
|
|
544
|
-
};
|
|
545
|
-
const handleRemove = () => {
|
|
546
|
-
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
547
|
-
onClose();
|
|
548
|
-
};
|
|
549
|
-
const handleKeyDown = (e) => {
|
|
550
|
-
if (e.key === "Enter") {
|
|
551
|
-
e.preventDefault();
|
|
552
|
-
handleApply();
|
|
553
|
-
} else if (e.key === "Escape") {
|
|
554
|
-
e.preventDefault();
|
|
555
|
-
onClose();
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
return /* @__PURE__ */ jsxs(
|
|
559
|
-
"div",
|
|
560
|
-
{
|
|
561
|
-
className: "flex w-64 flex-col gap-2 rounded bg-base-accent p-3 shadow-lg",
|
|
562
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
563
|
-
onKeyDown: handleKeyDown,
|
|
564
|
-
children: [
|
|
565
|
-
/* @__PURE__ */ jsx7("div", { className: "flex gap-2", role: "tablist", children: ["external", "internal"].map((kind) => /* @__PURE__ */ jsx7(
|
|
566
|
-
"button",
|
|
567
|
-
{
|
|
568
|
-
type: "button",
|
|
569
|
-
role: "tab",
|
|
570
|
-
"aria-selected": mode === kind,
|
|
571
|
-
onClick: () => setMode(kind),
|
|
572
|
-
className: cn(
|
|
573
|
-
"cursor-pointer rounded border px-2 py-0.5 text-xs",
|
|
574
|
-
mode === kind ? "border-primary bg-primary text-primary-contrast" : "border-base-200 text-base-contrast"
|
|
575
|
-
),
|
|
576
|
-
children: kind === "external" ? "External URL" : "Internal page"
|
|
577
|
-
},
|
|
578
|
-
kind
|
|
579
|
-
)) }),
|
|
580
|
-
mode === "external" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
581
|
-
/* @__PURE__ */ jsx7(
|
|
582
|
-
"input",
|
|
583
|
-
{
|
|
584
|
-
autoFocus: true,
|
|
585
|
-
type: "url",
|
|
586
|
-
value: url,
|
|
587
|
-
onChange: (e) => setUrl(e.target.value),
|
|
588
|
-
placeholder: "https://example.com",
|
|
589
|
-
className: "rounded border border-base-contrast/20 bg-base px-2 py-1 text-sm text-base-contrast placeholder:text-base-contrast/40 focus:outline-none focus:ring-1 focus:ring-primary"
|
|
590
|
-
}
|
|
591
|
-
),
|
|
592
|
-
/* @__PURE__ */ jsxs("label", { className: "flex cursor-pointer items-center gap-2 text-sm text-base-contrast", children: [
|
|
593
|
-
/* @__PURE__ */ jsx7(
|
|
594
|
-
"input",
|
|
595
|
-
{
|
|
596
|
-
type: "checkbox",
|
|
597
|
-
checked: openInNewTab,
|
|
598
|
-
onChange: (e) => setOpenInNewTab(e.target.checked),
|
|
599
|
-
className: "accent-primary"
|
|
600
|
-
}
|
|
601
|
-
),
|
|
602
|
-
"Open in new tab"
|
|
603
|
-
] })
|
|
604
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
605
|
-
/* @__PURE__ */ jsxs(
|
|
606
|
-
"select",
|
|
607
|
-
{
|
|
608
|
-
autoFocus: true,
|
|
609
|
-
"aria-label": "Page",
|
|
610
|
-
value: pageId,
|
|
611
|
-
onChange: (e) => {
|
|
612
|
-
setPageId(e.target.value);
|
|
613
|
-
setAnchorId("");
|
|
614
|
-
},
|
|
615
|
-
className: selectClasses,
|
|
616
|
-
children: [
|
|
617
|
-
/* @__PURE__ */ jsx7("option", { value: "", children: "Select a page\u2026" }),
|
|
618
|
-
pages.map((p) => /* @__PURE__ */ jsx7("option", { value: p.id, children: p.title }, p.id))
|
|
619
|
-
]
|
|
620
|
-
}
|
|
621
|
-
),
|
|
622
|
-
/* @__PURE__ */ jsxs(
|
|
623
|
-
"select",
|
|
624
|
-
{
|
|
625
|
-
"aria-label": "Section",
|
|
626
|
-
value: anchorId,
|
|
627
|
-
disabled: !pageId,
|
|
628
|
-
onChange: (e) => setAnchorId(e.target.value),
|
|
629
|
-
className: cn(selectClasses, !pageId && "cursor-not-allowed opacity-50"),
|
|
630
|
-
children: [
|
|
631
|
-
/* @__PURE__ */ jsx7("option", { value: "", children: "None (top of page)" }),
|
|
632
|
-
headings.map((h) => /* @__PURE__ */ jsx7("option", { value: h.id, children: h.label }, h.id))
|
|
633
|
-
]
|
|
634
|
-
}
|
|
635
|
-
)
|
|
636
|
-
] }),
|
|
637
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
638
|
-
/* @__PURE__ */ jsx7(
|
|
639
|
-
Button,
|
|
640
|
-
{
|
|
641
|
-
variant: "brand",
|
|
642
|
-
size: "sm",
|
|
643
|
-
onMouseDown: (e) => {
|
|
644
|
-
e.preventDefault();
|
|
645
|
-
handleApply();
|
|
646
|
-
},
|
|
647
|
-
children: "Apply"
|
|
648
|
-
}
|
|
649
|
-
),
|
|
650
|
-
hasLink && /* @__PURE__ */ jsx7(
|
|
651
|
-
Button,
|
|
652
|
-
{
|
|
653
|
-
variant: "secondary",
|
|
654
|
-
size: "sm",
|
|
655
|
-
onMouseDown: (e) => {
|
|
656
|
-
e.preventDefault();
|
|
657
|
-
handleRemove();
|
|
658
|
-
},
|
|
659
|
-
children: "Remove"
|
|
660
|
-
}
|
|
661
|
-
),
|
|
662
|
-
/* @__PURE__ */ jsx7(
|
|
663
|
-
Button,
|
|
664
|
-
{
|
|
665
|
-
variant: "secondary",
|
|
666
|
-
size: "sm",
|
|
667
|
-
onMouseDown: (e) => {
|
|
668
|
-
e.preventDefault();
|
|
669
|
-
onClose();
|
|
670
|
-
},
|
|
671
|
-
children: "Cancel"
|
|
672
|
-
}
|
|
673
|
-
)
|
|
674
|
-
] })
|
|
675
|
-
]
|
|
676
|
-
}
|
|
677
|
-
);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// src/components/primitives/RichTextToolbar.tsx
|
|
681
|
-
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
682
|
-
function ToolbarButton({ isActive, onClick, title, children }) {
|
|
683
|
-
return /* @__PURE__ */ jsx8(
|
|
684
|
-
"button",
|
|
685
|
-
{
|
|
686
|
-
type: "button",
|
|
687
|
-
title,
|
|
688
|
-
"aria-label": title,
|
|
689
|
-
"aria-pressed": isActive,
|
|
690
|
-
onMouseDown: (e) => {
|
|
691
|
-
e.preventDefault();
|
|
692
|
-
onClick();
|
|
693
|
-
},
|
|
694
|
-
className: cn(
|
|
695
|
-
"cursor-pointer rounded px-2 py-1 text-sm font-medium transition-colors",
|
|
696
|
-
isActive ? "bg-primary text-primary-contrast" : "bg-base-accent text-base-contrast hover:opacity-80"
|
|
697
|
-
),
|
|
698
|
-
children
|
|
699
|
-
}
|
|
700
|
-
);
|
|
701
|
-
}
|
|
702
|
-
function Separator() {
|
|
703
|
-
return /* @__PURE__ */ jsx8("div", { className: "mx-1 h-5 w-px bg-base-contrast/20" });
|
|
704
|
-
}
|
|
705
|
-
function RichTextToolbar({ editor, preset }) {
|
|
706
|
-
const [showLinkPopover, setShowLinkPopover] = useState4(false);
|
|
707
|
-
const state = useEditorState({
|
|
708
|
-
editor,
|
|
709
|
-
selector: ({ editor: ed }) => ({
|
|
710
|
-
isBold: ed.isActive("bold"),
|
|
711
|
-
isItalic: ed.isActive("italic"),
|
|
712
|
-
isUnderline: ed.isActive("underline"),
|
|
713
|
-
isLink: ed.isActive("link"),
|
|
714
|
-
isBulletList: ed.isActive("bulletList"),
|
|
715
|
-
isOrderedList: ed.isActive("orderedList"),
|
|
716
|
-
isH3: ed.isActive("heading", { level: 3 }),
|
|
717
|
-
isH4: ed.isActive("heading", { level: 4 }),
|
|
718
|
-
isLarge: ed.isActive("paragraph", { class: "large" }),
|
|
719
|
-
isLeadIn: ed.isActive("paragraph", { class: "lead-in" })
|
|
720
|
-
})
|
|
721
|
-
});
|
|
722
|
-
const toggleParagraphVariant = (cls, isCurrentlyActive) => {
|
|
723
|
-
if (isCurrentlyActive) {
|
|
724
|
-
editor.chain().focus().setNode("paragraph").run();
|
|
725
|
-
} else {
|
|
726
|
-
editor.chain().focus().setNode("paragraph", { class: cls }).run();
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
return /* @__PURE__ */ jsxs2(
|
|
730
|
-
"div",
|
|
731
|
-
{
|
|
732
|
-
"data-testid": "rich-text-toolbar",
|
|
733
|
-
className: "flex items-center gap-1 rounded border border-base-contrast/10 bg-base-accent p-1 shadow-md",
|
|
734
|
-
children: [
|
|
735
|
-
/* @__PURE__ */ jsx8(
|
|
736
|
-
ToolbarButton,
|
|
737
|
-
{
|
|
738
|
-
isActive: state.isBold,
|
|
739
|
-
onClick: () => editor.chain().focus().toggleBold().run(),
|
|
740
|
-
title: "Bold",
|
|
741
|
-
children: /* @__PURE__ */ jsx8("strong", { children: "B" })
|
|
742
|
-
}
|
|
743
|
-
),
|
|
744
|
-
/* @__PURE__ */ jsx8(
|
|
745
|
-
ToolbarButton,
|
|
746
|
-
{
|
|
747
|
-
isActive: state.isItalic,
|
|
748
|
-
onClick: () => editor.chain().focus().toggleItalic().run(),
|
|
749
|
-
title: "Italic",
|
|
750
|
-
children: /* @__PURE__ */ jsx8("em", { children: "I" })
|
|
751
|
-
}
|
|
752
|
-
),
|
|
753
|
-
/* @__PURE__ */ jsx8(
|
|
754
|
-
ToolbarButton,
|
|
755
|
-
{
|
|
756
|
-
isActive: state.isUnderline,
|
|
757
|
-
onClick: () => editor.chain().focus().toggleUnderline().run(),
|
|
758
|
-
title: "Underline",
|
|
759
|
-
children: /* @__PURE__ */ jsx8("span", { className: "underline", children: "U" })
|
|
760
|
-
}
|
|
761
|
-
),
|
|
762
|
-
preset === "rich" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
763
|
-
/* @__PURE__ */ jsx8(Separator, {}),
|
|
764
|
-
/* @__PURE__ */ jsxs2("div", { className: "relative", children: [
|
|
765
|
-
/* @__PURE__ */ jsx8(
|
|
766
|
-
ToolbarButton,
|
|
767
|
-
{
|
|
768
|
-
isActive: state.isLink || showLinkPopover,
|
|
769
|
-
onClick: () => setShowLinkPopover((prev) => !prev),
|
|
770
|
-
title: "Link",
|
|
771
|
-
children: "\u{1F517}"
|
|
772
|
-
}
|
|
773
|
-
),
|
|
774
|
-
showLinkPopover && /* @__PURE__ */ jsx8("div", { className: "absolute left-0 top-full z-50 mt-1", children: /* @__PURE__ */ jsx8(
|
|
775
|
-
LinkPopover,
|
|
776
|
-
{
|
|
777
|
-
editor,
|
|
778
|
-
onClose: () => setShowLinkPopover(false)
|
|
779
|
-
}
|
|
780
|
-
) })
|
|
781
|
-
] }),
|
|
782
|
-
/* @__PURE__ */ jsx8(Separator, {}),
|
|
783
|
-
/* @__PURE__ */ jsx8(
|
|
784
|
-
ToolbarButton,
|
|
785
|
-
{
|
|
786
|
-
isActive: state.isBulletList,
|
|
787
|
-
onClick: () => editor.chain().focus().toggleBulletList().run(),
|
|
788
|
-
title: "Bullet List",
|
|
789
|
-
children: "\u2022\u2261"
|
|
790
|
-
}
|
|
791
|
-
),
|
|
792
|
-
/* @__PURE__ */ jsx8(
|
|
793
|
-
ToolbarButton,
|
|
794
|
-
{
|
|
795
|
-
isActive: state.isOrderedList,
|
|
796
|
-
onClick: () => editor.chain().focus().toggleOrderedList().run(),
|
|
797
|
-
title: "Ordered List",
|
|
798
|
-
children: "1\u2261"
|
|
799
|
-
}
|
|
800
|
-
),
|
|
801
|
-
/* @__PURE__ */ jsx8(Separator, {}),
|
|
802
|
-
/* @__PURE__ */ jsx8(
|
|
803
|
-
ToolbarButton,
|
|
804
|
-
{
|
|
805
|
-
isActive: state.isH3,
|
|
806
|
-
onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
807
|
-
title: "Heading 3",
|
|
808
|
-
children: "H3"
|
|
809
|
-
}
|
|
810
|
-
),
|
|
811
|
-
/* @__PURE__ */ jsx8(
|
|
812
|
-
ToolbarButton,
|
|
813
|
-
{
|
|
814
|
-
isActive: state.isH4,
|
|
815
|
-
onClick: () => editor.chain().focus().toggleHeading({ level: 4 }).run(),
|
|
816
|
-
title: "Heading 4",
|
|
817
|
-
children: "H4"
|
|
818
|
-
}
|
|
819
|
-
),
|
|
820
|
-
/* @__PURE__ */ jsx8(
|
|
821
|
-
ToolbarButton,
|
|
822
|
-
{
|
|
823
|
-
isActive: state.isLarge,
|
|
824
|
-
onClick: () => toggleParagraphVariant("large", state.isLarge),
|
|
825
|
-
title: "Large Paragraph",
|
|
826
|
-
children: "Lg"
|
|
827
|
-
}
|
|
828
|
-
),
|
|
829
|
-
/* @__PURE__ */ jsx8(
|
|
830
|
-
ToolbarButton,
|
|
831
|
-
{
|
|
832
|
-
isActive: state.isLeadIn,
|
|
833
|
-
onClick: () => toggleParagraphVariant("lead-in", state.isLeadIn),
|
|
834
|
-
title: "Lead-In",
|
|
835
|
-
children: "Li"
|
|
836
|
-
}
|
|
837
|
-
)
|
|
838
|
-
] })
|
|
839
|
-
]
|
|
840
|
-
}
|
|
841
|
-
);
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
// src/components/primitives/EditableRichText.tsx
|
|
845
|
-
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
846
|
-
function isContentEmpty(html) {
|
|
847
|
-
return html.replace(/<[^>]*>/g, "").trim().length === 0;
|
|
848
|
-
}
|
|
849
|
-
var DEFAULT_PLACEHOLDER = "Click to edit\u2026";
|
|
850
|
-
function EditableRichText({
|
|
851
|
-
value,
|
|
852
|
-
onChange,
|
|
853
|
-
isEditMode,
|
|
854
|
-
preset = "rich",
|
|
855
|
-
className,
|
|
856
|
-
placeholder = DEFAULT_PLACEHOLDER
|
|
857
|
-
}) {
|
|
858
|
-
const { isEditorActive, editor, activate, deactivate } = useEditableRichText({ value, onChange, preset, placeholder });
|
|
859
|
-
const wrapperRef = useRef4(null);
|
|
860
|
-
const blurTimeoutRef = useRef4(null);
|
|
861
|
-
const clickCoordsRef = useRef4(null);
|
|
862
|
-
useEffect4(() => {
|
|
863
|
-
return () => {
|
|
864
|
-
if (blurTimeoutRef.current) {
|
|
865
|
-
clearTimeout(blurTimeoutRef.current);
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
|
-
}, []);
|
|
869
|
-
useEffect4(() => {
|
|
870
|
-
if (!isEditorActive || !editor) return;
|
|
871
|
-
requestAnimationFrame(() => {
|
|
872
|
-
if (editor.isDestroyed) return;
|
|
873
|
-
const coords = clickCoordsRef.current;
|
|
874
|
-
if (coords) {
|
|
875
|
-
try {
|
|
876
|
-
const pos = editor.view.posAtCoords(coords);
|
|
877
|
-
if (pos) {
|
|
878
|
-
editor.commands.focus();
|
|
879
|
-
editor.commands.setTextSelection(pos.pos);
|
|
880
|
-
} else {
|
|
881
|
-
editor.commands.focus("end");
|
|
882
|
-
}
|
|
883
|
-
} catch {
|
|
884
|
-
editor.commands.focus("end");
|
|
885
|
-
} finally {
|
|
886
|
-
clickCoordsRef.current = null;
|
|
887
|
-
}
|
|
888
|
-
} else {
|
|
889
|
-
editor.commands.focus("end");
|
|
890
|
-
}
|
|
891
|
-
});
|
|
892
|
-
}, [isEditorActive, editor]);
|
|
893
|
-
const handleClick = useCallback4((e) => {
|
|
894
|
-
if (isEditMode && !isEditorActive) {
|
|
895
|
-
clickCoordsRef.current = { left: e.clientX, top: e.clientY };
|
|
896
|
-
activate();
|
|
897
|
-
}
|
|
898
|
-
}, [isEditMode, isEditorActive, activate]);
|
|
899
|
-
const handleFocus = useCallback4(() => {
|
|
900
|
-
if (blurTimeoutRef.current) {
|
|
901
|
-
clearTimeout(blurTimeoutRef.current);
|
|
902
|
-
blurTimeoutRef.current = null;
|
|
903
|
-
}
|
|
904
|
-
}, []);
|
|
905
|
-
const handleBlur = useCallback4(() => {
|
|
906
|
-
blurTimeoutRef.current = setTimeout(() => {
|
|
907
|
-
if (wrapperRef.current && !wrapperRef.current.contains(document.activeElement)) {
|
|
908
|
-
deactivate();
|
|
909
|
-
}
|
|
910
|
-
}, 150);
|
|
911
|
-
}, [deactivate]);
|
|
912
|
-
if (!isEditMode) {
|
|
913
|
-
return /* @__PURE__ */ jsx9(
|
|
914
|
-
"div",
|
|
915
|
-
{
|
|
916
|
-
className,
|
|
917
|
-
dangerouslySetInnerHTML: { __html: sanitizeHtml(value) }
|
|
918
|
-
}
|
|
919
|
-
);
|
|
920
|
-
}
|
|
921
|
-
if (!isEditorActive || !editor) {
|
|
922
|
-
const empty = isContentEmpty(value);
|
|
923
|
-
if (empty) {
|
|
924
|
-
return /* @__PURE__ */ jsx9("div", { className, onClick: handleClick, children: /* @__PURE__ */ jsx9("p", { className: "tiptap-placeholder", children: placeholder }) });
|
|
925
|
-
}
|
|
926
|
-
return /* @__PURE__ */ jsx9(
|
|
927
|
-
"div",
|
|
928
|
-
{
|
|
929
|
-
className,
|
|
930
|
-
onClick: handleClick,
|
|
931
|
-
dangerouslySetInnerHTML: { __html: sanitizeHtml(value) }
|
|
932
|
-
}
|
|
933
|
-
);
|
|
934
|
-
}
|
|
935
|
-
return /* @__PURE__ */ jsxs3(
|
|
936
|
-
"div",
|
|
937
|
-
{
|
|
938
|
-
ref: wrapperRef,
|
|
939
|
-
className,
|
|
940
|
-
onFocus: handleFocus,
|
|
941
|
-
onBlur: handleBlur,
|
|
942
|
-
children: [
|
|
943
|
-
/* @__PURE__ */ jsx9(
|
|
944
|
-
BubbleMenu,
|
|
945
|
-
{
|
|
946
|
-
editor,
|
|
947
|
-
className: "z-50",
|
|
948
|
-
shouldShow: ({ editor: ed, state }) => {
|
|
949
|
-
const { from, to } = state.selection;
|
|
950
|
-
return ed.isFocused && from !== to;
|
|
951
|
-
},
|
|
952
|
-
children: /* @__PURE__ */ jsx9(RichTextToolbar, { editor, preset })
|
|
953
|
-
}
|
|
954
|
-
),
|
|
955
|
-
/* @__PURE__ */ jsx9(EditorContent, { editor })
|
|
956
|
-
]
|
|
957
|
-
}
|
|
958
|
-
);
|
|
959
|
-
}
|
|
104
|
+
navExclusion: true
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// src/components/sections/Prose/index.tsx
|
|
108
|
+
import { z } from "zod";
|
|
109
|
+
import { AlignLeft } from "lucide-react";
|
|
960
110
|
|
|
961
111
|
// src/components/sections/Prose/Prose.tsx
|
|
962
|
-
import { jsx as
|
|
112
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
963
113
|
function Prose({ body, onChange }) {
|
|
964
114
|
if (onChange) {
|
|
965
|
-
return /* @__PURE__ */
|
|
115
|
+
return /* @__PURE__ */ jsx4("div", { className: "prose-content", children: /* @__PURE__ */ jsx4(
|
|
966
116
|
EditableRichText,
|
|
967
117
|
{
|
|
968
118
|
value: body,
|
|
@@ -973,7 +123,7 @@ function Prose({ body, onChange }) {
|
|
|
973
123
|
}
|
|
974
124
|
) });
|
|
975
125
|
}
|
|
976
|
-
return /* @__PURE__ */
|
|
126
|
+
return /* @__PURE__ */ jsx4(
|
|
977
127
|
"div",
|
|
978
128
|
{
|
|
979
129
|
className: "prose-content",
|
|
@@ -995,235 +145,46 @@ function pluralize(n, word) {
|
|
|
995
145
|
}
|
|
996
146
|
|
|
997
147
|
// src/components/sections/Prose/index.tsx
|
|
998
|
-
import { jsx as
|
|
999
|
-
var schema =
|
|
1000
|
-
type:
|
|
1001
|
-
content:
|
|
148
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
149
|
+
var schema = z.object({
|
|
150
|
+
type: z.literal("prose"),
|
|
151
|
+
content: z.object({ body: z.string() })
|
|
1002
152
|
});
|
|
1003
153
|
var Prose_default = defineSection({
|
|
1004
154
|
type: "prose",
|
|
1005
155
|
label: "Prose",
|
|
1006
|
-
icon: /* @__PURE__ */
|
|
156
|
+
icon: /* @__PURE__ */ jsx5(AlignLeft, { size: 18 }),
|
|
1007
157
|
schema,
|
|
1008
158
|
richTextFields: ["body"],
|
|
1009
|
-
component: ({ content, onChange }) => /* @__PURE__ */
|
|
159
|
+
component: ({ content, onChange }) => /* @__PURE__ */ jsx5(Prose, { body: content.content.body, onChange: onChange ? (c) => onChange(c) : void 0 }),
|
|
1010
160
|
defaults: () => ({ type: "prose", content: { body: "<p></p>" } }),
|
|
1011
161
|
getLabel: (content) => truncate(stripHtmlToPlainText(content.content.body), 60)
|
|
1012
162
|
});
|
|
1013
163
|
|
|
1014
164
|
// src/components/sections/Media/index.tsx
|
|
1015
|
-
import { z as
|
|
1016
|
-
import { Image as
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
// src/components/primitives/ResolvedMedia.tsx
|
|
1022
|
-
import { ImageIcon } from "lucide-react";
|
|
1023
|
-
|
|
1024
|
-
// src/hooks/useResolvedMedia.ts
|
|
1025
|
-
import { useMemo } from "react";
|
|
1026
|
-
|
|
1027
|
-
// src/components/shell/MediaLibraryContext.tsx
|
|
1028
|
-
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
1029
|
-
var MediaLibraryContext = createContext2(null);
|
|
1030
|
-
function useMediaLibrary() {
|
|
1031
|
-
return useContext2(MediaLibraryContext);
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
// src/hooks/useResolvedMedia.ts
|
|
1035
|
-
function useResolvedMedia(imageId) {
|
|
1036
|
-
const ctx = useMediaLibrary();
|
|
1037
|
-
return useMemo(() => {
|
|
1038
|
-
if (!imageId || !ctx) {
|
|
1039
|
-
return { src: void 0, srcset: void 0, poster: void 0, alt: "", kind: "image" };
|
|
1040
|
-
}
|
|
1041
|
-
const { manifest, pendingItems, pendingLocalUrls, siteConfig } = ctx;
|
|
1042
|
-
const sizes = siteConfig?.media?.sizes ?? [640, 1080, 1920];
|
|
1043
|
-
const manifestItem = manifest.images[imageId];
|
|
1044
|
-
const pendingItem = pendingItems.find((i) => i.id === imageId);
|
|
1045
|
-
const item = manifestItem ?? pendingItem;
|
|
1046
|
-
const alt = item?.alt ?? "";
|
|
1047
|
-
const kind = item?.kind ?? "image";
|
|
1048
|
-
const localUrl = pendingLocalUrls[imageId];
|
|
1049
|
-
if (localUrl) {
|
|
1050
|
-
return { src: localUrl, srcset: void 0, poster: void 0, alt, kind };
|
|
1051
|
-
}
|
|
1052
|
-
if (manifestItem) {
|
|
1053
|
-
const provider = getMediaProvider();
|
|
1054
|
-
const resolved = provider.resolve(manifestItem, sizes);
|
|
1055
|
-
if (resolved && resolved.tag === "img") {
|
|
1056
|
-
return {
|
|
1057
|
-
src: resolved.src,
|
|
1058
|
-
srcset: "srcSet" in resolved ? resolved.srcSet : void 0,
|
|
1059
|
-
poster: void 0,
|
|
1060
|
-
alt,
|
|
1061
|
-
kind
|
|
1062
|
-
};
|
|
1063
|
-
}
|
|
1064
|
-
if (resolved && resolved.tag === "video") {
|
|
1065
|
-
return { src: resolved.src, srcset: void 0, poster: resolved.poster, alt, kind };
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
return { src: void 0, srcset: void 0, poster: void 0, alt, kind };
|
|
1069
|
-
}, [imageId, ctx]);
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
// src/components/primitives/ResolvedMedia.tsx
|
|
1073
|
-
import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1074
|
-
function ResolvedMedia({
|
|
1075
|
-
imageId,
|
|
1076
|
-
src: propSrc,
|
|
1077
|
-
srcset: propSrcset,
|
|
1078
|
-
alt: propAlt,
|
|
1079
|
-
className,
|
|
1080
|
-
imgClassName,
|
|
1081
|
-
invertFrom
|
|
1082
|
-
}) {
|
|
1083
|
-
const resolved = useResolvedMedia(imageId);
|
|
1084
|
-
const src = propSrc || resolved.src;
|
|
1085
|
-
const srcset = propSrcset || resolved.srcset;
|
|
1086
|
-
const poster = resolved.poster;
|
|
1087
|
-
const alt = propAlt ?? resolved.alt;
|
|
1088
|
-
const kind = resolved.kind;
|
|
1089
|
-
const invertClass = invertFrom === "light" ? "invert dark:invert-0" : invertFrom === "dark" ? "dark:invert" : void 0;
|
|
1090
|
-
const mediaClass = cn("h-full w-full", imgClassName, invertClass);
|
|
1091
|
-
return /* @__PURE__ */ jsx12("div", { className, children: src ? kind === "video" ? /* @__PURE__ */ jsx12("video", { src, poster, muted: true, playsInline: true, loop: true, autoPlay: true, className: mediaClass }) : /* @__PURE__ */ jsx12("img", { src, srcSet: srcset, alt, className: mediaClass }) : /* @__PURE__ */ jsxs4("div", { className: "flex aspect-video h-full w-full flex-col items-center justify-center gap-1 rounded bg-base-accent text-base-contrast-light/50", children: [
|
|
1092
|
-
/* @__PURE__ */ jsx12(ImageIcon, { size: 24 }),
|
|
1093
|
-
/* @__PURE__ */ jsx12("span", { className: "text-sm", children: "No Image" })
|
|
1094
|
-
] }) });
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// src/components/primitives/ImageDropZone.tsx
|
|
1098
|
-
import { useState as useState5 } from "react";
|
|
1099
|
-
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1100
|
-
var ACCEPTED = /^(image|video)\//;
|
|
1101
|
-
function ImageDropZone({ onImageSelected, className, children }) {
|
|
1102
|
-
const mediaLibrary = useMediaLibrary();
|
|
1103
|
-
const [dragging, setDragging] = useState5(false);
|
|
1104
|
-
if (!mediaLibrary) return /* @__PURE__ */ jsx13(Fragment3, { children });
|
|
1105
|
-
const maxFileSize = mediaLibrary.siteConfig?.media.maxFileSize;
|
|
1106
|
-
const hasFiles = (e) => e.dataTransfer.types.includes("Files");
|
|
1107
|
-
const handleDragOver = (e) => {
|
|
1108
|
-
if (!hasFiles(e)) return;
|
|
1109
|
-
e.preventDefault();
|
|
1110
|
-
e.dataTransfer.dropEffect = "copy";
|
|
1111
|
-
setDragging(true);
|
|
1112
|
-
};
|
|
1113
|
-
const handleDragLeave = (e) => {
|
|
1114
|
-
if (!hasFiles(e)) return;
|
|
1115
|
-
const related = e.relatedTarget;
|
|
1116
|
-
if (related && e.currentTarget.contains(related)) return;
|
|
1117
|
-
setDragging(false);
|
|
1118
|
-
};
|
|
1119
|
-
const handleDrop = (e) => {
|
|
1120
|
-
if (!hasFiles(e)) return;
|
|
1121
|
-
e.preventDefault();
|
|
1122
|
-
e.stopPropagation();
|
|
1123
|
-
setDragging(false);
|
|
1124
|
-
const file = e.dataTransfer.files[0];
|
|
1125
|
-
if (!file) return;
|
|
1126
|
-
if (!ACCEPTED.test(file.type)) {
|
|
1127
|
-
mediaLibrary.reportRejectedUploads([{ name: file.name, reason: "type" }]);
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
if (maxFileSize && file.size > maxFileSize) {
|
|
1131
|
-
mediaLibrary.reportRejectedUploads([{ name: file.name, reason: "size" }]);
|
|
1132
|
-
return;
|
|
1133
|
-
}
|
|
1134
|
-
mediaLibrary.uploadFileWithCallback(file, onImageSelected);
|
|
1135
|
-
};
|
|
1136
|
-
return /* @__PURE__ */ jsxs5(
|
|
1137
|
-
"div",
|
|
1138
|
-
{
|
|
1139
|
-
className: cn("relative", className),
|
|
1140
|
-
onDragOver: handleDragOver,
|
|
1141
|
-
onDragLeave: handleDragLeave,
|
|
1142
|
-
onDrop: handleDrop,
|
|
1143
|
-
children: [
|
|
1144
|
-
children,
|
|
1145
|
-
dragging && /* @__PURE__ */ jsx13("div", { className: "pointer-events-none absolute inset-0 z-10 rounded-md border-2 border-primary bg-primary/5" })
|
|
1146
|
-
]
|
|
1147
|
-
}
|
|
1148
|
-
);
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
// src/components/sections/Media/MediaBlock.tsx
|
|
1152
|
-
import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1153
|
-
function MediaBlock({ refValue, options, link, dodont, isEditMode, onRefChange }) {
|
|
1154
|
-
const mediaLibrary = useMediaLibrary();
|
|
1155
|
-
const fit = refValue.objectFit ?? options.objectFit;
|
|
1156
|
-
const fitClass = fit === "cover" ? "object-cover" : "object-contain";
|
|
1157
|
-
const showBorder = refValue.border ?? options.border;
|
|
1158
|
-
const captionStr = refValue.caption ? Array.isArray(refValue.caption) ? refValue.caption.join("\n") : refValue.caption : "";
|
|
1159
|
-
const replace = onRefChange ? (imageId) => onRefChange({ ...refValue, imageId }) : void 0;
|
|
1160
|
-
const resolved = /* @__PURE__ */ jsx14(
|
|
1161
|
-
ResolvedMedia,
|
|
1162
|
-
{
|
|
1163
|
-
imageId: refValue.imageId || void 0,
|
|
1164
|
-
className: "h-full w-full",
|
|
1165
|
-
imgClassName: fitClass,
|
|
1166
|
-
invertFrom: refValue.invertFrom
|
|
1167
|
-
}
|
|
1168
|
-
);
|
|
1169
|
-
let media = isEditMode && replace ? /* @__PURE__ */ jsx14(ImageDropZone, { onImageSelected: replace, className: "h-full w-full", children: resolved }) : resolved;
|
|
1170
|
-
if (!isEditMode && link && link.kind === "external" && link.href) {
|
|
1171
|
-
media = /* @__PURE__ */ jsx14("a", { href: link.href, target: link.target, className: "group block", children: media });
|
|
1172
|
-
}
|
|
1173
|
-
const onImageClick = isEditMode && replace && mediaLibrary ? () => mediaLibrary.openSelectModal((imageId) => replace(imageId)) : void 0;
|
|
1174
|
-
return /* @__PURE__ */ jsxs6("figure", { children: [
|
|
1175
|
-
dodont && /* @__PURE__ */ jsx14("div", { className: "flex h-10 items-center justify-center pb-1", children: dodont === "do" ? /* @__PURE__ */ jsx14(Check, { size: 28, className: "text-green-600" }) : /* @__PURE__ */ jsx14(X, { size: 28, className: "text-red-600" }) }),
|
|
1176
|
-
/* @__PURE__ */ jsx14(
|
|
1177
|
-
"div",
|
|
1178
|
-
{
|
|
1179
|
-
"data-testid": "media-open-surface",
|
|
1180
|
-
className: cn(
|
|
1181
|
-
"overflow-hidden rounded-md",
|
|
1182
|
-
showBorder && "border border-base-200",
|
|
1183
|
-
options.square && "aspect-square",
|
|
1184
|
-
onImageClick && "cursor-pointer"
|
|
1185
|
-
),
|
|
1186
|
-
onClick: onImageClick,
|
|
1187
|
-
onPointerDown: onImageClick ? (e) => e.stopPropagation() : void 0,
|
|
1188
|
-
children: media
|
|
1189
|
-
}
|
|
1190
|
-
),
|
|
1191
|
-
options.showCaption && /* @__PURE__ */ jsx14("figcaption", { className: "mt-2 min-h-[1em] text-sm text-base-contrast-light", children: isEditMode && onRefChange ? /* @__PURE__ */ jsx14(
|
|
1192
|
-
EditablePlainText,
|
|
1193
|
-
{
|
|
1194
|
-
tag: "span",
|
|
1195
|
-
value: captionStr,
|
|
1196
|
-
onChange: (caption) => onRefChange({ ...refValue, caption: caption || void 0 }),
|
|
1197
|
-
isEditMode: true,
|
|
1198
|
-
placeholder: "Caption",
|
|
1199
|
-
className: "block min-h-[1em]"
|
|
1200
|
-
}
|
|
1201
|
-
) : captionStr || " " })
|
|
1202
|
-
] });
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
// src/components/sections/Media/index.tsx
|
|
1206
|
-
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1207
|
-
var schema2 = z3.object({
|
|
1208
|
-
type: z3.literal("media"),
|
|
1209
|
-
content: z3.object({
|
|
165
|
+
import { z as z2 } from "zod";
|
|
166
|
+
import { Image as ImageIcon } from "lucide-react";
|
|
167
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
168
|
+
var schema2 = z2.object({
|
|
169
|
+
type: z2.literal("media"),
|
|
170
|
+
content: z2.object({
|
|
1210
171
|
ref: SingleMediaReferenceSchema,
|
|
1211
172
|
link: LinkValueSchema.optional(),
|
|
1212
|
-
dodont:
|
|
173
|
+
dodont: z2.enum(["do", "dont"]).optional()
|
|
1213
174
|
}),
|
|
1214
|
-
options:
|
|
1215
|
-
square:
|
|
1216
|
-
showCaption:
|
|
1217
|
-
border:
|
|
1218
|
-
objectFit:
|
|
175
|
+
options: z2.object({
|
|
176
|
+
square: z2.boolean().optional(),
|
|
177
|
+
showCaption: z2.boolean().optional(),
|
|
178
|
+
border: z2.boolean().optional(),
|
|
179
|
+
objectFit: z2.enum(["cover", "contain"]).optional()
|
|
1219
180
|
}).default({})
|
|
1220
181
|
});
|
|
1221
182
|
var Media_default = defineSection({
|
|
1222
183
|
type: "media",
|
|
1223
184
|
label: "Media",
|
|
1224
|
-
icon: /* @__PURE__ */
|
|
185
|
+
icon: /* @__PURE__ */ jsx6(ImageIcon, { size: 18 }),
|
|
1225
186
|
schema: schema2,
|
|
1226
|
-
component: ({ content, options, onChange }) => /* @__PURE__ */
|
|
187
|
+
component: ({ content, options, onChange }) => /* @__PURE__ */ jsx6(
|
|
1227
188
|
MediaBlock,
|
|
1228
189
|
{
|
|
1229
190
|
refValue: content.content.ref,
|
|
@@ -1277,19 +238,19 @@ var Media_default = defineSection({
|
|
|
1277
238
|
});
|
|
1278
239
|
|
|
1279
240
|
// src/components/sections/Button/index.tsx
|
|
1280
|
-
import { z as
|
|
241
|
+
import { z as z3 } from "zod";
|
|
1281
242
|
import { RectangleHorizontal } from "lucide-react";
|
|
1282
243
|
|
|
1283
244
|
// src/components/sections/Button/CTAButton.tsx
|
|
1284
245
|
import { Download } from "lucide-react";
|
|
1285
|
-
import { jsx as
|
|
1286
|
-
function
|
|
246
|
+
import { jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
247
|
+
function Button({ text, link, download, onChange }) {
|
|
1287
248
|
const base = "inline-block rounded-md px-6 py-3 font-bold transition-colors";
|
|
1288
249
|
const variant = "border-2 border-primary text-primary hover:bg-primary hover:text-primary-contrast";
|
|
1289
250
|
if (onChange) {
|
|
1290
|
-
return /* @__PURE__ */
|
|
1291
|
-
download && /* @__PURE__ */
|
|
1292
|
-
/* @__PURE__ */
|
|
251
|
+
return /* @__PURE__ */ jsxs("span", { className: cn(base, variant, "inline-flex items-center gap-2"), children: [
|
|
252
|
+
download && /* @__PURE__ */ jsx7(Download, { size: 16, className: "shrink-0" }),
|
|
253
|
+
/* @__PURE__ */ jsx7(
|
|
1293
254
|
EditablePlainText,
|
|
1294
255
|
{
|
|
1295
256
|
tag: "span",
|
|
@@ -1304,7 +265,7 @@ function Button3({ text, link, download, onChange }) {
|
|
|
1304
265
|
const href = link && link.kind === "external" ? link.href : "";
|
|
1305
266
|
const target = link?.target;
|
|
1306
267
|
if (href) {
|
|
1307
|
-
return /* @__PURE__ */
|
|
268
|
+
return /* @__PURE__ */ jsxs(
|
|
1308
269
|
"a",
|
|
1309
270
|
{
|
|
1310
271
|
href,
|
|
@@ -1312,488 +273,63 @@ function Button3({ text, link, download, onChange }) {
|
|
|
1312
273
|
download: download ? "" : void 0,
|
|
1313
274
|
className: cn(base, variant, download && "inline-flex items-center gap-2"),
|
|
1314
275
|
children: [
|
|
1315
|
-
download && /* @__PURE__ */
|
|
276
|
+
download && /* @__PURE__ */ jsx7(Download, { size: 16, className: "shrink-0" }),
|
|
1316
277
|
text
|
|
1317
278
|
]
|
|
1318
279
|
}
|
|
1319
280
|
);
|
|
1320
281
|
}
|
|
1321
|
-
return /* @__PURE__ */
|
|
282
|
+
return /* @__PURE__ */ jsx7("button", { className: cn("cursor-pointer", base, variant), children: text });
|
|
1322
283
|
}
|
|
1323
284
|
|
|
1324
285
|
// src/components/sections/Button/index.tsx
|
|
1325
|
-
import { jsx as
|
|
1326
|
-
var schema3 =
|
|
1327
|
-
type:
|
|
1328
|
-
content:
|
|
1329
|
-
text:
|
|
286
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
287
|
+
var schema3 = z3.object({
|
|
288
|
+
type: z3.literal("button"),
|
|
289
|
+
content: z3.object({
|
|
290
|
+
text: z3.string(),
|
|
1330
291
|
link: LinkValueSchema.optional(),
|
|
1331
|
-
download:
|
|
1332
|
-
})
|
|
1333
|
-
});
|
|
1334
|
-
var Button_default = defineSection({
|
|
1335
|
-
type: "button",
|
|
1336
|
-
label: "Button",
|
|
1337
|
-
icon: /* @__PURE__ */
|
|
1338
|
-
schema: schema3,
|
|
1339
|
-
component: ({ content, onChange }) => /* @__PURE__ */
|
|
1340
|
-
|
|
1341
|
-
{
|
|
1342
|
-
text: content.content.text,
|
|
1343
|
-
link: content.content.link,
|
|
1344
|
-
download: content.content.download,
|
|
1345
|
-
onChange: onChange ? (c) => onChange(c) : void 0
|
|
1346
|
-
}
|
|
1347
|
-
),
|
|
1348
|
-
defaults: () => ({ type: "button", content: { text: "Button" } }),
|
|
1349
|
-
getLabel: (content) => content.content.text,
|
|
1350
|
-
settings: {
|
|
1351
|
-
link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" },
|
|
1352
|
-
download: { type: "checkbox", label: "Download link", default: false, target: "content" }
|
|
1353
|
-
}
|
|
1354
|
-
});
|
|
1355
|
-
|
|
1356
|
-
// src/components/sections/Colors/index.tsx
|
|
1357
|
-
import { z as z5 } from "zod";
|
|
1358
|
-
import { Palette } from "lucide-react";
|
|
1359
|
-
|
|
1360
|
-
// src/components/brandguide/Colors.tsx
|
|
1361
|
-
import { useState as useState9, useEffect as useEffect7 } from "react";
|
|
1362
|
-
import { Eye, EyeOff } from "lucide-react";
|
|
1363
|
-
|
|
1364
|
-
// src/lib/container-grid.ts
|
|
1365
|
-
var MAX_CONTAINER_COLUMNS = 6;
|
|
1366
|
-
var containerGridClass = {
|
|
1367
|
-
1: "grid-cols-1",
|
|
1368
|
-
2: "grid-cols-1 @sm:grid-cols-2",
|
|
1369
|
-
3: "grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3",
|
|
1370
|
-
4: "grid-cols-1 @xs:grid-cols-2 @lg:grid-cols-4",
|
|
1371
|
-
5: "grid-cols-1 @xs:grid-cols-2 @md:grid-cols-3 @xl:grid-cols-5",
|
|
1372
|
-
6: "grid-cols-1 @xs:grid-cols-2 @md:grid-cols-3 @2xl:grid-cols-6"
|
|
1373
|
-
};
|
|
1374
|
-
var colSpanClass = {
|
|
1375
|
-
1: { 1: "" },
|
|
1376
|
-
2: { 1: "", 2: "col-span-1 @sm:col-span-2" },
|
|
1377
|
-
3: { 1: "", 2: "col-span-1 @sm:col-span-2", 3: "col-span-1 @sm:col-span-2 @lg:col-span-3" },
|
|
1378
|
-
4: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @lg:col-span-3", 4: "col-span-1 @xs:col-span-2 @lg:col-span-4" },
|
|
1379
|
-
5: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @md:col-span-3", 4: "col-span-1 @xs:col-span-2 @md:col-span-3 @xl:col-span-4", 5: "col-span-1 @xs:col-span-2 @md:col-span-3 @xl:col-span-5" },
|
|
1380
|
-
6: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @md:col-span-3", 4: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-4", 5: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-5", 6: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-6" }
|
|
1381
|
-
};
|
|
1382
|
-
var spacerHiddenClass = {
|
|
1383
|
-
1: "hidden",
|
|
1384
|
-
2: "hidden @sm:block",
|
|
1385
|
-
3: "hidden @sm:block",
|
|
1386
|
-
4: "hidden @xs:block",
|
|
1387
|
-
5: "hidden @xs:block",
|
|
1388
|
-
6: "hidden @xs:block"
|
|
1389
|
-
};
|
|
1390
|
-
|
|
1391
|
-
// src/components/primitives/EditableGrid.tsx
|
|
1392
|
-
import { useRef as useRef6, useEffect as useEffect6, useState as useState7 } from "react";
|
|
1393
|
-
import { ImageIcon as ImageIcon3 } from "lucide-react";
|
|
1394
|
-
|
|
1395
|
-
// src/components/shared/icons.tsx
|
|
1396
|
-
import { GripVertical, Plus, Trash2, X as X2, Settings } from "lucide-react";
|
|
1397
|
-
import { GripVertical as GripVertical2, Plus as Plus2, Trash2 as Trash22, X as X3, Settings as Settings2 } from "lucide-react";
|
|
1398
|
-
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1399
|
-
function DragHandle({ size = 16 }) {
|
|
1400
|
-
return /* @__PURE__ */ jsx18(GripVertical, { size });
|
|
1401
|
-
}
|
|
1402
|
-
function AddIcon({ size = 14 }) {
|
|
1403
|
-
return /* @__PURE__ */ jsx18(Plus, { size });
|
|
1404
|
-
}
|
|
1405
|
-
function DeleteIcon({ size = 14 }) {
|
|
1406
|
-
return /* @__PURE__ */ jsx18(Trash2, { size });
|
|
1407
|
-
}
|
|
1408
|
-
function SettingsIcon({ size = 14 }) {
|
|
1409
|
-
return /* @__PURE__ */ jsx18(Settings, { size });
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// src/components/shared/IconButton.tsx
|
|
1413
|
-
import { forwardRef as forwardRef2 } from "react";
|
|
1414
|
-
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1415
|
-
var sizeClasses = {
|
|
1416
|
-
sm: "h-chrome-sm w-chrome-sm",
|
|
1417
|
-
md: "h-chrome-md w-chrome-md",
|
|
1418
|
-
lg: "h-chrome-lg w-chrome-lg"
|
|
1419
|
-
};
|
|
1420
|
-
var intentClasses = {
|
|
1421
|
-
default: "text-base-contrast-light hover:text-base-contrast",
|
|
1422
|
-
destructive: "text-destructive hover:text-destructive-hover",
|
|
1423
|
-
primary: "text-primary/60 hover:text-primary"
|
|
1424
|
-
};
|
|
1425
|
-
var IconButton = forwardRef2(
|
|
1426
|
-
function IconButton2({ icon, label, size = "md", intent = "default", className, ...rest }, ref) {
|
|
1427
|
-
return /* @__PURE__ */ jsx19(
|
|
1428
|
-
"button",
|
|
1429
|
-
{
|
|
1430
|
-
ref,
|
|
1431
|
-
type: "button",
|
|
1432
|
-
className: cn(
|
|
1433
|
-
"cursor-pointer flex items-center justify-center rounded transition-colors",
|
|
1434
|
-
sizeClasses[size],
|
|
1435
|
-
intentClasses[intent],
|
|
1436
|
-
className
|
|
1437
|
-
),
|
|
1438
|
-
"aria-label": label,
|
|
1439
|
-
...rest,
|
|
1440
|
-
children: icon
|
|
1441
|
-
}
|
|
1442
|
-
);
|
|
1443
|
-
}
|
|
1444
|
-
);
|
|
1445
|
-
|
|
1446
|
-
// src/components/primitives/useEditableCollection.ts
|
|
1447
|
-
import { useState as useState6, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect5 } from "react";
|
|
1448
|
-
var nextId = 0;
|
|
1449
|
-
function uid() {
|
|
1450
|
-
return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `_id_${nextId++}_${Date.now()}`;
|
|
1451
|
-
}
|
|
1452
|
-
function wrapItems(items) {
|
|
1453
|
-
return items.map((data) => ({ id: uid(), data }));
|
|
1454
|
-
}
|
|
1455
|
-
function useEditableCollection({
|
|
1456
|
-
items,
|
|
1457
|
-
onChange,
|
|
1458
|
-
createItem
|
|
1459
|
-
}) {
|
|
1460
|
-
const [wrappedItems, setWrappedItems] = useState6(
|
|
1461
|
-
() => wrapItems(items)
|
|
1462
|
-
);
|
|
1463
|
-
const prevItemsRef = useRef5(items);
|
|
1464
|
-
useEffect5(() => {
|
|
1465
|
-
if (items === prevItemsRef.current) return;
|
|
1466
|
-
prevItemsRef.current = items;
|
|
1467
|
-
setWrappedItems((prev) => {
|
|
1468
|
-
return items.map((data, i) => {
|
|
1469
|
-
if (i < prev.length) {
|
|
1470
|
-
return { id: prev[i].id, data };
|
|
1471
|
-
}
|
|
1472
|
-
return { id: uid(), data };
|
|
1473
|
-
});
|
|
1474
|
-
});
|
|
1475
|
-
}, [items]);
|
|
1476
|
-
const onReorder = useCallback5(
|
|
1477
|
-
(fromIndex, toIndex) => {
|
|
1478
|
-
setWrappedItems((prev) => {
|
|
1479
|
-
const next = [...prev];
|
|
1480
|
-
const [moved] = next.splice(fromIndex, 1);
|
|
1481
|
-
next.splice(toIndex, 0, moved);
|
|
1482
|
-
onChange(next.map((w) => w.data));
|
|
1483
|
-
return next;
|
|
1484
|
-
});
|
|
1485
|
-
},
|
|
1486
|
-
[onChange]
|
|
1487
|
-
);
|
|
1488
|
-
const onAdd = useCallback5(() => {
|
|
1489
|
-
const newItem = createItem();
|
|
1490
|
-
setWrappedItems((prev) => {
|
|
1491
|
-
const next = [...prev, { id: uid(), data: newItem }];
|
|
1492
|
-
onChange(next.map((w) => w.data));
|
|
1493
|
-
return next;
|
|
1494
|
-
});
|
|
1495
|
-
}, [createItem, onChange]);
|
|
1496
|
-
const onInsert = useCallback5(
|
|
1497
|
-
(index) => {
|
|
1498
|
-
const newItem = createItem();
|
|
1499
|
-
setWrappedItems((prev) => {
|
|
1500
|
-
const next = [...prev];
|
|
1501
|
-
next.splice(index, 0, { id: uid(), data: newItem });
|
|
1502
|
-
onChange(next.map((w) => w.data));
|
|
1503
|
-
return next;
|
|
1504
|
-
});
|
|
1505
|
-
},
|
|
1506
|
-
[createItem, onChange]
|
|
1507
|
-
);
|
|
1508
|
-
const onRemove = useCallback5(
|
|
1509
|
-
(id) => {
|
|
1510
|
-
setWrappedItems((prev) => {
|
|
1511
|
-
const next = prev.filter((w) => w.id !== id);
|
|
1512
|
-
onChange(next.map((w) => w.data));
|
|
1513
|
-
return next;
|
|
1514
|
-
});
|
|
1515
|
-
},
|
|
1516
|
-
[onChange]
|
|
1517
|
-
);
|
|
1518
|
-
return { wrappedItems, onReorder, onAdd, onInsert, onRemove };
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
// src/components/primitives/EditableGrid.tsx
|
|
1522
|
-
import { jsx as jsx20, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1523
|
-
function EditableGrid({
|
|
1524
|
-
items,
|
|
1525
|
-
columns,
|
|
1526
|
-
onChange,
|
|
1527
|
-
createItem,
|
|
1528
|
-
isEditMode,
|
|
1529
|
-
renderItem,
|
|
1530
|
-
onItemSettings,
|
|
1531
|
-
onItemImageClick,
|
|
1532
|
-
chromeTopClass,
|
|
1533
|
-
className
|
|
1534
|
-
}) {
|
|
1535
|
-
const { wrappedItems, onReorder, onAdd, onInsert, onRemove } = useEditableCollection({
|
|
1536
|
-
items,
|
|
1537
|
-
onChange,
|
|
1538
|
-
createItem
|
|
1539
|
-
});
|
|
1540
|
-
const [dragState, setDragState] = useState7({ sourceId: null, closestEdge: null });
|
|
1541
|
-
const [isDragging, setIsDragging] = useState7(false);
|
|
1542
|
-
useEffect6(() => {
|
|
1543
|
-
let cleanup;
|
|
1544
|
-
let cancelled = false;
|
|
1545
|
-
import("../../adapter-HH47ZPGM.js").then(({ monitorForElements }) => {
|
|
1546
|
-
if (cancelled) return;
|
|
1547
|
-
cleanup = monitorForElements({
|
|
1548
|
-
onDragStart: ({ source }) => {
|
|
1549
|
-
if (source.data.dragType === "grid-cell") setIsDragging(true);
|
|
1550
|
-
},
|
|
1551
|
-
onDrop: ({ source }) => {
|
|
1552
|
-
if (source.data.dragType === "grid-cell") setIsDragging(false);
|
|
1553
|
-
}
|
|
1554
|
-
});
|
|
1555
|
-
});
|
|
1556
|
-
return () => {
|
|
1557
|
-
cancelled = true;
|
|
1558
|
-
cleanup?.();
|
|
1559
|
-
};
|
|
1560
|
-
}, []);
|
|
1561
|
-
if (!isEditMode) {
|
|
1562
|
-
return /* @__PURE__ */ jsx20("div", { className: "@container", children: /* @__PURE__ */ jsx20("div", { className: cn("grid gap-4", containerGridClass[columns] || containerGridClass[1], className), children: wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx20("div", { children: renderItem(wrapped.data, { isEditMode: false, index }) }, wrapped.id)) }) });
|
|
1563
|
-
}
|
|
1564
|
-
return /* @__PURE__ */ jsx20("div", { className: "@container", children: /* @__PURE__ */ jsxs8("div", { className: cn("group/grid relative grid gap-4", containerGridClass[columns] || containerGridClass[1], className), children: [
|
|
1565
|
-
wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx20(
|
|
1566
|
-
GridCell,
|
|
1567
|
-
{
|
|
1568
|
-
id: wrapped.id,
|
|
1569
|
-
index,
|
|
1570
|
-
isLast: index === wrappedItems.length - 1,
|
|
1571
|
-
isDragging,
|
|
1572
|
-
onReorder,
|
|
1573
|
-
onRemove,
|
|
1574
|
-
onInsert,
|
|
1575
|
-
onSettings: onItemSettings ? () => onItemSettings(index) : void 0,
|
|
1576
|
-
onImageClick: onItemImageClick ? () => onItemImageClick(index) : void 0,
|
|
1577
|
-
chromeTopClass,
|
|
1578
|
-
dragState,
|
|
1579
|
-
setDragState,
|
|
1580
|
-
children: renderItem(wrapped.data, { isEditMode: true, index })
|
|
1581
|
-
},
|
|
1582
|
-
wrapped.id
|
|
1583
|
-
)),
|
|
1584
|
-
/* @__PURE__ */ jsx20(
|
|
1585
|
-
IconButton,
|
|
1586
|
-
{
|
|
1587
|
-
icon: /* @__PURE__ */ jsx20(AddIcon, { size: 16 }),
|
|
1588
|
-
label: "Add item",
|
|
1589
|
-
size: "lg",
|
|
1590
|
-
intent: "primary",
|
|
1591
|
-
onClick: onAdd,
|
|
1592
|
-
className: "absolute -bottom-6 left-1/2 z-20 -translate-x-1/2 rounded-full border border-base-200 bg-base opacity-0 transition-opacity group-hover/grid:opacity-100"
|
|
1593
|
-
}
|
|
1594
|
-
)
|
|
1595
|
-
] }) });
|
|
1596
|
-
}
|
|
1597
|
-
function GridCell({
|
|
1598
|
-
id,
|
|
1599
|
-
index,
|
|
1600
|
-
isLast,
|
|
1601
|
-
isDragging,
|
|
1602
|
-
onReorder,
|
|
1603
|
-
onRemove,
|
|
1604
|
-
onInsert,
|
|
1605
|
-
onSettings,
|
|
1606
|
-
onImageClick,
|
|
1607
|
-
chromeTopClass,
|
|
1608
|
-
dragState,
|
|
1609
|
-
setDragState,
|
|
1610
|
-
children
|
|
1611
|
-
}) {
|
|
1612
|
-
const cellRef = useRef6(null);
|
|
1613
|
-
const handleRef = useRef6(null);
|
|
1614
|
-
useEffect6(() => {
|
|
1615
|
-
const cell = cellRef.current;
|
|
1616
|
-
const handle = handleRef.current;
|
|
1617
|
-
if (!cell || !handle) return;
|
|
1618
|
-
let cleanup;
|
|
1619
|
-
let cancelled = false;
|
|
1620
|
-
Promise.all([
|
|
1621
|
-
import("../../adapter-HH47ZPGM.js"),
|
|
1622
|
-
import("../../closest-edge-EBOXL3YW.js")
|
|
1623
|
-
]).then(([{ draggable, dropTargetForElements }, { attachClosestEdge, extractClosestEdge }]) => {
|
|
1624
|
-
if (cancelled) return;
|
|
1625
|
-
const cleanupDraggable = draggable({
|
|
1626
|
-
element: handle,
|
|
1627
|
-
getInitialData: () => ({ dragType: "grid-cell", id, index }),
|
|
1628
|
-
onDragStart: () => setDragState({ sourceId: id, closestEdge: null }),
|
|
1629
|
-
onDrop: () => setDragState({ sourceId: null, closestEdge: null })
|
|
1630
|
-
});
|
|
1631
|
-
const cleanupDropTarget = dropTargetForElements({
|
|
1632
|
-
element: cell,
|
|
1633
|
-
canDrop: ({ source }) => source.data.dragType === "grid-cell",
|
|
1634
|
-
getData: ({ input, element }) => attachClosestEdge(
|
|
1635
|
-
{ id, index },
|
|
1636
|
-
{ input, element, allowedEdges: ["left", "right"] }
|
|
1637
|
-
),
|
|
1638
|
-
onDragEnter: ({ self }) => {
|
|
1639
|
-
const edge = extractClosestEdge(self.data);
|
|
1640
|
-
if (edge) setDragState((prev) => ({ ...prev, closestEdge: { id, edge } }));
|
|
1641
|
-
},
|
|
1642
|
-
onDrag: ({ self }) => {
|
|
1643
|
-
const edge = extractClosestEdge(self.data);
|
|
1644
|
-
if (edge) setDragState((prev) => ({ ...prev, closestEdge: { id, edge } }));
|
|
1645
|
-
},
|
|
1646
|
-
onDragLeave: () => {
|
|
1647
|
-
setDragState((prev) => prev.closestEdge?.id === id ? { ...prev, closestEdge: null } : prev);
|
|
1648
|
-
},
|
|
1649
|
-
onDrop: ({ source, self }) => {
|
|
1650
|
-
const fromIndex = source.data.index;
|
|
1651
|
-
const edge = extractClosestEdge(self.data);
|
|
1652
|
-
let toIndex = index;
|
|
1653
|
-
if (edge === "right") toIndex = index + 1;
|
|
1654
|
-
if (fromIndex < toIndex) toIndex--;
|
|
1655
|
-
if (fromIndex !== toIndex) {
|
|
1656
|
-
onReorder(fromIndex, toIndex);
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
});
|
|
1660
|
-
cleanup = () => {
|
|
1661
|
-
cleanupDraggable();
|
|
1662
|
-
cleanupDropTarget();
|
|
1663
|
-
};
|
|
1664
|
-
});
|
|
1665
|
-
return () => {
|
|
1666
|
-
cancelled = true;
|
|
1667
|
-
cleanup?.();
|
|
1668
|
-
};
|
|
1669
|
-
}, [id, index, onReorder, setDragState]);
|
|
1670
|
-
const isCellDragging = dragState.sourceId === id;
|
|
1671
|
-
const showLeftEdge = dragState.closestEdge?.id === id && dragState.closestEdge.edge === "left" && dragState.sourceId !== id;
|
|
1672
|
-
const showRightEdge = dragState.closestEdge?.id === id && dragState.closestEdge.edge === "right" && dragState.sourceId !== id;
|
|
1673
|
-
return /* @__PURE__ */ jsxs8(
|
|
1674
|
-
"div",
|
|
1675
|
-
{
|
|
1676
|
-
ref: cellRef,
|
|
1677
|
-
className: cn(
|
|
1678
|
-
"group/cell relative",
|
|
1679
|
-
isCellDragging && "opacity-50"
|
|
1680
|
-
),
|
|
1681
|
-
children: [
|
|
1682
|
-
showLeftEdge && /* @__PURE__ */ jsx20("div", { className: "absolute top-0 bottom-0 left-0 z-10 w-0.5 -translate-x-2 bg-primary" }),
|
|
1683
|
-
showRightEdge && /* @__PURE__ */ jsx20("div", { className: "absolute top-0 right-0 bottom-0 z-10 w-0.5 translate-x-2 bg-primary" }),
|
|
1684
|
-
!isDragging && !isLast && /* @__PURE__ */ jsx20(
|
|
1685
|
-
IconButton,
|
|
1686
|
-
{
|
|
1687
|
-
icon: /* @__PURE__ */ jsx20(AddIcon, { size: 12 }),
|
|
1688
|
-
label: "Insert item",
|
|
1689
|
-
size: "sm",
|
|
1690
|
-
intent: "primary",
|
|
1691
|
-
onClick: () => onInsert(index + 1),
|
|
1692
|
-
className: "absolute top-1/2 -right-2 z-20 -translate-y-1/2 translate-x-1/2 rounded-full border border-base-200 bg-base opacity-0 group-hover/cell:opacity-100"
|
|
1693
|
-
}
|
|
1694
|
-
),
|
|
1695
|
-
/* @__PURE__ */ jsx20(
|
|
1696
|
-
IconButton,
|
|
1697
|
-
{
|
|
1698
|
-
ref: handleRef,
|
|
1699
|
-
icon: /* @__PURE__ */ jsx20(DragHandle, { size: 16 }),
|
|
1700
|
-
label: "Drag to reorder",
|
|
1701
|
-
className: cn("absolute left-1.5 z-10 cursor-grab bg-base/80 opacity-0 shadow-sm group-hover/cell:opacity-100 no-hover:opacity-100", chromeTopClass || "top-1.5"),
|
|
1702
|
-
tabIndex: -1
|
|
1703
|
-
}
|
|
1704
|
-
),
|
|
1705
|
-
/* @__PURE__ */ jsxs8("div", { className: cn("absolute right-1.5 z-10 flex items-center gap-1 opacity-0 group-hover/cell:opacity-100 no-hover:opacity-100", chromeTopClass || "top-1.5"), children: [
|
|
1706
|
-
onImageClick && /* @__PURE__ */ jsx20(
|
|
1707
|
-
IconButton,
|
|
1708
|
-
{
|
|
1709
|
-
icon: /* @__PURE__ */ jsx20(ImageIcon3, { size: 16 }),
|
|
1710
|
-
label: "Change image",
|
|
1711
|
-
onClick: onImageClick,
|
|
1712
|
-
className: "bg-base/80 shadow-sm"
|
|
1713
|
-
}
|
|
1714
|
-
),
|
|
1715
|
-
onSettings && /* @__PURE__ */ jsx20(
|
|
1716
|
-
IconButton,
|
|
1717
|
-
{
|
|
1718
|
-
icon: /* @__PURE__ */ jsx20(SettingsIcon, { size: 16 }),
|
|
1719
|
-
label: "Item settings",
|
|
1720
|
-
onClick: onSettings,
|
|
1721
|
-
className: "bg-base/80 shadow-sm"
|
|
1722
|
-
}
|
|
1723
|
-
),
|
|
1724
|
-
/* @__PURE__ */ jsx20(
|
|
1725
|
-
IconButton,
|
|
1726
|
-
{
|
|
1727
|
-
icon: /* @__PURE__ */ jsx20(DeleteIcon, { size: 16 }),
|
|
1728
|
-
label: "Delete item",
|
|
1729
|
-
intent: "destructive",
|
|
1730
|
-
onClick: () => onRemove(id),
|
|
1731
|
-
className: "bg-base/80 shadow-sm"
|
|
1732
|
-
}
|
|
1733
|
-
)
|
|
1734
|
-
] }),
|
|
1735
|
-
children
|
|
1736
|
-
]
|
|
1737
|
-
}
|
|
1738
|
-
);
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
// src/components/brandguide/ColorSwatchSettings.tsx
|
|
1742
|
-
import { useState as useState8 } from "react";
|
|
1743
|
-
|
|
1744
|
-
// src/components/shared/Input.tsx
|
|
1745
|
-
import { forwardRef as forwardRef3, useId } from "react";
|
|
1746
|
-
|
|
1747
|
-
// src/components/shared/FormLabel.tsx
|
|
1748
|
-
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1749
|
-
function FormLabel({ htmlFor, children, className }) {
|
|
1750
|
-
return /* @__PURE__ */ jsx21(
|
|
1751
|
-
"label",
|
|
292
|
+
download: z3.boolean().optional()
|
|
293
|
+
})
|
|
294
|
+
});
|
|
295
|
+
var Button_default = defineSection({
|
|
296
|
+
type: "button",
|
|
297
|
+
label: "Button",
|
|
298
|
+
icon: /* @__PURE__ */ jsx8(RectangleHorizontal, { size: 18 }),
|
|
299
|
+
schema: schema3,
|
|
300
|
+
component: ({ content, onChange }) => /* @__PURE__ */ jsx8(
|
|
301
|
+
Button,
|
|
1752
302
|
{
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
303
|
+
text: content.content.text,
|
|
304
|
+
link: content.content.link,
|
|
305
|
+
download: content.content.download,
|
|
306
|
+
onChange: onChange ? (c) => onChange(c) : void 0
|
|
1756
307
|
}
|
|
1757
|
-
)
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
const errorId = `${id}-error`;
|
|
1765
|
-
return /* @__PURE__ */ jsxs9("div", { className, children: [
|
|
1766
|
-
/* @__PURE__ */ jsx22(FormLabel, { htmlFor: id, children: label }),
|
|
1767
|
-
/* @__PURE__ */ jsx22(
|
|
1768
|
-
"input",
|
|
1769
|
-
{
|
|
1770
|
-
ref,
|
|
1771
|
-
id,
|
|
1772
|
-
type,
|
|
1773
|
-
value,
|
|
1774
|
-
onChange: (e) => onChange(e.target.value),
|
|
1775
|
-
disabled,
|
|
1776
|
-
"aria-invalid": error ? true : void 0,
|
|
1777
|
-
"aria-describedby": error ? errorId : void 0,
|
|
1778
|
-
className: cn(
|
|
1779
|
-
"w-full rounded border bg-base px-3 py-2 text-sm text-base-contrast focus:outline-none focus:ring-1",
|
|
1780
|
-
error ? "border-red-600 focus:border-red-600 focus:ring-red-600" : "border-base-200 focus:border-base-contrast focus:ring-base-contrast",
|
|
1781
|
-
disabled && "cursor-not-allowed opacity-50"
|
|
1782
|
-
),
|
|
1783
|
-
...rest
|
|
1784
|
-
}
|
|
1785
|
-
),
|
|
1786
|
-
error && /* @__PURE__ */ jsx22("p", { id: errorId, className: "mt-1 text-xs text-red-600", children: error })
|
|
1787
|
-
] });
|
|
308
|
+
),
|
|
309
|
+
defaults: () => ({ type: "button", content: { text: "Button" } }),
|
|
310
|
+
getLabel: (content) => content.content.text,
|
|
311
|
+
settings: {
|
|
312
|
+
link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" },
|
|
313
|
+
download: { type: "checkbox", label: "Download link", default: false, target: "content" }
|
|
314
|
+
}
|
|
1788
315
|
});
|
|
1789
316
|
|
|
317
|
+
// src/components/sections/Colors/index.tsx
|
|
318
|
+
import { z as z4 } from "zod";
|
|
319
|
+
import { Palette } from "lucide-react";
|
|
320
|
+
|
|
321
|
+
// src/components/brandguide/Colors.tsx
|
|
322
|
+
import { useState as useState2, useEffect } from "react";
|
|
323
|
+
import { Eye, EyeOff } from "lucide-react";
|
|
324
|
+
|
|
1790
325
|
// src/components/brandguide/ColorSwatchSettings.tsx
|
|
1791
|
-
import {
|
|
326
|
+
import { useState } from "react";
|
|
327
|
+
import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1792
328
|
function mergeSpaces(spaces) {
|
|
1793
329
|
return Object.assign({}, ...spaces);
|
|
1794
330
|
}
|
|
1795
331
|
function ColorSwatchSettings({ color, onChange }) {
|
|
1796
|
-
const [localColor, setLocalColor] =
|
|
332
|
+
const [localColor, setLocalColor] = useState(() => ({
|
|
1797
333
|
...color,
|
|
1798
334
|
spaces: [mergeSpaces(color.spaces)]
|
|
1799
335
|
}));
|
|
@@ -1806,8 +342,8 @@ function ColorSwatchSettings({ color, onChange }) {
|
|
|
1806
342
|
const newSpace = { ...space, [key]: value || void 0 };
|
|
1807
343
|
update({ ...localColor, spaces: [newSpace] });
|
|
1808
344
|
};
|
|
1809
|
-
return /* @__PURE__ */
|
|
1810
|
-
/* @__PURE__ */
|
|
345
|
+
return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
|
|
346
|
+
/* @__PURE__ */ jsx9(
|
|
1811
347
|
Input,
|
|
1812
348
|
{
|
|
1813
349
|
label: "Name",
|
|
@@ -1815,7 +351,7 @@ function ColorSwatchSettings({ color, onChange }) {
|
|
|
1815
351
|
onChange: (name) => update({ ...localColor, name })
|
|
1816
352
|
}
|
|
1817
353
|
),
|
|
1818
|
-
["hex", "rgb", "cmyk", "pantone"].map((key) => /* @__PURE__ */
|
|
354
|
+
["hex", "rgb", "cmyk", "pantone"].map((key) => /* @__PURE__ */ jsx9(
|
|
1819
355
|
Input,
|
|
1820
356
|
{
|
|
1821
357
|
label: key.toUpperCase(),
|
|
@@ -1828,7 +364,7 @@ function ColorSwatchSettings({ color, onChange }) {
|
|
|
1828
364
|
}
|
|
1829
365
|
|
|
1830
366
|
// src/components/brandguide/Colors.tsx
|
|
1831
|
-
import { jsx as
|
|
367
|
+
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1832
368
|
function getContrastClass(hex) {
|
|
1833
369
|
if (!hex) return "text-white";
|
|
1834
370
|
const h = hex.replace("#", "");
|
|
@@ -1853,7 +389,7 @@ function buildContent(colors, options) {
|
|
|
1853
389
|
}
|
|
1854
390
|
function Colors({ colors, columns = 3, label, collapsing, showLabel = true, onChange, openModal }) {
|
|
1855
391
|
if (onChange && openModal) {
|
|
1856
|
-
return /* @__PURE__ */
|
|
392
|
+
return /* @__PURE__ */ jsx10(
|
|
1857
393
|
ColorsEditable,
|
|
1858
394
|
{
|
|
1859
395
|
colors,
|
|
@@ -1866,7 +402,7 @@ function Colors({ colors, columns = 3, label, collapsing, showLabel = true, onCh
|
|
|
1866
402
|
}
|
|
1867
403
|
);
|
|
1868
404
|
}
|
|
1869
|
-
return /* @__PURE__ */
|
|
405
|
+
return /* @__PURE__ */ jsx10(ColorsView, { colors, columns, label, collapsing, showLabel });
|
|
1870
406
|
}
|
|
1871
407
|
function ColorsView({
|
|
1872
408
|
colors,
|
|
@@ -1875,8 +411,8 @@ function ColorsView({
|
|
|
1875
411
|
collapsing,
|
|
1876
412
|
showLabel
|
|
1877
413
|
}) {
|
|
1878
|
-
const [expanded, setExpanded] =
|
|
1879
|
-
const [copiedIndex, setCopiedIndex] =
|
|
414
|
+
const [expanded, setExpanded] = useState2(!collapsing);
|
|
415
|
+
const [copiedIndex, setCopiedIndex] = useState2(null);
|
|
1880
416
|
const handleCopy = (value, colorIndex) => {
|
|
1881
417
|
if (navigator.clipboard?.writeText) {
|
|
1882
418
|
navigator.clipboard.writeText(value);
|
|
@@ -1893,37 +429,37 @@ function ColorsView({
|
|
|
1893
429
|
setCopiedIndex(colorIndex);
|
|
1894
430
|
setTimeout(() => setCopiedIndex(null), 1500);
|
|
1895
431
|
};
|
|
1896
|
-
return /* @__PURE__ */
|
|
1897
|
-
(showLabel && !!label || collapsing) && /* @__PURE__ */
|
|
1898
|
-
showLabel && !!label && /* @__PURE__ */
|
|
1899
|
-
collapsing && /* @__PURE__ */
|
|
432
|
+
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
433
|
+
(showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs3("div", { className: "mb-4 flex items-center gap-2", children: [
|
|
434
|
+
showLabel && !!label && /* @__PURE__ */ jsx10("span", { className: "text-lg font-bold", children: label }),
|
|
435
|
+
collapsing && /* @__PURE__ */ jsxs3(
|
|
1900
436
|
"button",
|
|
1901
437
|
{
|
|
1902
438
|
onClick: () => setExpanded(!expanded),
|
|
1903
439
|
className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast",
|
|
1904
440
|
children: [
|
|
1905
|
-
/* @__PURE__ */
|
|
1906
|
-
expanded ? /* @__PURE__ */
|
|
441
|
+
/* @__PURE__ */ jsx10("span", { children: expanded ? "Hide Details" : "Show Details" }),
|
|
442
|
+
expanded ? /* @__PURE__ */ jsx10(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx10(Eye, { size: 16 })
|
|
1907
443
|
]
|
|
1908
444
|
}
|
|
1909
445
|
)
|
|
1910
446
|
] }),
|
|
1911
|
-
/* @__PURE__ */
|
|
447
|
+
/* @__PURE__ */ jsx10("div", { className: "@container", children: /* @__PURE__ */ jsx10("div", { className: cn("grid gap-4", containerGridClass[columns] || containerGridClass[3]), children: colors.map((color, i) => {
|
|
1912
448
|
const hex = color.spaces[0]?.hex;
|
|
1913
449
|
const contrast = getContrastClass(hex);
|
|
1914
|
-
return /* @__PURE__ */
|
|
1915
|
-
/* @__PURE__ */
|
|
1916
|
-
color.name && /* @__PURE__ */
|
|
1917
|
-
copiedIndex === i && /* @__PURE__ */
|
|
450
|
+
return /* @__PURE__ */ jsxs3("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
|
|
451
|
+
/* @__PURE__ */ jsxs3("div", { className: cn("relative flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: [
|
|
452
|
+
color.name && /* @__PURE__ */ jsx10("span", { className: "text-sm font-bold", children: color.name }),
|
|
453
|
+
copiedIndex === i && /* @__PURE__ */ jsx10("span", { className: cn(
|
|
1918
454
|
"absolute top-2 right-2 rounded-full px-2.5 py-0.5 text-xs font-medium",
|
|
1919
455
|
getContrastClass(hex) === "text-black" ? "bg-black/15 text-black" : "bg-white/25 text-white"
|
|
1920
456
|
), children: "Copied!" })
|
|
1921
457
|
] }),
|
|
1922
|
-
expanded && /* @__PURE__ */
|
|
458
|
+
expanded && /* @__PURE__ */ jsx10("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
|
|
1923
459
|
(space, j) => Object.entries(space).map(
|
|
1924
|
-
([key, value]) => value ? /* @__PURE__ */
|
|
1925
|
-
/* @__PURE__ */
|
|
1926
|
-
/* @__PURE__ */
|
|
460
|
+
([key, value]) => value ? /* @__PURE__ */ jsxs3("button", { onClick: () => handleCopy(value, i), className: "cursor-pointer flex w-full justify-between hover:text-primary", children: [
|
|
461
|
+
/* @__PURE__ */ jsx10("span", { className: "font-medium uppercase", children: key }),
|
|
462
|
+
/* @__PURE__ */ jsx10("span", { children: value })
|
|
1927
463
|
] }, `${j}-${key}`) : null
|
|
1928
464
|
)
|
|
1929
465
|
) })
|
|
@@ -1940,24 +476,24 @@ function ColorsEditable({
|
|
|
1940
476
|
onChange,
|
|
1941
477
|
openModal
|
|
1942
478
|
}) {
|
|
1943
|
-
const [expanded, setExpanded] =
|
|
479
|
+
const [expanded, setExpanded] = useState2(!collapsing);
|
|
1944
480
|
const options = { label, columns, collapsing, showLabel };
|
|
1945
|
-
|
|
481
|
+
useEffect(() => {
|
|
1946
482
|
setExpanded(!collapsing);
|
|
1947
483
|
}, [collapsing]);
|
|
1948
484
|
const handleItemSettings = (index) => {
|
|
1949
485
|
const color = colors[index];
|
|
1950
486
|
openModal(
|
|
1951
487
|
"Color Settings",
|
|
1952
|
-
/* @__PURE__ */
|
|
488
|
+
/* @__PURE__ */ jsx10(ColorSwatchSettings, { color, onChange: (updated) => {
|
|
1953
489
|
const newColors = colors.map((c, i) => i === index ? updated : c);
|
|
1954
490
|
onChange(buildContent(newColors, options));
|
|
1955
491
|
} })
|
|
1956
492
|
);
|
|
1957
493
|
};
|
|
1958
|
-
return /* @__PURE__ */
|
|
1959
|
-
(showLabel && !!label || collapsing) && /* @__PURE__ */
|
|
1960
|
-
showLabel && !!label && /* @__PURE__ */
|
|
494
|
+
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
495
|
+
(showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs3("div", { className: "mb-4 flex items-center gap-2", children: [
|
|
496
|
+
showLabel && !!label && /* @__PURE__ */ jsx10(
|
|
1961
497
|
EditablePlainText,
|
|
1962
498
|
{
|
|
1963
499
|
tag: "span",
|
|
@@ -1967,19 +503,19 @@ function ColorsEditable({
|
|
|
1967
503
|
className: "text-lg font-bold"
|
|
1968
504
|
}
|
|
1969
505
|
),
|
|
1970
|
-
collapsing && /* @__PURE__ */
|
|
506
|
+
collapsing && /* @__PURE__ */ jsxs3(
|
|
1971
507
|
"button",
|
|
1972
508
|
{
|
|
1973
509
|
onClick: () => setExpanded(!expanded),
|
|
1974
510
|
className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast",
|
|
1975
511
|
children: [
|
|
1976
|
-
/* @__PURE__ */
|
|
1977
|
-
expanded ? /* @__PURE__ */
|
|
512
|
+
/* @__PURE__ */ jsx10("span", { children: expanded ? "Hide Details" : "Show Details" }),
|
|
513
|
+
expanded ? /* @__PURE__ */ jsx10(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx10(Eye, { size: 16 })
|
|
1978
514
|
]
|
|
1979
515
|
}
|
|
1980
516
|
)
|
|
1981
517
|
] }),
|
|
1982
|
-
/* @__PURE__ */
|
|
518
|
+
/* @__PURE__ */ jsx10(
|
|
1983
519
|
EditableGrid,
|
|
1984
520
|
{
|
|
1985
521
|
items: colors,
|
|
@@ -1988,7 +524,7 @@ function ColorsEditable({
|
|
|
1988
524
|
createItem: createColorItem,
|
|
1989
525
|
isEditMode: true,
|
|
1990
526
|
onItemSettings: handleItemSettings,
|
|
1991
|
-
renderItem: (color, { index }) => /* @__PURE__ */
|
|
527
|
+
renderItem: (color, { index }) => /* @__PURE__ */ jsx10(
|
|
1992
528
|
ColorSwatchEditable,
|
|
1993
529
|
{
|
|
1994
530
|
color,
|
|
@@ -2017,8 +553,8 @@ function ColorSwatchEditable({
|
|
|
2017
553
|
const newColors = colors.map((c, i) => i === index ? updated : c);
|
|
2018
554
|
onChange(buildContent(newColors, options));
|
|
2019
555
|
};
|
|
2020
|
-
return /* @__PURE__ */
|
|
2021
|
-
/* @__PURE__ */
|
|
556
|
+
return /* @__PURE__ */ jsxs3("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
|
|
557
|
+
/* @__PURE__ */ jsx10("div", { className: cn("flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: /* @__PURE__ */ jsx10(
|
|
2022
558
|
EditablePlainText,
|
|
2023
559
|
{
|
|
2024
560
|
tag: "span",
|
|
@@ -2029,11 +565,11 @@ function ColorSwatchEditable({
|
|
|
2029
565
|
className: "text-sm font-bold"
|
|
2030
566
|
}
|
|
2031
567
|
) }),
|
|
2032
|
-
expanded && /* @__PURE__ */
|
|
568
|
+
expanded && /* @__PURE__ */ jsx10("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
|
|
2033
569
|
(space, j) => Object.entries(space).map(
|
|
2034
|
-
([key, value]) => value ? /* @__PURE__ */
|
|
2035
|
-
/* @__PURE__ */
|
|
2036
|
-
/* @__PURE__ */
|
|
570
|
+
([key, value]) => value ? /* @__PURE__ */ jsxs3("div", { className: "flex w-full justify-between", children: [
|
|
571
|
+
/* @__PURE__ */ jsx10("span", { className: "font-medium uppercase", children: key }),
|
|
572
|
+
/* @__PURE__ */ jsx10("span", { children: value })
|
|
2037
573
|
] }, `${j}-${key}`) : null
|
|
2038
574
|
)
|
|
2039
575
|
) })
|
|
@@ -2041,23 +577,23 @@ function ColorSwatchEditable({
|
|
|
2041
577
|
}
|
|
2042
578
|
|
|
2043
579
|
// src/components/sections/Colors/index.tsx
|
|
2044
|
-
import { jsx as
|
|
2045
|
-
var schema4 =
|
|
2046
|
-
type:
|
|
2047
|
-
content:
|
|
2048
|
-
options:
|
|
2049
|
-
label:
|
|
2050
|
-
columns:
|
|
2051
|
-
collapsing:
|
|
2052
|
-
showLabel:
|
|
580
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
581
|
+
var schema4 = z4.object({
|
|
582
|
+
type: z4.literal("colors"),
|
|
583
|
+
content: z4.object({ colors: z4.array(ColorItemSchema) }),
|
|
584
|
+
options: z4.object({
|
|
585
|
+
label: z4.string().optional(),
|
|
586
|
+
columns: z4.number().int().min(2).max(4).optional(),
|
|
587
|
+
collapsing: z4.boolean().optional(),
|
|
588
|
+
showLabel: z4.boolean().optional()
|
|
2053
589
|
}).optional()
|
|
2054
590
|
});
|
|
2055
591
|
var Colors_default = defineSection({
|
|
2056
592
|
type: "colors",
|
|
2057
593
|
label: "Colors",
|
|
2058
|
-
icon: /* @__PURE__ */
|
|
594
|
+
icon: /* @__PURE__ */ jsx11(Palette, { size: 18 }),
|
|
2059
595
|
schema: schema4,
|
|
2060
|
-
component: ({ content, options, onChange, openModal }) => /* @__PURE__ */
|
|
596
|
+
component: ({ content, options, onChange, openModal }) => /* @__PURE__ */ jsx11(
|
|
2061
597
|
Colors,
|
|
2062
598
|
{
|
|
2063
599
|
colors: content.content.colors,
|
|
@@ -2090,17 +626,17 @@ var Colors_default = defineSection({
|
|
|
2090
626
|
});
|
|
2091
627
|
|
|
2092
628
|
// src/components/sections/IconList/index.tsx
|
|
2093
|
-
import { z as
|
|
629
|
+
import { z as z5 } from "zod";
|
|
2094
630
|
import { List } from "lucide-react";
|
|
2095
631
|
|
|
2096
632
|
// src/components/sections/IconList/IconList.tsx
|
|
2097
|
-
import { useRef as
|
|
633
|
+
import { useRef as useRef2, useEffect as useEffect3, useState as useState4, useCallback } from "react";
|
|
2098
634
|
import { CopyPlus, Pencil } from "lucide-react";
|
|
2099
635
|
|
|
2100
636
|
// src/components/primitives/IconPicker.tsx
|
|
2101
|
-
import { useEffect as
|
|
2102
|
-
import { Check
|
|
2103
|
-
import { Fragment
|
|
637
|
+
import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
|
|
638
|
+
import { Check, X } from "lucide-react";
|
|
639
|
+
import { Fragment, jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2104
640
|
function IconPicker({
|
|
2105
641
|
selected,
|
|
2106
642
|
onSelect,
|
|
@@ -2110,9 +646,9 @@ function IconPicker({
|
|
|
2110
646
|
dodont,
|
|
2111
647
|
onSelectDoDont
|
|
2112
648
|
}) {
|
|
2113
|
-
const panelRef =
|
|
2114
|
-
const [mode, setMode] =
|
|
2115
|
-
|
|
649
|
+
const panelRef = useRef(null);
|
|
650
|
+
const [mode, setMode] = useState3(dodont ? "dodont" : "none");
|
|
651
|
+
useEffect2(() => {
|
|
2116
652
|
function handleMouseDown(e) {
|
|
2117
653
|
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
2118
654
|
onClose();
|
|
@@ -2122,14 +658,14 @@ function IconPicker({
|
|
|
2122
658
|
return () => document.removeEventListener("mousedown", handleMouseDown);
|
|
2123
659
|
}, [onClose]);
|
|
2124
660
|
const showDoDont = allowDoDont && mode === "dodont";
|
|
2125
|
-
return /* @__PURE__ */
|
|
661
|
+
return /* @__PURE__ */ jsxs4(
|
|
2126
662
|
"div",
|
|
2127
663
|
{
|
|
2128
664
|
ref: panelRef,
|
|
2129
665
|
className: "absolute z-50 w-56 rounded-lg border border-base-200 bg-base p-2 shadow-lg",
|
|
2130
666
|
children: [
|
|
2131
|
-
allowDoDont && /* @__PURE__ */
|
|
2132
|
-
/* @__PURE__ */
|
|
667
|
+
allowDoDont && /* @__PURE__ */ jsxs4("div", { role: "tablist", "aria-label": "Icon mode", className: "mb-2 flex gap-1 rounded-md bg-base-200 p-0.5", children: [
|
|
668
|
+
/* @__PURE__ */ jsx12(
|
|
2133
669
|
"button",
|
|
2134
670
|
{
|
|
2135
671
|
type: "button",
|
|
@@ -2147,7 +683,7 @@ function IconPicker({
|
|
|
2147
683
|
children: "None"
|
|
2148
684
|
}
|
|
2149
685
|
),
|
|
2150
|
-
/* @__PURE__ */
|
|
686
|
+
/* @__PURE__ */ jsx12(
|
|
2151
687
|
"button",
|
|
2152
688
|
{
|
|
2153
689
|
type: "button",
|
|
@@ -2163,8 +699,8 @@ function IconPicker({
|
|
|
2163
699
|
}
|
|
2164
700
|
)
|
|
2165
701
|
] }),
|
|
2166
|
-
showDoDont ? /* @__PURE__ */
|
|
2167
|
-
/* @__PURE__ */
|
|
702
|
+
showDoDont ? /* @__PURE__ */ jsxs4("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
703
|
+
/* @__PURE__ */ jsxs4(
|
|
2168
704
|
"button",
|
|
2169
705
|
{
|
|
2170
706
|
type: "button",
|
|
@@ -2176,12 +712,12 @@ function IconPicker({
|
|
|
2176
712
|
),
|
|
2177
713
|
onClick: () => onSelectDoDont?.("do"),
|
|
2178
714
|
children: [
|
|
2179
|
-
/* @__PURE__ */
|
|
2180
|
-
/* @__PURE__ */
|
|
715
|
+
/* @__PURE__ */ jsx12(Check, { size: 20 }),
|
|
716
|
+
/* @__PURE__ */ jsx12("span", { className: "text-xs font-medium", children: "Do" })
|
|
2181
717
|
]
|
|
2182
718
|
}
|
|
2183
719
|
),
|
|
2184
|
-
/* @__PURE__ */
|
|
720
|
+
/* @__PURE__ */ jsxs4(
|
|
2185
721
|
"button",
|
|
2186
722
|
{
|
|
2187
723
|
type: "button",
|
|
@@ -2193,16 +729,16 @@ function IconPicker({
|
|
|
2193
729
|
),
|
|
2194
730
|
onClick: () => onSelectDoDont?.("dont"),
|
|
2195
731
|
children: [
|
|
2196
|
-
/* @__PURE__ */
|
|
2197
|
-
/* @__PURE__ */
|
|
732
|
+
/* @__PURE__ */ jsx12(X, { size: 20 }),
|
|
733
|
+
/* @__PURE__ */ jsx12("span", { className: "text-xs font-medium", children: "Don't" })
|
|
2198
734
|
]
|
|
2199
735
|
}
|
|
2200
736
|
)
|
|
2201
|
-
] }) : /* @__PURE__ */
|
|
2202
|
-
/* @__PURE__ */
|
|
737
|
+
] }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
738
|
+
/* @__PURE__ */ jsx12("div", { className: "grid grid-cols-5 gap-1", children: curatedIcons.map((entry) => {
|
|
2203
739
|
const Icon = entry.icon;
|
|
2204
740
|
const isSelected = selected === entry.id;
|
|
2205
|
-
return /* @__PURE__ */
|
|
741
|
+
return /* @__PURE__ */ jsx12(
|
|
2206
742
|
"button",
|
|
2207
743
|
{
|
|
2208
744
|
"aria-label": entry.label,
|
|
@@ -2212,12 +748,12 @@ function IconPicker({
|
|
|
2212
748
|
isSelected && "ring-2 ring-primary bg-base-accent text-primary"
|
|
2213
749
|
),
|
|
2214
750
|
onClick: () => onSelect(entry.id),
|
|
2215
|
-
children: /* @__PURE__ */
|
|
751
|
+
children: /* @__PURE__ */ jsx12(Icon, { size: 18 })
|
|
2216
752
|
},
|
|
2217
753
|
entry.id
|
|
2218
754
|
);
|
|
2219
755
|
}) }),
|
|
2220
|
-
showRemove && /* @__PURE__ */
|
|
756
|
+
showRemove && /* @__PURE__ */ jsx12(
|
|
2221
757
|
"button",
|
|
2222
758
|
{
|
|
2223
759
|
className: "cursor-pointer mt-2 w-full rounded px-2 py-1.5 text-center text-xs text-base-contrast-light hover:bg-base-accent hover:text-base-contrast",
|
|
@@ -2232,7 +768,7 @@ function IconPicker({
|
|
|
2232
768
|
}
|
|
2233
769
|
|
|
2234
770
|
// src/components/sections/IconList/IconList.tsx
|
|
2235
|
-
import { jsx as
|
|
771
|
+
import { jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2236
772
|
function IconList({
|
|
2237
773
|
items,
|
|
2238
774
|
icon = null,
|
|
@@ -2245,7 +781,7 @@ function IconList({
|
|
|
2245
781
|
onItemsChange
|
|
2246
782
|
}) {
|
|
2247
783
|
const isEditMode = !!onChange || !!onItemsChange;
|
|
2248
|
-
const emitItems =
|
|
784
|
+
const emitItems = useCallback(
|
|
2249
785
|
(newItems) => {
|
|
2250
786
|
onChange?.({
|
|
2251
787
|
type: "icon_list",
|
|
@@ -2257,7 +793,7 @@ function IconList({
|
|
|
2257
793
|
[onChange, onItemsChange, icon, showLabel, stackText]
|
|
2258
794
|
);
|
|
2259
795
|
if (!isEditMode) {
|
|
2260
|
-
return /* @__PURE__ */
|
|
796
|
+
return /* @__PURE__ */ jsx13(
|
|
2261
797
|
ViewIconList,
|
|
2262
798
|
{
|
|
2263
799
|
items,
|
|
@@ -2270,7 +806,7 @@ function IconList({
|
|
|
2270
806
|
}
|
|
2271
807
|
);
|
|
2272
808
|
}
|
|
2273
|
-
return /* @__PURE__ */
|
|
809
|
+
return /* @__PURE__ */ jsx13(
|
|
2274
810
|
EditIconList,
|
|
2275
811
|
{
|
|
2276
812
|
items,
|
|
@@ -2305,10 +841,10 @@ function ViewIconList({
|
|
|
2305
841
|
iconClassName
|
|
2306
842
|
}) {
|
|
2307
843
|
const hasAnyIcon = items.some((item) => resolveIcon(item, defaultIcon));
|
|
2308
|
-
return /* @__PURE__ */
|
|
844
|
+
return /* @__PURE__ */ jsx13("div", { className: "grid gap-4 pb-4", children: items.map((item, i) => {
|
|
2309
845
|
const iconEntry = resolveIcon(item, defaultIcon);
|
|
2310
846
|
const iconColor = resolveIconColor(item, iconClassName);
|
|
2311
|
-
return /* @__PURE__ */
|
|
847
|
+
return /* @__PURE__ */ jsxs5(
|
|
2312
848
|
"div",
|
|
2313
849
|
{
|
|
2314
850
|
className: cn(
|
|
@@ -2316,25 +852,25 @@ function ViewIconList({
|
|
|
2316
852
|
hasAnyIcon ? "grid-cols-[24px_1fr]" : "grid-cols-1"
|
|
2317
853
|
),
|
|
2318
854
|
children: [
|
|
2319
|
-
hasAnyIcon && /* @__PURE__ */
|
|
855
|
+
hasAnyIcon && /* @__PURE__ */ jsx13(
|
|
2320
856
|
"div",
|
|
2321
857
|
{
|
|
2322
858
|
"data-testid": "icon-list-icon",
|
|
2323
859
|
className: cn("flex items-start pt-0.5", iconColor),
|
|
2324
|
-
children: iconEntry && /* @__PURE__ */
|
|
860
|
+
children: iconEntry && /* @__PURE__ */ jsx13(iconEntry.icon, { size: 18 })
|
|
2325
861
|
}
|
|
2326
862
|
),
|
|
2327
|
-
/* @__PURE__ */
|
|
863
|
+
/* @__PURE__ */ jsxs5(
|
|
2328
864
|
"div",
|
|
2329
865
|
{
|
|
2330
866
|
"data-testid": "icon-list-content",
|
|
2331
867
|
className: stackText ? "flex flex-col" : void 0,
|
|
2332
868
|
children: [
|
|
2333
|
-
showLabel && /* @__PURE__ */
|
|
869
|
+
showLabel && /* @__PURE__ */ jsxs5("span", { className: labelClassName, children: [
|
|
2334
870
|
item.label,
|
|
2335
871
|
!stackText && " "
|
|
2336
872
|
] }),
|
|
2337
|
-
/* @__PURE__ */
|
|
873
|
+
/* @__PURE__ */ jsx13("span", { className: textClassName, children: item.text })
|
|
2338
874
|
]
|
|
2339
875
|
}
|
|
2340
876
|
)
|
|
@@ -2359,8 +895,8 @@ function EditIconList({
|
|
|
2359
895
|
onChange: onItemsChange,
|
|
2360
896
|
createItem: () => ({ label: "", text: "" })
|
|
2361
897
|
});
|
|
2362
|
-
const [dragState, setDragState] =
|
|
2363
|
-
const updateItem =
|
|
898
|
+
const [dragState, setDragState] = useState4({ sourceId: null, targetId: null });
|
|
899
|
+
const updateItem = useCallback(
|
|
2364
900
|
(index, patch) => {
|
|
2365
901
|
const updated = wrappedItems.map(
|
|
2366
902
|
(w, i) => i === index ? { ...w.data, ...patch } : w.data
|
|
@@ -2369,7 +905,7 @@ function EditIconList({
|
|
|
2369
905
|
},
|
|
2370
906
|
[wrappedItems, onItemsChange]
|
|
2371
907
|
);
|
|
2372
|
-
const duplicateItem =
|
|
908
|
+
const duplicateItem = useCallback(
|
|
2373
909
|
(index) => {
|
|
2374
910
|
const copy = { ...wrappedItems[index].data };
|
|
2375
911
|
const next = [
|
|
@@ -2382,8 +918,8 @@ function EditIconList({
|
|
|
2382
918
|
[wrappedItems, onItemsChange]
|
|
2383
919
|
);
|
|
2384
920
|
const hasAnyIcon = true;
|
|
2385
|
-
return /* @__PURE__ */
|
|
2386
|
-
wrappedItems.map((wrapped, index) => /* @__PURE__ */
|
|
921
|
+
return /* @__PURE__ */ jsxs5("div", { className: "group/list relative grid gap-4 pb-4", children: [
|
|
922
|
+
wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx13(
|
|
2387
923
|
EditableRow,
|
|
2388
924
|
{
|
|
2389
925
|
id: wrapped.id,
|
|
@@ -2405,7 +941,7 @@ function EditIconList({
|
|
|
2405
941
|
},
|
|
2406
942
|
wrapped.id
|
|
2407
943
|
)),
|
|
2408
|
-
/* @__PURE__ */
|
|
944
|
+
/* @__PURE__ */ jsx13(
|
|
2409
945
|
TrailingDropZone,
|
|
2410
946
|
{
|
|
2411
947
|
index: wrappedItems.length,
|
|
@@ -2414,10 +950,10 @@ function EditIconList({
|
|
|
2414
950
|
onReorder
|
|
2415
951
|
}
|
|
2416
952
|
),
|
|
2417
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsx13(
|
|
2418
954
|
IconButton,
|
|
2419
955
|
{
|
|
2420
|
-
icon: /* @__PURE__ */
|
|
956
|
+
icon: /* @__PURE__ */ jsx13(AddIcon, { size: 16 }),
|
|
2421
957
|
label: "Add item",
|
|
2422
958
|
size: "lg",
|
|
2423
959
|
intent: "primary",
|
|
@@ -2445,15 +981,15 @@ function EditableRow({
|
|
|
2445
981
|
onUpdateItem,
|
|
2446
982
|
onDuplicate
|
|
2447
983
|
}) {
|
|
2448
|
-
const rowRef =
|
|
2449
|
-
const handleRef =
|
|
2450
|
-
const [iconHover, setIconHover] =
|
|
2451
|
-
const [pickerOpen, setPickerOpen] =
|
|
2452
|
-
const [editingSuppressed, setEditingSuppressed] =
|
|
984
|
+
const rowRef = useRef2(null);
|
|
985
|
+
const handleRef = useRef2(null);
|
|
986
|
+
const [iconHover, setIconHover] = useState4(false);
|
|
987
|
+
const [pickerOpen, setPickerOpen] = useState4(false);
|
|
988
|
+
const [editingSuppressed, setEditingSuppressed] = useState4(false);
|
|
2453
989
|
const iconEntry = resolveIcon(item, defaultIcon);
|
|
2454
990
|
const effectiveIconId = item.icon ?? defaultIcon ?? null;
|
|
2455
991
|
const iconColor = resolveIconColor(item, iconClassName);
|
|
2456
|
-
|
|
992
|
+
useEffect3(() => {
|
|
2457
993
|
const row = rowRef.current;
|
|
2458
994
|
const handle = handleRef.current;
|
|
2459
995
|
if (!row || !handle) return;
|
|
@@ -2497,7 +1033,7 @@ function EditableRow({
|
|
|
2497
1033
|
setEditingSuppressed(true);
|
|
2498
1034
|
}
|
|
2499
1035
|
};
|
|
2500
|
-
return /* @__PURE__ */
|
|
1036
|
+
return /* @__PURE__ */ jsxs5(
|
|
2501
1037
|
"div",
|
|
2502
1038
|
{
|
|
2503
1039
|
ref: rowRef,
|
|
@@ -2510,7 +1046,7 @@ function EditableRow({
|
|
|
2510
1046
|
onInput: onEditableActivity,
|
|
2511
1047
|
onMouseMove: () => setEditingSuppressed(false),
|
|
2512
1048
|
children: [
|
|
2513
|
-
hasAnyIcon && /* @__PURE__ */
|
|
1049
|
+
hasAnyIcon && /* @__PURE__ */ jsxs5(
|
|
2514
1050
|
"div",
|
|
2515
1051
|
{
|
|
2516
1052
|
"data-testid": "icon-list-icon",
|
|
@@ -2518,16 +1054,16 @@ function EditableRow({
|
|
|
2518
1054
|
onMouseEnter: () => setIconHover(true),
|
|
2519
1055
|
onMouseLeave: () => setIconHover(false),
|
|
2520
1056
|
children: [
|
|
2521
|
-
/* @__PURE__ */
|
|
1057
|
+
/* @__PURE__ */ jsx13(
|
|
2522
1058
|
"button",
|
|
2523
1059
|
{
|
|
2524
1060
|
className: "cursor-pointer transition-opacity hover:opacity-70",
|
|
2525
1061
|
"aria-label": "Change icon",
|
|
2526
1062
|
onClick: () => setPickerOpen((prev) => !prev),
|
|
2527
|
-
children: iconHover && !pickerOpen ? /* @__PURE__ */
|
|
1063
|
+
children: iconHover && !pickerOpen ? /* @__PURE__ */ jsx13(Pencil, { size: 18, className: "text-base-contrast-light" }) : iconEntry ? /* @__PURE__ */ jsx13(iconEntry.icon, { size: 18 }) : /* @__PURE__ */ jsx13("span", { className: "flex h-[18px] w-[18px] items-center justify-center rounded-sm border border-dashed border-base-contrast-light/40" })
|
|
2528
1064
|
}
|
|
2529
1065
|
),
|
|
2530
|
-
pickerOpen && /* @__PURE__ */
|
|
1066
|
+
pickerOpen && /* @__PURE__ */ jsx13("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx13(
|
|
2531
1067
|
IconPicker,
|
|
2532
1068
|
{
|
|
2533
1069
|
selected: effectiveIconId,
|
|
@@ -2555,8 +1091,8 @@ function EditableRow({
|
|
|
2555
1091
|
]
|
|
2556
1092
|
}
|
|
2557
1093
|
),
|
|
2558
|
-
/* @__PURE__ */
|
|
2559
|
-
showLabel && /* @__PURE__ */
|
|
1094
|
+
/* @__PURE__ */ jsxs5("div", { className: stackText ? "flex flex-col" : void 0, children: [
|
|
1095
|
+
showLabel && /* @__PURE__ */ jsx13(
|
|
2560
1096
|
EditablePlainText,
|
|
2561
1097
|
{
|
|
2562
1098
|
tag: "span",
|
|
@@ -2567,7 +1103,7 @@ function EditableRow({
|
|
|
2567
1103
|
className: cn(labelClassName, !stackText && "mr-1")
|
|
2568
1104
|
}
|
|
2569
1105
|
),
|
|
2570
|
-
/* @__PURE__ */
|
|
1106
|
+
/* @__PURE__ */ jsx13(
|
|
2571
1107
|
EditablePlainText,
|
|
2572
1108
|
{
|
|
2573
1109
|
tag: "span",
|
|
@@ -2579,7 +1115,7 @@ function EditableRow({
|
|
|
2579
1115
|
}
|
|
2580
1116
|
)
|
|
2581
1117
|
] }),
|
|
2582
|
-
/* @__PURE__ */
|
|
1118
|
+
/* @__PURE__ */ jsxs5(
|
|
2583
1119
|
"div",
|
|
2584
1120
|
{
|
|
2585
1121
|
className: cn(
|
|
@@ -2587,30 +1123,30 @@ function EditableRow({
|
|
|
2587
1123
|
editingSuppressed ? "opacity-0 pointer-events-none" : "opacity-0 group-hover/row:opacity-100 no-hover:opacity-100"
|
|
2588
1124
|
),
|
|
2589
1125
|
children: [
|
|
2590
|
-
/* @__PURE__ */
|
|
1126
|
+
/* @__PURE__ */ jsx13(
|
|
2591
1127
|
IconButton,
|
|
2592
1128
|
{
|
|
2593
1129
|
ref: handleRef,
|
|
2594
|
-
icon: /* @__PURE__ */
|
|
1130
|
+
icon: /* @__PURE__ */ jsx13(DragHandle, { size: 14 }),
|
|
2595
1131
|
label: "Drag to reorder",
|
|
2596
1132
|
size: "sm",
|
|
2597
1133
|
className: "cursor-grab rounded bg-base/80 p-1 shadow-sm text-base-contrast-light/80 hover:text-base-contrast active:cursor-grabbing",
|
|
2598
1134
|
tabIndex: -1
|
|
2599
1135
|
}
|
|
2600
1136
|
),
|
|
2601
|
-
/* @__PURE__ */
|
|
1137
|
+
/* @__PURE__ */ jsx13(
|
|
2602
1138
|
"button",
|
|
2603
1139
|
{
|
|
2604
1140
|
"aria-label": "Duplicate item",
|
|
2605
1141
|
onClick: onDuplicate,
|
|
2606
1142
|
className: "cursor-pointer rounded bg-base/80 p-1 shadow-sm text-base-contrast-light hover:text-primary",
|
|
2607
|
-
children: /* @__PURE__ */
|
|
1143
|
+
children: /* @__PURE__ */ jsx13(CopyPlus, { size: 14 })
|
|
2608
1144
|
}
|
|
2609
1145
|
),
|
|
2610
|
-
/* @__PURE__ */
|
|
1146
|
+
/* @__PURE__ */ jsx13(
|
|
2611
1147
|
IconButton,
|
|
2612
1148
|
{
|
|
2613
|
-
icon: /* @__PURE__ */
|
|
1149
|
+
icon: /* @__PURE__ */ jsx13(DeleteIcon, { size: 14 }),
|
|
2614
1150
|
label: "Delete item",
|
|
2615
1151
|
size: "sm",
|
|
2616
1152
|
intent: "destructive",
|
|
@@ -2631,9 +1167,9 @@ function TrailingDropZone({
|
|
|
2631
1167
|
setDragState,
|
|
2632
1168
|
onReorder
|
|
2633
1169
|
}) {
|
|
2634
|
-
const ref =
|
|
1170
|
+
const ref = useRef2(null);
|
|
2635
1171
|
const trailingId = "__trailing__";
|
|
2636
|
-
|
|
1172
|
+
useEffect3(() => {
|
|
2637
1173
|
const el = ref.current;
|
|
2638
1174
|
if (!el) return;
|
|
2639
1175
|
let cleanup;
|
|
@@ -2660,7 +1196,7 @@ function TrailingDropZone({
|
|
|
2660
1196
|
};
|
|
2661
1197
|
}, [index, onReorder, setDragState]);
|
|
2662
1198
|
const isDropTarget = dragState.targetId === trailingId && dragState.sourceId !== null;
|
|
2663
|
-
return /* @__PURE__ */
|
|
1199
|
+
return /* @__PURE__ */ jsx13(
|
|
2664
1200
|
"div",
|
|
2665
1201
|
{
|
|
2666
1202
|
ref,
|
|
@@ -2670,110 +1206,38 @@ function TrailingDropZone({
|
|
|
2670
1206
|
}
|
|
2671
1207
|
|
|
2672
1208
|
// src/components/sections/IconList/IconListSettings.tsx
|
|
2673
|
-
import { useState as
|
|
2674
|
-
|
|
2675
|
-
// src/components/shared/Checkbox.tsx
|
|
2676
|
-
import { useId as useId2 } from "react";
|
|
2677
|
-
import { Check as Check3 } from "lucide-react";
|
|
2678
|
-
import { jsx as jsx28, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2679
|
-
function Checkbox({
|
|
2680
|
-
checked,
|
|
2681
|
-
onChange,
|
|
2682
|
-
label,
|
|
2683
|
-
description,
|
|
2684
|
-
disabled,
|
|
2685
|
-
className,
|
|
2686
|
-
startAdornment,
|
|
2687
|
-
align = "start"
|
|
2688
|
-
}) {
|
|
2689
|
-
const id = useId2();
|
|
2690
|
-
return /* @__PURE__ */ jsxs14(
|
|
2691
|
-
"label",
|
|
2692
|
-
{
|
|
2693
|
-
htmlFor: id,
|
|
2694
|
-
className: cn(
|
|
2695
|
-
"flex cursor-pointer gap-3 select-none hover:opacity-80",
|
|
2696
|
-
align === "start" ? "items-start" : "items-center",
|
|
2697
|
-
disabled && "cursor-not-allowed opacity-50",
|
|
2698
|
-
className
|
|
2699
|
-
),
|
|
2700
|
-
children: [
|
|
2701
|
-
/* @__PURE__ */ jsxs14(
|
|
2702
|
-
"span",
|
|
2703
|
-
{
|
|
2704
|
-
className: cn(
|
|
2705
|
-
"relative flex h-5 w-5 shrink-0 items-center justify-center",
|
|
2706
|
-
align === "start" && "mt-0.5"
|
|
2707
|
-
),
|
|
2708
|
-
children: [
|
|
2709
|
-
/* @__PURE__ */ jsx28(
|
|
2710
|
-
"input",
|
|
2711
|
-
{
|
|
2712
|
-
id,
|
|
2713
|
-
type: "checkbox",
|
|
2714
|
-
checked,
|
|
2715
|
-
disabled,
|
|
2716
|
-
onChange: (e) => onChange(e.target.checked),
|
|
2717
|
-
className: "sr-only"
|
|
2718
|
-
}
|
|
2719
|
-
),
|
|
2720
|
-
/* @__PURE__ */ jsx28(
|
|
2721
|
-
"span",
|
|
2722
|
-
{
|
|
2723
|
-
"aria-hidden": "true",
|
|
2724
|
-
className: cn(
|
|
2725
|
-
"flex h-5 w-5 items-center justify-center rounded border transition-colors",
|
|
2726
|
-
checked ? "border-primary bg-primary text-primary-contrast" : "border-base-300 bg-base hover:border-primary",
|
|
2727
|
-
disabled && "pointer-events-none"
|
|
2728
|
-
),
|
|
2729
|
-
children: checked && /* @__PURE__ */ jsx28(Check3, { size: 14, strokeWidth: 3 })
|
|
2730
|
-
}
|
|
2731
|
-
)
|
|
2732
|
-
]
|
|
2733
|
-
}
|
|
2734
|
-
),
|
|
2735
|
-
startAdornment,
|
|
2736
|
-
/* @__PURE__ */ jsxs14("div", { className: "text-sm", children: [
|
|
2737
|
-
/* @__PURE__ */ jsx28("span", { className: "font-medium text-base-contrast", children: label }),
|
|
2738
|
-
description && /* @__PURE__ */ jsx28("span", { className: "block text-base-contrast-light", children: description })
|
|
2739
|
-
] })
|
|
2740
|
-
]
|
|
2741
|
-
}
|
|
2742
|
-
);
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
|
-
// src/components/sections/IconList/IconListSettings.tsx
|
|
2746
|
-
import { jsx as jsx29, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1209
|
+
import { useState as useState5 } from "react";
|
|
1210
|
+
import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2747
1211
|
function IconListSettings({
|
|
2748
1212
|
icon: initialIcon,
|
|
2749
1213
|
showLabel: initialShowLabel,
|
|
2750
1214
|
stackText: initialStackText,
|
|
2751
1215
|
onChange
|
|
2752
1216
|
}) {
|
|
2753
|
-
const [icon, setIcon] =
|
|
2754
|
-
const [showLabel, setShowLabel] =
|
|
2755
|
-
const [stackText, setStackText] =
|
|
2756
|
-
const [pickerOpen, setPickerOpen] =
|
|
1217
|
+
const [icon, setIcon] = useState5(initialIcon);
|
|
1218
|
+
const [showLabel, setShowLabel] = useState5(initialShowLabel);
|
|
1219
|
+
const [stackText, setStackText] = useState5(initialStackText);
|
|
1220
|
+
const [pickerOpen, setPickerOpen] = useState5(false);
|
|
2757
1221
|
const emit = (overrides) => onChange({ content: {}, options: { icon, showLabel, stackText, ...overrides } });
|
|
2758
1222
|
const showIcons = icon !== null;
|
|
2759
1223
|
const iconEntry = icon ? getIcon(icon) : null;
|
|
2760
|
-
return /* @__PURE__ */
|
|
2761
|
-
/* @__PURE__ */
|
|
2762
|
-
/* @__PURE__ */
|
|
2763
|
-
/* @__PURE__ */
|
|
2764
|
-
/* @__PURE__ */
|
|
1224
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-4", children: [
|
|
1225
|
+
/* @__PURE__ */ jsxs6("div", { className: "relative", children: [
|
|
1226
|
+
/* @__PURE__ */ jsx14(FormLabel, { htmlFor: "icon-picker-btn", children: "Default Icon" }),
|
|
1227
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
1228
|
+
/* @__PURE__ */ jsxs6(
|
|
2765
1229
|
"button",
|
|
2766
1230
|
{
|
|
2767
1231
|
id: "icon-picker-btn",
|
|
2768
1232
|
className: "cursor-pointer flex items-center gap-2 rounded border border-base-200 px-3 py-1.5 text-sm text-base-contrast-light hover:border-primary hover:text-primary",
|
|
2769
1233
|
onClick: () => setPickerOpen((prev) => !prev),
|
|
2770
1234
|
children: [
|
|
2771
|
-
iconEntry && /* @__PURE__ */
|
|
2772
|
-
/* @__PURE__ */
|
|
1235
|
+
iconEntry && /* @__PURE__ */ jsx14(iconEntry.icon, { size: 16 }),
|
|
1236
|
+
/* @__PURE__ */ jsx14("span", { children: iconEntry?.label ?? "None" })
|
|
2773
1237
|
]
|
|
2774
1238
|
}
|
|
2775
1239
|
),
|
|
2776
|
-
icon && /* @__PURE__ */
|
|
1240
|
+
icon && /* @__PURE__ */ jsx14(
|
|
2777
1241
|
"button",
|
|
2778
1242
|
{
|
|
2779
1243
|
className: "cursor-pointer text-xs text-base-contrast-light hover:text-base-contrast",
|
|
@@ -2785,7 +1249,7 @@ function IconListSettings({
|
|
|
2785
1249
|
}
|
|
2786
1250
|
)
|
|
2787
1251
|
] }),
|
|
2788
|
-
pickerOpen && /* @__PURE__ */
|
|
1252
|
+
pickerOpen && /* @__PURE__ */ jsx14("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx14(
|
|
2789
1253
|
IconPicker,
|
|
2790
1254
|
{
|
|
2791
1255
|
selected: icon,
|
|
@@ -2800,7 +1264,7 @@ function IconListSettings({
|
|
|
2800
1264
|
}
|
|
2801
1265
|
) })
|
|
2802
1266
|
] }),
|
|
2803
|
-
/* @__PURE__ */
|
|
1267
|
+
/* @__PURE__ */ jsx14(
|
|
2804
1268
|
Checkbox,
|
|
2805
1269
|
{
|
|
2806
1270
|
checked: showLabel,
|
|
@@ -2811,7 +1275,7 @@ function IconListSettings({
|
|
|
2811
1275
|
label: "Show labels"
|
|
2812
1276
|
}
|
|
2813
1277
|
),
|
|
2814
|
-
showLabel && /* @__PURE__ */
|
|
1278
|
+
showLabel && /* @__PURE__ */ jsx14(
|
|
2815
1279
|
Checkbox,
|
|
2816
1280
|
{
|
|
2817
1281
|
checked: stackText,
|
|
@@ -2826,30 +1290,30 @@ function IconListSettings({
|
|
|
2826
1290
|
}
|
|
2827
1291
|
|
|
2828
1292
|
// src/components/sections/IconList/index.tsx
|
|
2829
|
-
import { jsx as
|
|
2830
|
-
var IconListItemSchema =
|
|
2831
|
-
label:
|
|
2832
|
-
text:
|
|
2833
|
-
icon:
|
|
2834
|
-
dodont:
|
|
1293
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1294
|
+
var IconListItemSchema = z5.object({
|
|
1295
|
+
label: z5.string(),
|
|
1296
|
+
text: z5.string(),
|
|
1297
|
+
icon: z5.string().optional(),
|
|
1298
|
+
dodont: z5.enum(["do", "dont"]).optional()
|
|
2835
1299
|
});
|
|
2836
|
-
var schema5 =
|
|
2837
|
-
type:
|
|
2838
|
-
content:
|
|
2839
|
-
items:
|
|
1300
|
+
var schema5 = z5.object({
|
|
1301
|
+
type: z5.literal("icon_list"),
|
|
1302
|
+
content: z5.object({
|
|
1303
|
+
items: z5.array(IconListItemSchema)
|
|
2840
1304
|
}),
|
|
2841
|
-
options:
|
|
2842
|
-
icon:
|
|
2843
|
-
showLabel:
|
|
2844
|
-
stackText:
|
|
1305
|
+
options: z5.object({
|
|
1306
|
+
icon: z5.string().nullable().optional(),
|
|
1307
|
+
showLabel: z5.boolean().optional(),
|
|
1308
|
+
stackText: z5.boolean().optional()
|
|
2845
1309
|
}).optional()
|
|
2846
1310
|
});
|
|
2847
1311
|
var IconList_default = defineSection({
|
|
2848
1312
|
type: "icon_list",
|
|
2849
1313
|
label: "Icon List",
|
|
2850
|
-
icon: /* @__PURE__ */
|
|
1314
|
+
icon: /* @__PURE__ */ jsx15(List, { size: 18 }),
|
|
2851
1315
|
schema: schema5,
|
|
2852
|
-
component: ({ content, options, onChange }) => /* @__PURE__ */
|
|
1316
|
+
component: ({ content, options, onChange }) => /* @__PURE__ */ jsx15(
|
|
2853
1317
|
IconList,
|
|
2854
1318
|
{
|
|
2855
1319
|
items: content.content.items,
|
|
@@ -2868,237 +1332,27 @@ var IconList_default = defineSection({
|
|
|
2868
1332
|
});
|
|
2869
1333
|
|
|
2870
1334
|
// src/components/sections/Container/index.tsx
|
|
2871
|
-
import { z as
|
|
1335
|
+
import { z as z6 } from "zod";
|
|
2872
1336
|
import { LayoutTemplate } from "lucide-react";
|
|
2873
1337
|
|
|
2874
1338
|
// src/components/sections/Container/Container.tsx
|
|
2875
1339
|
import "react";
|
|
2876
1340
|
|
|
2877
1341
|
// src/components/editor/ChildBlockWrapper.tsx
|
|
2878
|
-
import { forwardRef
|
|
1342
|
+
import { forwardRef } from "react";
|
|
2879
1343
|
import { CopyPlus as CopyPlus2 } from "lucide-react";
|
|
2880
1344
|
|
|
2881
|
-
// src/components/editor/DragHandle.tsx
|
|
2882
|
-
import { forwardRef as forwardRef4 } from "react";
|
|
2883
|
-
|
|
2884
|
-
// src/components/shared/Tooltip.tsx
|
|
2885
|
-
import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2886
|
-
function Tooltip({ content, children, className }) {
|
|
2887
|
-
return /* @__PURE__ */ jsxs16("div", { className: cn("group/tooltip relative inline-flex", className), children: [
|
|
2888
|
-
children,
|
|
2889
|
-
/* @__PURE__ */ jsx31(
|
|
2890
|
-
"span",
|
|
2891
|
-
{
|
|
2892
|
-
className: "pointer-events-none absolute left-1/2 top-full z-50 mt-1.5 -translate-x-1/2 opacity-0 transition-opacity delay-300 group-hover/tooltip:opacity-100",
|
|
2893
|
-
role: "tooltip",
|
|
2894
|
-
children: /* @__PURE__ */ jsx31("span", { className: "block whitespace-nowrap rounded bg-tooltip px-2 py-1 text-center text-xs leading-relaxed text-tooltip-muted", children: content })
|
|
2895
|
-
}
|
|
2896
|
-
)
|
|
2897
|
-
] });
|
|
2898
|
-
}
|
|
2899
|
-
function Kbd({ children }) {
|
|
2900
|
-
return /* @__PURE__ */ jsx31("strong", { className: "text-tooltip-contrast", children });
|
|
2901
|
-
}
|
|
2902
|
-
|
|
2903
|
-
// src/components/editor/DragHandle.tsx
|
|
2904
|
-
import { Fragment as Fragment5, jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2905
|
-
var DragHandle2 = forwardRef4(function DragHandle3(_, ref) {
|
|
2906
|
-
return /* @__PURE__ */ jsx32(Tooltip, { content: /* @__PURE__ */ jsxs17(Fragment5, { children: [
|
|
2907
|
-
/* @__PURE__ */ jsx32(Kbd, { children: "Drag" }),
|
|
2908
|
-
" to move"
|
|
2909
|
-
] }), children: /* @__PURE__ */ jsx32(
|
|
2910
|
-
IconButton,
|
|
2911
|
-
{
|
|
2912
|
-
ref,
|
|
2913
|
-
icon: /* @__PURE__ */ jsx32(DragHandle, { size: 18 }),
|
|
2914
|
-
label: "Drag to reorder section",
|
|
2915
|
-
className: "pointer-events-auto cursor-grab active:cursor-grabbing rounded-md text-base-contrast-light/80 hover:bg-base-contrast-light/10 hover:text-base-contrast",
|
|
2916
|
-
tabIndex: -1
|
|
2917
|
-
}
|
|
2918
|
-
) });
|
|
2919
|
-
});
|
|
2920
|
-
|
|
2921
|
-
// src/components/editor/DeleteButton.tsx
|
|
2922
|
-
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
2923
|
-
function DeleteButton({ onDelete }) {
|
|
2924
|
-
return /* @__PURE__ */ jsx33(
|
|
2925
|
-
IconButton,
|
|
2926
|
-
{
|
|
2927
|
-
icon: /* @__PURE__ */ jsx33(DeleteIcon, { size: 16 }),
|
|
2928
|
-
label: "Delete section",
|
|
2929
|
-
intent: "destructive",
|
|
2930
|
-
onClick: onDelete,
|
|
2931
|
-
className: "pointer-events-auto"
|
|
2932
|
-
}
|
|
2933
|
-
);
|
|
2934
|
-
}
|
|
2935
|
-
|
|
2936
|
-
// src/components/editor/SettingsButton.tsx
|
|
2937
|
-
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
2938
|
-
function SettingsButton({ onClick }) {
|
|
2939
|
-
return /* @__PURE__ */ jsx34(
|
|
2940
|
-
IconButton,
|
|
2941
|
-
{
|
|
2942
|
-
icon: /* @__PURE__ */ jsx34(SettingsIcon, { size: 16 }),
|
|
2943
|
-
label: "Section settings",
|
|
2944
|
-
onClick,
|
|
2945
|
-
className: "pointer-events-auto"
|
|
2946
|
-
}
|
|
2947
|
-
);
|
|
2948
|
-
}
|
|
2949
|
-
|
|
2950
1345
|
// src/components/editor/ColSpanControl.tsx
|
|
2951
|
-
import { useRef as
|
|
1346
|
+
import { useRef as useRef3, useState as useState6 } from "react";
|
|
2952
1347
|
import { Columns3 } from "lucide-react";
|
|
2953
|
-
|
|
2954
|
-
// src/components/shared/Popover.tsx
|
|
2955
|
-
import { useEffect as useEffect11, useLayoutEffect, useRef as useRef9, useState as useState13 } from "react";
|
|
2956
|
-
|
|
2957
|
-
// src/hooks/useFocusTrap.ts
|
|
2958
|
-
import { useEffect as useEffect10 } from "react";
|
|
2959
|
-
var FOCUSABLE_SELECTOR = [
|
|
2960
|
-
"a[href]",
|
|
2961
|
-
"button:not([disabled])",
|
|
2962
|
-
"input:not([disabled])",
|
|
2963
|
-
"select:not([disabled])",
|
|
2964
|
-
"textarea:not([disabled])",
|
|
2965
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
2966
|
-
].join(", ");
|
|
2967
|
-
function useFocusTrap(ref, active) {
|
|
2968
|
-
useEffect10(() => {
|
|
2969
|
-
if (!active || !ref.current) return;
|
|
2970
|
-
const container = ref.current;
|
|
2971
|
-
const previouslyFocused = document.activeElement;
|
|
2972
|
-
const getFocusable = () => Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
2973
|
-
const focusable = getFocusable();
|
|
2974
|
-
if (focusable.length > 0) {
|
|
2975
|
-
focusable[0].focus();
|
|
2976
|
-
}
|
|
2977
|
-
const handleKeyDown = (e) => {
|
|
2978
|
-
if (e.key !== "Tab") return;
|
|
2979
|
-
const elements = getFocusable();
|
|
2980
|
-
if (elements.length === 0) return;
|
|
2981
|
-
const first = elements[0];
|
|
2982
|
-
const last = elements[elements.length - 1];
|
|
2983
|
-
if (e.shiftKey) {
|
|
2984
|
-
if (document.activeElement === first) {
|
|
2985
|
-
e.preventDefault();
|
|
2986
|
-
last.focus();
|
|
2987
|
-
}
|
|
2988
|
-
} else {
|
|
2989
|
-
if (document.activeElement === last) {
|
|
2990
|
-
e.preventDefault();
|
|
2991
|
-
first.focus();
|
|
2992
|
-
}
|
|
2993
|
-
}
|
|
2994
|
-
};
|
|
2995
|
-
container.addEventListener("keydown", handleKeyDown);
|
|
2996
|
-
return () => {
|
|
2997
|
-
container.removeEventListener("keydown", handleKeyDown);
|
|
2998
|
-
if (previouslyFocused && document.body.contains(previouslyFocused)) {
|
|
2999
|
-
previouslyFocused.focus();
|
|
3000
|
-
}
|
|
3001
|
-
};
|
|
3002
|
-
}, [active, ref]);
|
|
3003
|
-
}
|
|
3004
|
-
|
|
3005
|
-
// src/components/shared/Popover.tsx
|
|
3006
|
-
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
3007
|
-
function Popover({
|
|
3008
|
-
isOpen,
|
|
3009
|
-
onClose,
|
|
3010
|
-
anchorRef,
|
|
3011
|
-
children,
|
|
3012
|
-
align = "auto",
|
|
3013
|
-
className
|
|
3014
|
-
}) {
|
|
3015
|
-
const panelRef = useRef9(null);
|
|
3016
|
-
const [resolvedAlign, setResolvedAlign] = useState13("start");
|
|
3017
|
-
useFocusTrap(panelRef, isOpen);
|
|
3018
|
-
useLayoutEffect(() => {
|
|
3019
|
-
if (!isOpen || align !== "auto") {
|
|
3020
|
-
if (!isOpen) setResolvedAlign("start");
|
|
3021
|
-
return;
|
|
3022
|
-
}
|
|
3023
|
-
const panel = panelRef.current;
|
|
3024
|
-
if (!panel) return;
|
|
3025
|
-
panel.style.left = "0";
|
|
3026
|
-
panel.style.right = "auto";
|
|
3027
|
-
const rect = panel.getBoundingClientRect();
|
|
3028
|
-
if (rect.right > window.innerWidth) {
|
|
3029
|
-
setResolvedAlign("end");
|
|
3030
|
-
} else {
|
|
3031
|
-
setResolvedAlign("start");
|
|
3032
|
-
}
|
|
3033
|
-
panel.style.left = "";
|
|
3034
|
-
panel.style.right = "";
|
|
3035
|
-
}, [isOpen, align]);
|
|
3036
|
-
useEffect11(() => {
|
|
3037
|
-
if (!isOpen) return;
|
|
3038
|
-
function onKeyDown(e) {
|
|
3039
|
-
if (e.key === "Escape") onClose();
|
|
3040
|
-
}
|
|
3041
|
-
function onMouseDown(e) {
|
|
3042
|
-
const target = e.target;
|
|
3043
|
-
if (panelRef.current?.contains(target)) return;
|
|
3044
|
-
if (anchorRef.current?.contains(target)) return;
|
|
3045
|
-
onClose();
|
|
3046
|
-
}
|
|
3047
|
-
document.addEventListener("keydown", onKeyDown);
|
|
3048
|
-
document.addEventListener("mousedown", onMouseDown);
|
|
3049
|
-
return () => {
|
|
3050
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
3051
|
-
document.removeEventListener("mousedown", onMouseDown);
|
|
3052
|
-
};
|
|
3053
|
-
}, [isOpen, onClose, anchorRef]);
|
|
3054
|
-
if (!isOpen) return null;
|
|
3055
|
-
const effectiveAlign = align === "auto" ? resolvedAlign : align;
|
|
3056
|
-
return /* @__PURE__ */ jsx35(
|
|
3057
|
-
"div",
|
|
3058
|
-
{
|
|
3059
|
-
ref: panelRef,
|
|
3060
|
-
role: "dialog",
|
|
3061
|
-
"aria-modal": "false",
|
|
3062
|
-
className: cn(
|
|
3063
|
-
"absolute top-full z-50 mt-1 rounded-md border border-base-200 bg-base shadow-lg",
|
|
3064
|
-
effectiveAlign === "end" ? "right-0" : "left-0",
|
|
3065
|
-
className
|
|
3066
|
-
),
|
|
3067
|
-
children
|
|
3068
|
-
}
|
|
3069
|
-
);
|
|
3070
|
-
}
|
|
3071
|
-
|
|
3072
|
-
// src/components/shared/PopoverItem.tsx
|
|
3073
|
-
import { forwardRef as forwardRef5 } from "react";
|
|
3074
|
-
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
3075
|
-
var PopoverItem = forwardRef5(
|
|
3076
|
-
function PopoverItem2({ className, children, ...rest }, ref) {
|
|
3077
|
-
return /* @__PURE__ */ jsx36(
|
|
3078
|
-
"button",
|
|
3079
|
-
{
|
|
3080
|
-
ref,
|
|
3081
|
-
type: "button",
|
|
3082
|
-
className: cn(
|
|
3083
|
-
"flex w-full cursor-pointer items-center gap-3 px-3 py-1.5 text-left text-xs hover:bg-base-accent",
|
|
3084
|
-
className
|
|
3085
|
-
),
|
|
3086
|
-
...rest,
|
|
3087
|
-
children
|
|
3088
|
-
}
|
|
3089
|
-
);
|
|
3090
|
-
}
|
|
3091
|
-
);
|
|
3092
|
-
|
|
3093
|
-
// src/components/editor/ColSpanControl.tsx
|
|
3094
|
-
import { jsx as jsx37, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1348
|
+
import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3095
1349
|
function ColSpanControl({ colSpan, columns, onChange }) {
|
|
3096
|
-
const buttonRef =
|
|
3097
|
-
const [open, setOpen] =
|
|
1350
|
+
const buttonRef = useRef3(null);
|
|
1351
|
+
const [open, setOpen] = useState6(false);
|
|
3098
1352
|
if (columns <= 1) return null;
|
|
3099
1353
|
const current = Math.min(Math.max(colSpan, 1), columns);
|
|
3100
|
-
return /* @__PURE__ */
|
|
3101
|
-
/* @__PURE__ */
|
|
1354
|
+
return /* @__PURE__ */ jsxs7("div", { className: "relative", children: [
|
|
1355
|
+
/* @__PURE__ */ jsx16(
|
|
3102
1356
|
"button",
|
|
3103
1357
|
{
|
|
3104
1358
|
ref: buttonRef,
|
|
@@ -3108,10 +1362,10 @@ function ColSpanControl({ colSpan, columns, onChange }) {
|
|
|
3108
1362
|
"aria-expanded": open,
|
|
3109
1363
|
onClick: () => setOpen((v) => !v),
|
|
3110
1364
|
className: "pointer-events-auto inline-flex cursor-pointer items-center gap-1 rounded p-1 text-xs text-base-contrast-light hover:text-primary",
|
|
3111
|
-
children: /* @__PURE__ */
|
|
1365
|
+
children: /* @__PURE__ */ jsx16(Columns3, { size: 14 })
|
|
3112
1366
|
}
|
|
3113
1367
|
),
|
|
3114
|
-
/* @__PURE__ */
|
|
1368
|
+
/* @__PURE__ */ jsx16(Popover, { isOpen: open, onClose: () => setOpen(false), anchorRef: buttonRef, className: "min-w-28", children: /* @__PURE__ */ jsx16("ul", { role: "list", className: "py-1", children: Array.from({ length: columns }, (_, i) => i + 1).map((span) => /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsxs7(
|
|
3115
1369
|
PopoverItem,
|
|
3116
1370
|
{
|
|
3117
1371
|
"aria-current": span === current,
|
|
@@ -3130,8 +1384,8 @@ function ColSpanControl({ colSpan, columns, onChange }) {
|
|
|
3130
1384
|
}
|
|
3131
1385
|
|
|
3132
1386
|
// src/components/editor/ChildBlockWrapper.tsx
|
|
3133
|
-
import { jsx as
|
|
3134
|
-
var ChildBlockWrapper =
|
|
1387
|
+
import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1388
|
+
var ChildBlockWrapper = forwardRef(
|
|
3135
1389
|
function ChildBlockWrapper2({
|
|
3136
1390
|
label,
|
|
3137
1391
|
columns,
|
|
@@ -3146,7 +1400,7 @@ var ChildBlockWrapper = forwardRef6(
|
|
|
3146
1400
|
onOpenSettings,
|
|
3147
1401
|
children
|
|
3148
1402
|
}, ref) {
|
|
3149
|
-
return /* @__PURE__ */
|
|
1403
|
+
return /* @__PURE__ */ jsxs8(
|
|
3150
1404
|
"div",
|
|
3151
1405
|
{
|
|
3152
1406
|
ref,
|
|
@@ -3156,39 +1410,39 @@ var ChildBlockWrapper = forwardRef6(
|
|
|
3156
1410
|
"hover:outline hover:outline-2 hover:outline-primary/30"
|
|
3157
1411
|
),
|
|
3158
1412
|
children: [
|
|
3159
|
-
/* @__PURE__ */
|
|
3160
|
-
/* @__PURE__ */
|
|
3161
|
-
/* @__PURE__ */
|
|
3162
|
-
/* @__PURE__ */
|
|
3163
|
-
hasSettings && onOpenSettings && /* @__PURE__ */
|
|
3164
|
-
/* @__PURE__ */
|
|
1413
|
+
/* @__PURE__ */ jsxs8("div", { className: "absolute top-0 left-0 -translate-x-full z-20 flex flex-col items-center gap-1 opacity-0 transition-opacity group-hover/childblock:opacity-100 group-focus-within/childblock:opacity-100 pointer-events-none", children: [
|
|
1414
|
+
/* @__PURE__ */ jsx17("span", { className: "sr-only", children: label }),
|
|
1415
|
+
/* @__PURE__ */ jsx17("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx17(DragHandle2, { ref: dragHandleRef }) }),
|
|
1416
|
+
/* @__PURE__ */ jsx17("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx17(ColSpanControl, { colSpan, columns, onChange: onColSpanChange }) }),
|
|
1417
|
+
hasSettings && onOpenSettings && /* @__PURE__ */ jsx17("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx17(SettingsButton, { onClick: onOpenSettings }) }),
|
|
1418
|
+
/* @__PURE__ */ jsx17("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx17(
|
|
3165
1419
|
"button",
|
|
3166
1420
|
{
|
|
3167
1421
|
type: "button",
|
|
3168
1422
|
"aria-label": "Duplicate block",
|
|
3169
1423
|
onClick: onDuplicate,
|
|
3170
1424
|
className: "cursor-pointer rounded p-1 text-base-contrast-light hover:text-primary",
|
|
3171
|
-
children: /* @__PURE__ */
|
|
1425
|
+
children: /* @__PURE__ */ jsx17(CopyPlus2, { size: 16 })
|
|
3172
1426
|
}
|
|
3173
1427
|
) }),
|
|
3174
|
-
/* @__PURE__ */
|
|
1428
|
+
/* @__PURE__ */ jsx17("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx17(DeleteButton, { onDelete }) })
|
|
3175
1429
|
] }),
|
|
3176
|
-
closestEdge === "left" && /* @__PURE__ */
|
|
1430
|
+
closestEdge === "left" && /* @__PURE__ */ jsx17(
|
|
3177
1431
|
"div",
|
|
3178
1432
|
{
|
|
3179
1433
|
"data-drop-edge": "left",
|
|
3180
1434
|
className: "absolute bottom-0 left-0 top-0 z-10 w-0.5 -translate-x-1 bg-primary"
|
|
3181
1435
|
}
|
|
3182
1436
|
),
|
|
3183
|
-
closestEdge === "right" && /* @__PURE__ */
|
|
1437
|
+
closestEdge === "right" && /* @__PURE__ */ jsx17(
|
|
3184
1438
|
"div",
|
|
3185
1439
|
{
|
|
3186
1440
|
"data-drop-edge": "right",
|
|
3187
1441
|
className: "absolute bottom-0 right-0 top-0 z-10 w-0.5 translate-x-1 bg-primary"
|
|
3188
1442
|
}
|
|
3189
1443
|
),
|
|
3190
|
-
closestEdge === "top" && /* @__PURE__ */
|
|
3191
|
-
closestEdge === "bottom" && /* @__PURE__ */
|
|
1444
|
+
closestEdge === "top" && /* @__PURE__ */ jsx17("div", { "data-drop-edge": "top", className: "absolute left-0 right-0 top-0 z-10 h-0.5 -translate-y-1 bg-primary" }),
|
|
1445
|
+
closestEdge === "bottom" && /* @__PURE__ */ jsx17("div", { "data-drop-edge": "bottom", className: "absolute left-0 right-0 bottom-0 z-10 h-0.5 translate-y-1 bg-primary" }),
|
|
3192
1446
|
children
|
|
3193
1447
|
]
|
|
3194
1448
|
}
|
|
@@ -3196,334 +1450,14 @@ var ChildBlockWrapper = forwardRef6(
|
|
|
3196
1450
|
}
|
|
3197
1451
|
);
|
|
3198
1452
|
|
|
3199
|
-
// src/components/editor/SettingsForm.tsx
|
|
3200
|
-
import { useId as useId4, useState as useState16 } from "react";
|
|
3201
|
-
|
|
3202
|
-
// src/components/shared/Select.tsx
|
|
3203
|
-
import { useId as useId3 } from "react";
|
|
3204
|
-
import { ChevronDown } from "lucide-react";
|
|
3205
|
-
import { jsx as jsx39, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3206
|
-
function Select({
|
|
3207
|
-
label,
|
|
3208
|
-
value,
|
|
3209
|
-
onChange,
|
|
3210
|
-
options,
|
|
3211
|
-
disabled,
|
|
3212
|
-
className,
|
|
3213
|
-
selectClassName
|
|
3214
|
-
}) {
|
|
3215
|
-
const id = useId3();
|
|
3216
|
-
return /* @__PURE__ */ jsxs20("div", { className, children: [
|
|
3217
|
-
label && /* @__PURE__ */ jsx39(FormLabel, { htmlFor: id, children: label }),
|
|
3218
|
-
/* @__PURE__ */ jsxs20("div", { className: "relative", children: [
|
|
3219
|
-
/* @__PURE__ */ jsx39(
|
|
3220
|
-
"select",
|
|
3221
|
-
{
|
|
3222
|
-
id,
|
|
3223
|
-
value,
|
|
3224
|
-
onChange: (e) => onChange(e.target.value),
|
|
3225
|
-
disabled,
|
|
3226
|
-
className: cn(
|
|
3227
|
-
"w-full appearance-none rounded border border-base-200 bg-base py-2 pr-8 pl-3 text-sm text-base-contrast",
|
|
3228
|
-
"focus:border-base-contrast focus:outline-none focus:ring-1 focus:ring-base-contrast",
|
|
3229
|
-
disabled && "cursor-not-allowed opacity-50",
|
|
3230
|
-
selectClassName
|
|
3231
|
-
),
|
|
3232
|
-
children: options.map((opt) => /* @__PURE__ */ jsx39("option", { value: opt.value, children: opt.label }, opt.value))
|
|
3233
|
-
}
|
|
3234
|
-
),
|
|
3235
|
-
/* @__PURE__ */ jsx39(
|
|
3236
|
-
ChevronDown,
|
|
3237
|
-
{
|
|
3238
|
-
size: 14,
|
|
3239
|
-
className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 text-base-contrast-light"
|
|
3240
|
-
}
|
|
3241
|
-
)
|
|
3242
|
-
] })
|
|
3243
|
-
] });
|
|
3244
|
-
}
|
|
3245
|
-
|
|
3246
|
-
// src/components/shared/LinkField.tsx
|
|
3247
|
-
import { Fragment as Fragment6, jsx as jsx40, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3248
|
-
var TARGET_OPTIONS = [
|
|
3249
|
-
{ label: "Same tab (_self)", value: "_self" },
|
|
3250
|
-
{ label: "New tab (_blank)", value: "_blank" }
|
|
3251
|
-
];
|
|
3252
|
-
function LinkField({ label, value, onChange }) {
|
|
3253
|
-
const { pages, getPageHeadings } = usePages();
|
|
3254
|
-
const isInternal = value.kind === "internal";
|
|
3255
|
-
function setMode(kind) {
|
|
3256
|
-
if (kind === value.kind) return;
|
|
3257
|
-
onChange(kind === "external" ? { kind: "external", href: "", target: value.target } : { kind: "internal", pageId: "", anchorSectionId: null, target: "_self" });
|
|
3258
|
-
}
|
|
3259
|
-
const pageId = isInternal ? value.pageId : "";
|
|
3260
|
-
const headings = pageId ? getPageHeadings(pageId) : [];
|
|
3261
|
-
return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-3", children: [
|
|
3262
|
-
/* @__PURE__ */ jsx40(FormLabel, { children: label }),
|
|
3263
|
-
/* @__PURE__ */ jsx40("div", { className: "flex gap-2", role: "tablist", children: ["external", "internal"].map((kind) => /* @__PURE__ */ jsx40(
|
|
3264
|
-
"button",
|
|
3265
|
-
{
|
|
3266
|
-
type: "button",
|
|
3267
|
-
role: "tab",
|
|
3268
|
-
"aria-selected": value.kind === kind,
|
|
3269
|
-
onClick: () => setMode(kind),
|
|
3270
|
-
className: cn(
|
|
3271
|
-
"cursor-pointer rounded border px-3 py-1 text-sm capitalize",
|
|
3272
|
-
value.kind === kind ? "border-primary bg-primary text-primary-contrast" : "border-base-200 text-base-contrast"
|
|
3273
|
-
),
|
|
3274
|
-
children: kind === "external" ? "External URL" : "Internal page"
|
|
3275
|
-
},
|
|
3276
|
-
kind
|
|
3277
|
-
)) }),
|
|
3278
|
-
value.kind === "external" ? /* @__PURE__ */ jsx40(
|
|
3279
|
-
Input,
|
|
3280
|
-
{
|
|
3281
|
-
label: "URL",
|
|
3282
|
-
value: value.href,
|
|
3283
|
-
placeholder: "https://...",
|
|
3284
|
-
onChange: (href) => onChange({ kind: "external", href, target: value.target })
|
|
3285
|
-
}
|
|
3286
|
-
) : /* @__PURE__ */ jsxs21(Fragment6, { children: [
|
|
3287
|
-
/* @__PURE__ */ jsx40(
|
|
3288
|
-
Select,
|
|
3289
|
-
{
|
|
3290
|
-
label: "Page",
|
|
3291
|
-
value: value.pageId,
|
|
3292
|
-
options: [{ label: "Select a page\u2026", value: "" }, ...pages.map((p) => ({ label: p.title, value: p.id }))],
|
|
3293
|
-
onChange: (pid) => onChange({ kind: "internal", pageId: pid, anchorSectionId: null, target: value.target })
|
|
3294
|
-
}
|
|
3295
|
-
),
|
|
3296
|
-
/* @__PURE__ */ jsx40(
|
|
3297
|
-
Select,
|
|
3298
|
-
{
|
|
3299
|
-
label: "Section",
|
|
3300
|
-
value: value.anchorSectionId ?? "",
|
|
3301
|
-
disabled: !pageId,
|
|
3302
|
-
options: [{ label: "None (top of page)", value: "" }, ...headings.map((h) => ({ label: h.label, value: h.id }))],
|
|
3303
|
-
onChange: (anchor) => onChange({ kind: "internal", pageId, anchorSectionId: anchor || null, target: value.target })
|
|
3304
|
-
}
|
|
3305
|
-
)
|
|
3306
|
-
] }),
|
|
3307
|
-
value.kind === "external" && /* @__PURE__ */ jsx40(
|
|
3308
|
-
Select,
|
|
3309
|
-
{
|
|
3310
|
-
label: "Opens in",
|
|
3311
|
-
value: value.target,
|
|
3312
|
-
options: TARGET_OPTIONS,
|
|
3313
|
-
onChange: (t) => onChange({ ...value, target: t })
|
|
3314
|
-
}
|
|
3315
|
-
)
|
|
3316
|
-
] });
|
|
3317
|
-
}
|
|
3318
|
-
|
|
3319
|
-
// src/components/shared/Tabs.tsx
|
|
3320
|
-
import { useState as useState15 } from "react";
|
|
3321
|
-
import { jsx as jsx41, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3322
|
-
function Tabs({ tabs, defaultTabId, activeTabId, onTabChange, fullBleedTabBar }) {
|
|
3323
|
-
const [uncontrolledId, setUncontrolledId] = useState15(defaultTabId ?? tabs[0]?.id);
|
|
3324
|
-
const isControlled = activeTabId !== void 0;
|
|
3325
|
-
const activeId = isControlled ? activeTabId : uncontrolledId;
|
|
3326
|
-
const activeTab = tabs.find((t) => t.id === activeId) ?? tabs[0];
|
|
3327
|
-
function handleSelect(id) {
|
|
3328
|
-
if (!isControlled) setUncontrolledId(id);
|
|
3329
|
-
onTabChange?.(id);
|
|
3330
|
-
}
|
|
3331
|
-
return /* @__PURE__ */ jsxs22("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
3332
|
-
/* @__PURE__ */ jsx41("div", { className: cn("border-b border-base-200", fullBleedTabBar && "-mx-6 px-6"), children: /* @__PURE__ */ jsx41("div", { className: "flex", role: "tablist", children: tabs.map((tab) => /* @__PURE__ */ jsx41(
|
|
3333
|
-
"button",
|
|
3334
|
-
{
|
|
3335
|
-
type: "button",
|
|
3336
|
-
role: "tab",
|
|
3337
|
-
"aria-selected": activeTab?.id === tab.id,
|
|
3338
|
-
onClick: () => handleSelect(tab.id),
|
|
3339
|
-
className: cn(
|
|
3340
|
-
"cursor-pointer px-4 py-2 text-sm font-medium border-b-2 -mb-px",
|
|
3341
|
-
activeTab?.id === tab.id ? "border-brand text-brand" : "border-transparent text-base-contrast-light hover:text-base-contrast"
|
|
3342
|
-
),
|
|
3343
|
-
children: tab.label
|
|
3344
|
-
},
|
|
3345
|
-
tab.id
|
|
3346
|
-
)) }) }),
|
|
3347
|
-
/* @__PURE__ */ jsx41("div", { role: "tabpanel", children: activeTab?.content })
|
|
3348
|
-
] });
|
|
3349
|
-
}
|
|
3350
|
-
|
|
3351
|
-
// src/components/editor/SettingsForm.tsx
|
|
3352
|
-
import { jsx as jsx42, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3353
|
-
function resolveValues(schema8, values) {
|
|
3354
|
-
const resolved = {};
|
|
3355
|
-
for (const [key, field] of Object.entries(schema8)) {
|
|
3356
|
-
resolved[key] = values[key] ?? field.default;
|
|
3357
|
-
}
|
|
3358
|
-
return resolved;
|
|
3359
|
-
}
|
|
3360
|
-
function coerceValue(field, value) {
|
|
3361
|
-
if (field.type === "select" && "coerce" in field && field.coerce === "number") {
|
|
3362
|
-
return Number(value);
|
|
3363
|
-
}
|
|
3364
|
-
return value;
|
|
3365
|
-
}
|
|
3366
|
-
function normalizeEmpty(field, value) {
|
|
3367
|
-
if (field.type === "select" && "emptyIsUndefined" in field && field.emptyIsUndefined && value === "") {
|
|
3368
|
-
return void 0;
|
|
3369
|
-
}
|
|
3370
|
-
return value;
|
|
3371
|
-
}
|
|
3372
|
-
function splitByTarget(schema8, allValues) {
|
|
3373
|
-
const content = {};
|
|
3374
|
-
const options = {};
|
|
3375
|
-
for (const [key, field] of Object.entries(schema8)) {
|
|
3376
|
-
const value = normalizeEmpty(field, coerceValue(field, allValues[key]));
|
|
3377
|
-
const target = field.target ?? "options";
|
|
3378
|
-
if (target === "content") {
|
|
3379
|
-
content[key] = value;
|
|
3380
|
-
} else {
|
|
3381
|
-
options[key] = value;
|
|
3382
|
-
}
|
|
3383
|
-
}
|
|
3384
|
-
return { content, options };
|
|
3385
|
-
}
|
|
3386
|
-
function RangeField({
|
|
3387
|
-
field,
|
|
3388
|
-
value,
|
|
3389
|
-
onChange
|
|
3390
|
-
}) {
|
|
3391
|
-
const id = useId4();
|
|
3392
|
-
return /* @__PURE__ */ jsxs23("div", { children: [
|
|
3393
|
-
/* @__PURE__ */ jsx42(FormLabel, { htmlFor: id, children: field.label }),
|
|
3394
|
-
/* @__PURE__ */ jsx42(
|
|
3395
|
-
"input",
|
|
3396
|
-
{
|
|
3397
|
-
id,
|
|
3398
|
-
type: "range",
|
|
3399
|
-
min: field.min,
|
|
3400
|
-
max: field.max,
|
|
3401
|
-
step: field.step,
|
|
3402
|
-
value,
|
|
3403
|
-
onChange: (e) => onChange(Number(e.target.value)),
|
|
3404
|
-
className: cn(
|
|
3405
|
-
"w-full accent-primary"
|
|
3406
|
-
)
|
|
3407
|
-
}
|
|
3408
|
-
)
|
|
3409
|
-
] });
|
|
3410
|
-
}
|
|
3411
|
-
function renderField(key, field, value, handleFieldChange) {
|
|
3412
|
-
switch (field.type) {
|
|
3413
|
-
case "text":
|
|
3414
|
-
return /* @__PURE__ */ jsx42(
|
|
3415
|
-
Input,
|
|
3416
|
-
{
|
|
3417
|
-
label: field.label,
|
|
3418
|
-
value: String(value ?? ""),
|
|
3419
|
-
placeholder: field.placeholder,
|
|
3420
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3421
|
-
},
|
|
3422
|
-
key
|
|
3423
|
-
);
|
|
3424
|
-
case "number":
|
|
3425
|
-
return /* @__PURE__ */ jsx42(
|
|
3426
|
-
Input,
|
|
3427
|
-
{
|
|
3428
|
-
label: field.label,
|
|
3429
|
-
type: "number",
|
|
3430
|
-
value: String(value ?? ""),
|
|
3431
|
-
onChange: (v) => handleFieldChange(key, v === "" ? "" : Number(v))
|
|
3432
|
-
},
|
|
3433
|
-
key
|
|
3434
|
-
);
|
|
3435
|
-
case "checkbox":
|
|
3436
|
-
return /* @__PURE__ */ jsx42(
|
|
3437
|
-
Checkbox,
|
|
3438
|
-
{
|
|
3439
|
-
label: field.label,
|
|
3440
|
-
checked: Boolean(value),
|
|
3441
|
-
onChange: (checked) => handleFieldChange(key, checked)
|
|
3442
|
-
},
|
|
3443
|
-
key
|
|
3444
|
-
);
|
|
3445
|
-
case "select":
|
|
3446
|
-
return /* @__PURE__ */ jsx42(
|
|
3447
|
-
Select,
|
|
3448
|
-
{
|
|
3449
|
-
label: field.label,
|
|
3450
|
-
value: String(value ?? ""),
|
|
3451
|
-
options: field.options,
|
|
3452
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3453
|
-
},
|
|
3454
|
-
key
|
|
3455
|
-
);
|
|
3456
|
-
case "range":
|
|
3457
|
-
return /* @__PURE__ */ jsx42(
|
|
3458
|
-
RangeField,
|
|
3459
|
-
{
|
|
3460
|
-
field,
|
|
3461
|
-
value: Number(value ?? field.min),
|
|
3462
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3463
|
-
},
|
|
3464
|
-
key
|
|
3465
|
-
);
|
|
3466
|
-
case "link":
|
|
3467
|
-
return /* @__PURE__ */ jsx42(
|
|
3468
|
-
LinkField,
|
|
3469
|
-
{
|
|
3470
|
-
label: field.label,
|
|
3471
|
-
value: value ?? field.default,
|
|
3472
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3473
|
-
},
|
|
3474
|
-
key
|
|
3475
|
-
);
|
|
3476
|
-
default:
|
|
3477
|
-
return null;
|
|
3478
|
-
}
|
|
3479
|
-
}
|
|
3480
|
-
function SettingsForm({ schema: schema8, values, onChange, tabs }) {
|
|
3481
|
-
const [local, setLocal] = useState16(() => resolveValues(schema8, values));
|
|
3482
|
-
function handleFieldChange(key, newValue) {
|
|
3483
|
-
const next = { ...local, [key]: newValue };
|
|
3484
|
-
setLocal(next);
|
|
3485
|
-
onChange(splitByTarget(schema8, next));
|
|
3486
|
-
}
|
|
3487
|
-
if (tabs) {
|
|
3488
|
-
const fields = (keys) => keys.filter((key) => key in schema8).map((key) => renderField(key, schema8[key], local[key], handleFieldChange));
|
|
3489
|
-
const listed = new Set(tabs.flatMap((t) => t.fields));
|
|
3490
|
-
const otherKeys = Object.keys(schema8).filter((key) => !listed.has(key));
|
|
3491
|
-
const tabItems = [
|
|
3492
|
-
...tabs.map((t) => ({ id: t.label, label: t.label, content: /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-4", children: fields(t.fields) }) })),
|
|
3493
|
-
...otherKeys.length > 0 ? [{ id: "__other__", label: "Other", content: /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-4", children: fields(otherKeys) }) }] : []
|
|
3494
|
-
];
|
|
3495
|
-
return /* @__PURE__ */ jsx42(Tabs, { tabs: tabItems, fullBleedTabBar: true });
|
|
3496
|
-
}
|
|
3497
|
-
return /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-4", children: Object.entries(schema8).map(([key, field]) => renderField(key, field, local[key], handleFieldChange)) });
|
|
3498
|
-
}
|
|
3499
|
-
|
|
3500
|
-
// src/hooks/useBlockDnd.ts
|
|
3501
|
-
import { useEffect as useEffect12, useRef as useRef11, useState as useState17 } from "react";
|
|
3502
|
-
|
|
3503
|
-
// src/lib/block-dnd.ts
|
|
3504
|
-
var ROOT_CONTAINER_ID = "__root__";
|
|
3505
|
-
function buildBlockDragData(args) {
|
|
3506
|
-
return { dragType: "block", ...args };
|
|
3507
|
-
}
|
|
3508
|
-
function buildBlockDropData(args) {
|
|
3509
|
-
return { ...args };
|
|
3510
|
-
}
|
|
3511
|
-
function isBlockDragData(data) {
|
|
3512
|
-
return data.dragType === "block";
|
|
3513
|
-
}
|
|
3514
|
-
function canDropBlock(source, dropContainerId) {
|
|
3515
|
-
if (source.blockId === dropContainerId) return false;
|
|
3516
|
-
if (source.isContainer && dropContainerId !== ROOT_CONTAINER_ID) return false;
|
|
3517
|
-
return true;
|
|
3518
|
-
}
|
|
3519
|
-
|
|
3520
1453
|
// src/hooks/useBlockDnd.ts
|
|
1454
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
|
|
3521
1455
|
function useBlockDnd({ blockId, containerId, index, isContainer, allowedEdges, enabled }) {
|
|
3522
|
-
const dragRef =
|
|
3523
|
-
const handleRef =
|
|
3524
|
-
const [closestEdge, setClosestEdge] =
|
|
3525
|
-
const [isDragging, setIsDragging] =
|
|
3526
|
-
|
|
1456
|
+
const dragRef = useRef4(null);
|
|
1457
|
+
const handleRef = useRef4(null);
|
|
1458
|
+
const [closestEdge, setClosestEdge] = useState7(null);
|
|
1459
|
+
const [isDragging, setIsDragging] = useState7(false);
|
|
1460
|
+
useEffect4(() => {
|
|
3527
1461
|
const element = dragRef.current;
|
|
3528
1462
|
const handle = handleRef.current;
|
|
3529
1463
|
if (!element || !enabled) return;
|
|
@@ -3579,9 +1513,9 @@ function useBlockDnd({ blockId, containerId, index, isContainer, allowedEdges, e
|
|
|
3579
1513
|
return { dragRef, handleRef, closestEdge, isDragging };
|
|
3580
1514
|
}
|
|
3581
1515
|
function useBlockDropZone({ containerId, index, toColumn, allowedEdges, enabled }) {
|
|
3582
|
-
const dropRef =
|
|
3583
|
-
const [closestEdge, setClosestEdge] =
|
|
3584
|
-
|
|
1516
|
+
const dropRef = useRef4(null);
|
|
1517
|
+
const [closestEdge, setClosestEdge] = useState7(null);
|
|
1518
|
+
useEffect4(() => {
|
|
3585
1519
|
const element = dropRef.current;
|
|
3586
1520
|
if (!element || !enabled) return;
|
|
3587
1521
|
let cleanup;
|
|
@@ -3678,7 +1612,7 @@ function trimTrailingSpacers(container) {
|
|
|
3678
1612
|
}
|
|
3679
1613
|
|
|
3680
1614
|
// src/components/sections/Container/Container.tsx
|
|
3681
|
-
import { jsx as
|
|
1615
|
+
import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3682
1616
|
var ROW_EDGES = ["left", "right"];
|
|
3683
1617
|
var COL_EDGES = ["top", "bottom"];
|
|
3684
1618
|
function ContainerChild({
|
|
@@ -3709,14 +1643,14 @@ function ContainerChild({
|
|
|
3709
1643
|
allowedEdges: flow === "column" ? COL_EDGES : ROW_EDGES,
|
|
3710
1644
|
enabled: true
|
|
3711
1645
|
});
|
|
3712
|
-
return /* @__PURE__ */
|
|
1646
|
+
return /* @__PURE__ */ jsx18(
|
|
3713
1647
|
"div",
|
|
3714
1648
|
{
|
|
3715
1649
|
ref: dragRef,
|
|
3716
1650
|
className: cellClass,
|
|
3717
1651
|
"data-child-index": index,
|
|
3718
1652
|
"data-child-id": child.id,
|
|
3719
|
-
children: /* @__PURE__ */
|
|
1653
|
+
children: /* @__PURE__ */ jsx18(
|
|
3720
1654
|
ChildBlockWrapper,
|
|
3721
1655
|
{
|
|
3722
1656
|
label,
|
|
@@ -3730,7 +1664,7 @@ function ContainerChild({
|
|
|
3730
1664
|
onDuplicate,
|
|
3731
1665
|
onColSpanChange,
|
|
3732
1666
|
onOpenSettings,
|
|
3733
|
-
children: /* @__PURE__ */
|
|
1667
|
+
children: /* @__PURE__ */ jsx18(
|
|
3734
1668
|
ChildComp,
|
|
3735
1669
|
{
|
|
3736
1670
|
content: child,
|
|
@@ -3758,7 +1692,7 @@ function EmptyColumnCell({
|
|
|
3758
1692
|
enabled: true
|
|
3759
1693
|
});
|
|
3760
1694
|
const active = closestEdge !== null;
|
|
3761
|
-
return /* @__PURE__ */
|
|
1695
|
+
return /* @__PURE__ */ jsx18(
|
|
3762
1696
|
"div",
|
|
3763
1697
|
{
|
|
3764
1698
|
ref: dropRef,
|
|
@@ -3796,7 +1730,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3796
1730
|
flow === "column" && "grid-flow-col"
|
|
3797
1731
|
);
|
|
3798
1732
|
if (!editable) {
|
|
3799
|
-
return /* @__PURE__ */
|
|
1733
|
+
return /* @__PURE__ */ jsx18("div", { className: "@container", children: /* @__PURE__ */ jsx18("div", { className: gridClass, children: children.map((child, index) => {
|
|
3800
1734
|
const def = getSection(child.type);
|
|
3801
1735
|
if (!def) return null;
|
|
3802
1736
|
const Child = def.component;
|
|
@@ -3807,7 +1741,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3807
1741
|
colSpanClass[columns]?.[Math.min(span, columns)] || void 0,
|
|
3808
1742
|
child.type === "spacer" && spacerHiddenClass[columns]
|
|
3809
1743
|
);
|
|
3810
|
-
return /* @__PURE__ */
|
|
1744
|
+
return /* @__PURE__ */ jsx18("div", { className: cellClass, children: /* @__PURE__ */ jsx18(Child, { content: child, options: mergedOptions, isEditMode }) }, child.id ?? index);
|
|
3811
1745
|
}) }) });
|
|
3812
1746
|
}
|
|
3813
1747
|
function columnStartOf(index) {
|
|
@@ -3821,7 +1755,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3821
1755
|
const def = getSection(child.type);
|
|
3822
1756
|
if (!def) return null;
|
|
3823
1757
|
if (isSpacer(child)) {
|
|
3824
|
-
return /* @__PURE__ */
|
|
1758
|
+
return /* @__PURE__ */ jsx18(
|
|
3825
1759
|
EmptyColumnCell,
|
|
3826
1760
|
{
|
|
3827
1761
|
containerId: container.id,
|
|
@@ -3849,12 +1783,12 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3849
1783
|
const CustomForm = def.settingsForm;
|
|
3850
1784
|
openModal(
|
|
3851
1785
|
`${def.label} Settings`,
|
|
3852
|
-
/* @__PURE__ */
|
|
1786
|
+
/* @__PURE__ */ jsx18(CustomForm, { ...seed, onChange: applyResult })
|
|
3853
1787
|
);
|
|
3854
1788
|
} else if (def.settings) {
|
|
3855
1789
|
openModal(
|
|
3856
1790
|
`${def.label} Settings`,
|
|
3857
|
-
/* @__PURE__ */
|
|
1791
|
+
/* @__PURE__ */ jsx18(
|
|
3858
1792
|
SettingsForm,
|
|
3859
1793
|
{
|
|
3860
1794
|
schema: def.settings,
|
|
@@ -3866,7 +1800,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3866
1800
|
);
|
|
3867
1801
|
}
|
|
3868
1802
|
} : void 0;
|
|
3869
|
-
return /* @__PURE__ */
|
|
1803
|
+
return /* @__PURE__ */ jsx18(
|
|
3870
1804
|
ContainerChild,
|
|
3871
1805
|
{
|
|
3872
1806
|
containerId: container.id,
|
|
@@ -3892,9 +1826,9 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3892
1826
|
}
|
|
3893
1827
|
const occupied = occupiedColumns(children, columns);
|
|
3894
1828
|
const emptyCols = occupied < columns ? columns - occupied : 0;
|
|
3895
|
-
return /* @__PURE__ */
|
|
1829
|
+
return /* @__PURE__ */ jsx18("div", { className: "@container", children: /* @__PURE__ */ jsxs9("div", { className: gridClass, children: [
|
|
3896
1830
|
children.map(renderEditChild),
|
|
3897
|
-
Array.from({ length: emptyCols }, (_, i) => /* @__PURE__ */
|
|
1831
|
+
Array.from({ length: emptyCols }, (_, i) => /* @__PURE__ */ jsx18(
|
|
3898
1832
|
EmptyColumnCell,
|
|
3899
1833
|
{
|
|
3900
1834
|
containerId: container.id,
|
|
@@ -3907,8 +1841,8 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3907
1841
|
}
|
|
3908
1842
|
|
|
3909
1843
|
// src/components/sections/Container/ContainerSettingsForm.tsx
|
|
3910
|
-
import { useState as
|
|
3911
|
-
import { jsx as
|
|
1844
|
+
import { useState as useState8 } from "react";
|
|
1845
|
+
import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3912
1846
|
function inheritableSchema(children) {
|
|
3913
1847
|
const out = {};
|
|
3914
1848
|
for (const child of children) {
|
|
@@ -3928,8 +1862,8 @@ function ContainerSettingsForm({
|
|
|
3928
1862
|
children = [],
|
|
3929
1863
|
onChange
|
|
3930
1864
|
}) {
|
|
3931
|
-
const [layout, setLayout] =
|
|
3932
|
-
const [defaults, setDefaults] =
|
|
1865
|
+
const [layout, setLayout] = useState8({ columns, flow });
|
|
1866
|
+
const [defaults, setDefaults] = useState8(childDefaults);
|
|
3933
1867
|
const childSchema = inheritableSchema(children);
|
|
3934
1868
|
const hasChildDefaults = Object.keys(childSchema).length > 0;
|
|
3935
1869
|
function emit(nextLayout, nextDefaults) {
|
|
@@ -3958,10 +1892,10 @@ function ContainerSettingsForm({
|
|
|
3958
1892
|
]
|
|
3959
1893
|
}
|
|
3960
1894
|
};
|
|
3961
|
-
return /* @__PURE__ */
|
|
3962
|
-
/* @__PURE__ */
|
|
3963
|
-
/* @__PURE__ */
|
|
3964
|
-
/* @__PURE__ */
|
|
1895
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-6", children: [
|
|
1896
|
+
/* @__PURE__ */ jsxs10("fieldset", { className: "flex flex-col gap-4", children: [
|
|
1897
|
+
/* @__PURE__ */ jsx19("legend", { className: "mb-2 text-sm font-semibold text-base-contrast", children: "Layout" }),
|
|
1898
|
+
/* @__PURE__ */ jsx19(
|
|
3965
1899
|
SettingsForm,
|
|
3966
1900
|
{
|
|
3967
1901
|
schema: layoutSchema,
|
|
@@ -3977,9 +1911,9 @@ function ContainerSettingsForm({
|
|
|
3977
1911
|
}
|
|
3978
1912
|
)
|
|
3979
1913
|
] }),
|
|
3980
|
-
hasChildDefaults && /* @__PURE__ */
|
|
3981
|
-
/* @__PURE__ */
|
|
3982
|
-
/* @__PURE__ */
|
|
1914
|
+
hasChildDefaults && /* @__PURE__ */ jsxs10("fieldset", { className: "flex flex-col gap-4 border-t border-base-200 pt-4", children: [
|
|
1915
|
+
/* @__PURE__ */ jsx19("legend", { className: "mb-2 text-sm font-semibold text-base-contrast", children: "Apply to all items" }),
|
|
1916
|
+
/* @__PURE__ */ jsx19(
|
|
3983
1917
|
SettingsForm,
|
|
3984
1918
|
{
|
|
3985
1919
|
schema: childSchema,
|
|
@@ -3996,16 +1930,16 @@ function ContainerSettingsForm({
|
|
|
3996
1930
|
}
|
|
3997
1931
|
|
|
3998
1932
|
// src/components/sections/Container/index.tsx
|
|
3999
|
-
import { jsx as
|
|
4000
|
-
var schema6 =
|
|
4001
|
-
type:
|
|
4002
|
-
content:
|
|
4003
|
-
columns:
|
|
4004
|
-
flow:
|
|
4005
|
-
childDefaults:
|
|
1933
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1934
|
+
var schema6 = z6.object({
|
|
1935
|
+
type: z6.literal("container"),
|
|
1936
|
+
content: z6.object({
|
|
1937
|
+
columns: z6.number().int().min(1).max(MAX_CONTAINER_COLUMNS).default(1),
|
|
1938
|
+
flow: z6.enum(["row", "column"]).default("row"),
|
|
1939
|
+
childDefaults: z6.record(z6.string(), z6.unknown()).optional(),
|
|
4006
1940
|
// Recursive: children are full blocks. z.lazy defers evaluation to parse
|
|
4007
1941
|
// time, by which point every section schema (incl. container) is registered.
|
|
4008
|
-
children:
|
|
1942
|
+
children: z6.array(z6.lazy(() => getSectionSchema())).default([])
|
|
4009
1943
|
}).transform((c) => ({
|
|
4010
1944
|
...c,
|
|
4011
1945
|
children: c.children.map(
|
|
@@ -4016,9 +1950,9 @@ var schema6 = z7.object({
|
|
|
4016
1950
|
var Container_default = defineSection({
|
|
4017
1951
|
type: "container",
|
|
4018
1952
|
label: "Container",
|
|
4019
|
-
icon: /* @__PURE__ */
|
|
1953
|
+
icon: /* @__PURE__ */ jsx20(LayoutTemplate, { size: 18 }),
|
|
4020
1954
|
schema: schema6,
|
|
4021
|
-
component: ({ content, onChange, isEditMode, openModal }) => /* @__PURE__ */
|
|
1955
|
+
component: ({ content, onChange, isEditMode, openModal }) => /* @__PURE__ */ jsx20(Container, { content, isEditMode: !!isEditMode, onChange, openModal }),
|
|
4022
1956
|
defaults: () => ({
|
|
4023
1957
|
type: "container",
|
|
4024
1958
|
content: { columns: 1, flow: "row", children: [] }
|
|
@@ -4028,27 +1962,27 @@ var Container_default = defineSection({
|
|
|
4028
1962
|
});
|
|
4029
1963
|
|
|
4030
1964
|
// src/components/sections/Spacer/index.tsx
|
|
4031
|
-
import { z as
|
|
1965
|
+
import { z as z7 } from "zod";
|
|
4032
1966
|
import { SquareDashed } from "lucide-react";
|
|
4033
1967
|
|
|
4034
1968
|
// src/components/sections/Spacer/Spacer.tsx
|
|
4035
|
-
import { jsx as
|
|
1969
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
4036
1970
|
function Spacer() {
|
|
4037
|
-
return /* @__PURE__ */
|
|
1971
|
+
return /* @__PURE__ */ jsx21("div", { "data-spacer": true, "aria-hidden": "true", className: "h-full" });
|
|
4038
1972
|
}
|
|
4039
1973
|
|
|
4040
1974
|
// src/components/sections/Spacer/index.tsx
|
|
4041
|
-
import { jsx as
|
|
4042
|
-
var schema7 =
|
|
4043
|
-
type:
|
|
4044
|
-
content:
|
|
1975
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
1976
|
+
var schema7 = z7.object({
|
|
1977
|
+
type: z7.literal("spacer"),
|
|
1978
|
+
content: z7.object({}).default({})
|
|
4045
1979
|
});
|
|
4046
1980
|
var Spacer_default = defineSection({
|
|
4047
1981
|
type: "spacer",
|
|
4048
1982
|
label: "Spacer",
|
|
4049
|
-
icon: /* @__PURE__ */
|
|
1983
|
+
icon: /* @__PURE__ */ jsx22(SquareDashed, { size: 18 }),
|
|
4050
1984
|
schema: schema7,
|
|
4051
|
-
component: () => /* @__PURE__ */
|
|
1985
|
+
component: () => /* @__PURE__ */ jsx22(Spacer, {}),
|
|
4052
1986
|
defaults: () => ({ type: "spacer", content: {} })
|
|
4053
1987
|
});
|
|
4054
1988
|
|