@charcuterie/ui 4.20.1 → 4.22.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/LICENSE +21 -0
- package/README.md +6 -6
- package/dist/AdaptiveGrid/AdaptiveGrid.d.ts +4 -1
- package/dist/AdaptiveGrid/AdaptiveGrid.d.ts.map +1 -1
- package/dist/AdaptiveGrid/AdaptiveGrid.js +3 -1
- package/dist/AdaptiveGrid/AdaptiveGrid.js.map +1 -1
- package/dist/AdaptiveGrid/chooseColumns.d.ts +10 -2
- package/dist/AdaptiveGrid/chooseColumns.d.ts.map +1 -1
- package/dist/AdaptiveGrid/chooseColumns.js +10 -3
- package/dist/AdaptiveGrid/chooseColumns.js.map +1 -1
- package/dist/AdaptiveGrid/useAdaptiveColumns.d.ts +6 -2
- package/dist/AdaptiveGrid/useAdaptiveColumns.d.ts.map +1 -1
- package/dist/AdaptiveGrid/useAdaptiveColumns.js +4 -1
- package/dist/AdaptiveGrid/useAdaptiveColumns.js.map +1 -1
- package/dist/ComparisonChart/ComparisonChart.d.ts +12 -0
- package/dist/ComparisonChart/ComparisonChart.d.ts.map +1 -0
- package/dist/ComparisonChart/ComparisonChart.js +64 -0
- package/dist/ComparisonChart/ComparisonChart.js.map +1 -0
- package/dist/Lightbox/Lightbox.d.ts +10 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +46 -3
- package/dist/Lightbox/Lightbox.js.map +1 -1
- package/dist/Overlay/useAnchoredOverlay.d.ts +2 -2
- package/dist/TableColumns/TableColumns.d.ts +14 -0
- package/dist/TableColumns/TableColumns.d.ts.map +1 -0
- package/dist/TableColumns/TableColumns.js +19 -0
- package/dist/TableColumns/TableColumns.js.map +1 -0
- package/dist/VirtualizedGrid/VirtualizedGrid.d.ts +4 -1
- package/dist/VirtualizedGrid/VirtualizedGrid.d.ts.map +1 -1
- package/dist/VirtualizedGrid/VirtualizedGrid.js +3 -1
- package/dist/VirtualizedGrid/VirtualizedGrid.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +12 -9
- package/src/AdaptiveGrid/AdaptiveGrid.mdx +10 -0
- package/src/AdaptiveGrid/AdaptiveGrid.stories.tsx +17 -0
- package/src/AdaptiveGrid/AdaptiveGrid.test.tsx +36 -2
- package/src/AdaptiveGrid/AdaptiveGrid.tsx +6 -0
- package/src/AdaptiveGrid/chooseColumns.ts +29 -1
- package/src/AdaptiveGrid/useAdaptiveColumns.ts +13 -1
- package/src/ComparisonChart/ComparisonChart.mdx +14 -0
- package/src/ComparisonChart/ComparisonChart.stories.tsx +85 -0
- package/src/ComparisonChart/ComparisonChart.test.tsx +33 -0
- package/src/ComparisonChart/ComparisonChart.tsx +161 -0
- package/src/CopyButton/CopyButton.test.tsx +25 -12
- package/src/Dialog/Dialog.test.tsx +38 -8
- package/src/LaneTimeline/LaneTimelineBar.tsx +3 -3
- package/src/Lightbox/Lightbox.mdx +9 -0
- package/src/Lightbox/Lightbox.stories.tsx +26 -0
- package/src/Lightbox/Lightbox.test.tsx +53 -0
- package/src/Lightbox/Lightbox.tsx +109 -5
- package/src/PortraitTiles/PortraitTiles.test.tsx +17 -11
- package/src/TableColumns/TableColumns.mdx +14 -0
- package/src/TableColumns/TableColumns.stories.tsx +81 -0
- package/src/TableColumns/TableColumns.test.tsx +35 -0
- package/src/TableColumns/TableColumns.tsx +93 -0
- package/src/VirtualizedGrid/VirtualizedGrid.test.tsx +21 -8
- package/src/VirtualizedGrid/VirtualizedGrid.tsx +6 -0
- package/src/board.storyHelpers.tsx +7 -1
- package/src/htmlEditor/HtmlEditor.test.tsx +32 -2
- package/src/index.ts +11 -1
- package/src/markdownEditorCodeMirror/MarkdownView.test.tsx +28 -10
- package/src/mdxReferences.test.ts +1 -1
- package/src/sourceRules.test.ts +2 -1
- package/src/vitestProvidedContext.d.ts +6 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kevin Ghadyani
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -210,7 +210,7 @@ M5 spent an hour on the second and third of these, so M5b and M6 do not have to:
|
|
|
210
210
|
// the PROJECT ROOT — `ui` declares its siblings as `workspace:*`, and that
|
|
211
211
|
// descriptor cannot resolve outside charcuterie's own workspace. Bare keys, not
|
|
212
212
|
// `@charcuterie/ui/@charcuterie/tokens`: the scoped form yields a different
|
|
213
|
-
// locator string from the app's own dependency on the same directory, and
|
|
213
|
+
// locator string from the app's own dependency on the same directory, and pnpm
|
|
214
214
|
// rejects the pair as conflicting.
|
|
215
215
|
"resolutions": {
|
|
216
216
|
"@charcuterie/logic": "portal:../charcuterie/packages/logic",
|
|
@@ -233,7 +233,7 @@ TypeError: Cannot read properties of null (reading 'useRef')
|
|
|
233
233
|
```
|
|
234
234
|
|
|
235
235
|
which mentions neither symlinks nor React identity. Keep the line after publish: it costs
|
|
236
|
-
nothing with one copy, and it is the difference between a working `
|
|
236
|
+
nothing with one copy, and it is the difference between a working `pnpm link` session and
|
|
237
237
|
an hour of confusion.
|
|
238
238
|
|
|
239
239
|
## How a component is put together
|
|
@@ -256,9 +256,9 @@ and fails on any candidate Tailwind cannot generate.
|
|
|
256
256
|
## Tests
|
|
257
257
|
|
|
258
258
|
```bash
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
pnpm vitest run --project ui # Node: class maps, status switches, clamping, boundaries
|
|
260
|
+
pnpm vitest run --project ui-dom # chromium: Component.test.tsx — behaviour, keyboard, ARIA
|
|
261
|
+
pnpm vitest run --project storybook # chromium: every story renders, axe at test: "error"
|
|
262
262
|
```
|
|
263
263
|
|
|
264
264
|
**Stories are demos and carry no assertions**
|
|
@@ -319,7 +319,7 @@ rename breaks only the rendered page).
|
|
|
319
319
|
from effects, so before those run a `RovingFocus` has no active value and a
|
|
320
320
|
`SinglePicker` / `VisibilityGroup` has no selected key — only a pending one. Two of M4's
|
|
321
321
|
four bugs were exactly that, and the isolated story runner saw neither —
|
|
322
|
-
`
|
|
322
|
+
`pnpm smoke:storybook` did.
|
|
323
323
|
7. **If it declares `@container`, every `StoryCell` holding it needs `align="stretch"`.**
|
|
324
324
|
`container-type: inline-size` forbids the element from being sized by its own
|
|
325
325
|
contents, so a default (shrink-to-fit) cell collapses it to min-content and every
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import type { GridLayout } from "./chooseColumns.ts";
|
|
2
3
|
import type { BlockSizeResolver } from "./useAdaptiveColumns.ts";
|
|
3
4
|
export type AdaptiveGridProps = {
|
|
4
5
|
/**
|
|
@@ -35,6 +36,8 @@ export type AdaptiveGridProps = {
|
|
|
35
36
|
* would be worse than one that is an item out.
|
|
36
37
|
*/
|
|
37
38
|
itemCount?: number;
|
|
39
|
+
/** Fill the container with readable columns instead of spending height first. */
|
|
40
|
+
layout?: GridLayout;
|
|
38
41
|
/** The most columns the automatic answer will take. */
|
|
39
42
|
maxColumns?: number;
|
|
40
43
|
/** The narrowest a column may be, in CSS px. */
|
|
@@ -90,5 +93,5 @@ export type AdaptiveGridProps = {
|
|
|
90
93
|
* need every count to survive the scan; an inline style needs
|
|
91
94
|
* none.
|
|
92
95
|
*/
|
|
93
|
-
export declare const AdaptiveGrid: ({ blockSizeResolver, children, chromeBlockSize, className, columns, itemBlockSize, itemCount, maxColumns, minColumnInlineSize, storageKey, }: AdaptiveGridProps) => ReactNode;
|
|
96
|
+
export declare const AdaptiveGrid: ({ blockSizeResolver, children, chromeBlockSize, className, columns, itemBlockSize, itemCount, layout: gridLayout, maxColumns, minColumnInlineSize, storageKey, }: AdaptiveGridProps) => ReactNode;
|
|
94
97
|
//# sourceMappingURL=AdaptiveGrid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdaptiveGrid.d.ts","sourceRoot":"","sources":["../../src/AdaptiveGrid/AdaptiveGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"AdaptiveGrid.d.ts","sourceRoot":"","sources":["../../src/AdaptiveGrid/AdaptiveGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAGhE,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,QAAQ,EAAE,SAAS,CAAA;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,eAAO,MAAM,YAAY,GAAI,kKAY1B,iBAAiB,KAAG,SAyCtB,CAAA"}
|
|
@@ -48,12 +48,13 @@ import { useAdaptiveColumns } from "./useAdaptiveColumns.js";
|
|
|
48
48
|
* need every count to survive the scan; an inline style needs
|
|
49
49
|
* none.
|
|
50
50
|
*/
|
|
51
|
-
export const AdaptiveGrid = ({ blockSizeResolver, children, chromeBlockSize, className, columns, itemBlockSize, itemCount, maxColumns, minColumnInlineSize, storageKey, }) => {
|
|
51
|
+
export const AdaptiveGrid = ({ blockSizeResolver, children, chromeBlockSize, className, columns, itemBlockSize, itemCount, layout: gridLayout = "height-first", maxColumns, minColumnInlineSize, storageKey, }) => {
|
|
52
52
|
const layout = useAdaptiveColumns({
|
|
53
53
|
blockSizeResolver,
|
|
54
54
|
chromeBlockSize,
|
|
55
55
|
itemBlockSize,
|
|
56
56
|
itemCount: itemCount ?? Children.count(children),
|
|
57
|
+
layout: gridLayout,
|
|
57
58
|
maxAutoColumns: maxColumns,
|
|
58
59
|
minColumnInlineSize,
|
|
59
60
|
storageKey,
|
|
@@ -64,6 +65,7 @@ export const AdaptiveGrid = ({ blockSizeResolver, children, chromeBlockSize, cla
|
|
|
64
65
|
// a one-column cap is the same bug as no cap at all, upside down.
|
|
65
66
|
const contentMaxInlineSize = getContentMaxInlineSize({
|
|
66
67
|
columns: drawnColumns,
|
|
68
|
+
layout: gridLayout,
|
|
67
69
|
});
|
|
68
70
|
return (_jsx("div", { className: toClassName("flex justify-center", className), ref: layout.containerRef, children: _jsx("div", { className: "grid w-full gap-4 [&>*]:min-w-0", style: {
|
|
69
71
|
gridTemplateColumns: `repeat(${drawnColumns}, minmax(0, 1fr))`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdaptiveGrid.js","sourceRoot":"","sources":["../../src/AdaptiveGrid/AdaptiveGrid.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"AdaptiveGrid.js","sourceRoot":"","sources":["../../src/AdaptiveGrid/AdaptiveGrid.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAkD5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAC3B,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,SAAS,EACT,OAAO,EACP,aAAa,EACb,SAAS,EACT,MAAM,EAAE,UAAU,GAAG,cAAc,EACnC,UAAU,EACV,mBAAmB,EACnB,UAAU,GACQ,EAAa,EAAE;IACjC,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,iBAAiB;QACjB,eAAe;QACf,aAAa;QACb,SAAS,EAAE,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;QAChD,MAAM,EAAE,UAAU;QAClB,cAAc,EAAE,UAAU;QAC1B,mBAAmB;QACnB,UAAU;KACX,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,OAAO,IAAI,MAAM,CAAC,OAAO,CAAA;IAE9C,iEAAiE;IACjE,kEAAkE;IAClE,kEAAkE;IAClE,MAAM,oBAAoB,GAAG,uBAAuB,CAAC;QACnD,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,UAAU;KACnB,CAAC,CAAA;IAEF,OAAO,CACL,cACE,SAAS,EAAE,WAAW,CACpB,qBAAqB,EACrB,SAAS,CACV,EACD,GAAG,EAAE,MAAM,CAAC,YAAY,YAExB,cACE,SAAS,EAAC,iCAAiC,EAC3C,KAAK,EAAE;gBACL,mBAAmB,EAAE,UAAU,YAAY,mBAAmB;gBAC9D,aAAa,EAAE,oBAAoB;aACpC,YAEA,QAAQ,GACL,GACF,CACP,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -98,11 +98,13 @@ export declare const DEFAULT_MIN_COLUMN_INLINE_SIZE_PX: number;
|
|
|
98
98
|
* `"auto"`, or the number of columns a person explicitly asked for.
|
|
99
99
|
*/
|
|
100
100
|
export type ColumnChoice = "auto" | number;
|
|
101
|
+
/** Fill is an explicit width-first layout for media galleries and fleets. */
|
|
102
|
+
export type GridLayout = "height-first" | "fill";
|
|
101
103
|
/**
|
|
102
104
|
* The column count the automatic rule wants, for one measured space
|
|
103
105
|
* and one set of items.
|
|
104
106
|
*/
|
|
105
|
-
export declare const chooseColumns: ({ availableBlockSize, availableInlineSize, chromeBlockSize, itemBlockSize, itemCount, maxColumns, minColumnInlineSize, }: {
|
|
107
|
+
export declare const chooseColumns: ({ availableBlockSize, availableInlineSize, chromeBlockSize, itemBlockSize, itemCount, gap, layout, maxColumns, minColumnInlineSize, }: {
|
|
106
108
|
/**
|
|
107
109
|
* The block size the layout has to spend, in CSS px — the
|
|
108
110
|
* viewport's, not the grid's.
|
|
@@ -153,6 +155,10 @@ export declare const chooseColumns: ({ availableBlockSize, availableInlineSize,
|
|
|
153
155
|
* finished loading would be worse than one that is an item out.
|
|
154
156
|
*/
|
|
155
157
|
itemCount: number;
|
|
158
|
+
/** Height-first by default; fill spends the available container width. */
|
|
159
|
+
layout?: GridLayout;
|
|
160
|
+
/** Space between tracks, in CSS px, used by fill. */
|
|
161
|
+
gap?: number;
|
|
156
162
|
/** @see DEFAULT_MAX_AUTO_COLUMNS */
|
|
157
163
|
maxColumns?: number;
|
|
158
164
|
/** @see DEFAULT_MIN_COLUMN_INLINE_SIZE_PX */
|
|
@@ -183,12 +189,14 @@ export declare const chooseColumns: ({ availableBlockSize, availableInlineSize,
|
|
|
183
189
|
* dense tables and an app of prose disagree about a measure and
|
|
184
190
|
* neither is wrong.
|
|
185
191
|
*/
|
|
186
|
-
export declare const getContentMaxInlineSize: ({ columnInlineSize, columns, gutterInlineSize, singleInlineSize, }: {
|
|
192
|
+
export declare const getContentMaxInlineSize: ({ columnInlineSize, columns, gutterInlineSize, layout, singleInlineSize, }: {
|
|
187
193
|
/** What one column is worth, once there are several. */
|
|
188
194
|
columnInlineSize?: string;
|
|
189
195
|
columns: number;
|
|
190
196
|
/** Slack added on top of a multi-column cap, for the gaps. */
|
|
191
197
|
gutterInlineSize?: string;
|
|
198
|
+
/** Fill uses all available width once there are multiple columns. */
|
|
199
|
+
layout?: GridLayout;
|
|
192
200
|
/** The cap when there is only one column. */
|
|
193
201
|
singleInlineSize?: string;
|
|
194
202
|
}) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chooseColumns.d.ts","sourceRoot":"","sources":["../../src/AdaptiveGrid/chooseColumns.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,iCAAiC,QACH,CAAA;AAE3C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAA;AAE1C;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,
|
|
1
|
+
{"version":3,"file":"chooseColumns.d.ts","sourceRoot":"","sources":["../../src/AdaptiveGrid/chooseColumns.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,iCAAiC,QACH,CAAA;AAE3C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAA;AAE1C,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,MAAM,CAAA;AAEhD;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,uIAU3B;IACD;;;;;;;;OAQG;IACH,kBAAkB,EAAE,MAAM,CAAA;IAC1B;;;;;;;;;;;;OAYG;IACH,mBAAmB,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;;;;OAUG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,KAAG,MA0CH,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,uBAAuB,GAAI,4EAMrC;IACD,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,qEAAqE;IACrE,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,KAAG,MAK+F,CAAA;AAEnG;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,iBAE9B;IACD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,KAAG,YAAY,EAMf,CAAA"}
|
|
@@ -99,13 +99,18 @@ export const DEFAULT_MIN_COLUMN_INLINE_SIZE_PX = Number.parseFloat(containerQuer
|
|
|
99
99
|
* The column count the automatic rule wants, for one measured space
|
|
100
100
|
* and one set of items.
|
|
101
101
|
*/
|
|
102
|
-
export const chooseColumns = ({ availableBlockSize, availableInlineSize, chromeBlockSize = 0, itemBlockSize, itemCount, maxColumns = DEFAULT_MAX_AUTO_COLUMNS, minColumnInlineSize = DEFAULT_MIN_COLUMN_INLINE_SIZE_PX, }) => {
|
|
102
|
+
export const chooseColumns = ({ availableBlockSize, availableInlineSize, chromeBlockSize = 0, itemBlockSize, itemCount, gap = 16, layout = "height-first", maxColumns = DEFAULT_MAX_AUTO_COLUMNS, minColumnInlineSize = DEFAULT_MIN_COLUMN_INLINE_SIZE_PX, }) => {
|
|
103
103
|
// Inline size is a CAP, never a reason. This is the "don't go
|
|
104
104
|
// 9-wide just because you're on an ultrawide" half of the rule.
|
|
105
105
|
const inlineSizeCap = Math.max(1, Math.min(maxColumns, Math.floor(availableInlineSize / minColumnInlineSize)));
|
|
106
106
|
if (itemCount <= 1) {
|
|
107
107
|
return 1;
|
|
108
108
|
}
|
|
109
|
+
if (layout === "fill") {
|
|
110
|
+
const columnsThatFit = Math.max(1, Math.floor((availableInlineSize + gap) /
|
|
111
|
+
(minColumnInlineSize + gap)));
|
|
112
|
+
return Math.max(1, Math.min(maxColumns, itemCount, columnsThatFit));
|
|
113
|
+
}
|
|
109
114
|
// Block size is the reason. How many items stack in the space,
|
|
110
115
|
// then how many stacks that many items need.
|
|
111
116
|
const rowsThatFit = Math.max(1, Math.floor((availableBlockSize - chromeBlockSize) /
|
|
@@ -138,9 +143,11 @@ export const chooseColumns = ({ availableBlockSize, availableInlineSize, chromeB
|
|
|
138
143
|
* dense tables and an app of prose disagree about a measure and
|
|
139
144
|
* neither is wrong.
|
|
140
145
|
*/
|
|
141
|
-
export const getContentMaxInlineSize = ({ columnInlineSize = contentInlineSize.column, columns, gutterInlineSize = contentInlineSize.gutter, singleInlineSize = contentInlineSize.single, }) => columns <= 1
|
|
146
|
+
export const getContentMaxInlineSize = ({ columnInlineSize = contentInlineSize.column, columns, gutterInlineSize = contentInlineSize.gutter, layout = "height-first", singleInlineSize = contentInlineSize.single, }) => columns <= 1
|
|
142
147
|
? singleInlineSize
|
|
143
|
-
:
|
|
148
|
+
: layout === "fill"
|
|
149
|
+
? "none"
|
|
150
|
+
: `${Number.parseFloat(columnInlineSize) * columns + Number.parseFloat(gutterInlineSize)}rem`;
|
|
144
151
|
/**
|
|
145
152
|
* The choices a manual picker offers: `"auto"`, then every count up
|
|
146
153
|
* to `maxColumns`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chooseColumns.js","sourceRoot":"","sources":["../../src/AdaptiveGrid/chooseColumns.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,iBAAiB,GAClB,MAAM,cAAc,CAAA;AAErB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAA;AAEzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAC5C,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"chooseColumns.js","sourceRoot":"","sources":["../../src/AdaptiveGrid/chooseColumns.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RefObject } from "react";
|
|
2
|
-
import type { ColumnChoice } from "./chooseColumns.ts";
|
|
2
|
+
import type { ColumnChoice, GridLayout } from "./chooseColumns.ts";
|
|
3
3
|
/**
|
|
4
4
|
* The height-first column rule, wired to a real element.
|
|
5
5
|
*
|
|
@@ -96,7 +96,7 @@ export declare const readStoredChoice: ({ maxColumns, persistence, }: {
|
|
|
96
96
|
maxColumns?: number;
|
|
97
97
|
persistence: ColumnPersistence | undefined;
|
|
98
98
|
}) => ColumnChoice;
|
|
99
|
-
export declare const useAdaptiveColumns: <ContainerElement extends HTMLElement = HTMLDivElement>({ blockSizeResolver, chromeBlockSize, columnInlineSize, gutterInlineSize, itemBlockSize, itemCount, maxAutoColumns, maxManualColumns, minColumnInlineSize, persistence, singleInlineSize, storageKey, }: {
|
|
99
|
+
export declare const useAdaptiveColumns: <ContainerElement extends HTMLElement = HTMLDivElement>({ blockSizeResolver, chromeBlockSize, columnInlineSize, gutterInlineSize, gap, itemBlockSize, itemCount, layout, maxAutoColumns, maxManualColumns, minColumnInlineSize, persistence, singleInlineSize, storageKey, }: {
|
|
100
100
|
/** @see BlockSizeResolver. Defaults to the viewport. */
|
|
101
101
|
blockSizeResolver?: BlockSizeResolver;
|
|
102
102
|
/** Everything down the page that is not this grid, in CSS px. */
|
|
@@ -105,10 +105,14 @@ export declare const useAdaptiveColumns: <ContainerElement extends HTMLElement =
|
|
|
105
105
|
columnInlineSize?: string;
|
|
106
106
|
/** Override `contentInlineSize.gutter`. */
|
|
107
107
|
gutterInlineSize?: string;
|
|
108
|
+
/** Space between tracks for the fill layout. */
|
|
109
|
+
gap?: number;
|
|
108
110
|
/** One item's block size in CSS px. Measure it; err high. */
|
|
109
111
|
itemBlockSize: number;
|
|
110
112
|
/** How many items the grid is being asked to fit. */
|
|
111
113
|
itemCount: number;
|
|
114
|
+
/** Opt in to width-first media layout. */
|
|
115
|
+
layout?: GridLayout;
|
|
112
116
|
/** The most columns the automatic answer will take. */
|
|
113
117
|
maxAutoColumns?: number;
|
|
114
118
|
/** The most a person may ask for. One above the auto cap. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAdaptiveColumns.d.ts","sourceRoot":"","sources":["../../src/AdaptiveGrid/useAdaptiveColumns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAStC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"useAdaptiveColumns.d.ts","sourceRoot":"","sources":["../../src/AdaptiveGrid/useAdaptiveColumns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAStC,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACX,MAAM,oBAAoB,CAAA;AAS3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,MAAM,CAAA;IACjB,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CAChD,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;IACzB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC/B,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,QAChC,iBAgBF,CAAA;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GACxC,KAAK,MAAM,KACV,iBAeD,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,8BAG9B;IACD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,iBAAiB,GAAG,SAAS,CAAA;CAC3C,KAAG,YAkBH,CAAA;AAED,eAAO,MAAM,kBAAkB,GAC7B,gBAAgB,SAAS,WAAW,GAAG,cAAc,EACrD,sNAeC;IACD,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAA;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,KAAG;IACF,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAA;IACnB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,oBAAoB,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,YAAY,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAChD;;;;;;;;;;;;;;OAcG;IACH,SAAS,EAAE,OAAO,CAAA;IAClB,0CAA0C;IAC1C,MAAM,EAAE,YAAY,CAAA;IACpB,SAAS,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAA;CAkH1C,CAAA"}
|
|
@@ -70,7 +70,7 @@ export const readStoredChoice = ({ maxColumns = DEFAULT_MAX_MANUAL_COLUMNS, pers
|
|
|
70
70
|
}
|
|
71
71
|
return parsed;
|
|
72
72
|
};
|
|
73
|
-
export const useAdaptiveColumns = ({ blockSizeResolver, chromeBlockSize, columnInlineSize, gutterInlineSize, itemBlockSize, itemCount, maxAutoColumns = DEFAULT_MAX_AUTO_COLUMNS, maxManualColumns = DEFAULT_MAX_MANUAL_COLUMNS, minColumnInlineSize = DEFAULT_MIN_COLUMN_INLINE_SIZE_PX, persistence, singleInlineSize, storageKey, }) => {
|
|
73
|
+
export const useAdaptiveColumns = ({ blockSizeResolver, chromeBlockSize, columnInlineSize, gutterInlineSize, gap, itemBlockSize, itemCount, layout = "height-first", maxAutoColumns = DEFAULT_MAX_AUTO_COLUMNS, maxManualColumns = DEFAULT_MAX_MANUAL_COLUMNS, minColumnInlineSize = DEFAULT_MIN_COLUMN_INLINE_SIZE_PX, persistence, singleInlineSize, storageKey, }) => {
|
|
74
74
|
const containerRef = useRef(null);
|
|
75
75
|
// Built once, so the `resize` subscription and the storage
|
|
76
76
|
// handle survive re-renders and StrictMode's double mount — the
|
|
@@ -132,6 +132,8 @@ export const useAdaptiveColumns = ({ blockSizeResolver, chromeBlockSize, columnI
|
|
|
132
132
|
chromeBlockSize,
|
|
133
133
|
itemBlockSize,
|
|
134
134
|
itemCount,
|
|
135
|
+
gap,
|
|
136
|
+
layout,
|
|
135
137
|
maxColumns: maxAutoColumns,
|
|
136
138
|
minColumnInlineSize,
|
|
137
139
|
});
|
|
@@ -145,6 +147,7 @@ export const useAdaptiveColumns = ({ blockSizeResolver, chromeBlockSize, columnI
|
|
|
145
147
|
columnInlineSize,
|
|
146
148
|
columns,
|
|
147
149
|
gutterInlineSize,
|
|
150
|
+
layout,
|
|
148
151
|
singleInlineSize,
|
|
149
152
|
}),
|
|
150
153
|
isLaidOut: availableInlineSize > 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAdaptiveColumns.js","sourceRoot":"","sources":["../../src/AdaptiveGrid/useAdaptiveColumns.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,SAAS,EACT,MAAM,EACN,QAAQ,EACR,oBAAoB,GACrB,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"useAdaptiveColumns.js","sourceRoot":"","sources":["../../src/AdaptiveGrid/useAdaptiveColumns.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,SAAS,EACT,MAAM,EACN,QAAQ,EACR,oBAAoB,GACrB,MAAM,OAAO,CAAA;AAMd,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,0BAA0B,EAC1B,iCAAiC,EACjC,uBAAuB,GACxB,MAAM,oBAAoB,CAAA;AAuE3B;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,yBAAyB,GACpC,GAAsB,EAAE,CAAC,CAAC;IACxB,GAAG,EAAE,GAAG,EAAE,CACR,OAAO,MAAM,KAAK,WAAW;QAC3B,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,MAAM,CAAC,WAAW;IACxB,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;QACtB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;QACjB,CAAC;QAED,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAE3C,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAChD,CAAC,CAAA;IACH,CAAC;CACF,CAAC,CAAA;AAEJ;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,GAAW,EACQ,EAAE,CAAC,CAAC;IACvB,IAAI,EAAE,GAAG,EAAE;QACT,IAAI,CAAC;YACH,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;QACpD,CAAC;IACH,CAAC;CACF,CAAC,CAAA;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,UAAU,GAAG,0BAA0B,EACvC,WAAW,GAIZ,EAAgB,EAAE;IACjB,MAAM,MAAM,GAAG,WAAW,EAAE,IAAI,EAAE,IAAI,IAAI,CAAA;IAE1C,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACzC,OAAO,MAAM,CAAA;IACf,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IAE7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,UAAU,EAAE,CAAC;QACtC,OAAO,MAAM,CAAA;IACf,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAEhC,EACA,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,GAAG,EACH,aAAa,EACb,SAAS,EACT,MAAM,GAAG,cAAc,EACvB,cAAc,GAAG,wBAAwB,EACzC,gBAAgB,GAAG,0BAA0B,EAC7C,mBAAmB,GAAG,iCAAiC,EACvD,WAAW,EACX,gBAAgB,EAChB,UAAU,GAyCX,EAmCC,EAAE;IACF,MAAM,YAAY,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAA;IAEnD,2DAA2D;IAC3D,gEAAgE;IAChE,+DAA+D;IAC/D,QAAQ;IACR,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QAC9B,SAAS,EACP,iBAAiB,IAAI,yBAAyB,EAAE;QAClD,WAAW,EACT,WAAW;YACX,CAAC,UAAU,KAAK,SAAS;gBACvB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,6BAA6B,CAAC,UAAU,CAAC,CAAC;KACjD,CAAC,CAAC,CAAA;IAEH,MAAM,kBAAkB,GAAG,oBAAoB,CAC7C,KAAK,CAAC,SAAS,CAAC,SAAS,EACzB,KAAK,CAAC,SAAS,CAAC,GAAG;IACnB,8DAA8D;IAC9D,GAAG,EAAE,CAAC,CAAC,CACR,CAAA;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GACjD,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEb,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAA;QAEtC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE;YAC9C,MAAM,IAAI,GACR,KAAK,EAAE,WAAW,CAAC,KAAK;gBACxB,SAAS,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAA;YAEzC,yDAAyD;YACzD,yDAAyD;YACzD,0BAA0B;YAC1B,sBAAsB,CAAC,CAAC,OAAO,EAAE,EAAE,CACjC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAClC,CAAA;QACH,CAAC,CAAC,CAAA;QAEF,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAE3B,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,UAAU,EAAE,CAAA;QACvB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,QAAQ,CACxC,GAAG,EAAE,CACH,gBAAgB,CAAC;QACf,UAAU,EAAE,gBAAgB;QAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;KAC/B,CAAC,CACL,CAAA;IAED,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,IAAkB,EAAE,EAAE;QACrB,eAAe,CAAC,IAAI,CAAC,CAAA;QAErB,oDAAoD;QACpD,6DAA6D;QAC7D,OAAO;QACP,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACxC,CAAC,EACD,CAAC,KAAK,CAAC,CACR,CAAA;IAED,MAAM,WAAW,GAAG,aAAa,CAAC;QAChC,kBAAkB;QAClB,mBAAmB;QACnB,eAAe;QACf,aAAa;QACb,SAAS;QACT,GAAG;QACH,MAAM;QACN,UAAU,EAAE,cAAc;QAC1B,mBAAmB;KACpB,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAA;IAExD,OAAO;QACL,WAAW;QACX,MAAM;QACN,OAAO;QACP,YAAY;QACZ,oBAAoB,EAAE,uBAAuB,CAAC;YAC5C,gBAAgB;YAChB,OAAO;YACP,gBAAgB;YAChB,MAAM;YACN,gBAAgB;SACjB,CAAC;QACF,SAAS,EAAE,mBAAmB,GAAG,CAAC;QAClC,SAAS;KACV,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ChartSeries } from "@charcuterie/logic/core";
|
|
2
|
+
export type ComparisonChartProps = {
|
|
3
|
+
title: string;
|
|
4
|
+
labels: readonly string[];
|
|
5
|
+
series: readonly ChartSeries[];
|
|
6
|
+
layout?: "nested" | "grouped";
|
|
7
|
+
formatValue?: (value: number) => string;
|
|
8
|
+
isTableVisible?: boolean;
|
|
9
|
+
};
|
|
10
|
+
/** Horizontal comparisons with one legend, a common scale, and original-value labels. */
|
|
11
|
+
export declare const ComparisonChart: ({ title, labels, series, layout, formatValue, isTableVisible, }: ComparisonChartProps) => import("react").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=ComparisonChart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComparisonChart.d.ts","sourceRoot":"","sources":["../../src/ComparisonChart/ComparisonChart.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAU1D,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,MAAM,EAAE,SAAS,WAAW,EAAE,CAAA;IAC9B,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC7B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACvC,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAED,yFAAyF;AACzF,eAAO,MAAM,eAAe,GAAI,iEAO7B,oBAAoB,gCAoItB,CAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ComparisonPlot } from "@charcuterie/logic/charts/react";
|
|
3
|
+
import { getReadableTextColour } from "@charcuterie/tokens";
|
|
4
|
+
import { useEffect, useRef, useState, } from "react";
|
|
5
|
+
import { DataTable } from "../DataTable/DataTable.js";
|
|
6
|
+
/** Horizontal comparisons with one legend, a common scale, and original-value labels. */
|
|
7
|
+
export const ComparisonChart = ({ title, labels, series, layout = "nested", formatValue = String, isTableVisible = false, }) => {
|
|
8
|
+
const container = useRef(null);
|
|
9
|
+
const [width, setWidth] = useState(640);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!container.current)
|
|
12
|
+
return;
|
|
13
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
14
|
+
if (entry.contentRect.width > 0)
|
|
15
|
+
setWidth(entry.contentRect.width);
|
|
16
|
+
});
|
|
17
|
+
observer.observe(container.current);
|
|
18
|
+
return () => observer.disconnect();
|
|
19
|
+
}, []);
|
|
20
|
+
const maximum = Math.max(1, ...series.flatMap((entry) => entry.values.filter((value) => value !== null && Number.isFinite(value))));
|
|
21
|
+
const minimum = Math.min(0, ...series.flatMap((entry) => entry.values.filter((value) => value !== null && Number.isFinite(value))));
|
|
22
|
+
return (_jsxs("figure", { className: "min-w-0 text-content-primary", style: {
|
|
23
|
+
"--ts-chart-tooltip-background": "var(--color-surface-raised)",
|
|
24
|
+
"--ts-chart-tooltip-color": "var(--color-content-primary)",
|
|
25
|
+
}, children: [_jsx("figcaption", { className: "sr-only", children: title }), _jsx("ul", { "aria-label": `${title} legend`, className: "mb-3 flex flex-wrap gap-3 text-xs", children: series.map((entry) => (_jsxs("li", { className: "min-w-0 wrap-anywhere", children: [_jsx("span", { "aria-hidden": "true", className: "me-1 inline-block size-2 rounded-full", style: { backgroundColor: entry.color } }), entry.label] }, entry.id))) }), _jsx("div", { ref: container, className: "space-y-3", children: labels.map((label, index) => {
|
|
26
|
+
const values = series.map((entry) => ({
|
|
27
|
+
id: entry.id,
|
|
28
|
+
label: entry.label,
|
|
29
|
+
value: entry.values[index] ?? null,
|
|
30
|
+
colour: entry.color ?? "currentColor",
|
|
31
|
+
textColour: entry.color &&
|
|
32
|
+
/^#[0-9a-f]{6}$/i.test(entry.color)
|
|
33
|
+
? getReadableTextColour(entry.color)
|
|
34
|
+
: "var(--color-surface-base)",
|
|
35
|
+
}));
|
|
36
|
+
const shown = values.filter((entry) => entry.value !== null);
|
|
37
|
+
return (_jsxs("div", { children: [_jsx("p", { className: "text-sm wrap-anywhere", children: label }), _jsx(ComparisonPlot, { title: `${title}: ${label}`, values: values, maximum: maximum, minimum: minimum, layout: layout, formatValue: formatValue, width: width, height: shown.length > 1 ? 60 : 34 })] }, JSON.stringify([
|
|
38
|
+
label,
|
|
39
|
+
values
|
|
40
|
+
.filter((entry) => entry.value !== null)
|
|
41
|
+
.map((entry) => entry.id),
|
|
42
|
+
])));
|
|
43
|
+
}) }), isTableVisible && (_jsx(DataTable, { label: `${title} values`, rows: labels.map((label, index) => ({
|
|
44
|
+
label,
|
|
45
|
+
index,
|
|
46
|
+
})), getRowKey: (row) => String(row.index), columns: [
|
|
47
|
+
{
|
|
48
|
+
key: "label",
|
|
49
|
+
header: "Card",
|
|
50
|
+
renderCell: (row) => row.label,
|
|
51
|
+
},
|
|
52
|
+
...series.map((entry) => ({
|
|
53
|
+
key: entry.id,
|
|
54
|
+
header: entry.label,
|
|
55
|
+
renderCell: (row) => {
|
|
56
|
+
const value = entry.values[row.index];
|
|
57
|
+
return value == null
|
|
58
|
+
? "-"
|
|
59
|
+
: formatValue(value);
|
|
60
|
+
},
|
|
61
|
+
})),
|
|
62
|
+
] }))] }));
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=ComparisonChart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComparisonChart.js","sourceRoot":"","sources":["../../src/ComparisonChart/ComparisonChart.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type LightboxImage = {
|
|
3
|
+
readonly alt: string;
|
|
4
|
+
readonly src: string;
|
|
5
|
+
readonly caption?: ReactNode;
|
|
6
|
+
};
|
|
2
7
|
export type LightboxProps = {
|
|
8
|
+
/** Optional ordered gallery. The trigger opens at initialIndex. */
|
|
9
|
+
images?: readonly LightboxImage[];
|
|
10
|
+
initialIndex?: number;
|
|
3
11
|
/**
|
|
4
12
|
* Required, and the whole reason this is not a bare `<img>` in a
|
|
5
13
|
* dialog. It names both the enlarged image and — via `heading`'s
|
|
@@ -53,5 +61,5 @@ export type LightboxProps = {
|
|
|
53
61
|
* unread two-field object, which is cheaper than splitting this into
|
|
54
62
|
* two components that share a Modal body.
|
|
55
63
|
*/
|
|
56
|
-
export declare const Lightbox: ({ alt, caption, className, heading, isOpen, onOpenChange, src, thumbnail, }: LightboxProps) => ReactNode;
|
|
64
|
+
export declare const Lightbox: ({ alt, caption, className, heading, images, initialIndex, isOpen, onOpenChange, src, thumbnail, }: LightboxProps) => ReactNode;
|
|
57
65
|
//# sourceMappingURL=Lightbox.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Lightbox.d.ts","sourceRoot":"","sources":["../../src/Lightbox/Lightbox.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"Lightbox.d.ts","sourceRoot":"","sources":["../../src/Lightbox/Lightbox.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,OAAO,CAAA;AAM3D,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,mEAAmE;IACnE,MAAM,CAAC,EAAE,SAAS,aAAa,EAAE,CAAA;IACjC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,CAAA;IACX,oEAAoE;IACpE,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACxC,GAAG,EAAE,MAAM,CAAA;IACX;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB,CAAA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,QAAQ,GAAI,mGAWtB,aAAa,KAAG,SAoKlB,CAAA"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useVisibility } from "@charcuterie/logic";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { Button } from "../Button/Button.js";
|
|
3
5
|
import { Dialog } from "../Dialog/Dialog.js";
|
|
4
6
|
import { toClassName } from "../toClassName.js";
|
|
5
7
|
/**
|
|
@@ -21,11 +23,51 @@ import { toClassName } from "../toClassName.js";
|
|
|
21
23
|
* unread two-field object, which is cheaper than splitting this into
|
|
22
24
|
* two components that share a Modal body.
|
|
23
25
|
*/
|
|
24
|
-
export const Lightbox = ({ alt, caption, className, heading, isOpen, onOpenChange, src, thumbnail, }) => {
|
|
26
|
+
export const Lightbox = ({ alt, caption, className, heading, images, initialIndex = 0, isOpen, onOpenChange, src, thumbnail, }) => {
|
|
25
27
|
const isControlled = isOpen !== undefined;
|
|
26
28
|
const { hide, isVisible, show } = useVisibility();
|
|
29
|
+
const [index, setIndex] = useState(initialIndex);
|
|
27
30
|
const isShown = isControlled ? isOpen : isVisible;
|
|
31
|
+
const gallery = images?.length
|
|
32
|
+
? images
|
|
33
|
+
: [{ alt, caption, src }];
|
|
34
|
+
const activeIndex = Math.max(0, Math.min(index, gallery.length - 1));
|
|
35
|
+
const active = gallery[activeIndex] ?? {
|
|
36
|
+
alt,
|
|
37
|
+
caption,
|
|
38
|
+
src,
|
|
39
|
+
};
|
|
40
|
+
const hasMultiple = gallery.length > 1;
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!isShown || !hasMultiple)
|
|
43
|
+
return;
|
|
44
|
+
const navigate = (event) => {
|
|
45
|
+
if (event.altKey ||
|
|
46
|
+
event.ctrlKey ||
|
|
47
|
+
event.metaKey ||
|
|
48
|
+
event.shiftKey)
|
|
49
|
+
return;
|
|
50
|
+
if (event.target instanceof HTMLElement &&
|
|
51
|
+
event.target.closest("input, textarea, [contenteditable=true]"))
|
|
52
|
+
return;
|
|
53
|
+
const delta = event.key === "ArrowLeft"
|
|
54
|
+
? -1
|
|
55
|
+
: event.key === "ArrowRight"
|
|
56
|
+
? 1
|
|
57
|
+
: 0;
|
|
58
|
+
if (delta === 0)
|
|
59
|
+
return;
|
|
60
|
+
event.preventDefault();
|
|
61
|
+
setIndex((current) => (Math.max(0, Math.min(current, gallery.length - 1)) +
|
|
62
|
+
delta +
|
|
63
|
+
gallery.length) %
|
|
64
|
+
gallery.length);
|
|
65
|
+
};
|
|
66
|
+
document.addEventListener("keydown", navigate);
|
|
67
|
+
return () => document.removeEventListener("keydown", navigate);
|
|
68
|
+
}, [isShown, hasMultiple, gallery.length]);
|
|
28
69
|
const requestOpen = () => {
|
|
70
|
+
setIndex(initialIndex);
|
|
29
71
|
if (!isControlled) {
|
|
30
72
|
show();
|
|
31
73
|
}
|
|
@@ -41,10 +83,11 @@ export const Lightbox = ({ alt, caption, className, heading, isOpen, onOpenChang
|
|
|
41
83
|
// `cursor-zoom-in` is the affordance a bare `<img>`
|
|
42
84
|
// never had, and the focus ring is the fleet's standard
|
|
43
85
|
// — the same one `MediaTile`'s link wears.
|
|
44
|
-
"group block cursor-zoom-in rounded-md outline-offset-2 focus-visible:outline-solid focus-visible:outline-(length:--focus-ring-width) focus-visible:outline-focus-ring", className), onClick: requestOpen, type: "button", children: thumbnail })), _jsx(Dialog, { heading: heading ?? alt, isVisible: isShown, onClose: requestClose, size: "xl",
|
|
86
|
+
"group block cursor-zoom-in rounded-md outline-offset-2 focus-visible:outline-solid focus-visible:outline-(length:--focus-ring-width) focus-visible:outline-focus-ring", className), onClick: requestOpen, type: "button", children: thumbnail })), _jsx(Dialog, { heading: heading ?? alt, isVisible: isShown, onClose: requestClose, size: "xl", footer: hasMultiple ? (_jsxs("div", { className: "flex w-full items-center justify-between gap-3", children: [_jsx(Button, { appearance: "ghost", size: "sm", onClick: () => setIndex((activeIndex + gallery.length - 1) %
|
|
87
|
+
gallery.length), children: "Previous image" }), _jsxs("span", { className: "text-content-secondary text-sm", role: "status", "aria-live": "polite", children: [activeIndex + 1, " of ", gallery.length] }), _jsx(Button, { appearance: "ghost", size: "sm", onClick: () => setIndex((activeIndex + 1) % gallery.length), children: "Next image" })] })) : undefined, children: _jsxs("figure", { className: "flex flex-col items-center gap-3", children: [_jsx("img", { alt: active.alt,
|
|
45
88
|
// `object-contain`, not `cover`: the enlarged view must
|
|
46
89
|
// show the whole image, and the clamp is `dvh` for the
|
|
47
90
|
// same address-bar reason `Modal`'s is.
|
|
48
|
-
className: "max-h-[75dvh] w-auto max-w-full rounded-md object-contain", src: src }), caption ? (_jsx("figcaption", { className: "text-center text-content-muted text-sm", children: caption })) : null] }) })] }));
|
|
91
|
+
className: "max-h-[75dvh] w-auto max-w-full rounded-md object-contain", src: active.src }), active.caption ? (_jsx("figcaption", { className: "text-center text-content-muted text-sm", children: active.caption })) : null] }) })] }));
|
|
49
92
|
};
|
|
50
93
|
//# sourceMappingURL=Lightbox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Lightbox.js","sourceRoot":"","sources":["../../src/Lightbox/Lightbox.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"Lightbox.js","sourceRoot":"","sources":["../../src/Lightbox/Lightbox.tsx"],"names":[],"mappings":"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"}
|
|
@@ -132,10 +132,10 @@ export declare const useAnchoredOverlay: ({ anchorRef, isEscapeDismissable, isHe
|
|
|
132
132
|
clonedTrigger: ReactElement<Record<string, unknown>, string | import("react").JSXElementConstructor<any>> | null;
|
|
133
133
|
context: {
|
|
134
134
|
placement: Placement;
|
|
135
|
-
strategy: import("@floating-ui/
|
|
135
|
+
strategy: import("@floating-ui/react").Strategy;
|
|
136
136
|
x: number;
|
|
137
137
|
y: number;
|
|
138
|
-
middlewareData: import("@floating-ui/
|
|
138
|
+
middlewareData: import("@floating-ui/react").MiddlewareData;
|
|
139
139
|
isPositioned: boolean;
|
|
140
140
|
update: () => void;
|
|
141
141
|
floatingStyles: React.CSSProperties;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type TableColumnChoice = {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
isVisible: boolean;
|
|
5
|
+
isRequired?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type TableColumnsProps = {
|
|
8
|
+
columns: readonly TableColumnChoice[];
|
|
9
|
+
onChange: (columns: TableColumnChoice[]) => void;
|
|
10
|
+
label?: string;
|
|
11
|
+
};
|
|
12
|
+
/** Column visibility and ordering, with keyboard moves as the primary path. */
|
|
13
|
+
export declare const TableColumns: ({ columns, onChange, label, }: TableColumnsProps) => import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=TableColumns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableColumns.d.ts","sourceRoot":"","sources":["../../src/TableColumns/TableColumns.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AACD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACrC,QAAQ,EAAE,CAAC,OAAO,EAAE,iBAAiB,EAAE,KAAK,IAAI,CAAA;IAChD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,+EAA+E;AAC/E,eAAO,MAAM,YAAY,GAAI,+BAI1B,iBAAiB,gCAqEnB,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Button } from "../Button/Button.js";
|
|
4
|
+
import { Checkbox } from "../Checkbox/Checkbox.js";
|
|
5
|
+
import { Popover } from "../Popover/Popover.js";
|
|
6
|
+
import { ReorderList } from "../ReorderList/ReorderList.js";
|
|
7
|
+
/** Column visibility and ordering, with keyboard moves as the primary path. */
|
|
8
|
+
export const TableColumns = ({ columns, onChange, label = "Columns", }) => {
|
|
9
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
10
|
+
return (_jsx(Popover, { heading: "Table columns", isVisible: isVisible, onDismiss: () => setIsVisible(false), trigger: _jsx(Button, { intent: "neutral", appearance: "soft", onClick: () => setIsVisible(!isVisible), children: label }), children: _jsx(ReorderList, { label: "Column order", items: columns, onReorder: (from, to) => {
|
|
11
|
+
const next = [...columns];
|
|
12
|
+
const [column] = next.splice(from, 1);
|
|
13
|
+
next.splice(to, 0, column);
|
|
14
|
+
onChange(next);
|
|
15
|
+
}, renderItem: ({ item, isFirst, isLast, moveBy }) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 py-1", children: [_jsx(Checkbox, { label: item.label, isChecked: item.isVisible, isDisabled: item.isRequired, onChange: (isChecked) => onChange(columns.map((column) => column.key === item.key
|
|
16
|
+
? { ...column, isVisible: isChecked }
|
|
17
|
+
: column)) }), _jsxs("div", { className: "flex gap-1", children: [_jsx(Button, { size: "sm", intent: "neutral", appearance: "ghost", "aria-label": `Move ${item.label} earlier`, isDisabled: isFirst, onClick: () => moveBy(-1), children: "Earlier" }), _jsx(Button, { size: "sm", intent: "neutral", appearance: "ghost", "aria-label": `Move ${item.label} later`, isDisabled: isLast, onClick: () => moveBy(1), children: "Later" })] })] })) }) }));
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=TableColumns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableColumns.js","sourceRoot":"","sources":["../../src/TableColumns/TableColumns.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAsB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAA0B,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAwB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAAgC,CAAA;AAc5D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAC3B,OAAO,EACP,QAAQ,EACR,KAAK,GAAG,SAAS,GACC,EAAE,EAAE;IACtB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACjD,OAAO,CACL,KAAC,OAAO,IACN,OAAO,EAAC,eAAe,EACvB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,EACpC,OAAO,EACL,KAAC,MAAM,IACL,MAAM,EAAC,SAAS,EAChB,UAAU,EAAC,MAAM,EACjB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,YAEtC,KAAK,GACC,YAGX,KAAC,WAAW,IACV,KAAK,EAAC,cAAc,EACpB,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;gBACtB,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,CAAA;gBACzB,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;gBACrC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAA;gBAC1B,QAAQ,CAAC,IAAI,CAAC,CAAA;YAChB,CAAC,EACD,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CACjD,eAAK,SAAS,EAAC,wDAAwD,aACrE,KAAC,QAAQ,IACP,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,SAAS,EAAE,IAAI,CAAC,SAAS,EACzB,UAAU,EAAE,IAAI,CAAC,UAAU,EAC3B,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CACtB,QAAQ,CACN,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACrB,MAAM,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG;4BACrB,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE;4BACrC,CAAC,CAAC,MAAM,CACX,CACF,GAEH,EACF,eAAK,SAAS,EAAC,YAAY,aACzB,KAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,MAAM,EAAC,SAAS,EAChB,UAAU,EAAC,OAAO,gBACN,QAAQ,IAAI,CAAC,KAAK,UAAU,EACxC,UAAU,EAAE,OAAO,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,wBAGlB,EACT,KAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,MAAM,EAAC,SAAS,EAChB,UAAU,EAAC,OAAO,gBACN,QAAQ,IAAI,CAAC,KAAK,QAAQ,EACtC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,sBAGjB,IACL,IACF,CACP,GACD,GACM,CACX,CAAA;AACH,CAAC,CAAA"}
|