@sustaina/shared-ui 1.51.1 → 1.52.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.
package/dist/index.js CHANGED
@@ -236,7 +236,7 @@ function stripNullishObject(value) {
236
236
 
237
237
  // src/utils/date.ts
238
238
  var pad = (num) => String(num).padStart(2, "0");
239
- function formatISODate(isoDate, format5 = "d/m/Y H:i") {
239
+ function formatISODate(isoDate, format6 = "d/m/Y H:i") {
240
240
  const date = new Date(isoDate);
241
241
  if (isNaN(date.getTime())) {
242
242
  return "Invalid Date";
@@ -267,7 +267,7 @@ function formatISODate(isoDate, format5 = "d/m/Y H:i") {
267
267
  // Second
268
268
  s: "s"
269
269
  };
270
- return format5.replace(/YYYY|Y|MM|m|DD|d|H|i|s/g, (match) => {
270
+ return format6.replace(/YYYY|Y|MM|m|DD|d|H|i|s/g, (match) => {
271
271
  const partKey = tokenMap[match];
272
272
  return partKey ? parts[partKey] : match;
273
273
  });
@@ -11667,8 +11667,8 @@ var GridSettingsModal = ({
11667
11667
  }
11668
11668
  }, [isOpen, currentColumns, form]);
11669
11669
  const addColumn = async () => {
11670
- const isValid6 = await trigger("columns");
11671
- if (isValid6) {
11670
+ const isValid7 = await trigger("columns");
11671
+ if (isValid7) {
11672
11672
  append({ id: "" });
11673
11673
  requestAnimationFrame(() => {
11674
11674
  const container = scrollRef.current;
@@ -13547,12 +13547,12 @@ function LinkPreviewPopover({
13547
13547
  function FormatPlugin({ disabled, state }) {
13548
13548
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
13549
13549
  const toggleFormat = React.useCallback(
13550
- (format5) => {
13550
+ (format6) => {
13551
13551
  if (disabled) {
13552
13552
  return;
13553
13553
  }
13554
13554
  editor.focus();
13555
- editor.dispatchCommand(lexical.FORMAT_TEXT_COMMAND, format5);
13555
+ editor.dispatchCommand(lexical.FORMAT_TEXT_COMMAND, format6);
13556
13556
  },
13557
13557
  [disabled, editor]
13558
13558
  );
@@ -13897,12 +13897,12 @@ function BlockPlugin({ disabled, state }) {
13897
13897
  function AlignPlugin({ disabled, state }) {
13898
13898
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
13899
13899
  const applyElementFormat = React.useCallback(
13900
- (format5) => {
13900
+ (format6) => {
13901
13901
  if (disabled) {
13902
13902
  return;
13903
13903
  }
13904
13904
  editor.focus();
13905
- editor.dispatchCommand(lexical.FORMAT_ELEMENT_COMMAND, format5);
13905
+ editor.dispatchCommand(lexical.FORMAT_ELEMENT_COMMAND, format6);
13906
13906
  },
13907
13907
  [disabled, editor]
13908
13908
  );
@@ -14282,6 +14282,65 @@ function MentionsPlugin({
14282
14282
  });
14283
14283
  });
14284
14284
  }, [editor, mentions, mentionKeyMap, mentionConfig]);
14285
+ React.useEffect(() => {
14286
+ if (mentions.length === 0) return;
14287
+ return editor.registerCommand(
14288
+ lexical.PASTE_COMMAND,
14289
+ (event) => {
14290
+ const clipboardData = event.clipboardData;
14291
+ if (!clipboardData) return false;
14292
+ const pastedText = clipboardData.getData("text/plain");
14293
+ if (!pastedText) return false;
14294
+ const variableMatches = [...pastedText.matchAll(COMPLETE_VARIABLE_REGEX)];
14295
+ const hasKnownVariable = variableMatches.some((match) => {
14296
+ const variableName = match[1];
14297
+ const fullMatch = match[0];
14298
+ return mentionKeyMap.has(variableName.toUpperCase()) || mentionKeyMap.has(fullMatch.toUpperCase());
14299
+ });
14300
+ if (!hasKnownVariable) return false;
14301
+ event.preventDefault();
14302
+ editor.update(
14303
+ () => {
14304
+ const selection = lexical.$getSelection();
14305
+ if (!lexical.$isRangeSelection(selection)) return;
14306
+ let lastIndex = 0;
14307
+ const nodesToInsert = [];
14308
+ for (const match of variableMatches) {
14309
+ const fullMatch = match[0];
14310
+ const variableName = match[1];
14311
+ const matchIndex = match.index;
14312
+ if (matchIndex > lastIndex) {
14313
+ const textBefore = pastedText.slice(lastIndex, matchIndex);
14314
+ nodesToInsert.push(lexical.$createTextNode(textBefore));
14315
+ }
14316
+ const mentionItem = mentionKeyMap.get(variableName.toUpperCase()) || mentionKeyMap.get(fullMatch.toUpperCase());
14317
+ if (mentionItem) {
14318
+ nodesToInsert.push(
14319
+ $createMentionNode(
14320
+ mentionConfig.getName(mentionItem),
14321
+ mentionConfig.getLabel(mentionItem)
14322
+ )
14323
+ );
14324
+ nodesToInsert.push(lexical.$createTextNode(" "));
14325
+ } else {
14326
+ nodesToInsert.push(lexical.$createTextNode(fullMatch));
14327
+ }
14328
+ lastIndex = matchIndex + fullMatch.length;
14329
+ }
14330
+ if (lastIndex < pastedText.length) {
14331
+ nodesToInsert.push(lexical.$createTextNode(pastedText.slice(lastIndex)));
14332
+ }
14333
+ for (const node of nodesToInsert) {
14334
+ selection.insertNodes([node]);
14335
+ }
14336
+ },
14337
+ { tag: "paste-mention-conversion" }
14338
+ );
14339
+ return true;
14340
+ },
14341
+ lexical.COMMAND_PRIORITY_LOW
14342
+ );
14343
+ }, [editor, mentions, mentionKeyMap, mentionConfig]);
14285
14344
  const options = React.useMemo(() => {
14286
14345
  if (!queryString) {
14287
14346
  return mentions.map(
@@ -14422,6 +14481,41 @@ function OnChangePluginFiltered({
14422
14481
  }, [editor, onChange, ignoreSelectionChange]);
14423
14482
  return null;
14424
14483
  }
14484
+ function MaxLengthPlugin({ maxLength }) {
14485
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
14486
+ React.useEffect(() => {
14487
+ if (!maxLength) return;
14488
+ let lastRestoredTextLength = 0;
14489
+ return editor.registerNodeTransform(lexical.RootNode, (rootNode) => {
14490
+ const selection$1 = lexical.$getSelection();
14491
+ if (!lexical.$isRangeSelection(selection$1) || !selection$1.isCollapsed()) {
14492
+ return;
14493
+ }
14494
+ const prevTextLength = lastRestoredTextLength;
14495
+ const textLength = rootNode.getTextContentSize();
14496
+ if (prevTextLength !== textLength) {
14497
+ const delCount = textLength - maxLength;
14498
+ const anchor = selection$1.anchor;
14499
+ if (delCount > 0) {
14500
+ if (prevTextLength === maxLength && lastRestoredTextLength !== maxLength) {
14501
+ lastRestoredTextLength = maxLength;
14502
+ $restoreTextContent(anchor);
14503
+ } else {
14504
+ selection.trimTextContentFromAnchor(editor, anchor, delCount);
14505
+ }
14506
+ }
14507
+ }
14508
+ });
14509
+ }, [editor, maxLength]);
14510
+ return null;
14511
+ }
14512
+ function $restoreTextContent(anchor) {
14513
+ const selection = lexical.$getSelection();
14514
+ if (lexical.$isRangeSelection(selection)) {
14515
+ selection.anchor.set(anchor.key, anchor.offset, "text");
14516
+ selection.focus.set(anchor.key, anchor.offset, "text");
14517
+ }
14518
+ }
14425
14519
  var theme = {
14426
14520
  paragraph: "mb-2 leading-normal text-sm text-foreground",
14427
14521
  placeholder: "pointer-events-none absolute left-0 top-0 px-3 py-2 text-sm text-muted-foreground select-none",
@@ -14477,6 +14571,7 @@ function RichTextInner({
14477
14571
  onImageDialogUploadError,
14478
14572
  acceptImageMimeTypes = "image/*",
14479
14573
  allowImageUrlInsert = true,
14574
+ maxLength,
14480
14575
  mentions,
14481
14576
  mentionConfig,
14482
14577
  mentionTrigger,
@@ -14596,7 +14691,8 @@ function RichTextInner({
14596
14691
  autoFocus ? /* @__PURE__ */ jsxRuntime.jsx(LexicalAutoFocusPlugin.AutoFocusPlugin, {}) : null,
14597
14692
  /* @__PURE__ */ jsxRuntime.jsx(EditableStatePlugin, { editable }),
14598
14693
  /* @__PURE__ */ jsxRuntime.jsx(ControlledValuePlugin, { value, trackAppliedValue: appliedValueRef }),
14599
- /* @__PURE__ */ jsxRuntime.jsx(OnChangePluginFiltered, { onChange: handleChange, ignoreSelectionChange: true })
14694
+ /* @__PURE__ */ jsxRuntime.jsx(OnChangePluginFiltered, { onChange: handleChange, ignoreSelectionChange: true }),
14695
+ maxLength && /* @__PURE__ */ jsxRuntime.jsx(MaxLengthPlugin, { maxLength })
14600
14696
  ] })
14601
14697
  ]
14602
14698
  }
@@ -14692,58 +14788,81 @@ var RightPanelContainer = ({
14692
14788
  );
14693
14789
  };
14694
14790
  var RightPanelContainer_default = RightPanelContainer;
14791
+ var defaultDisplayFormatter3 = (date, use24Hour) => use24Hour ? dateFns.format(date, "HH:mm") : dateFns.format(date, "hh:mm a");
14792
+ var defaultValueFormatter3 = (date) => dateFns.format(date, "HH:mm");
14793
+ var defaultValueParser3 = (value) => {
14794
+ let parsed = dateFns.parse(value, "HH:mm", /* @__PURE__ */ new Date());
14795
+ if (dateFns.isValid(parsed)) return parsed;
14796
+ parsed = dateFns.parse(value, "HH:mm:ss", /* @__PURE__ */ new Date());
14797
+ if (dateFns.isValid(parsed)) return parsed;
14798
+ parsed = dateFns.parse(value, "hh:mm a", /* @__PURE__ */ new Date());
14799
+ if (dateFns.isValid(parsed)) return parsed;
14800
+ return void 0;
14801
+ };
14695
14802
  var TimePicker = React__namespace.forwardRef(
14696
14803
  ({
14697
- value = "",
14804
+ value,
14698
14805
  onChange,
14806
+ onValueChange,
14699
14807
  disabled = false,
14700
14808
  className,
14809
+ buttonClassName,
14810
+ wrapperClassName,
14701
14811
  placeholder: placeholder2,
14702
14812
  use24Hour = false,
14703
14813
  iconPosition = "start",
14704
- icon
14814
+ icon,
14815
+ allowClear = true,
14816
+ clearAriaLabel = "Clear time",
14817
+ displayFormatter,
14818
+ valueFormatter,
14819
+ valueParser,
14820
+ invalid = false
14705
14821
  }, ref) => {
14706
14822
  const [open, setOpen] = React__namespace.useState(false);
14707
14823
  const [hours, setHours] = React__namespace.useState("12");
14708
14824
  const [minutes, setMinutes] = React__namespace.useState("00");
14709
14825
  const [period, setPeriod] = React__namespace.useState("AM");
14826
+ const parser = React__namespace.useMemo(() => valueParser ?? defaultValueParser3, [valueParser]);
14827
+ const outputFormatter = React__namespace.useMemo(
14828
+ () => valueFormatter ?? defaultValueFormatter3,
14829
+ [valueFormatter]
14830
+ );
14831
+ const labelFormatter = React__namespace.useMemo(
14832
+ () => displayFormatter ?? defaultDisplayFormatter3,
14833
+ [displayFormatter]
14834
+ );
14835
+ const parseInput = React__namespace.useCallback(
14836
+ (input) => {
14837
+ if (input === null || input === void 0) return void 0;
14838
+ if (input instanceof Date) return dateFns.isValid(input) ? input : void 0;
14839
+ const parsed = parser(input);
14840
+ return parsed && dateFns.isValid(parsed) ? parsed : void 0;
14841
+ },
14842
+ [parser]
14843
+ );
14844
+ const parsedValue = React__namespace.useMemo(() => parseInput(value), [parseInput, value]);
14845
+ const hasValue = parsedValue !== void 0;
14710
14846
  React__namespace.useEffect(() => {
14711
- if (value) {
14712
- let h, m;
14713
- if (value.includes("Z") || value.match(/^\d{2}:\d{2}:\d{2}/)) {
14714
- const [hour, min] = value.split(":");
14715
- const hour24 = parseInt(hour);
14716
- const minute = parseInt(min);
14717
- if (use24Hour) {
14718
- h = String(hour24);
14719
- m = String(minute);
14720
- } else {
14721
- const newPeriod = hour24 >= 12 ? "PM" : "AM";
14722
- const hour12 = hour24 === 0 ? 12 : hour24 > 12 ? hour24 - 12 : hour24;
14723
- h = String(hour12);
14724
- m = String(minute);
14725
- setPeriod(newPeriod);
14726
- }
14847
+ if (parsedValue) {
14848
+ const hour24 = parsedValue.getHours();
14849
+ const minute = parsedValue.getMinutes();
14850
+ if (use24Hour) {
14851
+ setHours(String(hour24).padStart(2, "0"));
14727
14852
  } else {
14728
- const [time, meridiem] = value.split(" ");
14729
- const [hour, min] = time.split(":");
14730
- h = hour;
14731
- m = min;
14732
- if (meridiem) {
14733
- setPeriod(meridiem);
14734
- }
14853
+ const newPeriod = hour24 >= 12 ? "PM" : "AM";
14854
+ const hour12 = hour24 === 0 ? 12 : hour24 > 12 ? hour24 - 12 : hour24;
14855
+ setHours(String(hour12).padStart(2, "0"));
14856
+ setPeriod(newPeriod);
14735
14857
  }
14736
- setHours(h.padStart(2, "0"));
14737
- setMinutes(m.padStart(2, "0"));
14738
- }
14739
- }, [value, use24Hour]);
14740
- const formatTime = (h, m, p) => {
14741
- if (use24Hour) {
14742
- return `${h.padStart(2, "0")}:${m.padStart(2, "0")}`;
14858
+ setMinutes(String(minute).padStart(2, "0"));
14859
+ } else {
14860
+ setHours(use24Hour ? "00" : "12");
14861
+ setMinutes("00");
14862
+ setPeriod("AM");
14743
14863
  }
14744
- return `${h.padStart(2, "0")}:${m.padStart(2, "0")} ${p}`;
14745
- };
14746
- const toISOTime = (h, m, p) => {
14864
+ }, [parsedValue, use24Hour]);
14865
+ const createTimeDate = (h, m, p) => {
14747
14866
  let hour = parseInt(h) || 0;
14748
14867
  const minute = parseInt(m) || 0;
14749
14868
  if (!use24Hour) {
@@ -14753,28 +14872,37 @@ var TimePicker = React__namespace.forwardRef(
14753
14872
  hour = 0;
14754
14873
  }
14755
14874
  }
14756
- return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}:00.000Z`;
14875
+ const today = /* @__PURE__ */ new Date();
14876
+ return new Date(today.getFullYear(), today.getMonth(), today.getDate(), hour, minute, 0, 0);
14877
+ };
14878
+ const emitChange = (date) => {
14879
+ onChange?.(date);
14880
+ onValueChange?.(outputFormatter(date));
14881
+ };
14882
+ const handleClear = () => {
14883
+ onChange?.(void 0);
14884
+ onValueChange?.(void 0);
14757
14885
  };
14758
14886
  const handleHourChange = (newHour) => {
14759
14887
  const hour = parseInt(newHour) || 0;
14760
14888
  const maxHour = use24Hour ? 23 : 12;
14761
14889
  const minHour = use24Hour ? 0 : 1;
14762
14890
  if (hour <= maxHour && hour >= minHour) {
14763
- setHours(newHour);
14764
- onChange?.(toISOTime(newHour, minutes, period));
14891
+ setHours(newHour.padStart(2, "0"));
14892
+ emitChange(createTimeDate(newHour, minutes, period));
14765
14893
  }
14766
14894
  };
14767
14895
  const handleMinuteChange = (newMinute) => {
14768
14896
  const minute = parseInt(newMinute) || 0;
14769
14897
  if (minute <= 59 && minute >= 0) {
14770
- setMinutes(newMinute);
14771
- onChange?.(toISOTime(hours, newMinute, period));
14898
+ setMinutes(newMinute.padStart(2, "0"));
14899
+ emitChange(createTimeDate(hours, newMinute, period));
14772
14900
  }
14773
14901
  };
14774
14902
  const handlePeriodToggle = () => {
14775
14903
  const newPeriod = period === "AM" ? "PM" : "AM";
14776
14904
  setPeriod(newPeriod);
14777
- onChange?.(toISOTime(hours, minutes, newPeriod));
14905
+ emitChange(createTimeDate(hours, minutes, newPeriod));
14778
14906
  };
14779
14907
  const incrementHour = () => {
14780
14908
  const hour = parseInt(hours) || 0;
@@ -14800,193 +14928,207 @@ var TimePicker = React__namespace.forwardRef(
14800
14928
  const newMinute = minute <= 0 ? 59 : minute - 1;
14801
14929
  handleMinuteChange(String(newMinute));
14802
14930
  };
14803
- const displayValue = formatTime(hours, minutes, period);
14931
+ const displayValue = parsedValue ? labelFormatter(parsedValue, use24Hour) : placeholder2;
14804
14932
  const displayIcon = icon || /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4" });
14805
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
14806
- /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
14807
- Button,
14808
- {
14809
- variant: "outline",
14810
- disabled,
14811
- className: cn(
14812
- "w-full justify-between text-left font-normal",
14813
- !value && "text-muted-foreground",
14814
- className
14815
- ),
14816
- children: [
14817
- iconPosition === "start" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: displayIcon }),
14933
+ const showClear = allowClear && hasValue && !disabled;
14934
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative inline-flex w-full", wrapperClassName), children: [
14935
+ /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
14936
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
14937
+ Button,
14938
+ {
14939
+ variant: "outline",
14940
+ disabled,
14941
+ className: cn(
14942
+ "w-full justify-between text-left font-normal",
14943
+ !hasValue && "text-muted-foreground",
14944
+ invalid && "border-destructive focus-visible:ring-destructive",
14945
+ showClear && "pr-8",
14946
+ buttonClassName,
14947
+ className
14948
+ ),
14949
+ children: [
14950
+ iconPosition === "start" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: displayIcon }),
14951
+ /* @__PURE__ */ jsxRuntime.jsx(
14952
+ "span",
14953
+ {
14954
+ className: cn(
14955
+ "flex-1 truncate",
14956
+ iconPosition === "start" && "ml-2",
14957
+ iconPosition === "end" && "mr-2"
14958
+ ),
14959
+ children: displayValue || placeholder2 || "Select time"
14960
+ }
14961
+ ),
14962
+ iconPosition === "end" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: displayIcon })
14963
+ ]
14964
+ }
14965
+ ) }),
14966
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-auto p-4", align: "start", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
14967
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
14818
14968
  /* @__PURE__ */ jsxRuntime.jsx(
14819
- "span",
14969
+ Button,
14820
14970
  {
14821
- className: cn(
14822
- "flex-1",
14823
- iconPosition === "start" && "ml-2",
14824
- iconPosition === "end" && "mr-2"
14825
- ),
14826
- children: value ? displayValue : placeholder2 || displayValue
14971
+ variant: "ghost",
14972
+ size: "icon",
14973
+ className: "h-8 w-8",
14974
+ onClick: incrementHour,
14975
+ type: "button",
14976
+ children: /* @__PURE__ */ jsxRuntime.jsx(
14977
+ "svg",
14978
+ {
14979
+ xmlns: "http://www.w3.org/2000/svg",
14980
+ width: "16",
14981
+ height: "16",
14982
+ viewBox: "0 0 24 24",
14983
+ fill: "none",
14984
+ stroke: "currentColor",
14985
+ strokeWidth: "2",
14986
+ strokeLinecap: "round",
14987
+ strokeLinejoin: "round",
14988
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" })
14989
+ }
14990
+ )
14827
14991
  }
14828
14992
  ),
14829
- iconPosition === "end" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: displayIcon })
14830
- ]
14831
- }
14832
- ) }),
14833
- /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-auto p-4", align: "start", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
14834
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
14835
- /* @__PURE__ */ jsxRuntime.jsx(
14836
- Button,
14837
- {
14838
- variant: "ghost",
14839
- size: "icon",
14840
- className: "h-8 w-8",
14841
- onClick: incrementHour,
14842
- type: "button",
14843
- children: /* @__PURE__ */ jsxRuntime.jsx(
14844
- "svg",
14845
- {
14846
- xmlns: "http://www.w3.org/2000/svg",
14847
- width: "16",
14848
- height: "16",
14849
- viewBox: "0 0 24 24",
14850
- fill: "none",
14851
- stroke: "currentColor",
14852
- strokeWidth: "2",
14853
- strokeLinecap: "round",
14854
- strokeLinejoin: "round",
14855
- children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" })
14856
- }
14857
- )
14858
- }
14859
- ),
14860
- /* @__PURE__ */ jsxRuntime.jsx(
14861
- Input,
14862
- {
14863
- ref,
14864
- type: "text",
14865
- inputMode: "numeric",
14866
- value: hours,
14867
- onChange: (e) => handleHourChange(e.target.value),
14868
- className: "w-16 text-center",
14869
- maxLength: 2
14870
- }
14871
- ),
14872
- /* @__PURE__ */ jsxRuntime.jsx(
14873
- Button,
14874
- {
14875
- variant: "ghost",
14876
- size: "icon",
14877
- className: "h-8 w-8",
14878
- onClick: decrementHour,
14879
- type: "button",
14880
- children: /* @__PURE__ */ jsxRuntime.jsx(
14881
- "svg",
14882
- {
14883
- xmlns: "http://www.w3.org/2000/svg",
14884
- width: "16",
14885
- height: "16",
14886
- viewBox: "0 0 24 24",
14887
- fill: "none",
14888
- stroke: "currentColor",
14889
- strokeWidth: "2",
14890
- strokeLinecap: "round",
14891
- strokeLinejoin: "round",
14892
- children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
14893
- }
14894
- )
14895
- }
14896
- )
14897
- ] }),
14898
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl font-semibold", children: ":" }),
14899
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
14900
- /* @__PURE__ */ jsxRuntime.jsx(
14901
- Button,
14902
- {
14903
- variant: "ghost",
14904
- size: "icon",
14905
- className: "h-8 w-8",
14906
- onClick: incrementMinute,
14907
- type: "button",
14908
- children: /* @__PURE__ */ jsxRuntime.jsx(
14909
- "svg",
14910
- {
14911
- xmlns: "http://www.w3.org/2000/svg",
14912
- width: "16",
14913
- height: "16",
14914
- viewBox: "0 0 24 24",
14915
- fill: "none",
14916
- stroke: "currentColor",
14917
- strokeWidth: "2",
14918
- strokeLinecap: "round",
14919
- strokeLinejoin: "round",
14920
- children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" })
14921
- }
14922
- )
14923
- }
14924
- ),
14925
- /* @__PURE__ */ jsxRuntime.jsx(
14926
- Input,
14927
- {
14928
- type: "text",
14929
- inputMode: "numeric",
14930
- value: minutes,
14931
- onChange: (e) => handleMinuteChange(e.target.value),
14932
- className: "w-16 text-center",
14933
- maxLength: 2
14934
- }
14935
- ),
14936
- /* @__PURE__ */ jsxRuntime.jsx(
14937
- Button,
14938
- {
14939
- variant: "ghost",
14940
- size: "icon",
14941
- className: "h-8 w-8",
14942
- onClick: decrementMinute,
14943
- type: "button",
14944
- children: /* @__PURE__ */ jsxRuntime.jsx(
14945
- "svg",
14946
- {
14947
- xmlns: "http://www.w3.org/2000/svg",
14948
- width: "16",
14949
- height: "16",
14950
- viewBox: "0 0 24 24",
14951
- fill: "none",
14952
- stroke: "currentColor",
14953
- strokeWidth: "2",
14954
- strokeLinecap: "round",
14955
- strokeLinejoin: "round",
14956
- children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
14957
- }
14958
- )
14959
- }
14960
- )
14961
- ] }),
14962
- !use24Hour && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
14963
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-16 bg-border mx-1" }),
14993
+ /* @__PURE__ */ jsxRuntime.jsx(
14994
+ Input,
14995
+ {
14996
+ ref,
14997
+ type: "text",
14998
+ inputMode: "numeric",
14999
+ value: hours,
15000
+ onChange: (e) => handleHourChange(e.target.value),
15001
+ className: "w-16 text-center",
15002
+ maxLength: 2
15003
+ }
15004
+ ),
15005
+ /* @__PURE__ */ jsxRuntime.jsx(
15006
+ Button,
15007
+ {
15008
+ variant: "ghost",
15009
+ size: "icon",
15010
+ className: "h-8 w-8",
15011
+ onClick: decrementHour,
15012
+ type: "button",
15013
+ children: /* @__PURE__ */ jsxRuntime.jsx(
15014
+ "svg",
15015
+ {
15016
+ xmlns: "http://www.w3.org/2000/svg",
15017
+ width: "16",
15018
+ height: "16",
15019
+ viewBox: "0 0 24 24",
15020
+ fill: "none",
15021
+ stroke: "currentColor",
15022
+ strokeWidth: "2",
15023
+ strokeLinecap: "round",
15024
+ strokeLinejoin: "round",
15025
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
15026
+ }
15027
+ )
15028
+ }
15029
+ )
15030
+ ] }),
15031
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl font-semibold", children: ":" }),
14964
15032
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
14965
15033
  /* @__PURE__ */ jsxRuntime.jsx(
14966
15034
  Button,
14967
15035
  {
14968
- variant: period === "AM" ? "default" : "outline",
14969
- size: "sm",
14970
- className: "w-14 h-12",
14971
- onClick: handlePeriodToggle,
15036
+ variant: "ghost",
15037
+ size: "icon",
15038
+ className: "h-8 w-8",
15039
+ onClick: incrementMinute,
14972
15040
  type: "button",
14973
- children: "AM"
15041
+ children: /* @__PURE__ */ jsxRuntime.jsx(
15042
+ "svg",
15043
+ {
15044
+ xmlns: "http://www.w3.org/2000/svg",
15045
+ width: "16",
15046
+ height: "16",
15047
+ viewBox: "0 0 24 24",
15048
+ fill: "none",
15049
+ stroke: "currentColor",
15050
+ strokeWidth: "2",
15051
+ strokeLinecap: "round",
15052
+ strokeLinejoin: "round",
15053
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" })
15054
+ }
15055
+ )
15056
+ }
15057
+ ),
15058
+ /* @__PURE__ */ jsxRuntime.jsx(
15059
+ Input,
15060
+ {
15061
+ type: "text",
15062
+ inputMode: "numeric",
15063
+ value: minutes,
15064
+ onChange: (e) => handleMinuteChange(e.target.value),
15065
+ className: "w-16 text-center",
15066
+ maxLength: 2
14974
15067
  }
14975
15068
  ),
14976
15069
  /* @__PURE__ */ jsxRuntime.jsx(
14977
15070
  Button,
14978
15071
  {
14979
- variant: period === "PM" ? "default" : "outline",
14980
- size: "sm",
14981
- className: "w-14 h-12",
14982
- onClick: handlePeriodToggle,
15072
+ variant: "ghost",
15073
+ size: "icon",
15074
+ className: "h-8 w-8",
15075
+ onClick: decrementMinute,
14983
15076
  type: "button",
14984
- children: "PM"
15077
+ children: /* @__PURE__ */ jsxRuntime.jsx(
15078
+ "svg",
15079
+ {
15080
+ xmlns: "http://www.w3.org/2000/svg",
15081
+ width: "16",
15082
+ height: "16",
15083
+ viewBox: "0 0 24 24",
15084
+ fill: "none",
15085
+ stroke: "currentColor",
15086
+ strokeWidth: "2",
15087
+ strokeLinecap: "round",
15088
+ strokeLinejoin: "round",
15089
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
15090
+ }
15091
+ )
14985
15092
  }
14986
15093
  )
15094
+ ] }),
15095
+ !use24Hour && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15096
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-16 bg-border mx-1" }),
15097
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1", children: [
15098
+ /* @__PURE__ */ jsxRuntime.jsx(
15099
+ Button,
15100
+ {
15101
+ variant: period === "AM" ? "default" : "outline",
15102
+ size: "sm",
15103
+ className: "w-14 h-12",
15104
+ onClick: handlePeriodToggle,
15105
+ type: "button",
15106
+ children: "AM"
15107
+ }
15108
+ ),
15109
+ /* @__PURE__ */ jsxRuntime.jsx(
15110
+ Button,
15111
+ {
15112
+ variant: period === "PM" ? "default" : "outline",
15113
+ size: "sm",
15114
+ className: "w-14 h-12",
15115
+ onClick: handlePeriodToggle,
15116
+ type: "button",
15117
+ children: "PM"
15118
+ }
15119
+ )
15120
+ ] })
14987
15121
  ] })
14988
- ] })
14989
- ] }) })
15122
+ ] }) })
15123
+ ] }),
15124
+ showClear && /* @__PURE__ */ jsxRuntime.jsx(
15125
+ ClearButton,
15126
+ {
15127
+ onClick: handleClear,
15128
+ ariaLabel: clearAriaLabel,
15129
+ className: "absolute right-2 top-1/2 -translate-y-1/2"
15130
+ }
15131
+ )
14990
15132
  ] });
14991
15133
  }
14992
15134
  );
@@ -16173,7 +16315,7 @@ var useFieldNames = ({
16173
16315
  };
16174
16316
  var useFieldNames_default = useFieldNames;
16175
16317
  var ROW_HEIGHT = 32;
16176
- var MIN_HEIGHT_EMPTY = 76;
16318
+ var MIN_HEIGHT_EMPTY = 68;
16177
16319
  var VirtualizedCommand = ({
16178
16320
  name,
16179
16321
  height = 292,
@@ -16305,7 +16447,7 @@ var VirtualizedCommand = ({
16305
16447
  onMouseMove: () => setIsKeyboardNavActive(false),
16306
16448
  children: [
16307
16449
  /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { "data-testid": `command-item-empty-${name}`, children: internalOptions.length === 0 ? emptyContent : notFoundContent }),
16308
- /* @__PURE__ */ jsxRuntime.jsx(
16450
+ filteredOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
16309
16451
  CommandGroup,
16310
16452
  {
16311
16453
  style: {
@@ -16409,7 +16551,7 @@ var NonVirtualizedCommand = ({
16409
16551
  },
16410
16552
  children: [
16411
16553
  /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { "data-testid": `command-item-empty-${name}`, children: internalOptions.length === 0 ? emptyContent : notFoundContent }),
16412
- /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: filteredOptions.map((option, index) => {
16554
+ filteredOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(CommandGroup, { children: filteredOptions.map((option, index) => {
16413
16555
  const optionLabel = getLabelField(option);
16414
16556
  const optionValue = getValueField(option);
16415
16557
  const labelRendered = labelRender ? labelRender(option) : optionLabel;
@@ -16472,6 +16614,8 @@ var ComboboxInner = ({
16472
16614
  virtual = true,
16473
16615
  isLoading,
16474
16616
  loadingContent,
16617
+ popoverProps,
16618
+ popoverContentProps,
16475
16619
  ...props
16476
16620
  }, ref) => {
16477
16621
  const { getLabelField, getValueField } = useFieldNames_default({ fieldNames });
@@ -16543,7 +16687,7 @@ var ComboboxInner = ({
16543
16687
  },
16544
16688
  [currentSelectedOption, onClear, selectedValue, setSelectedValue]
16545
16689
  );
16546
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: openPopover, onOpenChange: handleOpenPopover, children: [
16690
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: openPopover, onOpenChange: handleOpenPopover, ...popoverProps, children: [
16547
16691
  /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
16548
16692
  "button",
16549
16693
  {
@@ -16598,9 +16742,17 @@ var ComboboxInner = ({
16598
16742
  /* @__PURE__ */ jsxRuntime.jsx(
16599
16743
  PopoverContent,
16600
16744
  {
16601
- className: "p-0 w-(--radix-popper-anchor-width) min-w-(--radix-popper-anchor-width) max-w-(--radix-popper-available-width) rounded-md",
16602
16745
  align: "start",
16603
16746
  sideOffset: 4,
16747
+ ...popoverContentProps,
16748
+ onWheel: (e) => {
16749
+ e.stopPropagation();
16750
+ popoverContentProps?.onWheel?.(e);
16751
+ },
16752
+ className: cn(
16753
+ "p-0 w-(--radix-popper-anchor-width) min-w-(--radix-popper-anchor-width) max-w-(--radix-popper-available-width) rounded-md",
16754
+ popoverContentProps?.className
16755
+ ),
16604
16756
  children: virtual ? /* @__PURE__ */ jsxRuntime.jsx(
16605
16757
  VirtualizedCommand_default,
16606
16758
  {
@@ -17166,6 +17318,65 @@ function MentionsPlugin2({
17166
17318
  });
17167
17319
  });
17168
17320
  }, [editor, mentions, mentionKeyMap, mentionConfig]);
17321
+ React.useEffect(() => {
17322
+ if (mentions.length === 0) return;
17323
+ return editor.registerCommand(
17324
+ lexical.PASTE_COMMAND,
17325
+ (event) => {
17326
+ const clipboardData = event.clipboardData;
17327
+ if (!clipboardData) return false;
17328
+ const pastedText = clipboardData.getData("text/plain");
17329
+ if (!pastedText) return false;
17330
+ const variableMatches = [...pastedText.matchAll(COMPLETE_VARIABLE_REGEX2)];
17331
+ const hasKnownVariable = variableMatches.some((match) => {
17332
+ const variableName = match[1];
17333
+ const fullMatch = match[0];
17334
+ return mentionKeyMap.has(variableName.toUpperCase()) || mentionKeyMap.has(fullMatch.toUpperCase());
17335
+ });
17336
+ if (!hasKnownVariable) return false;
17337
+ event.preventDefault();
17338
+ editor.update(
17339
+ () => {
17340
+ const selection = lexical.$getSelection();
17341
+ if (!lexical.$isRangeSelection(selection)) return;
17342
+ let lastIndex = 0;
17343
+ const nodesToInsert = [];
17344
+ for (const match of variableMatches) {
17345
+ const fullMatch = match[0];
17346
+ const variableName = match[1];
17347
+ const matchIndex = match.index;
17348
+ if (matchIndex > lastIndex) {
17349
+ const textBefore = pastedText.slice(lastIndex, matchIndex);
17350
+ nodesToInsert.push(lexical.$createTextNode(textBefore));
17351
+ }
17352
+ const mentionItem = mentionKeyMap.get(variableName.toUpperCase()) || mentionKeyMap.get(fullMatch.toUpperCase());
17353
+ if (mentionItem) {
17354
+ nodesToInsert.push(
17355
+ $createMentionNode2(
17356
+ mentionConfig.getName(mentionItem),
17357
+ mentionConfig.getLabel(mentionItem)
17358
+ )
17359
+ );
17360
+ nodesToInsert.push(lexical.$createTextNode(" "));
17361
+ } else {
17362
+ nodesToInsert.push(lexical.$createTextNode(fullMatch));
17363
+ }
17364
+ lastIndex = matchIndex + fullMatch.length;
17365
+ }
17366
+ if (lastIndex < pastedText.length) {
17367
+ nodesToInsert.push(lexical.$createTextNode(pastedText.slice(lastIndex)));
17368
+ }
17369
+ for (const node of nodesToInsert) {
17370
+ selection.insertNodes([node]);
17371
+ }
17372
+ },
17373
+ { tag: "paste-mention-conversion" }
17374
+ );
17375
+ return true;
17376
+ },
17377
+ lexical.COMMAND_PRIORITY_LOW
17378
+ );
17379
+ }, [editor, mentions, mentionKeyMap, mentionConfig]);
17169
17380
  const options = React.useMemo(() => {
17170
17381
  if (!queryString) {
17171
17382
  return mentions.map(
@@ -17309,6 +17520,41 @@ function OnChangePluginFiltered2({
17309
17520
  }, [editor, onChange, ignoreSelectionChange]);
17310
17521
  return null;
17311
17522
  }
17523
+ function MaxLengthPlugin2({ maxLength }) {
17524
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
17525
+ React.useEffect(() => {
17526
+ if (!maxLength) return;
17527
+ let lastRestoredTextLength = 0;
17528
+ return editor.registerNodeTransform(lexical.RootNode, (rootNode) => {
17529
+ const selection$1 = lexical.$getSelection();
17530
+ if (!lexical.$isRangeSelection(selection$1) || !selection$1.isCollapsed()) {
17531
+ return;
17532
+ }
17533
+ const prevTextLength = lastRestoredTextLength;
17534
+ const textLength = rootNode.getTextContentSize();
17535
+ if (prevTextLength !== textLength) {
17536
+ const delCount = textLength - maxLength;
17537
+ const anchor = selection$1.anchor;
17538
+ if (delCount > 0) {
17539
+ if (prevTextLength === maxLength && lastRestoredTextLength !== maxLength) {
17540
+ lastRestoredTextLength = maxLength;
17541
+ $restoreTextContent2(anchor);
17542
+ } else {
17543
+ selection.trimTextContentFromAnchor(editor, anchor, delCount);
17544
+ }
17545
+ }
17546
+ }
17547
+ });
17548
+ }, [editor, maxLength]);
17549
+ return null;
17550
+ }
17551
+ function $restoreTextContent2(anchor) {
17552
+ const selection = lexical.$getSelection();
17553
+ if (lexical.$isRangeSelection(selection)) {
17554
+ selection.anchor.set(anchor.key, anchor.offset, "text");
17555
+ selection.focus.set(anchor.key, anchor.offset, "text");
17556
+ }
17557
+ }
17312
17558
  var theme2 = {
17313
17559
  paragraph: "leading-6 text-sm text-foreground",
17314
17560
  placeholder: "pointer-events-none absolute left-0 top-0 px-3 py-2 text-sm text-muted-foreground select-none"
@@ -17322,6 +17568,7 @@ function InputMentionInner({
17322
17568
  disabled,
17323
17569
  editorClassName,
17324
17570
  autoFocus,
17571
+ maxLength,
17325
17572
  mentions,
17326
17573
  mentionConfig,
17327
17574
  mentionTrigger,
@@ -17418,7 +17665,8 @@ function InputMentionInner({
17418
17665
  mentionConfig: finalMentionConfig
17419
17666
  }
17420
17667
  ),
17421
- /* @__PURE__ */ jsxRuntime.jsx(OnChangePluginFiltered2, { onChange: handleChange, ignoreSelectionChange: true })
17668
+ /* @__PURE__ */ jsxRuntime.jsx(OnChangePluginFiltered2, { onChange: handleChange, ignoreSelectionChange: true }),
17669
+ maxLength && /* @__PURE__ */ jsxRuntime.jsx(MaxLengthPlugin2, { maxLength })
17422
17670
  ]
17423
17671
  }
17424
17672
  ) });