@sustaina/shared-ui 1.49.0 → 1.49.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8762,7 +8762,7 @@ function DialogContent({
8762
8762
  {
8763
8763
  "data-slot": "dialog-content",
8764
8764
  className: cn(
8765
- "fixed top-1/2 left-1/2 z-50 flex min-h-0 max-h-[90vh] w-full max-w-[80vw] translate-x-[-50%] translate-y-[-50%] flex-col rounded-lg border bg-background shadow-lg duration-200 sm:max-w-7xl",
8765
+ "fixed top-1/2 left-1/2 z-50 flex min-h-0 max-h-[90vh] w-full max-w-[80vw] translate-x-[-50%] translate-y-[-50%] flex-col rounded-lg bg-background shadow-lg duration-200 sm:max-w-7xl",
8766
8766
  className
8767
8767
  ),
8768
8768
  ...props,
@@ -12533,7 +12533,7 @@ var ToolbarButton = React.forwardRef(function ToolbarButton2({ label, icon: Icon
12533
12533
  disabled ? "pointer-events-none opacity-40" : ""
12534
12534
  ),
12535
12535
  children: [
12536
- /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "h-4 w-4", "aria-hidden": true, style: { color: iconColor } }),
12536
+ /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "h-4 w-4", "aria-hidden": true, color: iconColor }),
12537
12537
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: label })
12538
12538
  ]
12539
12539
  }
@@ -13110,11 +13110,11 @@ function LinkPlugin({ disabled, state }) {
13110
13110
  return;
13111
13111
  }
13112
13112
  const nodeKey = detectedLink.getKey();
13113
- const rect = linkElement.getBoundingClientRect();
13113
+ const linkRect = linkElement.getBoundingClientRect();
13114
13114
  setLinkPreview({
13115
13115
  nodeKey,
13116
13116
  url: initialUrl,
13117
- rect
13117
+ rect: linkRect
13118
13118
  });
13119
13119
  },
13120
13120
  [disabled, findLink, hidePreview]
@@ -13156,11 +13156,13 @@ function LinkPlugin({ disabled, state }) {
13156
13156
  }
13157
13157
  rootElement.addEventListener("click", handleClick);
13158
13158
  document.addEventListener("mousedown", handleClickOutside);
13159
+ window.addEventListener("scroll", hidePreview, true);
13159
13160
  return () => {
13160
13161
  rootElement.removeEventListener("click", handleClick);
13161
13162
  document.removeEventListener("mousedown", handleClickOutside);
13163
+ window.removeEventListener("scroll", hidePreview, true);
13162
13164
  };
13163
- }, [editor, handleClick, handleClickOutside]);
13165
+ }, [editor, handleClick, handleClickOutside, hidePreview]);
13164
13166
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13165
13167
  /* @__PURE__ */ jsxRuntime.jsx(
13166
13168
  ToolbarButton,
@@ -13184,7 +13186,7 @@ function LinkPlugin({ disabled, state }) {
13184
13186
  /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isLinkDialogOpen, onOpenChange: handleLinkDialogOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
13185
13187
  DialogContent,
13186
13188
  {
13187
- className: "min-w-[70vw] max-w-7xl",
13189
+ className: "max-w-[50vw]! min-w-[320px]!",
13188
13190
  header: editingExistingLink ? "Edit link" : "Insert link",
13189
13191
  children: [
13190
13192
  /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { hidden: true }),
@@ -13223,66 +13225,107 @@ function LinkPlugin({ disabled, state }) {
13223
13225
  ]
13224
13226
  }
13225
13227
  ) }),
13226
- linkPreview && /* @__PURE__ */ jsxRuntime.jsxs(
13227
- "div",
13228
- {
13229
- ref: previewRef,
13230
- className: "fixed z-50 flex items-center gap-2 rounded-md border border-border bg-popover p-2 shadow-md",
13231
- style: {
13232
- top: `${linkPreview.rect.bottom + 4}px`,
13233
- left: `${linkPreview.rect.left}px`,
13234
- maxWidth: "300px"
13235
- },
13236
- children: [
13237
- /* @__PURE__ */ jsxRuntime.jsx(
13238
- "a",
13239
- {
13240
- href: linkPreview.url,
13241
- target: "_blank",
13242
- rel: "noopener noreferrer",
13243
- className: "flex-1 truncate text-sm text-primary hover:underline",
13244
- onClick: (e) => {
13245
- e.preventDefault();
13246
- handleOpenLink();
13247
- },
13248
- children: linkPreview.url
13249
- }
13250
- ),
13251
- /* @__PURE__ */ jsxRuntime.jsx(
13252
- "button",
13253
- {
13254
- type: "button",
13255
- title: "Open link",
13256
- onClick: handleOpenLink,
13257
- className: "cursor-pointer inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
13258
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3.5 w-3.5" })
13259
- }
13260
- ),
13261
- /* @__PURE__ */ jsxRuntime.jsx(
13262
- "button",
13263
- {
13264
- type: "button",
13265
- title: "Edit link",
13266
- onClick: handleEditClick,
13267
- className: "cursor-pointer inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
13268
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" })
13269
- }
13270
- ),
13271
- /* @__PURE__ */ jsxRuntime.jsx(
13272
- "button",
13273
- {
13274
- type: "button",
13275
- title: "Edit link",
13276
- onClick: handleRemoveLink,
13277
- className: "cursor-pointer inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
13278
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2Off, { className: "h-3.5 w-3.5" })
13279
- }
13280
- )
13281
- ]
13282
- }
13228
+ linkPreview && reactDom.createPortal(
13229
+ /* @__PURE__ */ jsxRuntime.jsx(
13230
+ LinkPreviewPopover,
13231
+ {
13232
+ previewRef,
13233
+ linkPreview,
13234
+ handleOpenLink,
13235
+ handleEditClick,
13236
+ handleRemoveLink
13237
+ }
13238
+ ),
13239
+ document.body
13283
13240
  )
13284
13241
  ] });
13285
13242
  }
13243
+ var PREVIEW_WIDTH = 300;
13244
+ var PREVIEW_PADDING = 8;
13245
+ var PREVIEW_HEIGHT = 40;
13246
+ function LinkPreviewPopover({
13247
+ previewRef,
13248
+ linkPreview,
13249
+ handleOpenLink,
13250
+ handleEditClick,
13251
+ handleRemoveLink
13252
+ }) {
13253
+ const { rect } = linkPreview;
13254
+ const viewportWidth = typeof window !== "undefined" ? window.innerWidth : 0;
13255
+ const viewportHeight = typeof window !== "undefined" ? window.innerHeight : 0;
13256
+ let top = rect.bottom + 4;
13257
+ let left = rect.left;
13258
+ if (left + PREVIEW_WIDTH > viewportWidth - PREVIEW_PADDING) {
13259
+ left = Math.max(PREVIEW_PADDING, viewportWidth - PREVIEW_WIDTH - PREVIEW_PADDING);
13260
+ }
13261
+ if (left < PREVIEW_PADDING) {
13262
+ left = PREVIEW_PADDING;
13263
+ }
13264
+ if (top + PREVIEW_HEIGHT > viewportHeight - PREVIEW_PADDING) {
13265
+ top = rect.top - PREVIEW_HEIGHT - 4;
13266
+ }
13267
+ if (top < PREVIEW_PADDING) {
13268
+ top = PREVIEW_PADDING;
13269
+ }
13270
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13271
+ "div",
13272
+ {
13273
+ ref: previewRef,
13274
+ className: "fixed z-9999 flex items-center gap-2 rounded-md border border-border bg-popover p-2 shadow-md",
13275
+ style: {
13276
+ top: `${top}px`,
13277
+ left: `${left}px`,
13278
+ maxWidth: `${PREVIEW_WIDTH}px`
13279
+ },
13280
+ children: [
13281
+ /* @__PURE__ */ jsxRuntime.jsx(
13282
+ "a",
13283
+ {
13284
+ href: linkPreview.url,
13285
+ target: "_blank",
13286
+ rel: "noopener noreferrer",
13287
+ className: "flex-1 truncate text-sm text-primary hover:underline",
13288
+ onClick: (e) => {
13289
+ e.preventDefault();
13290
+ handleOpenLink();
13291
+ },
13292
+ children: linkPreview.url
13293
+ }
13294
+ ),
13295
+ /* @__PURE__ */ jsxRuntime.jsx(
13296
+ "button",
13297
+ {
13298
+ type: "button",
13299
+ title: "Open link",
13300
+ onClick: handleOpenLink,
13301
+ className: "cursor-pointer inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
13302
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3.5 w-3.5" })
13303
+ }
13304
+ ),
13305
+ /* @__PURE__ */ jsxRuntime.jsx(
13306
+ "button",
13307
+ {
13308
+ type: "button",
13309
+ title: "Edit link",
13310
+ onClick: handleEditClick,
13311
+ className: "cursor-pointer inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
13312
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-3.5 w-3.5" })
13313
+ }
13314
+ ),
13315
+ /* @__PURE__ */ jsxRuntime.jsx(
13316
+ "button",
13317
+ {
13318
+ type: "button",
13319
+ title: "Remove link",
13320
+ onClick: handleRemoveLink,
13321
+ className: "cursor-pointer inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
13322
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2Off, { className: "h-3.5 w-3.5" })
13323
+ }
13324
+ )
13325
+ ]
13326
+ }
13327
+ );
13328
+ }
13286
13329
  function FormatPlugin({ disabled, state }) {
13287
13330
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
13288
13331
  const toggleFormat = React.useCallback(
@@ -13290,6 +13333,7 @@ function FormatPlugin({ disabled, state }) {
13290
13333
  if (disabled) {
13291
13334
  return;
13292
13335
  }
13336
+ editor.focus();
13293
13337
  editor.dispatchCommand(lexical.FORMAT_TEXT_COMMAND, format5);
13294
13338
  },
13295
13339
  [disabled, editor]
@@ -13347,74 +13391,80 @@ function FormatPlugin({ disabled, state }) {
13347
13391
  )
13348
13392
  ] });
13349
13393
  }
13350
- function AdjustFontSizePlugin({ disabled }) {
13394
+ var fontSizes = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 48, 64, 72];
13395
+ var DEFAULT_FONT_SIZE = 14;
13396
+ function AdjustFontSizePlugin({ disabled, state }) {
13351
13397
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
13352
- const adjustFontSize = React.useCallback(
13353
- (direction) => {
13398
+ const [isOpen, setIsOpen] = React.useState(false);
13399
+ const currentSize = state.fontSize ? parseInt(state.fontSize, 10) : DEFAULT_FONT_SIZE;
13400
+ const applyFontSize = React.useCallback(
13401
+ (size = DEFAULT_FONT_SIZE) => {
13354
13402
  if (disabled) {
13355
13403
  return;
13356
13404
  }
13405
+ editor.focus();
13357
13406
  editor.update(() => {
13358
13407
  const selection$1 = lexical.$getSelection();
13359
13408
  if (!lexical.$isRangeSelection(selection$1)) {
13360
13409
  return;
13361
13410
  }
13362
- const currentFontSize = selection.$getSelectionStyleValueForProperty(selection$1, "font-size", "14px");
13363
- const currentSize = parseInt(currentFontSize, 10) || 14;
13364
- const step = 2;
13365
- const minSize = 8;
13366
- const maxSize = 72;
13367
- let newSize;
13368
- if (direction === "increase") {
13369
- newSize = Math.min(currentSize + step, maxSize);
13370
- } else {
13371
- newSize = Math.max(currentSize - step, minSize);
13372
- }
13373
- selection.$patchStyleText(selection$1, { "font-size": `${newSize}px` });
13411
+ selection.$patchStyleText(selection$1, { "font-size": `${size}px` });
13374
13412
  });
13413
+ setIsOpen(false);
13414
+ editor.focus();
13375
13415
  },
13376
13416
  [disabled, editor]
13377
13417
  );
13378
- const resetFontSize = React.useCallback(() => {
13379
- if (disabled) {
13380
- return;
13381
- }
13382
- editor.update(() => {
13383
- const selection$1 = lexical.$getSelection();
13384
- if (!lexical.$isRangeSelection(selection$1)) {
13385
- return;
13386
- }
13387
- selection.$patchStyleText(selection$1, { "font-size": null });
13388
- });
13389
- }, [disabled, editor]);
13390
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13391
- /* @__PURE__ */ jsxRuntime.jsx(
13392
- ToolbarButton,
13393
- {
13394
- label: "Increase text size",
13395
- icon: lucideReact.AArrowUp,
13396
- onClick: () => adjustFontSize("increase"),
13397
- disabled
13398
- }
13399
- ),
13400
- /* @__PURE__ */ jsxRuntime.jsx(
13401
- ToolbarButton,
13402
- {
13403
- label: "Decrease text size",
13404
- icon: lucideReact.AArrowDown,
13405
- onClick: () => adjustFontSize("decrease"),
13406
- disabled
13407
- }
13408
- ),
13409
- /* @__PURE__ */ jsxRuntime.jsx(
13410
- ToolbarButton,
13418
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
13419
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
13420
+ "button",
13411
13421
  {
13412
- label: "Reset text size",
13413
- icon: lucideReact.ALargeSmall,
13414
- onClick: resetFontSize,
13415
- disabled
13422
+ type: "button",
13423
+ title: "Font size",
13424
+ disabled,
13425
+ onMouseDown: (e) => e.preventDefault(),
13426
+ className: cn(
13427
+ "inline-flex h-8 min-w-14 items-center justify-between gap-1 rounded-md border border-input bg-background px-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
13428
+ ),
13429
+ children: [
13430
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: `${currentSize}px` }),
13431
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3.5 w-3.5 opacity-50" })
13432
+ ]
13416
13433
  }
13417
- )
13434
+ ) }),
13435
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-fit p-1", align: "start", onOpenAutoFocus: (e) => e.preventDefault(), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col max-h-60 overflow-y-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-muted-foreground/30 [&::-webkit-scrollbar-track]:bg-transparent", children: [
13436
+ /* @__PURE__ */ jsxRuntime.jsx(
13437
+ "button",
13438
+ {
13439
+ disabled: currentSize === DEFAULT_FONT_SIZE,
13440
+ type: "button",
13441
+ onClick: () => applyFontSize(DEFAULT_FONT_SIZE),
13442
+ className: cn(
13443
+ "rounded px-2 py-1 text-left text-sm",
13444
+ currentSize !== DEFAULT_FONT_SIZE && "hover:bg-muted",
13445
+ currentSize === DEFAULT_FONT_SIZE && "text-gray-400"
13446
+ ),
13447
+ children: "Default"
13448
+ },
13449
+ "default"
13450
+ ),
13451
+ fontSizes.map((size) => /* @__PURE__ */ jsxRuntime.jsxs(
13452
+ "button",
13453
+ {
13454
+ type: "button",
13455
+ onClick: () => applyFontSize(size),
13456
+ className: cn(
13457
+ "rounded px-2 py-1 text-left text-sm hover:bg-muted",
13458
+ currentSize === size && "bg-muted font-medium"
13459
+ ),
13460
+ children: [
13461
+ size,
13462
+ "px"
13463
+ ]
13464
+ },
13465
+ size
13466
+ ))
13467
+ ] }) })
13418
13468
  ] });
13419
13469
  }
13420
13470
  var textColors = [
@@ -13438,6 +13488,7 @@ function ColorPlugin({ disabled, state }) {
13438
13488
  if (disabled) {
13439
13489
  return;
13440
13490
  }
13491
+ editor.focus();
13441
13492
  editor.update(() => {
13442
13493
  const selection$1 = lexical.$getSelection();
13443
13494
  if (!lexical.$isRangeSelection(selection$1)) {
@@ -13455,7 +13506,7 @@ function ColorPlugin({ disabled, state }) {
13455
13506
  ToolbarButton,
13456
13507
  {
13457
13508
  label: "Text color",
13458
- icon: lucideReact.Palette,
13509
+ icon: lucideReact.BaselineIcon,
13459
13510
  disabled,
13460
13511
  iconColor: state.textColor || void 0
13461
13512
  }
@@ -13484,6 +13535,7 @@ function BlockPlugin({ disabled, state }) {
13484
13535
  if (disabled) {
13485
13536
  return;
13486
13537
  }
13538
+ editor.focus();
13487
13539
  editor.update(() => {
13488
13540
  const selection$1 = lexical.$getSelection();
13489
13541
  if (!lexical.$isRangeSelection(selection$1)) {
@@ -13631,6 +13683,7 @@ function AlignPlugin({ disabled, state }) {
13631
13683
  if (disabled) {
13632
13684
  return;
13633
13685
  }
13686
+ editor.focus();
13634
13687
  editor.dispatchCommand(lexical.FORMAT_ELEMENT_COMMAND, format5);
13635
13688
  },
13636
13689
  [disabled, editor]
@@ -13679,7 +13732,8 @@ var initialToolbarState = {
13679
13732
  elementFormat: null,
13680
13733
  canUndo: false,
13681
13734
  canRedo: false,
13682
- textColor: null
13735
+ textColor: null,
13736
+ fontSize: `${DEFAULT_FONT_SIZE}px`
13683
13737
  };
13684
13738
  function ToolbarPlugin({ disabled, ...props }) {
13685
13739
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
@@ -13713,6 +13767,7 @@ function ToolbarPlugin({ disabled, ...props }) {
13713
13767
  const hasLink = nodes2.some((node) => link.$isLinkNode(node) || link.$isLinkNode(node.getParent()));
13714
13768
  const elementFormat = element.getFormatType?.() ?? null;
13715
13769
  const textColor = selection.$getSelectionStyleValueForProperty(selection$1, "color", void 0);
13770
+ const fontSize = selection.$getSelectionStyleValueForProperty(selection$1, "font-size", void 0);
13716
13771
  setState((current) => ({
13717
13772
  ...current,
13718
13773
  blockType,
@@ -13723,7 +13778,8 @@ function ToolbarPlugin({ disabled, ...props }) {
13723
13778
  isStrikethrough: selection$1.hasFormat("strikethrough"),
13724
13779
  isCode: selection$1.hasFormat("code"),
13725
13780
  isLink: hasLink,
13726
- textColor: textColor || null
13781
+ textColor: textColor || null,
13782
+ fontSize: fontSize || null
13727
13783
  }));
13728
13784
  }, []);
13729
13785
  React.useEffect(() => {
@@ -13777,11 +13833,11 @@ function ToolbarPlugin({ disabled, ...props }) {
13777
13833
  }
13778
13834
  ),
13779
13835
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": true }),
13780
- /* @__PURE__ */ jsxRuntime.jsx(FormatPlugin, { disabled: false, state }),
13781
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": true }),
13782
- /* @__PURE__ */ jsxRuntime.jsx(AdjustFontSizePlugin, { disabled }),
13836
+ /* @__PURE__ */ jsxRuntime.jsx(AdjustFontSizePlugin, { disabled, state }),
13783
13837
  /* @__PURE__ */ jsxRuntime.jsx(ColorPlugin, { disabled, state }),
13784
13838
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": true }),
13839
+ /* @__PURE__ */ jsxRuntime.jsx(FormatPlugin, { disabled: false, state }),
13840
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": true }),
13785
13841
  /* @__PURE__ */ jsxRuntime.jsx(BlockPlugin, { disabled, state }),
13786
13842
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": true }),
13787
13843
  /* @__PURE__ */ jsxRuntime.jsx(LinkPlugin, { disabled, state }),
@@ -13856,7 +13912,7 @@ function ControlledValuePlugin({
13856
13912
  return null;
13857
13913
  }
13858
13914
  var theme = {
13859
- paragraph: "mb-2 leading-6 text-sm text-foreground",
13915
+ paragraph: "mb-2 leading-normal text-sm text-foreground",
13860
13916
  placeholder: "pointer-events-none absolute left-0 top-0 px-3 py-2 text-sm text-muted-foreground select-none",
13861
13917
  quote: "border-l-2 border-border pl-3 italic text-muted-foreground",
13862
13918
  heading: {