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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to Twico UI are documented here (newest first). This file is generated automatically on each release by [semantic-release](https://semantic-release.gitbook.io/) from [Conventional Commits](https://www.conventionalcommits.org/) — do not edit it by hand. The same notes appear on each [GitHub Release](https://github.com/EncryptionL/twico-ui/releases).
4
4
 
5
+ # [1.23.0](https://github.com/EncryptionL/twico-ui/compare/v1.22.3...v1.23.0) (2026-07-30)
6
+
7
+
8
+ ### Features
9
+
10
+ * **combobox:** add wrapOptions to wrap long option labels/descriptions ([#300](https://github.com/EncryptionL/twico-ui/issues/300)) ([f0f247b](https://github.com/EncryptionL/twico-ui/commit/f0f247b75b3ce5bb593bbfd682d5feb4f63065d7))
11
+
12
+ ## [1.22.3](https://github.com/EncryptionL/twico-ui/compare/v1.22.2...v1.22.3) (2026-07-29)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * **datatable:** stop stateKey persistence being clobbered under Strict Mode + async columns ([#298](https://github.com/EncryptionL/twico-ui/issues/298)) ([d7ff41e](https://github.com/EncryptionL/twico-ui/commit/d7ff41e2bd9f3e1d20d31eaf2b6ca0ae2348c6ab))
18
+
5
19
  ## [1.22.2](https://github.com/EncryptionL/twico-ui/compare/v1.22.1...v1.22.2) (2026-07-29)
6
20
 
7
21
 
package/dist/index.cjs CHANGED
@@ -5671,6 +5671,10 @@ var COMBO_CSS = `
5671
5671
  .twc-opt__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
5672
5672
  .twc-opt__label { line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5673
5673
  .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; }
5674
+ /* #300: wrapOptions \u2014 let long labels/descriptions wrap onto multiple lines instead of truncating.
5675
+ overflow-wrap: anywhere also breaks a single very long token so it can't overflow the popover edge. */
5676
+ .twc-opt[data-wrap="true"] { align-items: flex-start; }
5677
+ .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; }
5674
5678
  .twc-opt__check { flex: none; color: var(--color-primary); display: inline-flex; }
5675
5679
  .twc-opt__check svg { width: 16px; height: 16px; }
5676
5680
  .twc-pop__empty { padding: 14px 12px; text-align: center; font-size: var(--text-sm); color: var(--color-text-subtle); }
@@ -5731,8 +5735,9 @@ function Combobox({
5731
5735
  loading = false,
5732
5736
  emptyText = "No results found",
5733
5737
  name,
5734
- virtualized = false,
5738
+ virtualized: virtualizedProp = false,
5735
5739
  overscan = 8,
5740
+ wrapOptions = false,
5736
5741
  id,
5737
5742
  className = "",
5738
5743
  onFocus,
@@ -5740,6 +5745,8 @@ function Combobox({
5740
5745
  ...rest
5741
5746
  }) {
5742
5747
  const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
5748
+ if (virtualizedProp && wrapOptions) warnOnce("combobox-wrap-virtualized", "twico-ui Combobox: `wrapOptions` disables `virtualized` \u2014 wrapped option rows aren't a fixed height.");
5749
+ const virtualized = virtualizedProp && !wrapOptions;
5743
5750
  const groups = React51__namespace.default.useMemo(() => normalizeGroups(options), [options]);
5744
5751
  const flat = React51__namespace.default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
5745
5752
  const autoId = React51__namespace.default.useId();
@@ -5926,6 +5933,7 @@ function Combobox({
5926
5933
  "data-disabled": o.disabled || void 0,
5927
5934
  "data-selected": isSel || void 0,
5928
5935
  "data-active": idx === active || void 0,
5936
+ "data-wrap": wrapOptions || void 0,
5929
5937
  onMouseEnter: () => {
5930
5938
  if (!o.disabled) setActive(idx);
5931
5939
  },
@@ -9361,6 +9369,7 @@ function Datatable({
9361
9369
  }
9362
9370
  };
9363
9371
  const stateReadyRef = React51__namespace.default.useRef(false);
9372
+ const stateRestoredRef = React51__namespace.default.useRef(false);
9364
9373
  const onStateChangeRef = React51__namespace.default.useRef(onStateChange);
9365
9374
  onStateChangeRef.current = onStateChange;
9366
9375
  React51__namespace.default.useEffect(() => {
@@ -9376,7 +9385,7 @@ function Datatable({
9376
9385
  }
9377
9386
  return void 0;
9378
9387
  }, [filters, sort, quick, pageVal, sizeVal, order, widths, hidden, pins, density, fWidths, fPanelSize, stateKey]);
9379
- React51__namespace.default.useEffect(() => {
9388
+ const restoreState = () => {
9380
9389
  let saved = null;
9381
9390
  if (stateKey) {
9382
9391
  try {
@@ -9387,8 +9396,22 @@ function Datatable({
9387
9396
  }
9388
9397
  if (!saved && initialState) saved = initialState;
9389
9398
  if (saved) applyState(saved);
9390
- stateReadyRef.current = true;
9399
+ stateRestoredRef.current = true;
9400
+ };
9401
+ React51__namespace.default.useEffect(() => {
9402
+ if (columns.length) {
9403
+ restoreState();
9404
+ stateReadyRef.current = true;
9405
+ }
9406
+ return () => {
9407
+ stateReadyRef.current = false;
9408
+ };
9391
9409
  }, []);
9410
+ React51__namespace.default.useEffect(() => {
9411
+ if (stateRestoredRef.current || !columns.length) return;
9412
+ restoreState();
9413
+ stateReadyRef.current = true;
9414
+ }, [columns.length]);
9392
9415
  const rootRef = React51__namespace.default.useRef(null);
9393
9416
  const [compact, setCompact] = React51__namespace.default.useState(false);
9394
9417
  React51__namespace.default.useEffect(() => {
@@ -9461,20 +9484,19 @@ function Datatable({
9461
9484
  React51__namespace.default.useEffect(() => {
9462
9485
  setOrder((prev) => mergeColOrder(prev, columns.map((c) => c.field).filter(Boolean)));
9463
9486
  }, [columns]);
9464
- const densitySyncedRef = React51__namespace.default.useRef(false);
9487
+ const densityPropRef = React51__namespace.default.useRef(densityProp);
9465
9488
  React51__namespace.default.useEffect(() => {
9466
- if (densitySyncedRef.current) setDensity(densityProp);
9467
- else densitySyncedRef.current = true;
9489
+ if (densityPropRef.current === densityProp) return;
9490
+ densityPropRef.current = densityProp;
9491
+ setDensity(densityProp);
9468
9492
  }, [densityProp]);
9469
9493
  React51__namespace.default.useEffect(() => {
9470
9494
  setAggOn(showAggregation);
9471
9495
  }, [showAggregation]);
9472
- const pageSizeSyncedRef = React51__namespace.default.useRef(false);
9496
+ const pageSizePropRef = React51__namespace.default.useRef(pageSize);
9473
9497
  React51__namespace.default.useEffect(() => {
9474
- if (!pageSizeSyncedRef.current) {
9475
- pageSizeSyncedRef.current = true;
9476
- return;
9477
- }
9498
+ if (pageSizePropRef.current === pageSize) return;
9499
+ pageSizePropRef.current = pageSize;
9478
9500
  if (pageSizeControlled) return;
9479
9501
  setInternalRpp(pageSize > 0 ? pageSize : 10);
9480
9502
  setInternalPage(0);