@hjmds/react 1.8.0 → 1.10.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 (65) hide show
  1. package/README.md +4 -0
  2. package/THIRD_PARTY_NOTICES.md +29 -0
  3. package/dist/affix.d.ts +10 -0
  4. package/dist/affix.d.ts.map +1 -0
  5. package/dist/affix.js +51 -0
  6. package/dist/affix.js.map +1 -0
  7. package/dist/carousel-motion.d.ts +13 -0
  8. package/dist/carousel-motion.d.ts.map +1 -0
  9. package/dist/carousel-motion.js +35 -0
  10. package/dist/carousel-motion.js.map +1 -0
  11. package/dist/celebration.d.ts +8 -0
  12. package/dist/celebration.d.ts.map +1 -0
  13. package/dist/celebration.js +51 -0
  14. package/dist/celebration.js.map +1 -0
  15. package/dist/color-picker.d.ts +18 -0
  16. package/dist/color-picker.d.ts.map +1 -0
  17. package/dist/color-picker.js +40 -0
  18. package/dist/color-picker.js.map +1 -0
  19. package/dist/content-transition.d.ts +18 -0
  20. package/dist/content-transition.d.ts.map +1 -0
  21. package/dist/content-transition.js +33 -0
  22. package/dist/content-transition.js.map +1 -0
  23. package/dist/date-picker.d.ts.map +1 -1
  24. package/dist/date-picker.js +39 -1
  25. package/dist/date-picker.js.map +1 -1
  26. package/dist/evidence.d.ts +46 -1
  27. package/dist/evidence.d.ts.map +1 -1
  28. package/dist/evidence.js +5 -2
  29. package/dist/evidence.js.map +1 -1
  30. package/dist/menu-morph.d.ts.map +1 -1
  31. package/dist/menu-morph.js +2 -1
  32. package/dist/menu-morph.js.map +1 -1
  33. package/dist/menubar.d.ts.map +1 -1
  34. package/dist/menubar.js +24 -15
  35. package/dist/menubar.js.map +1 -1
  36. package/dist/modal.d.ts +1 -0
  37. package/dist/modal.d.ts.map +1 -1
  38. package/dist/modal.js.map +1 -1
  39. package/dist/overlays.d.ts.map +1 -1
  40. package/dist/overlays.js +33 -2
  41. package/dist/overlays.js.map +1 -1
  42. package/dist/sortable.d.ts +14 -0
  43. package/dist/sortable.d.ts.map +1 -0
  44. package/dist/sortable.js +87 -0
  45. package/dist/sortable.js.map +1 -0
  46. package/dist/styles.css +47 -13
  47. package/dist/styles.layered.css +47 -13
  48. package/dist/swipe-actions.d.ts +13 -0
  49. package/dist/swipe-actions.d.ts.map +1 -0
  50. package/dist/swipe-actions.js +25 -0
  51. package/dist/swipe-actions.js.map +1 -0
  52. package/dist/theme.d.ts.map +1 -1
  53. package/dist/theme.js +9 -0
  54. package/dist/theme.js.map +1 -1
  55. package/dist/toast.d.ts.map +1 -1
  56. package/dist/toast.js +12 -7
  57. package/dist/toast.js.map +1 -1
  58. package/dist/tree.d.ts.map +1 -1
  59. package/dist/tree.js +14 -3
  60. package/dist/tree.js.map +1 -1
  61. package/dist/watermark.d.ts +12 -0
  62. package/dist/watermark.d.ts.map +1 -0
  63. package/dist/watermark.js +10 -0
  64. package/dist/watermark.js.map +1 -0
  65. package/package.json +65 -4
package/dist/tree.js CHANGED
@@ -107,14 +107,25 @@ export const Tree = forwardRef(function Tree({ label, nodes, composeAccessibleNa
107
107
  return (_jsxs("div", { ref: composeRefs(rootRef, forwardedRef), role: "tree", "aria-label": label, "aria-busy": asyncState.status === "loading" || asyncState.status === "loadingMore" || undefined, "aria-multiselectable": selection?.mode === "multiple" || undefined, className: classNames("hjm-tree", className), style: { "--hjm-tree-indent": `${treeRecipe.indentPerLevel}px` }, children: [asyncState.status === "empty" || asyncState.status === "error" || asyncState.status === "loading" ? (_jsx("p", { className: "hjm-tree__state", role: asyncState.status === "error" ? "alert" : "status", children: asyncState.message })) : null, visible.map((node) => (_jsxs("div", { role: "treeitem", "data-hjm-tree-node": node.id, "aria-level": node.depth, "aria-posinset": node.position, "aria-setsize": node.siblingCount, "aria-expanded": node.hasChildren ? node.expanded : undefined, "aria-selected": selection && selection.mode !== "none" ? selected.has(node.id) : undefined, "aria-checked": checkedStates ? (checkedStates.get(node.id) === "mixed" ? "mixed" : String(checkedStates.get(node.id) === true)) : undefined, "aria-disabled": node.disabled || undefined, "aria-label": node.accessibleName,
108
108
  // One tab stop for the whole tree; the glyph is decorative, not a
109
109
  // nested control, so a node is the only focusable thing in a row.
110
- tabIndex: node.id === activeId ? 0 : -1, className: "hjm-tree__node", style: { "--hjm-tree-depth": node.depth - 1 }, onClick: () => {
110
+ tabIndex: node.id === activeId ? 0 : -1, className: "hjm-tree__node", style: { "--hjm-tree-depth": node.depth - 1 }, onClick: (event) => {
111
111
  setFocusedId(node.id);
112
+ // Pointer users had no way to expand: only arrow keys toggled (2026-09-30
113
+ // audit WR-0930-2). The contract lets a row click change expansion; the
114
+ // glyph toggles only, and in check mode the row click stays the check.
115
+ const onGlyph = node.hasChildren &&
116
+ event.target.closest?.(".hjm-tree__toggle") !== null;
117
+ if (onGlyph) {
118
+ setExpanded(node.id, !node.expanded);
119
+ return;
120
+ }
112
121
  if (checkedStates && onCheckedToggle) {
113
122
  if (!node.disabled)
114
123
  onCheckedToggle(node.id);
124
+ return;
115
125
  }
116
- else
117
- toggleSelection(node);
126
+ if (node.hasChildren)
127
+ setExpanded(node.id, !node.expanded);
128
+ toggleSelection(node);
118
129
  }, onFocus: () => setFocusedId(node.id), onKeyDown: (event) => onKeyDown(event, node), children: [_jsx("span", { "aria-hidden": "true", className: "hjm-tree__indent" }), checkedStates ? (_jsx("span", { "aria-hidden": "true", className: "hjm-tree__check", "data-state": String(checkedStates.get(node.id) ?? false), children: checkedStates.get(node.id) === true ? "✓" : checkedStates.get(node.id) === "mixed" ? "–" : "" })) : null, _jsx("span", { "aria-hidden": "true", className: "hjm-tree__toggle", "data-visible": node.hasChildren || undefined, children: node.hasChildren ? renderToggle?.({ expanded: node.expanded }) ?? (node.expanded ? "▾" : "▸") : null }), _jsxs("span", { "aria-hidden": "true", className: "hjm-tree__label", children: [node.label, node.description ? _jsx("span", { className: "hjm-tree__description", children: node.description }) : null] })] }, node.id))), asyncState.status === "loadingMore" ? _jsx("p", { className: "hjm-tree__state", role: "status", children: asyncState.message }) : null] }));
119
130
  });
120
131
  //# sourceMappingURL=tree.js.map
package/dist/tree.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tree.js","sourceRoot":"","sources":["../src/tree.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n getTreeArrowKeyIntent,\n getTreeArrowResult,\n getVisibleTreeNavigationTarget,\n getVisibleTreeTypeaheadMatch,\n reconcileTreeExpansion,\n resolveTreeDescriptor,\n treeRecipe,\n type ComposeTreeAccessibleName,\n type ResolvedTreeNodeDescriptor,\n type TreeAsyncState,\n type TreeNodeDescriptor,\n type TreeSelectionModel,\n} from \"@hjmds/design-contracts/components/tree\";\nimport type { CheckboxState, WebKeyboardKey } from \"@hjmds/design-contracts/behaviors\";\nimport {\n forwardRef,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { classNames, composeRefs, useControllableState } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\n\nexport type TreeProps<Id extends string = string> = Readonly<{\n label: string;\n nodes: readonly TreeNodeDescriptor<Id>[];\n composeAccessibleName: ComposeTreeAccessibleName;\n expandedKeys?: ReadonlySet<Id>;\n defaultExpandedKeys?: ReadonlySet<Id>;\n onExpandedKeysChange?: (keys: ReadonlySet<Id>) => void;\n selection?: TreeSelectionModel<Id>;\n /**\n * Tri-state check marks per node, as `resolveTreeCheckedStates` derives them.\n * Checkboxes are not nested controls in a tree: the state rides on the node\n * itself as `aria-checked`, keeping the contract's one-tab-stop-per-node rule.\n */\n checkedStates?: ReadonlyMap<Id, CheckboxState>;\n onCheckedToggle?: (id: Id) => void;\n asyncState?: TreeAsyncState;\n /** Product-owned glyph for the expand/collapse affordance; decorative by contract. */\n renderToggle?: (state: Readonly<{ expanded: boolean }>) => ReactNode;\n className?: string;\n}>;\n\nconst typeaheadResetMs = 500;\n\nfunction selectedIds<Id extends string>(selection: TreeSelectionModel<Id> | undefined): ReadonlySet<Id> {\n if (!selection || selection.mode === \"none\") return new Set<Id>();\n if (selection.mode === \"single\") {\n const key = selection.selectedKey ?? selection.defaultSelectedKey ?? null;\n return key === null ? new Set<Id>() : new Set<Id>([key]);\n }\n return selection.selectedKeys ?? selection.defaultSelectedKeys ?? new Set<Id>();\n}\n\nexport const Tree = forwardRef(function Tree<Id extends string = string>(\n {\n label,\n nodes,\n composeAccessibleName,\n expandedKeys: controlledExpanded,\n defaultExpandedKeys,\n onExpandedKeysChange,\n selection,\n checkedStates,\n onCheckedToggle,\n asyncState = { status: \"idle\" },\n renderToggle,\n className,\n }: TreeProps<Id>,\n forwardedRef: React.Ref<HTMLDivElement>,\n) {\n const [expandedKeys, setExpandedKeys] = useControllableState<ReadonlySet<Id>>({\n ...(controlledExpanded === undefined ? {} : { value: controlledExpanded }),\n defaultValue: defaultExpandedKeys ?? new Set<Id>(),\n ...(onExpandedKeysChange === undefined ? {} : { onChange: onExpandedKeysChange }),\n });\n const direction = useOptionalHjmTheme()?.environment.direction ?? \"ltr\";\n // Expansion keys survive a node list change only where the node still exists\n // and can still hold children; the contract owns that reconciliation.\n const liveExpanded = useMemo(() => reconcileTreeExpansion(nodes, expandedKeys), [nodes, expandedKeys]);\n const resolved = useMemo(\n () => resolveTreeDescriptor(nodes, liveExpanded, { composeAccessibleName }),\n [nodes, liveExpanded, composeAccessibleName],\n );\n const visible = useMemo(() => resolved.filter((node) => node.visible), [resolved]);\n const selected = selectedIds(selection);\n const [focusedId, setFocusedId] = useState<Id | null>(null);\n // Roving tab stop: one node is tabbable, and it must stay a real visible node\n // after a collapse removed the previously focused descendant.\n const activeId = visible.some((node) => node.id === focusedId) ? focusedId : visible[0]?.id ?? null;\n const rootRef = useRef<HTMLDivElement>(null);\n const typeahead = useRef<Readonly<{ query: string; at: number }>>({ query: \"\", at: 0 });\n\n const focusNode = (id: Id) => {\n setFocusedId(id);\n rootRef.current?.querySelector<HTMLElement>(`[data-hjm-tree-node=\"${CSS.escape(id)}\"]`)?.focus();\n };\n const setExpanded = (id: Id, expanded: boolean) => {\n const next = new Set(liveExpanded);\n if (expanded) next.add(id); else next.delete(id);\n setExpandedKeys(next);\n };\n const toggleSelection = (node: ResolvedTreeNodeDescriptor<Id>) => {\n if (node.disabled || !selection || selection.mode === \"none\") return;\n if (selection.mode === \"single\") {\n const current = selection.selectedKey ?? selection.defaultSelectedKey ?? null;\n const next = current === node.id && selection.disallowEmptySelection !== true ? null : node.id;\n selection.onSelectionChange?.(next);\n return;\n }\n const next = new Set(selection.selectedKeys ?? selection.defaultSelectedKeys ?? []);\n if (next.has(node.id)) next.delete(node.id); else next.add(node.id);\n selection.onSelectionChange?.(next);\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>, node: ResolvedTreeNodeDescriptor<Id>) => {\n const key = event.key as WebKeyboardKey;\n const arrow = getTreeArrowKeyIntent(key, direction);\n if (arrow) {\n const result = getTreeArrowResult(visible, node.id, arrow);\n if (result.action === \"none\") return;\n event.preventDefault();\n if (result.action === \"moveFocus\") focusNode(result.targetId);\n else setExpanded(node.id, result.action === \"expand\");\n return;\n }\n if (key === \"ArrowDown\" || key === \"ArrowUp\" || key === \"Home\" || key === \"End\") {\n const intent = key === \"ArrowDown\" ? \"next\" : key === \"ArrowUp\" ? \"previous\" : key === \"Home\" ? \"first\" : \"last\";\n const target = getVisibleTreeNavigationTarget(visible, node.id, intent);\n if (target === undefined) return;\n event.preventDefault();\n focusNode(target);\n return;\n }\n if (key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n if (checkedStates && onCheckedToggle) { if (!node.disabled) onCheckedToggle(node.id); }\n else toggleSelection(node);\n return;\n }\n if (event.key.length !== 1 || event.metaKey || event.ctrlKey || event.altKey) return;\n const now = Date.now();\n const query = now - typeahead.current.at > typeaheadResetMs ? event.key : typeahead.current.query + event.key;\n typeahead.current = { query, at: now };\n const match = getVisibleTreeTypeaheadMatch(visible, query, { startsAfterKey: node.id });\n if (match !== undefined) { event.preventDefault(); focusNode(match); }\n };\n\n return (\n <div\n ref={composeRefs(rootRef, forwardedRef)}\n role=\"tree\"\n aria-label={label}\n aria-busy={asyncState.status === \"loading\" || asyncState.status === \"loadingMore\" || undefined}\n aria-multiselectable={selection?.mode === \"multiple\" || undefined}\n className={classNames(\"hjm-tree\", className)}\n style={{ \"--hjm-tree-indent\": `${treeRecipe.indentPerLevel}px` } as CSSProperties}\n >\n {asyncState.status === \"empty\" || asyncState.status === \"error\" || asyncState.status === \"loading\" ? (\n <p className=\"hjm-tree__state\" role={asyncState.status === \"error\" ? \"alert\" : \"status\"}>{asyncState.message}</p>\n ) : null}\n {visible.map((node) => (\n <div\n key={node.id}\n role=\"treeitem\"\n data-hjm-tree-node={node.id}\n aria-level={node.depth}\n aria-posinset={node.position}\n aria-setsize={node.siblingCount}\n aria-expanded={node.hasChildren ? node.expanded : undefined}\n aria-selected={selection && selection.mode !== \"none\" ? selected.has(node.id) : undefined}\n aria-checked={checkedStates ? (checkedStates.get(node.id) === \"mixed\" ? \"mixed\" : String(checkedStates.get(node.id) === true)) as \"true\" | \"false\" | \"mixed\" : undefined}\n aria-disabled={node.disabled || undefined}\n aria-label={node.accessibleName}\n // One tab stop for the whole tree; the glyph is decorative, not a\n // nested control, so a node is the only focusable thing in a row.\n tabIndex={node.id === activeId ? 0 : -1}\n className=\"hjm-tree__node\"\n style={{ \"--hjm-tree-depth\": node.depth - 1 } as CSSProperties}\n onClick={() => {\n setFocusedId(node.id);\n if (checkedStates && onCheckedToggle) { if (!node.disabled) onCheckedToggle(node.id); }\n else toggleSelection(node);\n }}\n onFocus={() => setFocusedId(node.id)}\n onKeyDown={(event) => onKeyDown(event, node)}\n >\n <span aria-hidden=\"true\" className=\"hjm-tree__indent\" />\n {checkedStates ? (\n <span aria-hidden=\"true\" className=\"hjm-tree__check\" data-state={String(checkedStates.get(node.id) ?? false)}>\n {checkedStates.get(node.id) === true ? \"✓\" : checkedStates.get(node.id) === \"mixed\" ? \"–\" : \"\"}\n </span>\n ) : null}\n <span aria-hidden=\"true\" className=\"hjm-tree__toggle\" data-visible={node.hasChildren || undefined}>\n {node.hasChildren ? renderToggle?.({ expanded: node.expanded }) ?? (node.expanded ? \"▾\" : \"▸\") : null}\n </span>\n <span aria-hidden=\"true\" className=\"hjm-tree__label\">\n {node.label}\n {node.description ? <span className=\"hjm-tree__description\">{node.description}</span> : null}\n </span>\n </div>\n ))}\n {asyncState.status === \"loadingMore\" ? <p className=\"hjm-tree__state\" role=\"status\">{asyncState.message}</p> : null}\n </div>\n );\n}) as <Id extends string = string>(\n props: TreeProps<Id> & { ref?: React.Ref<HTMLDivElement> },\n) => React.ReactElement | null;\n"]}
1
+ {"version":3,"file":"tree.js","sourceRoot":"","sources":["../src/tree.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n getTreeArrowKeyIntent,\n getTreeArrowResult,\n getVisibleTreeNavigationTarget,\n getVisibleTreeTypeaheadMatch,\n reconcileTreeExpansion,\n resolveTreeDescriptor,\n treeRecipe,\n type ComposeTreeAccessibleName,\n type ResolvedTreeNodeDescriptor,\n type TreeAsyncState,\n type TreeNodeDescriptor,\n type TreeSelectionModel,\n} from \"@hjmds/design-contracts/components/tree\";\nimport type { CheckboxState, WebKeyboardKey } from \"@hjmds/design-contracts/behaviors\";\nimport {\n forwardRef,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { classNames, composeRefs, useControllableState } from \"./internal.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\n\nexport type TreeProps<Id extends string = string> = Readonly<{\n label: string;\n nodes: readonly TreeNodeDescriptor<Id>[];\n composeAccessibleName: ComposeTreeAccessibleName;\n expandedKeys?: ReadonlySet<Id>;\n defaultExpandedKeys?: ReadonlySet<Id>;\n onExpandedKeysChange?: (keys: ReadonlySet<Id>) => void;\n selection?: TreeSelectionModel<Id>;\n /**\n * Tri-state check marks per node, as `resolveTreeCheckedStates` derives them.\n * Checkboxes are not nested controls in a tree: the state rides on the node\n * itself as `aria-checked`, keeping the contract's one-tab-stop-per-node rule.\n */\n checkedStates?: ReadonlyMap<Id, CheckboxState>;\n onCheckedToggle?: (id: Id) => void;\n asyncState?: TreeAsyncState;\n /** Product-owned glyph for the expand/collapse affordance; decorative by contract. */\n renderToggle?: (state: Readonly<{ expanded: boolean }>) => ReactNode;\n className?: string;\n}>;\n\nconst typeaheadResetMs = 500;\n\nfunction selectedIds<Id extends string>(selection: TreeSelectionModel<Id> | undefined): ReadonlySet<Id> {\n if (!selection || selection.mode === \"none\") return new Set<Id>();\n if (selection.mode === \"single\") {\n const key = selection.selectedKey ?? selection.defaultSelectedKey ?? null;\n return key === null ? new Set<Id>() : new Set<Id>([key]);\n }\n return selection.selectedKeys ?? selection.defaultSelectedKeys ?? new Set<Id>();\n}\n\nexport const Tree = forwardRef(function Tree<Id extends string = string>(\n {\n label,\n nodes,\n composeAccessibleName,\n expandedKeys: controlledExpanded,\n defaultExpandedKeys,\n onExpandedKeysChange,\n selection,\n checkedStates,\n onCheckedToggle,\n asyncState = { status: \"idle\" },\n renderToggle,\n className,\n }: TreeProps<Id>,\n forwardedRef: React.Ref<HTMLDivElement>,\n) {\n const [expandedKeys, setExpandedKeys] = useControllableState<ReadonlySet<Id>>({\n ...(controlledExpanded === undefined ? {} : { value: controlledExpanded }),\n defaultValue: defaultExpandedKeys ?? new Set<Id>(),\n ...(onExpandedKeysChange === undefined ? {} : { onChange: onExpandedKeysChange }),\n });\n const direction = useOptionalHjmTheme()?.environment.direction ?? \"ltr\";\n // Expansion keys survive a node list change only where the node still exists\n // and can still hold children; the contract owns that reconciliation.\n const liveExpanded = useMemo(() => reconcileTreeExpansion(nodes, expandedKeys), [nodes, expandedKeys]);\n const resolved = useMemo(\n () => resolveTreeDescriptor(nodes, liveExpanded, { composeAccessibleName }),\n [nodes, liveExpanded, composeAccessibleName],\n );\n const visible = useMemo(() => resolved.filter((node) => node.visible), [resolved]);\n const selected = selectedIds(selection);\n const [focusedId, setFocusedId] = useState<Id | null>(null);\n // Roving tab stop: one node is tabbable, and it must stay a real visible node\n // after a collapse removed the previously focused descendant.\n const activeId = visible.some((node) => node.id === focusedId) ? focusedId : visible[0]?.id ?? null;\n const rootRef = useRef<HTMLDivElement>(null);\n const typeahead = useRef<Readonly<{ query: string; at: number }>>({ query: \"\", at: 0 });\n\n const focusNode = (id: Id) => {\n setFocusedId(id);\n rootRef.current?.querySelector<HTMLElement>(`[data-hjm-tree-node=\"${CSS.escape(id)}\"]`)?.focus();\n };\n const setExpanded = (id: Id, expanded: boolean) => {\n const next = new Set(liveExpanded);\n if (expanded) next.add(id); else next.delete(id);\n setExpandedKeys(next);\n };\n const toggleSelection = (node: ResolvedTreeNodeDescriptor<Id>) => {\n if (node.disabled || !selection || selection.mode === \"none\") return;\n if (selection.mode === \"single\") {\n const current = selection.selectedKey ?? selection.defaultSelectedKey ?? null;\n const next = current === node.id && selection.disallowEmptySelection !== true ? null : node.id;\n selection.onSelectionChange?.(next);\n return;\n }\n const next = new Set(selection.selectedKeys ?? selection.defaultSelectedKeys ?? []);\n if (next.has(node.id)) next.delete(node.id); else next.add(node.id);\n selection.onSelectionChange?.(next);\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>, node: ResolvedTreeNodeDescriptor<Id>) => {\n const key = event.key as WebKeyboardKey;\n const arrow = getTreeArrowKeyIntent(key, direction);\n if (arrow) {\n const result = getTreeArrowResult(visible, node.id, arrow);\n if (result.action === \"none\") return;\n event.preventDefault();\n if (result.action === \"moveFocus\") focusNode(result.targetId);\n else setExpanded(node.id, result.action === \"expand\");\n return;\n }\n if (key === \"ArrowDown\" || key === \"ArrowUp\" || key === \"Home\" || key === \"End\") {\n const intent = key === \"ArrowDown\" ? \"next\" : key === \"ArrowUp\" ? \"previous\" : key === \"Home\" ? \"first\" : \"last\";\n const target = getVisibleTreeNavigationTarget(visible, node.id, intent);\n if (target === undefined) return;\n event.preventDefault();\n focusNode(target);\n return;\n }\n if (key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n if (checkedStates && onCheckedToggle) { if (!node.disabled) onCheckedToggle(node.id); }\n else toggleSelection(node);\n return;\n }\n if (event.key.length !== 1 || event.metaKey || event.ctrlKey || event.altKey) return;\n const now = Date.now();\n const query = now - typeahead.current.at > typeaheadResetMs ? event.key : typeahead.current.query + event.key;\n typeahead.current = { query, at: now };\n const match = getVisibleTreeTypeaheadMatch(visible, query, { startsAfterKey: node.id });\n if (match !== undefined) { event.preventDefault(); focusNode(match); }\n };\n\n return (\n <div\n ref={composeRefs(rootRef, forwardedRef)}\n role=\"tree\"\n aria-label={label}\n aria-busy={asyncState.status === \"loading\" || asyncState.status === \"loadingMore\" || undefined}\n aria-multiselectable={selection?.mode === \"multiple\" || undefined}\n className={classNames(\"hjm-tree\", className)}\n style={{ \"--hjm-tree-indent\": `${treeRecipe.indentPerLevel}px` } as CSSProperties}\n >\n {asyncState.status === \"empty\" || asyncState.status === \"error\" || asyncState.status === \"loading\" ? (\n <p className=\"hjm-tree__state\" role={asyncState.status === \"error\" ? \"alert\" : \"status\"}>{asyncState.message}</p>\n ) : null}\n {visible.map((node) => (\n <div\n key={node.id}\n role=\"treeitem\"\n data-hjm-tree-node={node.id}\n aria-level={node.depth}\n aria-posinset={node.position}\n aria-setsize={node.siblingCount}\n aria-expanded={node.hasChildren ? node.expanded : undefined}\n aria-selected={selection && selection.mode !== \"none\" ? selected.has(node.id) : undefined}\n aria-checked={checkedStates ? (checkedStates.get(node.id) === \"mixed\" ? \"mixed\" : String(checkedStates.get(node.id) === true)) as \"true\" | \"false\" | \"mixed\" : undefined}\n aria-disabled={node.disabled || undefined}\n aria-label={node.accessibleName}\n // One tab stop for the whole tree; the glyph is decorative, not a\n // nested control, so a node is the only focusable thing in a row.\n tabIndex={node.id === activeId ? 0 : -1}\n className=\"hjm-tree__node\"\n style={{ \"--hjm-tree-depth\": node.depth - 1 } as CSSProperties}\n onClick={(event) => {\n setFocusedId(node.id);\n // Pointer users had no way to expand: only arrow keys toggled (2026-09-30\n // audit WR-0930-2). The contract lets a row click change expansion; the\n // glyph toggles only, and in check mode the row click stays the check.\n const onGlyph = node.hasChildren &&\n (event.target as Element).closest?.(\".hjm-tree__toggle\") !== null;\n if (onGlyph) { setExpanded(node.id, !node.expanded); return; }\n if (checkedStates && onCheckedToggle) { if (!node.disabled) onCheckedToggle(node.id); return; }\n if (node.hasChildren) setExpanded(node.id, !node.expanded);\n toggleSelection(node);\n }}\n onFocus={() => setFocusedId(node.id)}\n onKeyDown={(event) => onKeyDown(event, node)}\n >\n <span aria-hidden=\"true\" className=\"hjm-tree__indent\" />\n {checkedStates ? (\n <span aria-hidden=\"true\" className=\"hjm-tree__check\" data-state={String(checkedStates.get(node.id) ?? false)}>\n {checkedStates.get(node.id) === true ? \"✓\" : checkedStates.get(node.id) === \"mixed\" ? \"–\" : \"\"}\n </span>\n ) : null}\n <span aria-hidden=\"true\" className=\"hjm-tree__toggle\" data-visible={node.hasChildren || undefined}>\n {node.hasChildren ? renderToggle?.({ expanded: node.expanded }) ?? (node.expanded ? \"▾\" : \"▸\") : null}\n </span>\n <span aria-hidden=\"true\" className=\"hjm-tree__label\">\n {node.label}\n {node.description ? <span className=\"hjm-tree__description\">{node.description}</span> : null}\n </span>\n </div>\n ))}\n {asyncState.status === \"loadingMore\" ? <p className=\"hjm-tree__state\" role=\"status\">{asyncState.message}</p> : null}\n </div>\n );\n}) as <Id extends string = string>(\n props: TreeProps<Id> & { ref?: React.Ref<HTMLDivElement> },\n) => React.ReactElement | null;\n"]}
@@ -0,0 +1,12 @@
1
+ import { type ReactNode } from "react";
2
+ export type WatermarkProps = Readonly<{
3
+ text: string | readonly string[];
4
+ children: ReactNode;
5
+ tileWidth?: number;
6
+ tileHeight?: number;
7
+ rotate?: number;
8
+ opacity?: number;
9
+ }>;
10
+ /** React escapes all text; an inline SVG pattern avoids canvas, external requests and markup interpolation. */
11
+ export declare function Watermark({ text, children, tileWidth, tileHeight, rotate, opacity }: WatermarkProps): import("react").JSX.Element;
12
+ //# sourceMappingURL=watermark.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watermark.d.ts","sourceRoot":"","sources":["../src/watermark.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9C,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAC7K,+GAA+G;AAC/G,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,cAAc,+BAanG"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
3
+ import { resolveWatermark } from "@hjmds/design-contracts/components/watermark";
4
+ /** React escapes all text; an inline SVG pattern avoids canvas, external requests and markup interpolation. */
5
+ export function Watermark({ text, children, tileWidth, tileHeight, rotate, opacity }) {
6
+ const config = resolveWatermark(text, tileWidth, tileHeight, rotate, opacity);
7
+ const id = `hjm-watermark-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
8
+ return _jsxs("div", { className: "hjm-watermark", "data-hjm-watermark": true, children: [_jsx("div", { className: "hjm-watermark__content", children: children }), _jsxs("svg", { className: "hjm-watermark__overlay", "aria-hidden": "true", focusable: "false", width: "100%", height: "100%", children: [_jsx("defs", { children: _jsx("pattern", { id: id, width: config.width, height: config.height, patternUnits: "userSpaceOnUse", children: _jsx("g", { transform: `rotate(${config.rotate} ${config.width / 2} ${config.height / 2})`, opacity: config.opacity, fill: "currentColor", children: config.lines.map((line, index) => _jsx("text", { x: config.width / 2, y: config.height / 2, dy: `${(index - (config.lines.length - 1) / 2) * 1.2}em`, textAnchor: "middle", dominantBaseline: "middle", children: line }, index)) }) }) }), _jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })] })] });
9
+ }
10
+ //# sourceMappingURL=watermark.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watermark.js","sourceRoot":"","sources":["../src/watermark.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAkB,MAAM,OAAO,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAEhF,+GAA+G;AAC/G,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAkB;IAClG,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9E,MAAM,EAAE,GAAG,iBAAiB,KAAK,EAAE,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,EAAE,CAAC;IACrE,OAAO,eAAK,SAAS,EAAC,eAAe,yCACnC,cAAK,SAAS,EAAC,wBAAwB,YAAE,QAAQ,GAAO,EACxD,eAAK,SAAS,EAAC,wBAAwB,iBAAa,MAAM,EAAC,SAAS,EAAC,OAAO,EAAC,KAAK,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,aACrG,yBAAM,kBAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAC,gBAAgB,YAC9F,YAAG,SAAS,EAAE,UAAU,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAC,cAAc,YAC5H,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,eAAkB,CAAC,EAAE,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,IAAI,EAAE,UAAU,EAAC,QAAQ,EAAC,gBAAgB,EAAC,QAAQ,YAAE,IAAI,IAA/J,KAAK,CAAkK,CAAC,GACpN,GACI,GAAO,EAAA,eAAM,KAAK,EAAC,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,GAAI,IACrE,IACF,CAAC;AACT,CAAC","sourcesContent":["import { useId, type ReactNode } from \"react\";\nimport { resolveWatermark } from \"@hjmds/design-contracts/components/watermark\";\nexport type WatermarkProps = Readonly<{ text: string | readonly string[]; children: ReactNode; tileWidth?: number; tileHeight?: number; rotate?: number; opacity?: number }>;\n/** React escapes all text; an inline SVG pattern avoids canvas, external requests and markup interpolation. */\nexport function Watermark({ text, children, tileWidth, tileHeight, rotate, opacity }: WatermarkProps) {\n const config = resolveWatermark(text, tileWidth, tileHeight, rotate, opacity);\n const id = `hjm-watermark-${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n return <div className=\"hjm-watermark\" data-hjm-watermark>\n <div className=\"hjm-watermark__content\">{children}</div>\n <svg className=\"hjm-watermark__overlay\" aria-hidden=\"true\" focusable=\"false\" width=\"100%\" height=\"100%\">\n <defs><pattern id={id} width={config.width} height={config.height} patternUnits=\"userSpaceOnUse\">\n <g transform={`rotate(${config.rotate} ${config.width / 2} ${config.height / 2})`} opacity={config.opacity} fill=\"currentColor\">\n {config.lines.map((line, index) => <text key={index} x={config.width / 2} y={config.height / 2} dy={`${(index - (config.lines.length - 1) / 2) * 1.2}em`} textAnchor=\"middle\" dominantBaseline=\"middle\">{line}</text>)}\n </g>\n </pattern></defs><rect width=\"100%\" height=\"100%\" fill={`url(#${id})`} />\n </svg>\n </div>;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hjmds/react",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "Accessible React 19 renderers for HJM design contracts.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -308,6 +308,21 @@
308
308
  "import": "./dist/menu-morph.js",
309
309
  "default": "./dist/menu-morph.js"
310
310
  },
311
+ "./affix": {
312
+ "types": "./dist/affix.d.ts",
313
+ "import": "./dist/affix.js",
314
+ "default": "./dist/affix.js"
315
+ },
316
+ "./color-picker": {
317
+ "types": "./dist/color-picker.d.ts",
318
+ "import": "./dist/color-picker.js",
319
+ "default": "./dist/color-picker.js"
320
+ },
321
+ "./watermark": {
322
+ "types": "./dist/watermark.d.ts",
323
+ "import": "./dist/watermark.js",
324
+ "default": "./dist/watermark.js"
325
+ },
311
326
  "./masonry": {
312
327
  "types": "./dist/masonry.d.ts",
313
328
  "react-native": "./dist/masonry.js",
@@ -326,6 +341,31 @@
326
341
  "import": "./dist/qr-code.js",
327
342
  "default": "./dist/qr-code.js"
328
343
  },
344
+ "./sortable": {
345
+ "types": "./dist/sortable.d.ts",
346
+ "import": "./dist/sortable.js",
347
+ "default": "./dist/sortable.js"
348
+ },
349
+ "./swipe-actions": {
350
+ "types": "./dist/swipe-actions.d.ts",
351
+ "import": "./dist/swipe-actions.js",
352
+ "default": "./dist/swipe-actions.js"
353
+ },
354
+ "./content-transition": {
355
+ "types": "./dist/content-transition.d.ts",
356
+ "import": "./dist/content-transition.js",
357
+ "default": "./dist/content-transition.js"
358
+ },
359
+ "./carousel-motion": {
360
+ "types": "./dist/carousel-motion.d.ts",
361
+ "import": "./dist/carousel-motion.js",
362
+ "default": "./dist/carousel-motion.js"
363
+ },
364
+ "./celebration": {
365
+ "types": "./dist/celebration.d.ts",
366
+ "import": "./dist/celebration.js",
367
+ "default": "./dist/celebration.js"
368
+ },
329
369
  "./styles.css": "./dist/styles.css",
330
370
  "./styles.layered.css": "./dist/styles.layered.css"
331
371
  },
@@ -336,13 +376,17 @@
336
376
  "THIRD_PARTY_NOTICES.md"
337
377
  ],
338
378
  "peerDependencies": {
339
- "@hjmds/design-contracts": ">=1.8.0 <1.9.0",
379
+ "@hjmds/design-contracts": ">=1.10.0 <1.11.0",
340
380
  "react": ">=19.0.0",
341
381
  "react-dom": ">=19.0.0",
342
382
  "@number-flow/react": "0.6.2",
343
383
  "bloom-menu": "0.1.0",
344
384
  "framer-motion": "13.4.4",
345
- "qrcode-generator": "2.0.4"
385
+ "qrcode-generator": "2.0.4",
386
+ "@dnd-kit/react": "0.5.0",
387
+ "embla-carousel-react": "8.6.0",
388
+ "canvas-confetti": "1.9.4",
389
+ "@dnd-kit/dom": "0.5.0"
346
390
  },
347
391
  "devDependencies": {
348
392
  "@types/node": "^24.13.3",
@@ -358,7 +402,12 @@
358
402
  "bloom-menu": "0.1.0",
359
403
  "framer-motion": "13.4.4",
360
404
  "qrcode-generator": "2.0.4",
361
- "@hjmds/design-contracts": "1.8.0"
405
+ "@dnd-kit/react": "0.5.0",
406
+ "embla-carousel-react": "8.6.0",
407
+ "canvas-confetti": "1.9.4",
408
+ "@types/canvas-confetti": "1.9.0",
409
+ "@dnd-kit/dom": "0.5.0",
410
+ "@hjmds/design-contracts": "1.10.0"
362
411
  },
363
412
  "peerDependenciesMeta": {
364
413
  "@number-flow/react": {
@@ -372,6 +421,18 @@
372
421
  },
373
422
  "qrcode-generator": {
374
423
  "optional": true
424
+ },
425
+ "@dnd-kit/react": {
426
+ "optional": true
427
+ },
428
+ "embla-carousel-react": {
429
+ "optional": true
430
+ },
431
+ "canvas-confetti": {
432
+ "optional": true
433
+ },
434
+ "@dnd-kit/dom": {
435
+ "optional": true
375
436
  }
376
437
  },
377
438
  "scripts": {