@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.
@@ -1,17 +1,51 @@
1
1
  import {
2
- getMediaProvider
3
- } from "../../chunk-CBWK3KPV.js";
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-ZU2MKPTG.js";
38
+ } from "../../chunk-3DCG4DNU.js";
8
39
  import {
9
- cn,
10
40
  curatedIcons,
11
- getIcon,
12
- sanitizeHtml,
13
- toSectionId
14
- } from "../../chunk-RFZNNCAS.js";
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__ */ jsx3(Heading1, { size: 18 }),
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 jsx4 } from "react/jsx-runtime";
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__ */ jsx4(Heading2, { size: 18 }),
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 jsx5 } from "react/jsx-runtime";
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__ */ jsx5(Heading3, { size: 18 }),
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 as z2 } from "zod";
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 jsx10 } from "react/jsx-runtime";
112
+ import { jsx as jsx4 } from "react/jsx-runtime";
963
113
  function Prose({ body, onChange }) {
964
114
  if (onChange) {
965
- return /* @__PURE__ */ jsx10("div", { className: "prose-content", children: /* @__PURE__ */ jsx10(
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__ */ jsx10(
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 jsx11 } from "react/jsx-runtime";
999
- var schema = z2.object({
1000
- type: z2.literal("prose"),
1001
- content: z2.object({ body: z2.string() })
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__ */ jsx11(AlignLeft, { size: 18 }),
156
+ icon: /* @__PURE__ */ jsx5(AlignLeft, { size: 18 }),
1007
157
  schema,
1008
158
  richTextFields: ["body"],
1009
- component: ({ content, onChange }) => /* @__PURE__ */ jsx11(Prose, { body: content.content.body, onChange: onChange ? (c) => onChange(c) : void 0 }),
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 z3 } from "zod";
1016
- import { Image as ImageIcon2 } from "lucide-react";
1017
-
1018
- // src/components/sections/Media/MediaBlock.tsx
1019
- import { Check, X } from "lucide-react";
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: z3.enum(["do", "dont"]).optional()
173
+ dodont: z2.enum(["do", "dont"]).optional()
1213
174
  }),
1214
- options: z3.object({
1215
- square: z3.boolean().optional(),
1216
- showCaption: z3.boolean().optional(),
1217
- border: z3.boolean().optional(),
1218
- objectFit: z3.enum(["cover", "contain"]).optional()
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__ */ jsx15(ImageIcon2, { size: 18 }),
185
+ icon: /* @__PURE__ */ jsx6(ImageIcon, { size: 18 }),
1225
186
  schema: schema2,
1226
- component: ({ content, options, onChange }) => /* @__PURE__ */ jsx15(
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 z4 } from "zod";
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 jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
1286
- function Button3({ text, link, download, onChange }) {
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__ */ jsxs7("span", { className: cn(base, variant, "inline-flex items-center gap-2"), children: [
1291
- download && /* @__PURE__ */ jsx16(Download, { size: 16, className: "shrink-0" }),
1292
- /* @__PURE__ */ jsx16(
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__ */ jsxs7(
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__ */ jsx16(Download, { size: 16, className: "shrink-0" }),
276
+ download && /* @__PURE__ */ jsx7(Download, { size: 16, className: "shrink-0" }),
1316
277
  text
1317
278
  ]
1318
279
  }
1319
280
  );
1320
281
  }
1321
- return /* @__PURE__ */ jsx16("button", { className: cn("cursor-pointer", base, variant), children: text });
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 jsx17 } from "react/jsx-runtime";
1326
- var schema3 = z4.object({
1327
- type: z4.literal("button"),
1328
- content: z4.object({
1329
- text: z4.string(),
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: z4.boolean().optional()
1332
- })
1333
- });
1334
- var Button_default = defineSection({
1335
- type: "button",
1336
- label: "Button",
1337
- icon: /* @__PURE__ */ jsx17(RectangleHorizontal, { size: 18 }),
1338
- schema: schema3,
1339
- component: ({ content, onChange }) => /* @__PURE__ */ jsx17(
1340
- Button3,
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
- htmlFor,
1754
- className: cn("mb-1.5 block text-sm font-medium text-base-contrast", className),
1755
- children
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
- // src/components/shared/Input.tsx
1761
- import { jsx as jsx22, jsxs as jsxs9 } from "react/jsx-runtime";
1762
- var Input = forwardRef3(function Input2({ label, value, onChange, type = "text", className, disabled, error, ...rest }, ref) {
1763
- const id = useId();
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 { jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
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] = useState8(() => ({
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__ */ jsxs10("div", { className: "space-y-3", children: [
1810
- /* @__PURE__ */ jsx23(
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__ */ jsx23(
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 jsx24, jsxs as jsxs11 } from "react/jsx-runtime";
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__ */ jsx24(
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__ */ jsx24(ColorsView, { colors, columns, label, collapsing, showLabel });
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] = useState9(!collapsing);
1879
- const [copiedIndex, setCopiedIndex] = useState9(null);
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__ */ jsxs11("div", { children: [
1897
- (showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs11("div", { className: "mb-4 flex items-center gap-2", children: [
1898
- showLabel && !!label && /* @__PURE__ */ jsx24("span", { className: "text-lg font-bold", children: label }),
1899
- collapsing && /* @__PURE__ */ jsxs11(
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__ */ jsx24("span", { children: expanded ? "Hide Details" : "Show Details" }),
1906
- expanded ? /* @__PURE__ */ jsx24(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx24(Eye, { size: 16 })
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__ */ jsx24("div", { className: "@container", children: /* @__PURE__ */ jsx24("div", { className: cn("grid gap-4", containerGridClass[columns] || containerGridClass[3]), children: colors.map((color, i) => {
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__ */ jsxs11("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
1915
- /* @__PURE__ */ jsxs11("div", { className: cn("relative flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: [
1916
- color.name && /* @__PURE__ */ jsx24("span", { className: "text-sm font-bold", children: color.name }),
1917
- copiedIndex === i && /* @__PURE__ */ jsx24("span", { className: cn(
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__ */ jsx24("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
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__ */ jsxs11("button", { onClick: () => handleCopy(value, i), className: "cursor-pointer flex w-full justify-between hover:text-primary", children: [
1925
- /* @__PURE__ */ jsx24("span", { className: "font-medium uppercase", children: key }),
1926
- /* @__PURE__ */ jsx24("span", { children: value })
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] = useState9(!collapsing);
479
+ const [expanded, setExpanded] = useState2(!collapsing);
1944
480
  const options = { label, columns, collapsing, showLabel };
1945
- useEffect7(() => {
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__ */ jsx24(ColorSwatchSettings, { color, onChange: (updated) => {
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__ */ jsxs11("div", { children: [
1959
- (showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs11("div", { className: "mb-4 flex items-center gap-2", children: [
1960
- showLabel && !!label && /* @__PURE__ */ jsx24(
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__ */ jsxs11(
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__ */ jsx24("span", { children: expanded ? "Hide Details" : "Show Details" }),
1977
- expanded ? /* @__PURE__ */ jsx24(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx24(Eye, { size: 16 })
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__ */ jsx24(
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__ */ jsx24(
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__ */ jsxs11("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
2021
- /* @__PURE__ */ jsx24("div", { className: cn("flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: /* @__PURE__ */ jsx24(
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__ */ jsx24("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
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__ */ jsxs11("div", { className: "flex w-full justify-between", children: [
2035
- /* @__PURE__ */ jsx24("span", { className: "font-medium uppercase", children: key }),
2036
- /* @__PURE__ */ jsx24("span", { children: value })
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 jsx25 } from "react/jsx-runtime";
2045
- var schema4 = z5.object({
2046
- type: z5.literal("colors"),
2047
- content: z5.object({ colors: z5.array(ColorItemSchema) }),
2048
- options: z5.object({
2049
- label: z5.string().optional(),
2050
- columns: z5.number().int().min(2).max(4).optional(),
2051
- collapsing: z5.boolean().optional(),
2052
- showLabel: z5.boolean().optional()
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__ */ jsx25(Palette, { size: 18 }),
594
+ icon: /* @__PURE__ */ jsx11(Palette, { size: 18 }),
2059
595
  schema: schema4,
2060
- component: ({ content, options, onChange, openModal }) => /* @__PURE__ */ jsx25(
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 z6 } from "zod";
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 useRef8, useEffect as useEffect9, useState as useState11, useCallback as useCallback6 } from "react";
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 useEffect8, useRef as useRef7, useState as useState10 } from "react";
2102
- import { Check as Check2, X as X4 } from "lucide-react";
2103
- import { Fragment as Fragment4, jsx as jsx26, jsxs as jsxs12 } from "react/jsx-runtime";
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 = useRef7(null);
2114
- const [mode, setMode] = useState10(dodont ? "dodont" : "none");
2115
- useEffect8(() => {
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__ */ jsxs12(
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__ */ jsxs12("div", { role: "tablist", "aria-label": "Icon mode", className: "mb-2 flex gap-1 rounded-md bg-base-200 p-0.5", children: [
2132
- /* @__PURE__ */ jsx26(
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__ */ jsx26(
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__ */ jsxs12("div", { className: "grid grid-cols-2 gap-2", children: [
2167
- /* @__PURE__ */ jsxs12(
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__ */ jsx26(Check2, { size: 20 }),
2180
- /* @__PURE__ */ jsx26("span", { className: "text-xs font-medium", children: "Do" })
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__ */ jsxs12(
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__ */ jsx26(X4, { size: 20 }),
2197
- /* @__PURE__ */ jsx26("span", { className: "text-xs font-medium", children: "Don't" })
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__ */ jsxs12(Fragment4, { children: [
2202
- /* @__PURE__ */ jsx26("div", { className: "grid grid-cols-5 gap-1", children: curatedIcons.map((entry) => {
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__ */ jsx26(
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__ */ jsx26(Icon, { size: 18 })
751
+ children: /* @__PURE__ */ jsx12(Icon, { size: 18 })
2216
752
  },
2217
753
  entry.id
2218
754
  );
2219
755
  }) }),
2220
- showRemove && /* @__PURE__ */ jsx26(
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 jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
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 = useCallback6(
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__ */ jsx27(
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__ */ jsx27(
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__ */ jsx27("div", { className: "grid gap-4 pb-4", children: items.map((item, i) => {
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__ */ jsxs13(
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__ */ jsx27(
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__ */ jsx27(iconEntry.icon, { size: 18 })
860
+ children: iconEntry && /* @__PURE__ */ jsx13(iconEntry.icon, { size: 18 })
2325
861
  }
2326
862
  ),
2327
- /* @__PURE__ */ jsxs13(
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__ */ jsxs13("span", { className: labelClassName, children: [
869
+ showLabel && /* @__PURE__ */ jsxs5("span", { className: labelClassName, children: [
2334
870
  item.label,
2335
871
  !stackText && " "
2336
872
  ] }),
2337
- /* @__PURE__ */ jsx27("span", { className: textClassName, children: item.text })
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] = useState11({ sourceId: null, targetId: null });
2363
- const updateItem = useCallback6(
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 = useCallback6(
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__ */ jsxs13("div", { className: "group/list relative grid gap-4 pb-4", children: [
2386
- wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx27(
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__ */ jsx27(
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__ */ jsx27(
953
+ /* @__PURE__ */ jsx13(
2418
954
  IconButton,
2419
955
  {
2420
- icon: /* @__PURE__ */ jsx27(AddIcon, { size: 16 }),
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 = useRef8(null);
2449
- const handleRef = useRef8(null);
2450
- const [iconHover, setIconHover] = useState11(false);
2451
- const [pickerOpen, setPickerOpen] = useState11(false);
2452
- const [editingSuppressed, setEditingSuppressed] = useState11(false);
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
- useEffect9(() => {
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__ */ jsxs13(
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__ */ jsxs13(
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__ */ jsx27(
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__ */ jsx27(Pencil, { size: 18, className: "text-base-contrast-light" }) : iconEntry ? /* @__PURE__ */ jsx27(iconEntry.icon, { size: 18 }) : /* @__PURE__ */ jsx27("span", { className: "flex h-[18px] w-[18px] items-center justify-center rounded-sm border border-dashed border-base-contrast-light/40" })
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__ */ jsx27("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx27(
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__ */ jsxs13("div", { className: stackText ? "flex flex-col" : void 0, children: [
2559
- showLabel && /* @__PURE__ */ jsx27(
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__ */ jsx27(
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__ */ jsxs13(
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__ */ jsx27(
1126
+ /* @__PURE__ */ jsx13(
2591
1127
  IconButton,
2592
1128
  {
2593
1129
  ref: handleRef,
2594
- icon: /* @__PURE__ */ jsx27(DragHandle, { size: 14 }),
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__ */ jsx27(
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__ */ jsx27(CopyPlus, { size: 14 })
1143
+ children: /* @__PURE__ */ jsx13(CopyPlus, { size: 14 })
2608
1144
  }
2609
1145
  ),
2610
- /* @__PURE__ */ jsx27(
1146
+ /* @__PURE__ */ jsx13(
2611
1147
  IconButton,
2612
1148
  {
2613
- icon: /* @__PURE__ */ jsx27(DeleteIcon, { size: 14 }),
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 = useRef8(null);
1170
+ const ref = useRef2(null);
2635
1171
  const trailingId = "__trailing__";
2636
- useEffect9(() => {
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__ */ jsx27(
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 useState12 } from "react";
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] = useState12(initialIcon);
2754
- const [showLabel, setShowLabel] = useState12(initialShowLabel);
2755
- const [stackText, setStackText] = useState12(initialStackText);
2756
- const [pickerOpen, setPickerOpen] = useState12(false);
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__ */ jsxs15("div", { className: "space-y-4", children: [
2761
- /* @__PURE__ */ jsxs15("div", { className: "relative", children: [
2762
- /* @__PURE__ */ jsx29(FormLabel, { htmlFor: "icon-picker-btn", children: "Default Icon" }),
2763
- /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
2764
- /* @__PURE__ */ jsxs15(
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__ */ jsx29(iconEntry.icon, { size: 16 }),
2772
- /* @__PURE__ */ jsx29("span", { children: iconEntry?.label ?? "None" })
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__ */ jsx29(
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__ */ jsx29("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx29(
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__ */ jsx29(
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__ */ jsx29(
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 jsx30 } from "react/jsx-runtime";
2830
- var IconListItemSchema = z6.object({
2831
- label: z6.string(),
2832
- text: z6.string(),
2833
- icon: z6.string().optional(),
2834
- dodont: z6.enum(["do", "dont"]).optional()
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 = z6.object({
2837
- type: z6.literal("icon_list"),
2838
- content: z6.object({
2839
- items: z6.array(IconListItemSchema)
1300
+ var schema5 = z5.object({
1301
+ type: z5.literal("icon_list"),
1302
+ content: z5.object({
1303
+ items: z5.array(IconListItemSchema)
2840
1304
  }),
2841
- options: z6.object({
2842
- icon: z6.string().nullable().optional(),
2843
- showLabel: z6.boolean().optional(),
2844
- stackText: z6.boolean().optional()
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__ */ jsx30(List, { size: 18 }),
1314
+ icon: /* @__PURE__ */ jsx15(List, { size: 18 }),
2851
1315
  schema: schema5,
2852
- component: ({ content, options, onChange }) => /* @__PURE__ */ jsx30(
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 z7 } from "zod";
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 as forwardRef6 } from "react";
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 useRef10, useState as useState14 } from "react";
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 = useRef10(null);
3097
- const [open, setOpen] = useState14(false);
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__ */ jsxs18("div", { className: "relative", children: [
3101
- /* @__PURE__ */ jsx37(
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__ */ jsx37(Columns3, { size: 14 })
1365
+ children: /* @__PURE__ */ jsx16(Columns3, { size: 14 })
3112
1366
  }
3113
1367
  ),
3114
- /* @__PURE__ */ jsx37(Popover, { isOpen: open, onClose: () => setOpen(false), anchorRef: buttonRef, className: "min-w-28", children: /* @__PURE__ */ jsx37("ul", { role: "list", className: "py-1", children: Array.from({ length: columns }, (_, i) => i + 1).map((span) => /* @__PURE__ */ jsx37("li", { children: /* @__PURE__ */ jsxs18(
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 jsx38, jsxs as jsxs19 } from "react/jsx-runtime";
3134
- var ChildBlockWrapper = forwardRef6(
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__ */ jsxs19(
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__ */ jsxs19("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: [
3160
- /* @__PURE__ */ jsx38("span", { className: "sr-only", children: label }),
3161
- /* @__PURE__ */ jsx38("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx38(DragHandle2, { ref: dragHandleRef }) }),
3162
- /* @__PURE__ */ jsx38("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx38(ColSpanControl, { colSpan, columns, onChange: onColSpanChange }) }),
3163
- hasSettings && onOpenSettings && /* @__PURE__ */ jsx38("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx38(SettingsButton, { onClick: onOpenSettings }) }),
3164
- /* @__PURE__ */ jsx38("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx38(
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__ */ jsx38(CopyPlus2, { size: 16 })
1425
+ children: /* @__PURE__ */ jsx17(CopyPlus2, { size: 16 })
3172
1426
  }
3173
1427
  ) }),
3174
- /* @__PURE__ */ jsx38("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx38(DeleteButton, { onDelete }) })
1428
+ /* @__PURE__ */ jsx17("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx17(DeleteButton, { onDelete }) })
3175
1429
  ] }),
3176
- closestEdge === "left" && /* @__PURE__ */ jsx38(
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__ */ jsx38(
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__ */ jsx38("div", { "data-drop-edge": "top", className: "absolute left-0 right-0 top-0 z-10 h-0.5 -translate-y-1 bg-primary" }),
3191
- closestEdge === "bottom" && /* @__PURE__ */ jsx38("div", { "data-drop-edge": "bottom", className: "absolute left-0 right-0 bottom-0 z-10 h-0.5 translate-y-1 bg-primary" }),
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 = useRef11(null);
3523
- const handleRef = useRef11(null);
3524
- const [closestEdge, setClosestEdge] = useState17(null);
3525
- const [isDragging, setIsDragging] = useState17(false);
3526
- useEffect12(() => {
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 = useRef11(null);
3583
- const [closestEdge, setClosestEdge] = useState17(null);
3584
- useEffect12(() => {
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 jsx43, jsxs as jsxs24 } from "react/jsx-runtime";
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__ */ jsx43(
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__ */ jsx43(
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__ */ jsx43(
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__ */ jsx43(
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__ */ jsx43("div", { className: "@container", children: /* @__PURE__ */ jsx43("div", { className: gridClass, children: children.map((child, index) => {
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__ */ jsx43("div", { className: cellClass, children: /* @__PURE__ */ jsx43(Child, { content: child, options: mergedOptions, isEditMode }) }, child.id ?? index);
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__ */ jsx43(
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__ */ jsx43(CustomForm, { ...seed, onChange: applyResult })
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__ */ jsx43(
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__ */ jsx43(
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__ */ jsx43("div", { className: "@container", children: /* @__PURE__ */ jsxs24("div", { className: gridClass, children: [
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__ */ jsx43(
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 useState18 } from "react";
3911
- import { jsx as jsx44, jsxs as jsxs25 } from "react/jsx-runtime";
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] = useState18({ columns, flow });
3932
- const [defaults, setDefaults] = useState18(childDefaults);
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__ */ jsxs25("div", { className: "flex flex-col gap-6", children: [
3962
- /* @__PURE__ */ jsxs25("fieldset", { className: "flex flex-col gap-4", children: [
3963
- /* @__PURE__ */ jsx44("legend", { className: "mb-2 text-sm font-semibold text-base-contrast", children: "Layout" }),
3964
- /* @__PURE__ */ jsx44(
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__ */ jsxs25("fieldset", { className: "flex flex-col gap-4 border-t border-base-200 pt-4", children: [
3981
- /* @__PURE__ */ jsx44("legend", { className: "mb-2 text-sm font-semibold text-base-contrast", children: "Apply to all items" }),
3982
- /* @__PURE__ */ jsx44(
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 jsx45 } from "react/jsx-runtime";
4000
- var schema6 = z7.object({
4001
- type: z7.literal("container"),
4002
- content: z7.object({
4003
- columns: z7.number().int().min(1).max(MAX_CONTAINER_COLUMNS).default(1),
4004
- flow: z7.enum(["row", "column"]).default("row"),
4005
- childDefaults: z7.record(z7.string(), z7.unknown()).optional(),
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: z7.array(z7.lazy(() => getSectionSchema())).default([])
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__ */ jsx45(LayoutTemplate, { size: 18 }),
1953
+ icon: /* @__PURE__ */ jsx20(LayoutTemplate, { size: 18 }),
4020
1954
  schema: schema6,
4021
- component: ({ content, onChange, isEditMode, openModal }) => /* @__PURE__ */ jsx45(Container, { content, isEditMode: !!isEditMode, onChange, openModal }),
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 z8 } from "zod";
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 jsx46 } from "react/jsx-runtime";
1969
+ import { jsx as jsx21 } from "react/jsx-runtime";
4036
1970
  function Spacer() {
4037
- return /* @__PURE__ */ jsx46("div", { "data-spacer": true, "aria-hidden": "true", className: "h-full" });
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 jsx47 } from "react/jsx-runtime";
4042
- var schema7 = z8.object({
4043
- type: z8.literal("spacer"),
4044
- content: z8.object({}).default({})
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__ */ jsx47(SquareDashed, { size: 18 }),
1983
+ icon: /* @__PURE__ */ jsx22(SquareDashed, { size: 18 }),
4050
1984
  schema: schema7,
4051
- component: () => /* @__PURE__ */ jsx47(Spacer, {}),
1985
+ component: () => /* @__PURE__ */ jsx22(Spacer, {}),
4052
1986
  defaults: () => ({ type: "spacer", content: {} })
4053
1987
  });
4054
1988