@luscii-healthtech/web-ui 54.4.3 → 54.5.0

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.
@@ -29,6 +29,7 @@ var Creatable = require('react-select/creatable');
29
29
  var RadixSwitch = require('@radix-ui/react-switch');
30
30
  var react = require('@tiptap/react');
31
31
  var StarterKit = require('@tiptap/starter-kit');
32
+ var extensionMention = require('@tiptap/extension-mention');
32
33
  var solid = require('@heroicons/react/20/solid');
33
34
  var react$1 = require('@headlessui/react');
34
35
  var ToggleGroup = require('@radix-ui/react-toggle-group');
@@ -4490,7 +4491,26 @@ function generateCustomStyles(hasError) {
4490
4491
  return Object.assign(Object.assign({}, baseStyles), { padding: 0, margin: 0 });
4491
4492
  },
4492
4493
  multiValue: (baseStyles) => {
4493
- return Object.assign(Object.assign({}, baseStyles), { lineHeight: "1rem" });
4494
+ return Object.assign(Object.assign({}, baseStyles), {
4495
+ // background-info-primary-default (blue-300)
4496
+ backgroundColor: "#d7e3fb",
4497
+ borderRadius: "4px",
4498
+ lineHeight: "1rem"
4499
+ });
4500
+ },
4501
+ multiValueLabel: (baseStyles) => {
4502
+ return Object.assign(Object.assign({}, baseStyles), {
4503
+ // text-info-primary-default (brand-900)
4504
+ color: "#112d9c",
4505
+ fontSize: "14px"
4506
+ });
4507
+ },
4508
+ multiValueRemove: (baseStyles) => {
4509
+ return Object.assign(Object.assign({}, baseStyles), { color: "#112d9c", borderRadius: "0 4px 4px 0", "&:hover": {
4510
+ // background-info-primary-hovered (blue-500)
4511
+ backgroundColor: "#b3cafc",
4512
+ color: "#112d9c"
4513
+ } });
4494
4514
  },
4495
4515
  valueContainer: (baseStyles) => {
4496
4516
  return Object.assign(Object.assign({}, baseStyles), { padding: ".5rem", margin: 0 });
@@ -5170,6 +5190,15 @@ const TextEditorToolbarButton = ({ option, hasTextSelected, editor, translations
5170
5190
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
5171
5191
  }
5172
5192
  }, "aria-pressed": editor.isActive("link"), children: jsxRuntime.jsx(solid.LinkIcon, { width: 16 }) });
5193
+ case "tag":
5194
+ if (!editor.schema.nodes.mention) {
5195
+ return null;
5196
+ }
5197
+ return jsxRuntime.jsx(TertiaryIconButton, { label: translations.tagLabel, className: buttonClasses, onClick: () => {
5198
+ const before = editor.state.selection.$from.nodeBefore;
5199
+ const needsSpace = Boolean((before === null || before === void 0 ? void 0 : before.isText) && before.text && !/\s$/.test(before.text));
5200
+ editor.chain().focus().insertContent(needsSpace ? " @" : "@").run();
5201
+ }, children: jsxRuntime.jsx(solid.AtSymbolIcon, { width: 16 }) });
5173
5202
  default:
5174
5203
  return null;
5175
5204
  }
@@ -5205,6 +5234,123 @@ const TextEditorToolbar = ({ toolbarId, toolbar, hasTextSelected, editor, transl
5205
5234
  return jsxRuntime.jsx(Stack, { axis: "x", gap: "m", _px: "xs", id: toolbarId, children: toolbar.map((group) => jsxRuntime.jsx(Stack, { axis: "x", _gap: "xs", children: group.map((option, optionIndex) => jsxRuntime.jsx(TextEditorToolbarButton, { option, hasTextSelected, editor, translations }, getOptionKey(option, optionIndex))) }, getGroupKey(group))) });
5206
5235
  };
5207
5236
 
5237
+ const MentionList = React.forwardRef(({ items, command }, ref) => {
5238
+ const [selectedIndex, setSelectedIndex] = React.useState(0);
5239
+ React.useEffect(() => {
5240
+ setSelectedIndex(0);
5241
+ }, [items]);
5242
+ const selectItem = (index) => {
5243
+ const item = items[index];
5244
+ if (item) {
5245
+ command({ id: item.id, label: item.label });
5246
+ }
5247
+ };
5248
+ React.useImperativeHandle(ref, () => ({
5249
+ onKeyDown: ({ event }) => {
5250
+ if (items.length === 0) {
5251
+ return false;
5252
+ }
5253
+ if (event.key === "ArrowUp") {
5254
+ setSelectedIndex((selectedIndex + items.length - 1) % items.length);
5255
+ return true;
5256
+ }
5257
+ if (event.key === "ArrowDown") {
5258
+ setSelectedIndex((selectedIndex + 1) % items.length);
5259
+ return true;
5260
+ }
5261
+ if (event.key === "Enter") {
5262
+ selectItem(selectedIndex);
5263
+ return true;
5264
+ }
5265
+ return false;
5266
+ }
5267
+ }));
5268
+ if (items.length === 0) {
5269
+ return null;
5270
+ }
5271
+ return jsxRuntime.jsx(Card, { borderRadius: "s", elevation: "large", padding: false, border: true, className: "ui:max-w-80 ui:overflow-hidden", children: jsxRuntime.jsx(Stack, { width: "full", align: "stretch", className: "ui:p-1", children: items.map((item, index) => jsxRuntime.jsx(Box, {
5272
+ as: "button",
5273
+ type: "button",
5274
+ // Use mousedown so selection happens before the editor loses focus.
5275
+ onMouseDown: (event) => {
5276
+ event.preventDefault();
5277
+ selectItem(index);
5278
+ },
5279
+ onMouseEnter: () => setSelectedIndex(index),
5280
+ borderRadius: "xs",
5281
+ className: classNames__default.default("ui:w-full ui:text-left ui:cursor-pointer ui:px-2 ui:py-1.5", {
5282
+ "ui:bg-background-neutral-secondary-hovered": index === selectedIndex
5283
+ }),
5284
+ children: jsxRuntime.jsx(Text, { truncate: true, children: item.label })
5285
+ }, item.id)) }) });
5286
+ });
5287
+ MentionList.displayName = "MentionList";
5288
+
5289
+ const MAX_RESULTS = 8;
5290
+ const createMentionSuggestion = (getTags) => ({
5291
+ items: ({ query }) => {
5292
+ const normalizedQuery = query.toLowerCase();
5293
+ return getTags().filter((tag) => tag.label.toLowerCase().includes(normalizedQuery)).slice(0, MAX_RESULTS);
5294
+ },
5295
+ render: () => {
5296
+ let component = null;
5297
+ let popup = null;
5298
+ const reposition = (clientRect) => {
5299
+ if (!popup || !clientRect) {
5300
+ return;
5301
+ }
5302
+ const rect = clientRect();
5303
+ if (!rect) {
5304
+ return;
5305
+ }
5306
+ popup.style.top = `${rect.bottom + 4}px`;
5307
+ popup.style.left = `${rect.left}px`;
5308
+ };
5309
+ return {
5310
+ onStart: (props) => {
5311
+ component = new react.ReactRenderer(MentionList, {
5312
+ props,
5313
+ editor: props.editor
5314
+ });
5315
+ if (!props.clientRect) {
5316
+ return;
5317
+ }
5318
+ popup = document.createElement("div");
5319
+ popup.style.position = "fixed";
5320
+ popup.style.zIndex = "1000";
5321
+ popup.appendChild(component.element);
5322
+ document.body.appendChild(popup);
5323
+ reposition(props.clientRect);
5324
+ },
5325
+ onUpdate: (props) => {
5326
+ component === null || component === void 0 ? void 0 : component.updateProps(props);
5327
+ reposition(props.clientRect);
5328
+ },
5329
+ onKeyDown: (props) => {
5330
+ var _a, _b;
5331
+ return (_b = (_a = component === null || component === void 0 ? void 0 : component.ref) === null || _a === void 0 ? void 0 : _a.onKeyDown(props)) !== null && _b !== void 0 ? _b : false;
5332
+ },
5333
+ onExit: () => {
5334
+ popup === null || popup === void 0 ? void 0 : popup.remove();
5335
+ popup = null;
5336
+ component === null || component === void 0 ? void 0 : component.destroy();
5337
+ component = null;
5338
+ }
5339
+ };
5340
+ }
5341
+ });
5342
+
5343
+ const MentionView = ({ node }) => {
5344
+ var _a, _b;
5345
+ const id = node.attrs.id;
5346
+ const label = (_a = node.attrs.label) !== null && _a !== void 0 ? _a : id;
5347
+ const char = (_b = node.attrs.mentionSuggestionChar) !== null && _b !== void 0 ? _b : "@";
5348
+ const display = `${char}${label}`;
5349
+ const tooltipText = id && id !== label ? id : null;
5350
+ const pill = jsxRuntime.jsx("span", { className: "web-ui-mention", children: display });
5351
+ return jsxRuntime.jsx(react.NodeViewWrapper, { as: "span", children: tooltipText ? jsxRuntime.jsx(Tooltip$1.Provider, { children: jsxRuntime.jsxs(Tooltip.Root, { children: [jsxRuntime.jsx(Tooltip.Trigger, { asChild: true, children: pill }), jsxRuntime.jsx(Tooltip.Content, { children: jsxRuntime.jsx(Tooltip.Text, { children: tooltipText }) })] }) }) : pill });
5352
+ };
5353
+
5208
5354
  const TEXT_EDITOR_TRANSLATIONS = {
5209
5355
  "en-GB": {
5210
5356
  boldLabel: "bold",
@@ -5212,6 +5358,7 @@ const TEXT_EDITOR_TRANSLATIONS = {
5212
5358
  underlineLabel: "underline",
5213
5359
  strikeLabel: "strike",
5214
5360
  linkLabel: "link",
5361
+ tagLabel: "insert tag",
5215
5362
  orderedListLabel: "ordered list",
5216
5363
  bulletListLabel: "bullet list",
5217
5364
  enterUrlPrompt: "Enter URL:",
@@ -5227,6 +5374,7 @@ const TEXT_EDITOR_TRANSLATIONS = {
5227
5374
  underlineLabel: "onderstreept",
5228
5375
  strikeLabel: "doorgestreept",
5229
5376
  linkLabel: "link",
5377
+ tagLabel: "tag invoegen",
5230
5378
  orderedListLabel: "genummerde lijst",
5231
5379
  bulletListLabel: "opsommingslijst",
5232
5380
  enterUrlPrompt: "Voer URL in:",
@@ -5242,6 +5390,7 @@ const TEXT_EDITOR_TRANSLATIONS = {
5242
5390
  underlineLabel: "unterstrichen",
5243
5391
  strikeLabel: "durchgestrichen",
5244
5392
  linkLabel: "Link",
5393
+ tagLabel: "Tag einf\xFCgen",
5245
5394
  orderedListLabel: "nummerierte Liste",
5246
5395
  bulletListLabel: "Aufz\xE4hlungsliste",
5247
5396
  enterUrlPrompt: "URL eingeben:",
@@ -5257,6 +5406,7 @@ const TEXT_EDITOR_TRANSLATIONS = {
5257
5406
  underlineLabel: "soulign\xE9",
5258
5407
  strikeLabel: "barr\xE9",
5259
5408
  linkLabel: "lien",
5409
+ tagLabel: "ins\xE9rer une balise",
5260
5410
  orderedListLabel: "liste num\xE9rot\xE9e",
5261
5411
  bulletListLabel: "liste \xE0 puces",
5262
5412
  enterUrlPrompt: "Entrer l'URL :",
@@ -5272,6 +5422,7 @@ const TEXT_EDITOR_TRANSLATIONS = {
5272
5422
  underlineLabel: "sublinhado",
5273
5423
  strikeLabel: "riscado",
5274
5424
  linkLabel: "liga\xE7\xE3o",
5425
+ tagLabel: "inserir etiqueta",
5275
5426
  orderedListLabel: "lista numerada",
5276
5427
  bulletListLabel: "lista com marcadores",
5277
5428
  enterUrlPrompt: "Introduzir URL:",
@@ -5286,29 +5437,46 @@ const getTextEditorTranslations = (locale) => {
5286
5437
  return TEXT_EDITOR_TRANSLATIONS[locale] || TEXT_EDITOR_TRANSLATIONS["en-GB"];
5287
5438
  };
5288
5439
 
5289
- 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.web-ui-text-editor {\n resize: vertical;\n min-height: 10rem;\n padding: 1rem;\n font-size: 0.8rem;\n line-height: 1.5;\n outline: none;\n}\n.web-ui-text-editor.tiptap.ProseMirror p.is-editor-empty:first-child::before {\n color: var(--ui-color-text-neutral-primary-disabled);\n content: attr(data-placeholder);\n float: left;\n height: 0;\n pointer-events: none;\n}\n.web-ui-text-editor a {\n color: var(--ui-color-text-brand-primary-default);\n text-decoration: underline;\n cursor: pointer;\n}\n.web-ui-text-editor ul,\n.web-ui-text-editor ol {\n padding-left: 1.5rem;\n}\n.web-ui-text-editor ul {\n list-style-type: disc;\n}\n.web-ui-text-editor ol {\n list-style-type: decimal;\n}\n.web-ui-text-editor li {\n margin-bottom: 0.25rem;\n}\n.web-ui-text-editor strong {\n font-weight: 600;\n}\n.web-ui-text-editor em {\n font-style: italic;\n}\n.web-ui-text-editor u {\n text-decoration: underline;\n}\n.web-ui-text-editor s {\n text-decoration: line-through;\n}\n.web-ui-text-editor h1,\n.web-ui-text-editor h2,\n.web-ui-text-editor h3,\n.web-ui-text-editor h4,\n.web-ui-text-editor h5,\n.web-ui-text-editor h6 {\n font-weight: 600;\n margin-bottom: 0.75rem;\n margin-top: 1rem;\n}\n.web-ui-text-editor h1:first-child,\n.web-ui-text-editor h2:first-child,\n.web-ui-text-editor h3:first-child,\n.web-ui-text-editor h4:first-child,\n.web-ui-text-editor h5:first-child,\n.web-ui-text-editor h6:first-child {\n margin-top: 0;\n}\n.web-ui-text-editor h1 {\n font-size: 2rem;\n}\n.web-ui-text-editor h2 {\n font-size: 1.5rem;\n}\n.web-ui-text-editor h3 {\n font-size: 1.25rem;\n}\n.web-ui-text-editor h4 {\n font-size: 1.125rem;\n}\n.web-ui-text-editor h5,\n.web-ui-text-editor h6 {\n font-size: 1rem;\n}";
5440
+ 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.web-ui-text-editor {\n resize: vertical;\n min-height: 10rem;\n padding: 1rem;\n font-size: 0.8rem;\n line-height: 1.5;\n outline: none;\n}\n.web-ui-text-editor.tiptap.ProseMirror p.is-editor-empty:first-child::before {\n color: var(--ui-color-text-neutral-primary-disabled);\n content: attr(data-placeholder);\n float: left;\n height: 0;\n pointer-events: none;\n}\n.web-ui-text-editor a {\n color: var(--ui-color-text-brand-primary-default);\n text-decoration: underline;\n cursor: pointer;\n}\n.web-ui-text-editor .web-ui-mention {\n display: inline-block;\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n background-color: var(--ui-primitive-color-pink-100);\n color: var(--ui-primitive-color-pink-700);\n font-weight: 500;\n white-space: nowrap;\n}\n.web-ui-text-editor ul,\n.web-ui-text-editor ol {\n padding-left: 1.5rem;\n}\n.web-ui-text-editor ul {\n list-style-type: disc;\n}\n.web-ui-text-editor ol {\n list-style-type: decimal;\n}\n.web-ui-text-editor li {\n margin-bottom: 0.25rem;\n}\n.web-ui-text-editor strong {\n font-weight: 600;\n}\n.web-ui-text-editor em {\n font-style: italic;\n}\n.web-ui-text-editor u {\n text-decoration: underline;\n}\n.web-ui-text-editor s {\n text-decoration: line-through;\n}\n.web-ui-text-editor h1,\n.web-ui-text-editor h2,\n.web-ui-text-editor h3,\n.web-ui-text-editor h4,\n.web-ui-text-editor h5,\n.web-ui-text-editor h6 {\n font-weight: 600;\n margin-bottom: 0.75rem;\n margin-top: 1rem;\n}\n.web-ui-text-editor h1:first-child,\n.web-ui-text-editor h2:first-child,\n.web-ui-text-editor h3:first-child,\n.web-ui-text-editor h4:first-child,\n.web-ui-text-editor h5:first-child,\n.web-ui-text-editor h6:first-child {\n margin-top: 0;\n}\n.web-ui-text-editor h1 {\n font-size: 2rem;\n}\n.web-ui-text-editor h2 {\n font-size: 1.5rem;\n}\n.web-ui-text-editor h3 {\n font-size: 1.25rem;\n}\n.web-ui-text-editor h4 {\n font-size: 1.125rem;\n}\n.web-ui-text-editor h5,\n.web-ui-text-editor h6 {\n font-size: 1rem;\n}";
5290
5441
  styleInject(css_248z$1);
5291
5442
 
5443
+ const MentionWithTooltip = extensionMention.Mention.extend({
5444
+ addNodeView() {
5445
+ return react.ReactNodeViewRenderer(MentionView);
5446
+ }
5447
+ });
5292
5448
  const sanitize = (html) => DOMPurify__default.default.sanitize(html, {
5293
- ALLOWED_TAGS: ["u", "a", "s", "ul", "ol", "li", "p", "strong", "em"],
5294
- ALLOWED_ATTR: ["href", "target"]
5449
+ ALLOWED_TAGS: ["u", "a", "s", "ul", "ol", "li", "p", "strong", "em", "span"],
5450
+ ALLOWED_ATTR: [
5451
+ "href",
5452
+ "target",
5453
+ // Mention/tag nodes render as a span carrying these attributes.
5454
+ "class",
5455
+ "data-type",
5456
+ "data-id",
5457
+ "data-label",
5458
+ "data-mention-suggestion-char"
5459
+ ]
5295
5460
  });
5296
5461
  const TextEditor = (_a) => {
5297
5462
  var { defaultValue, formats = ["bold", "italic", "underline", "strike", "list", "link"], toolbar = [
5298
5463
  ["bold", "italic", "underline", "strike"],
5299
5464
  [{ list: "ordered" }, { list: "bullet" }],
5300
5465
  ["link"]
5301
- ], placeholder, onValueChange } = _a, attrs = __rest(_a, ["defaultValue", "formats", "toolbar", "placeholder", "onValueChange"]);
5466
+ ], placeholder, tags, onValueChange } = _a, attrs = __rest(_a, ["defaultValue", "formats", "toolbar", "placeholder", "tags", "onValueChange"]);
5302
5467
  const rawId = React.useId();
5303
5468
  const toolbarId = `toolbar-${rawId.replace(/:/g, "")}`;
5304
5469
  const defaultValueRef = React.useRef(sanitize(defaultValue !== null && defaultValue !== void 0 ? defaultValue : ""));
5305
5470
  const onTextChangeRef = React.useRef(onValueChange);
5471
+ const tagsRef = React.useRef(tags !== null && tags !== void 0 ? tags : []);
5472
+ const mentionsEnabled = tags !== void 0;
5306
5473
  const [linkTooltip, setLinkTooltip] = React.useState(null);
5307
5474
  const [hasTextSelected, setHasTextSelected] = React.useState(false);
5308
5475
  const locale = useLocaleContext();
5309
5476
  const translations = getTextEditorTranslations(locale);
5310
5477
  React.useLayoutEffect(() => {
5311
5478
  onTextChangeRef.current = onValueChange;
5479
+ tagsRef.current = tags !== null && tags !== void 0 ? tags : [];
5312
5480
  });
5313
5481
  const editor = react.useEditor({
5314
5482
  extensions: [
@@ -5335,7 +5503,13 @@ const TextEditor = (_a) => {
5335
5503
  }
5336
5504
  } : false,
5337
5505
  codeBlock: (formats === null || formats === void 0 ? void 0 : formats.includes("code")) ? {} : false
5338
- })
5506
+ }),
5507
+ ...mentionsEnabled ? [
5508
+ MentionWithTooltip.configure({
5509
+ HTMLAttributes: { class: "web-ui-mention" },
5510
+ suggestion: createMentionSuggestion(() => tagsRef.current)
5511
+ })
5512
+ ] : []
5339
5513
  ],
5340
5514
  content: defaultValueRef.current,
5341
5515
  editorProps: {