@drawnagency/primitives 0.1.61 → 0.1.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/{chunk-UQ4OYRW7.js → chunk-2BHPWO7M.js} +54 -166
  2. package/dist/chunk-4E66N6UV.js +10 -0
  3. package/dist/chunk-5THS4K5D.js +123 -0
  4. package/dist/{chunk-TG43X7JO.js → chunk-75P6HWPN.js} +29 -5
  5. package/dist/{chunk-ODCJQOVO.js → chunk-7IMQVDDJ.js} +1 -1
  6. package/dist/{chunk-4OX3Z7SB.js → chunk-FJBDGYHE.js} +32 -671
  7. package/dist/{chunk-WLMJCNU7.js → chunk-I5737FJY.js} +0 -8
  8. package/dist/chunk-JRT4KWHU.js +1201 -0
  9. package/dist/chunk-QWDOJUUO.js +648 -0
  10. package/dist/{chunk-BT7STGDW.js → chunk-TEYTLQVH.js} +0 -15
  11. package/dist/{chunk-AM5LZD6Q.js → chunk-ZYXLNJ5M.js} +6 -5
  12. package/dist/components/brandguide/ColorSwatchSettings.d.ts +1 -1
  13. package/dist/components/brandguide/ColorSwatchSettings.d.ts.map +1 -1
  14. package/dist/components/brandguide/Colors.d.ts +1 -1
  15. package/dist/components/brandguide/Colors.d.ts.map +1 -1
  16. package/dist/components/editor/index.js +4 -2
  17. package/dist/components/primitives/IconPicker.d.ts +1 -7
  18. package/dist/components/primitives/IconPicker.d.ts.map +1 -1
  19. package/dist/components/primitives/index.js +10 -7
  20. package/dist/components/sections/Colors/index.d.ts.map +1 -1
  21. package/dist/components/sections/Colors/schema.d.ts +19 -0
  22. package/dist/components/sections/Colors/schema.d.ts.map +1 -0
  23. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts +20 -0
  24. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts.map +1 -0
  25. package/dist/components/sections/DoDontMedia/index.d.ts +45 -0
  26. package/dist/components/sections/DoDontMedia/index.d.ts.map +1 -0
  27. package/dist/components/sections/IconList/DoDontToggle.d.ts +14 -0
  28. package/dist/components/sections/IconList/DoDontToggle.d.ts.map +1 -0
  29. package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
  30. package/dist/components/sections/IconList/index.d.ts.map +1 -1
  31. package/dist/components/sections/Media/MediaBlock.d.ts +1 -3
  32. package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -1
  33. package/dist/components/sections/Media/index.d.ts +0 -1
  34. package/dist/components/sections/Media/index.d.ts.map +1 -1
  35. package/dist/components/sections/all-sections.d.ts +54 -18
  36. package/dist/components/sections/all-sections.d.ts.map +1 -1
  37. package/dist/components/sections/brand-guide.d.ts +84 -0
  38. package/dist/components/sections/brand-guide.d.ts.map +1 -0
  39. package/dist/components/sections/brand-guide.js +21 -0
  40. package/dist/components/sections/core-sections.d.ts +93 -0
  41. package/dist/components/sections/core-sections.d.ts.map +1 -0
  42. package/dist/components/sections/register-schemas.js +108 -1155
  43. package/dist/index.js +29 -33
  44. package/dist/lib/index.js +4 -4
  45. package/dist/lib/loader.d.ts.map +1 -1
  46. package/dist/lib/migrate-sections-transform.d.ts.map +1 -1
  47. package/dist/lib/migrate-sections-transform.js +1 -1
  48. package/dist/lib/registry.d.ts +6 -1
  49. package/dist/lib/registry.d.ts.map +1 -1
  50. package/dist/media/index.js +1 -1
  51. package/dist/schemas/index.js +3 -7
  52. package/dist/schemas/shared.d.ts +0 -17
  53. package/dist/schemas/shared.d.ts.map +1 -1
  54. package/package.json +5 -1
  55. package/src/components/brandguide/ColorSwatchSettings.tsx +1 -1
  56. package/src/components/brandguide/Colors.tsx +1 -1
  57. package/src/components/primitives/IconPicker.tsx +27 -119
  58. package/src/components/sections/Colors/index.tsx +2 -1
  59. package/src/components/sections/Colors/schema.ts +24 -0
  60. package/src/components/sections/DoDontMedia/DoDontMediaBlock.tsx +35 -0
  61. package/src/components/sections/DoDontMedia/index.tsx +84 -0
  62. package/src/components/sections/IconList/DoDontToggle.tsx +76 -0
  63. package/src/components/sections/IconList/IconList.tsx +24 -14
  64. package/src/components/sections/IconList/index.tsx +1 -0
  65. package/src/components/sections/Media/MediaBlock.tsx +1 -11
  66. package/src/components/sections/Media/index.tsx +0 -15
  67. package/src/components/sections/all-sections.ts +7 -35
  68. package/src/components/sections/brand-guide.ts +13 -0
  69. package/src/components/sections/core-sections.ts +26 -0
  70. package/src/lib/loader.ts +10 -4
  71. package/src/lib/migrate-sections-transform.ts +33 -5
  72. package/src/lib/registry.ts +6 -1
  73. package/src/schemas/shared.ts +0 -18
@@ -0,0 +1,1201 @@
1
+ import {
2
+ Checkbox,
3
+ FormLabel,
4
+ Input
5
+ } from "./chunk-5THS4K5D.js";
6
+ import {
7
+ EditableGrid,
8
+ EditablePlainText,
9
+ MediaBlock,
10
+ containerGridClass,
11
+ useEditableCollection
12
+ } from "./chunk-QWDOJUUO.js";
13
+ import {
14
+ AddIcon,
15
+ DeleteIcon,
16
+ DragHandle,
17
+ IconButton
18
+ } from "./chunk-I5737FJY.js";
19
+ import {
20
+ DEFAULT_LINK,
21
+ LinkValueSchema
22
+ } from "./chunk-3DCG4DNU.js";
23
+ import {
24
+ curatedIcons,
25
+ getIcon
26
+ } from "./chunk-WDSVHKAH.js";
27
+ import {
28
+ cn
29
+ } from "./chunk-7EOSDFS3.js";
30
+ import {
31
+ HexColorSchema,
32
+ SingleMediaReferenceSchema
33
+ } from "./chunk-TEYTLQVH.js";
34
+ import {
35
+ defineSection
36
+ } from "./chunk-VKAGMEKE.js";
37
+
38
+ // src/components/sections/Colors/index.tsx
39
+ import { z as z2 } from "zod";
40
+ import { Palette } from "lucide-react";
41
+
42
+ // src/components/sections/Colors/schema.ts
43
+ import { z } from "zod";
44
+ var ColorSpaceSchema = z.object({
45
+ hex: HexColorSchema.optional(),
46
+ rgb: z.string().optional(),
47
+ cmyk: z.string().optional(),
48
+ pantone: z.string().optional()
49
+ }).refine(
50
+ (data) => data.hex !== void 0 || data.rgb !== void 0 || data.cmyk !== void 0 || data.pantone !== void 0,
51
+ { message: "At least one color space must be defined" }
52
+ );
53
+ var ColorItemSchema = z.object({
54
+ name: z.string().optional(),
55
+ spaces: z.array(ColorSpaceSchema).min(1)
56
+ });
57
+
58
+ // src/components/brandguide/Colors.tsx
59
+ import { useState as useState2, useEffect } from "react";
60
+ import { Eye, EyeOff } from "lucide-react";
61
+
62
+ // src/components/brandguide/ColorSwatchSettings.tsx
63
+ import { useState } from "react";
64
+ import { jsx, jsxs } from "react/jsx-runtime";
65
+ function mergeSpaces(spaces) {
66
+ return Object.assign({}, ...spaces);
67
+ }
68
+ function ColorSwatchSettings({ color, onChange }) {
69
+ const [localColor, setLocalColor] = useState(() => ({
70
+ ...color,
71
+ spaces: [mergeSpaces(color.spaces)]
72
+ }));
73
+ const space = localColor.spaces[0] || {};
74
+ const update = (updated) => {
75
+ setLocalColor(updated);
76
+ onChange(updated);
77
+ };
78
+ const updateSpace = (key, value) => {
79
+ const newSpace = { ...space, [key]: value || void 0 };
80
+ update({ ...localColor, spaces: [newSpace] });
81
+ };
82
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
83
+ /* @__PURE__ */ jsx(
84
+ Input,
85
+ {
86
+ label: "Name",
87
+ value: localColor.name || "",
88
+ onChange: (name) => update({ ...localColor, name })
89
+ }
90
+ ),
91
+ ["hex", "rgb", "cmyk", "pantone"].map((key) => /* @__PURE__ */ jsx(
92
+ Input,
93
+ {
94
+ label: key.toUpperCase(),
95
+ value: space[key] || "",
96
+ onChange: (value) => updateSpace(key, value)
97
+ },
98
+ key
99
+ ))
100
+ ] });
101
+ }
102
+
103
+ // src/components/brandguide/Colors.tsx
104
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
105
+ function getContrastClass(hex) {
106
+ if (!hex) return "text-white";
107
+ const h = hex.replace("#", "");
108
+ if (h.length < 6) return "text-white";
109
+ const r = parseInt(h.substring(0, 2), 16);
110
+ const g = parseInt(h.substring(2, 4), 16);
111
+ const b = parseInt(h.substring(4, 6), 16);
112
+ const yiq = (r * 299 + g * 587 + b * 114) / 1e3;
113
+ return yiq >= 128 ? "text-black" : "text-white";
114
+ }
115
+ var createColorItem = () => ({
116
+ name: "",
117
+ spaces: [{ hex: "#cccccc" }]
118
+ });
119
+ function buildContent(colors, options) {
120
+ const { label, columns, collapsing, showLabel } = options;
121
+ return {
122
+ type: "colors",
123
+ content: { colors },
124
+ ...label || columns || collapsing !== void 0 || showLabel !== void 0 ? { options: { label, columns, collapsing, showLabel } } : {}
125
+ };
126
+ }
127
+ function Colors({ colors, columns = 3, label, collapsing, showLabel = true, onChange, openModal }) {
128
+ if (onChange && openModal) {
129
+ return /* @__PURE__ */ jsx2(
130
+ ColorsEditable,
131
+ {
132
+ colors,
133
+ columns,
134
+ label,
135
+ collapsing,
136
+ showLabel,
137
+ onChange,
138
+ openModal
139
+ }
140
+ );
141
+ }
142
+ return /* @__PURE__ */ jsx2(ColorsView, { colors, columns, label, collapsing, showLabel });
143
+ }
144
+ function ColorsView({
145
+ colors,
146
+ columns,
147
+ label,
148
+ collapsing,
149
+ showLabel
150
+ }) {
151
+ const [expanded, setExpanded] = useState2(!collapsing);
152
+ const [copiedIndex, setCopiedIndex] = useState2(null);
153
+ const handleCopy = (value, colorIndex) => {
154
+ if (navigator.clipboard?.writeText) {
155
+ navigator.clipboard.writeText(value);
156
+ } else {
157
+ const ta = document.createElement("textarea");
158
+ ta.value = value;
159
+ ta.style.position = "fixed";
160
+ ta.style.opacity = "0";
161
+ document.body.appendChild(ta);
162
+ ta.select();
163
+ document.execCommand("copy");
164
+ document.body.removeChild(ta);
165
+ }
166
+ setCopiedIndex(colorIndex);
167
+ setTimeout(() => setCopiedIndex(null), 1500);
168
+ };
169
+ return /* @__PURE__ */ jsxs2("div", { children: [
170
+ (showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs2("div", { className: "mb-4 flex items-center gap-2", children: [
171
+ showLabel && !!label && /* @__PURE__ */ jsx2("span", { className: "text-lg font-bold", children: label }),
172
+ collapsing && /* @__PURE__ */ jsxs2(
173
+ "button",
174
+ {
175
+ onClick: () => setExpanded(!expanded),
176
+ className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast",
177
+ children: [
178
+ /* @__PURE__ */ jsx2("span", { children: expanded ? "Hide Details" : "Show Details" }),
179
+ expanded ? /* @__PURE__ */ jsx2(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx2(Eye, { size: 16 })
180
+ ]
181
+ }
182
+ )
183
+ ] }),
184
+ /* @__PURE__ */ jsx2("div", { className: "@container", children: /* @__PURE__ */ jsx2("div", { className: cn("grid gap-4", containerGridClass[columns] || containerGridClass[3]), children: colors.map((color, i) => {
185
+ const hex = color.spaces[0]?.hex;
186
+ const contrast = getContrastClass(hex);
187
+ return /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
188
+ /* @__PURE__ */ jsxs2("div", { className: cn("relative flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: [
189
+ color.name && /* @__PURE__ */ jsx2("span", { className: "text-sm font-bold", children: color.name }),
190
+ copiedIndex === i && /* @__PURE__ */ jsx2("span", { className: cn(
191
+ "absolute top-2 right-2 rounded-full px-2.5 py-0.5 text-xs font-medium",
192
+ getContrastClass(hex) === "text-black" ? "bg-black/15 text-black" : "bg-white/25 text-white"
193
+ ), children: "Copied!" })
194
+ ] }),
195
+ expanded && /* @__PURE__ */ jsx2("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
196
+ (space, j) => Object.entries(space).map(
197
+ ([key, value]) => value ? /* @__PURE__ */ jsxs2("button", { onClick: () => handleCopy(value, i), className: "cursor-pointer flex w-full justify-between hover:text-primary", children: [
198
+ /* @__PURE__ */ jsx2("span", { className: "font-medium uppercase", children: key }),
199
+ /* @__PURE__ */ jsx2("span", { children: value })
200
+ ] }, `${j}-${key}`) : null
201
+ )
202
+ ) })
203
+ ] }, i);
204
+ }) }) })
205
+ ] });
206
+ }
207
+ function ColorsEditable({
208
+ colors,
209
+ columns,
210
+ label,
211
+ collapsing,
212
+ showLabel,
213
+ onChange,
214
+ openModal
215
+ }) {
216
+ const [expanded, setExpanded] = useState2(!collapsing);
217
+ const options = { label, columns, collapsing, showLabel };
218
+ useEffect(() => {
219
+ setExpanded(!collapsing);
220
+ }, [collapsing]);
221
+ const handleItemSettings = (index) => {
222
+ const color = colors[index];
223
+ openModal(
224
+ "Color Settings",
225
+ /* @__PURE__ */ jsx2(ColorSwatchSettings, { color, onChange: (updated) => {
226
+ const newColors = colors.map((c, i) => i === index ? updated : c);
227
+ onChange(buildContent(newColors, options));
228
+ } })
229
+ );
230
+ };
231
+ return /* @__PURE__ */ jsxs2("div", { children: [
232
+ (showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs2("div", { className: "mb-4 flex items-center gap-2", children: [
233
+ showLabel && !!label && /* @__PURE__ */ jsx2(
234
+ EditablePlainText,
235
+ {
236
+ tag: "span",
237
+ value: label,
238
+ onChange: (newLabel) => onChange(buildContent(colors, { ...options, label: newLabel })),
239
+ isEditMode: true,
240
+ className: "text-lg font-bold"
241
+ }
242
+ ),
243
+ collapsing && /* @__PURE__ */ jsxs2(
244
+ "button",
245
+ {
246
+ onClick: () => setExpanded(!expanded),
247
+ className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast",
248
+ children: [
249
+ /* @__PURE__ */ jsx2("span", { children: expanded ? "Hide Details" : "Show Details" }),
250
+ expanded ? /* @__PURE__ */ jsx2(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx2(Eye, { size: 16 })
251
+ ]
252
+ }
253
+ )
254
+ ] }),
255
+ /* @__PURE__ */ jsx2(
256
+ EditableGrid,
257
+ {
258
+ items: colors,
259
+ columns,
260
+ onChange: (newColors) => onChange(buildContent(newColors, options)),
261
+ createItem: createColorItem,
262
+ isEditMode: true,
263
+ onItemSettings: handleItemSettings,
264
+ renderItem: (color, { index }) => /* @__PURE__ */ jsx2(
265
+ ColorSwatchEditable,
266
+ {
267
+ color,
268
+ index,
269
+ colors,
270
+ options,
271
+ onChange,
272
+ expanded
273
+ }
274
+ )
275
+ }
276
+ )
277
+ ] });
278
+ }
279
+ function ColorSwatchEditable({
280
+ color,
281
+ index,
282
+ colors,
283
+ options,
284
+ onChange,
285
+ expanded
286
+ }) {
287
+ const hex = color.spaces[0]?.hex;
288
+ const contrast = getContrastClass(hex);
289
+ const updateColor = (updated) => {
290
+ const newColors = colors.map((c, i) => i === index ? updated : c);
291
+ onChange(buildContent(newColors, options));
292
+ };
293
+ return /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
294
+ /* @__PURE__ */ jsx2("div", { className: cn("flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: /* @__PURE__ */ jsx2(
295
+ EditablePlainText,
296
+ {
297
+ tag: "span",
298
+ value: color.name || "",
299
+ onChange: (name) => updateColor({ ...color, name }),
300
+ isEditMode: true,
301
+ placeholder: "Color name",
302
+ className: "text-sm font-bold"
303
+ }
304
+ ) }),
305
+ expanded && /* @__PURE__ */ jsx2("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
306
+ (space, j) => Object.entries(space).map(
307
+ ([key, value]) => value ? /* @__PURE__ */ jsxs2("div", { className: "flex w-full justify-between", children: [
308
+ /* @__PURE__ */ jsx2("span", { className: "font-medium uppercase", children: key }),
309
+ /* @__PURE__ */ jsx2("span", { children: value })
310
+ ] }, `${j}-${key}`) : null
311
+ )
312
+ ) })
313
+ ] });
314
+ }
315
+
316
+ // src/lib/text.ts
317
+ function stripHtmlToPlainText(html) {
318
+ return html.replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1>/gi, "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
319
+ }
320
+ function truncate(text, maxLength) {
321
+ if (text.length <= maxLength) return text;
322
+ return text.slice(0, maxLength) + "...";
323
+ }
324
+ function pluralize(n, word) {
325
+ return `${n} ${word}${n === 1 ? "" : "s"}`;
326
+ }
327
+
328
+ // src/components/sections/Colors/index.tsx
329
+ import { jsx as jsx3 } from "react/jsx-runtime";
330
+ var schema = z2.object({
331
+ type: z2.literal("colors"),
332
+ content: z2.object({ colors: z2.array(ColorItemSchema) }),
333
+ options: z2.object({
334
+ label: z2.string().optional(),
335
+ columns: z2.number().int().min(2).max(4).optional(),
336
+ collapsing: z2.boolean().optional(),
337
+ showLabel: z2.boolean().optional()
338
+ }).optional()
339
+ });
340
+ var Colors_default = defineSection({
341
+ type: "colors",
342
+ category: "brand-guide",
343
+ label: "Colors",
344
+ icon: /* @__PURE__ */ jsx3(Palette, { size: 18 }),
345
+ schema,
346
+ component: ({ content, options, onChange, openModal }) => /* @__PURE__ */ jsx3(
347
+ Colors,
348
+ {
349
+ colors: content.content.colors,
350
+ columns: options?.columns,
351
+ label: options?.label,
352
+ collapsing: options?.collapsing,
353
+ showLabel: options?.showLabel,
354
+ onChange: onChange ? (c) => onChange(c) : void 0,
355
+ openModal
356
+ }
357
+ ),
358
+ defaults: () => ({
359
+ type: "colors",
360
+ content: { colors: [{ spaces: [{ hex: "#000000" }] }] }
361
+ }),
362
+ getLabel: (content) => pluralize(content.content.colors.length, "color"),
363
+ getThumbnails: (content) => content.content.colors.filter((c) => c.spaces[0]?.hex).map((c) => ({ type: "color", value: c.spaces[0].hex })),
364
+ settings: {
365
+ columns: {
366
+ type: "select",
367
+ label: "Columns",
368
+ default: "3",
369
+ coerce: "number",
370
+ options: [{ label: "2", value: "2" }, { label: "3", value: "3" }, { label: "4", value: "4" }]
371
+ },
372
+ label: { type: "text", label: "Label", default: "", placeholder: "Color Section Label" },
373
+ showLabel: { type: "checkbox", label: "Show label", default: true },
374
+ collapsing: { type: "checkbox", label: "Collapsing layout", default: false }
375
+ }
376
+ });
377
+
378
+ // src/components/sections/IconList/index.tsx
379
+ import { z as z3 } from "zod";
380
+ import { List } from "lucide-react";
381
+
382
+ // src/components/sections/IconList/IconList.tsx
383
+ import { useRef as useRef3, useEffect as useEffect4, useState as useState3, useCallback } from "react";
384
+ import { Check as Check2, CopyPlus, Pencil, X as X2 } from "lucide-react";
385
+
386
+ // src/components/primitives/IconPicker.tsx
387
+ import { useEffect as useEffect2, useRef } from "react";
388
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
389
+ function IconPicker({ selected, onSelect, onClose, showRemove = true }) {
390
+ const panelRef = useRef(null);
391
+ useEffect2(() => {
392
+ function handleMouseDown(e) {
393
+ if (panelRef.current && !panelRef.current.contains(e.target)) onClose();
394
+ }
395
+ document.addEventListener("mousedown", handleMouseDown);
396
+ return () => document.removeEventListener("mousedown", handleMouseDown);
397
+ }, [onClose]);
398
+ return /* @__PURE__ */ jsxs3(
399
+ "div",
400
+ {
401
+ ref: panelRef,
402
+ className: "absolute z-50 w-56 rounded-lg border border-base-200 bg-base p-2 shadow-lg",
403
+ children: [
404
+ /* @__PURE__ */ jsx4("div", { className: "grid grid-cols-5 gap-1", children: curatedIcons.map((entry) => {
405
+ const Icon = entry.icon;
406
+ const isSelected = selected === entry.id;
407
+ return /* @__PURE__ */ jsx4(
408
+ "button",
409
+ {
410
+ "aria-label": entry.label,
411
+ className: cn(
412
+ "cursor-pointer flex h-9 w-9 items-center justify-center rounded transition-colors",
413
+ "text-base-contrast-light hover:bg-base-accent hover:text-base-contrast",
414
+ isSelected && "ring-2 ring-primary bg-base-accent text-primary"
415
+ ),
416
+ onClick: () => onSelect(entry.id),
417
+ children: /* @__PURE__ */ jsx4(Icon, { size: 18 })
418
+ },
419
+ entry.id
420
+ );
421
+ }) }),
422
+ showRemove && /* @__PURE__ */ jsx4(
423
+ "button",
424
+ {
425
+ 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",
426
+ onClick: () => onSelect(null),
427
+ children: "Remove icon"
428
+ }
429
+ )
430
+ ]
431
+ }
432
+ );
433
+ }
434
+
435
+ // src/components/sections/IconList/DoDontToggle.tsx
436
+ import { useEffect as useEffect3, useRef as useRef2 } from "react";
437
+ import { Check, X } from "lucide-react";
438
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
439
+ function DoDontToggle({ value, onSelect, onClose }) {
440
+ const panelRef = useRef2(null);
441
+ useEffect3(() => {
442
+ function handleMouseDown(e) {
443
+ if (panelRef.current && !panelRef.current.contains(e.target)) onClose();
444
+ }
445
+ document.addEventListener("mousedown", handleMouseDown);
446
+ return () => document.removeEventListener("mousedown", handleMouseDown);
447
+ }, [onClose]);
448
+ return /* @__PURE__ */ jsx5(
449
+ "div",
450
+ {
451
+ ref: panelRef,
452
+ className: "absolute z-50 w-44 rounded-lg border border-base-200 bg-base p-2 shadow-lg",
453
+ children: /* @__PURE__ */ jsxs4("div", { className: "grid grid-cols-3 gap-2", children: [
454
+ /* @__PURE__ */ jsxs4(
455
+ "button",
456
+ {
457
+ type: "button",
458
+ "aria-label": "No do/don't tag",
459
+ className: cn(
460
+ "cursor-pointer flex flex-col items-center justify-center gap-1 rounded py-2 transition-colors",
461
+ "text-base-contrast-light hover:bg-base-accent",
462
+ value === void 0 && "ring-2 ring-primary bg-base-accent"
463
+ ),
464
+ onClick: () => onSelect(void 0),
465
+ children: [
466
+ /* @__PURE__ */ jsx5("span", { className: "flex h-5 w-5 items-center justify-center rounded-sm border border-dashed border-base-contrast-light/40" }),
467
+ /* @__PURE__ */ jsx5("span", { className: "text-xs font-medium", children: "None" })
468
+ ]
469
+ }
470
+ ),
471
+ /* @__PURE__ */ jsxs4(
472
+ "button",
473
+ {
474
+ type: "button",
475
+ "aria-label": "Do",
476
+ className: cn(
477
+ "cursor-pointer flex flex-col items-center justify-center gap-1 rounded py-2 transition-colors",
478
+ "text-green-600 hover:bg-base-accent",
479
+ value === "do" && "ring-2 ring-primary bg-base-accent"
480
+ ),
481
+ onClick: () => onSelect("do"),
482
+ children: [
483
+ /* @__PURE__ */ jsx5(Check, { size: 20 }),
484
+ /* @__PURE__ */ jsx5("span", { className: "text-xs font-medium", children: "Do" })
485
+ ]
486
+ }
487
+ ),
488
+ /* @__PURE__ */ jsxs4(
489
+ "button",
490
+ {
491
+ type: "button",
492
+ "aria-label": "Don't",
493
+ className: cn(
494
+ "cursor-pointer flex flex-col items-center justify-center gap-1 rounded py-2 transition-colors",
495
+ "text-red-600 hover:bg-base-accent",
496
+ value === "dont" && "ring-2 ring-primary bg-base-accent"
497
+ ),
498
+ onClick: () => onSelect("dont"),
499
+ children: [
500
+ /* @__PURE__ */ jsx5(X, { size: 20 }),
501
+ /* @__PURE__ */ jsx5("span", { className: "text-xs font-medium", children: "Don't" })
502
+ ]
503
+ }
504
+ )
505
+ ] })
506
+ }
507
+ );
508
+ }
509
+
510
+ // src/components/sections/IconList/IconList.tsx
511
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
512
+ function IconList({
513
+ items,
514
+ icon = null,
515
+ showLabel = true,
516
+ stackText = false,
517
+ labelClassName = "font-bold text-base-contrast",
518
+ textClassName = "text-base-contrast-light",
519
+ iconClassName = "text-primary",
520
+ onChange,
521
+ onItemsChange
522
+ }) {
523
+ const isEditMode = !!onChange || !!onItemsChange;
524
+ const emitItems = useCallback(
525
+ (newItems) => {
526
+ onChange?.({
527
+ type: "icon_list",
528
+ content: { items: newItems },
529
+ options: { icon, showLabel, stackText }
530
+ });
531
+ onItemsChange?.(newItems);
532
+ },
533
+ [onChange, onItemsChange, icon, showLabel, stackText]
534
+ );
535
+ if (!isEditMode) {
536
+ return /* @__PURE__ */ jsx6(
537
+ ViewIconList,
538
+ {
539
+ items,
540
+ defaultIcon: icon,
541
+ showLabel,
542
+ stackText,
543
+ labelClassName,
544
+ textClassName,
545
+ iconClassName
546
+ }
547
+ );
548
+ }
549
+ return /* @__PURE__ */ jsx6(
550
+ EditIconList,
551
+ {
552
+ items,
553
+ defaultIcon: icon,
554
+ showLabel,
555
+ stackText,
556
+ labelClassName,
557
+ textClassName,
558
+ iconClassName,
559
+ onItemsChange: emitItems
560
+ }
561
+ );
562
+ }
563
+ function resolveIcon(item, defaultIcon) {
564
+ if (item.dodont === "do") return getIcon("check") ?? null;
565
+ if (item.dodont === "dont") return getIcon("x") ?? null;
566
+ const id = item.icon ?? defaultIcon;
567
+ return id ? getIcon(id) : null;
568
+ }
569
+ function resolveIconColor(item, iconClassName) {
570
+ if (item.dodont === "do") return "text-green-600";
571
+ if (item.dodont === "dont") return "text-red-600";
572
+ return iconClassName;
573
+ }
574
+ function ViewIconList({
575
+ items,
576
+ defaultIcon,
577
+ showLabel,
578
+ stackText,
579
+ labelClassName,
580
+ textClassName,
581
+ iconClassName
582
+ }) {
583
+ const hasAnyIcon = items.some((item) => resolveIcon(item, defaultIcon));
584
+ return /* @__PURE__ */ jsx6("div", { className: "grid gap-4 pb-4", children: items.map((item, i) => {
585
+ const iconEntry = resolveIcon(item, defaultIcon);
586
+ const iconColor = resolveIconColor(item, iconClassName);
587
+ return /* @__PURE__ */ jsxs5(
588
+ "div",
589
+ {
590
+ className: cn(
591
+ "grid gap-x-3",
592
+ hasAnyIcon ? "grid-cols-[24px_1fr]" : "grid-cols-1"
593
+ ),
594
+ children: [
595
+ hasAnyIcon && /* @__PURE__ */ jsx6(
596
+ "div",
597
+ {
598
+ "data-testid": "icon-list-icon",
599
+ className: cn("flex items-start pt-0.5", iconColor),
600
+ children: iconEntry && /* @__PURE__ */ jsx6(iconEntry.icon, { size: 18 })
601
+ }
602
+ ),
603
+ /* @__PURE__ */ jsxs5(
604
+ "div",
605
+ {
606
+ "data-testid": "icon-list-content",
607
+ className: stackText ? "flex flex-col" : void 0,
608
+ children: [
609
+ showLabel && /* @__PURE__ */ jsxs5("span", { className: labelClassName, children: [
610
+ item.label,
611
+ !stackText && " "
612
+ ] }),
613
+ /* @__PURE__ */ jsx6("span", { className: textClassName, children: item.text })
614
+ ]
615
+ }
616
+ )
617
+ ]
618
+ },
619
+ i
620
+ );
621
+ }) });
622
+ }
623
+ function EditIconList({
624
+ items,
625
+ defaultIcon,
626
+ showLabel,
627
+ stackText,
628
+ labelClassName,
629
+ textClassName,
630
+ iconClassName,
631
+ onItemsChange
632
+ }) {
633
+ const { wrappedItems, onReorder, onAdd, onRemove } = useEditableCollection({
634
+ items,
635
+ onChange: onItemsChange,
636
+ createItem: () => ({ label: "", text: "" })
637
+ });
638
+ const [dragState, setDragState] = useState3({ sourceId: null, targetId: null });
639
+ const updateItem = useCallback(
640
+ (index, patch) => {
641
+ const updated = wrappedItems.map(
642
+ (w, i) => i === index ? { ...w.data, ...patch } : w.data
643
+ );
644
+ onItemsChange(updated);
645
+ },
646
+ [wrappedItems, onItemsChange]
647
+ );
648
+ const duplicateItem = useCallback(
649
+ (index) => {
650
+ const copy = { ...wrappedItems[index].data };
651
+ const next = [
652
+ ...wrappedItems.slice(0, index + 1).map((w) => w.data),
653
+ copy,
654
+ ...wrappedItems.slice(index + 1).map((w) => w.data)
655
+ ];
656
+ onItemsChange(next);
657
+ },
658
+ [wrappedItems, onItemsChange]
659
+ );
660
+ const hasAnyIcon = true;
661
+ return /* @__PURE__ */ jsxs5("div", { className: "group/list relative grid gap-4 pb-4", children: [
662
+ wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx6(
663
+ EditableRow,
664
+ {
665
+ id: wrapped.id,
666
+ index,
667
+ item: wrapped.data,
668
+ defaultIcon,
669
+ hasAnyIcon,
670
+ showLabel,
671
+ stackText,
672
+ labelClassName,
673
+ textClassName,
674
+ iconClassName,
675
+ dragState,
676
+ setDragState,
677
+ onReorder,
678
+ onRemove,
679
+ onUpdateItem: (patch) => updateItem(index, patch),
680
+ onDuplicate: () => duplicateItem(index)
681
+ },
682
+ wrapped.id
683
+ )),
684
+ /* @__PURE__ */ jsx6(
685
+ TrailingDropZone,
686
+ {
687
+ index: wrappedItems.length,
688
+ dragState,
689
+ setDragState,
690
+ onReorder
691
+ }
692
+ ),
693
+ /* @__PURE__ */ jsx6(
694
+ IconButton,
695
+ {
696
+ icon: /* @__PURE__ */ jsx6(AddIcon, { size: 16 }),
697
+ label: "Add item",
698
+ size: "lg",
699
+ intent: "primary",
700
+ onClick: onAdd,
701
+ 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/list:opacity-100"
702
+ }
703
+ )
704
+ ] });
705
+ }
706
+ function EditableRow({
707
+ id,
708
+ index,
709
+ item,
710
+ defaultIcon,
711
+ hasAnyIcon,
712
+ showLabel,
713
+ stackText,
714
+ labelClassName,
715
+ textClassName,
716
+ iconClassName,
717
+ dragState,
718
+ setDragState,
719
+ onReorder,
720
+ onRemove,
721
+ onUpdateItem,
722
+ onDuplicate
723
+ }) {
724
+ const rowRef = useRef3(null);
725
+ const handleRef = useRef3(null);
726
+ const [iconHover, setIconHover] = useState3(false);
727
+ const [pickerOpen, setPickerOpen] = useState3(false);
728
+ const [dodontOpen, setDodontOpen] = useState3(false);
729
+ const [editingSuppressed, setEditingSuppressed] = useState3(false);
730
+ const iconEntry = resolveIcon(item, defaultIcon);
731
+ const effectiveIconId = item.icon ?? defaultIcon ?? null;
732
+ const iconColor = resolveIconColor(item, iconClassName);
733
+ useEffect4(() => {
734
+ const row = rowRef.current;
735
+ const handle = handleRef.current;
736
+ if (!row || !handle) return;
737
+ let cleanup;
738
+ let cancelled = false;
739
+ import("./adapter-HH47ZPGM.js").then(({ draggable, dropTargetForElements }) => {
740
+ if (cancelled) return;
741
+ const cleanupDraggable = draggable({
742
+ element: handle,
743
+ getInitialData: () => ({ dragType: "icon-list-row", id, index }),
744
+ onDragStart: () => setDragState({ sourceId: id, targetId: null }),
745
+ onDrop: () => setDragState({ sourceId: null, targetId: null })
746
+ });
747
+ const cleanupDropTarget = dropTargetForElements({
748
+ element: row,
749
+ canDrop: ({ source }) => source.data.dragType === "icon-list-row",
750
+ getData: () => ({ id, index }),
751
+ onDragEnter: () => setDragState((prev) => ({ ...prev, targetId: id })),
752
+ onDragLeave: () => setDragState(
753
+ (prev) => prev.targetId === id ? { ...prev, targetId: null } : prev
754
+ ),
755
+ onDrop: ({ source }) => {
756
+ const fromIndex = source.data.index;
757
+ if (fromIndex !== index) onReorder(fromIndex, index);
758
+ }
759
+ });
760
+ cleanup = () => {
761
+ cleanupDraggable();
762
+ cleanupDropTarget();
763
+ };
764
+ });
765
+ return () => {
766
+ cancelled = true;
767
+ cleanup?.();
768
+ };
769
+ }, [id, index, onReorder, setDragState]);
770
+ const isDropTarget = dragState.targetId === id && dragState.sourceId !== id;
771
+ const onEditableActivity = (e) => {
772
+ const t = e.target;
773
+ if (t.matches?.("input, textarea, [contenteditable], [contenteditable='true']")) {
774
+ setEditingSuppressed(true);
775
+ }
776
+ };
777
+ return /* @__PURE__ */ jsxs5(
778
+ "div",
779
+ {
780
+ ref: rowRef,
781
+ className: cn(
782
+ "group/row relative grid gap-x-3",
783
+ hasAnyIcon ? "grid-cols-[24px_1fr]" : "grid-cols-1",
784
+ isDropTarget && "border-t-2 border-primary"
785
+ ),
786
+ onFocusCapture: onEditableActivity,
787
+ onInput: onEditableActivity,
788
+ onMouseMove: () => setEditingSuppressed(false),
789
+ children: [
790
+ hasAnyIcon && /* @__PURE__ */ jsxs5(
791
+ "div",
792
+ {
793
+ "data-testid": "icon-list-icon",
794
+ className: cn("relative flex items-start pt-0.5", iconColor),
795
+ onMouseEnter: () => setIconHover(true),
796
+ onMouseLeave: () => setIconHover(false),
797
+ children: [
798
+ /* @__PURE__ */ jsx6(
799
+ "button",
800
+ {
801
+ className: "cursor-pointer transition-opacity hover:opacity-70",
802
+ "aria-label": "Change icon",
803
+ onClick: () => {
804
+ setPickerOpen((prev) => !prev);
805
+ setDodontOpen(false);
806
+ },
807
+ children: iconHover && !pickerOpen ? /* @__PURE__ */ jsx6(Pencil, { size: 18, className: "text-base-contrast-light" }) : iconEntry ? /* @__PURE__ */ jsx6(iconEntry.icon, { size: 18 }) : /* @__PURE__ */ jsx6("span", { className: "flex h-[18px] w-[18px] items-center justify-center rounded-sm border border-dashed border-base-contrast-light/40" })
808
+ }
809
+ ),
810
+ pickerOpen && /* @__PURE__ */ jsx6("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx6(
811
+ IconPicker,
812
+ {
813
+ selected: effectiveIconId,
814
+ showRemove: true,
815
+ onSelect: (newIcon) => {
816
+ onUpdateItem({ icon: newIcon ?? void 0, dodont: void 0 });
817
+ setPickerOpen(false);
818
+ setIconHover(false);
819
+ },
820
+ onClose: () => {
821
+ setPickerOpen(false);
822
+ setIconHover(false);
823
+ }
824
+ }
825
+ ) })
826
+ ]
827
+ }
828
+ ),
829
+ /* @__PURE__ */ jsxs5("div", { className: stackText ? "flex flex-col" : void 0, children: [
830
+ showLabel && /* @__PURE__ */ jsx6(
831
+ EditablePlainText,
832
+ {
833
+ tag: "span",
834
+ value: item.label,
835
+ onChange: (label) => onUpdateItem({ label }),
836
+ isEditMode: true,
837
+ placeholder: "Label",
838
+ className: cn(labelClassName, !stackText && "mr-1")
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsx6(
842
+ EditablePlainText,
843
+ {
844
+ tag: "span",
845
+ value: item.text,
846
+ onChange: (text) => onUpdateItem({ text }),
847
+ isEditMode: true,
848
+ placeholder: "Text",
849
+ className: textClassName
850
+ }
851
+ )
852
+ ] }),
853
+ /* @__PURE__ */ jsxs5(
854
+ "div",
855
+ {
856
+ className: cn(
857
+ "absolute right-1 top-1 z-10 flex items-center gap-1",
858
+ editingSuppressed ? "opacity-0 pointer-events-none" : "opacity-0 group-hover/row:opacity-100 no-hover:opacity-100"
859
+ ),
860
+ children: [
861
+ /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
862
+ /* @__PURE__ */ jsx6(
863
+ "button",
864
+ {
865
+ "aria-label": "Set do/don't",
866
+ onClick: () => {
867
+ setDodontOpen((p) => !p);
868
+ setPickerOpen(false);
869
+ },
870
+ className: "cursor-pointer rounded bg-base/80 p-1 shadow-sm text-base-contrast-light hover:text-primary",
871
+ children: item.dodont === "do" ? /* @__PURE__ */ jsx6(Check2, { size: 14, className: "text-green-600" }) : item.dodont === "dont" ? /* @__PURE__ */ jsx6(X2, { size: 14, className: "text-red-600" }) : /* @__PURE__ */ jsx6(Pencil, { size: 14 })
872
+ }
873
+ ),
874
+ dodontOpen && /* @__PURE__ */ jsx6("div", { className: "absolute top-full right-0 z-50 mt-1", children: /* @__PURE__ */ jsx6(
875
+ DoDontToggle,
876
+ {
877
+ value: item.dodont,
878
+ onSelect: (v) => {
879
+ onUpdateItem({ dodont: v });
880
+ setDodontOpen(false);
881
+ },
882
+ onClose: () => setDodontOpen(false)
883
+ }
884
+ ) })
885
+ ] }),
886
+ /* @__PURE__ */ jsx6(
887
+ IconButton,
888
+ {
889
+ ref: handleRef,
890
+ icon: /* @__PURE__ */ jsx6(DragHandle, { size: 14 }),
891
+ label: "Drag to reorder",
892
+ size: "sm",
893
+ className: "cursor-grab rounded bg-base/80 p-1 shadow-sm text-base-contrast-light/80 hover:text-base-contrast active:cursor-grabbing",
894
+ tabIndex: -1
895
+ }
896
+ ),
897
+ /* @__PURE__ */ jsx6(
898
+ "button",
899
+ {
900
+ "aria-label": "Duplicate item",
901
+ onClick: onDuplicate,
902
+ className: "cursor-pointer rounded bg-base/80 p-1 shadow-sm text-base-contrast-light hover:text-primary",
903
+ children: /* @__PURE__ */ jsx6(CopyPlus, { size: 14 })
904
+ }
905
+ ),
906
+ /* @__PURE__ */ jsx6(
907
+ IconButton,
908
+ {
909
+ icon: /* @__PURE__ */ jsx6(DeleteIcon, { size: 14 }),
910
+ label: "Delete item",
911
+ size: "sm",
912
+ intent: "destructive",
913
+ onClick: () => onRemove(id),
914
+ className: "bg-base/80 shadow-sm"
915
+ }
916
+ )
917
+ ]
918
+ }
919
+ )
920
+ ]
921
+ }
922
+ );
923
+ }
924
+ function TrailingDropZone({
925
+ index,
926
+ dragState,
927
+ setDragState,
928
+ onReorder
929
+ }) {
930
+ const ref = useRef3(null);
931
+ const trailingId = "__trailing__";
932
+ useEffect4(() => {
933
+ const el = ref.current;
934
+ if (!el) return;
935
+ let cleanup;
936
+ let cancelled = false;
937
+ import("./adapter-HH47ZPGM.js").then(({ dropTargetForElements }) => {
938
+ if (cancelled) return;
939
+ cleanup = dropTargetForElements({
940
+ element: el,
941
+ canDrop: ({ source }) => source.data.dragType === "icon-list-row",
942
+ getData: () => ({ id: trailingId, index }),
943
+ onDragEnter: () => setDragState((prev) => ({ ...prev, targetId: trailingId })),
944
+ onDragLeave: () => setDragState(
945
+ (prev) => prev.targetId === trailingId ? { ...prev, targetId: null } : prev
946
+ ),
947
+ onDrop: ({ source }) => {
948
+ const fromIndex = source.data.index;
949
+ if (fromIndex !== index - 1) onReorder(fromIndex, index - 1);
950
+ }
951
+ });
952
+ });
953
+ return () => {
954
+ cancelled = true;
955
+ cleanup?.();
956
+ };
957
+ }, [index, onReorder, setDragState]);
958
+ const isDropTarget = dragState.targetId === trailingId && dragState.sourceId !== null;
959
+ return /* @__PURE__ */ jsx6(
960
+ "div",
961
+ {
962
+ ref,
963
+ className: cn("absolute bottom-0 left-0 right-0 h-4", isDropTarget && "border-t-2 border-primary")
964
+ }
965
+ );
966
+ }
967
+
968
+ // src/components/sections/IconList/IconListSettings.tsx
969
+ import { useState as useState4 } from "react";
970
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
971
+ function IconListSettings({
972
+ icon: initialIcon,
973
+ showLabel: initialShowLabel,
974
+ stackText: initialStackText,
975
+ onChange
976
+ }) {
977
+ const [icon, setIcon] = useState4(initialIcon);
978
+ const [showLabel, setShowLabel] = useState4(initialShowLabel);
979
+ const [stackText, setStackText] = useState4(initialStackText);
980
+ const [pickerOpen, setPickerOpen] = useState4(false);
981
+ const emit = (overrides) => onChange({ content: {}, options: { icon, showLabel, stackText, ...overrides } });
982
+ const showIcons = icon !== null;
983
+ const iconEntry = icon ? getIcon(icon) : null;
984
+ return /* @__PURE__ */ jsxs6("div", { className: "space-y-4", children: [
985
+ /* @__PURE__ */ jsxs6("div", { className: "relative", children: [
986
+ /* @__PURE__ */ jsx7(FormLabel, { htmlFor: "icon-picker-btn", children: "Default Icon" }),
987
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
988
+ /* @__PURE__ */ jsxs6(
989
+ "button",
990
+ {
991
+ id: "icon-picker-btn",
992
+ 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",
993
+ onClick: () => setPickerOpen((prev) => !prev),
994
+ children: [
995
+ iconEntry && /* @__PURE__ */ jsx7(iconEntry.icon, { size: 16 }),
996
+ /* @__PURE__ */ jsx7("span", { children: iconEntry?.label ?? "None" })
997
+ ]
998
+ }
999
+ ),
1000
+ icon && /* @__PURE__ */ jsx7(
1001
+ "button",
1002
+ {
1003
+ className: "cursor-pointer text-xs text-base-contrast-light hover:text-base-contrast",
1004
+ onClick: () => {
1005
+ setIcon(null);
1006
+ emit({ icon: null });
1007
+ },
1008
+ children: "Clear"
1009
+ }
1010
+ )
1011
+ ] }),
1012
+ pickerOpen && /* @__PURE__ */ jsx7("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx7(
1013
+ IconPicker,
1014
+ {
1015
+ selected: icon,
1016
+ onSelect: (newIcon) => {
1017
+ if (newIcon !== null) {
1018
+ setIcon(newIcon);
1019
+ emit({ icon: newIcon });
1020
+ }
1021
+ setPickerOpen(false);
1022
+ },
1023
+ onClose: () => setPickerOpen(false)
1024
+ }
1025
+ ) })
1026
+ ] }),
1027
+ /* @__PURE__ */ jsx7(
1028
+ Checkbox,
1029
+ {
1030
+ checked: showLabel,
1031
+ onChange: (v) => {
1032
+ setShowLabel(v);
1033
+ emit({ showLabel: v });
1034
+ },
1035
+ label: "Show labels"
1036
+ }
1037
+ ),
1038
+ showLabel && /* @__PURE__ */ jsx7(
1039
+ Checkbox,
1040
+ {
1041
+ checked: stackText,
1042
+ onChange: (v) => {
1043
+ setStackText(v);
1044
+ emit({ stackText: v });
1045
+ },
1046
+ label: "Stack label above text"
1047
+ }
1048
+ )
1049
+ ] });
1050
+ }
1051
+
1052
+ // src/components/sections/IconList/index.tsx
1053
+ import { jsx as jsx8 } from "react/jsx-runtime";
1054
+ var IconListItemSchema = z3.object({
1055
+ label: z3.string(),
1056
+ text: z3.string(),
1057
+ icon: z3.string().optional(),
1058
+ dodont: z3.enum(["do", "dont"]).optional()
1059
+ });
1060
+ var schema2 = z3.object({
1061
+ type: z3.literal("icon_list"),
1062
+ content: z3.object({
1063
+ items: z3.array(IconListItemSchema)
1064
+ }),
1065
+ options: z3.object({
1066
+ icon: z3.string().nullable().optional(),
1067
+ showLabel: z3.boolean().optional(),
1068
+ stackText: z3.boolean().optional()
1069
+ }).optional()
1070
+ });
1071
+ var IconList_default = defineSection({
1072
+ type: "icon_list",
1073
+ category: "brand-guide",
1074
+ label: "Icon List",
1075
+ icon: /* @__PURE__ */ jsx8(List, { size: 18 }),
1076
+ schema: schema2,
1077
+ component: ({ content, options, onChange }) => /* @__PURE__ */ jsx8(
1078
+ IconList,
1079
+ {
1080
+ items: content.content.items,
1081
+ icon: options?.icon,
1082
+ showLabel: options?.showLabel,
1083
+ stackText: options?.stackText,
1084
+ onChange: onChange ? (c) => onChange(c) : void 0
1085
+ }
1086
+ ),
1087
+ defaults: () => ({
1088
+ type: "icon_list",
1089
+ content: { items: [{ label: "", text: "" }] }
1090
+ }),
1091
+ getLabel: (content) => pluralize(content.content.items.length, "icon"),
1092
+ settingsForm: IconListSettings
1093
+ });
1094
+
1095
+ // src/components/sections/DoDontMedia/index.tsx
1096
+ import { z as z4 } from "zod";
1097
+ import { Image as ImageIcon } from "lucide-react";
1098
+
1099
+ // src/components/sections/DoDontMedia/DoDontMediaBlock.tsx
1100
+ import { Check as Check3, X as X3 } from "lucide-react";
1101
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1102
+ function DoDontMediaBlock({ refValue, options, link, dodont, isEditMode, onRefChange }) {
1103
+ return /* @__PURE__ */ jsxs7("div", { children: [
1104
+ /* @__PURE__ */ jsx9("div", { className: "flex h-10 items-center justify-center pb-1", children: dodont === "do" ? /* @__PURE__ */ jsx9(Check3, { size: 28, className: "text-green-600" }) : /* @__PURE__ */ jsx9(X3, { size: 28, className: "text-red-600" }) }),
1105
+ /* @__PURE__ */ jsx9(
1106
+ MediaBlock,
1107
+ {
1108
+ refValue,
1109
+ options,
1110
+ link,
1111
+ isEditMode,
1112
+ onRefChange
1113
+ }
1114
+ )
1115
+ ] });
1116
+ }
1117
+
1118
+ // src/components/sections/DoDontMedia/index.tsx
1119
+ import { jsx as jsx10 } from "react/jsx-runtime";
1120
+ var schema3 = z4.object({
1121
+ type: z4.literal("dodont_media"),
1122
+ content: z4.object({
1123
+ ref: SingleMediaReferenceSchema,
1124
+ link: LinkValueSchema.optional(),
1125
+ dodont: z4.enum(["do", "dont"])
1126
+ }),
1127
+ options: z4.object({
1128
+ square: z4.boolean().optional(),
1129
+ showCaption: z4.boolean().optional(),
1130
+ border: z4.boolean().optional(),
1131
+ objectFit: z4.enum(["cover", "contain"]).optional()
1132
+ }).default({})
1133
+ });
1134
+ var DoDontMedia_default = defineSection({
1135
+ type: "dodont_media",
1136
+ label: "Do / Don't Media",
1137
+ category: "brand-guide",
1138
+ icon: /* @__PURE__ */ jsx10(ImageIcon, { size: 18 }),
1139
+ schema: schema3,
1140
+ component: ({ content, options, onChange }) => /* @__PURE__ */ jsx10(
1141
+ DoDontMediaBlock,
1142
+ {
1143
+ refValue: content.content.ref,
1144
+ options: options ?? {},
1145
+ link: content.content.link,
1146
+ dodont: content.content.dodont,
1147
+ isEditMode: !!onChange,
1148
+ onRefChange: onChange ? (ref) => onChange({ ...content, content: { ...content.content, ref } }) : void 0
1149
+ }
1150
+ ),
1151
+ defaults: () => ({
1152
+ type: "dodont_media",
1153
+ content: { ref: { type: "image", imageId: "" }, dodont: "do" },
1154
+ options: {}
1155
+ }),
1156
+ getLabel: () => "Do / Don't Media",
1157
+ getThumbnails: (content) => content.content.ref.imageId ? [{ type: "image", src: content.content.ref.imageId }] : [],
1158
+ settings: {
1159
+ square: { type: "checkbox", label: "Square aspect ratio", default: false },
1160
+ showCaption: { type: "checkbox", label: "Show caption", default: false },
1161
+ border: { type: "checkbox", label: "Border", default: false },
1162
+ objectFit: {
1163
+ type: "select",
1164
+ label: "Image fit",
1165
+ default: "contain",
1166
+ options: [
1167
+ { label: "Contain", value: "contain" },
1168
+ { label: "Cover", value: "cover" }
1169
+ ]
1170
+ },
1171
+ link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" },
1172
+ dodont: {
1173
+ type: "select",
1174
+ label: "Do / Don't",
1175
+ target: "content",
1176
+ default: "do",
1177
+ options: [
1178
+ { label: "Do", value: "do" },
1179
+ { label: "Don't", value: "dont" }
1180
+ ]
1181
+ }
1182
+ },
1183
+ inheritableSettings: ["square", "showCaption", "border", "objectFit"],
1184
+ settingsTabs: [
1185
+ { label: "Display", fields: ["square", "showCaption", "border", "objectFit"] },
1186
+ { label: "Link", fields: ["link"] },
1187
+ { label: "Do / Don't", fields: ["dodont"] }
1188
+ ]
1189
+ });
1190
+
1191
+ // src/components/sections/brand-guide.ts
1192
+ var brandGuideSectionDefs = [Colors_default, IconList_default, DoDontMedia_default];
1193
+
1194
+ export {
1195
+ stripHtmlToPlainText,
1196
+ truncate,
1197
+ pluralize,
1198
+ ColorSpaceSchema,
1199
+ ColorItemSchema,
1200
+ brandGuideSectionDefs
1201
+ };