@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.
Files changed (98) hide show
  1. package/README.md +13 -1
  2. package/dist/AdaptiveGrid/AdaptiveGrid.d.ts +94 -0
  3. package/dist/AdaptiveGrid/AdaptiveGrid.d.ts.map +1 -0
  4. package/dist/AdaptiveGrid/AdaptiveGrid.js +73 -0
  5. package/dist/AdaptiveGrid/AdaptiveGrid.js.map +1 -0
  6. package/dist/AdaptiveGrid/chooseColumns.d.ts +206 -0
  7. package/dist/AdaptiveGrid/chooseColumns.d.ts.map +1 -0
  8. package/dist/AdaptiveGrid/chooseColumns.js +156 -0
  9. package/dist/AdaptiveGrid/chooseColumns.js.map +1 -0
  10. package/dist/AdaptiveGrid/useAdaptiveColumns.d.ts +155 -0
  11. package/dist/AdaptiveGrid/useAdaptiveColumns.d.ts.map +1 -0
  12. package/dist/AdaptiveGrid/useAdaptiveColumns.js +153 -0
  13. package/dist/AdaptiveGrid/useAdaptiveColumns.js.map +1 -0
  14. package/dist/Button/Button.d.ts.map +1 -1
  15. package/dist/Button/Button.js +11 -6
  16. package/dist/Button/Button.js.map +1 -1
  17. package/dist/ButtonLink/ButtonLink.d.ts +59 -0
  18. package/dist/ButtonLink/ButtonLink.d.ts.map +1 -0
  19. package/dist/ButtonLink/ButtonLink.js +69 -0
  20. package/dist/ButtonLink/ButtonLink.js.map +1 -0
  21. package/dist/Combobox/Combobox.d.ts.map +1 -1
  22. package/dist/Combobox/Combobox.js +1 -1
  23. package/dist/Combobox/Combobox.js.map +1 -1
  24. package/dist/Dialog/Dialog.js +1 -1
  25. package/dist/Dialog/Dialog.js.map +1 -1
  26. package/dist/LogViewer/LogViewer.d.ts.map +1 -1
  27. package/dist/LogViewer/LogViewer.js +33 -1
  28. package/dist/LogViewer/LogViewer.js.map +1 -1
  29. package/dist/RouterLink/AnchorLink.d.ts +17 -0
  30. package/dist/RouterLink/AnchorLink.d.ts.map +1 -0
  31. package/dist/RouterLink/AnchorLink.js +16 -0
  32. package/dist/RouterLink/AnchorLink.js.map +1 -0
  33. package/dist/RouterLink/RouterLinkProvider.d.ts +13 -0
  34. package/dist/RouterLink/RouterLinkProvider.d.ts.map +1 -0
  35. package/dist/RouterLink/RouterLinkProvider.js +47 -0
  36. package/dist/RouterLink/RouterLinkProvider.js.map +1 -0
  37. package/dist/RouterLink/routerLink.d.ts +45 -0
  38. package/dist/RouterLink/routerLink.d.ts.map +1 -0
  39. package/dist/RouterLink/routerLink.js +31 -0
  40. package/dist/RouterLink/routerLink.js.map +1 -0
  41. package/dist/TextLink/TextLink.d.ts +69 -0
  42. package/dist/TextLink/TextLink.d.ts.map +1 -0
  43. package/dist/TextLink/TextLink.js +79 -0
  44. package/dist/TextLink/TextLink.js.map +1 -0
  45. package/dist/controlStyles.d.ts +36 -1
  46. package/dist/controlStyles.d.ts.map +1 -1
  47. package/dist/controlStyles.js +30 -0
  48. package/dist/controlStyles.js.map +1 -1
  49. package/dist/index.d.ts +16 -2
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +10 -2
  52. package/dist/index.js.map +1 -1
  53. package/dist/intentStyles.d.ts +17 -0
  54. package/dist/intentStyles.d.ts.map +1 -1
  55. package/dist/intentStyles.js +17 -0
  56. package/dist/intentStyles.js.map +1 -1
  57. package/dist/reactRouter/ReactRouterLink.d.ts +23 -0
  58. package/dist/reactRouter/ReactRouterLink.d.ts.map +1 -0
  59. package/dist/reactRouter/ReactRouterLink.js +23 -0
  60. package/dist/reactRouter/ReactRouterLink.js.map +1 -0
  61. package/dist/reactRouter/index.d.ts +29 -0
  62. package/dist/reactRouter/index.d.ts.map +1 -0
  63. package/dist/reactRouter/index.js +29 -0
  64. package/dist/reactRouter/index.js.map +1 -0
  65. package/dist/styles.css +88 -8
  66. package/package.json +15 -3
  67. package/src/AdaptiveGrid/AdaptiveGrid.mdx +169 -0
  68. package/src/AdaptiveGrid/AdaptiveGrid.stories.tsx +240 -0
  69. package/src/AdaptiveGrid/AdaptiveGrid.test.tsx +243 -0
  70. package/src/AdaptiveGrid/AdaptiveGrid.tsx +150 -0
  71. package/src/AdaptiveGrid/chooseColumns.test.ts +253 -0
  72. package/src/AdaptiveGrid/chooseColumns.ts +270 -0
  73. package/src/AdaptiveGrid/useAdaptiveColumns.ts +355 -0
  74. package/src/Button/Button.tsx +10 -22
  75. package/src/ButtonLink/ButtonLink.mdx +75 -0
  76. package/src/ButtonLink/ButtonLink.stories.tsx +281 -0
  77. package/src/ButtonLink/ButtonLink.test.tsx +203 -0
  78. package/src/ButtonLink/ButtonLink.tsx +149 -0
  79. package/src/Combobox/Combobox.tsx +4 -1
  80. package/src/Dialog/Dialog.tsx +1 -1
  81. package/src/LogViewer/LogViewer.test.tsx +47 -0
  82. package/src/LogViewer/LogViewer.tsx +35 -1
  83. package/src/RouterLink/AnchorLink.tsx +23 -0
  84. package/src/RouterLink/RouterLink.mdx +178 -0
  85. package/src/RouterLink/RouterLinkProvider.tsx +68 -0
  86. package/src/RouterLink/routerLink.ts +56 -0
  87. package/src/TextLink/TextLink.mdx +93 -0
  88. package/src/TextLink/TextLink.stories.tsx +260 -0
  89. package/src/TextLink/TextLink.test.tsx +230 -0
  90. package/src/TextLink/TextLink.tsx +194 -0
  91. package/src/controlStyles.ts +69 -1
  92. package/src/icons.storyHelpers.tsx +32 -0
  93. package/src/index.ts +41 -0
  94. package/src/intentStyles.ts +19 -0
  95. package/src/reactRouter/ReactRouterLink.tsx +30 -0
  96. package/src/reactRouter/index.ts +29 -0
  97. package/src/sourceRules.test.ts +41 -6
  98. 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":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAOH,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA2B,CAAA;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAiC,CAAA;AAE9D,OAAO,EACL,aAAa,EACb,wBAAwB,EACxB,0BAA0B,EAC1B,iCAAiC,EACjC,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,iCAAiC,CAAA;AAKxC,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,sCAAsC,CAAA;AAK7C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAE5C,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AAMxD,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAiB,CAAA;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAyB,CAAA;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA+C,CAAA;AAKnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA2C,CAAA;AAE7E,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAyB,CAAA;AAElD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAK3B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAK5C,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AAExD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAwB,CAAA;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAiC,CAAA;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AAExD,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAyB,CAAA;AAKlD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAuB,CAAA;AAK/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA+C,CAAA;AAKnF,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA2B,CAAA;AAKrD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA2B,CAAA;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAK7D,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAiB,CAAA;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AAEzC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAuB,CAAA;AAK/C,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA+B,CAAA;AAE3D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,gCAAgC,CAAA;AAKvC,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AACxD,OAAO,EACL,kBAAkB,EAClB,aAAa,GACd,MAAM,oCAAqC,CAAA;AAK5C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAK5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAyC,CAAA;AAO1E,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAK5C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAyB,CAAA;AAKlD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA+C,CAAA;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAuB,CAAA;AAM/C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EACL,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,mBAAmB,CAAA;AAO1B,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAiB,CAAA;AAKtC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAyB,CAAA;AAElD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AAKzC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAyB,CAAA;AAErD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAE5D,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAuB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAqC,CAAA"}
@@ -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"}
@@ -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
@@ -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, and
2
- * nothing else.
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. Animation is the one thing utilities
7
- * cannot express against our tokens: Tailwind's own `animate-spin`
8
- * and `animate-pulse` hardcode 1s and 2s, ignore
9
- * `prefers-reduced-motion`, and are therefore beyond the theme's
10
- * reach — which is exactly why `MotionTokens` carries a separate
11
- * `loopFast`/`loopSlow` ramp.
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.6.0",
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.1.3",
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} />