@charcuterie/ui 3.28.1 → 3.29.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 (48) hide show
  1. package/dist/SearchInput/SearchInput.d.ts +22 -0
  2. package/dist/SearchInput/SearchInput.d.ts.map +1 -0
  3. package/dist/SearchInput/SearchInput.js +36 -0
  4. package/dist/SearchInput/SearchInput.js.map +1 -0
  5. package/dist/VirtualizedGrid/ElementGrid.d.ts +7 -0
  6. package/dist/VirtualizedGrid/ElementGrid.d.ts.map +1 -0
  7. package/dist/VirtualizedGrid/ElementGrid.js +19 -0
  8. package/dist/VirtualizedGrid/ElementGrid.js.map +1 -0
  9. package/dist/VirtualizedGrid/GridRows.d.ts +4 -0
  10. package/dist/VirtualizedGrid/GridRows.d.ts.map +1 -0
  11. package/dist/VirtualizedGrid/GridRows.js +40 -0
  12. package/dist/VirtualizedGrid/GridRows.js.map +1 -0
  13. package/dist/VirtualizedGrid/VirtualizedGrid.d.ts +6 -8
  14. package/dist/VirtualizedGrid/VirtualizedGrid.d.ts.map +1 -1
  15. package/dist/VirtualizedGrid/VirtualizedGrid.js +30 -87
  16. package/dist/VirtualizedGrid/VirtualizedGrid.js.map +1 -1
  17. package/dist/VirtualizedGrid/WindowGrid.d.ts +3 -0
  18. package/dist/VirtualizedGrid/WindowGrid.d.ts.map +1 -0
  19. package/dist/VirtualizedGrid/WindowGrid.js +20 -0
  20. package/dist/VirtualizedGrid/WindowGrid.js.map +1 -0
  21. package/dist/VirtualizedGrid/virtualizedGridScroll.d.ts +25 -0
  22. package/dist/VirtualizedGrid/virtualizedGridScroll.d.ts.map +1 -0
  23. package/dist/VirtualizedGrid/virtualizedGridScroll.js +50 -0
  24. package/dist/VirtualizedGrid/virtualizedGridScroll.js.map +1 -0
  25. package/dist/VirtualizedGrid/virtualizedGridTypes.d.ts +27 -0
  26. package/dist/VirtualizedGrid/virtualizedGridTypes.d.ts.map +1 -0
  27. package/dist/VirtualizedGrid/virtualizedGridTypes.js +2 -0
  28. package/dist/VirtualizedGrid/virtualizedGridTypes.js.map +1 -0
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1 -0
  32. package/dist/index.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/SearchInput/SearchInput.mdx +15 -0
  35. package/src/SearchInput/SearchInput.stories.tsx +136 -0
  36. package/src/SearchInput/SearchInput.test.tsx +28 -0
  37. package/src/SearchInput/SearchInput.tsx +105 -0
  38. package/src/VirtualizedGrid/ElementGrid.tsx +45 -0
  39. package/src/VirtualizedGrid/GridRows.tsx +90 -0
  40. package/src/VirtualizedGrid/VirtualizedGrid.mdx +9 -8
  41. package/src/VirtualizedGrid/VirtualizedGrid.stories.tsx +26 -0
  42. package/src/VirtualizedGrid/VirtualizedGrid.test.tsx +60 -1
  43. package/src/VirtualizedGrid/VirtualizedGrid.tsx +42 -142
  44. package/src/VirtualizedGrid/WindowGrid.tsx +39 -0
  45. package/src/VirtualizedGrid/virtualizedGridScroll.ts +69 -0
  46. package/src/VirtualizedGrid/virtualizedGridTypes.ts +32 -0
  47. package/src/index.ts +2 -0
  48. package/src/sourceRules.test.ts +1 -1
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;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;AAKzC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAE5C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AAGzC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA+B,CAAA;AAK3D,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AASzC,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAE5C,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AAMxD,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAiB,CAAA;AAGtC,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;AAKlD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,uBAAuB,EACvB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAO3B,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA2B,CAAA;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AAExD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAMlE,OAAO,EACL,2BAA2B,EAC3B,cAAc,GACf,MAAM,gCAAgC,CAAA;AAMvC,OAAO,EACL,OAAO,EACP,SAAS,EACT,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,YAAY,EACZ,SAAS,GACV,MAAM,2BAA2B,CAAA;AAKlC,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,2CAA2C,CAAA;AAKlD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAK5C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAyB,CAAA;AAKlD,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,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAE5C,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;AAErD,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAiB,CAAA;AAKtC,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAqC,CAAA;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAA;AAOtE,OAAO,EACL,WAAW,EACX,eAAe,GAChB,MAAM,mCAAmC,CAAA;AAE1C,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,kCAAkC,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAiC,CAAA;AAK9D,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;AAKzC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAe,CAAA;AAKnC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,mBAAmB,CAAA;AAO1B,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAKpD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAK5C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAE5C,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,YAAY,EAAE,MAAM,gCAAiC,CAAA;AAK9D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA6B,CAAA;AAMxD,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAiB,CAAA;AAMtC,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA+B,CAAA;AAC3D,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;AAY1E,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAM5C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAmB,CAAA;AAKzC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAyB,CAAA;AAKlD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAqB,CAAA;AAK5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA+C,CAAA;AAEnF,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAuB,CAAA;AAO/C,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;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAOpE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAuB,CAAA;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAuB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAuC,CAAA;AAEvE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAqC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@charcuterie/ui",
3
- "version": "3.28.1",
3
+ "version": "3.29.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",
@@ -0,0 +1,15 @@
1
+ import { Canvas, Meta } from "@storybook/addon-docs/blocks";
2
+ import * as Stories from "./SearchInput.stories";
3
+
4
+ <Meta of={Stories} />
5
+
6
+ # SearchInput
7
+
8
+ The search field with a labelled icon button for clearing its value. The app supplies the
9
+ glyph and owns the query. The component owns the field skin, the full control-sized target,
10
+ the native cancel-widget suppression, and focus return after a clear.
11
+
12
+ Use `Field` for a visible label, or pass `aria-label` when the surrounding layout already
13
+ names the search.
14
+
15
+ <Canvas of={Stories.Default} />
@@ -0,0 +1,136 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { useState } from "react"
3
+
4
+ import { controlSizeArgType } from "../argTypes.storyHelpers.ts"
5
+ import {
6
+ ContainerBoard,
7
+ StoryCell,
8
+ StoryGrid,
9
+ StorySection,
10
+ } from "../board.storyHelpers.tsx"
11
+ import { Field } from "../Field/Field.tsx"
12
+ import { SearchInput } from "./SearchInput.tsx"
13
+
14
+ const ClearIcon = () => (
15
+ <svg aria-hidden="true" fill="none" viewBox="0 0 24 24">
16
+ <path
17
+ d="m6 6 12 12M18 6 6 18"
18
+ stroke="currentColor"
19
+ strokeLinecap="round"
20
+ strokeWidth="2"
21
+ />
22
+ </svg>
23
+ )
24
+
25
+ const ControlledSearch = ({
26
+ size = "md",
27
+ }: {
28
+ size?: "sm" | "md" | "lg"
29
+ }) => {
30
+ const [value, setValue] = useState("filter paper")
31
+
32
+ return (
33
+ <Field label="Search inventory">
34
+ <SearchInput
35
+ clearIcon={<ClearIcon />}
36
+ onChange={(event) => setValue(event.target.value)}
37
+ onClear={() => setValue("")}
38
+ placeholder="Name or location…"
39
+ size={size}
40
+ value={value}
41
+ />
42
+ </Field>
43
+ )
44
+ }
45
+
46
+ const meta = {
47
+ title: "Components/Controls/SearchInput",
48
+ component: SearchInput,
49
+ parameters: { layout: "padded" },
50
+ argTypes: { size: controlSizeArgType },
51
+ args: {
52
+ clearIcon: <ClearIcon />,
53
+ onClear: () => undefined,
54
+ placeholder: "Name or location…",
55
+ readOnly: true,
56
+ size: "md",
57
+ value: "filter paper",
58
+ },
59
+ } satisfies Meta<typeof SearchInput>
60
+
61
+ export default meta
62
+ type Story = StoryObj<typeof meta>
63
+
64
+ export const Default: Story = {
65
+ render: () => <ControlledSearch />,
66
+ }
67
+
68
+ export const AllVariants: Story = {
69
+ render: () => (
70
+ <StorySection title="The field and its clear button share one density-aware control size.">
71
+ <StoryGrid columns={3}>
72
+ {(["sm", "md", "lg"] as const).map((size) => (
73
+ <StoryCell key={size} label={size}>
74
+ <ControlledSearch size={size} />
75
+ </StoryCell>
76
+ ))}
77
+ </StoryGrid>
78
+ </StorySection>
79
+ ),
80
+ }
81
+
82
+ export const AllStates: Story = {
83
+ render: () => (
84
+ <StoryGrid columns={2}>
85
+ <StoryCell label="empty">
86
+ <SearchInput
87
+ aria-label="Empty search"
88
+ clearIcon={<ClearIcon />}
89
+ onClear={() => undefined}
90
+ value=""
91
+ />
92
+ </StoryCell>
93
+ <StoryCell label="filled">
94
+ <SearchInput
95
+ aria-label="Filled search"
96
+ clearIcon={<ClearIcon />}
97
+ onClear={() => undefined}
98
+ readOnly
99
+ value="filter paper"
100
+ />
101
+ </StoryCell>
102
+ <StoryCell label="disabled">
103
+ <SearchInput
104
+ aria-label="Disabled search"
105
+ clearIcon={<ClearIcon />}
106
+ disabled
107
+ onClear={() => undefined}
108
+ readOnly
109
+ value="filter paper"
110
+ />
111
+ </StoryCell>
112
+ <StoryCell label="invalid">
113
+ <SearchInput
114
+ aria-label="Invalid search"
115
+ aria-invalid="true"
116
+ clearIcon={<ClearIcon />}
117
+ onClear={() => undefined}
118
+ readOnly
119
+ value="filter paper"
120
+ />
121
+ </StoryCell>
122
+ </StoryGrid>
123
+ ),
124
+ }
125
+
126
+ export const Responsive: Story = {
127
+ render: () => (
128
+ <ContainerBoard>
129
+ <ControlledSearch />
130
+ </ContainerBoard>
131
+ ),
132
+ }
133
+
134
+ export const Interactive: Story = {
135
+ render: () => <ControlledSearch />,
136
+ }
@@ -0,0 +1,28 @@
1
+ import { composeStories } from "@storybook/react"
2
+ import { expect, userEvent } from "storybook/test"
3
+ import { test } from "vitest"
4
+
5
+ import { expectNoAxeViolations } from "../expectNoAxeViolations.testHelpers.ts"
6
+ import { mountStory } from "../mountStory.testHelpers.ts"
7
+ import { expectAgentDrivable } from "../testing/index.ts"
8
+ import * as stories from "./SearchInput.stories.tsx"
9
+
10
+ const { Interactive } = composeStories(stories)
11
+
12
+ test("the clear affordance is a labelled button and returns focus", async () => {
13
+ const { canvas, canvasElement } =
14
+ await mountStory(Interactive)
15
+ const input = expectAgentDrivable(canvas, {
16
+ name: "Search inventory",
17
+ role: "searchbox",
18
+ })
19
+ const clear = expectAgentDrivable(canvas, {
20
+ name: "Clear search",
21
+ role: "button",
22
+ })
23
+
24
+ await userEvent.click(clear)
25
+ await expect(input).toHaveValue("")
26
+ await expect(input).toHaveFocus()
27
+ await expectNoAxeViolations(canvasElement)
28
+ })
@@ -0,0 +1,105 @@
1
+ import type { ControlSize } from "@charcuterie/tokens"
2
+ import {
3
+ type ComponentPropsWithRef,
4
+ type ReactNode,
5
+ useRef,
6
+ } from "react"
7
+
8
+ import { IconButton } from "../IconButton/IconButton.tsx"
9
+ import {
10
+ DISABLED_CLASS,
11
+ FOCUS_RING_CLASS,
12
+ } from "../intentStyles.ts"
13
+ import { toClassName } from "../toClassName.ts"
14
+
15
+ const INPUT_SIZE_CLASS: Record<ControlSize, string> = {
16
+ sm: "h-(--control-height-sm) ps-(--control-padding-inline-sm) pe-(--control-height-sm) text-sm",
17
+ md: "h-(--control-height-md) ps-(--control-padding-inline-md) pe-(--control-height-md) text-md",
18
+ lg: "h-(--control-height-lg) ps-(--control-padding-inline-lg) pe-(--control-height-lg) text-lg",
19
+ }
20
+
21
+ export type SearchInputProps = Omit<
22
+ ComponentPropsWithRef<"input">,
23
+ "size" | "type"
24
+ > & {
25
+ /** The app-owned glyph inside the clear button. */
26
+ clearIcon: ReactNode
27
+ clearLabel?: string
28
+ /** Override value-derived visibility for an uncontrolled input. */
29
+ isClearVisible?: boolean
30
+ onClear: () => void
31
+ size?: ControlSize
32
+ }
33
+
34
+ /**
35
+ * A search field whose clear affordance is a real, labelled icon
36
+ * button. The native search cancel widget is suppressed because it
37
+ * is platform-painted, cannot use the token system, and provides a
38
+ * much smaller pointer target than the control beside it.
39
+ *
40
+ * The app supplies the icon and owns the value. `SearchInput` owns
41
+ * the shape, focus return, accessible button name, and target size.
42
+ */
43
+ export const SearchInput = ({
44
+ className,
45
+ clearIcon,
46
+ clearLabel = "Clear search",
47
+ defaultValue,
48
+ isClearVisible,
49
+ onClear,
50
+ ref,
51
+ size = "md",
52
+ value,
53
+ ...inputProps
54
+ }: SearchInputProps): ReactNode => {
55
+ const inputRef = useRef<HTMLInputElement>(null)
56
+ const hasValue =
57
+ isClearVisible ??
58
+ String(value ?? defaultValue ?? "").length > 0
59
+
60
+ const setInputRef = (node: HTMLInputElement | null) => {
61
+ inputRef.current = node
62
+
63
+ if (typeof ref === "function") ref(node)
64
+ else if (ref) ref.current = node
65
+ }
66
+
67
+ return (
68
+ <span
69
+ className={toClassName("relative block", className)}
70
+ >
71
+ <input
72
+ {...inputProps}
73
+ className={toClassName(
74
+ "w-full min-w-0 appearance-none rounded-md border border-border-default bg-surface-raised text-content-primary transition-colors duration-(--duration-fast) ease-standard placeholder:text-content-muted hover:border-border-strong aria-invalid:border-intent-danger-border [&::-webkit-search-cancel-button]:appearance-none",
75
+ INPUT_SIZE_CLASS[size],
76
+ FOCUS_RING_CLASS,
77
+ DISABLED_CLASS,
78
+ )}
79
+ defaultValue={defaultValue}
80
+ ref={setInputRef}
81
+ type="search"
82
+ value={value}
83
+ />
84
+
85
+ {hasValue && !inputProps.disabled ? (
86
+ <span className="absolute inset-y-0 end-0 flex items-center">
87
+ <IconButton
88
+ appearance="ghost"
89
+ label={clearLabel}
90
+ onClick={() => {
91
+ onClear()
92
+ inputRef.current?.focus()
93
+ }}
94
+ onPointerDown={(event) =>
95
+ event.preventDefault()
96
+ }
97
+ size={size}
98
+ >
99
+ {clearIcon}
100
+ </IconButton>
101
+ </span>
102
+ ) : null}
103
+ </span>
104
+ )
105
+ }
@@ -0,0 +1,45 @@
1
+ import { useVirtualizer } from "@tanstack/react-virtual"
2
+ import { useCallback } from "react"
3
+
4
+ import { GridRows } from "./GridRows.tsx"
5
+ import { useScrollMargin } from "./virtualizedGridScroll.ts"
6
+ import type {
7
+ GridWindowProps,
8
+ ScrollOwner,
9
+ } from "./virtualizedGridTypes.ts"
10
+
11
+ export const ElementGrid = <Item,>(
12
+ props: GridWindowProps<Item> & {
13
+ scrollOwner: Extract<ScrollOwner, { kind: "element" }>
14
+ },
15
+ ) => {
16
+ const { gridElement, scrollMargin } = useScrollMargin(
17
+ props.scrollOwner,
18
+ )
19
+
20
+ const measureRow = useCallback(
21
+ (element: Element) =>
22
+ element.getBoundingClientRect().height + props.gap,
23
+ [props.gap],
24
+ )
25
+
26
+ const rowVirtualizer = useVirtualizer({
27
+ count: props.rowCount,
28
+ estimateSize: () => props.itemBlockSize + props.gap,
29
+ getScrollElement: () => props.scrollOwner.element,
30
+ measureElement: measureRow,
31
+ overscan: props.overscanRows,
32
+ scrollMargin,
33
+ })
34
+
35
+ return (
36
+ <GridRows
37
+ {...props}
38
+ gridElement={gridElement}
39
+ measureElement={rowVirtualizer.measureElement}
40
+ scrollMargin={scrollMargin}
41
+ totalSize={rowVirtualizer.getTotalSize()}
42
+ virtualRows={rowVirtualizer.getVirtualItems()}
43
+ />
44
+ )
45
+ }
@@ -0,0 +1,90 @@
1
+ import { getContentMaxInlineSize } from "../AdaptiveGrid/chooseColumns.ts"
2
+ import type { GridRowsProps } from "./virtualizedGridTypes.ts"
3
+
4
+ /** The shared markup. Only the scroll observer differs between the two owners. */
5
+ export const GridRows = <Item,>({
6
+ drawnColumns,
7
+ gap,
8
+ getItemKey,
9
+ gridElement,
10
+ items,
11
+ label,
12
+ measureElement,
13
+ renderItem,
14
+ scrollMargin,
15
+ totalSize,
16
+ virtualRows,
17
+ }: GridRowsProps<Item>) => {
18
+ const firstRow = virtualRows[0]
19
+ const lastRow = virtualRows[virtualRows.length - 1]
20
+
21
+ // Everything scrolled past, and everything still to come. The two
22
+ // numbers that stand in for the rows that do not exist.
23
+ const paddingBlockStart = firstRow?.start ?? 0
24
+
25
+ const paddingBlockEnd = lastRow
26
+ ? Math.max(0, totalSize - lastRow.end)
27
+ : 0
28
+
29
+ return (
30
+ <ul
31
+ aria-label={label}
32
+ className="grid w-full list-none p-0 [&>*]:min-w-0"
33
+ ref={gridElement}
34
+ style={{
35
+ gap: `${gap}px`,
36
+ gridTemplateColumns: `repeat(${drawnColumns}, minmax(0, 1fr))`,
37
+ maxInlineSize: getContentMaxInlineSize({
38
+ columns: drawnColumns,
39
+ }),
40
+ // Offset by `scrollMargin` because `start` is measured
41
+ // from the top of the scroll owner, and this padding is
42
+ // measured from the top of the grid.
43
+ paddingBlockEnd: `${paddingBlockEnd}px`,
44
+ paddingBlockStart: `${Math.max(0, paddingBlockStart - scrollMargin)}px`,
45
+ }}
46
+ >
47
+ {virtualRows.flatMap((row) => {
48
+ const firstIndex = row.index * drawnColumns
49
+
50
+ return items
51
+ .slice(firstIndex, firstIndex + drawnColumns)
52
+ .map((item, offset) => {
53
+ const index = firstIndex + offset
54
+
55
+ return (
56
+ <li
57
+ aria-posinset={index + 1}
58
+ aria-setsize={items.length}
59
+ // `data-index` names the ROW, so it goes on
60
+ // every cell in it — they all sit in that row
61
+ // and the attribute is true of all of them.
62
+ //
63
+ // Putting it only on the measured cell is the
64
+ // version that looks tidier and warns on every
65
+ // resize: the virtualizer keeps a
66
+ // `ResizeObserver` on whatever it measured and
67
+ // re-reads the attribute whenever that node
68
+ // changes size. Let the node stop being the
69
+ // leading cell — a column count change is all it
70
+ // takes — and it is still observed, now with no
71
+ // attribute to resolve.
72
+ data-index={row.index}
73
+ key={getItemKey?.(item, index) ?? index}
74
+ // Measured on the leading cell alone. A CSS grid
75
+ // stretches every cell to its row's height, so
76
+ // one is enough — and measuring all of them
77
+ // would have the virtualizer record the same row
78
+ // once per column.
79
+ ref={
80
+ offset === 0 ? measureElement : undefined
81
+ }
82
+ >
83
+ {renderItem(item, index)}
84
+ </li>
85
+ )
86
+ })
87
+ })}
88
+ </ul>
89
+ )
90
+ }
@@ -47,16 +47,17 @@ commitment — every mounted row is measured and the estimate corrected. It stil
47
47
  be close, because it is what the scrollbar is sized from before anything has been
48
48
  measured. A bad guess makes the bar jump under the thumb on the first scroll.
49
49
 
50
- ## It scrolls the page, not a box of its own
50
+ ## It follows the page's scroll region
51
51
 
52
- `useWindowVirtualizer`, so the page scrolls the way every other page in the fleet
53
- scrolls — the header leaves, the scrollbar is the browser's, `Ctrl+End` works. A
54
- component that grew its own `overflow: auto` well would trap the wheel and strand the
55
- page header above it.
52
+ The grid never creates a scroll box. It follows the nearest ancestor whose vertical
53
+ overflow is `auto` or `scroll`. Inside `Shell`, that is `Main`, so the header and rail stay
54
+ available while the grid scrolls. A standalone grid falls back to the browser window.
56
55
 
57
- The cost is that the grid has to know how far down the document it starts, which it
58
- measures in a layout effect and feeds to the virtualizer as `scrollMargin`. Get that
59
- wrong and every row is offset by the height of the header above it.
56
+ The cost is that the grid has to know how far down its scroll region it starts. It measures
57
+ that offset in a layout effect and feeds it to the virtualizer as `scrollMargin`. Get that
58
+ wrong and every row is offset by the chrome above it.
59
+
60
+ <Canvas of={VirtualizedGridStories.InShellScrollRegion} />
60
61
 
61
62
  ## The column rule is inherited, not reimplemented
62
63
 
@@ -3,9 +3,13 @@ import { useState } from "react"
3
3
 
4
4
  import { getColumnChoices } from "../AdaptiveGrid/chooseColumns.ts"
5
5
  import type { BlockSizeResolver } from "../AdaptiveGrid/useAdaptiveColumns.ts"
6
+ import { Button } from "../Button/Button.tsx"
6
7
  import { StorySection } from "../board.storyHelpers.tsx"
7
8
  import { Card } from "../Card/Card.tsx"
9
+ import { Header } from "../Header/Header.tsx"
10
+ import { Main } from "../Main/Main.tsx"
8
11
  import { SegmentedControl } from "../SegmentedControl/SegmentedControl.tsx"
12
+ import { Shell } from "../Shell/Shell.tsx"
9
13
  import { VirtualizedGrid } from "./VirtualizedGrid.tsx"
10
14
 
11
15
  /**
@@ -104,6 +108,28 @@ type Story = StoryObj<typeof meta>
104
108
  */
105
109
  export const Default: Story = {}
106
110
 
111
+ /**
112
+ * The app-shell contract: `Main` is the one vertical scroll region,
113
+ * and the grid follows it rather than adding document height.
114
+ *
115
+ * This is QueuePilot's Pending shape. It is a separate story because
116
+ * a standalone grid still follows the browser window and both paths
117
+ * need a real consumer.
118
+ */
119
+ export const InShellScrollRegion: Story = {
120
+ parameters: { layout: "fullscreen" },
121
+ render: (gridProps) => (
122
+ <Shell contentWidth="full">
123
+ <Header heading="Pending" />
124
+
125
+ <Main>
126
+ <Button onClick={() => {}}>Mark all seen</Button>
127
+ <VirtualizedGrid {...gridProps} />
128
+ </Main>
129
+ </Shell>
130
+ ),
131
+ }
132
+
107
133
  /**
108
134
  * The same 2,000 items at three window heights.
109
135
  *
@@ -33,7 +33,8 @@ import * as stories from "./VirtualizedGrid.stories.tsx"
33
33
  * on.
34
34
  */
35
35
 
36
- const { AllStates, Default } = composeStories(stories)
36
+ const { AllStates, Default, InShellScrollRegion } =
37
+ composeStories(stories)
37
38
 
38
39
  const getLists = (canvasElement: HTMLElement) => [
39
40
  ...canvasElement.querySelectorAll<HTMLElement>("ul"),
@@ -146,6 +147,64 @@ test("scrolling changes which rows exist", async () => {
146
147
  }
147
148
  })
148
149
 
150
+ test("a grid inside Shell follows Main's one scroll region", async () => {
151
+ const { canvasElement } = await mountStory(
152
+ InShellScrollRegion,
153
+ )
154
+ const main =
155
+ canvasElement.querySelector<HTMLElement>("main")
156
+
157
+ if (!main) {
158
+ throw new Error("The shell story has no Main element.")
159
+ }
160
+
161
+ await waitFor(async () => {
162
+ await expect(
163
+ getRowIndexes(canvasElement).length,
164
+ ).toBeGreaterThan(0)
165
+ })
166
+
167
+ await expect(getComputedStyle(main).overflowY).toBe(
168
+ "auto",
169
+ )
170
+ await expect(main.scrollHeight).toBeGreaterThan(
171
+ main.clientHeight,
172
+ )
173
+
174
+ const before = getRowIndexes(canvasElement)
175
+
176
+ main.scrollTop = 6000
177
+ main.dispatchEvent(new Event("scroll"))
178
+
179
+ await waitFor(async () => {
180
+ await expect(
181
+ getRowIndexes(canvasElement).some((index) =>
182
+ before.includes(index),
183
+ ),
184
+ ).toBe(false)
185
+ })
186
+
187
+ // The last row must replace the virtual spacer. This is the
188
+ // reported failure's visible half: the old window observer left
189
+ // tens of thousands of blank pixels below the first mounted rows
190
+ // when Main scrolled.
191
+ main.scrollTop = main.scrollHeight
192
+ main.dispatchEvent(new Event("scroll"))
193
+
194
+ await waitFor(async () => {
195
+ await expect(
196
+ getCells(canvasElement).some(
197
+ (cell) =>
198
+ cell.getAttribute("aria-posinset") === "2000",
199
+ ),
200
+ ).toBe(true)
201
+ })
202
+
203
+ await expect(
204
+ getList(canvasElement).style.paddingBlockEnd,
205
+ ).toBe("0px")
206
+ })
207
+
149
208
  test("a screen reader is told the real length", async () => {
150
209
  const { canvasElement } = await mountStory(Default)
151
210