@12-apps/ui 6.64.0 → 6.64.1

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.
@@ -1,14 +1,15 @@
1
1
  "use client";
2
2
  import {
3
3
  PickerSheet
4
- } from "../../../../chunk-43UPEJML.js";
5
- import "../../../../chunk-Z3DEMZ5J.js";
6
- import "../../../../chunk-ZQRNCUBB.js";
4
+ } from "../../../../chunk-TX3B7OAA.js";
5
+ import "../../../../chunk-OLT6ZXK5.js";
6
+ import "../../../../chunk-WSMUOFWF.js";
7
7
  import "../../../../chunk-QZOXMH7X.js";
8
- import "../../../../chunk-RLTCU57K.js";
8
+ import "../../../../chunk-WYRDR4T5.js";
9
9
  import "../../../../chunk-VPGDYI63.js";
10
10
  import "../../../../chunk-DMNZD3Q7.js";
11
11
  import "../../../../chunk-PN4HVM43.js";
12
+ import "../../../../chunk-TZ23DNKY.js";
12
13
  import "../../../../chunk-RGVNXES5.js";
13
14
  import "../../../../chunk-GDN2LUTZ.js";
14
15
  import "../../../../chunk-7ZADLRLP.js";
@@ -3,9 +3,10 @@ import {
3
3
  PickerSheetHead,
4
4
  PickerSheetList,
5
5
  PickerSheetSearch
6
- } from "../../../../chunk-Z3DEMZ5J.js";
7
- import "../../../../chunk-RLTCU57K.js";
6
+ } from "../../../../chunk-OLT6ZXK5.js";
7
+ import "../../../../chunk-WYRDR4T5.js";
8
8
  import "../../../../chunk-DMNZD3Q7.js";
9
+ import "../../../../chunk-TZ23DNKY.js";
9
10
  import "../../../../chunk-RGVNXES5.js";
10
11
  import "../../../../chunk-GDN2LUTZ.js";
11
12
  import "../../../../chunk-7ZADLRLP.js";
@@ -17,7 +17,8 @@ import {
17
17
  searchFieldSx,
18
18
  sheetPaperSx,
19
19
  titleSx
20
- } from "../../../../chunk-RLTCU57K.js";
20
+ } from "../../../../chunk-WYRDR4T5.js";
21
+ import "../../../../chunk-TZ23DNKY.js";
21
22
  import "../../../../chunk-RGVNXES5.js";
22
23
  import "../../../../chunk-GDN2LUTZ.js";
23
24
  import "../../../../chunk-7ZADLRLP.js";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  usePickerSheet
4
- } from "../../../../chunk-ZQRNCUBB.js";
4
+ } from "../../../../chunk-WSMUOFWF.js";
5
5
  import "../../../../chunk-QZOXMH7X.js";
6
6
  import "../../../../chunk-PN4HVM43.js";
7
7
  import "../../../../chunk-PZ5AY32C.js";
@@ -13,7 +13,7 @@ import {
13
13
  rowTextSx,
14
14
  searchFieldSx,
15
15
  titleSx
16
- } from "./chunk-RLTCU57K.js";
16
+ } from "./chunk-WYRDR4T5.js";
17
17
  import {
18
18
  CheckGlyph,
19
19
  SearchGlyph
@@ -152,4 +152,4 @@ export {
152
152
  PickerSheetSearch,
153
153
  PickerSheetList
154
154
  };
155
- //# sourceMappingURL=chunk-Z3DEMZ5J.js.map
155
+ //# sourceMappingURL=chunk-OLT6ZXK5.js.map
@@ -2,16 +2,16 @@ import {
2
2
  PickerSheetHead,
3
3
  PickerSheetList,
4
4
  PickerSheetSearch
5
- } from "./chunk-Z3DEMZ5J.js";
5
+ } from "./chunk-OLT6ZXK5.js";
6
6
  import {
7
7
  usePickerSheet
8
- } from "./chunk-ZQRNCUBB.js";
8
+ } from "./chunk-WSMUOFWF.js";
9
9
  import {
10
10
  bodySx,
11
11
  dialogPaperSx,
12
12
  footSx,
13
13
  sheetPaperSx
14
- } from "./chunk-RLTCU57K.js";
14
+ } from "./chunk-WYRDR4T5.js";
15
15
  import {
16
16
  METRICS
17
17
  } from "./chunk-VPGDYI63.js";
@@ -105,4 +105,4 @@ function PickerSheet(props) {
105
105
  export {
106
106
  PickerSheet
107
107
  };
108
- //# sourceMappingURL=chunk-43UPEJML.js.map
108
+ //# sourceMappingURL=chunk-TX3B7OAA.js.map
@@ -5,14 +5,7 @@ import {
5
5
 
6
6
  // src/components/form/PickerSheet/usePickerSheet.ts
7
7
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
8
- function useSheetScroll(open, activeIndex, listRef) {
9
- useEffect(() => {
10
- if (!open) return void 0;
11
- const frame = requestAnimationFrame(() => {
12
- listRef.current?.querySelector('[aria-selected="true"]')?.scrollIntoView?.({ block: "nearest" });
13
- });
14
- return () => cancelAnimationFrame(frame);
15
- }, [open, listRef]);
8
+ function useCursorScroll(activeIndex, listRef) {
16
9
  useEffect(() => {
17
10
  if (activeIndex < 0) return;
18
11
  const rows = listRef.current?.querySelectorAll('[role="option"]');
@@ -37,7 +30,7 @@ function usePickerSheet({ open, items, onPick, onCreate, createLabel }) {
37
30
  const creatable = Boolean(onCreate && createLabel);
38
31
  const view = useMemo(() => pickerSheetView(items, query, creatable), [items, query, creatable]);
39
32
  const activeIndex = rawActiveIndex < view.rowCount ? rawActiveIndex : -1;
40
- useSheetScroll(open, activeIndex, listRef);
33
+ useCursorScroll(activeIndex, listRef);
41
34
  const setQuery = useCallback((next) => {
42
35
  setRawQuery(next);
43
36
  setActiveIndex(next.trim() ? 0 : -1);
@@ -75,4 +68,4 @@ function usePickerSheet({ open, items, onPick, onCreate, createLabel }) {
75
68
  export {
76
69
  usePickerSheet
77
70
  };
78
- //# sourceMappingURL=chunk-ZQRNCUBB.js.map
71
+ //# sourceMappingURL=chunk-WSMUOFWF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/form/PickerSheet/usePickerSheet.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { pickerSheetView, stepActiveIndex, type PickerSheetView } from './picker-sheet-model';\nimport type { PickerSheetProps } from './PickerSheet.types';\n\n/** Everything the sheet's parts read: the query, the derived list, the cursor and the handlers. */\ninterface PickerSheetState {\n query: string;\n view: PickerSheetView;\n /** The keyboard cursor, an index into `view` (items, then the create row); -1 for none. Always a row that exists. */\n activeIndex: number;\n /** Draw the cursor: only once an arrow key has moved it, never from typing alone. */\n cursorShown: boolean;\n searchInputRef: React.RefObject<HTMLInputElement | null>;\n listRef: React.RefObject<HTMLUListElement | null>;\n setQuery: (next: string) => void;\n /** Pick the row at `index` — an item, or the create row when it is the last one. */\n choose: (index: number) => void;\n onSearchKeyDown: (event: React.KeyboardEvent) => void;\n}\n\ntype HookProps = Pick<PickerSheetProps, 'open' | 'items' | 'onPick' | 'onCreate' | 'createLabel'>;\n\n/**\n * Keep the keyboard cursor in view.\n *\n * Nothing inside is focused on open — the modal focuses its own paper. Focusing\n * the search box raised a phone's keyboard over the list it was opened to show.\n * The list opens at its top, the selected row wherever it falls (the design's\n * picker does not jump to it).\n */\nfunction useCursorScroll(activeIndex: number, listRef: React.RefObject<HTMLUListElement | null>): void {\n useEffect(() => {\n if (activeIndex < 0) return;\n const rows = listRef.current?.querySelectorAll('[role=\"option\"]');\n rows?.[activeIndex]?.scrollIntoView?.({ block: 'nearest' });\n }, [activeIndex, listRef]);\n}\n\n/**\n * The sheet's state. The query resets every time the sheet opens; typing puts\n * the cursor on the first match, so \"type, then Enter\" picks it (or creates,\n * when the create row is all there is).\n */\nexport function usePickerSheet({ open, items, onPick, onCreate, createLabel }: HookProps): PickerSheetState {\n const [query, setRawQuery] = useState('');\n const [rawActiveIndex, setActiveIndex] = useState(-1);\n const [cursorShown, setCursorShown] = useState(false);\n const searchInputRef = useRef<HTMLInputElement | null>(null);\n const listRef = useRef<HTMLUListElement | null>(null);\n\n // Reset while rendering the frame that opens the sheet, not in an effect\n // after it — an effect would paint the last session's query for one frame.\n const [wasOpen, setWasOpen] = useState(open);\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) {\n setRawQuery('');\n setActiveIndex(-1);\n setCursorShown(false);\n }\n }\n\n const creatable = Boolean(onCreate && createLabel);\n const view = useMemo(() => pickerSheetView(items, query, creatable), [items, query, creatable]);\n // Clamped on read: the rows can shrink under the cursor (a query, new items),\n // and `aria-activedescendant` must never name a row that is not there.\n const activeIndex = rawActiveIndex < view.rowCount ? rawActiveIndex : -1;\n\n useCursorScroll(activeIndex, listRef);\n\n const setQuery = useCallback((next: string) => {\n setRawQuery(next);\n setActiveIndex(next.trim() ? 0 : -1);\n }, []);\n\n const choose = useCallback(\n (index: number) => {\n const item = view.items[index];\n if (item) {\n onPick(item.id);\n return;\n }\n if (view.canCreate && index === view.items.length) onCreate?.(view.query);\n },\n [view, onPick, onCreate],\n );\n\n const onSearchKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const delta = event.key === 'ArrowDown' ? 1 : -1;\n setActiveIndex(stepActiveIndex(activeIndex, delta, view.rowCount));\n setCursorShown(true);\n return;\n }\n if (event.key === 'Enter' && activeIndex >= 0) {\n event.preventDefault();\n choose(activeIndex);\n }\n // Escape is the modal's: it closes through `onClose`, once.\n },\n [view.rowCount, activeIndex, choose],\n );\n\n return { query, view, activeIndex, cursorShown, searchInputRef, listRef, setQuery, choose, onSearchKeyDown };\n}\n"],"mappings":";;;;;;AAEA,SAAS,aAAa,WAAW,SAAS,QAAQ,gBAAgB;AA+BlE,SAAS,gBAAgB,aAAqB,SAAyD;AACrG,YAAU,MAAM;AACd,QAAI,cAAc,EAAG;AACrB,UAAM,OAAO,QAAQ,SAAS,iBAAiB,iBAAiB;AAChE,WAAO,WAAW,GAAG,iBAAiB,EAAE,OAAO,UAAU,CAAC;AAAA,EAC5D,GAAG,CAAC,aAAa,OAAO,CAAC;AAC3B;AAOO,SAAS,eAAe,EAAE,MAAM,OAAO,QAAQ,UAAU,YAAY,GAAgC;AAC1G,QAAM,CAAC,OAAO,WAAW,IAAI,SAAS,EAAE;AACxC,QAAM,CAAC,gBAAgB,cAAc,IAAI,SAAS,EAAE;AACpD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AACpD,QAAM,iBAAiB,OAAgC,IAAI;AAC3D,QAAM,UAAU,OAAgC,IAAI;AAIpD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,MAAI,SAAS,SAAS;AACpB,eAAW,IAAI;AACf,QAAI,MAAM;AACR,kBAAY,EAAE;AACd,qBAAe,EAAE;AACjB,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,YAAY,QAAQ,YAAY,WAAW;AACjD,QAAM,OAAO,QAAQ,MAAM,gBAAgB,OAAO,OAAO,SAAS,GAAG,CAAC,OAAO,OAAO,SAAS,CAAC;AAG9F,QAAM,cAAc,iBAAiB,KAAK,WAAW,iBAAiB;AAEtE,kBAAgB,aAAa,OAAO;AAEpC,QAAM,WAAW,YAAY,CAAC,SAAiB;AAC7C,gBAAY,IAAI;AAChB,mBAAe,KAAK,KAAK,IAAI,IAAI,EAAE;AAAA,EACrC,GAAG,CAAC,CAAC;AAEL,QAAM,SAAS;AAAA,IACb,CAAC,UAAkB;AACjB,YAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,UAAI,MAAM;AACR,eAAO,KAAK,EAAE;AACd;AAAA,MACF;AACA,UAAI,KAAK,aAAa,UAAU,KAAK,MAAM,OAAQ,YAAW,KAAK,KAAK;AAAA,IAC1E;AAAA,IACA,CAAC,MAAM,QAAQ,QAAQ;AAAA,EACzB;AAEA,QAAM,kBAAkB;AAAA,IACtB,CAAC,UAA+B;AAC9B,UAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,WAAW;AACxD,cAAM,eAAe;AACrB,cAAM,QAAQ,MAAM,QAAQ,cAAc,IAAI;AAC9C,uBAAe,gBAAgB,aAAa,OAAO,KAAK,QAAQ,CAAC;AACjE,uBAAe,IAAI;AACnB;AAAA,MACF;AACA,UAAI,MAAM,QAAQ,WAAW,eAAe,GAAG;AAC7C,cAAM,eAAe;AACrB,eAAO,WAAW;AAAA,MACpB;AAAA,IAEF;AAAA,IACA,CAAC,KAAK,UAAU,aAAa,MAAM;AAAA,EACrC;AAEA,SAAO,EAAE,OAAO,MAAM,aAAa,aAAa,gBAAgB,SAAS,UAAU,QAAQ,gBAAgB;AAC7G;","names":[]}
@@ -1,3 +1,6 @@
1
+ import {
2
+ surfaces
3
+ } from "./chunk-TZ23DNKY.js";
1
4
  import {
2
5
  fieldBorder,
3
6
  fieldHeight
@@ -51,7 +54,8 @@ var dialogPaperSx = (theme) => ({
51
54
  margin: 0,
52
55
  borderRadius: rem(theme, METRICS.dialogRadiusPx),
53
56
  boxShadow: panelShadow(theme),
54
- background: theme.palette.background.paper,
57
+ // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.
58
+ background: surfaces(theme).raised,
55
59
  backgroundImage: "none",
56
60
  display: "flex",
57
61
  flexDirection: "column",
@@ -62,7 +66,8 @@ var sheetPaperSx = (theme) => ({
62
66
  maxHeight: "88%",
63
67
  borderRadius: rems(theme, METRICS.sheetRadiusPx, METRICS.sheetRadiusPx, 0, 0),
64
68
  boxShadow: panelShadow(theme),
65
- background: theme.palette.background.paper,
69
+ // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.
70
+ background: surfaces(theme).raised,
66
71
  backgroundImage: "none",
67
72
  display: "flex",
68
73
  flexDirection: "column",
@@ -169,6 +174,9 @@ var rowSx = (theme, selected, active) => ({
169
174
  gap: rem(theme, 10),
170
175
  padding: rem(theme, METRICS.rowPaddingPx),
171
176
  minHeight: rem(theme, METRICS.rowMinHeightPx),
177
+ // The list is a capped flex column: without this a row with a meta line
178
+ // shrinks to the 44px floor and the two lines overprint.
179
+ flexShrink: 0,
172
180
  boxSizing: "border-box",
173
181
  borderRadius: rem(theme, METRICS.controlRadiusPx),
174
182
  textAlign: "left",
@@ -235,4 +243,4 @@ export {
235
243
  emptySx,
236
244
  footSx
237
245
  };
238
- //# sourceMappingURL=chunk-RLTCU57K.js.map
246
+ //# sourceMappingURL=chunk-WYRDR4T5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/form/PickerSheet/PickerSheet.styles.ts"],"sourcesContent":["import { alpha, type CSSObject, type Theme } from '@mui/material/styles/index.js';\n\nimport { fieldBorder, fieldHeight } from '../../../tokens/field-height';\nimport { fieldRadiusPx } from '../../../tokens/field-radius';\nimport { fieldWell, uiInk } from '../../../tokens/ink';\nimport { rem, rems } from '../../../tokens/relative';\nimport { surfaces } from '../../../tokens/surfaces';\n\n/**\n * The prototype's measurements, verbatim, in the design's px.\n *\n * Each is drawn through `rem()` where it is read, so the sheet follows a\n * density mode the way every other surface in the package does. Colours come\n * from the palette (a white-labelled tenant and dark mode carry through).\n */\nconst METRICS = {\n dialogWidthPx: 520,\n dialogMaxHeightPx: 780,\n dialogRadiusPx: 14,\n /** The gap a centred dialog keeps from the viewport edge. */\n dialogMarginPx: 32,\n sheetRadiusPx: 16,\n headGapPx: 10,\n closeButtonPx: 36,\n controlRadiusPx: 8,\n bodyPaddingPx: 16,\n bodyGapPx: 12,\n listMaxHeightPx: 380,\n listGapPx: 2,\n rowPaddingPx: 10,\n rowMinHeightPx: 44,\n /** Left padding per level of `indent` (`.pitem.ind{padding-left:28px}` at depth 1). */\n rowIndentStepPx: 28,\n checkGlyphPx: 16,\n closeGlyphPx: 18,\n searchGlyphPx: 16,\n /** The magnifier's inset from the field's inner edge, and the gap before the text. */\n searchGlyphInsetPx: 10,\n searchGlyphGapPx: 6,\n /** The prototype's body line-height; the sheet sets it rather than inheriting a host's. */\n lineHeight: 1.4,\n} as const;\n\n/** The panel's shadow: `0 16px 48px` of ink at 0.28. */\nconst panelShadow = (theme: Theme): string =>\n `${rems(theme, 0, 16, 48)} ${alpha(uiInk(theme).panelShadowInk, 0.28)}`;\n\n/** The centred dialog's paper, on a pointer. */\nexport const dialogPaperSx = (theme: Theme): CSSObject => ({\n width: rem(theme, METRICS.dialogWidthPx),\n maxWidth: `calc(100% - ${rem(theme, METRICS.dialogMarginPx)})`,\n maxHeight: `min(${rem(theme, METRICS.dialogMaxHeightPx)}, calc(100% - ${rem(theme, METRICS.dialogMarginPx * 2)}))`,\n margin: 0,\n borderRadius: rem(theme, METRICS.dialogRadiusPx),\n boxShadow: panelShadow(theme),\n // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.\n background: surfaces(theme).raised,\n backgroundImage: 'none',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n});\n\n/** The bottom sheet's paper, on a phone: full width, no grab handle. */\nexport const sheetPaperSx = (theme: Theme): CSSObject => ({\n width: '100%',\n maxHeight: '88%',\n borderRadius: rems(theme, METRICS.sheetRadiusPx, METRICS.sheetRadiusPx, 0, 0),\n boxShadow: panelShadow(theme),\n // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.\n background: surfaces(theme).raised,\n backgroundImage: 'none',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n});\n\n/** `.sh` — kicker and title on the left, the close button on the right. */\nexport const headSx = (theme: Theme): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: rem(theme, METRICS.headGapPx),\n padding: rems(theme, 14, 16),\n // A shade under the controls' own border: the rule separates, it does not frame.\n borderBottom: `1px solid ${alpha(theme.palette.divider, 0.6)}`,\n flex: '0 0 auto',\n});\n\nexport const kickerSx = (theme: Theme): CSSObject => ({\n fontSize: rem(theme, 11.5),\n color: theme.palette.text.secondary,\n lineHeight: METRICS.lineHeight,\n});\n\nexport const titleSx = (theme: Theme): CSSObject => ({\n margin: 0,\n fontSize: rem(theme, 14),\n fontWeight: 700,\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.primary,\n});\n\nexport const closeButtonSx = (theme: Theme): CSSObject => ({\n flex: '0 0 auto',\n width: rem(theme, METRICS.closeButtonPx),\n height: rem(theme, METRICS.closeButtonPx),\n display: 'grid',\n placeItems: 'center',\n padding: 0,\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: rem(theme, METRICS.controlRadiusPx),\n background: 'transparent',\n color: theme.palette.text.primary,\n cursor: 'pointer',\n '& svg': { width: rem(theme, METRICS.closeGlyphPx), height: rem(theme, METRICS.closeGlyphPx) },\n '&:hover': { background: theme.palette.action.hover },\n '&:focus-visible': { outline: `${rem(theme, 2)} solid ${theme.palette.primary.main}`, outlineOffset: rem(theme, 1) },\n});\n\n/** `.sb` — the scrolling body: search, list, foot. */\nexport const bodySx = (theme: Theme): CSSObject => ({\n display: 'flex',\n flexDirection: 'column',\n gap: rem(theme, METRICS.bodyGapPx),\n padding: rem(theme, METRICS.bodyPaddingPx),\n overflow: 'auto',\n minHeight: 0,\n flex: '1 1 auto',\n});\n\n/**\n * The search field: the library's field height, border and corner, with a\n * leading magnifier. White on the light sheet, so the field reads as a field\n * against the paper behind it.\n */\nexport const searchFieldSx = (theme: Theme): CSSObject => ({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n flex: '0 0 auto',\n '& > svg': {\n position: 'absolute',\n // + 1 for the input's own border, which the glyph sits inside of.\n left: rem(theme, METRICS.searchGlyphInsetPx + 1),\n width: rem(theme, METRICS.searchGlyphPx),\n height: rem(theme, METRICS.searchGlyphPx),\n color: theme.palette.text.secondary,\n pointerEvents: 'none',\n zIndex: 1,\n },\n '& input': {\n width: '100%',\n height: fieldHeight(theme),\n boxSizing: 'border-box',\n padding: rems(theme, 0, 10, 0, METRICS.searchGlyphInsetPx + METRICS.searchGlyphPx + METRICS.searchGlyphGapPx),\n fontSize: rem(theme, 14),\n border: fieldBorder(theme),\n borderRadius: fieldRadiusPx(theme),\n background: fieldWell(theme),\n color: theme.palette.text.primary,\n '&:focus': {\n outline: 'none',\n borderColor: theme.palette.primary.main,\n boxShadow: `0 0 0 ${rem(theme, 3)} ${alpha(theme.palette.primary.main, 0.15)}`,\n },\n },\n});\n\n/** The list: a column, scrolling on its own past 380px. */\nexport const listSx = (theme: Theme): CSSObject => ({\n display: 'flex',\n flexDirection: 'column',\n gap: rem(theme, METRICS.listGapPx),\n maxHeight: rem(theme, METRICS.listMaxHeightPx),\n overflow: 'auto',\n overscrollBehavior: 'contain',\n margin: 0,\n padding: 0,\n listStyle: 'none',\n flex: '0 1 auto',\n});\n\n/** Left padding for a row at `depth` — the row's own 10px at depth 0, 28px per level below it. */\nexport const rowPaddingLeft = (theme: Theme, depth: number): string =>\n rem(theme, depth > 0 ? METRICS.rowIndentStepPx * depth : METRICS.rowPaddingPx);\n\n/** Background of a row: selected wins over the keyboard cursor, which wins over rest. */\nfunction rowBackground(theme: Theme, selected: boolean, active: boolean): string {\n if (selected) return alpha(theme.palette.primary.main, 0.1);\n return active ? theme.palette.action.hover : 'transparent';\n}\n\n/** `.pitem` — a row. `active` is the keyboard cursor, drawn as a ring so it reads apart from `selected`. */\nexport const rowSx = (theme: Theme, selected: boolean, active: boolean): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: rem(theme, 10),\n padding: rem(theme, METRICS.rowPaddingPx),\n minHeight: rem(theme, METRICS.rowMinHeightPx),\n // The list is a capped flex column: without this a row with a meta line\n // shrinks to the 44px floor and the two lines overprint.\n flexShrink: 0,\n boxSizing: 'border-box',\n borderRadius: rem(theme, METRICS.controlRadiusPx),\n textAlign: 'left',\n cursor: 'pointer',\n userSelect: 'none',\n color: theme.palette.text.primary,\n background: rowBackground(theme, selected, active),\n boxShadow: active ? `inset 0 0 0 ${rem(theme, 1)} ${alpha(theme.palette.primary.main, 0.3)}` : 'none',\n '&:hover': { background: selected ? alpha(theme.palette.primary.main, 0.1) : theme.palette.action.hover },\n});\n\nexport const rowTextSx: CSSObject = { flex: '1 1 auto', minWidth: 0 };\n\nexport const rowLabelSx = (theme: Theme): CSSObject => ({\n display: 'block',\n fontSize: rem(theme, 14),\n lineHeight: METRICS.lineHeight,\n});\n\nexport const rowMetaSx = (theme: Theme): CSSObject => ({\n display: 'block',\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n});\n\nexport const checkSx = (theme: Theme): CSSObject => ({\n flex: '0 0 auto',\n display: 'grid',\n color: theme.palette.primary.main,\n '& svg': { width: rem(theme, METRICS.checkGlyphPx), height: rem(theme, METRICS.checkGlyphPx) },\n});\n\n/** The create row's text: the accent, at 600. */\nexport const createLabelSx = (theme: Theme): CSSObject => ({\n ...rowLabelSx(theme),\n color: theme.palette.primary.main,\n fontWeight: 600,\n});\n\nexport const emptySx = (theme: Theme): CSSObject => ({\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n padding: rem(theme, 10),\n});\n\nexport const footSx = (theme: Theme): CSSObject => ({\n margin: 0,\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n});\n"],"mappings":"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","names":[]}
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  PickerSheet
3
- } from "../chunk-43UPEJML.js";
4
- import "../chunk-Z3DEMZ5J.js";
5
- import "../chunk-ZQRNCUBB.js";
3
+ } from "../chunk-TX3B7OAA.js";
4
+ import "../chunk-OLT6ZXK5.js";
5
+ import "../chunk-WSMUOFWF.js";
6
6
  import "../chunk-QZOXMH7X.js";
7
- import "../chunk-RLTCU57K.js";
7
+ import "../chunk-WYRDR4T5.js";
8
8
  import "../chunk-VPGDYI63.js";
9
9
  import "../chunk-DMNZD3Q7.js";
10
10
  import "../chunk-PN4HVM43.js";
11
+ import "../chunk-TZ23DNKY.js";
11
12
  import "../chunk-RGVNXES5.js";
12
13
  import "../chunk-GDN2LUTZ.js";
13
14
  import "../chunk-7ZADLRLP.js";
@@ -1 +1 @@
1
- {"version":3,"file":"PickerSheet.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/PickerSheet/PickerSheet.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,+BAA+B,CAAC;AA8ClF,gDAAgD;AAChD,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SAY3C,CAAC;AAEH,wEAAwE;AACxE,eAAO,MAAM,YAAY,GAAI,OAAO,KAAK,KAAG,SAU1C,CAAC;AAEH,2EAA2E;AAC3E,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAQpC,CAAC;AAEH,eAAO,MAAM,QAAQ,GAAI,OAAO,KAAK,KAAG,SAItC,CAAC;AAEH,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,SAMrC,CAAC;AAEH,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SAe3C,CAAC;AAEH,sDAAsD;AACtD,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAQpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SA+B3C,CAAC;AAEH,2DAA2D;AAC3D,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAWpC,CAAC;AAEH,kGAAkG;AAClG,eAAO,MAAM,cAAc,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,KAAG,MACmB,CAAC;AAQjF,4GAA4G;AAC5G,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,EAAE,UAAU,OAAO,EAAE,QAAQ,OAAO,KAAG,SAevE,CAAC;AAEH,eAAO,MAAM,SAAS,EAAE,SAA6C,CAAC;AAEtE,eAAO,MAAM,UAAU,GAAI,OAAO,KAAK,KAAG,SAIxC,CAAC;AAEH,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,KAAG,SAKvC,CAAC;AAEH,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,SAKrC,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SAI3C,CAAC;AAEH,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,SAKrC,CAAC;AAEH,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAKpC,CAAC"}
1
+ {"version":3,"file":"PickerSheet.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/PickerSheet/PickerSheet.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,+BAA+B,CAAC;AA+ClF,gDAAgD;AAChD,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SAa3C,CAAC;AAEH,wEAAwE;AACxE,eAAO,MAAM,YAAY,GAAI,OAAO,KAAK,KAAG,SAW1C,CAAC;AAEH,2EAA2E;AAC3E,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAQpC,CAAC;AAEH,eAAO,MAAM,QAAQ,GAAI,OAAO,KAAK,KAAG,SAItC,CAAC;AAEH,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,SAMrC,CAAC;AAEH,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SAe3C,CAAC;AAEH,sDAAsD;AACtD,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAQpC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SA+B3C,CAAC;AAEH,2DAA2D;AAC3D,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAWpC,CAAC;AAEH,kGAAkG;AAClG,eAAO,MAAM,cAAc,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,KAAG,MACmB,CAAC;AAQjF,4GAA4G;AAC5G,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,EAAE,UAAU,OAAO,EAAE,QAAQ,OAAO,KAAG,SAkBvE,CAAC;AAEH,eAAO,MAAM,SAAS,EAAE,SAA6C,CAAC;AAEtE,eAAO,MAAM,UAAU,GAAI,OAAO,KAAK,KAAG,SAIxC,CAAC;AAEH,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,KAAG,SAKvC,CAAC;AAEH,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,SAKrC,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,SAI3C,CAAC;AAEH,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,SAKrC,CAAC;AAEH,eAAO,MAAM,MAAM,GAAI,OAAO,KAAK,KAAG,SAKpC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePickerSheet.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/PickerSheet/usePickerSheet.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoC,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,mGAAmG;AACnG,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;IACtB,qHAAqH;IACrH,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACzD,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,oFAAoF;IACpF,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;CACvD;AAED,KAAK,SAAS,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,CAAC,CAAC;AA8BlG;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,SAAS,GAAG,gBAAgB,CA+D1G"}
1
+ {"version":3,"file":"usePickerSheet.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/PickerSheet/usePickerSheet.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoC,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,mGAAmG;AACnG,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;IACtB,qHAAqH;IACrH,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACzD,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,oFAAoF;IACpF,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,eAAe,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;CACvD;AAED,KAAK,SAAS,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,CAAC,CAAC;AAkBlG;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,SAAS,GAAG,gBAAgB,CA+D1G"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "6.64.0",
3
+ "version": "6.64.1",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@10.34.5",
6
6
  "type": "module",
@@ -44,7 +44,7 @@ Every word it shows comes from the caller: the package ships no copy for it.
44
44
 
45
45
  ## Behaviour
46
46
 
47
- - Nothing takes focus inside the sheet on open — the dialog itself does — so a phone does not raise its keyboard over the list; the selected row is scrolled into view. Tab reaches the search box.
47
+ - Nothing takes focus inside the sheet on open — the dialog itself does — so a phone does not raise its keyboard over the list. The list opens at its top. Tab reaches the search box.
48
48
  - Filtering is a substring match on each item's label and `searchText`, case and ACCENTS aside ("acai" finds "Açaí", as in `CategorySelect`).
49
49
  - ↑/↓ move the keyboard cursor (wrapping at both ends, as `Command` does) and Enter picks the row under it. Typing puts the cursor on the first match, so "type, then Enter" picks it — or creates, when the create row is the only row. The cursor is drawn only once an arrow key has moved it: typing alone shows no ring on a phone.
50
50
  - Esc and a tap outside close (through `onClose`).
@@ -4,6 +4,7 @@ import { fieldBorder, fieldHeight } from '../../../tokens/field-height';
4
4
  import { fieldRadiusPx } from '../../../tokens/field-radius';
5
5
  import { fieldWell, uiInk } from '../../../tokens/ink';
6
6
  import { rem, rems } from '../../../tokens/relative';
7
+ import { surfaces } from '../../../tokens/surfaces';
7
8
 
8
9
  /**
9
10
  * The prototype's measurements, verbatim, in the design's px.
@@ -52,7 +53,8 @@ export const dialogPaperSx = (theme: Theme): CSSObject => ({
52
53
  margin: 0,
53
54
  borderRadius: rem(theme, METRICS.dialogRadiusPx),
54
55
  boxShadow: panelShadow(theme),
55
- background: theme.palette.background.paper,
56
+ // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.
57
+ background: surfaces(theme).raised,
56
58
  backgroundImage: 'none',
57
59
  display: 'flex',
58
60
  flexDirection: 'column',
@@ -65,7 +67,8 @@ export const sheetPaperSx = (theme: Theme): CSSObject => ({
65
67
  maxHeight: '88%',
66
68
  borderRadius: rems(theme, METRICS.sheetRadiusPx, METRICS.sheetRadiusPx, 0, 0),
67
69
  boxShadow: panelShadow(theme),
68
- background: theme.palette.background.paper,
70
+ // The raised step (`uiSurfaces.raised`): a sheet is nearer than the page.
71
+ background: surfaces(theme).raised,
69
72
  backgroundImage: 'none',
70
73
  display: 'flex',
71
74
  flexDirection: 'column',
@@ -194,6 +197,9 @@ export const rowSx = (theme: Theme, selected: boolean, active: boolean): CSSObje
194
197
  gap: rem(theme, 10),
195
198
  padding: rem(theme, METRICS.rowPaddingPx),
196
199
  minHeight: rem(theme, METRICS.rowMinHeightPx),
200
+ // The list is a capped flex column: without this a row with a meta line
201
+ // shrinks to the 44px floor and the two lines overprint.
202
+ flexShrink: 0,
197
203
  boxSizing: 'border-box',
198
204
  borderRadius: rem(theme, METRICS.controlRadiusPx),
199
205
  textAlign: 'left',
@@ -24,26 +24,14 @@ interface PickerSheetState {
24
24
  type HookProps = Pick<PickerSheetProps, 'open' | 'items' | 'onPick' | 'onCreate' | 'createLabel'>;
25
25
 
26
26
  /**
27
- * Bring the selected row into view on open, and keep the keyboard cursor in view.
27
+ * Keep the keyboard cursor in view.
28
28
  *
29
29
  * Nothing inside is focused on open — the modal focuses its own paper. Focusing
30
30
  * the search box raised a phone's keyboard over the list it was opened to show.
31
- * Deferred a frame: the surface mounts its content in the same commit as this
32
- * effect.
31
+ * The list opens at its top, the selected row wherever it falls (the design's
32
+ * picker does not jump to it).
33
33
  */
34
- function useSheetScroll(
35
- open: boolean,
36
- activeIndex: number,
37
- listRef: React.RefObject<HTMLUListElement | null>,
38
- ): void {
39
- useEffect(() => {
40
- if (!open) return undefined;
41
- const frame = requestAnimationFrame(() => {
42
- listRef.current?.querySelector('[aria-selected="true"]')?.scrollIntoView?.({ block: 'nearest' });
43
- });
44
- return () => cancelAnimationFrame(frame);
45
- }, [open, listRef]);
46
-
34
+ function useCursorScroll(activeIndex: number, listRef: React.RefObject<HTMLUListElement | null>): void {
47
35
  useEffect(() => {
48
36
  if (activeIndex < 0) return;
49
37
  const rows = listRef.current?.querySelectorAll('[role="option"]');
@@ -81,7 +69,7 @@ export function usePickerSheet({ open, items, onPick, onCreate, createLabel }: H
81
69
  // and `aria-activedescendant` must never name a row that is not there.
82
70
  const activeIndex = rawActiveIndex < view.rowCount ? rawActiveIndex : -1;
83
71
 
84
- useSheetScroll(open, activeIndex, listRef);
72
+ useCursorScroll(activeIndex, listRef);
85
73
 
86
74
  const setQuery = useCallback((next: string) => {
87
75
  setRawQuery(next);
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/PickerSheet/PickerSheet.styles.ts"],"sourcesContent":["import { alpha, type CSSObject, type Theme } from '@mui/material/styles/index.js';\n\nimport { fieldBorder, fieldHeight } from '../../../tokens/field-height';\nimport { fieldRadiusPx } from '../../../tokens/field-radius';\nimport { fieldWell, uiInk } from '../../../tokens/ink';\nimport { rem, rems } from '../../../tokens/relative';\n\n/**\n * The prototype's measurements, verbatim, in the design's px.\n *\n * Each is drawn through `rem()` where it is read, so the sheet follows a\n * density mode the way every other surface in the package does. Colours come\n * from the palette (a white-labelled tenant and dark mode carry through).\n */\nconst METRICS = {\n dialogWidthPx: 520,\n dialogMaxHeightPx: 780,\n dialogRadiusPx: 14,\n /** The gap a centred dialog keeps from the viewport edge. */\n dialogMarginPx: 32,\n sheetRadiusPx: 16,\n headGapPx: 10,\n closeButtonPx: 36,\n controlRadiusPx: 8,\n bodyPaddingPx: 16,\n bodyGapPx: 12,\n listMaxHeightPx: 380,\n listGapPx: 2,\n rowPaddingPx: 10,\n rowMinHeightPx: 44,\n /** Left padding per level of `indent` (`.pitem.ind{padding-left:28px}` at depth 1). */\n rowIndentStepPx: 28,\n checkGlyphPx: 16,\n closeGlyphPx: 18,\n searchGlyphPx: 16,\n /** The magnifier's inset from the field's inner edge, and the gap before the text. */\n searchGlyphInsetPx: 10,\n searchGlyphGapPx: 6,\n /** The prototype's body line-height; the sheet sets it rather than inheriting a host's. */\n lineHeight: 1.4,\n} as const;\n\n/** The panel's shadow: `0 16px 48px` of ink at 0.28. */\nconst panelShadow = (theme: Theme): string =>\n `${rems(theme, 0, 16, 48)} ${alpha(uiInk(theme).panelShadowInk, 0.28)}`;\n\n/** The centred dialog's paper, on a pointer. */\nexport const dialogPaperSx = (theme: Theme): CSSObject => ({\n width: rem(theme, METRICS.dialogWidthPx),\n maxWidth: `calc(100% - ${rem(theme, METRICS.dialogMarginPx)})`,\n maxHeight: `min(${rem(theme, METRICS.dialogMaxHeightPx)}, calc(100% - ${rem(theme, METRICS.dialogMarginPx * 2)}))`,\n margin: 0,\n borderRadius: rem(theme, METRICS.dialogRadiusPx),\n boxShadow: panelShadow(theme),\n background: theme.palette.background.paper,\n backgroundImage: 'none',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n});\n\n/** The bottom sheet's paper, on a phone: full width, no grab handle. */\nexport const sheetPaperSx = (theme: Theme): CSSObject => ({\n width: '100%',\n maxHeight: '88%',\n borderRadius: rems(theme, METRICS.sheetRadiusPx, METRICS.sheetRadiusPx, 0, 0),\n boxShadow: panelShadow(theme),\n background: theme.palette.background.paper,\n backgroundImage: 'none',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n});\n\n/** `.sh` — kicker and title on the left, the close button on the right. */\nexport const headSx = (theme: Theme): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: rem(theme, METRICS.headGapPx),\n padding: rems(theme, 14, 16),\n // A shade under the controls' own border: the rule separates, it does not frame.\n borderBottom: `1px solid ${alpha(theme.palette.divider, 0.6)}`,\n flex: '0 0 auto',\n});\n\nexport const kickerSx = (theme: Theme): CSSObject => ({\n fontSize: rem(theme, 11.5),\n color: theme.palette.text.secondary,\n lineHeight: METRICS.lineHeight,\n});\n\nexport const titleSx = (theme: Theme): CSSObject => ({\n margin: 0,\n fontSize: rem(theme, 14),\n fontWeight: 700,\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.primary,\n});\n\nexport const closeButtonSx = (theme: Theme): CSSObject => ({\n flex: '0 0 auto',\n width: rem(theme, METRICS.closeButtonPx),\n height: rem(theme, METRICS.closeButtonPx),\n display: 'grid',\n placeItems: 'center',\n padding: 0,\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: rem(theme, METRICS.controlRadiusPx),\n background: 'transparent',\n color: theme.palette.text.primary,\n cursor: 'pointer',\n '& svg': { width: rem(theme, METRICS.closeGlyphPx), height: rem(theme, METRICS.closeGlyphPx) },\n '&:hover': { background: theme.palette.action.hover },\n '&:focus-visible': { outline: `${rem(theme, 2)} solid ${theme.palette.primary.main}`, outlineOffset: rem(theme, 1) },\n});\n\n/** `.sb` — the scrolling body: search, list, foot. */\nexport const bodySx = (theme: Theme): CSSObject => ({\n display: 'flex',\n flexDirection: 'column',\n gap: rem(theme, METRICS.bodyGapPx),\n padding: rem(theme, METRICS.bodyPaddingPx),\n overflow: 'auto',\n minHeight: 0,\n flex: '1 1 auto',\n});\n\n/**\n * The search field: the library's field height, border and corner, with a\n * leading magnifier. White on the light sheet, so the field reads as a field\n * against the paper behind it.\n */\nexport const searchFieldSx = (theme: Theme): CSSObject => ({\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n flex: '0 0 auto',\n '& > svg': {\n position: 'absolute',\n // + 1 for the input's own border, which the glyph sits inside of.\n left: rem(theme, METRICS.searchGlyphInsetPx + 1),\n width: rem(theme, METRICS.searchGlyphPx),\n height: rem(theme, METRICS.searchGlyphPx),\n color: theme.palette.text.secondary,\n pointerEvents: 'none',\n zIndex: 1,\n },\n '& input': {\n width: '100%',\n height: fieldHeight(theme),\n boxSizing: 'border-box',\n padding: rems(theme, 0, 10, 0, METRICS.searchGlyphInsetPx + METRICS.searchGlyphPx + METRICS.searchGlyphGapPx),\n fontSize: rem(theme, 14),\n border: fieldBorder(theme),\n borderRadius: fieldRadiusPx(theme),\n background: fieldWell(theme),\n color: theme.palette.text.primary,\n '&:focus': {\n outline: 'none',\n borderColor: theme.palette.primary.main,\n boxShadow: `0 0 0 ${rem(theme, 3)} ${alpha(theme.palette.primary.main, 0.15)}`,\n },\n },\n});\n\n/** The list: a column, scrolling on its own past 380px. */\nexport const listSx = (theme: Theme): CSSObject => ({\n display: 'flex',\n flexDirection: 'column',\n gap: rem(theme, METRICS.listGapPx),\n maxHeight: rem(theme, METRICS.listMaxHeightPx),\n overflow: 'auto',\n overscrollBehavior: 'contain',\n margin: 0,\n padding: 0,\n listStyle: 'none',\n flex: '0 1 auto',\n});\n\n/** Left padding for a row at `depth` — the row's own 10px at depth 0, 28px per level below it. */\nexport const rowPaddingLeft = (theme: Theme, depth: number): string =>\n rem(theme, depth > 0 ? METRICS.rowIndentStepPx * depth : METRICS.rowPaddingPx);\n\n/** Background of a row: selected wins over the keyboard cursor, which wins over rest. */\nfunction rowBackground(theme: Theme, selected: boolean, active: boolean): string {\n if (selected) return alpha(theme.palette.primary.main, 0.1);\n return active ? theme.palette.action.hover : 'transparent';\n}\n\n/** `.pitem` — a row. `active` is the keyboard cursor, drawn as a ring so it reads apart from `selected`. */\nexport const rowSx = (theme: Theme, selected: boolean, active: boolean): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: rem(theme, 10),\n padding: rem(theme, METRICS.rowPaddingPx),\n minHeight: rem(theme, METRICS.rowMinHeightPx),\n boxSizing: 'border-box',\n borderRadius: rem(theme, METRICS.controlRadiusPx),\n textAlign: 'left',\n cursor: 'pointer',\n userSelect: 'none',\n color: theme.palette.text.primary,\n background: rowBackground(theme, selected, active),\n boxShadow: active ? `inset 0 0 0 ${rem(theme, 1)} ${alpha(theme.palette.primary.main, 0.3)}` : 'none',\n '&:hover': { background: selected ? alpha(theme.palette.primary.main, 0.1) : theme.palette.action.hover },\n});\n\nexport const rowTextSx: CSSObject = { flex: '1 1 auto', minWidth: 0 };\n\nexport const rowLabelSx = (theme: Theme): CSSObject => ({\n display: 'block',\n fontSize: rem(theme, 14),\n lineHeight: METRICS.lineHeight,\n});\n\nexport const rowMetaSx = (theme: Theme): CSSObject => ({\n display: 'block',\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n});\n\nexport const checkSx = (theme: Theme): CSSObject => ({\n flex: '0 0 auto',\n display: 'grid',\n color: theme.palette.primary.main,\n '& svg': { width: rem(theme, METRICS.checkGlyphPx), height: rem(theme, METRICS.checkGlyphPx) },\n});\n\n/** The create row's text: the accent, at 600. */\nexport const createLabelSx = (theme: Theme): CSSObject => ({\n ...rowLabelSx(theme),\n color: theme.palette.primary.main,\n fontWeight: 600,\n});\n\nexport const emptySx = (theme: Theme): CSSObject => ({\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n padding: rem(theme, 10),\n});\n\nexport const footSx = (theme: Theme): CSSObject => ({\n margin: 0,\n fontSize: rem(theme, 12),\n lineHeight: METRICS.lineHeight,\n color: theme.palette.text.secondary,\n});\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/PickerSheet/usePickerSheet.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { pickerSheetView, stepActiveIndex, type PickerSheetView } from './picker-sheet-model';\nimport type { PickerSheetProps } from './PickerSheet.types';\n\n/** Everything the sheet's parts read: the query, the derived list, the cursor and the handlers. */\ninterface PickerSheetState {\n query: string;\n view: PickerSheetView;\n /** The keyboard cursor, an index into `view` (items, then the create row); -1 for none. Always a row that exists. */\n activeIndex: number;\n /** Draw the cursor: only once an arrow key has moved it, never from typing alone. */\n cursorShown: boolean;\n searchInputRef: React.RefObject<HTMLInputElement | null>;\n listRef: React.RefObject<HTMLUListElement | null>;\n setQuery: (next: string) => void;\n /** Pick the row at `index` — an item, or the create row when it is the last one. */\n choose: (index: number) => void;\n onSearchKeyDown: (event: React.KeyboardEvent) => void;\n}\n\ntype HookProps = Pick<PickerSheetProps, 'open' | 'items' | 'onPick' | 'onCreate' | 'createLabel'>;\n\n/**\n * Bring the selected row into view on open, and keep the keyboard cursor in view.\n *\n * Nothing inside is focused on open — the modal focuses its own paper. Focusing\n * the search box raised a phone's keyboard over the list it was opened to show.\n * Deferred a frame: the surface mounts its content in the same commit as this\n * effect.\n */\nfunction useSheetScroll(\n open: boolean,\n activeIndex: number,\n listRef: React.RefObject<HTMLUListElement | null>,\n): void {\n useEffect(() => {\n if (!open) return undefined;\n const frame = requestAnimationFrame(() => {\n listRef.current?.querySelector('[aria-selected=\"true\"]')?.scrollIntoView?.({ block: 'nearest' });\n });\n return () => cancelAnimationFrame(frame);\n }, [open, listRef]);\n\n useEffect(() => {\n if (activeIndex < 0) return;\n const rows = listRef.current?.querySelectorAll('[role=\"option\"]');\n rows?.[activeIndex]?.scrollIntoView?.({ block: 'nearest' });\n }, [activeIndex, listRef]);\n}\n\n/**\n * The sheet's state. The query resets every time the sheet opens; typing puts\n * the cursor on the first match, so \"type, then Enter\" picks it (or creates,\n * when the create row is all there is).\n */\nexport function usePickerSheet({ open, items, onPick, onCreate, createLabel }: HookProps): PickerSheetState {\n const [query, setRawQuery] = useState('');\n const [rawActiveIndex, setActiveIndex] = useState(-1);\n const [cursorShown, setCursorShown] = useState(false);\n const searchInputRef = useRef<HTMLInputElement | null>(null);\n const listRef = useRef<HTMLUListElement | null>(null);\n\n // Reset while rendering the frame that opens the sheet, not in an effect\n // after it — an effect would paint the last session's query for one frame.\n const [wasOpen, setWasOpen] = useState(open);\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) {\n setRawQuery('');\n setActiveIndex(-1);\n setCursorShown(false);\n }\n }\n\n const creatable = Boolean(onCreate && createLabel);\n const view = useMemo(() => pickerSheetView(items, query, creatable), [items, query, creatable]);\n // Clamped on read: the rows can shrink under the cursor (a query, new items),\n // and `aria-activedescendant` must never name a row that is not there.\n const activeIndex = rawActiveIndex < view.rowCount ? rawActiveIndex : -1;\n\n useSheetScroll(open, activeIndex, listRef);\n\n const setQuery = useCallback((next: string) => {\n setRawQuery(next);\n setActiveIndex(next.trim() ? 0 : -1);\n }, []);\n\n const choose = useCallback(\n (index: number) => {\n const item = view.items[index];\n if (item) {\n onPick(item.id);\n return;\n }\n if (view.canCreate && index === view.items.length) onCreate?.(view.query);\n },\n [view, onPick, onCreate],\n );\n\n const onSearchKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n const delta = event.key === 'ArrowDown' ? 1 : -1;\n setActiveIndex(stepActiveIndex(activeIndex, delta, view.rowCount));\n setCursorShown(true);\n return;\n }\n if (event.key === 'Enter' && activeIndex >= 0) {\n event.preventDefault();\n choose(activeIndex);\n }\n // Escape is the modal's: it closes through `onClose`, once.\n },\n [view.rowCount, activeIndex, choose],\n );\n\n return { query, view, activeIndex, cursorShown, searchInputRef, listRef, setQuery, choose, onSearchKeyDown };\n}\n"],"mappings":";;;;;;AAEA,SAAS,aAAa,WAAW,SAAS,QAAQ,gBAAgB;AA+BlE,SAAS,eACP,MACA,aACA,SACM;AACN,YAAU,MAAM;AACd,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,QAAQ,sBAAsB,MAAM;AACxC,cAAQ,SAAS,cAAc,wBAAwB,GAAG,iBAAiB,EAAE,OAAO,UAAU,CAAC;AAAA,IACjG,CAAC;AACD,WAAO,MAAM,qBAAqB,KAAK;AAAA,EACzC,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,YAAU,MAAM;AACd,QAAI,cAAc,EAAG;AACrB,UAAM,OAAO,QAAQ,SAAS,iBAAiB,iBAAiB;AAChE,WAAO,WAAW,GAAG,iBAAiB,EAAE,OAAO,UAAU,CAAC;AAAA,EAC5D,GAAG,CAAC,aAAa,OAAO,CAAC;AAC3B;AAOO,SAAS,eAAe,EAAE,MAAM,OAAO,QAAQ,UAAU,YAAY,GAAgC;AAC1G,QAAM,CAAC,OAAO,WAAW,IAAI,SAAS,EAAE;AACxC,QAAM,CAAC,gBAAgB,cAAc,IAAI,SAAS,EAAE;AACpD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AACpD,QAAM,iBAAiB,OAAgC,IAAI;AAC3D,QAAM,UAAU,OAAgC,IAAI;AAIpD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,MAAI,SAAS,SAAS;AACpB,eAAW,IAAI;AACf,QAAI,MAAM;AACR,kBAAY,EAAE;AACd,qBAAe,EAAE;AACjB,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,YAAY,QAAQ,YAAY,WAAW;AACjD,QAAM,OAAO,QAAQ,MAAM,gBAAgB,OAAO,OAAO,SAAS,GAAG,CAAC,OAAO,OAAO,SAAS,CAAC;AAG9F,QAAM,cAAc,iBAAiB,KAAK,WAAW,iBAAiB;AAEtE,iBAAe,MAAM,aAAa,OAAO;AAEzC,QAAM,WAAW,YAAY,CAAC,SAAiB;AAC7C,gBAAY,IAAI;AAChB,mBAAe,KAAK,KAAK,IAAI,IAAI,EAAE;AAAA,EACrC,GAAG,CAAC,CAAC;AAEL,QAAM,SAAS;AAAA,IACb,CAAC,UAAkB;AACjB,YAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,UAAI,MAAM;AACR,eAAO,KAAK,EAAE;AACd;AAAA,MACF;AACA,UAAI,KAAK,aAAa,UAAU,KAAK,MAAM,OAAQ,YAAW,KAAK,KAAK;AAAA,IAC1E;AAAA,IACA,CAAC,MAAM,QAAQ,QAAQ;AAAA,EACzB;AAEA,QAAM,kBAAkB;AAAA,IACtB,CAAC,UAA+B;AAC9B,UAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,WAAW;AACxD,cAAM,eAAe;AACrB,cAAM,QAAQ,MAAM,QAAQ,cAAc,IAAI;AAC9C,uBAAe,gBAAgB,aAAa,OAAO,KAAK,QAAQ,CAAC;AACjE,uBAAe,IAAI;AACnB;AAAA,MACF;AACA,UAAI,MAAM,QAAQ,WAAW,eAAe,GAAG;AAC7C,cAAM,eAAe;AACrB,eAAO,WAAW;AAAA,MACpB;AAAA,IAEF;AAAA,IACA,CAAC,KAAK,UAAU,aAAa,MAAM;AAAA,EACrC;AAEA,SAAO,EAAE,OAAO,MAAM,aAAa,aAAa,gBAAgB,SAAS,UAAU,QAAQ,gBAAgB;AAC7G;","names":[]}