@luscii-healthtech/web-ui 46.2.2 → 46.2.3

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.
@@ -32,11 +32,10 @@ var ReactSelect = require('react-select');
32
32
  var RadixSwitch = require('@radix-ui/react-switch');
33
33
  var Quill = require('quill');
34
34
  require('quill-paste-smart');
35
- require('quill/dist/quill.snow.css');
35
+ var solid = require('@heroicons/react/20/solid');
36
36
  var isFunction = require('lodash/isFunction');
37
37
  var isObjectLike = require('lodash/isObjectLike');
38
38
  var react = require('@headlessui/react');
39
- var solid = require('@heroicons/react/20/solid');
40
39
  var ToggleGroup = require('@radix-ui/react-toggle-group');
41
40
 
42
41
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -5231,7 +5230,119 @@ const Textarea = React__namespace.default.forwardRef((_a, ref) => {
5231
5230
  ]), style, ref }));
5232
5231
  });
5233
5232
 
5234
- var css_248z$1 = "/**\n * --- DEPRECATED ---\n * DON'T USE ANYTHING FROM THIS FILE IN FUTURE CHANGES. WE SHOULD BE\n * USING TAILWIND CLASSES DIRECTLY IN OUR COMPONENTS.\n */\n.ql-editor {\n resize: vertical;\n min-height: 10rem;\n}\n\n.ql-snow.ql-toolbar {\n display: block;\n background: #f1f5f9;\n border-top-left-radius: 0.5em;\n border-top-right-radius: 0.5em;\n margin-top: 0.5em;\n}";
5233
+ const LinkTooltip = ({ linkElement, quillInstance, onClose }) => {
5234
+ const dialogRef = React.useRef(null);
5235
+ const anchorName = React.useRef(`link-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`);
5236
+ React.useEffect(() => {
5237
+ var _a;
5238
+ linkElement.style.setProperty("anchor-name", `--${anchorName.current}`);
5239
+ (_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.show();
5240
+ return () => {
5241
+ linkElement.style.removeProperty("anchor-name");
5242
+ };
5243
+ }, [linkElement]);
5244
+ React.useEffect(() => {
5245
+ const handleClickOutside = (event) => {
5246
+ var _a, _b;
5247
+ const target = event.target;
5248
+ if (linkElement.contains(target) || ((_a = dialogRef.current) === null || _a === void 0 ? void 0 : _a.contains(target))) {
5249
+ return;
5250
+ }
5251
+ (_b = dialogRef.current) === null || _b === void 0 ? void 0 : _b.close();
5252
+ onClose();
5253
+ };
5254
+ document.addEventListener("mousedown", handleClickOutside);
5255
+ return () => {
5256
+ document.removeEventListener("mousedown", handleClickOutside);
5257
+ };
5258
+ }, [linkElement, onClose]);
5259
+ const handleEditLink = () => {
5260
+ const currentUrl = linkElement.getAttribute("href") || "";
5261
+ const newUrl = prompt("Link URL:", currentUrl);
5262
+ if (newUrl !== null) {
5263
+ const blot = quillInstance.scroll.find(linkElement);
5264
+ if (blot) {
5265
+ const index = quillInstance.getIndex(blot);
5266
+ const length = blot.length();
5267
+ quillInstance.setSelection(index, length);
5268
+ quillInstance.format("link", newUrl || false);
5269
+ }
5270
+ }
5271
+ onClose();
5272
+ };
5273
+ const handleRemoveLink = () => {
5274
+ const blot = quillInstance.scroll.find(linkElement);
5275
+ if (blot) {
5276
+ const index = quillInstance.getIndex(blot);
5277
+ const length = blot.length();
5278
+ quillInstance.setSelection(index, length);
5279
+ quillInstance.format("link", false);
5280
+ }
5281
+ onClose();
5282
+ };
5283
+ const url = linkElement.getAttribute("href") || "";
5284
+ return jsxRuntime.jsx("dialog", { ref: dialogRef, className: "ui:m-0 ui:p-0 ui:border-0 ui:bg-transparent", style: {
5285
+ position: "absolute",
5286
+ // @ts-expect-error - CSS anchor positioning is not yet in TypeScript types
5287
+ positionAnchor: `--${anchorName.current}`,
5288
+ top: "anchor(bottom)",
5289
+ left: "anchor(left)",
5290
+ marginTop: "8px"
5291
+ }, children: jsxRuntime.jsx(Card, { borderRadius: "s", elevation: "large", className: "ui:max-w-80", padding: false, border: true, children: jsxRuntime.jsxs(Stack, { width: "full", align: "stretch", children: [jsxRuntime.jsx(Box, { p: "xs", children: jsxRuntime.jsxs(Text, { children: ["Visit URL:", " ", jsxRuntime.jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "ui:text-blue-600 ui:underline ui:text-sm ui:overflow-hidden ui:text-ellipsis ui:whitespace-nowrap hover:ui:text-blue-700", children: url })] }) }), jsxRuntime.jsx(Divider, { version: "v2" }), jsxRuntime.jsxs(Stack, { axis: "x", gap: "xxs", p: "xs", children: [jsxRuntime.jsx(TertiaryButton, { onClick: handleEditLink, text: "Edit", size: "medium" }), jsxRuntime.jsx(TertiaryButton, { onClick: handleRemoveLink, text: "Remove", size: "medium" }), jsxRuntime.jsx(TertiaryButton, { onClick: onClose, text: "Close", size: "medium" })] })] }) }) });
5292
+ };
5293
+
5294
+ const TextEditorToolbarButton = ({ option, hasTextSelected }) => {
5295
+ const buttonClasses = "ui:aria-pressed:bg-primary-background ui:aria-disabled:cursor-not-allowed";
5296
+ if (typeof option === "string") {
5297
+ switch (option) {
5298
+ case "bold":
5299
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "bold", className: `ql-bold ${buttonClasses}`, children: jsxRuntime.jsx(solid.BoldIcon, { width: 16 }) });
5300
+ case "italic":
5301
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "italic", className: `ql-italic ${buttonClasses}`, children: jsxRuntime.jsx(solid.ItalicIcon, { width: 16 }) });
5302
+ case "underline":
5303
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "underline", className: `ql-underline ${buttonClasses}`, children: jsxRuntime.jsx(solid.UnderlineIcon, { width: 16 }) });
5304
+ case "strike":
5305
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "strike", className: `ql-strike ${buttonClasses}`, children: jsxRuntime.jsx(solid.StrikethroughIcon, { width: 16 }) });
5306
+ case "link":
5307
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "link", className: `ql-link ${buttonClasses}`, disabled: !hasTextSelected, children: jsxRuntime.jsx(solid.LinkIcon, { width: 16 }) });
5308
+ case "video":
5309
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "video", className: `ql-video ${buttonClasses}`, children: jsxRuntime.jsx(solid.VideoCameraIcon, { width: 16 }) });
5310
+ default:
5311
+ return null;
5312
+ }
5313
+ } else if (typeof option === "object" && "list" in option) {
5314
+ if (option.list === "ordered") {
5315
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "ordered list", className: `ql-list ${buttonClasses}`, value: "ordered", children: jsxRuntime.jsx(solid.NumberedListIcon, { width: 16 }) });
5316
+ } else if (option.list === "bullet") {
5317
+ return jsxRuntime.jsx(TertiaryIconButton, { label: "bullet list", className: `ql-list ${buttonClasses}`, value: "bullet", children: jsxRuntime.jsx(solid.ListBulletIcon, { width: 16 }) });
5318
+ }
5319
+ }
5320
+ return null;
5321
+ };
5322
+
5323
+ const getOptionKey = (option, index) => {
5324
+ if (typeof option === "string") {
5325
+ return option;
5326
+ } else if (typeof option === "object" && "list" in option) {
5327
+ return `list-${option.list}`;
5328
+ }
5329
+ return `option-${index}`;
5330
+ };
5331
+ const getGroupKey = (group) => {
5332
+ return group.map((option) => {
5333
+ if (typeof option === "string") {
5334
+ return option;
5335
+ } else if (typeof option === "object" && "list" in option) {
5336
+ return `list-${option.list}`;
5337
+ }
5338
+ return "";
5339
+ }).join("-");
5340
+ };
5341
+ const TextEditorToolbar = ({ toolbarId, toolbar, hasTextSelected }) => {
5342
+ return jsxRuntime.jsx(Stack, { axis: "x", gap: "m", px: "xxxs", id: toolbarId, children: toolbar.map((group) => jsxRuntime.jsx(Stack, { axis: "x", gap: "xxxxs", children: group.map((option, optionIndex) => jsxRuntime.jsx(TextEditorToolbarButton, { option, hasTextSelected }, getOptionKey(option, optionIndex))) }, getGroupKey(group))) });
5343
+ };
5344
+
5345
+ var css_248z$1 = "/**\n * --- DEPRECATED ---\n * DON'T USE ANYTHING FROM THIS FILE IN FUTURE CHANGES. WE SHOULD BE\n * USING TAILWIND CLASSES DIRECTLY IN OUR COMPONENTS.\n */\n.ql-editor {\n resize: vertical;\n min-height: 10rem;\n padding: 1rem;\n font-size: 0.8rem;\n line-height: 1.5;\n}\n.ql-editor a {\n color: var(--ui-color-text-brand-primary-default);\n text-decoration: underline;\n cursor: pointer;\n}\n.ql-editor ul,\n.ql-editor ol {\n padding-left: 1.5rem;\n}\n.ql-editor ul {\n list-style-type: disc;\n}\n.ql-editor ol {\n list-style-type: decimal;\n}\n.ql-editor li {\n margin-bottom: 0.25rem;\n}\n.ql-editor strong {\n font-weight: 600;\n}\n.ql-editor em {\n font-style: italic;\n}\n.ql-editor u {\n text-decoration: underline;\n}\n.ql-editor s {\n text-decoration: line-through;\n}\n.ql-editor h1,\n.ql-editor h2,\n.ql-editor h3,\n.ql-editor h4,\n.ql-editor h5,\n.ql-editor h6 {\n font-weight: 600;\n margin-bottom: 0.75rem;\n margin-top: 1rem;\n}\n.ql-editor h1:first-child,\n.ql-editor h2:first-child,\n.ql-editor h3:first-child,\n.ql-editor h4:first-child,\n.ql-editor h5:first-child,\n.ql-editor h6:first-child {\n margin-top: 0;\n}\n.ql-editor h1 {\n font-size: 2rem;\n}\n.ql-editor h2 {\n font-size: 1.5rem;\n}\n.ql-editor h3 {\n font-size: 1.25rem;\n}\n.ql-editor h4 {\n font-size: 1.125rem;\n}\n.ql-editor h5,\n.ql-editor h6 {\n font-size: 1rem;\n}";
5235
5346
  styleInject(css_248z$1);
5236
5347
 
5237
5348
  const TextEditor = (_a) => {
@@ -5240,36 +5351,62 @@ const TextEditor = (_a) => {
5240
5351
  [{ list: "ordered" }, { list: "bullet" }],
5241
5352
  ["link"]
5242
5353
  ], placeholder, onValueChange } = _a, attrs = __rest(_a, ["defaultValue", "formats", "toolbar", "placeholder", "onValueChange"]);
5354
+ const rawId = React.useId();
5355
+ const toolbarId = `toolbar-${rawId.replace(/:/g, "")}`;
5243
5356
  const defaultValueRef = React.useRef(defaultValue);
5244
5357
  const onTextChangeRef = React.useRef(onValueChange);
5245
5358
  const editorRef = React.useRef(null);
5246
5359
  const quillRef = React.useRef(null);
5360
+ const [linkTooltip, setLinkTooltip] = React.useState(null);
5361
+ const [hasTextSelected, setHasTextSelected] = React.useState(false);
5247
5362
  React.useLayoutEffect(() => {
5248
5363
  onTextChangeRef.current = onValueChange;
5249
5364
  });
5250
5365
  React.useEffect(() => {
5251
- if (editorRef.current) {
5252
- const quill = new Quill__default.default(editorRef.current, {
5253
- theme: "snow",
5254
- formats,
5255
- modules: {
5256
- toolbar
5257
- },
5258
- placeholder
5259
- });
5260
- quill.on(Quill__default.default.events.TEXT_CHANGE, (value, _, source) => {
5261
- var _a2;
5262
- (_a2 = onTextChangeRef.current) === null || _a2 === void 0 ? void 0 : _a2.call(onTextChangeRef, quill.getSemanticHTML(), value, source);
5263
- });
5264
- if (defaultValueRef.current) {
5265
- quill.setContents(quill.clipboard.convert({
5266
- html: defaultValueRef.current
5267
- }));
5268
- }
5269
- quillRef.current = quill;
5366
+ if (!editorRef.current || quillRef.current) {
5367
+ return void 0;
5368
+ }
5369
+ const editor = editorRef.current;
5370
+ const quill = new Quill__default.default(editor, {
5371
+ formats,
5372
+ modules: {
5373
+ toolbar: `#${toolbarId}`
5374
+ },
5375
+ placeholder
5376
+ });
5377
+ quill.on(Quill__default.default.events.TEXT_CHANGE, (value, _, source) => {
5378
+ var _a2;
5379
+ (_a2 = onTextChangeRef.current) === null || _a2 === void 0 ? void 0 : _a2.call(onTextChangeRef, quill.getSemanticHTML(), value, source);
5380
+ });
5381
+ const handleSelectionChange = () => {
5382
+ const selection = quill.getSelection();
5383
+ setHasTextSelected(selection ? selection.length > 0 : false);
5384
+ };
5385
+ quill.on(Quill__default.default.events.SELECTION_CHANGE, handleSelectionChange);
5386
+ if (defaultValueRef.current) {
5387
+ quill.setContents(quill.clipboard.convert({
5388
+ html: defaultValueRef.current
5389
+ }));
5270
5390
  }
5391
+ quillRef.current = quill;
5392
+ const qlEditor = editor.querySelector(".ql-editor");
5393
+ if (qlEditor) {
5394
+ qlEditor.classList.add("ui:overflow-auto", "ui:resize-y", "ui:min-h-40");
5395
+ }
5396
+ const handleEditorClick = (e) => {
5397
+ const target = e.target;
5398
+ if (target.tagName === "A") {
5399
+ e.preventDefault();
5400
+ const anchor = target;
5401
+ setLinkTooltip(anchor);
5402
+ }
5403
+ };
5404
+ editor.addEventListener("click", handleEditorClick);
5405
+ return () => {
5406
+ editor.removeEventListener("click", handleEditorClick);
5407
+ };
5271
5408
  }, []);
5272
- return jsxRuntime.jsx("div", Object.assign({}, attrs, { children: jsxRuntime.jsx("div", { ref: editorRef }) }));
5409
+ return jsxRuntime.jsxs(Card, Object.assign({ padding: false, border: true, borderRadius: "xs", backgroundColor: "base" }, attrs, { children: [jsxRuntime.jsx(Card.TopBar, { children: jsxRuntime.jsx(Card.Actions, { className: "ui:justify-start", children: jsxRuntime.jsx(TextEditorToolbar, { toolbarId, toolbar, hasTextSelected }) }) }), jsxRuntime.jsx(Divider, { version: "v2" }), jsxRuntime.jsx("div", { className: "editor", ref: editorRef }), jsxRuntime.jsx("div", { children: linkTooltip && quillRef.current && jsxRuntime.jsx(LinkTooltip, { linkElement: linkTooltip, quillInstance: quillRef.current, onClose: () => setLinkTooltip(null) }) })] }));
5273
5410
  };
5274
5411
 
5275
5412
  const TextLink = (props) => {