@rovula/ui 0.1.42 → 0.1.44

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.
@@ -61,13 +61,15 @@ export type AutoCompleteProps<T extends AutoCompleteOption = AutoCompleteOption>
61
61
  listboxClassName?: string;
62
62
  /** Extra inline styles applied to the options list container */
63
63
  listboxStyle?: React.CSSProperties;
64
+ /** Extra inline styles applied to the Popover content wrapper (portal mode only) */
65
+ popoverStyle?: React.CSSProperties;
64
66
  /** Extra className applied to each option item */
65
67
  optionClassName?: string;
66
68
  /** Extra inline styles applied to each option item */
67
69
  optionStyle?: React.CSSProperties;
68
70
  "data-testid"?: string;
69
71
  } & Omit<InputProps, OmittedInputProps>;
70
- declare function AutoCompleteInner<T extends AutoCompleteOption = AutoCompleteOption>({ options, value, onChange, onSelect, onBlur, onSearch, loading, noOptionsText, showNoOptions, renderOption, filterOptions, portal, listboxClassName, listboxStyle, optionClassName, optionStyle, "data-testid": testId, id, label, fullwidth, size, rounded, variant, disabled, ...rest }: AutoCompleteProps<T>, ref: React.ForwardedRef<HTMLInputElement>): import("react/jsx-runtime").JSX.Element;
72
+ declare function AutoCompleteInner<T extends AutoCompleteOption = AutoCompleteOption>({ options, value, onChange, onSelect, onBlur, onSearch, loading, noOptionsText, showNoOptions, renderOption, filterOptions, portal, listboxClassName, listboxStyle, popoverStyle, optionClassName, optionStyle, "data-testid": testId, id, label, fullwidth, size, rounded, variant, disabled, ...rest }: AutoCompleteProps<T>, ref: React.ForwardedRef<HTMLInputElement>): import("react/jsx-runtime").JSX.Element;
71
73
  declare const AutoComplete: <T extends AutoCompleteOption = AutoCompleteOption>(props: AutoCompleteProps<T> & {
72
74
  ref?: React.ForwardedRef<HTMLInputElement>;
73
75
  }) => ReturnType<typeof AutoCompleteInner>;
@@ -5,7 +5,7 @@ declare const meta: {
5
5
  title: string;
6
6
  component: <T extends AutoCompleteOption = AutoCompleteOption>(props: import("./AutoComplete").AutoCompleteProps<T> & {
7
7
  ref?: React.ForwardedRef<HTMLInputElement>;
8
- }) => ReturnType<(<T_1 extends AutoCompleteOption = AutoCompleteOption>({ options, value, onChange, onSelect, onBlur, onSearch, loading, noOptionsText, showNoOptions, renderOption, filterOptions, portal, listboxClassName, listboxStyle, optionClassName, optionStyle, "data-testid": testId, id, label, fullwidth, size, rounded, variant, disabled, ...rest }: import("./AutoComplete").AutoCompleteProps<T_1>, ref: React.ForwardedRef<HTMLInputElement>) => import("react/jsx-runtime").JSX.Element)>;
8
+ }) => ReturnType<(<T_1 extends AutoCompleteOption = AutoCompleteOption>({ options, value, onChange, onSelect, onBlur, onSearch, loading, noOptionsText, showNoOptions, renderOption, filterOptions, portal, listboxClassName, listboxStyle, popoverStyle, optionClassName, optionStyle, "data-testid": testId, id, label, fullwidth, size, rounded, variant, disabled, ...rest }: import("./AutoComplete").AutoCompleteProps<T_1>, ref: React.ForwardedRef<HTMLInputElement>) => import("react/jsx-runtime").JSX.Element)>;
9
9
  tags: string[];
10
10
  parameters: {
11
11
  layout: string;
@@ -25,6 +25,7 @@ declare const meta: {
25
25
  portal?: boolean | undefined;
26
26
  listboxClassName?: string | undefined;
27
27
  listboxStyle?: React.CSSProperties | undefined;
28
+ popoverStyle?: React.CSSProperties | undefined;
28
29
  optionClassName?: string | undefined;
29
30
  optionStyle?: React.CSSProperties | undefined;
30
31
  "data-testid"?: string | undefined;
@@ -26,9 +26,9 @@ function AutoCompleteInner(_a, ref) {
26
26
  var _b;
27
27
  var {
28
28
  // AutoComplete-specific props
29
- options, value = "", onChange, onSelect, onBlur, onSearch, loading = false, noOptionsText = "No results", showNoOptions = false, renderOption, filterOptions = (x) => x, portal = true, listboxClassName, listboxStyle, optionClassName, optionStyle, "data-testid": testId,
29
+ options, value = "", onChange, onSelect, onBlur, onSearch, loading = false, noOptionsText = "No results", showNoOptions = false, renderOption, filterOptions = (x) => x, portal = true, listboxClassName, listboxStyle, popoverStyle, optionClassName, optionStyle, "data-testid": testId,
30
30
  // InputProps with explicit defaults (rest passes everything else through)
31
- id, label, fullwidth = true, size = "md", rounded = "normal", variant = "outline", disabled } = _a, rest = __rest(_a, ["options", "value", "onChange", "onSelect", "onBlur", "onSearch", "loading", "noOptionsText", "showNoOptions", "renderOption", "filterOptions", "portal", "listboxClassName", "listboxStyle", "optionClassName", "optionStyle", "data-testid", "id", "label", "fullwidth", "size", "rounded", "variant", "disabled"]);
31
+ id, label, fullwidth = true, size = "md", rounded = "normal", variant = "outline", disabled } = _a, rest = __rest(_a, ["options", "value", "onChange", "onSelect", "onBlur", "onSearch", "loading", "noOptionsText", "showNoOptions", "renderOption", "filterOptions", "portal", "listboxClassName", "listboxStyle", "popoverStyle", "optionClassName", "optionStyle", "data-testid", "id", "label", "fullwidth", "size", "rounded", "variant", "disabled"]);
32
32
  const [open, setOpen] = useState(false);
33
33
  const [activeIndex, setActiveIndex] = useState(-1);
34
34
  const inputRef = useRef(null);
@@ -85,7 +85,7 @@ function AutoCompleteInner(_a, ref) {
85
85
  setActiveIndex(-1);
86
86
  }
87
87
  }, [open, activeIndex, filteredOptions, commitSelection]);
88
- const listContent = (_jsx("div", { role: "listbox", style: Object.assign({ boxShadow: "var(--dropdown-menu-shadow)" }, listboxStyle), className: cn("rounded-md border border-bg-stroke3 overflow-hidden", "bg-modal-dropdown-surface text-text-g-contrast-high", !portal && "absolute top-full left-0 w-full -mt-3 z-[51]", portal && "z-[51]", listboxClassName), "data-testid": testId ? `${testId}-listbox` : undefined, children: loading ? (_jsx("div", { className: "flex items-center justify-center py-6", children: _jsx(Loading, { size: 20 }) })) : filteredOptions.length === 0 ? (_jsx("div", { className: "px-4 py-6 text-center", children: _jsx(Text, { variant: "small1", className: "text-[var(--dropdown-menu-default-text)]", children: noOptionsText }) })) : (filteredOptions.map((option, index) => {
88
+ const listContent = (_jsx("div", { role: "listbox", style: Object.assign({ boxShadow: "var(--dropdown-menu-shadow)" }, listboxStyle), className: cn("max-h-60 overflow-y-auto", "rounded-md border border-bg-stroke3", "bg-modal-dropdown-surface text-text-g-contrast-high", !portal && "absolute top-full left-0 w-full -mt-3 z-[51]", portal && "z-[51]", listboxClassName), "data-testid": testId ? `${testId}-listbox` : undefined, children: loading ? (_jsx("div", { className: "flex items-center justify-center py-6", children: _jsx(Loading, { size: 20 }) })) : filteredOptions.length === 0 ? (_jsx("div", { className: "px-4 py-6 text-center", children: _jsx(Text, { variant: "small1", className: "text-[var(--dropdown-menu-default-text)]", children: noOptionsText }) })) : (filteredOptions.map((option, index) => {
89
89
  const isSelected = option.value === value;
90
90
  const isActive = index === activeIndex;
91
91
  return (_jsxs("button", { id: `autocomplete-option-${option.value}`, type: "button", role: "option", "aria-selected": isSelected, style: optionStyle, className: cn(menuItemBaseStyles, "w-full", isSelected &&
@@ -95,7 +95,7 @@ function AutoCompleteInner(_a, ref) {
95
95
  })) }));
96
96
  return (_jsxs(PopoverPrimitive.Root, { open: showPopover, children: [_jsx(PopoverPrimitive.Anchor, { asChild: true, children: _jsxs("div", { className: cn("relative", fullwidth && "w-full"), children: [_jsx(TextInput, Object.assign({}, rest, { ref: ref !== null && ref !== void 0 ? ref : inputRef, id: id, label: label, value: value, size: size, rounded: rounded, variant: variant, disabled: disabled, fullwidth: fullwidth, autoComplete: "off", role: "combobox", "aria-expanded": showPopover, "aria-autocomplete": "list", "aria-activedescendant": activeIndex >= 0
97
97
  ? `autocomplete-option-${(_b = filteredOptions[activeIndex]) === null || _b === void 0 ? void 0 : _b.value}`
98
- : undefined, hasClearIcon: true, onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, "data-testid": testId })), showPopover && !portal && listContent] }) }), portal && (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: (e) => e.preventDefault(), onFocusOutside: (e) => e.preventDefault(), side: "bottom", align: "start", sideOffset: -12, style: { width: "var(--radix-popover-trigger-width)" }, children: listContent }) }))] }));
98
+ : undefined, hasClearIcon: true, onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, "data-testid": testId })), showPopover && !portal && listContent] }) }), portal && (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: (e) => e.preventDefault(), onFocusOutside: (e) => e.preventDefault(), side: "bottom", align: "start", sideOffset: -12, style: Object.assign({ width: "var(--radix-popover-trigger-width)", zIndex: 51 }, popoverStyle), children: listContent }) }))] }));
99
99
  }
100
100
  // forwardRef with generics requires a manual cast
101
101
  const AutoComplete = forwardRef(AutoCompleteInner);
@@ -1,6 +1,6 @@
1
1
  import { cva } from "class-variance-authority";
2
2
  export const badgeVariants = cva([
3
- "inline-flex items-center justify-center rounded-lg px-3 py-1",
3
+ "inline-flex items-center justify-center rounded-[6px] px-3 py-1",
4
4
  "typography-body3",
5
5
  ], {
6
6
  variants: {
@@ -44,7 +44,7 @@ export const badgeVariants = cva([
44
44
  },
45
45
  });
46
46
  export const severityBadgeVariants = cva([
47
- "inline-flex items-center justify-center rounded px-1 py-0.5",
47
+ "inline-flex items-center justify-center rounded-[4px] px-1 py-0.5",
48
48
  "typography-small6 text-[var(--badge-severity-text)]",
49
49
  ], {
50
50
  variants: {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useCallback, useEffect, useMemo, useState } from "react";
2
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
3
  import TextInput from "@/components/TextInput/TextInput";
4
4
  import NumberInput from "@/components/NumberInput";
5
5
  import { Checkbox } from "@/components/Checkbox/Checkbox";
@@ -295,6 +295,22 @@ function EditCellText({ columnId, row, placeholder, autoFocus, errorMessage, onB
295
295
  }
296
296
  function EditCellSelect({ row, columnId, col, autoFocus, onCommit, onBlurField, onKeyDown, keepOpenAfterSelect, errorMessage, }) {
297
297
  var _a, _b, _c, _d, _e;
298
+ const selectRef = useRef(null);
299
+ // Cell mode: React's `autoFocus` fires el.focus() during the commit phase,
300
+ // which causes Headless UI's flushSync-inside-microTask to run while React
301
+ // is still committing → silent failure in concurrent mode. Delay focus to a
302
+ // rAF (same approach as row-mode Tab navigation) so it fires safely after
303
+ // the commit. Cancel on cleanup so StrictMode's double-mount is safe.
304
+ useEffect(() => {
305
+ if (!autoFocus)
306
+ return;
307
+ const el = selectRef.current;
308
+ if (!el)
309
+ return;
310
+ const rafId = requestAnimationFrame(() => el.focus());
311
+ return () => cancelAnimationFrame(rafId);
312
+ // eslint-disable-next-line react-hooks/exhaustive-deps
313
+ }, []);
298
314
  const displayValue = String((_a = row.original[columnId]) !== null && _a !== void 0 ? _a : "");
299
315
  const rawOptions = typeof ((_b = col.editSelectProps) === null || _b === void 0 ? void 0 : _b.options) === "function"
300
316
  ? col.editSelectProps.options(row)
@@ -311,11 +327,11 @@ function EditCellSelect({ row, columnId, col, autoFocus, onCommit, onBlurField,
311
327
  return options[0];
312
328
  return (_a = options.find((o) => o.label === cur)) !== null && _a !== void 0 ? _a : options[0];
313
329
  }, [displayValue, options]);
314
- return (_jsx("div", { children: _jsx(Dropdown, { id: `edit-dd-${columnId}-${row.id}`, options: options, value: selected, onSelect: (opt) => {
330
+ return (_jsx("div", { children: _jsx(Dropdown, { id: `edit-dd-${columnId}-${row.id}`, ref: selectRef, options: options, value: selected, onSelect: (opt) => {
315
331
  if (isPlaceholderOption(opt))
316
332
  return;
317
333
  onCommit(opt.label);
318
- }, size: "sm", variant: "outline", rounded: "normal", fullwidth: true, required: false, isFloatingLabel: false, label: "", keepFooterSpace: false, segmentedInput: true, autoFocus: autoFocus, onBlur: onBlurField, onKeyDown: onKeyDown, keepOpenAfterSelect: keepOpenAfterSelect, portal: true, error: !!errorMessage, errorMessage: errorMessage, className: cn("rounded-md", customInputVariant({ size: "sm" }), displayValue.trim().length > 0 && "font-medium") }) }));
334
+ }, size: "sm", variant: "outline", rounded: "normal", fullwidth: true, required: false, isFloatingLabel: false, label: "", keepFooterSpace: false, segmentedInput: true, autoFocus: false, onBlur: onBlurField, onKeyDown: onKeyDown, keepOpenAfterSelect: keepOpenAfterSelect, portal: true, error: !!errorMessage, errorMessage: errorMessage, className: cn("rounded-md", customInputVariant({ size: "sm" }), displayValue.trim().length > 0 && "font-medium") }) }));
319
335
  }
320
336
  // ---------------------------------------------------------------------------
321
337
  // EditCellNumber — inline number editor
@@ -84,7 +84,10 @@ const Dropdown = forwardRef((_a, ref) => {
84
84
  });
85
85
  };
86
86
  return (_jsx(Combobox, { value: selectedOption, onChange: handleSelect, immediate: true, by: "value", disabled: disabled, children: ({ open }) => (_jsxs("div", { className: cn("relative", fullwidth && "w-full"), children: [_jsx(ComboboxInput, Object.assign({ as: TextInput, ref: inputRef, hasClearIcon: false, endIcon: _jsx(ChevronDownIcon, { className: dropdownIconVariant({ isFocus: open }) }), label: label, autoComplete: "off", rounded: rounded, variant: variant, helperText: helperText, errorMessage: errorMessage, fullwidth: fullwidth, error: error, required: required, id: _id, disabled: disabled, size: size, className: segmentedInput ? customInputVariant({ size }) : undefined, displayValue: (opt) => { var _a; return (_a = opt === null || opt === void 0 ? void 0 : opt.label) !== null && _a !== void 0 ? _a : ""; }, readOnly: !filterMode, onChange: handleInputChange }, props)), _jsx(ComboboxOptions, Object.assign({}, (portal
87
- ? { portal: true, anchor: { to: "bottom start", gap: 4 } }
87
+ ? {
88
+ portal: true,
89
+ anchor: { to: "bottom start", gap: 4 },
90
+ }
88
91
  : {}), { className: cn(!portal && "absolute top-full left-0 w-full -mt-3 z-[51]", portal && "z-[51] !max-h-60 w-[var(--input-width)]", "min-w-[154px] max-h-60 overflow-y-auto", "rounded-md bg-modal-dropdown-surface border border-bg-stroke3 text-text-g-contrast-high", optionContainerClassName), style: { boxShadow: "var(--dropdown-menu-shadow)" }, children: renderOptionList() }))] })) }));
89
92
  });
90
93
  Dropdown.displayName = "Dropdown";
@@ -1629,6 +1629,12 @@ input[type=number] {
1629
1629
  .rounded-\[2px\]{
1630
1630
  border-radius: 2px;
1631
1631
  }
1632
+ .rounded-\[4px\]{
1633
+ border-radius: 4px;
1634
+ }
1635
+ .rounded-\[6px\]{
1636
+ border-radius: 6px;
1637
+ }
1632
1638
  .rounded-\[8px\]{
1633
1639
  border-radius: 8px;
1634
1640
  }