@charcuterie/ui 3.28.0 → 3.28.2
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/Main/Main.js +1 -1
- package/dist/Main/Main.js.map +1 -1
- package/dist/Rail/Rail.js +1 -1
- package/dist/Rail/Rail.js.map +1 -1
- package/dist/Shell/Shell.js +1 -1
- package/dist/Shell/Shell.js.map +1 -1
- package/dist/VirtualizedGrid/ElementGrid.d.ts +7 -0
- package/dist/VirtualizedGrid/ElementGrid.d.ts.map +1 -0
- package/dist/VirtualizedGrid/ElementGrid.js +19 -0
- package/dist/VirtualizedGrid/ElementGrid.js.map +1 -0
- package/dist/VirtualizedGrid/GridRows.d.ts +4 -0
- package/dist/VirtualizedGrid/GridRows.d.ts.map +1 -0
- package/dist/VirtualizedGrid/GridRows.js +40 -0
- package/dist/VirtualizedGrid/GridRows.js.map +1 -0
- package/dist/VirtualizedGrid/VirtualizedGrid.d.ts +6 -8
- package/dist/VirtualizedGrid/VirtualizedGrid.d.ts.map +1 -1
- package/dist/VirtualizedGrid/VirtualizedGrid.js +30 -87
- package/dist/VirtualizedGrid/VirtualizedGrid.js.map +1 -1
- package/dist/VirtualizedGrid/WindowGrid.d.ts +3 -0
- package/dist/VirtualizedGrid/WindowGrid.d.ts.map +1 -0
- package/dist/VirtualizedGrid/WindowGrid.js +20 -0
- package/dist/VirtualizedGrid/WindowGrid.js.map +1 -0
- package/dist/VirtualizedGrid/virtualizedGridScroll.d.ts +25 -0
- package/dist/VirtualizedGrid/virtualizedGridScroll.d.ts.map +1 -0
- package/dist/VirtualizedGrid/virtualizedGridScroll.js +50 -0
- package/dist/VirtualizedGrid/virtualizedGridScroll.js.map +1 -0
- package/dist/VirtualizedGrid/virtualizedGridTypes.d.ts +27 -0
- package/dist/VirtualizedGrid/virtualizedGridTypes.d.ts.map +1 -0
- package/dist/VirtualizedGrid/virtualizedGridTypes.js +2 -0
- package/dist/VirtualizedGrid/virtualizedGridTypes.js.map +1 -0
- package/package.json +1 -1
- package/src/Main/Main.tsx +1 -1
- package/src/Rail/Rail.tsx +1 -1
- package/src/Shell/Shell.mdx +8 -0
- package/src/Shell/Shell.stories.tsx +24 -0
- package/src/Shell/Shell.test.tsx +29 -0
- package/src/Shell/Shell.tsx +1 -1
- package/src/VirtualizedGrid/ElementGrid.tsx +45 -0
- package/src/VirtualizedGrid/GridRows.tsx +90 -0
- package/src/VirtualizedGrid/VirtualizedGrid.mdx +9 -8
- package/src/VirtualizedGrid/VirtualizedGrid.stories.tsx +26 -0
- package/src/VirtualizedGrid/VirtualizedGrid.test.tsx +60 -1
- package/src/VirtualizedGrid/VirtualizedGrid.tsx +42 -142
- package/src/VirtualizedGrid/WindowGrid.tsx +39 -0
- package/src/VirtualizedGrid/virtualizedGridScroll.ts +69 -0
- package/src/VirtualizedGrid/virtualizedGridTypes.ts +32 -0
package/dist/Main/Main.js
CHANGED
|
@@ -118,6 +118,6 @@ export const Main = ({ children, className, contentWidth, id, ...mainProps }) =>
|
|
|
118
118
|
const maxInlineSize = toMaxInlineSize(contentWidth ??
|
|
119
119
|
shell?.contentWidth ??
|
|
120
120
|
DEFAULT_CONTENT_WIDTH);
|
|
121
|
-
return (_jsx("main", { ...mainProps, className: toClassName("col-start-1 row-start-3 min-w-0 md:col-start-2 md:row-start-2", className), id: id ?? shell?.mainId ?? fallbackId, tabIndex: -1, children: _jsx("div", { className: "@container mx-auto flex w-full min-w-0 flex-col gap-6 wrap-anywhere px-4 py-6 sm:px-6", style: { maxInlineSize }, children: children }) }));
|
|
121
|
+
return (_jsx("main", { ...mainProps, className: toClassName("charcuterie-scrollbar col-start-1 row-start-3 min-h-0 min-w-0 overflow-y-auto md:col-start-2 md:row-start-2", className), id: id ?? shell?.mainId ?? fallbackId, tabIndex: -1, children: _jsx("div", { className: "@container mx-auto flex w-full min-w-0 flex-col gap-6 wrap-anywhere px-4 py-6 sm:px-6", style: { maxInlineSize }, children: children }) }));
|
|
122
122
|
};
|
|
123
123
|
//# sourceMappingURL=Main.js.map
|
package/dist/Main/Main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Main.js","sourceRoot":"","sources":["../../src/Main/Main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAGL,UAAU,GACX,MAAM,OAAO,CAAA;AAEd,OAAO,EAEL,qBAAqB,EACrB,eAAe,GAChB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAM/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EACnB,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,EAAE,EACF,GAAG,SAAS,EACF,EAAa,EAAE;IACzB,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAA;IAEtC,iEAAiE;IACjE,2DAA2D;IAC3D,MAAM,UAAU,GAAG,WAAW,EAAE,CAAA;IAEhC,MAAM,aAAa,GAAG,eAAe,CACnC,YAAY;QACV,KAAK,EAAE,YAAY;QACnB,qBAAqB,CACxB,CAAA;IAED,OAAO,CACL,kBACM,SAAS,EACb,SAAS,EAAE,WAAW,CACpB
|
|
1
|
+
{"version":3,"file":"Main.js","sourceRoot":"","sources":["../../src/Main/Main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAGL,UAAU,GACX,MAAM,OAAO,CAAA;AAEd,OAAO,EAEL,qBAAqB,EACrB,eAAe,GAChB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAM/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EACnB,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,EAAE,EACF,GAAG,SAAS,EACF,EAAa,EAAE;IACzB,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAA;IAEtC,iEAAiE;IACjE,2DAA2D;IAC3D,MAAM,UAAU,GAAG,WAAW,EAAE,CAAA;IAEhC,MAAM,aAAa,GAAG,eAAe,CACnC,YAAY;QACV,KAAK,EAAE,YAAY;QACnB,qBAAqB,CACxB,CAAA;IAED,OAAO,CACL,kBACM,SAAS,EACb,SAAS,EAAE,WAAW,CACpB,6GAA6G,EAC7G,SAAS,CACV,EACD,EAAE,EAAE,EAAE,IAAI,KAAK,EAAE,MAAM,IAAI,UAAU,EACrC,QAAQ,EAAE,CAAC,CAAC,YAaZ,cACE,SAAS,EAAC,uFAAuF,EACjG,KAAK,EAAE,EAAE,aAAa,EAAE,YAEvB,QAAQ,GACL,GACD,CACR,CAAA;AACH,CAAC,CAAA"}
|
package/dist/Rail/Rail.js
CHANGED
|
@@ -57,7 +57,7 @@ const LANDMARK_ELEMENT = {
|
|
|
57
57
|
*/
|
|
58
58
|
export const Rail = ({ children, className, label, landmark = "complementary", side = "start", ...railProps }) => {
|
|
59
59
|
const Element = LANDMARK_ELEMENT[landmark];
|
|
60
|
-
return (_jsx(Element, { ...railProps, "aria-label": label, className: toClassName("flex min-w-0 gap-2 overflow-x-auto border-border-subtle p-4 md:row-start-2 md:w-64 md:flex-col md:overflow-x-visible", side === "start"
|
|
60
|
+
return (_jsx(Element, { ...railProps, "aria-label": label, className: toClassName("flex min-w-0 gap-2 overflow-x-auto border-border-subtle p-4 md:row-start-2 md:min-h-0 md:w-64 md:flex-col md:overflow-x-visible", side === "start"
|
|
61
61
|
? "row-start-2 border-b md:col-start-1 md:border-b-0 md:border-e"
|
|
62
62
|
: "row-start-4 border-t md:col-start-3 md:border-t-0 md:border-s", className), children: children }));
|
|
63
63
|
};
|
package/dist/Rail/Rail.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Rail.js","sourceRoot":"","sources":["../../src/Rail/Rail.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAY/C,MAAM,gBAAgB,GAGlB;IACF,aAAa,EAAE,OAAO;IACtB,UAAU,EAAE,KAAK;CAClB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EACnB,QAAQ,EACR,SAAS,EACT,KAAK,EACL,QAAQ,GAAG,eAAe,EAC1B,IAAI,GAAG,OAAO,EACd,GAAG,SAAS,EACF,EAAa,EAAE;IACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAE1C,OAAO,CACL,KAAC,OAAO,OACF,SAAS,gBACD,KAAK,EACjB,SAAS,EAAE,WAAW,CACpB,
|
|
1
|
+
{"version":3,"file":"Rail.js","sourceRoot":"","sources":["../../src/Rail/Rail.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAY/C,MAAM,gBAAgB,GAGlB;IACF,aAAa,EAAE,OAAO;IACtB,UAAU,EAAE,KAAK;CAClB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EACnB,QAAQ,EACR,SAAS,EACT,KAAK,EACL,QAAQ,GAAG,eAAe,EAC1B,IAAI,GAAG,OAAO,EACd,GAAG,SAAS,EACF,EAAa,EAAE;IACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAE1C,OAAO,CACL,KAAC,OAAO,OACF,SAAS,gBACD,KAAK,EACjB,SAAS,EAAE,WAAW,CACpB,iIAAiI,EACjI,IAAI,KAAK,OAAO;YACd,CAAC,CAAC,+DAA+D;YACjE,CAAC,CAAC,+DAA+D,EACnE,SAAS,CACV,YAEA,QAAQ,GACD,CACX,CAAA;AACH,CAAC,CAAA"}
|
package/dist/Shell/Shell.js
CHANGED
|
@@ -111,6 +111,6 @@ import { ShellContext } from "./shellContext.js";
|
|
|
111
111
|
export const Shell = ({ children, className, contentWidth = DEFAULT_CONTENT_WIDTH, skipLinkLabel = "Skip to main content", ...divProps }) => {
|
|
112
112
|
const mainId = useUniqueId();
|
|
113
113
|
const shellContext = useMemo(() => ({ contentWidth, mainId }), [contentWidth, mainId]);
|
|
114
|
-
return (_jsx(ShellContext.Provider, { value: shellContext, children: _jsxs("div", { ...divProps, className: toClassName("relative grid
|
|
114
|
+
return (_jsx(ShellContext.Provider, { value: shellContext, children: _jsxs("div", { ...divProps, className: toClassName("relative grid h-dvh grid-cols-1 grid-rows-[auto_auto_minmax(0,1fr)_auto] overflow-x-clip bg-surface-base text-content-primary md:grid-cols-[auto_minmax(0,1fr)_auto] md:grid-rows-[auto_minmax(0,1fr)]", className), children: [_jsx("a", { className: "fixed top-0 start-0 z-[var(--layer-toast)] m-3 -translate-y-24 rounded-md border border-border-subtle bg-surface-raised px-3 py-2 font-medium text-content-primary text-sm shadow-medium focus-visible:translate-y-0", href: `#${mainId}`, children: skipLinkLabel }), children] }) }));
|
|
115
115
|
};
|
|
116
116
|
//# sourceMappingURL=Shell.js.map
|
package/dist/Shell/Shell.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Shell.js","sourceRoot":"","sources":["../../src/Shell/Shell.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAGL,OAAO,GACR,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAEL,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAOhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EACpB,QAAQ,EACR,SAAS,EACT,YAAY,GAAG,qBAAqB,EACpC,aAAa,GAAG,sBAAsB,EACtC,GAAG,QAAQ,EACA,EAAa,EAAE;IAC1B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAA;IAE5B,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAChC,CAAC,YAAY,EAAE,MAAM,CAAC,CACvB,CAAA;IAED,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YACxC,kBACM,QAAQ,EACZ,SAAS,EAAE,WAAW,CACpB,
|
|
1
|
+
{"version":3,"file":"Shell.js","sourceRoot":"","sources":["../../src/Shell/Shell.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAGL,OAAO,GACR,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAEL,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAOhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EACpB,QAAQ,EACR,SAAS,EACT,YAAY,GAAG,qBAAqB,EACpC,aAAa,GAAG,sBAAsB,EACtC,GAAG,QAAQ,EACA,EAAa,EAAE;IAC1B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAA;IAE5B,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAChC,CAAC,YAAY,EAAE,MAAM,CAAC,CACvB,CAAA;IAED,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YACxC,kBACM,QAAQ,EACZ,SAAS,EAAE,WAAW,CACpB,wMAAwM,EACxM,SAAS,CACV,aAcD,YACE,SAAS,EAAC,sNAAsN,EAChO,IAAI,EAAE,IAAI,MAAM,EAAE,YAEjB,aAAa,GACZ,EAEH,QAAQ,IACL,GACgB,CACzB,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GridWindowProps, ScrollOwner } from "./virtualizedGridTypes.ts";
|
|
2
|
+
export declare const ElementGrid: <Item>(props: GridWindowProps<Item> & {
|
|
3
|
+
scrollOwner: Extract<ScrollOwner, {
|
|
4
|
+
kind: "element";
|
|
5
|
+
}>;
|
|
6
|
+
}) => import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=ElementGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ElementGrid.d.ts","sourceRoot":"","sources":["../../src/VirtualizedGrid/ElementGrid.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACZ,MAAM,2BAA2B,CAAA;AAElC,eAAO,MAAM,WAAW,GAAI,IAAI,EAC9B,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG;IAC7B,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;CACvD,gCA+BF,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { GridRows } from "./GridRows.js";
|
|
5
|
+
import { useScrollMargin } from "./virtualizedGridScroll.js";
|
|
6
|
+
export const ElementGrid = (props) => {
|
|
7
|
+
const { gridElement, scrollMargin } = useScrollMargin(props.scrollOwner);
|
|
8
|
+
const measureRow = useCallback((element) => element.getBoundingClientRect().height + props.gap, [props.gap]);
|
|
9
|
+
const rowVirtualizer = useVirtualizer({
|
|
10
|
+
count: props.rowCount,
|
|
11
|
+
estimateSize: () => props.itemBlockSize + props.gap,
|
|
12
|
+
getScrollElement: () => props.scrollOwner.element,
|
|
13
|
+
measureElement: measureRow,
|
|
14
|
+
overscan: props.overscanRows,
|
|
15
|
+
scrollMargin,
|
|
16
|
+
});
|
|
17
|
+
return (_jsx(GridRows, { ...props, gridElement: gridElement, measureElement: rowVirtualizer.measureElement, scrollMargin: scrollMargin, totalSize: rowVirtualizer.getTotalSize(), virtualRows: rowVirtualizer.getVirtualItems() }));
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=ElementGrid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ElementGrid.js","sourceRoot":"","sources":["../../src/VirtualizedGrid/ElementGrid.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAgB,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAM5D,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,KAEC,EACD,EAAE;IACF,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,eAAe,CACnD,KAAK,CAAC,WAAW,CAClB,CAAA;IAED,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,OAAgB,EAAE,EAAE,CACnB,OAAO,CAAC,qBAAqB,EAAE,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,EACpD,CAAC,KAAK,CAAC,GAAG,CAAC,CACZ,CAAA;IAED,MAAM,cAAc,GAAG,cAAc,CAAC;QACpC,KAAK,EAAE,KAAK,CAAC,QAAQ;QACrB,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,GAAG;QACnD,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO;QACjD,cAAc,EAAE,UAAU;QAC1B,QAAQ,EAAE,KAAK,CAAC,YAAY;QAC5B,YAAY;KACb,CAAC,CAAA;IAEF,OAAO,CACL,KAAC,QAAQ,OACH,KAAK,EACT,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,cAAc,CAAC,cAAc,EAC7C,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,cAAc,CAAC,YAAY,EAAE,EACxC,WAAW,EAAE,cAAc,CAAC,eAAe,EAAE,GAC7C,CACH,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GridRowsProps } from "./virtualizedGridTypes.ts";
|
|
2
|
+
/** The shared markup. Only the scroll observer differs between the two owners. */
|
|
3
|
+
export declare const GridRows: <Item>({ drawnColumns, gap, getItemKey, gridElement, items, label, measureElement, renderItem, scrollMargin, totalSize, virtualRows, }: GridRowsProps<Item>) => import("react").JSX.Element;
|
|
4
|
+
//# sourceMappingURL=GridRows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GridRows.d.ts","sourceRoot":"","sources":["../../src/VirtualizedGrid/GridRows.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAE9D,kFAAkF;AAClF,eAAO,MAAM,QAAQ,GAAI,IAAI,EAAG,iIAY7B,aAAa,CAAC,IAAI,CAAC,gCAyErB,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getContentMaxInlineSize } from "../AdaptiveGrid/chooseColumns.js";
|
|
3
|
+
/** The shared markup. Only the scroll observer differs between the two owners. */
|
|
4
|
+
export const GridRows = ({ drawnColumns, gap, getItemKey, gridElement, items, label, measureElement, renderItem, scrollMargin, totalSize, virtualRows, }) => {
|
|
5
|
+
const firstRow = virtualRows[0];
|
|
6
|
+
const lastRow = virtualRows[virtualRows.length - 1];
|
|
7
|
+
// Everything scrolled past, and everything still to come. The two
|
|
8
|
+
// numbers that stand in for the rows that do not exist.
|
|
9
|
+
const paddingBlockStart = firstRow?.start ?? 0;
|
|
10
|
+
const paddingBlockEnd = lastRow
|
|
11
|
+
? Math.max(0, totalSize - lastRow.end)
|
|
12
|
+
: 0;
|
|
13
|
+
return (_jsx("ul", { "aria-label": label, className: "grid w-full list-none p-0 [&>*]:min-w-0", ref: gridElement, style: {
|
|
14
|
+
gap: `${gap}px`,
|
|
15
|
+
gridTemplateColumns: `repeat(${drawnColumns}, minmax(0, 1fr))`,
|
|
16
|
+
maxInlineSize: getContentMaxInlineSize({
|
|
17
|
+
columns: drawnColumns,
|
|
18
|
+
}),
|
|
19
|
+
// Offset by `scrollMargin` because `start` is measured
|
|
20
|
+
// from the top of the scroll owner, and this padding is
|
|
21
|
+
// measured from the top of the grid.
|
|
22
|
+
paddingBlockEnd: `${paddingBlockEnd}px`,
|
|
23
|
+
paddingBlockStart: `${Math.max(0, paddingBlockStart - scrollMargin)}px`,
|
|
24
|
+
}, children: virtualRows.flatMap((row) => {
|
|
25
|
+
const firstIndex = row.index * drawnColumns;
|
|
26
|
+
return items
|
|
27
|
+
.slice(firstIndex, firstIndex + drawnColumns)
|
|
28
|
+
.map((item, offset) => {
|
|
29
|
+
const index = firstIndex + offset;
|
|
30
|
+
return (_jsx("li", { "aria-posinset": index + 1, "aria-setsize": items.length, "data-index": row.index,
|
|
31
|
+
// Measured on the leading cell alone. A CSS grid
|
|
32
|
+
// stretches every cell to its row's height, so
|
|
33
|
+
// one is enough — and measuring all of them
|
|
34
|
+
// would have the virtualizer record the same row
|
|
35
|
+
// once per column.
|
|
36
|
+
ref: offset === 0 ? measureElement : undefined, children: renderItem(item, index) }, getItemKey?.(item, index) ?? index));
|
|
37
|
+
});
|
|
38
|
+
}) }));
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=GridRows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GridRows.js","sourceRoot":"","sources":["../../src/VirtualizedGrid/GridRows.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAA;AAG1E,kFAAkF;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAQ,EAC9B,YAAY,EACZ,GAAG,EACH,UAAU,EACV,WAAW,EACX,KAAK,EACL,KAAK,EACL,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,EACT,WAAW,GACS,EAAE,EAAE;IACxB,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;IAC/B,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAEnD,kEAAkE;IAClE,wDAAwD;IACxD,MAAM,iBAAiB,GAAG,QAAQ,EAAE,KAAK,IAAI,CAAC,CAAA;IAE9C,MAAM,eAAe,GAAG,OAAO;QAC7B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC;QACtC,CAAC,CAAC,CAAC,CAAA;IAEL,OAAO,CACL,2BACc,KAAK,EACjB,SAAS,EAAC,yCAAyC,EACnD,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE;YACL,GAAG,EAAE,GAAG,GAAG,IAAI;YACf,mBAAmB,EAAE,UAAU,YAAY,mBAAmB;YAC9D,aAAa,EAAE,uBAAuB,CAAC;gBACrC,OAAO,EAAE,YAAY;aACtB,CAAC;YACF,uDAAuD;YACvD,wDAAwD;YACxD,qCAAqC;YACrC,eAAe,EAAE,GAAG,eAAe,IAAI;YACvC,iBAAiB,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,GAAG,YAAY,CAAC,IAAI;SACxE,YAEA,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAC3B,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,GAAG,YAAY,CAAA;YAE3C,OAAO,KAAK;iBACT,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,YAAY,CAAC;iBAC5C,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;gBACpB,MAAM,KAAK,GAAG,UAAU,GAAG,MAAM,CAAA;gBAEjC,OAAO,CACL,8BACiB,KAAK,GAAG,CAAC,kBACV,KAAK,CAAC,MAAM,gBAcd,GAAG,CAAC,KAAK;oBAErB,iDAAiD;oBACjD,+CAA+C;oBAC/C,4CAA4C;oBAC5C,iDAAiD;oBACjD,mBAAmB;oBACnB,GAAG,EACD,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,YAG1C,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,IAVnB,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,CAWpC,CACN,CAAA;YACH,CAAC,CAAC,CAAA;QACN,CAAC,CAAC,GACC,CACN,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -123,15 +123,13 @@ export type VirtualizedGridProps<Item> = {
|
|
|
123
123
|
* idea of the distance from one row to the next and the browser's
|
|
124
124
|
* the same number.
|
|
125
125
|
*
|
|
126
|
-
* ###
|
|
126
|
+
* ### It follows the page's existing scroll owner
|
|
127
127
|
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* `
|
|
132
|
-
*
|
|
133
|
-
* to be told how far down the document the grid starts, which is
|
|
134
|
-
* measured below.
|
|
128
|
+
* A standalone grid follows the browser window. Inside `Shell`, it
|
|
129
|
+
* follows `Main`, which is the shell's one vertical scroll region.
|
|
130
|
+
* It never creates a scroll box of its own. The cost is
|
|
131
|
+
* `scrollMargin`: the virtualizer has to be told how far down its
|
|
132
|
+
* scroll owner the grid starts, which is measured below.
|
|
135
133
|
*
|
|
136
134
|
* ### What windowing costs, and what is done about it
|
|
137
135
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualizedGrid.d.ts","sourceRoot":"","sources":["../../src/VirtualizedGrid/VirtualizedGrid.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VirtualizedGrid.d.ts","sourceRoot":"","sources":["../../src/VirtualizedGrid/VirtualizedGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAY9E,MAAM,MAAM,oBAAoB,CAAC,IAAI,IAAI;IACvC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,KACV,MAAM,GAAG,MAAM,CAAA;IACpB;;;;;;;;OAQG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB,kCAAkC;IAClC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,qBAAqB;IACrB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAA;IACpD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,eAAO,MAAM,eAAe,GAAI,IAAI,EAAG,kLAepC,oBAAoB,CAAC,IAAI,CAAC,KAAG,SAgE/B,CAAA"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { useCallback, useLayoutEffect, useRef, useState, } from "react";
|
|
4
|
-
import { getContentMaxInlineSize } from "../AdaptiveGrid/chooseColumns.js";
|
|
2
|
+
import { useLayoutEffect, useState } from "react";
|
|
5
3
|
import { useAdaptiveColumns } from "../AdaptiveGrid/useAdaptiveColumns.js";
|
|
6
4
|
import { toClassName } from "../toClassName.js";
|
|
5
|
+
import { ElementGrid } from "./ElementGrid.js";
|
|
7
6
|
import { DEFAULT_GRID_GAP_PX } from "./gridGap.js";
|
|
7
|
+
import { findScrollOwner } from "./virtualizedGridScroll.js";
|
|
8
|
+
import { WindowGrid } from "./WindowGrid.js";
|
|
8
9
|
/**
|
|
9
10
|
* `AdaptiveGrid`'s layout, with only the rows you can see mounted.
|
|
10
11
|
*
|
|
@@ -59,15 +60,13 @@ import { DEFAULT_GRID_GAP_PX } from "./gridGap.js";
|
|
|
59
60
|
* idea of the distance from one row to the next and the browser's
|
|
60
61
|
* the same number.
|
|
61
62
|
*
|
|
62
|
-
* ###
|
|
63
|
+
* ### It follows the page's existing scroll owner
|
|
63
64
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* `
|
|
68
|
-
*
|
|
69
|
-
* to be told how far down the document the grid starts, which is
|
|
70
|
-
* measured below.
|
|
65
|
+
* A standalone grid follows the browser window. Inside `Shell`, it
|
|
66
|
+
* follows `Main`, which is the shell's one vertical scroll region.
|
|
67
|
+
* It never creates a scroll box of its own. The cost is
|
|
68
|
+
* `scrollMargin`: the virtualizer has to be told how far down its
|
|
69
|
+
* scroll owner the grid starts, which is measured below.
|
|
71
70
|
*
|
|
72
71
|
* ### What windowing costs, and what is done about it
|
|
73
72
|
*
|
|
@@ -90,88 +89,32 @@ export const VirtualizedGrid = ({ blockSizeResolver, chromeBlockSize, className,
|
|
|
90
89
|
storageKey,
|
|
91
90
|
});
|
|
92
91
|
const drawnColumns = columns ?? layout.columns;
|
|
93
|
-
// Folded from what is DRAWN rather than read off the hook, so an
|
|
94
|
-
// override widens the page cap with it — the same rule
|
|
95
|
-
// `AdaptiveGrid` follows, and wrong in the same way if it does
|
|
96
|
-
// not.
|
|
97
|
-
const contentMaxInlineSize = getContentMaxInlineSize({
|
|
98
|
-
columns: drawnColumns,
|
|
99
|
-
});
|
|
100
92
|
const rowCount = Math.ceil(items.length / drawnColumns);
|
|
101
93
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* the top of the page, and the whole list sits shifted by the
|
|
107
|
-
* height of the header above it.
|
|
108
|
-
*
|
|
109
|
-
* State and not a ref, because it feeds `scrollMargin` and a
|
|
110
|
-
* change has to re-render. Measured on every commit rather than
|
|
111
|
-
* on a dependency list: a filter row that grows a line moves the
|
|
112
|
-
* grid down the page, and nothing in this component's own props
|
|
113
|
-
* would report that.
|
|
94
|
+
* Main owns vertical scrolling inside an app Shell. Older pages
|
|
95
|
+
* and a standalone grid still use the window. Resolve the owner
|
|
96
|
+
* from the actual tree rather than making every app wire a ref
|
|
97
|
+
* between two Charcuterie components.
|
|
114
98
|
*/
|
|
115
|
-
const
|
|
116
|
-
const [scrollMargin, setScrollMargin] = useState(0);
|
|
99
|
+
const [scrollOwner, setScrollOwner] = useState(null);
|
|
117
100
|
useLayoutEffect(() => {
|
|
118
|
-
const element =
|
|
101
|
+
const element = layout.containerRef.current;
|
|
119
102
|
if (!element) {
|
|
120
103
|
return;
|
|
121
104
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
estimateSize: () => itemBlockSize + gap,
|
|
137
|
-
measureElement: measureRow,
|
|
138
|
-
overscan: overscanRows,
|
|
139
|
-
scrollMargin,
|
|
140
|
-
});
|
|
141
|
-
const virtualRows = rowVirtualizer.getVirtualItems();
|
|
142
|
-
const firstRow = virtualRows[0];
|
|
143
|
-
const lastRow = virtualRows[virtualRows.length - 1];
|
|
144
|
-
// Everything scrolled past, and everything still to come. The two
|
|
145
|
-
// numbers that stand in for the rows that do not exist.
|
|
146
|
-
const paddingBlockStart = firstRow?.start ?? 0;
|
|
147
|
-
const paddingBlockEnd = lastRow
|
|
148
|
-
? Math.max(0, rowVirtualizer.getTotalSize() - lastRow.end)
|
|
149
|
-
: 0;
|
|
150
|
-
return (_jsx("div", { className: toClassName("flex justify-center", className), ref: layout.containerRef, children: _jsx("ul", { "aria-label": label, className: "grid w-full list-none p-0 [&>*]:min-w-0", ref: gridElement, style: {
|
|
151
|
-
gap: `${gap}px`,
|
|
152
|
-
gridTemplateColumns: `repeat(${drawnColumns}, minmax(0, 1fr))`,
|
|
153
|
-
maxInlineSize: contentMaxInlineSize,
|
|
154
|
-
// Offset by `scrollMargin` because `start` is measured
|
|
155
|
-
// from the top of the document, and this padding is
|
|
156
|
-
// measured from the top of the grid.
|
|
157
|
-
paddingBlockEnd: `${paddingBlockEnd}px`,
|
|
158
|
-
paddingBlockStart: `${Math.max(0, paddingBlockStart - scrollMargin)}px`,
|
|
159
|
-
}, children: virtualRows.flatMap((row) => {
|
|
160
|
-
const firstIndex = row.index * drawnColumns;
|
|
161
|
-
return items
|
|
162
|
-
.slice(firstIndex, firstIndex + drawnColumns)
|
|
163
|
-
.map((item, offset) => {
|
|
164
|
-
const index = firstIndex + offset;
|
|
165
|
-
return (_jsx("li", { "aria-posinset": index + 1, "aria-setsize": items.length, "data-index": row.index,
|
|
166
|
-
// Measured on the leading cell alone. A CSS grid
|
|
167
|
-
// stretches every cell to its row's height, so
|
|
168
|
-
// one is enough — and measuring all of them
|
|
169
|
-
// would have the virtualizer record the same row
|
|
170
|
-
// once per column.
|
|
171
|
-
ref: offset === 0
|
|
172
|
-
? rowVirtualizer.measureElement
|
|
173
|
-
: undefined, children: renderItem(item, index) }, getItemKey?.(item, index) ?? index));
|
|
174
|
-
});
|
|
175
|
-
}) }) }));
|
|
105
|
+
setScrollOwner(findScrollOwner(element));
|
|
106
|
+
}, [layout.containerRef]);
|
|
107
|
+
const gridProps = {
|
|
108
|
+
drawnColumns,
|
|
109
|
+
gap,
|
|
110
|
+
getItemKey,
|
|
111
|
+
itemBlockSize,
|
|
112
|
+
items,
|
|
113
|
+
label,
|
|
114
|
+
overscanRows,
|
|
115
|
+
renderItem,
|
|
116
|
+
rowCount,
|
|
117
|
+
};
|
|
118
|
+
return (_jsx("div", { className: toClassName("flex justify-center", className), ref: layout.containerRef, children: scrollOwner?.kind === "element" ? (_jsx(ElementGrid, { ...gridProps, scrollOwner: scrollOwner })) : scrollOwner?.kind === "window" ? (_jsx(WindowGrid, { ...gridProps })) : null }));
|
|
176
119
|
};
|
|
177
120
|
//# sourceMappingURL=VirtualizedGrid.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualizedGrid.js","sourceRoot":"","sources":["../../src/VirtualizedGrid/VirtualizedGrid.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"VirtualizedGrid.js","sourceRoot":"","sources":["../../src/VirtualizedGrid/VirtualizedGrid.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAA;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAmB,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAK5D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAkB,CAAA;AA2E7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAQ,EACrC,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,OAAO,EACP,GAAG,GAAG,mBAAmB,EACzB,UAAU,EACV,aAAa,EACb,KAAK,EACL,KAAK,EACL,UAAU,EACV,mBAAmB,EACnB,YAAY,GAAG,CAAC,EAChB,UAAU,EACV,UAAU,GACiB,EAAa,EAAE;IAC1C,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,iBAAiB;QACjB,eAAe;QACf,aAAa;QACb,SAAS,EAAE,KAAK,CAAC,MAAM;QACvB,cAAc,EAAE,UAAU;QAC1B,mBAAmB;QACnB,UAAU;KACX,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,OAAO,IAAI,MAAM,CAAC,OAAO,CAAA;IAE9C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,CAAA;IAEvD;;;;;OAKG;IACH,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GACjC,QAAQ,CAAqB,IAAI,CAAC,CAAA;IAEpC,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAA;QAE3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAM;QACR,CAAC;QAED,cAAc,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAA;IAC1C,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;IAEzB,MAAM,SAAS,GAA0B;QACvC,YAAY;QACZ,GAAG;QACH,UAAU;QACV,aAAa;QACb,KAAK;QACL,KAAK;QACL,YAAY;QACZ,UAAU;QACV,QAAQ;KACT,CAAA;IAED,OAAO,CACL,cACE,SAAS,EAAE,WAAW,CACpB,qBAAqB,EACrB,SAAS,CACV,EACD,GAAG,EAAE,MAAM,CAAC,YAAY,YAEvB,WAAW,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CACjC,KAAC,WAAW,OACN,SAAS,EACb,WAAW,EAAE,WAAW,GACxB,CACH,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CACnC,KAAC,UAAU,OAAK,SAAS,GAAI,CAC9B,CAAC,CAAC,CAAC,IAAI,GACJ,CACP,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WindowGrid.d.ts","sourceRoot":"","sources":["../../src/VirtualizedGrid/WindowGrid.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAEhE,eAAO,MAAM,UAAU,GAAI,IAAI,EAC7B,OAAO,eAAe,CAAC,IAAI,CAAC,gCA8B7B,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useWindowVirtualizer } from "@tanstack/react-virtual";
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { GridRows } from "./GridRows.js";
|
|
5
|
+
import { useScrollMargin } from "./virtualizedGridScroll.js";
|
|
6
|
+
export const WindowGrid = (props) => {
|
|
7
|
+
const { gridElement, scrollMargin } = useScrollMargin({
|
|
8
|
+
kind: "window",
|
|
9
|
+
});
|
|
10
|
+
const measureRow = useCallback((element) => element.getBoundingClientRect().height + props.gap, [props.gap]);
|
|
11
|
+
const rowVirtualizer = useWindowVirtualizer({
|
|
12
|
+
count: props.rowCount,
|
|
13
|
+
estimateSize: () => props.itemBlockSize + props.gap,
|
|
14
|
+
measureElement: measureRow,
|
|
15
|
+
overscan: props.overscanRows,
|
|
16
|
+
scrollMargin,
|
|
17
|
+
});
|
|
18
|
+
return (_jsx(GridRows, { ...props, gridElement: gridElement, measureElement: rowVirtualizer.measureElement, scrollMargin: scrollMargin, totalSize: rowVirtualizer.getTotalSize(), virtualRows: rowVirtualizer.getVirtualItems() }));
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=WindowGrid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WindowGrid.js","sourceRoot":"","sources":["../../src/VirtualizedGrid/WindowGrid.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAgB,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAG5D,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,KAA4B,EAC5B,EAAE;IACF,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,eAAe,CAAC;QACpD,IAAI,EAAE,QAAQ;KACf,CAAC,CAAA;IAEF,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,OAAgB,EAAE,EAAE,CACnB,OAAO,CAAC,qBAAqB,EAAE,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,EACpD,CAAC,KAAK,CAAC,GAAG,CAAC,CACZ,CAAA;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC;QAC1C,KAAK,EAAE,KAAK,CAAC,QAAQ;QACrB,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,GAAG;QACnD,cAAc,EAAE,UAAU;QAC1B,QAAQ,EAAE,KAAK,CAAC,YAAY;QAC5B,YAAY;KACb,CAAC,CAAA;IAEF,OAAO,CACL,KAAC,QAAQ,OACH,KAAK,EACT,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,cAAc,CAAC,cAAc,EAC7C,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,cAAc,CAAC,YAAY,EAAE,EACxC,WAAW,EAAE,cAAc,CAAC,eAAe,EAAE,GAC7C,CACH,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ScrollOwner } from "./virtualizedGridTypes.ts";
|
|
2
|
+
/**
|
|
3
|
+
* The closest ancestor that owns vertical scrolling.
|
|
4
|
+
*
|
|
5
|
+
* The computed value is enough. An `overflow-y:auto` ancestor can
|
|
6
|
+
* be shorter than its contents only AFTER this grid installs its
|
|
7
|
+
* virtual spacer, so requiring `scrollHeight > clientHeight` here
|
|
8
|
+
* would miss the owner on the first commit and create the exact
|
|
9
|
+
* document scrollbar this lookup prevents.
|
|
10
|
+
*/
|
|
11
|
+
export declare const findScrollOwner: (element: HTMLElement) => ScrollOwner;
|
|
12
|
+
/**
|
|
13
|
+
* The offset from the scroll owner's content origin to the grid.
|
|
14
|
+
*
|
|
15
|
+
* Both formulas stay stable while their owner scrolls: the grid's
|
|
16
|
+
* viewport-relative top falls by the same amount that `scrollY` or
|
|
17
|
+
* `scrollTop` rises. The element path subtracts its border because
|
|
18
|
+
* a scroll offset starts at the padding edge, not at the outer
|
|
19
|
+
* border returned by `getBoundingClientRect()`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const useScrollMargin: (scrollOwner: ScrollOwner) => {
|
|
22
|
+
gridElement: import("react").RefObject<HTMLUListElement | null>;
|
|
23
|
+
scrollMargin: number;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=virtualizedGridScroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualizedGridScroll.d.ts","sourceRoot":"","sources":["../../src/VirtualizedGrid/virtualizedGridScroll.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAE5D;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAC1B,SAAS,WAAW,KACnB,WAcF,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAC1B,aAAa,WAAW;;;CA2BzB,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The closest ancestor that owns vertical scrolling.
|
|
4
|
+
*
|
|
5
|
+
* The computed value is enough. An `overflow-y:auto` ancestor can
|
|
6
|
+
* be shorter than its contents only AFTER this grid installs its
|
|
7
|
+
* virtual spacer, so requiring `scrollHeight > clientHeight` here
|
|
8
|
+
* would miss the owner on the first commit and create the exact
|
|
9
|
+
* document scrollbar this lookup prevents.
|
|
10
|
+
*/
|
|
11
|
+
export const findScrollOwner = (element) => {
|
|
12
|
+
let ancestor = element.parentElement;
|
|
13
|
+
while (ancestor) {
|
|
14
|
+
const overflow = getComputedStyle(ancestor).overflowY;
|
|
15
|
+
if (overflow === "auto" || overflow === "scroll") {
|
|
16
|
+
return { element: ancestor, kind: "element" };
|
|
17
|
+
}
|
|
18
|
+
ancestor = ancestor.parentElement;
|
|
19
|
+
}
|
|
20
|
+
return { kind: "window" };
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The offset from the scroll owner's content origin to the grid.
|
|
24
|
+
*
|
|
25
|
+
* Both formulas stay stable while their owner scrolls: the grid's
|
|
26
|
+
* viewport-relative top falls by the same amount that `scrollY` or
|
|
27
|
+
* `scrollTop` rises. The element path subtracts its border because
|
|
28
|
+
* a scroll offset starts at the padding edge, not at the outer
|
|
29
|
+
* border returned by `getBoundingClientRect()`.
|
|
30
|
+
*/
|
|
31
|
+
export const useScrollMargin = (scrollOwner) => {
|
|
32
|
+
const gridElement = useRef(null);
|
|
33
|
+
const [scrollMargin, setScrollMargin] = useState(0);
|
|
34
|
+
useLayoutEffect(() => {
|
|
35
|
+
const element = gridElement.current;
|
|
36
|
+
if (!element) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const gridTop = element.getBoundingClientRect().top;
|
|
40
|
+
const next = scrollOwner.kind === "window"
|
|
41
|
+
? gridTop + window.scrollY
|
|
42
|
+
: gridTop -
|
|
43
|
+
scrollOwner.element.getBoundingClientRect().top -
|
|
44
|
+
scrollOwner.element.clientTop +
|
|
45
|
+
scrollOwner.element.scrollTop;
|
|
46
|
+
setScrollMargin((current) => current === next ? current : next);
|
|
47
|
+
});
|
|
48
|
+
return { gridElement, scrollMargin };
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=virtualizedGridScroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualizedGridScroll.js","sourceRoot":"","sources":["../../src/VirtualizedGrid/virtualizedGridScroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAIzD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,OAAoB,EACP,EAAE;IACf,IAAI,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAA;IAEpC,OAAO,QAAQ,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAA;QAErD,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;QAC/C,CAAC;QAED,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAA;IACnC,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;AAC3B,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,WAAwB,EACxB,EAAE;IACF,MAAM,WAAW,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAA;IAClD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEnD,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAA;QAEnC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAA;QACnD,MAAM,IAAI,GACR,WAAW,CAAC,IAAI,KAAK,QAAQ;YAC3B,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO;YAC1B,CAAC,CAAC,OAAO;gBACP,WAAW,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,GAAG;gBAC/C,WAAW,CAAC,OAAO,CAAC,SAAS;gBAC7B,WAAW,CAAC,OAAO,CAAC,SAAS,CAAA;QAEnC,eAAe,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1B,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAClC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAA;AACtC,CAAC,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { VirtualItem } from "@tanstack/react-virtual";
|
|
2
|
+
import type { ReactNode, RefObject } from "react";
|
|
3
|
+
export type ScrollOwner = {
|
|
4
|
+
kind: "element";
|
|
5
|
+
element: HTMLElement;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "window";
|
|
8
|
+
};
|
|
9
|
+
export type GridWindowProps<Item> = {
|
|
10
|
+
drawnColumns: number;
|
|
11
|
+
gap: number;
|
|
12
|
+
getItemKey?: (item: Item, index: number) => string | number;
|
|
13
|
+
itemBlockSize: number;
|
|
14
|
+
items: readonly Item[];
|
|
15
|
+
label?: string;
|
|
16
|
+
overscanRows: number;
|
|
17
|
+
renderItem: (item: Item, index: number) => ReactNode;
|
|
18
|
+
rowCount: number;
|
|
19
|
+
};
|
|
20
|
+
export type GridRowsProps<Item> = Omit<GridWindowProps<Item>, "itemBlockSize" | "overscanRows" | "rowCount"> & {
|
|
21
|
+
gridElement: RefObject<HTMLUListElement | null>;
|
|
22
|
+
measureElement: (element: Element | null) => void;
|
|
23
|
+
scrollMargin: number;
|
|
24
|
+
totalSize: number;
|
|
25
|
+
virtualRows: VirtualItem[];
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=virtualizedGridTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualizedGridTypes.d.ts","sourceRoot":"","sources":["../../src/VirtualizedGrid/virtualizedGridTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjD,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAEtB,MAAM,MAAM,eAAe,CAAC,IAAI,IAAI;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,KACV,MAAM,GAAG,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAA;IACpD,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,aAAa,CAAC,IAAI,IAAI,IAAI,CACpC,eAAe,CAAC,IAAI,CAAC,EACrB,eAAe,GAAG,cAAc,GAAG,UAAU,CAC9C,GAAG;IACF,WAAW,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC/C,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAA;IACjD,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,WAAW,EAAE,CAAA;CAC3B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualizedGridTypes.js","sourceRoot":"","sources":["../../src/VirtualizedGrid/virtualizedGridTypes.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
package/src/Main/Main.tsx
CHANGED
|
@@ -146,7 +146,7 @@ export const Main = ({
|
|
|
146
146
|
<main
|
|
147
147
|
{...mainProps}
|
|
148
148
|
className={toClassName(
|
|
149
|
-
"col-start-1 row-start-3 min-w-0 md:col-start-2 md:row-start-2",
|
|
149
|
+
"charcuterie-scrollbar col-start-1 row-start-3 min-h-0 min-w-0 overflow-y-auto md:col-start-2 md:row-start-2",
|
|
150
150
|
className,
|
|
151
151
|
)}
|
|
152
152
|
id={id ?? shell?.mainId ?? fallbackId}
|
package/src/Rail/Rail.tsx
CHANGED
|
@@ -89,7 +89,7 @@ export const Rail = ({
|
|
|
89
89
|
{...railProps}
|
|
90
90
|
aria-label={label}
|
|
91
91
|
className={toClassName(
|
|
92
|
-
"flex min-w-0 gap-2 overflow-x-auto border-border-subtle p-4 md:row-start-2 md:w-64 md:flex-col md:overflow-x-visible",
|
|
92
|
+
"flex min-w-0 gap-2 overflow-x-auto border-border-subtle p-4 md:row-start-2 md:min-h-0 md:w-64 md:flex-col md:overflow-x-visible",
|
|
93
93
|
side === "start"
|
|
94
94
|
? "row-start-2 border-b md:col-start-1 md:border-b-0 md:border-e"
|
|
95
95
|
: "row-start-4 border-t md:col-start-3 md:border-t-0 md:border-s",
|
package/src/Shell/Shell.mdx
CHANGED
|
@@ -127,6 +127,14 @@ rail that only changes *position* uses a media query and nothing else.
|
|
|
127
127
|
|
|
128
128
|
<Canvas of={ShellStories.Responsive} />
|
|
129
129
|
|
|
130
|
+
## The page content scrolls; the frame stays available
|
|
131
|
+
|
|
132
|
+
The shell fills the viewport. `Main` is the only vertical scroll region, so a long page does
|
|
133
|
+
not scroll the header or either rail away. This keeps navigation actions available, including
|
|
134
|
+
an app's rail-collapse control. The rail is not a second vertical scroll area.
|
|
135
|
+
|
|
136
|
+
<Canvas of={ShellStories.Scrollable} />
|
|
137
|
+
|
|
130
138
|
## It does not scroll sideways, and that is a test
|
|
131
139
|
|
|
132
140
|
Plex Channels' narrow view scrolls left and right as wide as its content area. The usual
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
PageContent,
|
|
11
11
|
RailDetail,
|
|
12
12
|
RailNavigation,
|
|
13
|
+
ScrollFiller,
|
|
13
14
|
} from "../shell.storyHelpers.tsx"
|
|
14
15
|
import { Shell } from "./Shell.tsx"
|
|
15
16
|
|
|
@@ -183,3 +184,26 @@ export const Interactive: Story = {
|
|
|
183
184
|
</Shell>
|
|
184
185
|
),
|
|
185
186
|
}
|
|
187
|
+
|
|
188
|
+
/** A long page leaves the header and rail in place. */
|
|
189
|
+
export const Scrollable: Story = {
|
|
190
|
+
render: (shellProps) => (
|
|
191
|
+
<Shell {...shellProps}>
|
|
192
|
+
<Header
|
|
193
|
+
actions={<HeaderSchemeToggle />}
|
|
194
|
+
heading="Rip Deck"
|
|
195
|
+
/>
|
|
196
|
+
|
|
197
|
+
<Rail label="Sections" landmark="navigation">
|
|
198
|
+
<RailNavigation />
|
|
199
|
+
</Rail>
|
|
200
|
+
|
|
201
|
+
<Main>
|
|
202
|
+
<PageContent />
|
|
203
|
+
<div style={{ minBlockSize: "150vh" }}>
|
|
204
|
+
<ScrollFiller />
|
|
205
|
+
</div>
|
|
206
|
+
</Main>
|
|
207
|
+
</Shell>
|
|
208
|
+
),
|
|
209
|
+
}
|