twico-ui 1.30.0 → 1.31.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 +12 -0
- package/dist/index.cjs +36 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.mjs +36 -19
- package/dist/index.mjs.map +1 -1
- package/llms.txt +3 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1822,6 +1822,15 @@ interface DatatableProps<T = any> extends Omit<React.HTMLAttributes<HTMLDivEleme
|
|
|
1822
1822
|
quickFilter?: string;
|
|
1823
1823
|
/** Fires with the new quick-search string as the user types (and when a host sets it). */
|
|
1824
1824
|
onQuickFilterChange?: (value: string) => void;
|
|
1825
|
+
/** #330: how the filter clauses combine — `"and"` (all must match) or `"or"` (any). A single, set-wide
|
|
1826
|
+
* connective (matching MUI DataGrid's `logicOperator`), surfaced as the per-row And/Or connector in the
|
|
1827
|
+
* Filters panel and included as `filterLogic` in the `onServerChange` query. Pass this (with
|
|
1828
|
+
* `onFilterLogicChange`) to control it; omit for uncontrolled (seeded by `defaultFilterLogic`). */
|
|
1829
|
+
filterLogic?: "and" | "or";
|
|
1830
|
+
/** #330: initial And/Or connective when `filterLogic` is uncontrolled. @default "and" */
|
|
1831
|
+
defaultFilterLogic?: "and" | "or";
|
|
1832
|
+
/** #330: fires with the new connective (`"and"` | `"or"`) when the user changes the per-row And/Or select. */
|
|
1833
|
+
onFilterLogicChange?: (logic: "and" | "or") => void;
|
|
1825
1834
|
/** Custom node rendered in a **leading slot** of the toolbar row, before the built-in Columns/Filters
|
|
1826
1835
|
* cluster (#286) — for host controls like an "Add row" button or bulk actions. Mirrors `CardGrid`'s
|
|
1827
1836
|
* `toolbar` prop, so no internal-class/absolute-position hacks are needed. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1822,6 +1822,15 @@ interface DatatableProps<T = any> extends Omit<React.HTMLAttributes<HTMLDivEleme
|
|
|
1822
1822
|
quickFilter?: string;
|
|
1823
1823
|
/** Fires with the new quick-search string as the user types (and when a host sets it). */
|
|
1824
1824
|
onQuickFilterChange?: (value: string) => void;
|
|
1825
|
+
/** #330: how the filter clauses combine — `"and"` (all must match) or `"or"` (any). A single, set-wide
|
|
1826
|
+
* connective (matching MUI DataGrid's `logicOperator`), surfaced as the per-row And/Or connector in the
|
|
1827
|
+
* Filters panel and included as `filterLogic` in the `onServerChange` query. Pass this (with
|
|
1828
|
+
* `onFilterLogicChange`) to control it; omit for uncontrolled (seeded by `defaultFilterLogic`). */
|
|
1829
|
+
filterLogic?: "and" | "or";
|
|
1830
|
+
/** #330: initial And/Or connective when `filterLogic` is uncontrolled. @default "and" */
|
|
1831
|
+
defaultFilterLogic?: "and" | "or";
|
|
1832
|
+
/** #330: fires with the new connective (`"and"` | `"or"`) when the user changes the per-row And/Or select. */
|
|
1833
|
+
onFilterLogicChange?: (logic: "and" | "or") => void;
|
|
1825
1834
|
/** Custom node rendered in a **leading slot** of the toolbar row, before the built-in Columns/Filters
|
|
1826
1835
|
* cluster (#286) — for host controls like an "Add row" button or bulk actions. Mirrors `CardGrid`'s
|
|
1827
1836
|
* `toolbar` prop, so no internal-class/absolute-position hacks are needed. */
|
package/dist/index.mjs
CHANGED
|
@@ -8190,6 +8190,8 @@ function classifyDiff(from = [], to = [], columns = [], rowKey, opts = {}) {
|
|
|
8190
8190
|
});
|
|
8191
8191
|
return { rows, counts };
|
|
8192
8192
|
}
|
|
8193
|
+
var DT_FILTER_PANEL_W = 620;
|
|
8194
|
+
var DT_FILTER_LOGIC_W = 68;
|
|
8193
8195
|
var DT_CSS = `
|
|
8194
8196
|
.twc-dt { display: flex; flex-direction: column; font-family: var(--font-sans); color: var(--color-text);
|
|
8195
8197
|
border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg);
|
|
@@ -8612,13 +8614,11 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
|
|
|
8612
8614
|
.twc-dt__panel-count { font-weight: 600; color: var(--color-text-muted); text-transform: none; letter-spacing: 0; margin-inline-start: 6px; font-variant-numeric: tabular-nums; }
|
|
8613
8615
|
.twc-dt__link { border: none; background: transparent; color: var(--color-primary); font-family: inherit; font-size: var(--text-xs); font-weight: 600; cursor: pointer; padding: 2px 4px; border-radius: var(--radius-sm); }
|
|
8614
8616
|
.twc-dt__link:hover { background: var(--color-primary-subtle); }
|
|
8615
|
-
/* #
|
|
8616
|
-
|
|
8617
|
-
.
|
|
8618
|
-
.twc-
|
|
8619
|
-
.twc-
|
|
8620
|
-
.twc-dt__flogic-btn[data-active] { background: var(--color-primary); color: var(--color-primary-fg); }
|
|
8621
|
-
.twc-dt__flogic-btn[data-active]:hover { background: var(--color-primary); }
|
|
8617
|
+
/* #330: MUI DataGrid-style per-row And/Or connector. Row 1 shows a static "Where"; the first connector
|
|
8618
|
+
row (row 2) hosts an editable And/Or Select bound to the single filterLogic; rows 3+ echo it as static
|
|
8619
|
+
text. Fixed-width leading cell so the Column/Operator/Value cells stay aligned across rows. */
|
|
8620
|
+
.twc-dt__f-logic { position: relative; flex: none; width: 68px; }
|
|
8621
|
+
.twc-dt__f-where { display: inline-flex; align-items: center; height: 38px; padding-inline: 6px; color: var(--color-text-muted); font-size: var(--text-sm); font-weight: var(--font-medium); }
|
|
8622
8622
|
|
|
8623
8623
|
/* Filter panel \u2014 user-resizable (#292): panel size + per-field widths resolve through a two-tier CSS var
|
|
8624
8624
|
cascade \u2014 user drag (-usr) > #289 measured auto-fit (-fit) > 118px fallback \u2014 entirely in clamp(), so
|
|
@@ -8628,7 +8628,7 @@ th.twc-dt__rownum .twc-dt__th-inner { padding-inline: 8px; gap: 2px; justify-con
|
|
|
8628
8628
|
equal-specificity 'position: relative' defined later would clobber it, dropping the popover into normal
|
|
8629
8629
|
flow below the table. The panel stays position: fixed, which already anchors the absolutely-positioned
|
|
8630
8630
|
.twc-dt__pop-grip; per-field handles anchor to their own position: relative .twc-dt__f-* fields. */
|
|
8631
|
-
width: var(--twc-dt-panel-w,
|
|
8631
|
+
width: var(--twc-dt-panel-w, 620px); max-width: calc(100vw - 32px);
|
|
8632
8632
|
height: var(--twc-dt-panel-h, auto); max-height: calc(100vh - 32px);
|
|
8633
8633
|
display: flex; flex-direction: column;
|
|
8634
8634
|
}
|
|
@@ -9240,6 +9240,9 @@ function Datatable({
|
|
|
9240
9240
|
searchable = true,
|
|
9241
9241
|
quickFilter,
|
|
9242
9242
|
onQuickFilterChange,
|
|
9243
|
+
filterLogic: filterLogicProp,
|
|
9244
|
+
defaultFilterLogic = "and",
|
|
9245
|
+
onFilterLogicChange,
|
|
9243
9246
|
toolbarActions,
|
|
9244
9247
|
resizableFilters = true,
|
|
9245
9248
|
resizablePopovers = true,
|
|
@@ -9333,7 +9336,14 @@ function Datatable({
|
|
|
9333
9336
|
});
|
|
9334
9337
|
const [sort, setSort] = React51__default.useState(null);
|
|
9335
9338
|
const [filters, setFilters] = React51__default.useState([]);
|
|
9336
|
-
const
|
|
9339
|
+
const filterLogicControlled = filterLogicProp !== void 0;
|
|
9340
|
+
const [filterLogicInternal, setFilterLogicInternal] = React51__default.useState(defaultFilterLogic === "or" ? "or" : "and");
|
|
9341
|
+
const filterLogic = filterLogicControlled ? filterLogicProp === "or" ? "or" : "and" : filterLogicInternal;
|
|
9342
|
+
const setFilterLogic = (next) => {
|
|
9343
|
+
const v = next === "or" ? "or" : "and";
|
|
9344
|
+
if (!filterLogicControlled) setFilterLogicInternal(v);
|
|
9345
|
+
onFilterLogicChange?.(v);
|
|
9346
|
+
};
|
|
9337
9347
|
const [hidden, setHidden] = React51__default.useState(() => /* @__PURE__ */ new Set());
|
|
9338
9348
|
const [showRowNum, setShowRowNum] = React51__default.useState(rowNumbers);
|
|
9339
9349
|
const [wrapped, setWrapped] = React51__default.useState(() => new Set((columns || []).filter((c) => c.wrapText).map((c) => c.field)));
|
|
@@ -9429,7 +9439,7 @@ function Datatable({
|
|
|
9429
9439
|
if (!s || typeof s !== "object") return;
|
|
9430
9440
|
const known = new Set(cols.map((c) => c.field).filter(Boolean));
|
|
9431
9441
|
if (Array.isArray(s.filters)) setFilters(s.filters.filter((f) => f && known.has(f.field)).map((f, i) => ({ id: Date.now() + Math.random() + i, field: f.field, op: f.op, value: f.value })));
|
|
9432
|
-
if (s.filterLogic === "or" || s.filterLogic === "and")
|
|
9442
|
+
if ((s.filterLogic === "or" || s.filterLogic === "and") && !filterLogicControlled) setFilterLogicInternal(s.filterLogic);
|
|
9433
9443
|
if ("sort" in s) setSort(s.sort && known.has(s.sort.field) ? { field: s.sort.field, dir: s.sort.dir === "desc" ? "desc" : "asc" } : null);
|
|
9434
9444
|
if (typeof s.quickFilter === "string" && quickFilter === void 0) setInternalQuick(s.quickFilter);
|
|
9435
9445
|
if (typeof s.page === "number" && !pageControlled) setInternalPage(Math.max(0, Math.floor(s.page)));
|
|
@@ -10822,7 +10832,7 @@ function Datatable({
|
|
|
10822
10832
|
const pad2 = trigger ? (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0) : 24;
|
|
10823
10833
|
const chrome = pad2 + 8 + 16 + 4;
|
|
10824
10834
|
const widest = (labels) => labels.reduce((m, l) => Math.max(m, ctx.measureText(String(l)).width), 0);
|
|
10825
|
-
const colCap = Math.max(118, Math.min(210, el.clientWidth - 118 - 30 - 140 -
|
|
10835
|
+
const colCap = Math.max(118, Math.min(210, el.clientWidth - DT_FILTER_LOGIC_W - 118 - 30 - 30 - 140 - 5 * 6 - 2 * 4));
|
|
10826
10836
|
const colW = Math.min(colCap, Math.max(118, Math.ceil(widest(filterableCols.map((c) => c.headerName ?? c.field)) + chrome)));
|
|
10827
10837
|
const opW = Math.min(170, Math.max(118, Math.ceil(widest(ALL_OP_LABELS) + chrome)));
|
|
10828
10838
|
if (Number.isFinite(colW)) el.style.setProperty("--twc-dt-fcol-fit", `${colW}px`);
|
|
@@ -10854,7 +10864,7 @@ function Datatable({
|
|
|
10854
10864
|
if (field === "op") return filterFieldMaxWidth || 260;
|
|
10855
10865
|
const p = filterPanelRef.current;
|
|
10856
10866
|
if (!p) return 640;
|
|
10857
|
-
return clampNum(p.clientWidth - fLiveW("col") - fLiveW("op") - 30 -
|
|
10867
|
+
return clampNum(p.clientWidth - DT_FILTER_LOGIC_W - fLiveW("col") - fLiveW("op") - 30 - 30 - 5 * 6 - 2 * 4, F_MIN.val, 640);
|
|
10858
10868
|
};
|
|
10859
10869
|
const isRtl = () => {
|
|
10860
10870
|
const p = filterPanelRef.current;
|
|
@@ -11551,7 +11561,7 @@ function Datatable({
|
|
|
11551
11561
|
} else {
|
|
11552
11562
|
setPanel("filters");
|
|
11553
11563
|
setColMenu(null);
|
|
11554
|
-
openPanel(e.currentTarget, "left",
|
|
11564
|
+
openPanel(e.currentTarget, "left", DT_FILTER_PANEL_W);
|
|
11555
11565
|
}
|
|
11556
11566
|
},
|
|
11557
11567
|
children: [
|
|
@@ -12119,7 +12129,7 @@ function Datatable({
|
|
|
12119
12129
|
closeMenu();
|
|
12120
12130
|
restoreTriggerFocus();
|
|
12121
12131
|
setPanel("filters");
|
|
12122
|
-
openPanel(document.querySelector(".twc-dt__toolbar .twc-dt__tbtn:nth-child(2)"), "left",
|
|
12132
|
+
openPanel(document.querySelector(".twc-dt__toolbar .twc-dt__tbtn:nth-child(2)"), "left", DT_FILTER_PANEL_W);
|
|
12123
12133
|
}, children: [
|
|
12124
12134
|
/* @__PURE__ */ jsx(Svg, { d: I.filter }),
|
|
12125
12135
|
" Filter"
|
|
@@ -12553,10 +12563,6 @@ function Datatable({
|
|
|
12553
12563
|
/* @__PURE__ */ jsxs("div", { className: "twc-dt__panel-head", children: [
|
|
12554
12564
|
/* @__PURE__ */ jsx("span", { className: "twc-dt__panel-title", children: "Filters" }),
|
|
12555
12565
|
/* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6 }, children: [
|
|
12556
|
-
filters.length > 1 ? /* @__PURE__ */ jsxs("span", { className: "twc-dt__flogic", role: "group", "aria-label": "Combine filters with", children: [
|
|
12557
|
-
/* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__flogic-btn", "data-active": filterLogic === "and" || void 0, "aria-pressed": filterLogic === "and", onClick: () => setFilterLogic("and"), children: "AND" }),
|
|
12558
|
-
/* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__flogic-btn", "data-active": filterLogic === "or" || void 0, "aria-pressed": filterLogic === "or", onClick: () => setFilterLogic("or"), children: "OR" })
|
|
12559
|
-
] }) : null,
|
|
12560
12566
|
resizableFilters && hasFilterSizeOverride ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: resetFilterSizes, children: "Reset sizes" }) : null,
|
|
12561
12567
|
filters.length ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__link", onClick: () => setFilters([]), children: "Clear all" }) : null
|
|
12562
12568
|
] })
|
|
@@ -12566,6 +12572,17 @@ function Datatable({
|
|
|
12566
12572
|
const ops = opsFor(filterTypeOf(col));
|
|
12567
12573
|
const op = ops.find((o) => o.value === f.op) || ops[0];
|
|
12568
12574
|
return /* @__PURE__ */ jsxs("div", { className: "twc-dt__frow", children: [
|
|
12575
|
+
/* @__PURE__ */ jsx("div", { className: "twc-dt__f-logic", children: i === 0 ? /* @__PURE__ */ jsx("span", { className: "twc-dt__f-where", children: "Where" }) : i === 1 ? /* @__PURE__ */ jsx(
|
|
12576
|
+
Select,
|
|
12577
|
+
{
|
|
12578
|
+
size: "sm",
|
|
12579
|
+
portal: true,
|
|
12580
|
+
"aria-label": "Combine with the other filters",
|
|
12581
|
+
value: filterLogic,
|
|
12582
|
+
options: [{ value: "and", label: "And" }, { value: "or", label: "Or" }],
|
|
12583
|
+
onChange: (v) => setFilterLogic(v)
|
|
12584
|
+
}
|
|
12585
|
+
) : /* @__PURE__ */ jsx("span", { className: "twc-dt__f-where", children: filterLogic === "or" ? "Or" : "And" }) }),
|
|
12569
12586
|
/* @__PURE__ */ jsxs("div", { className: "twc-dt__f-col", children: [
|
|
12570
12587
|
/* @__PURE__ */ jsx(
|
|
12571
12588
|
Select,
|
|
@@ -12645,7 +12662,7 @@ function Datatable({
|
|
|
12645
12662
|
role: "slider",
|
|
12646
12663
|
tabIndex: 0,
|
|
12647
12664
|
"aria-label": "Resize filters panel (Enter to reset)",
|
|
12648
|
-
"aria-valuetext": `Width ${Math.round(fPanelSize?.w ??
|
|
12665
|
+
"aria-valuetext": `Width ${Math.round(fPanelSize?.w ?? DT_FILTER_PANEL_W)} pixels, height ${fPanelSize?.h != null ? Math.round(fPanelSize.h) + " pixels" : "auto"}`,
|
|
12649
12666
|
onPointerDown: startPanelResize,
|
|
12650
12667
|
onKeyDown: onPanelGripKey,
|
|
12651
12668
|
onDoubleClick: (e) => {
|