@mieweb/ui 0.11.0-dev.25 → 0.11.0-dev.27

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 (32) hide show
  1. package/dist/{chunk-OCRUE3HI.cjs → chunk-7S3GBPRD.cjs} +10 -2
  2. package/dist/chunk-7S3GBPRD.cjs.map +1 -0
  3. package/dist/{chunk-3S5LK2EW.cjs → chunk-FA7STF2M.cjs} +139 -170
  4. package/dist/chunk-FA7STF2M.cjs.map +1 -0
  5. package/dist/{chunk-JTLOCREL.js → chunk-GTAHQBUK.js} +3 -3
  6. package/dist/{chunk-JTLOCREL.js.map → chunk-GTAHQBUK.js.map} +1 -1
  7. package/dist/{chunk-CY7ZRKLW.cjs → chunk-S2QKRL5S.cjs} +4 -4
  8. package/dist/{chunk-CY7ZRKLW.cjs.map → chunk-S2QKRL5S.cjs.map} +1 -1
  9. package/dist/{chunk-UY3PIO7F.js → chunk-STDGAFW2.js} +10 -2
  10. package/dist/chunk-STDGAFW2.js.map +1 -0
  11. package/dist/{chunk-UTSRPQ5B.js → chunk-UWHVSRSU.js} +140 -171
  12. package/dist/chunk-UWHVSRSU.js.map +1 -0
  13. package/dist/components/EmailEditor/index.cjs +11 -11
  14. package/dist/components/EmailEditor/index.js +2 -2
  15. package/dist/components/RichTextEditor/index.cjs +4 -4
  16. package/dist/components/RichTextEditor/index.d.cts +10 -5
  17. package/dist/components/RichTextEditor/index.d.ts +10 -5
  18. package/dist/components/RichTextEditor/index.js +1 -1
  19. package/dist/index.cjs +41 -18
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +32 -6
  22. package/dist/index.d.ts +32 -6
  23. package/dist/index.js +27 -4
  24. package/dist/index.js.map +1 -1
  25. package/dist/styles.css +1 -1
  26. package/dist/tailwind-preset.cjs +4 -4
  27. package/dist/tailwind-preset.js +1 -1
  28. package/package.json +2 -2
  29. package/dist/chunk-3S5LK2EW.cjs.map +0 -1
  30. package/dist/chunk-OCRUE3HI.cjs.map +0 -1
  31. package/dist/chunk-UTSRPQ5B.js.map +0 -1
  32. package/dist/chunk-UY3PIO7F.js.map +0 -1
@@ -41,11 +41,7 @@ var DEFAULT_LABELS = {
41
41
  empty: "No macros available",
42
42
  emptyHint: "The application has not provided a macro list.",
43
43
  noResults: "No macros match",
44
- clearSearch: "Clear search",
45
- showFullContent: "Show full content",
46
- hideFullContent: "Hide full content",
47
- more: "more",
48
- less: "less"
44
+ clearSearch: "Clear search"
49
45
  };
50
46
  function matchesQuery(macro, query) {
51
47
  const q = query.toLowerCase();
@@ -59,131 +55,6 @@ function rankMacros(macros, query) {
59
55
  (a, b) => Number(isShortcutHit(b, query)) - Number(isShortcutHit(a, query))
60
56
  );
61
57
  }
62
- function MacroRow({
63
- macro,
64
- isPrevious,
65
- isPeeked,
66
- peekId,
67
- labels,
68
- onSelect,
69
- onTogglePeek,
70
- onRowKeyDown
71
- }) {
72
- const [truncated, setTruncated] = React2__namespace.useState(false);
73
- const rowRef = React2__namespace.useRef(null);
74
- const lessRef = React2__namespace.useRef(null);
75
- const focusAfterToggle = React2__namespace.useRef(false);
76
- React2__namespace.useEffect(() => {
77
- if (!focusAfterToggle.current) return;
78
- focusAfterToggle.current = false;
79
- (isPeeked ? lessRef.current : rowRef.current)?.focus();
80
- }, [isPeeked]);
81
- const handleToggle = () => {
82
- focusAfterToggle.current = true;
83
- onTogglePeek();
84
- };
85
- const previewObserver = React2__namespace.useRef(null);
86
- const measurePreview = (el) => {
87
- previewObserver.current?.disconnect();
88
- previewObserver.current = null;
89
- if (!el) return;
90
- const measure = () => setTruncated(el.scrollHeight > el.clientHeight);
91
- measure();
92
- if (typeof ResizeObserver !== "undefined") {
93
- previewObserver.current = new ResizeObserver(measure);
94
- previewObserver.current.observe(el);
95
- }
96
- };
97
- return /* @__PURE__ */ jsxRuntime.jsxs(
98
- "div",
99
- {
100
- "data-slot": "macro-library-item",
101
- className: "group/macro hover:bg-muted/60 relative rounded-md",
102
- children: [
103
- /* @__PURE__ */ jsxRuntime.jsxs(
104
- "button",
105
- {
106
- type: "button",
107
- "data-macro-row": true,
108
- ref: rowRef,
109
- className: "focus-visible:ring-ring text-foreground hover:text-primary flex w-full cursor-pointer flex-col items-stretch gap-0.5 rounded-md px-2 py-1.5 text-start focus-visible:ring-2 focus-visible:outline-none",
110
- onClick: () => onSelect(macro),
111
- onKeyDown: onRowKeyDown,
112
- children: [
113
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
114
- macro.shortcut && /* @__PURE__ */ jsxRuntime.jsx(
115
- "span",
116
- {
117
- dir: "ltr",
118
- className: chunkS5RVSXDV_cjs.cn(
119
- "border-border bg-background text-muted-foreground rounded border px-1 font-mono text-[11px]",
120
- isPrevious && "border-warning-300 bg-warning-50 text-warning-800 dark:border-warning-700 dark:bg-warning-950 dark:text-warning-300"
121
- ),
122
- children: macro.shortcut
123
- }
124
- ),
125
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: macro.label })
126
- ] }),
127
- !isPeeked && /* @__PURE__ */ jsxRuntime.jsx(
128
- "span",
129
- {
130
- ref: measurePreview,
131
- className: "text-muted-foreground line-clamp-2 text-xs break-words",
132
- children: macro.content
133
- }
134
- )
135
- ]
136
- }
137
- ),
138
- isPeeked && /* @__PURE__ */ jsxRuntime.jsx(
139
- "div",
140
- {
141
- id: peekId,
142
- "data-slot": "macro-library-peek",
143
- className: "text-muted-foreground px-2 pb-1 text-xs break-words whitespace-pre-line",
144
- children: macro.content
145
- }
146
- ),
147
- truncated && !isPeeked && // Overlays the end of the clamped second line; revealed on row
148
- // hover or keyboard focus so short rows stay entirely clean. Always
149
- // visible on devices without hover (touch).
150
- /* @__PURE__ */ jsxRuntime.jsxs(
151
- "button",
152
- {
153
- type: "button",
154
- className: "bg-muted text-muted-foreground hover:text-primary focus-visible:ring-ring invisible absolute end-1.5 bottom-1.5 flex cursor-pointer items-center rounded-sm px-1 text-[11px] leading-4 group-focus-within/macro:visible group-hover/macro:visible hover:underline focus-visible:ring-2 focus-visible:outline-none [@media(hover:none)]:visible",
155
- "aria-expanded": false,
156
- "aria-label": `${labels.showFullContent}: ${macro.label}`,
157
- onClick: handleToggle,
158
- children: [
159
- labels.more,
160
- /* @__PURE__ */ jsxRuntime.jsx(
161
- chunkL7L5S2HO_cjs.ChevronRight,
162
- {
163
- "aria-hidden": "true",
164
- className: "h-3 w-3 rtl:-scale-x-100"
165
- }
166
- )
167
- ]
168
- }
169
- ),
170
- isPeeked && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "-mt-1 flex justify-end px-2 pb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
171
- "button",
172
- {
173
- type: "button",
174
- ref: lessRef,
175
- className: "text-muted-foreground hover:text-primary focus-visible:ring-ring cursor-pointer rounded text-[11px] hover:underline focus-visible:ring-2 focus-visible:outline-none",
176
- "aria-expanded": true,
177
- "aria-controls": peekId,
178
- "aria-label": `${labels.hideFullContent}: ${macro.label}`,
179
- onClick: handleToggle,
180
- children: labels.less
181
- }
182
- ) })
183
- ]
184
- }
185
- );
186
- }
187
58
  var MacroLibrary = React2__namespace.forwardRef(
188
59
  function MacroLibrary2({
189
60
  groups,
@@ -201,7 +72,6 @@ var MacroLibrary = React2__namespace.forwardRef(
201
72
  const [collapsed, setCollapsed] = React2__namespace.useState(
202
73
  {}
203
74
  );
204
- const [peeked, setPeeked] = React2__namespace.useState(null);
205
75
  const listRef = React2__namespace.useRef(null);
206
76
  const searchRef = React2__namespace.useRef(null);
207
77
  const panelId = React2__namespace.useId();
@@ -403,23 +273,32 @@ var MacroLibrary = React2__namespace.forwardRef(
403
273
  ]
404
274
  }
405
275
  ),
406
- !isCollapsed && group.macros.map((macro) => {
407
- const isPeeked = peeked === macro.id;
408
- return /* @__PURE__ */ jsxRuntime.jsx(
409
- MacroRow,
410
- {
411
- macro,
412
- isPrevious,
413
- isPeeked,
414
- peekId: `${panelId}-peek-${macro.id}`,
415
- labels,
416
- onSelect,
417
- onTogglePeek: () => setPeeked(isPeeked ? null : macro.id),
418
- onRowKeyDown: handleRowKeyDown
419
- },
420
- macro.id
421
- );
422
- })
276
+ !isCollapsed && group.macros.map((macro) => /* @__PURE__ */ jsxRuntime.jsxs(
277
+ "button",
278
+ {
279
+ type: "button",
280
+ "data-macro-row": true,
281
+ "data-slot": "macro-library-item",
282
+ className: "focus-visible:ring-ring text-foreground hover:bg-muted/60 hover:text-primary flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-start focus-visible:ring-2 focus-visible:outline-none",
283
+ onClick: () => onSelect(macro),
284
+ onKeyDown: handleRowKeyDown,
285
+ children: [
286
+ macro.shortcut && /* @__PURE__ */ jsxRuntime.jsx(
287
+ "span",
288
+ {
289
+ dir: "ltr",
290
+ className: chunkS5RVSXDV_cjs.cn(
291
+ "border-border bg-background text-muted-foreground rounded border px-1 font-mono text-[11px]",
292
+ isPrevious && "border-warning-300 bg-warning-50 text-warning-800 dark:border-warning-700 dark:bg-warning-950 dark:text-warning-300"
293
+ ),
294
+ children: macro.shortcut
295
+ }
296
+ ),
297
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: macro.label })
298
+ ]
299
+ },
300
+ macro.id
301
+ ))
423
302
  ]
424
303
  },
425
304
  group.id
@@ -605,6 +484,7 @@ var RichTextEditor = React2__namespace.forwardRef(
605
484
  blockMenu = false,
606
485
  blockMenuLabels,
607
486
  markdownShortcuts = false,
487
+ chromeless = false,
608
488
  "aria-label": ariaLabel
609
489
  }, ref) => {
610
490
  const editorRef = React2__namespace.useRef(null);
@@ -618,6 +498,9 @@ var RichTextEditor = React2__namespace.forwardRef(
618
498
  const macroPanelId = React2__namespace.useId();
619
499
  const hasVariables = Boolean(variableGroups && variableGroups.length > 0);
620
500
  const hasMacros = Boolean(macros);
501
+ const hasMacroEntries = Boolean(
502
+ macros?.some((group) => group.macros.length > 0)
503
+ );
621
504
  const isEmpty = chunkC7RVKV25_cjs.isHtmlEmpty(value);
622
505
  const [uncontrolledToolbar, setUncontrolledToolbar] = React2__namespace.useState(defaultToolbar);
623
506
  const toolbarVisible = (toolbar ?? uncontrolledToolbar) !== "hidden";
@@ -627,9 +510,36 @@ var RichTextEditor = React2__namespace.forwardRef(
627
510
  };
628
511
  const toolbarVisibleRef = React2__namespace.useRef(toolbarVisible);
629
512
  const [blockMenuOpen, setBlockMenuOpen] = React2__namespace.useState(false);
630
- const [gutterTop, setGutterTop] = React2__namespace.useState(16);
513
+ const [gutterTop, setGutterTop] = React2__namespace.useState(chromeless ? 7 : 16);
631
514
  const gutterWrapperRef = React2__namespace.useRef(null);
515
+ const measureRestGutterTop = React2__namespace.useCallback(() => {
516
+ const fallback = chromeless ? 7 : 16;
517
+ if (!editorRef.current) return fallback;
518
+ const padding = parseFloat(
519
+ getComputedStyle(editorRef.current).paddingTop
520
+ );
521
+ return Number.isNaN(padding) ? fallback : Math.round(padding);
522
+ }, [chromeless]);
523
+ React2__namespace.useLayoutEffect(() => {
524
+ if (!blockMenu || !editorRef.current) return;
525
+ setGutterTop((current) => {
526
+ const next = measureRestGutterTop();
527
+ return current === next ? current : next;
528
+ });
529
+ }, [blockMenu, measureRestGutterTop]);
632
530
  const hoverBlockNodeRef = React2__namespace.useRef(null);
531
+ const resetGutter = React2__namespace.useCallback(() => {
532
+ hoverBlockNodeRef.current = null;
533
+ const next = measureRestGutterTop();
534
+ setGutterTop((current) => current === next ? current : next);
535
+ }, [measureRestGutterTop]);
536
+ const reconcileGutterWithContent = React2__namespace.useCallback(() => {
537
+ if (!blockMenu || !editorRef.current) return;
538
+ const hovered = hoverBlockNodeRef.current;
539
+ if (hovered && !editorRef.current.contains(hovered) || !editorRef.current.hasChildNodes()) {
540
+ resetGutter();
541
+ }
542
+ }, [blockMenu, resetGutter]);
633
543
  const blockTargetRangeRef = React2__namespace.useRef(null);
634
544
  const firstBlockItemRef = React2__namespace.useRef(null);
635
545
  React2__namespace.useImperativeHandle(ref, () => editorRef.current);
@@ -658,10 +568,12 @@ var RichTextEditor = React2__namespace.forwardRef(
658
568
  React2__namespace.useEffect(() => {
659
569
  if (editorRef.current && editorRef.current.innerHTML !== value) {
660
570
  editorRef.current.innerHTML = value;
571
+ reconcileGutterWithContent();
661
572
  }
662
- }, [value]);
573
+ }, [value, reconcileGutterWithContent]);
663
574
  const updateContent = () => {
664
575
  if (editorRef.current) onChange(editorRef.current.innerHTML);
576
+ reconcileGutterWithContent();
665
577
  };
666
578
  const insertSanitized = (html) => {
667
579
  if (!sanitizeHtml) return false;
@@ -904,7 +816,10 @@ var RichTextEditor = React2__namespace.forwardRef(
904
816
  top = rect.top;
905
817
  }
906
818
  }
907
- if (!target || top === null) return;
819
+ if (!target || top === null) {
820
+ resetGutter();
821
+ return;
822
+ }
908
823
  hoverBlockNodeRef.current = target;
909
824
  const wrapperTop = gutterWrapperRef.current.getBoundingClientRect().top;
910
825
  const next = Math.max(Math.round(top - wrapperTop), 4);
@@ -1115,8 +1030,10 @@ var RichTextEditor = React2__namespace.forwardRef(
1115
1030
  "div",
1116
1031
  {
1117
1032
  "data-slot": "rich-text-editor",
1033
+ "data-chromeless": chromeless || void 0,
1118
1034
  className: chunkS5RVSXDV_cjs.cn(
1119
- "border-border bg-background flex flex-col overflow-hidden rounded-lg border",
1035
+ "bg-background flex flex-col",
1036
+ !chromeless && "border-border overflow-hidden rounded-lg border",
1120
1037
  className
1121
1038
  ),
1122
1039
  children: [
@@ -1400,20 +1317,62 @@ var RichTextEditor = React2__namespace.forwardRef(
1400
1317
  item.key
1401
1318
  )),
1402
1319
  /* @__PURE__ */ jsxRuntime.jsx(chunkPINIBEIU_cjs.DropdownSeparator, {}),
1403
- hasMacros && /* @__PURE__ */ jsxRuntime.jsx(
1404
- chunkPINIBEIU_cjs.DropdownItem,
1405
- {
1406
- onClick: () => {
1407
- setBlockMenuOpen(false);
1408
- if (blockTargetRangeRef.current) {
1409
- savedRangeRef.current = blockTargetRangeRef.current;
1410
- }
1411
- setMacrosOpen(true);
1412
- focusRestoringSelection();
1413
- },
1414
- children: blockMenuLabels?.insertMacro ?? "Insert macro\u2026"
1415
- }
1416
- ),
1320
+ hasMacros && macros && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1321
+ /* @__PURE__ */ jsxRuntime.jsx(
1322
+ chunkPINIBEIU_cjs.DropdownSubmenu,
1323
+ {
1324
+ label: blockMenuLabels?.insertMacro ?? "Insert macro",
1325
+ disabled: !hasMacroEntries,
1326
+ children: blockMenuOpen && macros.flatMap((group) => [
1327
+ // Group headings only earn their row when there
1328
+ // is more than one group to tell apart.
1329
+ ...macros.length > 1 ? [
1330
+ /* @__PURE__ */ jsxRuntime.jsx(chunkPINIBEIU_cjs.DropdownLabel, { children: group.label }, `h:${group.id}`)
1331
+ ] : [],
1332
+ ...group.macros.map((macro) => /* @__PURE__ */ jsxRuntime.jsx(
1333
+ chunkPINIBEIU_cjs.DropdownItem,
1334
+ {
1335
+ className: "[&>[data-slot=dropdown-item-label]]:min-w-0 [&>[data-slot=dropdown-item-label]]:flex-1",
1336
+ onClick: () => {
1337
+ setBlockMenuOpen(false);
1338
+ if (blockTargetRangeRef.current) {
1339
+ savedRangeRef.current = blockTargetRangeRef.current;
1340
+ }
1341
+ insertMacro(macro);
1342
+ },
1343
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
1344
+ macro.shortcut && /* @__PURE__ */ jsxRuntime.jsx(
1345
+ "span",
1346
+ {
1347
+ dir: "ltr",
1348
+ className: "border-border bg-background text-muted-foreground rounded border px-1 font-mono text-[11px]",
1349
+ children: macro.shortcut
1350
+ }
1351
+ ),
1352
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: macro.label })
1353
+ ] })
1354
+ },
1355
+ `m:${JSON.stringify([group.id, macro.id])}`
1356
+ ))
1357
+ ])
1358
+ }
1359
+ ),
1360
+ /* @__PURE__ */ jsxRuntime.jsx(
1361
+ chunkPINIBEIU_cjs.DropdownItem,
1362
+ {
1363
+ onClick: () => {
1364
+ setBlockMenuOpen(false);
1365
+ if (blockTargetRangeRef.current) {
1366
+ savedRangeRef.current = blockTargetRangeRef.current;
1367
+ }
1368
+ setMacrosOpen(true);
1369
+ focusRestoringSelection();
1370
+ },
1371
+ children: blockMenuLabels?.showMacroLibrary ?? "Show macro library"
1372
+ }
1373
+ ),
1374
+ /* @__PURE__ */ jsxRuntime.jsx(chunkPINIBEIU_cjs.DropdownSeparator, {})
1375
+ ] }),
1417
1376
  /* @__PURE__ */ jsxRuntime.jsx(
1418
1377
  chunkPINIBEIU_cjs.DropdownItem,
1419
1378
  {
@@ -1437,7 +1396,12 @@ var RichTextEditor = React2__namespace.forwardRef(
1437
1396
  {
1438
1397
  "aria-hidden": "true",
1439
1398
  className: chunkS5RVSXDV_cjs.cn(
1440
- "text-muted-foreground pointer-events-none absolute start-0 top-0 p-4",
1399
+ "text-muted-foreground pointer-events-none absolute start-0 top-0",
1400
+ // Chromeless hosts drop the wrapper's clipping, so a long
1401
+ // placeholder must stay a single ellipsized line (as a
1402
+ // native textarea clips its own) instead of wrapping out
1403
+ // of the one-row field.
1404
+ chromeless ? "end-0 truncate px-3 py-[7px] text-base" : "p-4",
1441
1405
  blockMenu && "ps-10"
1442
1406
  ),
1443
1407
  children: placeholder
@@ -1451,6 +1415,7 @@ var RichTextEditor = React2__namespace.forwardRef(
1451
1415
  "aria-multiline": "true",
1452
1416
  "aria-label": ariaLabel ?? placeholder,
1453
1417
  contentEditable: !disabled,
1418
+ "data-macros-open": hasMacros && macrosOpen ? "" : void 0,
1454
1419
  tabIndex: disabled ? -1 : 0,
1455
1420
  onInput: updateContent,
1456
1421
  onPaste: handlePaste,
@@ -1460,7 +1425,11 @@ var RichTextEditor = React2__namespace.forwardRef(
1460
1425
  onKeyUp: hasMacros ? saveSelection : void 0,
1461
1426
  onMouseUp: hasMacros ? saveSelection : void 0,
1462
1427
  className: chunkS5RVSXDV_cjs.cn(
1463
- "min-h-[250px] overflow-y-auto p-4 focus:outline-none",
1428
+ "overflow-y-auto focus:outline-none",
1429
+ // Chromeless surfaces start one Input row tall (Textarea md
1430
+ // metrics: 24px line + 7px padding + the host's 1px borders
1431
+ // = h-10) and auto-grow with content.
1432
+ chromeless ? "min-h-[38px] px-3 py-[7px] text-base" : "min-h-[250px] p-4",
1464
1433
  "prose prose-sm max-w-none",
1465
1434
  // Baseline block styles: Tailwind preflight strips heading,
1466
1435
  // list and quote styling, and the `prose` classes above only
@@ -1510,5 +1479,5 @@ exports.MacroLibrary = MacroLibrary;
1510
1479
  exports.RichTextEditor = RichTextEditor;
1511
1480
  exports.convertAngleBracketsToMustache = convertAngleBracketsToMustache;
1512
1481
  exports.processDictation = processDictation;
1513
- //# sourceMappingURL=chunk-3S5LK2EW.cjs.map
1514
- //# sourceMappingURL=chunk-3S5LK2EW.cjs.map
1482
+ //# sourceMappingURL=chunk-FA7STF2M.cjs.map
1483
+ //# sourceMappingURL=chunk-FA7STF2M.cjs.map