@hjmds/react 1.48.0 → 1.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced-display.d.ts +3 -1
- package/dist/advanced-display.d.ts.map +1 -1
- package/dist/advanced-display.js +23 -15
- package/dist/advanced-display.js.map +1 -1
- package/dist/display.d.ts +4 -0
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +3 -3
- package/dist/display.js.map +1 -1
- package/dist/drawing-editor.d.ts +7 -0
- package/dist/drawing-editor.d.ts.map +1 -0
- package/dist/drawing-editor.js +123 -0
- package/dist/drawing-editor.js.map +1 -0
- package/dist/evidence.d.ts +1 -1
- package/dist/evidence.js +1 -1
- package/dist/evidence.js.map +1 -1
- package/dist/image-choice.js +2 -1
- package/dist/image-choice.js.map +1 -1
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +81 -2
- package/dist/overlays.js.map +1 -1
- package/dist/public-exports.generated.d.ts +1 -0
- package/dist/public-exports.generated.d.ts.map +1 -1
- package/dist/public-exports.generated.js +3 -0
- package/dist/public-exports.generated.js.map +1 -1
- package/dist/styles.css +23 -1
- package/dist/styles.layered.css +23 -1
- package/package.json +8 -3
package/dist/image-choice.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-choice.js","sourceRoot":"","sources":["../src/image-choice.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { Text } from \"./layout.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport { typography } from \"@hjmds/design-contracts/foundations\";\nimport {\n imageChoiceRecipe, resolveImageChoiceCaptionLines, resolveImageChoiceColumns, resolveImageChoiceOuterSize, resolveImageChoiceTileHeight, resolveImageChoiceToggle,\n validateImageChoiceItemLabelLines, validateImageChoiceItems, type ImageChoiceItemDescriptor, type ImageChoiceItemLabelLines,\n} from \"@hjmds/design-contracts/components/image-choice\";\nimport { resolveVirtualWindow, virtualListRecipe } from \"@hjmds/design-contracts/components/virtual-list\";\n\nexport type ImageChoiceItem = ImageChoiceItemDescriptor & Readonly<{ image: ReactNode }>;\nexport type ImageChoiceVirtualization = Readonly<{\n /** Height of the scrolling viewport in px. The group scrolls itself, so do not also put it in a scrolling parent. */\n height: number;\n /** Rows kept mounted above and below the visible window. */\n overscan?: number;\n}>;\ntype Base = Readonly<{\n /** Localized group name read before the choices. */\n label: string;\n /** Visible caption above the tiles; omit when the screen heading already names the choice. */\n showLabel?: boolean;\n /**\n * Shows each item's `label` under its tile (one ellipsized line), e.g. a person's name in a recipient picker.\n * The tile keeps the same accessible name, so turning this on does not change what assistive tech reads.\n */\n showItemLabels?: boolean;\n /** Lines the visible item label wraps to before the ellipsis (default 1). Every tile reserves the same height. */\n itemLabelLines?: ImageChoiceItemLabelLines;\n items: readonly ImageChoiceItem[];\n disabled?: boolean;\n className?: string;\n /**\n * Long lists (hundreds of people): only the rows near the viewport are mounted. Tiles keep their size; the column\n * count follows the measured width.\n */\n virtualized?: ImageChoiceVirtualization;\n}>;\nexport type ImageChoiceGroupProps = Base & (\n | Readonly<{ selectionMode: \"single\"; value: string | null; onValueChange(value: string): void }>\n | Readonly<{ selectionMode: \"multiple\"; value: readonly string[]; onValueChange(value: string[]): void }>\n);\n\n/**\n * Picks avatars or photos by image (2026-10-16). Tiles are square, wrap to the available width, and show\n * a brand ring plus a check when chosen; assistive tech hears radios (single) or checkboxes (multiple).\n */\nexport function ImageChoiceGroup(props: ImageChoiceGroupProps) {\n const { label, showLabel = false, showItemLabels = false, itemLabelLines = imageChoiceRecipe.itemLabelLines, items, disabled = false, className, virtualized } = props;\n validateImageChoiceItems(items);\n validateImageChoiceItemLabelLines(itemLabelLines);\n const theme = useOptionalHjmTheme();\n const baseId = useId();\n const isSelected = (id: string) => props.selectionMode === \"single\" ? props.value === id : props.value.includes(id);\n const choose = (id: string) => {\n if (props.selectionMode === \"single\") props.onValueChange(resolveImageChoiceToggle(\"single\", props.value, id));\n else props.onValueChange(resolveImageChoiceToggle(\"multiple\", props.value, id));\n };\n const role = props.selectionMode === \"single\" ? \"radio\" : \"checkbox\";\n const groupRole = props.selectionMode === \"single\" ? \"radiogroup\" : \"group\";\n const captionLines = resolveImageChoiceCaptionLines({ showItemLabels, itemLabelLines, hasDescription: items.some(item => item.description !== undefined) });\n const style = { \"--hjm-image-choice-size\": `${imageChoiceRecipe.tileSize}px`, \"--hjm-image-choice-gap\": `${imageChoiceRecipe.gap}px`, \"--hjm-image-choice-radius\": `${imageChoiceRecipe.radius}px`, \"--hjm-image-choice-ring\": `${imageChoiceRecipe.ringWidth}px`, \"--hjm-image-choice-offset\": `${imageChoiceRecipe.ringOffset}px`, \"--hjm-image-choice-check\": `${imageChoiceRecipe.checkSize}px`, \"--hjm-image-choice-item-label-gap\": `${imageChoiceRecipe.itemLabelGap}px`, \"--hjm-image-choice-caption-lines\": captionLines, \"--hjm-image-choice-viewport-inset\": `${imageChoiceRecipe.virtualViewportInset}px` } as CSSProperties;\n const renderTile = (item: ImageChoiceItem, index: number) => {\n const selected = isSelected(item.id);\n const descriptionId = item.description === undefined ? undefined : `${baseId}-description-${index}`;\n return <button key={item.id} type=\"button\" role={role} aria-checked={selected} aria-label={item.label} aria-describedby={descriptionId} className=\"hjm-image-choice__tile\" data-selected={selected || undefined}\n disabled={disabled || item.disabled} onClick={() => choose(item.id)}>\n {/* The ring lives on an inner frame so an item label can sit below it inside the same button (one tap target). */}\n <span className=\"hjm-image-choice__ring\">\n <span className=\"hjm-image-choice__image\">{item.image}</span>\n {selected ? <span className=\"hjm-image-choice__check\" aria-hidden=\"true\">✓</span> : null}\n </span>\n {/* Every tile reserves the same caption block, so wrapped rows stay even and virtual rows share one height.\n aria-label already names the tile; the description is read once through aria-describedby. */}\n {captionLines > 0 ? <span className=\"hjm-image-choice__caption\">\n {showItemLabels ? <Text variant={imageChoiceRecipe.itemLabelVariant} className=\"hjm-image-choice__item-label\" aria-hidden=\"true\" data-lines={itemLabelLines === 1 ? undefined : itemLabelLines}>{item.label}</Text> : null}\n {item.description === undefined ? null : <Text id={descriptionId} variant={imageChoiceRecipe.itemDescriptionVariant} tone={imageChoiceRecipe.itemDescriptionTone} className=\"hjm-image-choice__item-description\" aria-hidden=\"true\">{item.description}</Text>}\n </span> : null}\n </button>;\n };\n // First-paint estimate in px; the rendered row is measured afterwards because caption line height is rem-based.\n const estimatedTileHeight = resolveImageChoiceTileHeight(captionLines, typography[imageChoiceRecipe.itemLabelVariant].lineHeight * (theme?.environment.textScale ?? 1));\n return <div className={[\"hjm-image-choice\", className].filter(Boolean).join(\" \")} style={style}>\n {showLabel ? <span className=\"hjm-image-choice__label\">{label}</span> : null}\n {virtualized\n ? <VirtualTileRows items={items} renderTile={renderTile} label={label} role={groupRole} height={virtualized.height} overscan={virtualized.overscan ?? virtualListRecipe.overscan} estimatedTileHeight={estimatedTileHeight} />\n : <div className=\"hjm-image-choice__tiles\" role={groupRole} aria-label={label}>{items.map(renderTile)}</div>}\n </div>;\n}\n\n/**\n * Windowed rows of tiles. It reuses the VirtualList window math (`resolveVirtualWindow`) but not the VirtualList\n * component: that one names its rows as list items and moves focus row by row, which would replace the radio/checkbox\n * group this control is. Tiles stay in the tab order; focusing one scrolls it into view and the window follows.\n */\nfunction VirtualTileRows({ items, renderTile, label, role, height, overscan, estimatedTileHeight }: Readonly<{\n items: readonly ImageChoiceItem[]; renderTile: (item: ImageChoiceItem, index: number) => ReactNode; label: string;\n role: \"radiogroup\" | \"group\"; height: number; overscan: number; estimatedTileHeight: number;\n}>) {\n const host = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n const [measuredTileHeight, setMeasuredTileHeight] = useState(0);\n const [scrollTop, setScrollTop] = useState(0);\n const [focusedRow, setFocusedRow] = useState<number | null>(null);\n useEffect(() => {\n if (!host.current) return;\n // Measure the slot itself (content box: inside the inset and the scrollbar); sheets and sidebars change it.\n const observer = new ResizeObserver(([entry]) => setWidth(entry?.contentRect.width ?? 0));\n observer.observe(host.current);\n return () => observer.disconnect();\n }, []);\n useLayoutEffect(() => {\n // Every row is one tile high (the caption block is reserved), so any mounted row gives the real stride.\n const rendered = host.current?.querySelector<HTMLElement>(\".hjm-image-choice__row\")?.offsetHeight ?? 0;\n if (rendered > 0 && rendered !== measuredTileHeight) setMeasuredTileHeight(rendered);\n });\n const columns = width > 0 ? Math.min(items.length, resolveImageChoiceColumns(width)) : 0;\n const stride = (measuredTileHeight || estimatedTileHeight) + imageChoiceRecipe.gap;\n const rowCount = columns ? Math.ceil(items.length / columns) : 0;\n const range = resolveVirtualWindow(rowCount, stride, height, scrollTop, overscan);\n // Keep the focused tile's row mounted when scrolling moves it out of the window, so focus is not dropped to body.\n const rows = Array.from({ length: range.end - range.start }, (_, i) => range.start + i);\n if (focusedRow !== null && focusedRow < rowCount && !rows.includes(focusedRow)) rows.push(focusedRow);\n rows.sort((first, second) => first - second); // DOM order is the tab order\n return <div ref={host} className=\"hjm-image-choice__viewport\" role={role} aria-label={label} style={{ height }}\n onScroll={event => setScrollTop(event.currentTarget.scrollTop)}>\n {columns ? <div style={{ position: \"relative\", height: Math.max(0, range.totalHeight - imageChoiceRecipe.gap) }}>\n {rows.map(row => <div key={row} className=\"hjm-image-choice__row\" style={{ top: row * stride, display: \"grid\", gridTemplateColumns: `repeat(${columns}, ${resolveImageChoiceOuterSize()}px)`, justifyContent: \"space-between\" }}\n onFocusCapture={() => setFocusedRow(row)} onBlurCapture={event => { if (!event.currentTarget.contains(event.relatedTarget)) setFocusedRow(current => current === row ? null : current); }}>\n {items.slice(row * columns, row * columns + columns).map((item, offset) => renderTile(item, row * columns + offset))}\n </div>)}\n </div> : null}\n </div>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"image-choice.js","sourceRoot":"","sources":["../src/image-choice.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { Text } from \"./layout.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport { typography } from \"@hjmds/design-contracts/foundations\";\nimport {\n imageChoiceRecipe, resolveImageChoiceCaptionLines, resolveImageChoiceColumns, resolveImageChoiceOuterSize, resolveImageChoiceTileHeight, resolveImageChoiceToggle,\n validateImageChoiceItemLabelLines, validateImageChoiceItems, type ImageChoiceItemDescriptor, type ImageChoiceItemLabelLines,\n} from \"@hjmds/design-contracts/components/image-choice\";\nimport { resolveVirtualWindow, virtualListRecipe } from \"@hjmds/design-contracts/components/virtual-list\";\n\nexport type ImageChoiceItem = ImageChoiceItemDescriptor & Readonly<{ image: ReactNode }>;\nexport type ImageChoiceVirtualization = Readonly<{\n /** Height of the scrolling viewport in px. The group scrolls itself, so do not also put it in a scrolling parent. */\n height: number;\n /** Rows kept mounted above and below the visible window. */\n overscan?: number;\n}>;\ntype Base = Readonly<{\n /** Localized group name read before the choices. */\n label: string;\n /** Visible caption above the tiles; omit when the screen heading already names the choice. */\n showLabel?: boolean;\n /**\n * Shows each item's `label` under its tile (one ellipsized line), e.g. a person's name in a recipient picker.\n * The tile keeps the same accessible name, so turning this on does not change what assistive tech reads.\n */\n showItemLabels?: boolean;\n /** Lines the visible item label wraps to before the ellipsis (default 1). Every tile reserves the same height. */\n itemLabelLines?: ImageChoiceItemLabelLines;\n items: readonly ImageChoiceItem[];\n disabled?: boolean;\n className?: string;\n /**\n * Long lists (hundreds of people): only the rows near the viewport are mounted. Tiles keep their size; the column\n * count follows the measured width.\n */\n virtualized?: ImageChoiceVirtualization;\n}>;\nexport type ImageChoiceGroupProps = Base & (\n | Readonly<{ selectionMode: \"single\"; value: string | null; onValueChange(value: string): void }>\n | Readonly<{ selectionMode: \"multiple\"; value: readonly string[]; onValueChange(value: string[]): void }>\n);\n\n/**\n * Picks avatars or photos by image (2026-10-16). Tiles are square, wrap to the available width, and show\n * a brand ring plus a check when chosen; assistive tech hears radios (single) or checkboxes (multiple).\n */\nexport function ImageChoiceGroup(props: ImageChoiceGroupProps) {\n const { label, showLabel = false, showItemLabels = false, itemLabelLines = imageChoiceRecipe.itemLabelLines, items, disabled = false, className, virtualized } = props;\n validateImageChoiceItems(items);\n validateImageChoiceItemLabelLines(itemLabelLines);\n const theme = useOptionalHjmTheme();\n const baseId = useId();\n const isSelected = (id: string) => props.selectionMode === \"single\" ? props.value === id : props.value.includes(id);\n const choose = (id: string) => {\n if (props.selectionMode === \"single\") props.onValueChange(resolveImageChoiceToggle(\"single\", props.value, id));\n else props.onValueChange(resolveImageChoiceToggle(\"multiple\", props.value, id));\n };\n const role = props.selectionMode === \"single\" ? \"radio\" : \"checkbox\";\n const groupRole = props.selectionMode === \"single\" ? \"radiogroup\" : \"group\";\n const captionLines = resolveImageChoiceCaptionLines({ showItemLabels, itemLabelLines, hasDescription: items.some(item => item.description !== undefined) });\n const style = { \"--hjm-image-choice-size\": `${imageChoiceRecipe.tileSize}px`, \"--hjm-image-choice-gap\": `${imageChoiceRecipe.gap}px`, \"--hjm-image-choice-radius\": `${imageChoiceRecipe.radius}px`, \"--hjm-image-choice-ring\": `${imageChoiceRecipe.ringWidth}px`, \"--hjm-image-choice-offset\": `${imageChoiceRecipe.ringOffset}px`, \"--hjm-image-choice-check\": `${imageChoiceRecipe.checkSize}px`, \"--hjm-image-choice-item-label-gap\": `${imageChoiceRecipe.itemLabelGap}px`, \"--hjm-image-choice-caption-lines\": captionLines, \"--hjm-image-choice-viewport-inset\": `${imageChoiceRecipe.virtualViewportInset}px` } as CSSProperties;\n const renderTile = (item: ImageChoiceItem, index: number) => {\n const selected = isSelected(item.id);\n const descriptionId = item.description === undefined ? undefined : `${baseId}-description-${index}`;\n return <button key={item.id} type=\"button\" role={role} aria-checked={selected} aria-label={item.label} aria-describedby={descriptionId} className=\"hjm-image-choice__tile\" data-selected={selected || undefined}\n disabled={disabled || item.disabled} onClick={() => choose(item.id)}>\n {/* The ring lives on an inner frame so an item label can sit below it inside the same button (one tap target). */}\n <span className=\"hjm-image-choice__ring\">\n <span className=\"hjm-image-choice__image\">{item.image}</span>\n {selected ? <span className=\"hjm-image-choice__check\" aria-hidden=\"true\">✓</span> : null}\n </span>\n {/* Every tile reserves the same caption block, so wrapped rows stay even and virtual rows share one height.\n aria-label already names the tile; the description is read once through aria-describedby. */}\n {captionLines > 0 ? <span className=\"hjm-image-choice__caption\">\n {showItemLabels ? <Text variant={imageChoiceRecipe.itemLabelVariant} className=\"hjm-image-choice__item-label\" aria-hidden=\"true\" data-lines={itemLabelLines === 1 ? undefined : itemLabelLines}>{item.label}</Text> : null}\n {item.description === undefined ? null : <Text id={descriptionId} variant={imageChoiceRecipe.itemDescriptionVariant} tone={imageChoiceRecipe.itemDescriptionTone} className=\"hjm-image-choice__item-description\" aria-hidden=\"true\">{item.description}</Text>}\n </span> : null}\n </button>;\n };\n // First-paint estimate in px; the rendered row is measured afterwards because caption line height is rem-based.\n const estimatedTileHeight = resolveImageChoiceTileHeight(captionLines, typography[imageChoiceRecipe.itemLabelVariant].lineHeight * (theme?.environment.textScale ?? 1));\n return <div className={[\"hjm-image-choice\", className].filter(Boolean).join(\" \")} style={style}>\n {showLabel ? <span className=\"hjm-image-choice__label\">{label}</span> : null}\n {virtualized\n ? <VirtualTileRows items={items} renderTile={renderTile} label={label} role={groupRole} height={virtualized.height} overscan={virtualized.overscan ?? virtualListRecipe.overscan} estimatedTileHeight={estimatedTileHeight} />\n : <div className=\"hjm-image-choice__tiles\" role={groupRole} aria-label={label}>{items.map(renderTile)}</div>}\n </div>;\n}\n\n/**\n * Windowed rows of tiles. It reuses the VirtualList window math (`resolveVirtualWindow`) but not the VirtualList\n * component: that one names its rows as list items and moves focus row by row, which would replace the radio/checkbox\n * group this control is. Tiles stay in the tab order; focusing one scrolls it into view and the window follows.\n */\nfunction VirtualTileRows({ items, renderTile, label, role, height, overscan, estimatedTileHeight }: Readonly<{\n items: readonly ImageChoiceItem[]; renderTile: (item: ImageChoiceItem, index: number) => ReactNode; label: string;\n role: \"radiogroup\" | \"group\"; height: number; overscan: number; estimatedTileHeight: number;\n}>) {\n const host = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n const [measuredTileHeight, setMeasuredTileHeight] = useState(0);\n const [scrollTop, setScrollTop] = useState(0);\n const [focusedRow, setFocusedRow] = useState<number | null>(null);\n useEffect(() => {\n if (!host.current) return;\n // Measure the slot itself (content box: inside the inset and the scrollbar); sheets and sidebars change it.\n const observer = new ResizeObserver(([entry]) => setWidth(entry?.contentRect.width ?? 0));\n observer.observe(host.current);\n return () => observer.disconnect();\n }, []);\n useLayoutEffect(() => {\n // Every row is one tile high (the caption block is reserved), so any mounted row gives the real stride.\n const rendered = host.current?.querySelector<HTMLElement>(\".hjm-image-choice__row\")?.offsetHeight ?? 0;\n if (rendered > 0 && rendered !== measuredTileHeight) setMeasuredTileHeight(rendered);\n });\n // Preserve empty columns so a short list fills the same slots as a full row (Diairy, 2026-10-27).\n const columns = width > 0 ? resolveImageChoiceColumns(width) : 0;\n const stride = (measuredTileHeight || estimatedTileHeight) + imageChoiceRecipe.gap;\n const rowCount = columns ? Math.ceil(items.length / columns) : 0;\n const range = resolveVirtualWindow(rowCount, stride, height, scrollTop, overscan);\n // Keep the focused tile's row mounted when scrolling moves it out of the window, so focus is not dropped to body.\n const rows = Array.from({ length: range.end - range.start }, (_, i) => range.start + i);\n if (focusedRow !== null && focusedRow < rowCount && !rows.includes(focusedRow)) rows.push(focusedRow);\n rows.sort((first, second) => first - second); // DOM order is the tab order\n return <div ref={host} className=\"hjm-image-choice__viewport\" role={role} aria-label={label} style={{ height }}\n onScroll={event => setScrollTop(event.currentTarget.scrollTop)}>\n {columns ? <div style={{ position: \"relative\", height: Math.max(0, range.totalHeight - imageChoiceRecipe.gap) }}>\n {rows.map(row => <div key={row} className=\"hjm-image-choice__row\" style={{ top: row * stride, display: \"grid\", gridTemplateColumns: `repeat(${columns}, ${resolveImageChoiceOuterSize()}px)`, justifyContent: \"space-between\" }}\n onFocusCapture={() => setFocusedRow(row)} onBlurCapture={event => { if (!event.currentTarget.contains(event.relatedTarget)) setFocusedRow(current => current === row ? null : current); }}>\n {items.slice(row * columns, row * columns + columns).map((item, offset) => renderTile(item, row * columns + offset))}\n </div>)}\n </div> : null}\n </div>;\n}\n"]}
|
package/dist/overlays.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../src/overlays.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../src/overlays.tsx"],"names":[],"mappings":"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"}
|
package/dist/overlays.js
CHANGED
|
@@ -202,7 +202,7 @@ export const Sheet = forwardRef(function Sheet({ trigger, title, description, ch
|
|
|
202
202
|
});
|
|
203
203
|
const policy = resolveSheetDismissPolicy(placement, dismissPolicy);
|
|
204
204
|
const closeVisible = resolveSheetCloseButton(placement, showClose);
|
|
205
|
-
// Drag-to-dismiss (2026-10-16 user decision):
|
|
205
|
+
// Drag-to-dismiss (2026-10-16 user decision; body touch pull-downs joined 2026-10-27): the sheet follows the pointer downward and a
|
|
206
206
|
// release past the distance or velocity threshold closes with reason "swipe".
|
|
207
207
|
const showHandle = (placement === "bottom" || swipeDirection === "down") && policy.dismissible && policy.swipeDismiss;
|
|
208
208
|
const closeBlocked = busy && !policy.dismissWhileBusy;
|
|
@@ -225,6 +225,84 @@ export const Sheet = forwardRef(function Sheet({ trigger, title, description, ch
|
|
|
225
225
|
suppressDragClick.current = false;
|
|
226
226
|
setDragY(0);
|
|
227
227
|
}, [open, canSwipe]);
|
|
228
|
+
// State, not a ref: the portal mounts the body after this component's first commit.
|
|
229
|
+
const [bodyElement, setBodyElement] = useState(null);
|
|
230
|
+
const requestCloseRef = useRef(() => undefined);
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
// Body drag-to-dismiss (2026-10-27 user decision): a touch pull-down on the body closes like the handle,
|
|
233
|
+
// but only while the body, and any scroller between the finger and it, is already at the top. Otherwise
|
|
234
|
+
// the same pull scrolls the content back first. Touch only: a mouse keeps text selection and uses the handle.
|
|
235
|
+
// Native listeners because React's touch handlers are passive and cannot stop the browser's own pan.
|
|
236
|
+
const body = bodyElement;
|
|
237
|
+
if (!open || !canSwipe || !body)
|
|
238
|
+
return undefined;
|
|
239
|
+
let drag = null;
|
|
240
|
+
const atTop = (target) => {
|
|
241
|
+
for (let node = target instanceof Element ? target : null; node && body.contains(node); node = node.parentElement) {
|
|
242
|
+
if (node.scrollTop > 0)
|
|
243
|
+
return false;
|
|
244
|
+
if (node === body)
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
return body.scrollTop <= 0;
|
|
248
|
+
};
|
|
249
|
+
const onStart = (event) => {
|
|
250
|
+
const touch = event.touches[0];
|
|
251
|
+
const editable = event.target instanceof Element && event.target.closest("input,textarea,select,[contenteditable]:not([contenteditable='false'])");
|
|
252
|
+
drag = event.touches.length !== 1 || !touch || editable || !atTop(event.target)
|
|
253
|
+
? null
|
|
254
|
+
: { x: touch.clientX, y: touch.clientY, t: event.timeStamp, state: "pending" };
|
|
255
|
+
};
|
|
256
|
+
const onMove = (event) => {
|
|
257
|
+
const touch = event.touches[0];
|
|
258
|
+
if (!drag || !touch || drag.state === "rejected")
|
|
259
|
+
return;
|
|
260
|
+
const dy = touch.clientY - drag.y;
|
|
261
|
+
const dx = Math.abs(touch.clientX - drag.x);
|
|
262
|
+
if (drag.state === "pending") {
|
|
263
|
+
// Upward or sideways movement belongs to scrolling, rails and swipe rows inside the body.
|
|
264
|
+
if (dy < 0 || dx > dy) {
|
|
265
|
+
if (dy < 0 || dx > sheetDragRecipe.activationDistance)
|
|
266
|
+
drag.state = "rejected";
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
// Hold the browser's pan from the first downward move so the pull is still cancelable once it activates.
|
|
270
|
+
if (event.cancelable)
|
|
271
|
+
event.preventDefault();
|
|
272
|
+
if (dy < sheetDragRecipe.activationDistance)
|
|
273
|
+
return;
|
|
274
|
+
drag.state = "dragging";
|
|
275
|
+
}
|
|
276
|
+
if (event.cancelable)
|
|
277
|
+
event.preventDefault();
|
|
278
|
+
setDragY(Math.max(0, dy));
|
|
279
|
+
};
|
|
280
|
+
const onEnd = (event) => {
|
|
281
|
+
const current = drag;
|
|
282
|
+
drag = null;
|
|
283
|
+
if (current?.state !== "dragging")
|
|
284
|
+
return;
|
|
285
|
+
setDragY(0);
|
|
286
|
+
const touch = event.changedTouches[0];
|
|
287
|
+
if (event.type === "touchcancel" || !touch)
|
|
288
|
+
return;
|
|
289
|
+
const dy = touch.clientY - current.y;
|
|
290
|
+
const velocity = dy / Math.max(1, event.timeStamp - current.t);
|
|
291
|
+
const height = contentRef.current?.getBoundingClientRect().height ?? 0;
|
|
292
|
+
if (dy > height * sheetDragRecipe.dismissDistanceRatio || velocity > sheetDragRecipe.dismissVelocity)
|
|
293
|
+
requestCloseRef.current("swipe");
|
|
294
|
+
};
|
|
295
|
+
body.addEventListener("touchstart", onStart, { passive: true });
|
|
296
|
+
body.addEventListener("touchmove", onMove, { passive: false });
|
|
297
|
+
body.addEventListener("touchend", onEnd);
|
|
298
|
+
body.addEventListener("touchcancel", onEnd);
|
|
299
|
+
return () => {
|
|
300
|
+
body.removeEventListener("touchstart", onStart);
|
|
301
|
+
body.removeEventListener("touchmove", onMove);
|
|
302
|
+
body.removeEventListener("touchend", onEnd);
|
|
303
|
+
body.removeEventListener("touchcancel", onEnd);
|
|
304
|
+
};
|
|
305
|
+
}, [open, canSwipe, bodyElement]);
|
|
228
306
|
const lifecycleRef = useRef(createSheetLifecycle(open));
|
|
229
307
|
const previousOpenRef = useRef(open);
|
|
230
308
|
const currentOpenRef = useRef(open);
|
|
@@ -261,6 +339,7 @@ export const Sheet = forwardRef(function Sheet({ trigger, title, description, ch
|
|
|
261
339
|
});
|
|
262
340
|
}
|
|
263
341
|
};
|
|
342
|
+
requestCloseRef.current = requestClose;
|
|
264
343
|
useEffect(() => {
|
|
265
344
|
if (open) {
|
|
266
345
|
lifecycleRef.current.open();
|
|
@@ -355,7 +434,7 @@ export const Sheet = forwardRef(function Sheet({ trigger, title, description, ch
|
|
|
355
434
|
onDetentChange?.(next);
|
|
356
435
|
}, children: _jsx("span", { "aria-hidden": "true", className: "hjm-sheet__handle-bar" }) }) })) : showHandle ? (
|
|
357
436
|
// Keep one close command: an explicit × owns it; otherwise the handle supports keyboard and switch users.
|
|
358
|
-
_jsx("div", { className: "hjm-sheet__handle-row", children: closeVisible ? (_jsx("div", { className: "hjm-sheet__handle", "aria-hidden": "true", children: _jsx("span", { className: "hjm-sheet__handle-bar" }) })) : (_jsx("button", { type: "button", className: "hjm-sheet__handle", "aria-label": closeLabel, disabled: closeBlocked, onClick: () => requestClose("close-action"), children: _jsx("span", { "aria-hidden": "true", className: "hjm-sheet__handle-bar" }) })) })) : null, description || (policy.dismissible && closeVisible) ? _jsxs("header", { className: "hjm-sheet__header", children: [description ? _jsx("div", { children: _jsx("p", { id: descriptionId, className: "hjm-sheet__description", children: description }) }) : null, policy.dismissible && closeVisible ? (_jsx("button", { type: "button", className: "hjm-dialog__close", "aria-label": closeLabel, disabled: busy && !policy.dismissWhileBusy, onClick: () => requestClose("close-action"), children: "\u00D7" })) : null] }) : null] }), children ? _jsx("div", { className: "hjm-sheet__body", children: _jsx(ScreenFooterContext.Provider, { value: null, children: _jsx(InitialFocusProvider, { scope: focusScope, children: children }) }) }) : null, footer ? _jsx("footer", { className: "hjm-sheet__footer", children: _jsx(ScreenFooterContext.Provider, { value: { bottomPadding: placement === "bottom" ? "calc(var(--hjm-space-sm) + env(safe-area-inset-bottom, 0px))" : "var(--hjm-space-sm)" }, children: _jsx(InitialFocusProvider, { scope: focusScope, children: footer }) }) }) : null] }) }) })) : null] }));
|
|
437
|
+
_jsx("div", { className: "hjm-sheet__handle-row", children: closeVisible ? (_jsx("div", { className: "hjm-sheet__handle", "aria-hidden": "true", children: _jsx("span", { className: "hjm-sheet__handle-bar" }) })) : (_jsx("button", { type: "button", className: "hjm-sheet__handle", "aria-label": closeLabel, disabled: closeBlocked, onClick: () => requestClose("close-action"), children: _jsx("span", { "aria-hidden": "true", className: "hjm-sheet__handle-bar" }) })) })) : null, description || (policy.dismissible && closeVisible) ? _jsxs("header", { className: "hjm-sheet__header", children: [description ? _jsx("div", { children: _jsx("p", { id: descriptionId, className: "hjm-sheet__description", children: description }) }) : null, policy.dismissible && closeVisible ? (_jsx("button", { type: "button", className: "hjm-dialog__close", "aria-label": closeLabel, disabled: busy && !policy.dismissWhileBusy, onClick: () => requestClose("close-action"), children: "\u00D7" })) : null] }) : null] }), children ? _jsx("div", { ref: setBodyElement, className: "hjm-sheet__body", children: _jsx(ScreenFooterContext.Provider, { value: null, children: _jsx(InitialFocusProvider, { scope: focusScope, children: children }) }) }) : null, footer ? _jsx("footer", { className: "hjm-sheet__footer", children: _jsx(ScreenFooterContext.Provider, { value: { bottomPadding: placement === "bottom" ? "calc(var(--hjm-space-sm) + env(safe-area-inset-bottom, 0px))" : "var(--hjm-space-sm)" }, children: _jsx(InitialFocusProvider, { scope: focusScope, children: footer }) }) }) : null] }) }) })) : null] }));
|
|
359
438
|
});
|
|
360
439
|
export const Tooltip = forwardRef(function Tooltip({ trigger, content, placement, align, pointerOpenDelayMs = tooltipBehaviorDefaults.pointerOpenDelayMs, focusOpenDelayMs = tooltipBehaviorDefaults.focusOpenDelayMs, portalContainer, open: openProp, defaultOpen, onOpenChange, className, layoutStyle, }, ref) {
|
|
361
440
|
const descriptor = resolveTooltipDescriptor({
|