@dragunio/fe-libs 0.1.11 → 0.1.12

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.d.mts CHANGED
@@ -411,7 +411,21 @@ type SelectionProps = Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'default
411
411
  disabled?: boolean;
412
412
  name?: string;
413
413
  onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
414
+ /**
415
+ * Caps the field width. Numbers are pixels (`240` → `240px`); strings are
416
+ * any CSS length (`'16rem'`, `'50%'`). The field still shrinks inside
417
+ * narrower containers.
418
+ */
419
+ maxWidth?: number | string;
420
+ /**
421
+ * How a selected label longer than the field is shown:
422
+ * - `'ellipsis'` (default): one line ending in `…`; the full text appears
423
+ * in a tooltip on hover or focus.
424
+ * - `'wrap'`: the label wraps onto more lines and the field grows taller.
425
+ */
426
+ overflow?: SelectionOverflow;
414
427
  };
428
+ type SelectionOverflow = 'ellipsis' | 'wrap';
415
429
 
416
430
  /** A rounded, searchable custom dropdown with single, multiple, and tag modes. */
417
431
  declare const Selection: react.ForwardRefExoticComponent<Omit<react.HTMLAttributes<HTMLDivElement>, "value" | "defaultValue" | "onChange" | "onKeyDown"> & {
@@ -435,6 +449,8 @@ declare const Selection: react.ForwardRefExoticComponent<Omit<react.HTMLAttribut
435
449
  disabled?: boolean;
436
450
  name?: string;
437
451
  onKeyDown?: react.KeyboardEventHandler<HTMLButtonElement>;
452
+ maxWidth?: number | string;
453
+ overflow?: SelectionOverflow;
438
454
  } & react.RefAttributes<HTMLDivElement>>;
439
455
 
440
456
  declare function formatNumber(value: number, decimals?: number, thousandSeparator?: string, decimalSeparator?: string): string;
@@ -1001,4 +1017,4 @@ declare function NotFoundLost(props: NotFoundSceneProps): react.JSX.Element;
1001
1017
  /** A 404 page with a stable random design, or an explicitly selected variant. */
1002
1018
  declare function NotFound({ variant, ...props }: NotFoundProps): react.JSX.Element;
1003
1019
 
1004
- export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarShape, type AvatarSize, Button, ButtonBar, type ButtonBarAction, type ButtonBarItem, type ButtonBarProps, type ButtonColor, type ButtonHierarchy, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipStatus, type ChipVariant, type ColumnResizeHandler, type ControlLabelPosition, type Currency, CurrencyInput, type CurrencyInputProps, type DateRange, DateTimePicker, type DateTimePickerProps, type DateTimePickerRangeProps, type DateTimePickerSingleProps, type DescriptionDisplay, Drawer, type DrawerProps, type DrawerSide, type DrawerWidth, type DrawerWidthPreset, DrawerWidths, EmailInput, type EmailInputProps, ExpandableSection, type ExpandableSectionProps, FILE_UPLOAD_ACCEPTS, type FieldError, FilePreview, type FilePreviewActionHandler, type FilePreviewCloseReason, type FilePreviewKind, type FilePreviewProps, FileUpload, type FileUploadAccept, type FileUploadFileType, type FileUploadProps, type FileUploadRejection, type FileUploadRejectionCode, type InputValidator, Loading, type LoadingProps, type LoadingSize, Message, type MessageOptions, type MessageProps, type MessageSeverity, Modal, type ModalAction, type ModalProps, type ModalSize, NotFound, NotFoundCaveman, NotFoundLost, type NotFoundProps, type NotFoundSceneProps, type NotFoundVariant, NotFoundYeti, NumberInput, type NumberInputProps, Pagination, type PaginationProps, PasswordInput, type PasswordInputProps, PhoneNumberInput, type PhoneNumberInputProps, ProgressBar, type ProgressBarProps, type ProgressBarSize, RadioButton, type RadioButtonProps, RadioGroup, type RadioGroupOption, type RadioGroupProps, type RadioValue, Selection, type SelectionOption, type SelectionProps, type SelectionValue, Skeleton, SkeletonBox, type SkeletonBoxProps, SkeletonCircle, SkeletonLine, type SkeletonProps, type SkeletonSizeProps, SkeletonSquare, type SkeletonVariant, Snackbar, type SnackbarAnchorOrigin, type SnackbarProps, type TabChangeEvent, type TabItem, Table, TableBody, TableCaption, TableCell, type TableCellProps, type TableColumn, type TableColumnWidths, type TableData, TableHead, TableHeader, type TableHeaderProps, type TablePaginationPosition, type TableProps, type TableResizeHandler, TableRow, Tabs, type TabsProps, type TabsScrollButtons, type TabsVariant, TextArea, type TextAreaProps, TextInput, type TextInputProps, Toggle, type ToggleProps, Tooltip, type TooltipProps, type ValidatedTextInputProps, type ValidationTiming, formatFileSize, formatNumber, getFilePreviewKind, getIconSize, message, normalizePhoneNumber, validateEmail, validatePassword, validatePhoneNumber };
1020
+ export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarShape, type AvatarSize, Button, ButtonBar, type ButtonBarAction, type ButtonBarItem, type ButtonBarProps, type ButtonColor, type ButtonHierarchy, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipStatus, type ChipVariant, type ColumnResizeHandler, type ControlLabelPosition, type Currency, CurrencyInput, type CurrencyInputProps, type DateRange, DateTimePicker, type DateTimePickerProps, type DateTimePickerRangeProps, type DateTimePickerSingleProps, type DescriptionDisplay, Drawer, type DrawerProps, type DrawerSide, type DrawerWidth, type DrawerWidthPreset, DrawerWidths, EmailInput, type EmailInputProps, ExpandableSection, type ExpandableSectionProps, FILE_UPLOAD_ACCEPTS, type FieldError, FilePreview, type FilePreviewActionHandler, type FilePreviewCloseReason, type FilePreviewKind, type FilePreviewProps, FileUpload, type FileUploadAccept, type FileUploadFileType, type FileUploadProps, type FileUploadRejection, type FileUploadRejectionCode, type InputValidator, Loading, type LoadingProps, type LoadingSize, Message, type MessageOptions, type MessageProps, type MessageSeverity, Modal, type ModalAction, type ModalProps, type ModalSize, NotFound, NotFoundCaveman, NotFoundLost, type NotFoundProps, type NotFoundSceneProps, type NotFoundVariant, NotFoundYeti, NumberInput, type NumberInputProps, Pagination, type PaginationProps, PasswordInput, type PasswordInputProps, PhoneNumberInput, type PhoneNumberInputProps, ProgressBar, type ProgressBarProps, type ProgressBarSize, RadioButton, type RadioButtonProps, RadioGroup, type RadioGroupOption, type RadioGroupProps, type RadioValue, Selection, type SelectionOption, type SelectionOverflow, type SelectionProps, type SelectionValue, Skeleton, SkeletonBox, type SkeletonBoxProps, SkeletonCircle, SkeletonLine, type SkeletonProps, type SkeletonSizeProps, SkeletonSquare, type SkeletonVariant, Snackbar, type SnackbarAnchorOrigin, type SnackbarProps, type TabChangeEvent, type TabItem, Table, TableBody, TableCaption, TableCell, type TableCellProps, type TableColumn, type TableColumnWidths, type TableData, TableHead, TableHeader, type TableHeaderProps, type TablePaginationPosition, type TableProps, type TableResizeHandler, TableRow, Tabs, type TabsProps, type TabsScrollButtons, type TabsVariant, TextArea, type TextAreaProps, TextInput, type TextInputProps, Toggle, type ToggleProps, Tooltip, type TooltipProps, type ValidatedTextInputProps, type ValidationTiming, formatFileSize, formatNumber, getFilePreviewKind, getIconSize, message, normalizePhoneNumber, validateEmail, validatePassword, validatePhoneNumber };
package/dist/index.d.ts CHANGED
@@ -411,7 +411,21 @@ type SelectionProps = Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'default
411
411
  disabled?: boolean;
412
412
  name?: string;
413
413
  onKeyDown?: KeyboardEventHandler<HTMLButtonElement>;
414
+ /**
415
+ * Caps the field width. Numbers are pixels (`240` → `240px`); strings are
416
+ * any CSS length (`'16rem'`, `'50%'`). The field still shrinks inside
417
+ * narrower containers.
418
+ */
419
+ maxWidth?: number | string;
420
+ /**
421
+ * How a selected label longer than the field is shown:
422
+ * - `'ellipsis'` (default): one line ending in `…`; the full text appears
423
+ * in a tooltip on hover or focus.
424
+ * - `'wrap'`: the label wraps onto more lines and the field grows taller.
425
+ */
426
+ overflow?: SelectionOverflow;
414
427
  };
428
+ type SelectionOverflow = 'ellipsis' | 'wrap';
415
429
 
416
430
  /** A rounded, searchable custom dropdown with single, multiple, and tag modes. */
417
431
  declare const Selection: react.ForwardRefExoticComponent<Omit<react.HTMLAttributes<HTMLDivElement>, "value" | "defaultValue" | "onChange" | "onKeyDown"> & {
@@ -435,6 +449,8 @@ declare const Selection: react.ForwardRefExoticComponent<Omit<react.HTMLAttribut
435
449
  disabled?: boolean;
436
450
  name?: string;
437
451
  onKeyDown?: react.KeyboardEventHandler<HTMLButtonElement>;
452
+ maxWidth?: number | string;
453
+ overflow?: SelectionOverflow;
438
454
  } & react.RefAttributes<HTMLDivElement>>;
439
455
 
440
456
  declare function formatNumber(value: number, decimals?: number, thousandSeparator?: string, decimalSeparator?: string): string;
@@ -1001,4 +1017,4 @@ declare function NotFoundLost(props: NotFoundSceneProps): react.JSX.Element;
1001
1017
  /** A 404 page with a stable random design, or an explicitly selected variant. */
1002
1018
  declare function NotFound({ variant, ...props }: NotFoundProps): react.JSX.Element;
1003
1019
 
1004
- export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarShape, type AvatarSize, Button, ButtonBar, type ButtonBarAction, type ButtonBarItem, type ButtonBarProps, type ButtonColor, type ButtonHierarchy, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipStatus, type ChipVariant, type ColumnResizeHandler, type ControlLabelPosition, type Currency, CurrencyInput, type CurrencyInputProps, type DateRange, DateTimePicker, type DateTimePickerProps, type DateTimePickerRangeProps, type DateTimePickerSingleProps, type DescriptionDisplay, Drawer, type DrawerProps, type DrawerSide, type DrawerWidth, type DrawerWidthPreset, DrawerWidths, EmailInput, type EmailInputProps, ExpandableSection, type ExpandableSectionProps, FILE_UPLOAD_ACCEPTS, type FieldError, FilePreview, type FilePreviewActionHandler, type FilePreviewCloseReason, type FilePreviewKind, type FilePreviewProps, FileUpload, type FileUploadAccept, type FileUploadFileType, type FileUploadProps, type FileUploadRejection, type FileUploadRejectionCode, type InputValidator, Loading, type LoadingProps, type LoadingSize, Message, type MessageOptions, type MessageProps, type MessageSeverity, Modal, type ModalAction, type ModalProps, type ModalSize, NotFound, NotFoundCaveman, NotFoundLost, type NotFoundProps, type NotFoundSceneProps, type NotFoundVariant, NotFoundYeti, NumberInput, type NumberInputProps, Pagination, type PaginationProps, PasswordInput, type PasswordInputProps, PhoneNumberInput, type PhoneNumberInputProps, ProgressBar, type ProgressBarProps, type ProgressBarSize, RadioButton, type RadioButtonProps, RadioGroup, type RadioGroupOption, type RadioGroupProps, type RadioValue, Selection, type SelectionOption, type SelectionProps, type SelectionValue, Skeleton, SkeletonBox, type SkeletonBoxProps, SkeletonCircle, SkeletonLine, type SkeletonProps, type SkeletonSizeProps, SkeletonSquare, type SkeletonVariant, Snackbar, type SnackbarAnchorOrigin, type SnackbarProps, type TabChangeEvent, type TabItem, Table, TableBody, TableCaption, TableCell, type TableCellProps, type TableColumn, type TableColumnWidths, type TableData, TableHead, TableHeader, type TableHeaderProps, type TablePaginationPosition, type TableProps, type TableResizeHandler, TableRow, Tabs, type TabsProps, type TabsScrollButtons, type TabsVariant, TextArea, type TextAreaProps, TextInput, type TextInputProps, Toggle, type ToggleProps, Tooltip, type TooltipProps, type ValidatedTextInputProps, type ValidationTiming, formatFileSize, formatNumber, getFilePreviewKind, getIconSize, message, normalizePhoneNumber, validateEmail, validatePassword, validatePhoneNumber };
1020
+ export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarShape, type AvatarSize, Button, ButtonBar, type ButtonBarAction, type ButtonBarItem, type ButtonBarProps, type ButtonColor, type ButtonHierarchy, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipStatus, type ChipVariant, type ColumnResizeHandler, type ControlLabelPosition, type Currency, CurrencyInput, type CurrencyInputProps, type DateRange, DateTimePicker, type DateTimePickerProps, type DateTimePickerRangeProps, type DateTimePickerSingleProps, type DescriptionDisplay, Drawer, type DrawerProps, type DrawerSide, type DrawerWidth, type DrawerWidthPreset, DrawerWidths, EmailInput, type EmailInputProps, ExpandableSection, type ExpandableSectionProps, FILE_UPLOAD_ACCEPTS, type FieldError, FilePreview, type FilePreviewActionHandler, type FilePreviewCloseReason, type FilePreviewKind, type FilePreviewProps, FileUpload, type FileUploadAccept, type FileUploadFileType, type FileUploadProps, type FileUploadRejection, type FileUploadRejectionCode, type InputValidator, Loading, type LoadingProps, type LoadingSize, Message, type MessageOptions, type MessageProps, type MessageSeverity, Modal, type ModalAction, type ModalProps, type ModalSize, NotFound, NotFoundCaveman, NotFoundLost, type NotFoundProps, type NotFoundSceneProps, type NotFoundVariant, NotFoundYeti, NumberInput, type NumberInputProps, Pagination, type PaginationProps, PasswordInput, type PasswordInputProps, PhoneNumberInput, type PhoneNumberInputProps, ProgressBar, type ProgressBarProps, type ProgressBarSize, RadioButton, type RadioButtonProps, RadioGroup, type RadioGroupOption, type RadioGroupProps, type RadioValue, Selection, type SelectionOption, type SelectionOverflow, type SelectionProps, type SelectionValue, Skeleton, SkeletonBox, type SkeletonBoxProps, SkeletonCircle, SkeletonLine, type SkeletonProps, type SkeletonSizeProps, SkeletonSquare, type SkeletonVariant, Snackbar, type SnackbarAnchorOrigin, type SnackbarProps, type TabChangeEvent, type TabItem, Table, TableBody, TableCaption, TableCell, type TableCellProps, type TableColumn, type TableColumnWidths, type TableData, TableHead, TableHeader, type TableHeaderProps, type TablePaginationPosition, type TableProps, type TableResizeHandler, TableRow, Tabs, type TabsProps, type TabsScrollButtons, type TabsVariant, TextArea, type TextAreaProps, TextInput, type TextInputProps, Toggle, type ToggleProps, Tooltip, type TooltipProps, type ValidatedTextInputProps, type ValidationTiming, formatFileSize, formatNumber, getFilePreviewKind, getIconSize, message, normalizePhoneNumber, validateEmail, validatePassword, validatePhoneNumber };
package/dist/index.js CHANGED
@@ -2127,6 +2127,9 @@ var Selection = (0, import_react17.forwardRef)(
2127
2127
  disabled = false,
2128
2128
  name,
2129
2129
  onKeyDown,
2130
+ maxWidth,
2131
+ overflow = "ellipsis",
2132
+ style,
2130
2133
  "aria-label": ariaLabel,
2131
2134
  "aria-describedby": ariaDescribedBy,
2132
2135
  "aria-labelledby": ariaLabelledBy,
@@ -2137,6 +2140,7 @@ var Selection = (0, import_react17.forwardRef)(
2137
2140
  const listboxId = triggerId + "-listbox";
2138
2141
  const labelId = generatedId + "-label";
2139
2142
  const messageId2 = generatedId + "-message";
2143
+ const tooltipId = generatedId + "-tooltip";
2140
2144
  const fieldError = getFieldError(error, errorMessage);
2141
2145
  const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
2142
2146
  const resolvedDescription = description ?? helperText;
@@ -2163,6 +2167,26 @@ var Selection = (0, import_react17.forwardRef)(
2163
2167
  const [activeIndex, setActiveIndex] = (0, import_react17.useState)(0);
2164
2168
  const rootRef = (0, import_react17.useRef)(null);
2165
2169
  const menuRef = (0, import_react17.useRef)(null);
2170
+ const valueRef = (0, import_react17.useRef)(null);
2171
+ const [truncated, setTruncated] = (0, import_react17.useState)(false);
2172
+ const [hovered, setHovered] = (0, import_react17.useState)(false);
2173
+ const [focused, setFocused] = (0, import_react17.useState)(false);
2174
+ const showsTags = tag && multiple && selectedOptions.length > 0;
2175
+ const canTruncate = overflow === "ellipsis" && !showsTags && selectedOptions.length > 0;
2176
+ const selectedKey = selectedOptions.map((option) => String(option.value)).join("|");
2177
+ (0, import_react17.useLayoutEffect)(() => {
2178
+ const node = valueRef.current;
2179
+ if (!canTruncate || !node) {
2180
+ setTruncated(false);
2181
+ return;
2182
+ }
2183
+ const measure = () => setTruncated(node.scrollWidth > node.clientWidth + 1);
2184
+ measure();
2185
+ if (typeof ResizeObserver === "undefined") return;
2186
+ const observer = new ResizeObserver(measure);
2187
+ observer.observe(node);
2188
+ return () => observer.disconnect();
2189
+ }, [canTruncate, selectedKey]);
2166
2190
  const [menuPosition, setMenuPosition] = (0, import_react17.useState)(null);
2167
2191
  (0, import_react17.useEffect)(() => {
2168
2192
  const close = (event) => {
@@ -2227,6 +2251,12 @@ var Selection = (0, import_react17.forwardRef)(
2227
2251
  setQuery("");
2228
2252
  };
2229
2253
  const displayLabel = selectedOptions.length ? selectedOptions.map((option) => option.label) : null;
2254
+ const showTooltip = truncated && (hovered || focused) && !open;
2255
+ const renderLabels = () => displayLabel?.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
2256
+ item,
2257
+ index < displayLabel.length - 1 ? ", " : ""
2258
+ ] }, index));
2259
+ const toPx = (length) => typeof length === "number" ? length + "px" : length;
2230
2260
  const onTriggerKeyDown = (event) => {
2231
2261
  onKeyDown?.(event);
2232
2262
  if (disabled) return;
@@ -2258,12 +2288,14 @@ var Selection = (0, import_react17.forwardRef)(
2258
2288
  className: [
2259
2289
  "fe-selection",
2260
2290
  "fe-selection--" + size,
2291
+ "fe-selection--" + overflow,
2261
2292
  open && "fe-selection--open",
2262
2293
  clearable && selectedOptions.length > 0 && "fe-selection--clearable",
2263
2294
  hasError && "fe-selection--error",
2264
2295
  disabled && "fe-selection--disabled",
2265
2296
  className
2266
2297
  ].filter(Boolean).join(" "),
2298
+ style: maxWidth === void 0 ? style : { ...style, maxWidth: toPx(maxWidth) },
2267
2299
  ...props,
2268
2300
  children: [
2269
2301
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
@@ -2297,16 +2329,24 @@ var Selection = (0, import_react17.forwardRef)(
2297
2329
  "aria-invalid": hasError || void 0,
2298
2330
  "aria-required": isRequired || void 0,
2299
2331
  "aria-labelledby": labelledBy,
2300
- "aria-describedby": describedBy,
2332
+ "aria-describedby": getDescribedBy(
2333
+ describedBy,
2334
+ showTooltip ? tooltipId : void 0
2335
+ ),
2301
2336
  "aria-haspopup": "listbox",
2302
2337
  "aria-expanded": open,
2303
2338
  "aria-controls": listboxId,
2304
2339
  onClick: () => setOpen((current) => !current),
2305
2340
  onKeyDown: onTriggerKeyDown,
2341
+ onMouseEnter: () => setHovered(true),
2342
+ onMouseLeave: () => setHovered(false),
2343
+ onFocus: () => setFocused(true),
2344
+ onBlur: () => setFocused(false),
2306
2345
  children: [
2307
2346
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2308
2347
  "span",
2309
2348
  {
2349
+ ref: valueRef,
2310
2350
  className: [
2311
2351
  "fe-selection__value",
2312
2352
  !selectedOptions.length && "is-placeholder",
@@ -2322,10 +2362,7 @@ var Selection = (0, import_react17.forwardRef)(
2322
2362
  ]
2323
2363
  },
2324
2364
  String(option.value)
2325
- )) : displayLabel.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { children: [
2326
- item,
2327
- index < displayLabel.length - 1 ? ", " : ""
2328
- ] }, index)) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2365
+ )) : renderLabels() : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2329
2366
  /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: placeholder }),
2330
2367
  isRequired && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fe-field__required", "aria-hidden": "true", children: "*" })
2331
2368
  ] })
@@ -2344,6 +2381,7 @@ var Selection = (0, import_react17.forwardRef)(
2344
2381
  onClick: clear
2345
2382
  }
2346
2383
  ),
2384
+ showTooltip && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { id: tooltipId, role: "tooltip", className: "fe-selection__tooltip", children: renderLabels() }),
2347
2385
  open && menuPosition && (0, import_react_dom2.createPortal)(
2348
2386
  /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2349
2387
  "div",
@@ -2395,7 +2433,7 @@ var Selection = (0, import_react17.forwardRef)(
2395
2433
  onMouseMove: () => setActiveIndex(index),
2396
2434
  onClick: () => choose(option),
2397
2435
  children: [
2398
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: option.label }),
2436
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "fe-selection__option-label", children: option.label }),
2399
2437
  isSelected && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2400
2438
  "span",
2401
2439
  {
package/dist/index.mjs CHANGED
@@ -1821,6 +1821,9 @@ var Selection = forwardRef9(
1821
1821
  disabled = false,
1822
1822
  name,
1823
1823
  onKeyDown,
1824
+ maxWidth,
1825
+ overflow = "ellipsis",
1826
+ style,
1824
1827
  "aria-label": ariaLabel,
1825
1828
  "aria-describedby": ariaDescribedBy,
1826
1829
  "aria-labelledby": ariaLabelledBy,
@@ -1831,6 +1834,7 @@ var Selection = forwardRef9(
1831
1834
  const listboxId = triggerId + "-listbox";
1832
1835
  const labelId = generatedId + "-label";
1833
1836
  const messageId2 = generatedId + "-message";
1837
+ const tooltipId = generatedId + "-tooltip";
1834
1838
  const fieldError = getFieldError(error, errorMessage);
1835
1839
  const hasError = fieldError !== void 0 && fieldError !== false && fieldError !== null;
1836
1840
  const resolvedDescription = description ?? helperText;
@@ -1857,6 +1861,26 @@ var Selection = forwardRef9(
1857
1861
  const [activeIndex, setActiveIndex] = useState11(0);
1858
1862
  const rootRef = useRef7(null);
1859
1863
  const menuRef = useRef7(null);
1864
+ const valueRef = useRef7(null);
1865
+ const [truncated, setTruncated] = useState11(false);
1866
+ const [hovered, setHovered] = useState11(false);
1867
+ const [focused, setFocused] = useState11(false);
1868
+ const showsTags = tag && multiple && selectedOptions.length > 0;
1869
+ const canTruncate = overflow === "ellipsis" && !showsTags && selectedOptions.length > 0;
1870
+ const selectedKey = selectedOptions.map((option) => String(option.value)).join("|");
1871
+ useLayoutEffect3(() => {
1872
+ const node = valueRef.current;
1873
+ if (!canTruncate || !node) {
1874
+ setTruncated(false);
1875
+ return;
1876
+ }
1877
+ const measure = () => setTruncated(node.scrollWidth > node.clientWidth + 1);
1878
+ measure();
1879
+ if (typeof ResizeObserver === "undefined") return;
1880
+ const observer = new ResizeObserver(measure);
1881
+ observer.observe(node);
1882
+ return () => observer.disconnect();
1883
+ }, [canTruncate, selectedKey]);
1860
1884
  const [menuPosition, setMenuPosition] = useState11(null);
1861
1885
  useEffect5(() => {
1862
1886
  const close = (event) => {
@@ -1921,6 +1945,12 @@ var Selection = forwardRef9(
1921
1945
  setQuery("");
1922
1946
  };
1923
1947
  const displayLabel = selectedOptions.length ? selectedOptions.map((option) => option.label) : null;
1948
+ const showTooltip = truncated && (hovered || focused) && !open;
1949
+ const renderLabels = () => displayLabel?.map((item, index) => /* @__PURE__ */ jsxs12("span", { children: [
1950
+ item,
1951
+ index < displayLabel.length - 1 ? ", " : ""
1952
+ ] }, index));
1953
+ const toPx = (length) => typeof length === "number" ? length + "px" : length;
1924
1954
  const onTriggerKeyDown = (event) => {
1925
1955
  onKeyDown?.(event);
1926
1956
  if (disabled) return;
@@ -1952,12 +1982,14 @@ var Selection = forwardRef9(
1952
1982
  className: [
1953
1983
  "fe-selection",
1954
1984
  "fe-selection--" + size,
1985
+ "fe-selection--" + overflow,
1955
1986
  open && "fe-selection--open",
1956
1987
  clearable && selectedOptions.length > 0 && "fe-selection--clearable",
1957
1988
  hasError && "fe-selection--error",
1958
1989
  disabled && "fe-selection--disabled",
1959
1990
  className
1960
1991
  ].filter(Boolean).join(" "),
1992
+ style: maxWidth === void 0 ? style : { ...style, maxWidth: toPx(maxWidth) },
1961
1993
  ...props,
1962
1994
  children: [
1963
1995
  /* @__PURE__ */ jsx15(
@@ -1991,16 +2023,24 @@ var Selection = forwardRef9(
1991
2023
  "aria-invalid": hasError || void 0,
1992
2024
  "aria-required": isRequired || void 0,
1993
2025
  "aria-labelledby": labelledBy,
1994
- "aria-describedby": describedBy,
2026
+ "aria-describedby": getDescribedBy(
2027
+ describedBy,
2028
+ showTooltip ? tooltipId : void 0
2029
+ ),
1995
2030
  "aria-haspopup": "listbox",
1996
2031
  "aria-expanded": open,
1997
2032
  "aria-controls": listboxId,
1998
2033
  onClick: () => setOpen((current) => !current),
1999
2034
  onKeyDown: onTriggerKeyDown,
2035
+ onMouseEnter: () => setHovered(true),
2036
+ onMouseLeave: () => setHovered(false),
2037
+ onFocus: () => setFocused(true),
2038
+ onBlur: () => setFocused(false),
2000
2039
  children: [
2001
2040
  /* @__PURE__ */ jsx15(
2002
2041
  "span",
2003
2042
  {
2043
+ ref: valueRef,
2004
2044
  className: [
2005
2045
  "fe-selection__value",
2006
2046
  !selectedOptions.length && "is-placeholder",
@@ -2016,10 +2056,7 @@ var Selection = forwardRef9(
2016
2056
  ]
2017
2057
  },
2018
2058
  String(option.value)
2019
- )) : displayLabel.map((item, index) => /* @__PURE__ */ jsxs12("span", { children: [
2020
- item,
2021
- index < displayLabel.length - 1 ? ", " : ""
2022
- ] }, index)) : /* @__PURE__ */ jsxs12(Fragment2, { children: [
2059
+ )) : renderLabels() : /* @__PURE__ */ jsxs12(Fragment2, { children: [
2023
2060
  /* @__PURE__ */ jsx15("span", { children: placeholder }),
2024
2061
  isRequired && /* @__PURE__ */ jsx15("span", { className: "fe-field__required", "aria-hidden": "true", children: "*" })
2025
2062
  ] })
@@ -2038,6 +2075,7 @@ var Selection = forwardRef9(
2038
2075
  onClick: clear
2039
2076
  }
2040
2077
  ),
2078
+ showTooltip && /* @__PURE__ */ jsx15("span", { id: tooltipId, role: "tooltip", className: "fe-selection__tooltip", children: renderLabels() }),
2041
2079
  open && menuPosition && createPortal2(
2042
2080
  /* @__PURE__ */ jsxs12(
2043
2081
  "div",
@@ -2089,7 +2127,7 @@ var Selection = forwardRef9(
2089
2127
  onMouseMove: () => setActiveIndex(index),
2090
2128
  onClick: () => choose(option),
2091
2129
  children: [
2092
- /* @__PURE__ */ jsx15("span", { children: option.label }),
2130
+ /* @__PURE__ */ jsx15("span", { className: "fe-selection__option-label", children: option.label }),
2093
2131
  isSelected && /* @__PURE__ */ jsx15(
2094
2132
  "span",
2095
2133
  {
package/dist/styles.css CHANGED
@@ -886,8 +886,9 @@ table[data-fe-table][data-resizing] {
886
886
  display: flex;
887
887
  align-items: center;
888
888
  width: 100%;
889
+ min-width: 0;
889
890
  min-height: 40px;
890
- padding: 0 13px;
891
+ padding: 0 40px 0 13px;
891
892
  border: 1px solid #d4d8e0;
892
893
  border-radius: 12px;
893
894
  outline: 0;
@@ -902,7 +903,11 @@ table[data-fe-table][data-resizing] {
902
903
  background 0.15s;
903
904
  }
904
905
  .fe-selection--clearable .fe-selection__trigger {
905
- padding-right: 64px;
906
+ padding-right: 72px;
907
+ }
908
+ .fe-selection--wrap .fe-selection__trigger {
909
+ padding-top: 8px;
910
+ padding-bottom: 8px;
906
911
  }
907
912
  .fe-selection--small .fe-selection__trigger {
908
913
  min-height: 34px;
@@ -922,19 +927,24 @@ table[data-fe-table][data-resizing] {
922
927
  box-shadow: 0 0 0 3px rgba(40, 120, 240, 0.12);
923
928
  }
924
929
  .fe-selection__value {
925
- display: flex;
930
+ display: block;
926
931
  width: 100%;
927
932
  min-width: 0;
928
933
  flex: 1 1 auto;
929
- align-items: center;
930
934
  overflow: hidden;
931
935
  text-overflow: ellipsis;
932
936
  white-space: nowrap;
933
937
  }
938
+ .fe-selection--wrap .fe-selection__value {
939
+ line-height: 1.4;
940
+ overflow-wrap: anywhere;
941
+ white-space: normal;
942
+ }
934
943
  .fe-selection__value.is-placeholder {
935
944
  color: #8b94a4;
936
945
  }
937
946
  .fe-selection__value.is-tags {
947
+ display: flex;
938
948
  flex-wrap: wrap;
939
949
  align-content: center;
940
950
  gap: 5px;
@@ -1013,6 +1023,24 @@ table[data-fe-table][data-resizing] {
1013
1023
  outline: 2px solid #2878f0;
1014
1024
  outline-offset: 1px;
1015
1025
  }
1026
+ .fe-selection__tooltip {
1027
+ position: absolute;
1028
+ z-index: 50;
1029
+ bottom: calc(100% + 8px);
1030
+ left: 0;
1031
+ width: max-content;
1032
+ max-width: min(320px, calc(100vw - 32px));
1033
+ padding: 7px 9px;
1034
+ border-radius: 7px;
1035
+ background: #20242c;
1036
+ color: #fff;
1037
+ font-size: 12px;
1038
+ font-weight: 500;
1039
+ line-height: 1.35;
1040
+ overflow-wrap: anywhere;
1041
+ box-shadow: 0 5px 18px rgba(0, 0, 0, 0.22);
1042
+ pointer-events: none;
1043
+ }
1016
1044
  .fe-selection__chevron {
1017
1045
  position: absolute;
1018
1046
  top: 2px;
@@ -1073,6 +1101,7 @@ table[data-fe-table][data-resizing] {
1073
1101
  display: flex;
1074
1102
  align-items: center;
1075
1103
  justify-content: space-between;
1104
+ gap: 8px;
1076
1105
  width: 100%;
1077
1106
  min-height: 37px;
1078
1107
  padding: 8px 10px;
@@ -1098,7 +1127,12 @@ table[data-fe-table][data-resizing] {
1098
1127
  opacity: 0.45;
1099
1128
  cursor: not-allowed;
1100
1129
  }
1130
+ .fe-selection__option-label {
1131
+ min-width: 0;
1132
+ overflow-wrap: anywhere;
1133
+ }
1101
1134
  .fe-selection__check {
1135
+ flex: none;
1102
1136
  font-weight: 800;
1103
1137
  }
1104
1138
  .fe-selection__empty {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dragunio/fe-libs",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Reusable React components, icons, and table primitives.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -93,4 +93,4 @@
93
93
  "public"
94
94
  ]
95
95
  }
96
- }
96
+ }