@charcuterie/ui 2.7.0 → 2.8.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/README.md +11 -0
- package/dist/AdaptiveGrid/AdaptiveGrid.d.ts +94 -0
- package/dist/AdaptiveGrid/AdaptiveGrid.d.ts.map +1 -0
- package/dist/AdaptiveGrid/AdaptiveGrid.js +73 -0
- package/dist/AdaptiveGrid/AdaptiveGrid.js.map +1 -0
- package/dist/AdaptiveGrid/chooseColumns.d.ts +206 -0
- package/dist/AdaptiveGrid/chooseColumns.d.ts.map +1 -0
- package/dist/AdaptiveGrid/chooseColumns.js +156 -0
- package/dist/AdaptiveGrid/chooseColumns.js.map +1 -0
- package/dist/AdaptiveGrid/useAdaptiveColumns.d.ts +155 -0
- package/dist/AdaptiveGrid/useAdaptiveColumns.d.ts.map +1 -0
- package/dist/AdaptiveGrid/useAdaptiveColumns.js +153 -0
- package/dist/AdaptiveGrid/useAdaptiveColumns.js.map +1 -0
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +11 -6
- package/dist/Button/Button.js.map +1 -1
- package/dist/ButtonLink/ButtonLink.d.ts +59 -0
- package/dist/ButtonLink/ButtonLink.d.ts.map +1 -0
- package/dist/ButtonLink/ButtonLink.js +69 -0
- package/dist/ButtonLink/ButtonLink.js.map +1 -0
- package/dist/Combobox/Combobox.d.ts.map +1 -1
- package/dist/Combobox/Combobox.js +1 -1
- package/dist/Combobox/Combobox.js.map +1 -1
- package/dist/Dialog/Dialog.js +1 -1
- package/dist/Dialog/Dialog.js.map +1 -1
- package/dist/LogViewer/LogViewer.d.ts.map +1 -1
- package/dist/LogViewer/LogViewer.js +33 -1
- package/dist/LogViewer/LogViewer.js.map +1 -1
- package/dist/RouterLink/AnchorLink.d.ts +17 -0
- package/dist/RouterLink/AnchorLink.d.ts.map +1 -0
- package/dist/RouterLink/AnchorLink.js +16 -0
- package/dist/RouterLink/AnchorLink.js.map +1 -0
- package/dist/RouterLink/RouterLinkProvider.d.ts +13 -0
- package/dist/RouterLink/RouterLinkProvider.d.ts.map +1 -0
- package/dist/RouterLink/RouterLinkProvider.js +47 -0
- package/dist/RouterLink/RouterLinkProvider.js.map +1 -0
- package/dist/RouterLink/routerLink.d.ts +45 -0
- package/dist/RouterLink/routerLink.d.ts.map +1 -0
- package/dist/RouterLink/routerLink.js +31 -0
- package/dist/RouterLink/routerLink.js.map +1 -0
- package/dist/TextLink/TextLink.d.ts +69 -0
- package/dist/TextLink/TextLink.d.ts.map +1 -0
- package/dist/TextLink/TextLink.js +79 -0
- package/dist/TextLink/TextLink.js.map +1 -0
- package/dist/controlStyles.d.ts +36 -1
- package/dist/controlStyles.d.ts.map +1 -1
- package/dist/controlStyles.js +30 -0
- package/dist/controlStyles.js.map +1 -1
- package/dist/index.d.ts +16 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/intentStyles.d.ts +17 -0
- package/dist/intentStyles.d.ts.map +1 -1
- package/dist/intentStyles.js +17 -0
- package/dist/intentStyles.js.map +1 -1
- package/dist/reactRouter/ReactRouterLink.d.ts +23 -0
- package/dist/reactRouter/ReactRouterLink.d.ts.map +1 -0
- package/dist/reactRouter/ReactRouterLink.js +23 -0
- package/dist/reactRouter/ReactRouterLink.js.map +1 -0
- package/dist/reactRouter/index.d.ts +29 -0
- package/dist/reactRouter/index.d.ts.map +1 -0
- package/dist/reactRouter/index.js +29 -0
- package/dist/reactRouter/index.js.map +1 -0
- package/package.json +15 -3
- package/src/AdaptiveGrid/AdaptiveGrid.mdx +169 -0
- package/src/AdaptiveGrid/AdaptiveGrid.stories.tsx +240 -0
- package/src/AdaptiveGrid/AdaptiveGrid.test.tsx +243 -0
- package/src/AdaptiveGrid/AdaptiveGrid.tsx +150 -0
- package/src/AdaptiveGrid/chooseColumns.test.ts +253 -0
- package/src/AdaptiveGrid/chooseColumns.ts +270 -0
- package/src/AdaptiveGrid/useAdaptiveColumns.ts +355 -0
- package/src/Button/Button.tsx +10 -22
- package/src/ButtonLink/ButtonLink.mdx +75 -0
- package/src/ButtonLink/ButtonLink.stories.tsx +281 -0
- package/src/ButtonLink/ButtonLink.test.tsx +203 -0
- package/src/ButtonLink/ButtonLink.tsx +149 -0
- package/src/Combobox/Combobox.tsx +4 -1
- package/src/Dialog/Dialog.tsx +1 -1
- package/src/LogViewer/LogViewer.test.tsx +47 -0
- package/src/LogViewer/LogViewer.tsx +35 -1
- package/src/RouterLink/AnchorLink.tsx +23 -0
- package/src/RouterLink/RouterLink.mdx +178 -0
- package/src/RouterLink/RouterLinkProvider.tsx +68 -0
- package/src/RouterLink/routerLink.ts +56 -0
- package/src/TextLink/TextLink.mdx +93 -0
- package/src/TextLink/TextLink.stories.tsx +260 -0
- package/src/TextLink/TextLink.test.tsx +230 -0
- package/src/TextLink/TextLink.tsx +194 -0
- package/src/controlStyles.ts +69 -1
- package/src/icons.storyHelpers.tsx +32 -0
- package/src/index.ts +41 -0
- package/src/intentStyles.ts +19 -0
- package/src/reactRouter/ReactRouterLink.tsx +30 -0
- package/src/reactRouter/index.ts +29 -0
- package/src/sourceRules.test.ts +41 -6
package/README.md
CHANGED
|
@@ -27,6 +27,17 @@ an accordion panel is [a `group` rather than a landmark](../../docs/decisions/20
|
|
|
27
27
|
and [not every boolean is a state kind](../../docs/decisions/2026-07-31-not-every-boolean-is-a-state-kind.md).
|
|
28
28
|
Full write-up: [M6a handoff](../../docs/2026-07-31-m6a-the-p1-components.md).
|
|
29
29
|
|
|
30
|
+
**The link family** — `TextLink` and `ButtonLink` — closes the gap that had seven repos
|
|
31
|
+
hand-rolling a `←` back-link, plex-channels navigating with
|
|
32
|
+
`<button onClick={() => navigate(…)}>`, and mux-magic reloading the page through 14 raw
|
|
33
|
+
`<a href>`. Buttons are for on-page actions; links are for navigation, and both of these
|
|
34
|
+
render a real `<a href>` so middle-click, ctrl-click, open-in-new-tab and copy-link-address
|
|
35
|
+
work. They differ in **paint, not semantics**
|
|
36
|
+
([decision](../../docs/decisions/2026-08-10-buttons-are-actions-links-are-navigation.md)).
|
|
37
|
+
The router is **injected** rather than depended on — `RouterLinkProvider` at the app root,
|
|
38
|
+
with `@charcuterie/ui/react-router` as an optional subpath adapter and a plain `<a>` when
|
|
39
|
+
nothing is provided. Recipe: **Guides/Routing** in Storybook.
|
|
40
|
+
|
|
30
41
|
## Install and wire
|
|
31
42
|
|
|
32
43
|
```ts
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { BlockSizeResolver } from "./useAdaptiveColumns.ts";
|
|
3
|
+
export type AdaptiveGridProps = {
|
|
4
|
+
/**
|
|
5
|
+
* Where the available block size is read from. Defaults to the
|
|
6
|
+
* viewport, which is the only thing that can answer "will this
|
|
7
|
+
* scroll".
|
|
8
|
+
*/
|
|
9
|
+
blockSizeResolver?: BlockSizeResolver;
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* Everything down the page that is not this grid, in CSS px —
|
|
13
|
+
* header, rails, filter rows. Subtracted before asking how many
|
|
14
|
+
* items stack.
|
|
15
|
+
*/
|
|
16
|
+
chromeBlockSize?: number;
|
|
17
|
+
className?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Draw this many columns instead of the automatic answer — the
|
|
20
|
+
* manual override, for a picker or a page that hoisted
|
|
21
|
+
* `useAdaptiveColumns` itself.
|
|
22
|
+
*/
|
|
23
|
+
columns?: number;
|
|
24
|
+
/**
|
|
25
|
+
* One item's block size in CSS px. **The one genuinely
|
|
26
|
+
* app-specific number.** Measure it off a running page and err
|
|
27
|
+
* high: a page that scrolls when it did not have to is the
|
|
28
|
+
* complaint this component exists to answer.
|
|
29
|
+
*/
|
|
30
|
+
itemBlockSize: number;
|
|
31
|
+
/**
|
|
32
|
+
* How many items to lay out. Defaults to the number of children,
|
|
33
|
+
* and is worth passing explicitly when the rendered count churns
|
|
34
|
+
* — a grid that reflowed every time one item finished loading
|
|
35
|
+
* would be worse than one that is an item out.
|
|
36
|
+
*/
|
|
37
|
+
itemCount?: number;
|
|
38
|
+
/** The most columns the automatic answer will take. */
|
|
39
|
+
maxColumns?: number;
|
|
40
|
+
/** The narrowest a column may be, in CSS px. */
|
|
41
|
+
minColumnInlineSize?: number;
|
|
42
|
+
/**
|
|
43
|
+
* The `localStorage` key a manual choice is remembered under.
|
|
44
|
+
* Namespace it to the app; omit it and nothing is written.
|
|
45
|
+
*/
|
|
46
|
+
storageKey?: string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* A wrapping grid that spends height before it spends width.
|
|
50
|
+
*
|
|
51
|
+
* The fleet's grids are `auto-fill, minmax()`: they take every
|
|
52
|
+
* column the window allows and land on seven items strung across an
|
|
53
|
+
* ultrawide. This one adds a column only when the items will not
|
|
54
|
+
* stack inside the viewport, and caps the content at a reading
|
|
55
|
+
* measure the rest of the time —
|
|
56
|
+
*
|
|
57
|
+
* > "The idea is that, if you're going to vertically scroll, it's
|
|
58
|
+
* > best to widen the displayed items. If not, then keep them in a
|
|
59
|
+
* > smaller grid, so they all still fit on screen."
|
|
60
|
+
*
|
|
61
|
+
* The rule itself is `chooseColumns`; the measuring is
|
|
62
|
+
* `useAdaptiveColumns`. This is the markup, and it exists because
|
|
63
|
+
* three separate things about that markup are easy to get wrong and
|
|
64
|
+
* silent when you do.
|
|
65
|
+
*
|
|
66
|
+
* ### Two boxes, and why it is not one
|
|
67
|
+
*
|
|
68
|
+
* The outer box is measured and **never capped**; the inner box
|
|
69
|
+
* carries the cap and the tracks. Collapsing them is a real bug
|
|
70
|
+
* with no error message: the cap narrows the content when the item
|
|
71
|
+
* count is low, so an element that is both measured and capped
|
|
72
|
+
* feeds the fold its own output and can never widen again. One
|
|
73
|
+
* column, forever.
|
|
74
|
+
*
|
|
75
|
+
* ### `min-w-0` on every child
|
|
76
|
+
*
|
|
77
|
+
* `[&>*]:min-w-0`, because a grid item's automatic minimum size is
|
|
78
|
+
* `min-content` — so one long unbroken string (a file path, a URL)
|
|
79
|
+
* pushes its track wider than its share and shoves the whole grid
|
|
80
|
+
* out of the viewport. The rule that stops it has to be on the
|
|
81
|
+
* children, and they belong to the caller, so it is applied from
|
|
82
|
+
* here rather than asked for.
|
|
83
|
+
*
|
|
84
|
+
* ### The tracks are an inline style
|
|
85
|
+
*
|
|
86
|
+
* `repeat(N, minmax(0, 1fr))` is interpolated, which a className
|
|
87
|
+
* may not be: Tailwind v4 scans source *text* for complete class
|
|
88
|
+
* strings, so `grid-cols-${columns}` generates nothing at all — no
|
|
89
|
+
* error, no warning, an unstyled element. A class-per-count would
|
|
90
|
+
* need every count to survive the scan; an inline style needs
|
|
91
|
+
* none.
|
|
92
|
+
*/
|
|
93
|
+
export declare const AdaptiveGrid: ({ blockSizeResolver, children, chromeBlockSize, className, columns, itemBlockSize, itemCount, maxColumns, minColumnInlineSize, storageKey, }: AdaptiveGridProps) => ReactNode;
|
|
94
|
+
//# sourceMappingURL=AdaptiveGrid.d.ts.map
|
|
@@ -0,0 +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;AAKtC,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,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,8IAW1B,iBAAiB,KAAG,SAuCtB,CAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Children } from "react";
|
|
3
|
+
import { toClassName } from "../toClassName.js";
|
|
4
|
+
import { getContentMaxInlineSize } from "./chooseColumns.js";
|
|
5
|
+
import { useAdaptiveColumns } from "./useAdaptiveColumns.js";
|
|
6
|
+
/**
|
|
7
|
+
* A wrapping grid that spends height before it spends width.
|
|
8
|
+
*
|
|
9
|
+
* The fleet's grids are `auto-fill, minmax()`: they take every
|
|
10
|
+
* column the window allows and land on seven items strung across an
|
|
11
|
+
* ultrawide. This one adds a column only when the items will not
|
|
12
|
+
* stack inside the viewport, and caps the content at a reading
|
|
13
|
+
* measure the rest of the time —
|
|
14
|
+
*
|
|
15
|
+
* > "The idea is that, if you're going to vertically scroll, it's
|
|
16
|
+
* > best to widen the displayed items. If not, then keep them in a
|
|
17
|
+
* > smaller grid, so they all still fit on screen."
|
|
18
|
+
*
|
|
19
|
+
* The rule itself is `chooseColumns`; the measuring is
|
|
20
|
+
* `useAdaptiveColumns`. This is the markup, and it exists because
|
|
21
|
+
* three separate things about that markup are easy to get wrong and
|
|
22
|
+
* silent when you do.
|
|
23
|
+
*
|
|
24
|
+
* ### Two boxes, and why it is not one
|
|
25
|
+
*
|
|
26
|
+
* The outer box is measured and **never capped**; the inner box
|
|
27
|
+
* carries the cap and the tracks. Collapsing them is a real bug
|
|
28
|
+
* with no error message: the cap narrows the content when the item
|
|
29
|
+
* count is low, so an element that is both measured and capped
|
|
30
|
+
* feeds the fold its own output and can never widen again. One
|
|
31
|
+
* column, forever.
|
|
32
|
+
*
|
|
33
|
+
* ### `min-w-0` on every child
|
|
34
|
+
*
|
|
35
|
+
* `[&>*]:min-w-0`, because a grid item's automatic minimum size is
|
|
36
|
+
* `min-content` — so one long unbroken string (a file path, a URL)
|
|
37
|
+
* pushes its track wider than its share and shoves the whole grid
|
|
38
|
+
* out of the viewport. The rule that stops it has to be on the
|
|
39
|
+
* children, and they belong to the caller, so it is applied from
|
|
40
|
+
* here rather than asked for.
|
|
41
|
+
*
|
|
42
|
+
* ### The tracks are an inline style
|
|
43
|
+
*
|
|
44
|
+
* `repeat(N, minmax(0, 1fr))` is interpolated, which a className
|
|
45
|
+
* may not be: Tailwind v4 scans source *text* for complete class
|
|
46
|
+
* strings, so `grid-cols-${columns}` generates nothing at all — no
|
|
47
|
+
* error, no warning, an unstyled element. A class-per-count would
|
|
48
|
+
* need every count to survive the scan; an inline style needs
|
|
49
|
+
* none.
|
|
50
|
+
*/
|
|
51
|
+
export const AdaptiveGrid = ({ blockSizeResolver, children, chromeBlockSize, className, columns, itemBlockSize, itemCount, maxColumns, minColumnInlineSize, storageKey, }) => {
|
|
52
|
+
const layout = useAdaptiveColumns({
|
|
53
|
+
blockSizeResolver,
|
|
54
|
+
chromeBlockSize,
|
|
55
|
+
itemBlockSize,
|
|
56
|
+
itemCount: itemCount ?? Children.count(children),
|
|
57
|
+
maxAutoColumns: maxColumns,
|
|
58
|
+
minColumnInlineSize,
|
|
59
|
+
storageKey,
|
|
60
|
+
});
|
|
61
|
+
const drawnColumns = columns ?? layout.columns;
|
|
62
|
+
// Folded from what is DRAWN rather than read off the hook, so an
|
|
63
|
+
// override widens the page cap with it. A four-column grid inside
|
|
64
|
+
// a one-column cap is the same bug as no cap at all, upside down.
|
|
65
|
+
const contentMaxInlineSize = getContentMaxInlineSize({
|
|
66
|
+
columns: drawnColumns,
|
|
67
|
+
});
|
|
68
|
+
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
|
+
gridTemplateColumns: `repeat(${drawnColumns}, minmax(0, 1fr))`,
|
|
70
|
+
maxInlineSize: contentMaxInlineSize,
|
|
71
|
+
}, children: children }) }));
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=AdaptiveGrid.js.map
|
|
@@ -0,0 +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;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAE5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAgD5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAC3B,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,SAAS,EACT,OAAO,EACP,aAAa,EACb,SAAS,EACT,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,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;KACtB,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"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many columns a wrapping grid should draw, and how wide the
|
|
3
|
+
* page around it may get.
|
|
4
|
+
*
|
|
5
|
+
* The arithmetic, lifted out of rip-deck's `useLayoutColumns` and
|
|
6
|
+
* made generic. It stays a pure fold — no `window`, no ref, no
|
|
7
|
+
* React — because a heuristic nobody can unit-test at nine sizes is
|
|
8
|
+
* a heuristic hand-tuned against one screenshot, and the table in
|
|
9
|
+
* `chooseColumns.test.ts` is the only form in which the rule can be
|
|
10
|
+
* checked at all.
|
|
11
|
+
*
|
|
12
|
+
* ## Height is spent first
|
|
13
|
+
*
|
|
14
|
+
* The owner's ask, which is the whole design:
|
|
15
|
+
*
|
|
16
|
+
* > "All these apps seem to be really narrow with a very large
|
|
17
|
+
* > max-width — 1 column, but waaaaaaay too wide. What I really
|
|
18
|
+
* > want is something like Rip-Deck where the app has a narrower
|
|
19
|
+
* > main column but the wrapping grids are all full-width only when
|
|
20
|
+
* > you have too many items. […] The idea is that, if you're going
|
|
21
|
+
* > to vertically scroll, it's best to widen the displayed items.
|
|
22
|
+
* > If not, then keep them in a smaller grid, so they all still fit
|
|
23
|
+
* > on screen. Ideally, we wouldn't require users to scroll."
|
|
24
|
+
*
|
|
25
|
+
* And the sentence it replaced, from the app this came out of:
|
|
26
|
+
*
|
|
27
|
+
* > "Like if you have enough height, try to fill it. If you don't,
|
|
28
|
+
* > then abuse as much width side-by-side as possible. That way,
|
|
29
|
+
* > you don't get 9-wide just because you're on an ultrawide even
|
|
30
|
+
* > if you have more height available."
|
|
31
|
+
*
|
|
32
|
+
* Stated plainly: **a column is something the layout is FORCED
|
|
33
|
+
* into** when the items will not stack inside the space available —
|
|
34
|
+
* never something it takes merely because a monitor is wide. That
|
|
35
|
+
* inversion is why `availableInlineSize` only ever *caps* the
|
|
36
|
+
* answer here rather than producing it, and it is the opposite of
|
|
37
|
+
* every `auto-fill, minmax()` grid in the fleet, which takes every
|
|
38
|
+
* column the width allows and lands on seven items across an
|
|
39
|
+
* ultrawide.
|
|
40
|
+
*
|
|
41
|
+
* The visible consequence is deliberately non-monotonic: 1440x900
|
|
42
|
+
* takes three columns while the *larger* 1920x1080 takes two. That
|
|
43
|
+
* reads backwards and is the rule working — the taller window
|
|
44
|
+
* stacks the same items in fewer stacks, so it needs fewer.
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* The most columns the automatic answer will ever choose.
|
|
48
|
+
*
|
|
49
|
+
* > "It would look weird to do 9 side-by-side."
|
|
50
|
+
*
|
|
51
|
+
* Three is the number the owner said he could "easily fit". A
|
|
52
|
+
* caller with squarer content raises it; a caller with wide content
|
|
53
|
+
* lowers it. It is taste about one app's content, which is exactly
|
|
54
|
+
* why it is a default rather than a constant.
|
|
55
|
+
*/
|
|
56
|
+
export declare const DEFAULT_MAX_AUTO_COLUMNS = 3;
|
|
57
|
+
/**
|
|
58
|
+
* The widest a manual picker offers, one above the automatic cap —
|
|
59
|
+
* because a cap is a default and not a ceiling on what a person is
|
|
60
|
+
* allowed to ask for.
|
|
61
|
+
*/
|
|
62
|
+
export declare const DEFAULT_MAX_MANUAL_COLUMNS = 4;
|
|
63
|
+
/**
|
|
64
|
+
* The narrowest a column may be, in CSS px, before the grid stops
|
|
65
|
+
* adding them. `24rem` at a 16px root — `containerQuery.sm`.
|
|
66
|
+
*
|
|
67
|
+
* ## Which threshold system this is, and which it is not
|
|
68
|
+
*
|
|
69
|
+
* Two live in the fleet today and they answer different questions,
|
|
70
|
+
* so this reconciles them by *keeping them apart*:
|
|
71
|
+
*
|
|
72
|
+
* - A `cq-*` step is read **by the item, inside the track**: "how
|
|
73
|
+
* should this card lay itself out at the width it was handed."
|
|
74
|
+
* Charcuterie's are `--cq-xs` … `--cq-xl`, deliberately not
|
|
75
|
+
* Tailwind's `--container-*` (see
|
|
76
|
+
* `docs/decisions/2026-07-29-container-query-scale-is-cq-not-container.md`).
|
|
77
|
+
* - This number is read **by the grid, outside the item**: "is
|
|
78
|
+
* another track worth having at all."
|
|
79
|
+
*
|
|
80
|
+
* Nothing forces them to agree, and the source app's did not: its
|
|
81
|
+
* cards restyle at Tailwind's own `28rem` container variant while
|
|
82
|
+
* its grid floor sat at a hand-measured `380px`. It set the floor
|
|
83
|
+
* *below* the restyle threshold on purpose, because the denser card
|
|
84
|
+
* that appears under it is a real density rather than a failure.
|
|
85
|
+
*
|
|
86
|
+
* That relationship is what survives here, expressed in
|
|
87
|
+
* Charcuterie's own scale instead of a magic number: the floor
|
|
88
|
+
* defaults to `cq-sm` (24rem = 384px), which is within 4px of the
|
|
89
|
+
* measured 380 — every row of the ported spec table gives the same
|
|
90
|
+
* answer at either value — and stays a step below `cq-md` (32rem),
|
|
91
|
+
* where the library's own container-query components change shape.
|
|
92
|
+
*
|
|
93
|
+
* The link is asserted in `chooseColumns.test.ts` so it cannot
|
|
94
|
+
* drift back into a bare number.
|
|
95
|
+
*/
|
|
96
|
+
export declare const DEFAULT_MIN_COLUMN_INLINE_SIZE_PX: number;
|
|
97
|
+
/**
|
|
98
|
+
* `"auto"`, or the number of columns a person explicitly asked for.
|
|
99
|
+
*/
|
|
100
|
+
export type ColumnChoice = "auto" | number;
|
|
101
|
+
/**
|
|
102
|
+
* The column count the automatic rule wants, for one measured space
|
|
103
|
+
* and one set of items.
|
|
104
|
+
*/
|
|
105
|
+
export declare const chooseColumns: ({ availableBlockSize, availableInlineSize, chromeBlockSize, itemBlockSize, itemCount, maxColumns, minColumnInlineSize, }: {
|
|
106
|
+
/**
|
|
107
|
+
* The block size the layout has to spend, in CSS px — the
|
|
108
|
+
* viewport's, not the grid's.
|
|
109
|
+
*
|
|
110
|
+
* It has to come from the viewport, because the question being
|
|
111
|
+
* asked is "will this scroll", and an element's own block size
|
|
112
|
+
* cannot answer it: a grid in normal flow is exactly as tall as
|
|
113
|
+
* its contents, so measuring it always says "it fits."
|
|
114
|
+
*/
|
|
115
|
+
availableBlockSize: number;
|
|
116
|
+
/**
|
|
117
|
+
* The inline size the grid has to spend, in CSS px — the
|
|
118
|
+
* container's, not the viewport's.
|
|
119
|
+
*
|
|
120
|
+
* The container is the honest source here: a grid sitting beside
|
|
121
|
+
* a rail has less room than the window suggests, and this library
|
|
122
|
+
* is built around the case where "the component's container is
|
|
123
|
+
* what changed, not the window."
|
|
124
|
+
*
|
|
125
|
+
* It must be measured on an element that is **not itself capped
|
|
126
|
+
* by the answer**, or the fold feeds on its own output and can
|
|
127
|
+
* never widen. `AdaptiveGrid` guarantees that structurally.
|
|
128
|
+
*/
|
|
129
|
+
availableInlineSize: number;
|
|
130
|
+
/**
|
|
131
|
+
* Everything down the page that is not this grid, in CSS px —
|
|
132
|
+
* headers, rails, filter rows, labels. Subtracted from
|
|
133
|
+
* `availableBlockSize` before asking how many items stack.
|
|
134
|
+
*/
|
|
135
|
+
chromeBlockSize?: number;
|
|
136
|
+
/**
|
|
137
|
+
* One item's block size, in CSS px. **The one genuinely
|
|
138
|
+
* app-specific number**, and the only required one.
|
|
139
|
+
*
|
|
140
|
+
* Measure it off a running page rather than deriving it, and err
|
|
141
|
+
* high: over-estimating means the grid reaches for a column
|
|
142
|
+
* slightly early, and a page that scrolls when it did not have to
|
|
143
|
+
* is the complaint this exists to answer. It only has to be right
|
|
144
|
+
* to within about an item — being one out shifts a borderline
|
|
145
|
+
* size by one column, which is taste.
|
|
146
|
+
*/
|
|
147
|
+
itemBlockSize: number;
|
|
148
|
+
/**
|
|
149
|
+
* How many items the grid is being asked to fit.
|
|
150
|
+
*
|
|
151
|
+
* The stable count rather than the rendered one where those
|
|
152
|
+
* differ: a column count that reflowed every time one item
|
|
153
|
+
* finished loading would be worse than one that is an item out.
|
|
154
|
+
*/
|
|
155
|
+
itemCount: number;
|
|
156
|
+
/** @see DEFAULT_MAX_AUTO_COLUMNS */
|
|
157
|
+
maxColumns?: number;
|
|
158
|
+
/** @see DEFAULT_MIN_COLUMN_INLINE_SIZE_PX */
|
|
159
|
+
minColumnInlineSize?: number;
|
|
160
|
+
}) => number;
|
|
161
|
+
/**
|
|
162
|
+
* How wide the content around the grid may grow, as a CSS length.
|
|
163
|
+
*
|
|
164
|
+
* The other half of the ask — "the app has a narrower main column
|
|
165
|
+
* but the wrapping grids are all full-width only when you have too
|
|
166
|
+
* many items." One column stays at a reading measure, because a
|
|
167
|
+
* 2000px-wide card is not a better card, it is one line of text the
|
|
168
|
+
* eye has to track across a monitor. Past that the cap **grows with
|
|
169
|
+
* the columns**, so three columns get room to be three readable
|
|
170
|
+
* things rather than three slivers.
|
|
171
|
+
*
|
|
172
|
+
* ### Why the numbers live in `@charcuterie/tokens`
|
|
173
|
+
*
|
|
174
|
+
* They are `contentInlineSize`, not constants in this file. A
|
|
175
|
+
* readable measure is a structural fact about the fleet in exactly
|
|
176
|
+
* the sense `screen` and `containerQuery` are — a variant may
|
|
177
|
+
* change how a card *looks*, not how far the eye tracks — so it
|
|
178
|
+
* belongs in the one package a Satori renderer or a plain-CSS
|
|
179
|
+
* consumer can read without a React tree. The *arithmetic* is not a
|
|
180
|
+
* token, and stays here.
|
|
181
|
+
*
|
|
182
|
+
* The three parts are still overridable per call, because an app of
|
|
183
|
+
* dense tables and an app of prose disagree about a measure and
|
|
184
|
+
* neither is wrong.
|
|
185
|
+
*/
|
|
186
|
+
export declare const getContentMaxInlineSize: ({ columnInlineSize, columns, gutterInlineSize, singleInlineSize, }: {
|
|
187
|
+
/** What one column is worth, once there are several. */
|
|
188
|
+
columnInlineSize?: string;
|
|
189
|
+
columns: number;
|
|
190
|
+
/** Slack added on top of a multi-column cap, for the gaps. */
|
|
191
|
+
gutterInlineSize?: string;
|
|
192
|
+
/** The cap when there is only one column. */
|
|
193
|
+
singleInlineSize?: string;
|
|
194
|
+
}) => string;
|
|
195
|
+
/**
|
|
196
|
+
* The choices a manual picker offers: `"auto"`, then every count up
|
|
197
|
+
* to `maxColumns`.
|
|
198
|
+
*
|
|
199
|
+
* A function rather than a constant so the picker and the cap
|
|
200
|
+
* cannot disagree — an app that lowers its cap gets a shorter list
|
|
201
|
+
* for free, instead of offering a count it will then refuse.
|
|
202
|
+
*/
|
|
203
|
+
export declare const getColumnChoices: ({ maxColumns, }: {
|
|
204
|
+
maxColumns?: number;
|
|
205
|
+
}) => ColumnChoice[];
|
|
206
|
+
//# sourceMappingURL=chooseColumns.d.ts.map
|
|
@@ -0,0 +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,0HAQ3B;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,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,KAAG,MA4BH,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,uBAAuB,GAAI,oEAKrC;IACD,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,KAAG,MAG6F,CAAA;AAEjG;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,iBAE9B;IACD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,KAAG,YAAY,EAMf,CAAA"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { containerQuery, contentInlineSize, } from "../tokens.js";
|
|
2
|
+
/**
|
|
3
|
+
* How many columns a wrapping grid should draw, and how wide the
|
|
4
|
+
* page around it may get.
|
|
5
|
+
*
|
|
6
|
+
* The arithmetic, lifted out of rip-deck's `useLayoutColumns` and
|
|
7
|
+
* made generic. It stays a pure fold — no `window`, no ref, no
|
|
8
|
+
* React — because a heuristic nobody can unit-test at nine sizes is
|
|
9
|
+
* a heuristic hand-tuned against one screenshot, and the table in
|
|
10
|
+
* `chooseColumns.test.ts` is the only form in which the rule can be
|
|
11
|
+
* checked at all.
|
|
12
|
+
*
|
|
13
|
+
* ## Height is spent first
|
|
14
|
+
*
|
|
15
|
+
* The owner's ask, which is the whole design:
|
|
16
|
+
*
|
|
17
|
+
* > "All these apps seem to be really narrow with a very large
|
|
18
|
+
* > max-width — 1 column, but waaaaaaay too wide. What I really
|
|
19
|
+
* > want is something like Rip-Deck where the app has a narrower
|
|
20
|
+
* > main column but the wrapping grids are all full-width only when
|
|
21
|
+
* > you have too many items. […] The idea is that, if you're going
|
|
22
|
+
* > to vertically scroll, it's best to widen the displayed items.
|
|
23
|
+
* > If not, then keep them in a smaller grid, so they all still fit
|
|
24
|
+
* > on screen. Ideally, we wouldn't require users to scroll."
|
|
25
|
+
*
|
|
26
|
+
* And the sentence it replaced, from the app this came out of:
|
|
27
|
+
*
|
|
28
|
+
* > "Like if you have enough height, try to fill it. If you don't,
|
|
29
|
+
* > then abuse as much width side-by-side as possible. That way,
|
|
30
|
+
* > you don't get 9-wide just because you're on an ultrawide even
|
|
31
|
+
* > if you have more height available."
|
|
32
|
+
*
|
|
33
|
+
* Stated plainly: **a column is something the layout is FORCED
|
|
34
|
+
* into** when the items will not stack inside the space available —
|
|
35
|
+
* never something it takes merely because a monitor is wide. That
|
|
36
|
+
* inversion is why `availableInlineSize` only ever *caps* the
|
|
37
|
+
* answer here rather than producing it, and it is the opposite of
|
|
38
|
+
* every `auto-fill, minmax()` grid in the fleet, which takes every
|
|
39
|
+
* column the width allows and lands on seven items across an
|
|
40
|
+
* ultrawide.
|
|
41
|
+
*
|
|
42
|
+
* The visible consequence is deliberately non-monotonic: 1440x900
|
|
43
|
+
* takes three columns while the *larger* 1920x1080 takes two. That
|
|
44
|
+
* reads backwards and is the rule working — the taller window
|
|
45
|
+
* stacks the same items in fewer stacks, so it needs fewer.
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* The most columns the automatic answer will ever choose.
|
|
49
|
+
*
|
|
50
|
+
* > "It would look weird to do 9 side-by-side."
|
|
51
|
+
*
|
|
52
|
+
* Three is the number the owner said he could "easily fit". A
|
|
53
|
+
* caller with squarer content raises it; a caller with wide content
|
|
54
|
+
* lowers it. It is taste about one app's content, which is exactly
|
|
55
|
+
* why it is a default rather than a constant.
|
|
56
|
+
*/
|
|
57
|
+
export const DEFAULT_MAX_AUTO_COLUMNS = 3;
|
|
58
|
+
/**
|
|
59
|
+
* The widest a manual picker offers, one above the automatic cap —
|
|
60
|
+
* because a cap is a default and not a ceiling on what a person is
|
|
61
|
+
* allowed to ask for.
|
|
62
|
+
*/
|
|
63
|
+
export const DEFAULT_MAX_MANUAL_COLUMNS = 4;
|
|
64
|
+
/**
|
|
65
|
+
* The narrowest a column may be, in CSS px, before the grid stops
|
|
66
|
+
* adding them. `24rem` at a 16px root — `containerQuery.sm`.
|
|
67
|
+
*
|
|
68
|
+
* ## Which threshold system this is, and which it is not
|
|
69
|
+
*
|
|
70
|
+
* Two live in the fleet today and they answer different questions,
|
|
71
|
+
* so this reconciles them by *keeping them apart*:
|
|
72
|
+
*
|
|
73
|
+
* - A `cq-*` step is read **by the item, inside the track**: "how
|
|
74
|
+
* should this card lay itself out at the width it was handed."
|
|
75
|
+
* Charcuterie's are `--cq-xs` … `--cq-xl`, deliberately not
|
|
76
|
+
* Tailwind's `--container-*` (see
|
|
77
|
+
* `docs/decisions/2026-07-29-container-query-scale-is-cq-not-container.md`).
|
|
78
|
+
* - This number is read **by the grid, outside the item**: "is
|
|
79
|
+
* another track worth having at all."
|
|
80
|
+
*
|
|
81
|
+
* Nothing forces them to agree, and the source app's did not: its
|
|
82
|
+
* cards restyle at Tailwind's own `28rem` container variant while
|
|
83
|
+
* its grid floor sat at a hand-measured `380px`. It set the floor
|
|
84
|
+
* *below* the restyle threshold on purpose, because the denser card
|
|
85
|
+
* that appears under it is a real density rather than a failure.
|
|
86
|
+
*
|
|
87
|
+
* That relationship is what survives here, expressed in
|
|
88
|
+
* Charcuterie's own scale instead of a magic number: the floor
|
|
89
|
+
* defaults to `cq-sm` (24rem = 384px), which is within 4px of the
|
|
90
|
+
* measured 380 — every row of the ported spec table gives the same
|
|
91
|
+
* answer at either value — and stays a step below `cq-md` (32rem),
|
|
92
|
+
* where the library's own container-query components change shape.
|
|
93
|
+
*
|
|
94
|
+
* The link is asserted in `chooseColumns.test.ts` so it cannot
|
|
95
|
+
* drift back into a bare number.
|
|
96
|
+
*/
|
|
97
|
+
export const DEFAULT_MIN_COLUMN_INLINE_SIZE_PX = Number.parseFloat(containerQuery.sm) * 16;
|
|
98
|
+
/**
|
|
99
|
+
* The column count the automatic rule wants, for one measured space
|
|
100
|
+
* and one set of items.
|
|
101
|
+
*/
|
|
102
|
+
export const chooseColumns = ({ availableBlockSize, availableInlineSize, chromeBlockSize = 0, itemBlockSize, itemCount, maxColumns = DEFAULT_MAX_AUTO_COLUMNS, minColumnInlineSize = DEFAULT_MIN_COLUMN_INLINE_SIZE_PX, }) => {
|
|
103
|
+
// Inline size is a CAP, never a reason. This is the "don't go
|
|
104
|
+
// 9-wide just because you're on an ultrawide" half of the rule.
|
|
105
|
+
const inlineSizeCap = Math.max(1, Math.min(maxColumns, Math.floor(availableInlineSize / minColumnInlineSize)));
|
|
106
|
+
if (itemCount <= 1) {
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
// Block size is the reason. How many items stack in the space,
|
|
110
|
+
// then how many stacks that many items need.
|
|
111
|
+
const rowsThatFit = Math.max(1, Math.floor((availableBlockSize - chromeBlockSize) /
|
|
112
|
+
itemBlockSize));
|
|
113
|
+
const columnsNeeded = Math.ceil(itemCount / rowsThatFit);
|
|
114
|
+
return Math.max(1, Math.min(inlineSizeCap, columnsNeeded));
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* How wide the content around the grid may grow, as a CSS length.
|
|
118
|
+
*
|
|
119
|
+
* The other half of the ask — "the app has a narrower main column
|
|
120
|
+
* but the wrapping grids are all full-width only when you have too
|
|
121
|
+
* many items." One column stays at a reading measure, because a
|
|
122
|
+
* 2000px-wide card is not a better card, it is one line of text the
|
|
123
|
+
* eye has to track across a monitor. Past that the cap **grows with
|
|
124
|
+
* the columns**, so three columns get room to be three readable
|
|
125
|
+
* things rather than three slivers.
|
|
126
|
+
*
|
|
127
|
+
* ### Why the numbers live in `@charcuterie/tokens`
|
|
128
|
+
*
|
|
129
|
+
* They are `contentInlineSize`, not constants in this file. A
|
|
130
|
+
* readable measure is a structural fact about the fleet in exactly
|
|
131
|
+
* the sense `screen` and `containerQuery` are — a variant may
|
|
132
|
+
* change how a card *looks*, not how far the eye tracks — so it
|
|
133
|
+
* belongs in the one package a Satori renderer or a plain-CSS
|
|
134
|
+
* consumer can read without a React tree. The *arithmetic* is not a
|
|
135
|
+
* token, and stays here.
|
|
136
|
+
*
|
|
137
|
+
* The three parts are still overridable per call, because an app of
|
|
138
|
+
* dense tables and an app of prose disagree about a measure and
|
|
139
|
+
* neither is wrong.
|
|
140
|
+
*/
|
|
141
|
+
export const getContentMaxInlineSize = ({ columnInlineSize = contentInlineSize.column, columns, gutterInlineSize = contentInlineSize.gutter, singleInlineSize = contentInlineSize.single, }) => columns <= 1
|
|
142
|
+
? singleInlineSize
|
|
143
|
+
: `${Number.parseFloat(columnInlineSize) * columns + Number.parseFloat(gutterInlineSize)}rem`;
|
|
144
|
+
/**
|
|
145
|
+
* The choices a manual picker offers: `"auto"`, then every count up
|
|
146
|
+
* to `maxColumns`.
|
|
147
|
+
*
|
|
148
|
+
* A function rather than a constant so the picker and the cap
|
|
149
|
+
* cannot disagree — an app that lowers its cap gets a shorter list
|
|
150
|
+
* for free, instead of offering a count it will then refuse.
|
|
151
|
+
*/
|
|
152
|
+
export const getColumnChoices = ({ maxColumns = DEFAULT_MAX_MANUAL_COLUMNS, }) => [
|
|
153
|
+
"auto",
|
|
154
|
+
...Array.from({ length: Math.max(1, maxColumns) }, (_, index) => index + 1),
|
|
155
|
+
];
|
|
156
|
+
//# sourceMappingURL=chooseColumns.js.map
|
|
@@ -0,0 +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;AAO3C;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC5B,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,GAAG,CAAC,EACnB,aAAa,EACb,SAAS,EACT,UAAU,GAAG,wBAAwB,EACrC,mBAAmB,GAAG,iCAAiC,GAwDxD,EAAU,EAAE;IACX,8DAA8D;IAC9D,gEAAgE;IAChE,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAC5B,CAAC,EACD,IAAI,CAAC,GAAG,CACN,UAAU,EACV,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,mBAAmB,CAAC,CACtD,CACF,CAAA;IAED,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,CAAA;IACV,CAAC;IAED,+DAA+D;IAC/D,6CAA6C;IAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAC1B,CAAC,EACD,IAAI,CAAC,KAAK,CACR,CAAC,kBAAkB,GAAG,eAAe,CAAC;QACpC,aAAa,CAChB,CACF,CAAA;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,CAAA;IAExD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC,CAAA;AAC5D,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,EACtC,gBAAgB,GAAG,iBAAiB,CAAC,MAAM,EAC3C,OAAO,EACP,gBAAgB,GAAG,iBAAiB,CAAC,MAAM,EAC3C,gBAAgB,GAAG,iBAAiB,CAAC,MAAM,GAS5C,EAAU,EAAE,CACX,OAAO,IAAI,CAAC;IACV,CAAC,CAAC,gBAAgB;IAClB,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,GAAG,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,KAAK,CAAA;AAEjG;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,UAAU,GAAG,0BAA0B,GAGxC,EAAkB,EAAE,CAAC;IACpB,MAAM;IACN,GAAG,KAAK,CAAC,IAAI,CACX,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,EACnC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CACxB;CACF,CAAA"}
|