@charcuterie/ui 2.6.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 +13 -1
- 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/dist/styles.css +88 -8
- 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/src/styles.css +88 -8
package/dist/index.js
CHANGED
|
@@ -31,22 +31,26 @@
|
|
|
31
31
|
* this package's README has always told it to do.
|
|
32
32
|
*/
|
|
33
33
|
export { Accordion } from "./Accordion/Accordion.js";
|
|
34
|
+
export { AdaptiveGrid } from "./AdaptiveGrid/AdaptiveGrid.js";
|
|
35
|
+
export { chooseColumns, DEFAULT_MAX_AUTO_COLUMNS, DEFAULT_MAX_MANUAL_COLUMNS, DEFAULT_MIN_COLUMN_INLINE_SIZE_PX, getColumnChoices, getContentMaxInlineSize, } from "./AdaptiveGrid/chooseColumns.js";
|
|
36
|
+
export { localStorageColumnPersistence, readStoredChoice, useAdaptiveColumns, viewportBlockSizeResolver, } from "./AdaptiveGrid/useAdaptiveColumns.js";
|
|
34
37
|
export { Alert } from "./Alert/Alert.js";
|
|
35
38
|
export { Badge } from "./Badge/Badge.js";
|
|
36
39
|
export { Button } from "./Button/Button.js";
|
|
40
|
+
export { ButtonLink } from "./ButtonLink/ButtonLink.js";
|
|
37
41
|
export { Card } from "./Card/Card.js";
|
|
38
42
|
export { Checkbox } from "./Checkbox/Checkbox.js";
|
|
39
43
|
export { ColorSchemeSwitcher } from "./ColorSchemeSwitcher/ColorSchemeSwitcher.js";
|
|
40
44
|
export { ColorSchemeToggle } from "./ColorSchemeToggle/ColorSchemeToggle.js";
|
|
41
45
|
export { Combobox } from "./Combobox/Combobox.js";
|
|
42
|
-
export { BADGE_SIZE_CLASS, CONTROL_SIZE_CLASS, DOT_SIZE_CLASS, ICON_CONTROL_SIZE_CLASS, MIN_TOUCH_TARGET_CLASS, SPINNER_SIZE_CLASS, } from "./controlStyles.js";
|
|
46
|
+
export { BADGE_SIZE_CLASS, CONTROL_BASE_CLASS, CONTROL_SIZE_CLASS, DOT_SIZE_CLASS, getControlClassName, ICON_CONTROL_SIZE_CLASS, MIN_TOUCH_TARGET_CLASS, SPINNER_SIZE_CLASS, } from "./controlStyles.js";
|
|
43
47
|
export { Dialog } from "./Dialog/Dialog.js";
|
|
44
48
|
export { EmptyState } from "./EmptyState/EmptyState.js";
|
|
45
49
|
export { Field } from "./Field/Field.js";
|
|
46
50
|
export { FieldGroup } from "./Field/FieldGroup.js";
|
|
47
51
|
export { FileDropZone } from "./FileDropZone/FileDropZone.js";
|
|
48
52
|
export { IconButton } from "./IconButton/IconButton.js";
|
|
49
|
-
export { DISABLED_CLASS, FOCUS_RING_CLASS, INTENT_APPEARANCE_CLASS, INTENT_CONTENT_CLASS, INTENT_HOVER_CLASS, INTENT_SOLID_FILL_CLASS, } from "./intentStyles.js";
|
|
53
|
+
export { ARIA_DISABLED_CLASS, DISABLED_CLASS, FOCUS_RING_CLASS, INTENT_APPEARANCE_CLASS, INTENT_CONTENT_CLASS, INTENT_HOVER_CLASS, INTENT_SOLID_FILL_CLASS, } from "./intentStyles.js";
|
|
50
54
|
export { Lightbox } from "./Lightbox/Lightbox.js";
|
|
51
55
|
export { Listbox } from "./Listbox/Listbox.js";
|
|
52
56
|
export { LiveStatusIndicator } from "./LiveStatusIndicator/LiveStatusIndicator.js";
|
|
@@ -59,6 +63,9 @@ export { Popover } from "./Popover/Popover.js";
|
|
|
59
63
|
export { ProgressBar } from "./ProgressBar/ProgressBar.js";
|
|
60
64
|
export { getProgressIntent, toProgressPercent, toProgressValue, } from "./ProgressBar/progressValue.js";
|
|
61
65
|
export { RadioGroup } from "./RadioGroup/RadioGroup.js";
|
|
66
|
+
export { AnchorLink } from "./RouterLink/AnchorLink.js";
|
|
67
|
+
export { RouterLinkProvider, useRouterLink, } from "./RouterLink/RouterLinkProvider.js";
|
|
68
|
+
export { getIsRoutedHref } from "./RouterLink/routerLink.js";
|
|
62
69
|
export { SegmentedControl } from "./SegmentedControl/SegmentedControl.js";
|
|
63
70
|
export { Select } from "./Select/Select.js";
|
|
64
71
|
export { Skeleton } from "./Skeleton/Skeleton.js";
|
|
@@ -69,6 +76,7 @@ export { Switch } from "./Switch/Switch.js";
|
|
|
69
76
|
export { mergeSlotProps } from "./slotProps.js";
|
|
70
77
|
export { getAsyncIntent, getAsyncLabel, getConnectionIntent, getConnectionLabel, getIsConnectionBusy, } from "./statusIntent.js";
|
|
71
78
|
export { Tabs } from "./Tabs/Tabs.js";
|
|
79
|
+
export { TextLink } from "./TextLink/TextLink.js";
|
|
72
80
|
export { Toast } from "./Toast/Toast.js";
|
|
73
81
|
export { ToastRegion } from "./Toast/ToastRegion.js";
|
|
74
82
|
export { toastTransitions } from "./Toast/toastLifecycle.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAOH,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/intentStyles.d.ts
CHANGED
|
@@ -73,4 +73,21 @@ export declare const FOCUS_RING_CLASS = "focus-visible:outline-solid focus-visib
|
|
|
73
73
|
* Keeping it in one constant is what stops it drifting onto prose.
|
|
74
74
|
*/
|
|
75
75
|
export declare const DISABLED_CLASS = "disabled:cursor-not-allowed disabled:border-border-subtle disabled:bg-surface-sunken disabled:text-content-disabled disabled:shadow-none";
|
|
76
|
+
/**
|
|
77
|
+
* The same treatment for something that cannot *be* disabled.
|
|
78
|
+
*
|
|
79
|
+
* **`disabled` is not a thing an `<a>` has.** There is no attribute,
|
|
80
|
+
* no `:disabled` match, and no browser behaviour to inherit — so a
|
|
81
|
+
* "disabled link" is entirely something a component has to build, and
|
|
82
|
+
* the usual build of it is a focusable `<a href>` that silently does
|
|
83
|
+
* nothing when pressed. `ButtonLink` instead drops `href` (the
|
|
84
|
+
* platform's own way to make an anchor inert and unfocusable) and
|
|
85
|
+
* says so with `aria-disabled`, which is what this paints against.
|
|
86
|
+
*
|
|
87
|
+
* `pointer-events-none` rather than `cursor-not-allowed`: without a
|
|
88
|
+
* real `:disabled`, the `hover:` classes still match — CSS `:hover`
|
|
89
|
+
* fires on disabled elements too — so the hover fill has to be taken
|
|
90
|
+
* off the table rather than merely overridden.
|
|
91
|
+
*/
|
|
92
|
+
export declare const ARIA_DISABLED_CLASS = "aria-disabled:pointer-events-none aria-disabled:border-border-subtle aria-disabled:bg-surface-sunken aria-disabled:text-content-disabled aria-disabled:shadow-none";
|
|
76
93
|
//# sourceMappingURL=intentStyles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intentStyles.d.ts","sourceRoot":"","sources":["../src/intentStyles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GACxB,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,CAAA;AAEX,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,UAAU,EACV,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAwDjC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CACrC,UAAU,EACV,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAsCjC,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,UAAU,EACV,MAAM,CAQP,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CACvC,UAAU,EACV,MAAM,CAQP,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,sKACwI,CAAA;AAErK;;;;;GAKG;AACH,eAAO,MAAM,cAAc,6IACiH,CAAA"}
|
|
1
|
+
{"version":3,"file":"intentStyles.d.ts","sourceRoot":"","sources":["../src/intentStyles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GACxB,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,CAAA;AAEX,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,UAAU,EACV,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAwDjC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CACrC,UAAU,EACV,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAsCjC,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,UAAU,EACV,MAAM,CAQP,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CACvC,UAAU,EACV,MAAM,CAQP,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,sKACwI,CAAA;AAErK;;;;;GAKG;AACH,eAAO,MAAM,cAAc,6IACiH,CAAA;AAE5I;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB,uKACsI,CAAA"}
|
package/dist/intentStyles.js
CHANGED
|
@@ -147,4 +147,21 @@ export const FOCUS_RING_CLASS = "focus-visible:outline-solid focus-visible:outli
|
|
|
147
147
|
* Keeping it in one constant is what stops it drifting onto prose.
|
|
148
148
|
*/
|
|
149
149
|
export const DISABLED_CLASS = "disabled:cursor-not-allowed disabled:border-border-subtle disabled:bg-surface-sunken disabled:text-content-disabled disabled:shadow-none";
|
|
150
|
+
/**
|
|
151
|
+
* The same treatment for something that cannot *be* disabled.
|
|
152
|
+
*
|
|
153
|
+
* **`disabled` is not a thing an `<a>` has.** There is no attribute,
|
|
154
|
+
* no `:disabled` match, and no browser behaviour to inherit — so a
|
|
155
|
+
* "disabled link" is entirely something a component has to build, and
|
|
156
|
+
* the usual build of it is a focusable `<a href>` that silently does
|
|
157
|
+
* nothing when pressed. `ButtonLink` instead drops `href` (the
|
|
158
|
+
* platform's own way to make an anchor inert and unfocusable) and
|
|
159
|
+
* says so with `aria-disabled`, which is what this paints against.
|
|
160
|
+
*
|
|
161
|
+
* `pointer-events-none` rather than `cursor-not-allowed`: without a
|
|
162
|
+
* real `:disabled`, the `hover:` classes still match — CSS `:hover`
|
|
163
|
+
* fires on disabled elements too — so the hover fill has to be taken
|
|
164
|
+
* off the table rather than merely overridden.
|
|
165
|
+
*/
|
|
166
|
+
export const ARIA_DISABLED_CLASS = "aria-disabled:pointer-events-none aria-disabled:border-border-subtle aria-disabled:bg-surface-sunken aria-disabled:text-content-disabled aria-disabled:shadow-none";
|
|
150
167
|
//# sourceMappingURL=intentStyles.js.map
|
package/dist/intentStyles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intentStyles.js","sourceRoot":"","sources":["../src/intentStyles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAsBH,MAAM,CAAC,MAAM,uBAAuB,GAGhC;IACF,OAAO,EAAE;QACP,KAAK,EACH,wDAAwD;QAC1D,OAAO,EACL,yEAAyE;QAC3E,IAAI,EAAE,oFAAoF;QAC1F,KAAK,EACH,yEAAyE;KAC5E;IACD,MAAM,EAAE;QACN,KAAK,EACH,8DAA8D;QAChE,OAAO,EACL,uEAAuE;QACzE,IAAI,EAAE,iFAAiF;QACvF,KAAK,EACH,uEAAuE;KAC1E;IACD,OAAO,EAAE;QACP,KAAK,EACH,+DAA+D;QACjE,OAAO,EACL,yEAAyE;QAC3E,IAAI,EAAE,oFAAoF;QAC1F,KAAK,EACH,yEAAyE;KAC5E;IACD,OAAO,EAAE;QACP,KAAK,EACH,+DAA+D;QACjE,OAAO,EACL,yEAAyE;QAC3E,IAAI,EAAE,oFAAoF;QAC1F,KAAK,EACH,yEAAyE;KAC5E;IACD,MAAM,EAAE;QACN,KAAK,EACH,8DAA8D;QAChE,OAAO,EACL,uEAAuE;QACzE,IAAI,EAAE,iFAAiF;QACvF,KAAK,EACH,uEAAuE;KAC1E;IACD,IAAI,EAAE;QACJ,KAAK,EACH,4DAA4D;QAC9D,OAAO,EACL,mEAAmE;QACrE,IAAI,EAAE,2EAA2E;QACjF,KAAK,EACH,mEAAmE;KACtE;CACF,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAG3B;IACF,OAAO,EAAE;QACP,KAAK,EAAE,iCAAiC;QACxC,OAAO,EAAE,iCAAiC;QAC1C,IAAI,EAAE,uCAAuC;QAC7C,KAAK,EAAE,qCAAqC;KAC7C;IACD,MAAM,EAAE;QACN,KAAK,EAAE,gCAAgC;QACvC,OAAO,EAAE,gCAAgC;QACzC,IAAI,EAAE,sCAAsC;QAC5C,KAAK,EAAE,oCAAoC;KAC5C;IACD,OAAO,EAAE;QACP,KAAK,EAAE,iCAAiC;QACxC,OAAO,EAAE,iCAAiC;QAC1C,IAAI,EAAE,uCAAuC;QAC7C,KAAK,EAAE,qCAAqC;KAC7C;IACD,OAAO,EAAE;QACP,KAAK,EAAE,iCAAiC;QACxC,OAAO,EAAE,iCAAiC;QAC1C,IAAI,EAAE,uCAAuC;QAC7C,KAAK,EAAE,qCAAqC;KAC7C;IACD,MAAM,EAAE;QACN,KAAK,EAAE,gCAAgC;QACvC,OAAO,EAAE,gCAAgC;QACzC,IAAI,EAAE,sCAAsC;QAC5C,KAAK,EAAE,oCAAoC;KAC5C;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,8BAA8B;QACrC,OAAO,EAAE,8BAA8B;QACvC,IAAI,EAAE,oCAAoC;QAC1C,KAAK,EAAE,kCAAkC;KAC1C;CACF,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAGhC;IACF,OAAO,EAAE,yBAAyB;IAClC,MAAM,EAAE,wBAAwB;IAChC,OAAO,EAAE,yBAAyB;IAClC,OAAO,EAAE,yBAAyB;IAClC,MAAM,EAAE,wBAAwB;IAChC,IAAI,EAAE,sBAAsB;CAC7B,CAAA;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,oBAAoB,GAG7B;IACF,OAAO,EAAE,6BAA6B;IACtC,MAAM,EAAE,4BAA4B;IACpC,OAAO,EAAE,6BAA6B;IACtC,OAAO,EAAE,6BAA6B;IACtC,MAAM,EAAE,4BAA4B;IACpC,IAAI,EAAE,0BAA0B;CACjC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B,mKAAmK,CAAA;AAErK;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GACzB,0IAA0I,CAAA"}
|
|
1
|
+
{"version":3,"file":"intentStyles.js","sourceRoot":"","sources":["../src/intentStyles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { RouterLinkProps } from "../RouterLink/routerLink.ts";
|
|
3
|
+
/**
|
|
4
|
+
* react-router's `<Link>`, wearing the seam's `href`.
|
|
5
|
+
*
|
|
6
|
+
* The entire adapter, and that is the point: the seam's contract is
|
|
7
|
+
* "a component that takes `href`", so an adapter is a rename. wouter,
|
|
8
|
+
* TanStack Router, and a hand-rolled router each get the same four
|
|
9
|
+
* lines, written in the app rather than here.
|
|
10
|
+
*
|
|
11
|
+
* `to` versus `href` is the only mismatch worth naming. Everything
|
|
12
|
+
* else — `className`, `rel`, `target`, `aria-*`, the ref — passes
|
|
13
|
+
* through untouched, because react-router renders a real `<a>` and
|
|
14
|
+
* forwards what it does not understand.
|
|
15
|
+
*
|
|
16
|
+
* Imported from `react-router`, not `react-router-dom`. v7 and v8
|
|
17
|
+
* both export `Link` from the former, and `react-router-dom` v7 (what
|
|
18
|
+
* bambuddy has) is a re-export shim over exactly that module — so one
|
|
19
|
+
* import covers both installs, while naming `react-router-dom` would
|
|
20
|
+
* cover only one.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ReactRouterLink: ({ href, ...linkProps }: RouterLinkProps) => ReactNode;
|
|
23
|
+
//# sourceMappingURL=ReactRouterLink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactRouterLink.d.ts","sourceRoot":"","sources":["../../src/reactRouter/ReactRouterLink.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAElE;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,eAAe,GAAI,wBAG7B,eAAe,KAAG,SAEpB,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Link } from "react-router";
|
|
3
|
+
/**
|
|
4
|
+
* react-router's `<Link>`, wearing the seam's `href`.
|
|
5
|
+
*
|
|
6
|
+
* The entire adapter, and that is the point: the seam's contract is
|
|
7
|
+
* "a component that takes `href`", so an adapter is a rename. wouter,
|
|
8
|
+
* TanStack Router, and a hand-rolled router each get the same four
|
|
9
|
+
* lines, written in the app rather than here.
|
|
10
|
+
*
|
|
11
|
+
* `to` versus `href` is the only mismatch worth naming. Everything
|
|
12
|
+
* else — `className`, `rel`, `target`, `aria-*`, the ref — passes
|
|
13
|
+
* through untouched, because react-router renders a real `<a>` and
|
|
14
|
+
* forwards what it does not understand.
|
|
15
|
+
*
|
|
16
|
+
* Imported from `react-router`, not `react-router-dom`. v7 and v8
|
|
17
|
+
* both export `Link` from the former, and `react-router-dom` v7 (what
|
|
18
|
+
* bambuddy has) is a re-export shim over exactly that module — so one
|
|
19
|
+
* import covers both installs, while naming `react-router-dom` would
|
|
20
|
+
* cover only one.
|
|
21
|
+
*/
|
|
22
|
+
export const ReactRouterLink = ({ href, ...linkProps }) => (_jsx(Link, { ...linkProps, to: href }));
|
|
23
|
+
//# sourceMappingURL=ReactRouterLink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactRouterLink.js","sourceRoot":"","sources":["../../src/reactRouter/ReactRouterLink.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAInC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAC9B,IAAI,EACJ,GAAG,SAAS,EACI,EAAa,EAAE,CAAC,CAChC,KAAC,IAAI,OAAK,SAAS,EAAE,EAAE,EAAE,IAAI,GAAI,CAClC,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@charcuterie/ui/react-router` — the react-router adapter for the
|
|
3
|
+
* link seam.
|
|
4
|
+
*
|
|
5
|
+
* **A subpath export with an optional peer dependency**, and both
|
|
6
|
+
* halves of that matter. The base package must stay router-free: the
|
|
7
|
+
* fleet runs react-router v8, react-router-dom v7, wouter-preact, two
|
|
8
|
+
* hand-rolled routers, and five apps with no router at all, so a
|
|
9
|
+
* `react-router` in `@charcuterie/ui`'s dependencies would be a
|
|
10
|
+
* package eleven consumers install and six of them use. Optional
|
|
11
|
+
* peer + separate entry point means an app that never imports this
|
|
12
|
+
* path never resolves `react-router`, and `sourceRules.test.ts`
|
|
13
|
+
* asserts exactly that — the main entry is measured for what it
|
|
14
|
+
* reaches, so this cannot leak into it by accident.
|
|
15
|
+
*
|
|
16
|
+
* The wiring is one provider at the app root; `Guides/Routing` in
|
|
17
|
+
* Storybook is the copy-pasteable version.
|
|
18
|
+
*
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import { RouterLinkProvider } from "@charcuterie/ui"
|
|
21
|
+
* import { ReactRouterLink } from "@charcuterie/ui/react-router"
|
|
22
|
+
*
|
|
23
|
+
* <RouterLinkProvider link={ReactRouterLink}>
|
|
24
|
+
* <RouterProvider router={router} />
|
|
25
|
+
* </RouterLinkProvider>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export { ReactRouterLink } from "./ReactRouterLink.tsx";
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reactRouter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@charcuterie/ui/react-router` — the react-router adapter for the
|
|
3
|
+
* link seam.
|
|
4
|
+
*
|
|
5
|
+
* **A subpath export with an optional peer dependency**, and both
|
|
6
|
+
* halves of that matter. The base package must stay router-free: the
|
|
7
|
+
* fleet runs react-router v8, react-router-dom v7, wouter-preact, two
|
|
8
|
+
* hand-rolled routers, and five apps with no router at all, so a
|
|
9
|
+
* `react-router` in `@charcuterie/ui`'s dependencies would be a
|
|
10
|
+
* package eleven consumers install and six of them use. Optional
|
|
11
|
+
* peer + separate entry point means an app that never imports this
|
|
12
|
+
* path never resolves `react-router`, and `sourceRules.test.ts`
|
|
13
|
+
* asserts exactly that — the main entry is measured for what it
|
|
14
|
+
* reaches, so this cannot leak into it by accident.
|
|
15
|
+
*
|
|
16
|
+
* The wiring is one provider at the app root; `Guides/Routing` in
|
|
17
|
+
* Storybook is the copy-pasteable version.
|
|
18
|
+
*
|
|
19
|
+
* ```tsx
|
|
20
|
+
* import { RouterLinkProvider } from "@charcuterie/ui"
|
|
21
|
+
* import { ReactRouterLink } from "@charcuterie/ui/react-router"
|
|
22
|
+
*
|
|
23
|
+
* <RouterLinkProvider link={ReactRouterLink}>
|
|
24
|
+
* <RouterProvider router={router} />
|
|
25
|
+
* </RouterLinkProvider>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export { ReactRouterLink } from "./ReactRouterLink.js";
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reactRouter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAuB,CAAA"}
|
package/dist/styles.css
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
/* `@charcuterie/ui/styles.css` — the four looping affordances
|
|
2
|
-
*
|
|
1
|
+
/* `@charcuterie/ui/styles.css` — the four looping affordances and
|
|
2
|
+
* the token-tinted scrollbar: the visuals a Tailwind utility cannot
|
|
3
|
+
* express against our tokens, and nothing else.
|
|
3
4
|
*
|
|
4
5
|
* Every other visual in this package is a Tailwind utility reading
|
|
5
6
|
* a token, which is what makes a scheme/density/variant flip a
|
|
6
|
-
* repaint with no re-render.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `
|
|
7
|
+
* repaint with no re-render. Two things sit outside that reach.
|
|
8
|
+
* Animation is one: Tailwind's own `animate-spin` and `animate-pulse`
|
|
9
|
+
* hardcode 1s and 2s, ignore `prefers-reduced-motion`, and are
|
|
10
|
+
* therefore beyond the theme's reach — which is exactly why
|
|
11
|
+
* `MotionTokens` carries a separate `loopFast`/`loopSlow` ramp. The
|
|
12
|
+
* scrollbar is the other: the `::-webkit-scrollbar` pseudo-elements
|
|
13
|
+
* (and Firefox's `scrollbar-width`/`scrollbar-color`) have no
|
|
14
|
+
* `@theme`-generated utility, so `.charcuterie-scrollbar` at the foot
|
|
15
|
+
* of this file reads the same `--color-*` roles by hand and flips with
|
|
16
|
+
* `data-scheme` on the same repaint as everything else.
|
|
12
17
|
*
|
|
13
18
|
* Consumers import this once, after `@charcuterie/tokens/theme.css`.
|
|
14
19
|
*
|
|
@@ -128,3 +133,78 @@
|
|
|
128
133
|
);
|
|
129
134
|
}
|
|
130
135
|
}
|
|
136
|
+
|
|
137
|
+
/* `.charcuterie-scrollbar` — a token-tinted scrollbar for any element
|
|
138
|
+
* that scrolls. The fleet grew this twice by hand (gallery-downloader's
|
|
139
|
+
* `scrollbar-thin-token`, image-viewer's global `::-webkit-scrollbar`
|
|
140
|
+
* block); this is the one copy, promoted here so a scheme flip
|
|
141
|
+
* repaints it for free.
|
|
142
|
+
*
|
|
143
|
+
* The *designed* look is the `::-webkit-scrollbar` path: a 12px bar, a
|
|
144
|
+
* rounded thumb, a track-coloured inset, no step arrows. That is what
|
|
145
|
+
* Chromium, Edge, and Safari paint. Chromium 121+ will *prefer*
|
|
146
|
+
* `scrollbar-width` / `scrollbar-color` over these pseudo-elements
|
|
147
|
+
* whenever both are set, which collapses the bar to the thin OS chrome
|
|
148
|
+
* (arrows and all on Windows) — so the standard properties are scoped
|
|
149
|
+
* to Firefox only, where `::-webkit-scrollbar` never runs.
|
|
150
|
+
*
|
|
151
|
+
* Firefox gets the closest standard-property match (thin, token-tinted
|
|
152
|
+
* thumb, transparent track). It cannot round a corner or draw a track
|
|
153
|
+
* inset — a platform limit, not an omission here.
|
|
154
|
+
*
|
|
155
|
+
* `::-webkit-scrollbar-button` is suppressed deliberately: the
|
|
156
|
+
* affordance is the thumb on a track, not step arrows.
|
|
157
|
+
*
|
|
158
|
+
* Both engines read the same three roles — `border-strong` for the
|
|
159
|
+
* thumb, `surface-sunken` for the track, `content-muted` for the thumb
|
|
160
|
+
* on hover — so the bar is themed by `[data-scheme]` on `<html>` with
|
|
161
|
+
* nothing in React observing it. `width`/`height` rather than a
|
|
162
|
+
* logical property is not a lapse: the `::-webkit-scrollbar`
|
|
163
|
+
* pseudo-elements size only by the physical pair, and a vertical bar's
|
|
164
|
+
* thickness is its `width` regardless of writing direction. */
|
|
165
|
+
|
|
166
|
+
/* The designed bar — Chromium, Edge, Safari. */
|
|
167
|
+
.charcuterie-scrollbar::-webkit-scrollbar {
|
|
168
|
+
width: 12px;
|
|
169
|
+
height: 12px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.charcuterie-scrollbar::-webkit-scrollbar-button {
|
|
173
|
+
display: none;
|
|
174
|
+
width: 0;
|
|
175
|
+
height: 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.charcuterie-scrollbar::-webkit-scrollbar-track {
|
|
179
|
+
background-color: var(--color-surface-sunken);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.charcuterie-scrollbar::-webkit-scrollbar-thumb {
|
|
183
|
+
background-color: var(--color-border-strong);
|
|
184
|
+
border: 2px solid var(--color-surface-sunken);
|
|
185
|
+
border-radius: 6px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.charcuterie-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
189
|
+
background-color: var(--color-content-muted);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.charcuterie-scrollbar::-webkit-scrollbar-corner {
|
|
193
|
+
background-color: var(--color-surface-sunken);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Firefox only: it never paints `::-webkit-scrollbar`. `-moz-appearance`
|
|
197
|
+
* is the supports probe that Chromium and Safari reject, so this block
|
|
198
|
+
* does not reintroduce the standard properties on engines that would
|
|
199
|
+
* then drop the designed bar. */
|
|
200
|
+
@supports (-moz-appearance: none) {
|
|
201
|
+
.charcuterie-scrollbar {
|
|
202
|
+
scrollbar-width: thin;
|
|
203
|
+
scrollbar-color: color-mix(
|
|
204
|
+
in oklab,
|
|
205
|
+
var(--color-border-strong) 70%,
|
|
206
|
+
transparent
|
|
207
|
+
)
|
|
208
|
+
transparent;
|
|
209
|
+
}
|
|
210
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@charcuterie/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "The Charcuterie components. Tokens for look, @charcuterie/logic for state, ARIA that agents can actually drive.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"types": "./dist/index.d.ts",
|
|
20
20
|
"default": "./dist/index.js"
|
|
21
21
|
},
|
|
22
|
+
"./react-router": {
|
|
23
|
+
"source": "./src/reactRouter/index.ts",
|
|
24
|
+
"types": "./dist/reactRouter/index.d.ts",
|
|
25
|
+
"default": "./dist/reactRouter/index.js"
|
|
26
|
+
},
|
|
22
27
|
"./styles.css": "./dist/styles.css",
|
|
23
28
|
"./testing": {
|
|
24
29
|
"source": "./src/testing/index.ts",
|
|
@@ -44,13 +49,19 @@
|
|
|
44
49
|
},
|
|
45
50
|
"dependencies": {
|
|
46
51
|
"@charcuterie/logic": "1.2.0",
|
|
47
|
-
"@charcuterie/tokens": "1.
|
|
52
|
+
"@charcuterie/tokens": "1.2.0",
|
|
48
53
|
"@floating-ui/react": "^0.27.20",
|
|
49
54
|
"@tanstack/react-virtual": "^3.13.12"
|
|
50
55
|
},
|
|
51
56
|
"peerDependencies": {
|
|
52
57
|
"react": ">=19",
|
|
53
|
-
"react-dom": ">=19"
|
|
58
|
+
"react-dom": ">=19",
|
|
59
|
+
"react-router": ">=7"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"react-router": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
54
65
|
},
|
|
55
66
|
"devDependencies": {
|
|
56
67
|
"@storybook/react": "^10.3.6",
|
|
@@ -58,6 +69,7 @@
|
|
|
58
69
|
"@types/react-dom": "^19.2.3",
|
|
59
70
|
"react": "^19.2.8",
|
|
60
71
|
"react-dom": "^19.2.8",
|
|
72
|
+
"react-router": "^8.3.0",
|
|
61
73
|
"storybook": "^10.3.6",
|
|
62
74
|
"tailwindcss": "^4.3.0",
|
|
63
75
|
"typescript": "^6.0.3",
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Canvas, Controls, Meta } from "@storybook/addon-docs/blocks";
|
|
2
|
+
|
|
3
|
+
import * as AdaptiveGridStories from "./AdaptiveGrid.stories";
|
|
4
|
+
|
|
5
|
+
<Meta of={AdaptiveGridStories} />
|
|
6
|
+
|
|
7
|
+
# AdaptiveGrid
|
|
8
|
+
|
|
9
|
+
**Height is spent before width.** A column is something this grid is *forced* into when
|
|
10
|
+
the items will not stack inside the window — never something it takes because a monitor
|
|
11
|
+
is wide.
|
|
12
|
+
|
|
13
|
+
That is the opposite of every wrapping grid in the fleet today. `auto-fill, minmax()`
|
|
14
|
+
takes every column the width allows, which is how you end up with seven items strung
|
|
15
|
+
across an ultrawide and nothing below the fold.
|
|
16
|
+
|
|
17
|
+
<Canvas of={AdaptiveGridStories.Default} />
|
|
18
|
+
|
|
19
|
+
## Props
|
|
20
|
+
|
|
21
|
+
<Controls />
|
|
22
|
+
|
|
23
|
+
## The rule in one sentence
|
|
24
|
+
|
|
25
|
+
> If you're going to vertically scroll anyway, widen the items. If you're not, keep them
|
|
26
|
+
> in a smaller grid so they all still fit on screen.
|
|
27
|
+
|
|
28
|
+
Mechanically:
|
|
29
|
+
|
|
30
|
+
1. Ask how many items stack in the space available — the viewport's block size, minus
|
|
31
|
+
whatever chrome sits above and below.
|
|
32
|
+
2. Divide the item count by that. **That** is how many columns are needed.
|
|
33
|
+
3. Only then ask how many columns actually fit across the container, and take the smaller
|
|
34
|
+
of the two.
|
|
35
|
+
|
|
36
|
+
Step 3 can only ever *reduce* the answer. Width is a veto, not a reason.
|
|
37
|
+
|
|
38
|
+
## The part that reads backwards
|
|
39
|
+
|
|
40
|
+
<Canvas of={AdaptiveGridStories.AllVariants} />
|
|
41
|
+
|
|
42
|
+
Same nine items, same width, three heights — and the **taller** window takes **fewer**
|
|
43
|
+
columns. A 1440x900 laptop gets three columns while a larger 1920x1080 monitor gets two.
|
|
44
|
+
|
|
45
|
+
That is not a bug and it is not a tuned breakpoint. The taller window stacks the same nine
|
|
46
|
+
items in fewer stacks, so it needs fewer stacks. If you "fix" it, you have thrown the rule
|
|
47
|
+
away and rebuilt `auto-fill`.
|
|
48
|
+
|
|
49
|
+
## The content cap widens as columns are added
|
|
50
|
+
|
|
51
|
+
The other half of the complaint this answers is pages that are "1 column, but waaaaaaay
|
|
52
|
+
too wide". So the cap around the grid is not a constant:
|
|
53
|
+
|
|
54
|
+
| Columns | Cap |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| 1 | 56rem |
|
|
57
|
+
| 2 | 72rem |
|
|
58
|
+
| 3 | 106rem |
|
|
59
|
+
| 4 | 140rem |
|
|
60
|
+
|
|
61
|
+
One column stays at a reading measure, because a 2000px-wide card is not a better card —
|
|
62
|
+
it is one line of text the eye has to track from bezel to bezel. The page earns its width
|
|
63
|
+
by having something to fill it with.
|
|
64
|
+
|
|
65
|
+
The three numbers behind that table are `contentInlineSize` in `@charcuterie/tokens`,
|
|
66
|
+
beside `screen` and `containerQuery`, and every part is overridable per call. The
|
|
67
|
+
arithmetic lives in `getContentMaxInlineSize` and is not a token.
|
|
68
|
+
|
|
69
|
+
## When to reach for it
|
|
70
|
+
|
|
71
|
+
Reach for it when **all** of these are true:
|
|
72
|
+
|
|
73
|
+
- The items wrap, and there could be few or many of them.
|
|
74
|
+
- They are roughly the same height, and you can measure one.
|
|
75
|
+
- Scrolling is a cost rather than the point — a rack of bays, a fleet of hosts, a set of
|
|
76
|
+
status cards. Ideally the user never scrolls at all.
|
|
77
|
+
|
|
78
|
+
Do **not** reach for it for a feed, a search-results list, or anything else that is
|
|
79
|
+
inherently long. The rule optimises for "it all fits", and content that will never all fit
|
|
80
|
+
gets nothing from it.
|
|
81
|
+
|
|
82
|
+
## The one number you must measure
|
|
83
|
+
|
|
84
|
+
`itemBlockSize` is the only required option and the only genuinely app-specific one.
|
|
85
|
+
Measure it off a running page rather than deriving it from padding, and **err high** — over-
|
|
86
|
+
estimating makes the grid reach for a column slightly early, and a page that scrolls when
|
|
87
|
+
it did not have to is the entire complaint. It only has to be right to within about one
|
|
88
|
+
item; being one out shifts a borderline window by one column, which is taste.
|
|
89
|
+
|
|
90
|
+
`chromeBlockSize` is everything down the page that is not the grid: header, rails, filter
|
|
91
|
+
rows, labels. It defaults to `0`.
|
|
92
|
+
|
|
93
|
+
## It measures its container, not the window
|
|
94
|
+
|
|
95
|
+
<Canvas of={AdaptiveGridStories.Responsive} />
|
|
96
|
+
|
|
97
|
+
Three grids, one browser window, three different answers. The inline size comes off a
|
|
98
|
+
`ResizeObserver` on the grid's own container, so a grid sitting beside a rail is told the
|
|
99
|
+
truth about the room it has — the container-query thesis this library is built on, applied
|
|
100
|
+
to a layout decision instead of a card's internals.
|
|
101
|
+
|
|
102
|
+
The block size is the exception, and it has to be: the question is "will this scroll", and
|
|
103
|
+
an element in normal flow is exactly as tall as its contents, so measuring the grid always
|
|
104
|
+
answers "it fits." That number comes from the viewport, behind an injectable
|
|
105
|
+
`blockSizeResolver` for Electron windows, fixed-height kiosk panels, and tests.
|
|
106
|
+
|
|
107
|
+
⚠️ **Never apply the returned cap to the element being measured.** If you wire
|
|
108
|
+
`useAdaptiveColumns` by hand, the observed box and the capped box must be different
|
|
109
|
+
elements. Collapse them and the fold reads back its own narrowed output: one column,
|
|
110
|
+
forever, with no error anywhere. `AdaptiveGrid` enforces this structurally — an uncapped
|
|
111
|
+
outer box it measures, an inner box it caps.
|
|
112
|
+
|
|
113
|
+
## Composing with a shell
|
|
114
|
+
|
|
115
|
+
`AdaptiveGrid` caps itself, so it is correct standing alone. If you want the **page chrome**
|
|
116
|
+
to widen with the grid rather than the grid rattling around inside a fixed column, hoist
|
|
117
|
+
the hook to the page and hand the pieces out:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
const layout = useAdaptiveColumns({
|
|
121
|
+
chromeBlockSize: 260,
|
|
122
|
+
itemBlockSize: 150,
|
|
123
|
+
itemCount: bays.length,
|
|
124
|
+
storageKey: "rip-deck.layout-columns",
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
<Main maxInlineSize={layout.contentMaxInlineSize} ref={layout.containerRef}>
|
|
128
|
+
<AdaptiveGrid columns={layout.columns} itemBlockSize={150}>
|
|
129
|
+
{bays.map(…)}
|
|
130
|
+
</AdaptiveGrid>
|
|
131
|
+
</Main>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The `Main` region takes a caller-supplied max inline size; the ref goes on whatever box
|
|
135
|
+
sits **outside** that cap.
|
|
136
|
+
|
|
137
|
+
## Manual override
|
|
138
|
+
|
|
139
|
+
<Canvas of={AdaptiveGridStories.Interactive} />
|
|
140
|
+
|
|
141
|
+
`"auto"` is always in the list. A picker that only offers numbers once a number has been
|
|
142
|
+
chosen is a one-way door — it strands someone on a layout they tried once with no route
|
|
143
|
+
back to the mode that adapts.
|
|
144
|
+
|
|
145
|
+
Pass `storageKey` to remember the choice across visits, namespaced to your app; the
|
|
146
|
+
library will not invent that string for you. Omit it and the choice lasts the session and
|
|
147
|
+
is written nowhere. Every unreadable stored value — a corrupt key, a browser that refuses
|
|
148
|
+
storage, a count the picker cannot offer — falls back to `"auto"`, so a bad value costs a
|
|
149
|
+
preference rather than a page.
|
|
150
|
+
|
|
151
|
+
## Why the tracks are an inline style
|
|
152
|
+
|
|
153
|
+
`repeat(N, minmax(0, 1fr))` is interpolated, and a className may not be. Tailwind v4 scans
|
|
154
|
+
source *text* for complete class strings, so `grid-cols-${columns}` generates nothing at
|
|
155
|
+
all — no error, no warning, an unstyled element. A class-per-count would need every count
|
|
156
|
+
to survive the scan; an inline style needs none. `tailwindCandidates.test.ts` rejects the
|
|
157
|
+
interpolated form outright.
|
|
158
|
+
|
|
159
|
+
## `min-w-0` is not optional
|
|
160
|
+
|
|
161
|
+
Every child gets `min-w-0`, applied by the component rather than asked for. A grid item's
|
|
162
|
+
automatic minimum size is `min-content`, so one long unbroken string — a file path, a URL —
|
|
163
|
+
widens its own track and shoves the whole grid past the viewport. The rule that stops it
|
|
164
|
+
has to sit on children the caller owns, which is why it is not your job to remember.
|
|
165
|
+
|
|
166
|
+
You still owe your own items a wrap or a `truncate`; `min-w-0` lets the track get small
|
|
167
|
+
enough for that clipping to matter.
|
|
168
|
+
|
|
169
|
+
<Canvas of={AdaptiveGridStories.AllStates} />
|