twico-ui 1.22.2 → 1.23.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.d.cts CHANGED
@@ -1597,6 +1597,10 @@ interface ComboboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>
1597
1597
  virtualized?: boolean;
1598
1598
  /** Extra option rows rendered above/below the viewport when `virtualized`, to smooth fast scrolling. @default 8 */
1599
1599
  overscan?: number;
1600
+ /** Let long option labels/descriptions wrap onto multiple lines instead of truncating to one line with an
1601
+ * ellipsis — useful when options share a long prefix and differ only in a truncated tail. Takes precedence
1602
+ * over `virtualized` (wrapped rows aren't a fixed height). @default false */
1603
+ wrapOptions?: boolean;
1600
1604
  /** Composed with the field's open-on-focus behavior — your handler runs first. */
1601
1605
  onFocus?: React.FocusEventHandler<HTMLInputElement>;
1602
1606
  /** Composed with the field's keyboard navigation (Arrows/Enter/Escape) — your handler runs first; call `event.preventDefault()` to suppress it. */
package/dist/index.d.ts CHANGED
@@ -1597,6 +1597,10 @@ interface ComboboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>
1597
1597
  virtualized?: boolean;
1598
1598
  /** Extra option rows rendered above/below the viewport when `virtualized`, to smooth fast scrolling. @default 8 */
1599
1599
  overscan?: number;
1600
+ /** Let long option labels/descriptions wrap onto multiple lines instead of truncating to one line with an
1601
+ * ellipsis — useful when options share a long prefix and differ only in a truncated tail. Takes precedence
1602
+ * over `virtualized` (wrapped rows aren't a fixed height). @default false */
1603
+ wrapOptions?: boolean;
1600
1604
  /** Composed with the field's open-on-focus behavior — your handler runs first. */
1601
1605
  onFocus?: React.FocusEventHandler<HTMLInputElement>;
1602
1606
  /** Composed with the field's keyboard navigation (Arrows/Enter/Escape) — your handler runs first; call `event.preventDefault()` to suppress it. */
package/dist/index.mjs CHANGED
@@ -5650,6 +5650,10 @@ var COMBO_CSS = `
5650
5650
  .twc-opt__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
5651
5651
  .twc-opt__label { line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5652
5652
  .twc-opt__desc { font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5653
+ /* #300: wrapOptions \u2014 let long labels/descriptions wrap onto multiple lines instead of truncating.
5654
+ overflow-wrap: anywhere also breaks a single very long token so it can't overflow the popover edge. */
5655
+ .twc-opt[data-wrap="true"] { align-items: flex-start; }
5656
+ .twc-opt[data-wrap="true"] .twc-opt__label, .twc-opt[data-wrap="true"] .twc-opt__desc { overflow: visible; text-overflow: clip; white-space: normal; overflow-wrap: anywhere; }
5653
5657
  .twc-opt__check { flex: none; color: var(--color-primary); display: inline-flex; }
5654
5658
  .twc-opt__check svg { width: 16px; height: 16px; }
5655
5659
  .twc-pop__empty { padding: 14px 12px; text-align: center; font-size: var(--text-sm); color: var(--color-text-subtle); }
@@ -5710,8 +5714,9 @@ function Combobox({
5710
5714
  loading = false,
5711
5715
  emptyText = "No results found",
5712
5716
  name,
5713
- virtualized = false,
5717
+ virtualized: virtualizedProp = false,
5714
5718
  overscan = 8,
5719
+ wrapOptions = false,
5715
5720
  id,
5716
5721
  className = "",
5717
5722
  onFocus,
@@ -5719,6 +5724,8 @@ function Combobox({
5719
5724
  ...rest
5720
5725
  }) {
5721
5726
  const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
5727
+ if (virtualizedProp && wrapOptions) warnOnce("combobox-wrap-virtualized", "twico-ui Combobox: `wrapOptions` disables `virtualized` \u2014 wrapped option rows aren't a fixed height.");
5728
+ const virtualized = virtualizedProp && !wrapOptions;
5722
5729
  const groups = React51__default.useMemo(() => normalizeGroups(options), [options]);
5723
5730
  const flat = React51__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
5724
5731
  const autoId = React51__default.useId();
@@ -5905,6 +5912,7 @@ function Combobox({
5905
5912
  "data-disabled": o.disabled || void 0,
5906
5913
  "data-selected": isSel || void 0,
5907
5914
  "data-active": idx === active || void 0,
5915
+ "data-wrap": wrapOptions || void 0,
5908
5916
  onMouseEnter: () => {
5909
5917
  if (!o.disabled) setActive(idx);
5910
5918
  },
@@ -9340,6 +9348,7 @@ function Datatable({
9340
9348
  }
9341
9349
  };
9342
9350
  const stateReadyRef = React51__default.useRef(false);
9351
+ const stateRestoredRef = React51__default.useRef(false);
9343
9352
  const onStateChangeRef = React51__default.useRef(onStateChange);
9344
9353
  onStateChangeRef.current = onStateChange;
9345
9354
  React51__default.useEffect(() => {
@@ -9355,7 +9364,7 @@ function Datatable({
9355
9364
  }
9356
9365
  return void 0;
9357
9366
  }, [filters, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, stateKey]);
9358
- React51__default.useEffect(() => {
9367
+ const restoreState = () => {
9359
9368
  let saved = null;
9360
9369
  if (stateKey) {
9361
9370
  try {
@@ -9366,8 +9375,22 @@ function Datatable({
9366
9375
  }
9367
9376
  if (!saved && initialState) saved = initialState;
9368
9377
  if (saved) applyState(saved);
9369
- stateReadyRef.current = true;
9378
+ stateRestoredRef.current = true;
9379
+ };
9380
+ React51__default.useEffect(() => {
9381
+ if (columns.length) {
9382
+ restoreState();
9383
+ stateReadyRef.current = true;
9384
+ }
9385
+ return () => {
9386
+ stateReadyRef.current = false;
9387
+ };
9370
9388
  }, []);
9389
+ React51__default.useEffect(() => {
9390
+ if (stateRestoredRef.current || !columns.length) return;
9391
+ restoreState();
9392
+ stateReadyRef.current = true;
9393
+ }, [columns.length]);
9371
9394
  const rootRef = React51__default.useRef(null);
9372
9395
  const [compact, setCompact] = React51__default.useState(false);
9373
9396
  React51__default.useEffect(() => {
@@ -9440,20 +9463,19 @@ function Datatable({
9440
9463
  React51__default.useEffect(() => {
9441
9464
  setOrder((prev) => mergeColOrder(prev, columns.map((c) => c.field).filter(Boolean)));
9442
9465
  }, [columns]);
9443
- const densitySyncedRef = React51__default.useRef(false);
9466
+ const densityPropRef = React51__default.useRef(densityProp);
9444
9467
  React51__default.useEffect(() => {
9445
- if (densitySyncedRef.current) setDensity(densityProp);
9446
- else densitySyncedRef.current = true;
9468
+ if (densityPropRef.current === densityProp) return;
9469
+ densityPropRef.current = densityProp;
9470
+ setDensity(densityProp);
9447
9471
  }, [densityProp]);
9448
9472
  React51__default.useEffect(() => {
9449
9473
  setAggOn(showAggregation);
9450
9474
  }, [showAggregation]);
9451
- const pageSizeSyncedRef = React51__default.useRef(false);
9475
+ const pageSizePropRef = React51__default.useRef(pageSize);
9452
9476
  React51__default.useEffect(() => {
9453
- if (!pageSizeSyncedRef.current) {
9454
- pageSizeSyncedRef.current = true;
9455
- return;
9456
- }
9477
+ if (pageSizePropRef.current === pageSize) return;
9478
+ pageSizePropRef.current = pageSize;
9457
9479
  if (pageSizeControlled) return;
9458
9480
  setInternalRpp(pageSize > 0 ? pageSize : 10);
9459
9481
  setInternalPage(0);