@godxjp/ui 18.11.0 → 18.11.1
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/components/data-display/data-table.d.ts +4 -1
- package/dist/components/data-display/data-table.js +31 -2
- package/dist/styles/alert-layout.css +1 -1
- package/dist/styles/shell-layout.css +11 -0
- package/dist/styles/table-layout.css +11 -0
- package/dist/tokens/components/feedback.css +4 -0
- package/package.json +2 -2
|
@@ -41,7 +41,10 @@ interface DataTableProps<T> {
|
|
|
41
41
|
onColumnVisibilityChange?: OnChangeFn<VisibilityState>;
|
|
42
42
|
/**
|
|
43
43
|
* Manual (server) flags. Default `false` so the simple `data`+`columns` case
|
|
44
|
-
* sorts / filters
|
|
44
|
+
* sorts / filters in-browser with no extra wiring. Client pagination slices
|
|
45
|
+
* rows ONLY when engaged — a numbered `<DataTable.Pagination>` child is
|
|
46
|
+
* composed, or `pagination`/`onPaginationChange` is supplied; a plain table
|
|
47
|
+
* with neither renders every row (no silent 10-row cap, gh#270). Set the
|
|
45
48
|
* relevant flag `true` and drive the matching state from your query for
|
|
46
49
|
* server-side sort / filter / pagination.
|
|
47
50
|
*/
|
|
@@ -178,6 +178,10 @@ function DataTable({
|
|
|
178
178
|
}
|
|
179
179
|
};
|
|
180
180
|
const tanstackColumns = React.useMemo(() => toTanstackColumns(columns), [columns]);
|
|
181
|
+
const hasNumberedPager = React.Children.toArray(children).some(
|
|
182
|
+
(c) => React.isValidElement(c) && c.type.displayName === "DataTable.Pagination" && typeof c.props.onChange !== "function"
|
|
183
|
+
);
|
|
184
|
+
const paginationEngaged = manualPagination || controlledPagination !== void 0 || onPaginationChange !== void 0 || hasNumberedPager;
|
|
181
185
|
const table = useReactTable({
|
|
182
186
|
data,
|
|
183
187
|
columns: tanstackColumns,
|
|
@@ -185,7 +189,7 @@ function DataTable({
|
|
|
185
189
|
getCoreRowModel: getCoreRowModel(),
|
|
186
190
|
...manualSorting ? {} : { getSortedRowModel: getSortedRowModel() },
|
|
187
191
|
...manualFiltering ? {} : { getFilteredRowModel: getFilteredRowModel() },
|
|
188
|
-
...manualPagination ? {} : { getPaginationRowModel: getPaginationRowModel() },
|
|
192
|
+
...manualPagination || !paginationEngaged ? {} : { getPaginationRowModel: getPaginationRowModel() },
|
|
189
193
|
manualSorting,
|
|
190
194
|
manualFiltering,
|
|
191
195
|
manualPagination,
|
|
@@ -419,6 +423,26 @@ DataTable.Content = function DataTableContent() {
|
|
|
419
423
|
);
|
|
420
424
|
}
|
|
421
425
|
}, [missingHeaderNames]);
|
|
426
|
+
const scrollRef = React.useRef(null);
|
|
427
|
+
const [hasOverflowEnd, setHasOverflowEnd] = React.useState(false);
|
|
428
|
+
React.useEffect(() => {
|
|
429
|
+
const el = scrollRef.current;
|
|
430
|
+
if (!el) return;
|
|
431
|
+
const update = () => {
|
|
432
|
+
const overflowing = el.scrollWidth - el.clientWidth > 1;
|
|
433
|
+
const atEnd = Math.abs(el.scrollLeft) + el.clientWidth >= el.scrollWidth - 1;
|
|
434
|
+
setHasOverflowEnd(overflowing && !atEnd);
|
|
435
|
+
};
|
|
436
|
+
update();
|
|
437
|
+
el.addEventListener("scroll", update, { passive: true });
|
|
438
|
+
const observer = new ResizeObserver(update);
|
|
439
|
+
observer.observe(el);
|
|
440
|
+
if (el.firstElementChild) observer.observe(el.firstElementChild);
|
|
441
|
+
return () => {
|
|
442
|
+
el.removeEventListener("scroll", update);
|
|
443
|
+
observer.disconnect();
|
|
444
|
+
};
|
|
445
|
+
}, []);
|
|
422
446
|
const activeSort = sort ?? sortingStateToSort(table.getState().sorting);
|
|
423
447
|
const isControlledSort = sort !== void 0 || !!onSortChange;
|
|
424
448
|
const onHeaderClick = (col) => {
|
|
@@ -440,7 +464,12 @@ DataTable.Content = function DataTableContent() {
|
|
|
440
464
|
return /* @__PURE__ */ jsx(
|
|
441
465
|
"div",
|
|
442
466
|
{
|
|
443
|
-
|
|
467
|
+
ref: scrollRef,
|
|
468
|
+
className: cn(
|
|
469
|
+
"ui-data-table-scroll",
|
|
470
|
+
hasPinEnd && "ui-data-table-has-pin-end",
|
|
471
|
+
hasOverflowEnd && "ui-data-table-has-overflow-end"
|
|
472
|
+
),
|
|
444
473
|
"aria-busy": loading,
|
|
445
474
|
tabIndex: presetAttr ? void 0 : 0,
|
|
446
475
|
children: /* @__PURE__ */ jsx(
|
|
@@ -77,6 +77,17 @@
|
|
|
77
77
|
background-color: var(--app-shell-main-background);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
/* `.app-main` carries tabindex="0" (axe scrollable-region-focusable, dbad118), so keyboard
|
|
81
|
+
* focus can land on the region — without a rule here the USER-AGENT default outline (blue
|
|
82
|
+
* in Chrome) wraps the whole content area. Use the design-system ring instead; INSET because
|
|
83
|
+
* `.app-main` is the shell's clip boundary (`contain: paint`) and an outset shadow would be
|
|
84
|
+
* clipped by the grid. Never remove the indicator outright — the region is focusable and
|
|
85
|
+
* must show focus (WCAG 2.4.7, gh#271). */
|
|
86
|
+
.app-main:focus-visible {
|
|
87
|
+
outline: none;
|
|
88
|
+
box-shadow: inset 0 0 0 var(--focus-ring-width) hsl(var(--focus-ring-color, var(--ring)));
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
.app-footer {
|
|
81
92
|
grid-area: footer;
|
|
82
93
|
border-top: 1px solid hsl(var(--border));
|
|
@@ -169,6 +169,11 @@
|
|
|
169
169
|
padding-inline: var(--space-page-active-x);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/* Scroll-hint fade — a SCROLL affordance, so it only shows while the region
|
|
173
|
+
* actually overflows and is not scrolled to the inline-end. The component
|
|
174
|
+
* measures the scroll box and stamps `.ui-data-table-has-overflow-end`
|
|
175
|
+
* (gh#267 — the fade used to render unconditionally, washing out the last
|
|
176
|
+
* column of tables that never scroll). */
|
|
172
177
|
.ui-data-table-scroll::after {
|
|
173
178
|
content: "";
|
|
174
179
|
position: absolute;
|
|
@@ -178,9 +183,15 @@
|
|
|
178
183
|
z-index: 20;
|
|
179
184
|
width: 1.75rem;
|
|
180
185
|
pointer-events: none;
|
|
186
|
+
opacity: 0;
|
|
187
|
+
transition: opacity 150ms ease;
|
|
181
188
|
background: linear-gradient(to left, hsl(var(--background) / 0.88), transparent);
|
|
182
189
|
}
|
|
183
190
|
|
|
191
|
+
.ui-data-table-has-overflow-end::after {
|
|
192
|
+
opacity: 1;
|
|
193
|
+
}
|
|
194
|
+
|
|
184
195
|
[data-slot="card-content"][data-flush] .ui-data-table-scroll {
|
|
185
196
|
margin-inline: 0;
|
|
186
197
|
padding-inline: 0;
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
--dialog-space-inset: var(--dialog-space-y) var(--dialog-space-x);
|
|
22
22
|
--dialog-space-gap: var(--space-stack-md);
|
|
23
23
|
--dialog-close-space-offset: var(--space-4);
|
|
24
|
+
/* Alert corner radius (gh#268 — rule #45): a full-width Alert often sits in the
|
|
25
|
+
* same page column as a Card (--card-radius); a service aligns them by
|
|
26
|
+
* overriding this once. Default keeps the historical --radius-md. */
|
|
27
|
+
--alert-radius: var(--radius-md);
|
|
24
28
|
--alert-space-inset: var(--space-section-active);
|
|
25
29
|
--alert-space-gap: var(--space-inline-md);
|
|
26
30
|
--alert-inner-space-gap: var(--space-stack-sm);
|