@hjmds/react 1.41.1 → 1.42.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/README.md +2 -2
- package/dist/actions.d.ts +41 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +40 -3
- package/dist/actions.js.map +1 -1
- package/dist/activity-chip.d.ts.map +1 -1
- package/dist/activity-chip.js +1 -0
- package/dist/activity-chip.js.map +1 -1
- package/dist/advanced-display.d.ts +47 -14
- package/dist/advanced-display.d.ts.map +1 -1
- package/dist/advanced-display.js +72 -17
- package/dist/advanced-display.js.map +1 -1
- package/dist/advanced-forms.d.ts.map +1 -1
- package/dist/advanced-forms.js +1 -0
- package/dist/advanced-forms.js.map +1 -1
- package/dist/affix.d.ts +6 -1
- package/dist/affix.d.ts.map +1 -1
- package/dist/affix.js +5 -3
- package/dist/affix.js.map +1 -1
- package/dist/agreement.d.ts.map +1 -1
- package/dist/agreement.js +1 -0
- package/dist/agreement.js.map +1 -1
- package/dist/alert-dialog-queue.d.ts +24 -0
- package/dist/alert-dialog-queue.d.ts.map +1 -0
- package/dist/alert-dialog-queue.js +44 -0
- package/dist/alert-dialog-queue.js.map +1 -0
- package/dist/anchor.d.ts.map +1 -1
- package/dist/anchor.js +1 -0
- package/dist/anchor.js.map +1 -1
- package/dist/asset.d.ts.map +1 -1
- package/dist/asset.js +1 -0
- package/dist/asset.js.map +1 -1
- package/dist/auth-screen.d.ts.map +1 -1
- package/dist/auth-screen.js +1 -0
- package/dist/auth-screen.js.map +1 -1
- package/dist/avatar-blobatar-motion.d.ts.map +1 -1
- package/dist/avatar-blobatar-motion.js +1 -0
- package/dist/avatar-blobatar-motion.js.map +1 -1
- package/dist/avatar-blobatar.d.ts.map +1 -1
- package/dist/avatar-blobatar.js +1 -0
- package/dist/avatar-blobatar.js.map +1 -1
- package/dist/bottom-cta.d.ts.map +1 -1
- package/dist/bottom-cta.js +1 -0
- package/dist/bottom-cta.js.map +1 -1
- package/dist/bottom-info.d.ts.map +1 -1
- package/dist/bottom-info.js +1 -0
- package/dist/bottom-info.js.map +1 -1
- package/dist/bottom-navigation.d.ts.map +1 -1
- package/dist/bottom-navigation.js +1 -0
- package/dist/bottom-navigation.js.map +1 -1
- package/dist/breadcrumb.d.ts.map +1 -1
- package/dist/breadcrumb.js +1 -0
- package/dist/breadcrumb.js.map +1 -1
- package/dist/calendar.d.ts.map +1 -1
- package/dist/calendar.js +1 -0
- package/dist/calendar.js.map +1 -1
- package/dist/carousel-motion.d.ts.map +1 -1
- package/dist/carousel-motion.js +1 -0
- package/dist/carousel-motion.js.map +1 -1
- package/dist/carousel.d.ts.map +1 -1
- package/dist/carousel.js +1 -0
- package/dist/carousel.js.map +1 -1
- package/dist/celebration.d.ts.map +1 -1
- package/dist/celebration.js +1 -0
- package/dist/celebration.js.map +1 -1
- package/dist/chart.d.ts +7 -2
- package/dist/chart.d.ts.map +1 -1
- package/dist/chart.js +6 -3
- package/dist/chart.js.map +1 -1
- package/dist/choice-row.d.ts +24 -7
- package/dist/choice-row.d.ts.map +1 -1
- package/dist/choice-row.js +11 -6
- package/dist/choice-row.js.map +1 -1
- package/dist/clipboard.d.ts.map +1 -1
- package/dist/clipboard.js +1 -0
- package/dist/clipboard.js.map +1 -1
- package/dist/collapsible.d.ts.map +1 -1
- package/dist/collapsible.js +1 -0
- package/dist/collapsible.js.map +1 -1
- package/dist/collection-rail.d.ts.map +1 -1
- package/dist/collection-rail.js +3 -1
- package/dist/collection-rail.js.map +1 -1
- package/dist/color-picker.d.ts.map +1 -1
- package/dist/color-picker.js +1 -0
- package/dist/color-picker.js.map +1 -1
- package/dist/command-palette.d.ts.map +1 -1
- package/dist/command-palette.js +1 -0
- package/dist/command-palette.js.map +1 -1
- package/dist/content-transition.d.ts.map +1 -1
- package/dist/content-transition.js +1 -0
- package/dist/content-transition.js.map +1 -1
- package/dist/context-menu.d.ts.map +1 -1
- package/dist/context-menu.js +1 -0
- package/dist/context-menu.js.map +1 -1
- package/dist/conversation-row.d.ts.map +1 -1
- package/dist/conversation-row.js +1 -0
- package/dist/conversation-row.js.map +1 -1
- package/dist/data-table.d.ts.map +1 -1
- package/dist/data-table.js +1 -0
- package/dist/data-table.js.map +1 -1
- package/dist/date-entry.d.ts.map +1 -1
- package/dist/date-entry.js +1 -0
- package/dist/date-entry.js.map +1 -1
- package/dist/date-picker.d.ts.map +1 -1
- package/dist/date-picker.js +1 -0
- package/dist/date-picker.js.map +1 -1
- package/dist/date-range.d.ts.map +1 -1
- package/dist/date-range.js +1 -0
- package/dist/date-range.js.map +1 -1
- package/dist/design-profile.d.ts.map +1 -1
- package/dist/design-profile.js +1 -0
- package/dist/design-profile.js.map +1 -1
- package/dist/display.d.ts +21 -1
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +34 -8
- package/dist/display.js.map +1 -1
- package/dist/duration-field.d.ts.map +1 -1
- package/dist/duration-field.js +1 -0
- package/dist/duration-field.js.map +1 -1
- package/dist/effect-surface.d.ts.map +1 -1
- package/dist/effect-surface.js +1 -0
- package/dist/effect-surface.js.map +1 -1
- package/dist/evidence.d.ts +1 -1
- package/dist/evidence.js +1 -1
- package/dist/evidence.js.map +1 -1
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +1 -0
- package/dist/feedback.js.map +1 -1
- package/dist/field-group.d.ts.map +1 -1
- package/dist/field-group.js +1 -0
- package/dist/field-group.js.map +1 -1
- package/dist/file-picker.d.ts.map +1 -1
- package/dist/file-picker.js +1 -0
- package/dist/file-picker.js.map +1 -1
- package/dist/floating-action-button.d.ts.map +1 -1
- package/dist/floating-action-button.js +1 -0
- package/dist/floating-action-button.js.map +1 -1
- package/dist/folder-preview.d.ts.map +1 -1
- package/dist/folder-preview.js +1 -0
- package/dist/folder-preview.js.map +1 -1
- package/dist/forms.d.ts +30 -6
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +56 -14
- package/dist/forms.js.map +1 -1
- package/dist/gravity-letters.d.ts.map +1 -1
- package/dist/gravity-letters.js +1 -0
- package/dist/gravity-letters.js.map +1 -1
- package/dist/grid-reveal.d.ts.map +1 -1
- package/dist/grid-reveal.js +1 -0
- package/dist/grid-reveal.js.map +1 -1
- package/dist/heading.d.ts.map +1 -1
- package/dist/heading.js +1 -0
- package/dist/heading.js.map +1 -1
- package/dist/image-choice.d.ts.map +1 -1
- package/dist/image-choice.js +1 -0
- package/dist/image-choice.js.map +1 -1
- package/dist/image-comparison.d.ts.map +1 -1
- package/dist/image-comparison.js +1 -0
- package/dist/image-comparison.js.map +1 -1
- package/dist/image-viewer.d.ts +22 -1
- package/dist/image-viewer.d.ts.map +1 -1
- package/dist/image-viewer.js +14 -1
- package/dist/image-viewer.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/inline-confirm.d.ts.map +1 -1
- package/dist/inline-confirm.js +1 -0
- package/dist/inline-confirm.js.map +1 -1
- package/dist/internal/document-resource.d.ts.map +1 -1
- package/dist/internal/document-resource.js +1 -0
- package/dist/internal/document-resource.js.map +1 -1
- package/dist/internal/initial-focus.d.ts.map +1 -1
- package/dist/internal/initial-focus.js +1 -0
- package/dist/internal/initial-focus.js.map +1 -1
- package/dist/internal/media-album.d.ts.map +1 -1
- package/dist/internal/media-album.js +1 -0
- package/dist/internal/media-album.js.map +1 -1
- package/dist/internal/message-reactions.d.ts.map +1 -1
- package/dist/internal/message-reactions.js +1 -0
- package/dist/internal/message-reactions.js.map +1 -1
- package/dist/internal/overlay-origin-motion.d.ts.map +1 -1
- package/dist/internal/overlay-origin-motion.js +1 -0
- package/dist/internal/overlay-origin-motion.js.map +1 -1
- package/dist/internal/pending-content.d.ts.map +1 -1
- package/dist/internal/pending-content.js +1 -0
- package/dist/internal/pending-content.js.map +1 -1
- package/dist/internal/photo-source-icon.d.ts.map +1 -1
- package/dist/internal/photo-source-icon.js +1 -0
- package/dist/internal/photo-source-icon.js.map +1 -1
- package/dist/internal/screen-exit.d.ts.map +1 -1
- package/dist/internal/screen-exit.js +1 -0
- package/dist/internal/screen-exit.js.map +1 -1
- package/dist/internal/screen-footer.d.ts.map +1 -1
- package/dist/internal/screen-footer.js +1 -0
- package/dist/internal/screen-footer.js.map +1 -1
- package/dist/internal/spinner.d.ts.map +1 -1
- package/dist/internal/spinner.js +1 -0
- package/dist/internal/spinner.js.map +1 -1
- package/dist/internal/use-composition-action.d.ts.map +1 -1
- package/dist/internal/use-composition-action.js +1 -0
- package/dist/internal/use-composition-action.js.map +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -0
- package/dist/internal.js.map +1 -1
- package/dist/layout.d.ts +11 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +8 -4
- package/dist/layout.js.map +1 -1
- package/dist/mentions.d.ts.map +1 -1
- package/dist/mentions.js +1 -0
- package/dist/mentions.js.map +1 -1
- package/dist/menu-morph.d.ts.map +1 -1
- package/dist/menu-morph.js +1 -0
- package/dist/menu-morph.js.map +1 -1
- package/dist/menubar.d.ts.map +1 -1
- package/dist/menubar.js +1 -0
- package/dist/menubar.js.map +1 -1
- package/dist/modal.d.ts.map +1 -1
- package/dist/modal.js +1 -0
- package/dist/modal.js.map +1 -1
- package/dist/navigation-bar.d.ts.map +1 -1
- package/dist/navigation-bar.js +1 -0
- package/dist/navigation-bar.js.map +1 -1
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +1 -0
- package/dist/navigation.js.map +1 -1
- package/dist/notification-bell.d.ts +1 -1
- package/dist/notification-bell.d.ts.map +1 -1
- package/dist/notification-bell.js +5 -1
- package/dist/notification-bell.js.map +1 -1
- package/dist/number-field.d.ts.map +1 -1
- package/dist/number-field.js +1 -0
- package/dist/number-field.js.map +1 -1
- package/dist/overlay-stack.d.ts.map +1 -1
- package/dist/overlay-stack.js +1 -0
- package/dist/overlay-stack.js.map +1 -1
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +11 -2
- package/dist/overlays.js.map +1 -1
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +1 -0
- package/dist/pagination.js.map +1 -1
- package/dist/popover.d.ts.map +1 -1
- package/dist/popover.js +1 -0
- package/dist/popover.js.map +1 -1
- package/dist/portal.d.ts.map +1 -1
- package/dist/portal.js +1 -0
- package/dist/portal.js.map +1 -1
- package/dist/progressive-blur.d.ts.map +1 -1
- package/dist/progressive-blur.js +1 -0
- package/dist/progressive-blur.js.map +1 -1
- package/dist/provider-button.d.ts.map +1 -1
- package/dist/provider-button.js +1 -0
- package/dist/provider-button.js.map +1 -1
- package/dist/provider.d.ts +9 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +2 -2
- package/dist/provider.js.map +1 -1
- package/dist/public-exports.generated.d.ts +3 -0
- package/dist/public-exports.generated.d.ts.map +1 -1
- package/dist/public-exports.generated.js +9 -0
- package/dist/public-exports.generated.js.map +1 -1
- package/dist/rating.d.ts.map +1 -1
- package/dist/rating.js +1 -0
- package/dist/rating.js.map +1 -1
- package/dist/reaction-picker.d.ts.map +1 -1
- package/dist/reaction-picker.js +1 -0
- package/dist/reaction-picker.js.map +1 -1
- package/dist/saved-items.d.ts.map +1 -1
- package/dist/saved-items.js +1 -0
- package/dist/saved-items.js.map +1 -1
- package/dist/screen-flows.d.ts +5 -1
- package/dist/screen-flows.d.ts.map +1 -1
- package/dist/screen-flows.js +13 -4
- package/dist/screen-flows.js.map +1 -1
- package/dist/screens.d.ts +24 -4
- package/dist/screens.d.ts.map +1 -1
- package/dist/screens.js +38 -11
- package/dist/screens.js.map +1 -1
- package/dist/scroll-progress.d.ts.map +1 -1
- package/dist/scroll-progress.js +1 -0
- package/dist/scroll-progress.js.map +1 -1
- package/dist/select.d.ts.map +1 -1
- package/dist/select.js +1 -0
- package/dist/select.js.map +1 -1
- package/dist/selection.d.ts +7 -1
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +33 -10
- package/dist/selection.js.map +1 -1
- package/dist/side-panel.d.ts.map +1 -1
- package/dist/side-panel.js +1 -0
- package/dist/side-panel.js.map +1 -1
- package/dist/sidebar.d.ts +21 -2
- package/dist/sidebar.d.ts.map +1 -1
- package/dist/sidebar.js +40 -20
- package/dist/sidebar.js.map +1 -1
- package/dist/skip-nav.d.ts.map +1 -1
- package/dist/skip-nav.js +1 -0
- package/dist/skip-nav.js.map +1 -1
- package/dist/slider.d.ts.map +1 -1
- package/dist/slider.js +1 -0
- package/dist/slider.js.map +1 -1
- package/dist/sortable.d.ts.map +1 -1
- package/dist/sortable.js +1 -0
- package/dist/sortable.js.map +1 -1
- package/dist/splitter.d.ts.map +1 -1
- package/dist/splitter.js +1 -0
- package/dist/splitter.js.map +1 -1
- package/dist/statistic-motion.d.ts.map +1 -1
- package/dist/statistic-motion.js +1 -0
- package/dist/statistic-motion.js.map +1 -1
- package/dist/status-text.d.ts.map +1 -1
- package/dist/status-text.js +1 -0
- package/dist/status-text.js.map +1 -1
- package/dist/step-player.d.ts.map +1 -1
- package/dist/step-player.js +1 -0
- package/dist/step-player.js.map +1 -1
- package/dist/steps.d.ts +16 -14
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +26 -9
- package/dist/steps.js.map +1 -1
- package/dist/styles.css +140 -35
- package/dist/styles.layered.css +140 -35
- package/dist/supplemental-display.d.ts.map +1 -1
- package/dist/supplemental-display.js +1 -0
- package/dist/supplemental-display.js.map +1 -1
- package/dist/supplemental-navigation.d.ts.map +1 -1
- package/dist/supplemental-navigation.js +1 -0
- package/dist/supplemental-navigation.js.map +1 -1
- package/dist/swipe-actions.d.ts.map +1 -1
- package/dist/swipe-actions.js +1 -0
- package/dist/swipe-actions.js.map +1 -1
- package/dist/table-family.d.ts.map +1 -1
- package/dist/table-family.js +1 -0
- package/dist/table-family.js.map +1 -1
- package/dist/table-sort-button.d.ts.map +1 -1
- package/dist/table-sort-button.js +1 -0
- package/dist/table-sort-button.js.map +1 -1
- package/dist/tags-input.d.ts.map +1 -1
- package/dist/tags-input.js +1 -0
- package/dist/tags-input.js.map +1 -1
- package/dist/task-list.d.ts.map +1 -1
- package/dist/task-list.js +1 -0
- package/dist/task-list.js.map +1 -1
- package/dist/text-annotation.d.ts.map +1 -1
- package/dist/text-annotation.js +1 -0
- package/dist/text-annotation.js.map +1 -1
- package/dist/text-formats.d.ts.map +1 -1
- package/dist/text-formats.js +1 -0
- package/dist/text-formats.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +12 -1
- package/dist/theme.js.map +1 -1
- package/dist/thinking-orb.d.ts.map +1 -1
- package/dist/thinking-orb.js +1 -0
- package/dist/thinking-orb.js.map +1 -1
- package/dist/toast.d.ts.map +1 -1
- package/dist/toast.js +1 -0
- package/dist/toast.js.map +1 -1
- package/dist/toggle-group.d.ts.map +1 -1
- package/dist/toggle-group.js +1 -0
- package/dist/toggle-group.js.map +1 -1
- package/dist/top-bar.d.ts.map +1 -1
- package/dist/top-bar.js +1 -0
- package/dist/top-bar.js.map +1 -1
- package/dist/top.d.ts.map +1 -1
- package/dist/top.js +4 -3
- package/dist/top.js.map +1 -1
- package/dist/tour.d.ts.map +1 -1
- package/dist/tour.js +1 -0
- package/dist/tour.js.map +1 -1
- package/dist/transfer-list.d.ts.map +1 -1
- package/dist/transfer-list.js +1 -0
- package/dist/transfer-list.js.map +1 -1
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +1 -0
- package/dist/tree.js.map +1 -1
- package/dist/upload-item.d.ts.map +1 -1
- package/dist/upload-item.js +1 -0
- package/dist/upload-item.js.map +1 -1
- package/dist/virtual-list.d.ts.map +1 -1
- package/dist/virtual-list.js +1 -0
- package/dist/virtual-list.js.map +1 -1
- package/dist/voice-note.d.ts.map +1 -1
- package/dist/voice-note.js +1 -0
- package/dist/voice-note.js.map +1 -1
- package/package.json +8 -3
package/dist/choice-row.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useState } from "react";
|
|
3
4
|
import { resolveChoiceRow } from "@hjmds/design-contracts/choice-row";
|
|
4
5
|
import { ListRow } from "./display.js";
|
|
5
6
|
import { Sheet } from "./overlays.js";
|
|
6
7
|
import { RadioGroup } from "./selection.js";
|
|
7
|
-
export function ChoiceRow(
|
|
8
|
-
const {
|
|
9
|
-
|
|
8
|
+
export function ChoiceRow(props) {
|
|
9
|
+
const { title, items, value, closeLabel, errorLabel, sheetTitle, sheetDescription, placeholder, leading, trailing, density, disabled = false, loading = false } = props;
|
|
10
|
+
const { selected, valueLabel } = resolveChoiceRow({ title, items, value, ...(placeholder === undefined ? {} : { placeholder }) });
|
|
11
|
+
if (!closeLabel.trim() || (errorLabel !== undefined && !errorLabel.trim()))
|
|
10
12
|
throw new TypeError("ChoiceRow text must not be empty");
|
|
11
13
|
const [open, setOpen] = useState(false);
|
|
12
14
|
const [pending, setPending] = useState(false);
|
|
@@ -17,7 +19,7 @@ export function ChoiceRow({ title, items, value, onValueChange, closeLabel, erro
|
|
|
17
19
|
if (next === value || pending)
|
|
18
20
|
return;
|
|
19
21
|
setFailed(false);
|
|
20
|
-
const result = onValueChange(next);
|
|
22
|
+
const result = props.onValueChange(next);
|
|
21
23
|
if (!result) {
|
|
22
24
|
setOpen(false);
|
|
23
25
|
return;
|
|
@@ -25,7 +27,10 @@ export function ChoiceRow({ title, items, value, onValueChange, closeLabel, erro
|
|
|
25
27
|
setPending(true);
|
|
26
28
|
result.then(() => { setPending(false); setOpen(false); }, () => { setPending(false); setFailed(true); });
|
|
27
29
|
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
const rowLeading = leading ?? items.find((item) => item.value === selected?.value)?.leading;
|
|
31
|
+
const pictured = items.some((item) => item.leading != null);
|
|
32
|
+
const byValue = new Map(items.map((item) => [item.value, item]));
|
|
33
|
+
return _jsxs(_Fragment, { children: [_jsx(ListRow, { title: title, description: valueLabel, ...(rowLeading == null ? {} : { leading: rowLeading }), ...(trailing === undefined ? {} : { trailing }), ...(density === undefined ? {} : { density }), disabled: disabled, loading: loading, "aria-haspopup": "dialog", "aria-expanded": open, onClick: () => { setFailed(false); setOpen(true); } }), _jsx(Sheet, { open: open, onOpenChange: (next) => { if (!pending)
|
|
34
|
+
setOpen(next); }, title: sheetTitle ?? title, closeLabel: closeLabel, busy: pending, ...(sheetDescription === undefined ? {} : { description: sheetDescription }), children: _jsx(RadioGroup, { accessibilityLabel: sheetTitle ?? title, orientation: "vertical", value: value, items: items, disabled: pending, ...(failed && errorLabel !== undefined ? { error: errorLabel } : {}), onValueChange: choose, ...(pictured ? { renderLeading: (item) => _jsx("span", { className: "hjm-choice-row__item-leading", children: byValue.get(item.value)?.leading }) } : {}) }) })] });
|
|
30
35
|
}
|
|
31
36
|
//# sourceMappingURL=choice-row.js.map
|
package/dist/choice-row.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choice-row.js","sourceRoot":"","sources":["../src/choice-row.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"choice-row.js","sourceRoot":"","sources":["../src/choice-row.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\nimport { resolveChoiceRow, type ChoiceRowItem as ChoiceRowItemContract } from \"@hjmds/design-contracts/choice-row\";\nimport type { ListRowDensity } from \"@hjmds/design-contracts/recipes\";\nimport { ListRow } from \"./display.js\";\nimport { Sheet } from \"./overlays.js\";\nimport { RadioGroup } from \"./selection.js\";\n\n/**\n * A choice. `leading` is the product picture for that choice (theme artwork, flag); the sheet draws it in the\n * recipe-owned box (choiceRowRecipe.itemLeading) and the row shows the confirmed choice's picture unless the row\n * gets its own `leading` (2026-10-23 utilverse shell theme row).\n */\nexport type ChoiceRowItem<Value extends string = string> = ChoiceRowItemContract<Value> & Readonly<{ leading?: ReactNode }>;\n/** A synchronous save closes the sheet at once. Only an async save can fail inside the sheet, so only it needs\n * `errorLabel`; a rejected promise keeps the sheet open with that message (2026-10-23 product adoption). */\nexport type ChoiceRowSave<Value extends string = string> =\n | Readonly<{ onValueChange: (value: Value) => void; errorLabel?: never }>\n | Readonly<{ onValueChange: (value: Value) => Promise<void>; errorLabel: string }>;\nexport type ChoiceRowProps<Value extends string = string> = ChoiceRowSave<Value> & Readonly<{\n title: string;\n items: readonly ChoiceRowItem<Value>[];\n /** The product-confirmed value; update it only after the save succeeds. */\n value: Value | null;\n closeLabel: string;\n sheetTitle?: string;\n sheetDescription?: string;\n placeholder?: string;\n /** Row picture; defaults to the confirmed item's `leading`. */\n leading?: ReactNode;\n trailing?: ReactNode;\n /** ListRow density, so the row matches the surrounding settings rows. */\n density?: ListRowDensity;\n disabled?: boolean;\n loading?: boolean;\n}>;\n\nexport function ChoiceRow<Value extends string = string>(props: ChoiceRowProps<Value>) {\n const { title, items, value, closeLabel, errorLabel, sheetTitle, sheetDescription, placeholder, leading, trailing, density, disabled = false, loading = false } = props;\n const { selected, valueLabel } = resolveChoiceRow({ title, items, value, ...(placeholder === undefined ? {} : { placeholder }) });\n if (!closeLabel.trim() || (errorLabel !== undefined && !errorLabel.trim())) throw new TypeError(\"ChoiceRow text must not be empty\");\n const [open, setOpen] = useState(false);\n const [pending, setPending] = useState(false);\n const [failed, setFailed] = useState(false);\n const choose = (raw: string) => {\n // RadioGroup only offers the values passed in `items`, so the string is one of `Value`.\n const next = raw as Value;\n if (next === value || pending) return;\n setFailed(false);\n const result: void | Promise<void> = props.onValueChange(next);\n if (!result) { setOpen(false); return; }\n setPending(true);\n result.then(() => { setPending(false); setOpen(false); }, () => { setPending(false); setFailed(true); });\n };\n const rowLeading = leading ?? items.find((item) => item.value === selected?.value)?.leading;\n const pictured = items.some((item) => item.leading != null);\n const byValue = new Map(items.map((item) => [item.value as string, item]));\n return <>\n <ListRow title={title} description={valueLabel} {...(rowLeading == null ? {} : { leading: rowLeading })} {...(trailing === undefined ? {} : { trailing })} {...(density === undefined ? {} : { density })} disabled={disabled} loading={loading}\n aria-haspopup=\"dialog\" aria-expanded={open}\n onClick={() => { setFailed(false); setOpen(true); }} />\n <Sheet open={open} onOpenChange={(next) => { if (!pending) setOpen(next); }} title={sheetTitle ?? title} closeLabel={closeLabel} busy={pending}\n {...(sheetDescription === undefined ? {} : { description: sheetDescription })}>\n <RadioGroup accessibilityLabel={sheetTitle ?? title} orientation=\"vertical\" value={value} items={items} disabled={pending}\n {...(failed && errorLabel !== undefined ? { error: errorLabel } : {})} onValueChange={choose}\n {...(pictured ? { renderLeading: (item: { value: string }) => <span className=\"hjm-choice-row__item-leading\">{byValue.get(item.value)?.leading}</span> } : {})} />\n </Sheet>\n </>;\n}\n"]}
|
package/dist/clipboard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../src/clipboard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../src/clipboard.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAwD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7F,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAM1F,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC,GACrF,QAAQ,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,MAAM,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACzD,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,CAAC,CAAC;AAgEL;;;;;GAKG;AACH,eAAO,MAAM,eAAe;WA7EjB,MAAM;IACb,oEAAoE;YAC5D,QAAQ,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,CAAC;IACxD,8CAA8C;uBAC3B,MAAM;aAChB,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;kBAClB,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI;sDA0FzC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC,GACpH,QAAQ,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,MAAM,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,CAAC,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,mBAAmB;WAZrB,MAAM;IACb,oFAAoF;YAC5E,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;uBAC/B,MAAM;aAChB,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;kBAClB,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI;sDAsBzC,CAAC"}
|
package/dist/clipboard.js
CHANGED
package/dist/clipboard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../src/clipboard.tsx"],"names":[],"mappings":"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","sourcesContent":["import { forwardRef, useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { Button, IconButton, type ButtonProps, type IconButtonProps } from \"./actions.js\";\nimport { Icon } from \"./supplemental-display.js\";\n\n// `onCopy` also names the DOM clipboard event handler on ButtonProps; intersected, the\n// value callback had to accept a ClipboardEvent too and no product could pass it. The\n// renderer consumes the prop and never forwards the DOM event, so omitting is lossless.\nexport type ClipboardButtonProps = Omit<ButtonProps, \"children\" | \"onClick\" | \"onCopy\"> &\n Readonly<{\n value: string;\n /** Localized copy for both states; the renderer invents neither. */\n labels: Readonly<{ idle: ReactNode; copied: ReactNode }>;\n /** How long the copied state stays, in ms. */\n feedbackDuration?: number;\n onCopy?: (value: string) => void;\n onCopyError?: (error: unknown) => void;\n }>;\n\nconst defaultFeedbackDuration = 2000;\n\ntype ClipboardCopyOptions = Readonly<{ value: string; feedbackDuration: number; onCopy?: ((value: string) => void) | undefined; onCopyError?: ((error: unknown) => void) | undefined }>;\n\n/** One copy state machine for the labelled and the icon presentation. */\nfunction useClipboardCopy({ value, feedbackDuration, onCopy, onCopyError }: ClipboardCopyOptions) {\n const [copied, setCopied] = useState(false);\n const [copying, setCopying] = useState(false);\n const pending = useRef(false);\n const generation = useRef(0);\n const mounted = useRef(false);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n useEffect(() => {\n mounted.current = true;\n setCopying(pending.current);\n return () => {\n mounted.current = false;\n generation.current += 1;\n if (timer.current !== undefined) clearTimeout(timer.current);\n };\n }, []);\n useEffect(() => {\n // A new value makes the previous \"copied\" claim false: it referred to the\n // old string, and leaving it up tells the user something untrue.\n generation.current += 1;\n setCopied(false);\n if (timer.current !== undefined) clearTimeout(timer.current);\n }, [value]);\n\n const copy = useCallback(async () => {\n // OS clipboard promises cannot be cancelled. A per-value generation ignores\n // obsolete feedback/callbacks instead of announcing an old source as copied.\n // A ref also closes the gap before React paints the unavailable busy button.\n if (!mounted.current || pending.current) return;\n const request = ++generation.current;\n pending.current = true;\n setCopying(true);\n setCopied(false);\n if (timer.current !== undefined) clearTimeout(timer.current);\n try {\n await navigator.clipboard.writeText(value);\n if (!mounted.current || request !== generation.current) return;\n setCopied(true);\n if (timer.current !== undefined) clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), feedbackDuration);\n onCopy?.(value);\n } catch (error) {\n // Clipboard access can be denied; swallowing that would leave the user\n // believing the value was copied.\n if (mounted.current && request === generation.current) onCopyError?.(error);\n } finally {\n // Keep the OS write single-flight across value changes as well: starting a\n // second write early could let the first overwrite its clipboard contents.\n pending.current = false;\n if (mounted.current) setCopying(false);\n }\n }, [value, feedbackDuration, onCopy, onCopyError]);\n\n return { copied, copying, copy };\n}\n\n\n/**\n * Copying is three things products kept re-deriving: the async clipboard call,\n * the temporary \"copied\" state, and announcing that state to a screen reader.\n * The last one is the part that was always missing — a label that only changes\n * visually tells a non-sighted user nothing happened.\n */\nexport const ClipboardButton = forwardRef<HTMLButtonElement, ClipboardButtonProps>(\n function ClipboardButton(\n // Default `secondary` (2026-10-06): copying is a helper beside the screen's main action, and the\n // inherited Button default `primary` added a second primary to screens that already had one.\n // Pass `tone=\"primary\"` explicitly when copying *is* the screen's main action.\n { value, labels, feedbackDuration = defaultFeedbackDuration, onCopy, onCopyError, tone = \"secondary\", ...props },\n forwardedRef,\n ) {\n const { copied, copying, copy } = useClipboardCopy({ value, feedbackDuration, onCopy, onCopyError });\n return (\n <>\n <Button {...props} tone={tone} loading={props.loading || copying} ref={forwardedRef} onClick={() => { void copy(); }}>\n {copied ? labels.copied : labels.idle}\n </Button>\n {/* The state change is announced, not only painted. */}\n <span role=\"status\" className=\"hjm-visually-hidden\">{copied ? labels.copied : \"\"}</span>\n </>\n );\n },\n);\n\nexport type ClipboardIconButtonProps = Omit<IconButtonProps, \"children\" | \"label\" | \"onClick\" | \"onCopy\" | \"selected\"> &\n Readonly<{\n value: string;\n /** Localized accessible names for both states; the icon carries no visible text. */\n labels: Readonly<{ idle: string; copied: string }>;\n feedbackDuration?: number;\n onCopy?: (value: string) => void;\n onCopyError?: (error: unknown) => void;\n }>;\n\n/**\n * Copy as a tool action (a code block or share-link header): an icon button named by the localized label, copy → check\n * while the copied state lasts. A bordered text button there read as a form action (2026-10-17 review E10).\n */\nexport const ClipboardIconButton = forwardRef<HTMLButtonElement, ClipboardIconButtonProps>(\n function ClipboardIconButton(\n { value, labels, feedbackDuration = defaultFeedbackDuration, onCopy, onCopyError, tone = \"ghost\", ...props },\n forwardedRef,\n ) {\n const { copied, copying, copy } = useClipboardCopy({ value, feedbackDuration, onCopy, onCopyError });\n return (\n <>\n <IconButton {...props} tone={tone} label={copied ? labels.copied : labels.idle} loading={props.loading || copying} ref={forwardedRef} onClick={() => { void copy(); }}>\n <Icon name={copied ? \"check\" : \"copy\"} />\n </IconButton>\n <span role=\"status\" className=\"hjm-visually-hidden\">{copied ? labels.copied : \"\"}</span>\n </>\n );\n },\n);\n"]}
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../src/clipboard.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { forwardRef, useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { Button, IconButton, type ButtonProps, type IconButtonProps } from \"./actions.js\";\nimport { Icon } from \"./supplemental-display.js\";\n\n// `onCopy` also names the DOM clipboard event handler on ButtonProps; intersected, the\n// value callback had to accept a ClipboardEvent too and no product could pass it. The\n// renderer consumes the prop and never forwards the DOM event, so omitting is lossless.\nexport type ClipboardButtonProps = Omit<ButtonProps, \"children\" | \"onClick\" | \"onCopy\"> &\n Readonly<{\n value: string;\n /** Localized copy for both states; the renderer invents neither. */\n labels: Readonly<{ idle: ReactNode; copied: ReactNode }>;\n /** How long the copied state stays, in ms. */\n feedbackDuration?: number;\n onCopy?: (value: string) => void;\n onCopyError?: (error: unknown) => void;\n }>;\n\nconst defaultFeedbackDuration = 2000;\n\ntype ClipboardCopyOptions = Readonly<{ value: string; feedbackDuration: number; onCopy?: ((value: string) => void) | undefined; onCopyError?: ((error: unknown) => void) | undefined }>;\n\n/** One copy state machine for the labelled and the icon presentation. */\nfunction useClipboardCopy({ value, feedbackDuration, onCopy, onCopyError }: ClipboardCopyOptions) {\n const [copied, setCopied] = useState(false);\n const [copying, setCopying] = useState(false);\n const pending = useRef(false);\n const generation = useRef(0);\n const mounted = useRef(false);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n useEffect(() => {\n mounted.current = true;\n setCopying(pending.current);\n return () => {\n mounted.current = false;\n generation.current += 1;\n if (timer.current !== undefined) clearTimeout(timer.current);\n };\n }, []);\n useEffect(() => {\n // A new value makes the previous \"copied\" claim false: it referred to the\n // old string, and leaving it up tells the user something untrue.\n generation.current += 1;\n setCopied(false);\n if (timer.current !== undefined) clearTimeout(timer.current);\n }, [value]);\n\n const copy = useCallback(async () => {\n // OS clipboard promises cannot be cancelled. A per-value generation ignores\n // obsolete feedback/callbacks instead of announcing an old source as copied.\n // A ref also closes the gap before React paints the unavailable busy button.\n if (!mounted.current || pending.current) return;\n const request = ++generation.current;\n pending.current = true;\n setCopying(true);\n setCopied(false);\n if (timer.current !== undefined) clearTimeout(timer.current);\n try {\n await navigator.clipboard.writeText(value);\n if (!mounted.current || request !== generation.current) return;\n setCopied(true);\n if (timer.current !== undefined) clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), feedbackDuration);\n onCopy?.(value);\n } catch (error) {\n // Clipboard access can be denied; swallowing that would leave the user\n // believing the value was copied.\n if (mounted.current && request === generation.current) onCopyError?.(error);\n } finally {\n // Keep the OS write single-flight across value changes as well: starting a\n // second write early could let the first overwrite its clipboard contents.\n pending.current = false;\n if (mounted.current) setCopying(false);\n }\n }, [value, feedbackDuration, onCopy, onCopyError]);\n\n return { copied, copying, copy };\n}\n\n\n/**\n * Copying is three things products kept re-deriving: the async clipboard call,\n * the temporary \"copied\" state, and announcing that state to a screen reader.\n * The last one is the part that was always missing — a label that only changes\n * visually tells a non-sighted user nothing happened.\n */\nexport const ClipboardButton = forwardRef<HTMLButtonElement, ClipboardButtonProps>(\n function ClipboardButton(\n // Default `secondary` (2026-10-06): copying is a helper beside the screen's main action, and the\n // inherited Button default `primary` added a second primary to screens that already had one.\n // Pass `tone=\"primary\"` explicitly when copying *is* the screen's main action.\n { value, labels, feedbackDuration = defaultFeedbackDuration, onCopy, onCopyError, tone = \"secondary\", ...props },\n forwardedRef,\n ) {\n const { copied, copying, copy } = useClipboardCopy({ value, feedbackDuration, onCopy, onCopyError });\n return (\n <>\n <Button {...props} tone={tone} loading={props.loading || copying} ref={forwardedRef} onClick={() => { void copy(); }}>\n {copied ? labels.copied : labels.idle}\n </Button>\n {/* The state change is announced, not only painted. */}\n <span role=\"status\" className=\"hjm-visually-hidden\">{copied ? labels.copied : \"\"}</span>\n </>\n );\n },\n);\n\nexport type ClipboardIconButtonProps = Omit<IconButtonProps, \"children\" | \"label\" | \"onClick\" | \"onCopy\" | \"selected\"> &\n Readonly<{\n value: string;\n /** Localized accessible names for both states; the icon carries no visible text. */\n labels: Readonly<{ idle: string; copied: string }>;\n feedbackDuration?: number;\n onCopy?: (value: string) => void;\n onCopyError?: (error: unknown) => void;\n }>;\n\n/**\n * Copy as a tool action (a code block or share-link header): an icon button named by the localized label, copy → check\n * while the copied state lasts. A bordered text button there read as a form action (2026-10-17 review E10).\n */\nexport const ClipboardIconButton = forwardRef<HTMLButtonElement, ClipboardIconButtonProps>(\n function ClipboardIconButton(\n { value, labels, feedbackDuration = defaultFeedbackDuration, onCopy, onCopyError, tone = \"ghost\", ...props },\n forwardedRef,\n ) {\n const { copied, copying, copy } = useClipboardCopy({ value, feedbackDuration, onCopy, onCopyError });\n return (\n <>\n <IconButton {...props} tone={tone} label={copied ? labels.copied : labels.idle} loading={props.loading || copying} ref={forwardedRef} onClick={() => { void copy(); }}>\n <Icon name={copied ? \"check\" : \"copy\"} />\n </IconButton>\n <span role=\"status\" className=\"hjm-visually-hidden\">{copied ? labels.copied : \"\"}</span>\n </>\n );\n },\n);\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collapsible.d.ts","sourceRoot":"","sources":["../src/collapsible.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"collapsible.d.ts","sourceRoot":"","sources":["../src/collapsible.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,gDAAgD,CAAC;AACxD,OAAO,EAA4E,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GACjD,QAAQ,CAAC;IACP,oEAAoE;IACpE,OAAO,EAAE,SAAS,CAAC;IACnB,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,GAAG,QAAQ,CAAC;IACvC,kFAAkF;IAClF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEL,eAAO,MAAM,WAAW,6GAmEtB,CAAC;AAEH,8GAA8G;AAC9G,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,+BAItE"}
|
package/dist/collapsible.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { collapsibleRecipe, validateCollapsibleOpenState, } from "@hjmds/design-contracts/components/collapsible";
|
|
3
4
|
import { forwardRef, useId, useLayoutEffect, useRef, useState } from "react";
|
package/dist/collapsible.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collapsible.js","sourceRoot":"","sources":["../src/collapsible.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n collapsibleRecipe,\n validateCollapsibleOpenState,\n type CollapsibleOpenState,\n} from \"@hjmds/design-contracts/components/collapsible\";\nimport { forwardRef, useId, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { assignRef, classNames } from \"./internal.js\";\nimport { Icon } from \"./supplemental-display.js\";\nimport { Spinner } from \"./internal/spinner.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type CollapsibleProps = CollapsibleOpenState &\n Readonly<{\n /** The control's label; it also tells the user what will appear. */\n trigger: ReactNode;\n /** Accessible action name when the trigger is artwork or has a shorter visible label. */\n triggerLabel?: string;\n /** Static heading beside the disclosure action, outside the button's accessible name. */\n title?: ReactNode;\n /** While content is being prepared, replace the action with one labeled spinner. */\n pendingLabel?: string;\n children: ReactNode;\n disabled?: boolean;\n /** Inline tools stay expanded without a disclosure trigger. */\n presentation?: \"disclosure\" | \"inline\";\n /** Preserve local input state while hidden; hidden content stays inaccessible. */\n keepMounted?: boolean;\n /**\n * `none` leaves the open/closed mark to the trigger, which then places `CollapsibleMarker` itself — for triggers\n * whose label is not a single row, where the end-aligned mark floated alone (FolderPreview, 2026-10-17 review).\n */\n marker?: \"end\" | \"none\";\n className?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n }>;\n\nexport const Collapsible = forwardRef<HTMLDivElement, CollapsibleProps>(function Collapsible(\n { trigger, triggerLabel, title, pendingLabel, children, disabled = false, presentation = \"disclosure\", keepMounted = false, marker = \"end\", className, layoutStyle, ...openState },\n forwardedRef,\n) {\n validateCollapsibleOpenState(openState as CollapsibleOpenState);\n const controlled = openState.open !== undefined;\n const [internalOpen, setInternalOpen] = useState(openState.defaultOpen ?? false);\n const open = presentation === \"inline\" || (openState.open ?? internalOpen);\n const host = useRef<HTMLDivElement>(null);\n const button = useRef<HTMLButtonElement>(null);\n const content = useRef<HTMLDivElement>(null);\n const focusedContent = useRef(false);\n const contentOpen = open && pendingLabel === undefined;\n const wasOpen = useRef(contentOpen);\n useLayoutEffect(() => {\n // A controlled close can remove or hide the currently focused input without\n // activating the trigger. Recover only that focus, never an outside control.\n const active = host.current?.ownerDocument.activeElement;\n if (wasOpen.current && !contentOpen && focusedContent.current &&\n (content.current?.contains(active ?? null) || active === host.current?.ownerDocument.body)) {\n (disabled || pendingLabel !== undefined ? host.current : button.current)?.focus();\n }\n if (!contentOpen) focusedContent.current = false;\n wasOpen.current = contentOpen;\n }, [contentOpen, disabled, pendingLabel]);\n const id = `${useId().replaceAll(\":\", \"\")}-collapsible`;\n return (\n <div\n ref={node => { host.current = node; assignRef(forwardedRef, node); }}\n tabIndex={-1}\n className={classNames(\"hjm-collapsible\", className)}\n data-state={open ? \"open\" : \"closed\"}\n aria-busy={pendingLabel === undefined ? undefined : true}\n style={{ ...layoutStyle, \"--hjm-collapsible-gap\": `${collapsibleRecipe.gap}px` } as CSSProperties}\n >\n <div className=\"hjm-collapsible__header\" data-titled={title == null ? undefined : true} hidden={presentation === \"inline\"}>\n {title == null ? null : <div className=\"hjm-collapsible__title\">{title}</div>}\n {pendingLabel === undefined ? <button\n ref={button}\n hidden={presentation === \"inline\"}\n type=\"button\"\n className=\"hjm-collapsible__trigger\"\n aria-label={triggerLabel}\n aria-expanded={open}\n aria-controls={`${id}-content`}\n disabled={disabled}\n onClick={event => {\n if (disabled || presentation === \"inline\") return;\n // Safari does not focus buttons on pointer activation; keep the closing\n // disclosure as the keyboard origin before its focused content disappears.\n if (open) event.currentTarget.focus();\n const next = !open;\n if (!controlled) setInternalOpen(next);\n openState.onOpenChange?.(next);\n }}\n >\n {trigger}\n {marker === \"end\" ? <CollapsibleMarker open={open} /> : null}\n </button> : <span className=\"hjm-collapsible__pending\"><Spinner label={pendingLabel} size=\"small\" /></span>}\n </div>\n {/* Optional persistence keeps theme changes and closing tools from erasing local\n drafts. The HTML hidden boundary removes closed content from focus and speech. */}\n {contentOpen || keepMounted ? (\n <div ref={content} onFocusCapture={() => { focusedContent.current = true; }} onBlurCapture={event => { if (event.relatedTarget instanceof Node && !event.currentTarget.contains(event.relatedTarget)) focusedContent.current = false; }} hidden={!contentOpen} id={`${id}-content`} role=\"region\" className=\"hjm-collapsible__content\">{children}</div>\n ) : null}\n </div>\n );\n});\n\n/** The decorative open/closed mark; the expanded state itself travels through the trigger's aria-expanded. */\nexport function CollapsibleMarker({ open }: Readonly<{ open: boolean }>) {\n // The shared chevron at glyph.sm: the text \"▸\" rendered about 8px and read as static text (2026-10-17 review).\n // `chevronEnd` is a logical icon, so Icon mirrors it in RTL.\n return <span aria-hidden=\"true\" className=\"hjm-collapsible__marker\" data-state={open ? \"open\" : \"closed\"}><Icon name={open ? \"chevronDown\" : \"chevronEnd\"} size=\"sm\" tone=\"secondary\" decorative /></span>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"collapsible.js","sourceRoot":"","sources":["../src/collapsible.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport {\n collapsibleRecipe,\n validateCollapsibleOpenState,\n type CollapsibleOpenState,\n} from \"@hjmds/design-contracts/components/collapsible\";\nimport { forwardRef, useId, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from \"react\";\nimport { assignRef, classNames } from \"./internal.js\";\nimport { Icon } from \"./supplemental-display.js\";\nimport { Spinner } from \"./internal/spinner.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type CollapsibleProps = CollapsibleOpenState &\n Readonly<{\n /** The control's label; it also tells the user what will appear. */\n trigger: ReactNode;\n /** Accessible action name when the trigger is artwork or has a shorter visible label. */\n triggerLabel?: string;\n /** Static heading beside the disclosure action, outside the button's accessible name. */\n title?: ReactNode;\n /** While content is being prepared, replace the action with one labeled spinner. */\n pendingLabel?: string;\n children: ReactNode;\n disabled?: boolean;\n /** Inline tools stay expanded without a disclosure trigger. */\n presentation?: \"disclosure\" | \"inline\";\n /** Preserve local input state while hidden; hidden content stays inaccessible. */\n keepMounted?: boolean;\n /**\n * `none` leaves the open/closed mark to the trigger, which then places `CollapsibleMarker` itself — for triggers\n * whose label is not a single row, where the end-aligned mark floated alone (FolderPreview, 2026-10-17 review).\n */\n marker?: \"end\" | \"none\";\n className?: string;\n /** Canonical layout-only placement on the root element. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n }>;\n\nexport const Collapsible = forwardRef<HTMLDivElement, CollapsibleProps>(function Collapsible(\n { trigger, triggerLabel, title, pendingLabel, children, disabled = false, presentation = \"disclosure\", keepMounted = false, marker = \"end\", className, layoutStyle, ...openState },\n forwardedRef,\n) {\n validateCollapsibleOpenState(openState as CollapsibleOpenState);\n const controlled = openState.open !== undefined;\n const [internalOpen, setInternalOpen] = useState(openState.defaultOpen ?? false);\n const open = presentation === \"inline\" || (openState.open ?? internalOpen);\n const host = useRef<HTMLDivElement>(null);\n const button = useRef<HTMLButtonElement>(null);\n const content = useRef<HTMLDivElement>(null);\n const focusedContent = useRef(false);\n const contentOpen = open && pendingLabel === undefined;\n const wasOpen = useRef(contentOpen);\n useLayoutEffect(() => {\n // A controlled close can remove or hide the currently focused input without\n // activating the trigger. Recover only that focus, never an outside control.\n const active = host.current?.ownerDocument.activeElement;\n if (wasOpen.current && !contentOpen && focusedContent.current &&\n (content.current?.contains(active ?? null) || active === host.current?.ownerDocument.body)) {\n (disabled || pendingLabel !== undefined ? host.current : button.current)?.focus();\n }\n if (!contentOpen) focusedContent.current = false;\n wasOpen.current = contentOpen;\n }, [contentOpen, disabled, pendingLabel]);\n const id = `${useId().replaceAll(\":\", \"\")}-collapsible`;\n return (\n <div\n ref={node => { host.current = node; assignRef(forwardedRef, node); }}\n tabIndex={-1}\n className={classNames(\"hjm-collapsible\", className)}\n data-state={open ? \"open\" : \"closed\"}\n aria-busy={pendingLabel === undefined ? undefined : true}\n style={{ ...layoutStyle, \"--hjm-collapsible-gap\": `${collapsibleRecipe.gap}px` } as CSSProperties}\n >\n <div className=\"hjm-collapsible__header\" data-titled={title == null ? undefined : true} hidden={presentation === \"inline\"}>\n {title == null ? null : <div className=\"hjm-collapsible__title\">{title}</div>}\n {pendingLabel === undefined ? <button\n ref={button}\n hidden={presentation === \"inline\"}\n type=\"button\"\n className=\"hjm-collapsible__trigger\"\n aria-label={triggerLabel}\n aria-expanded={open}\n aria-controls={`${id}-content`}\n disabled={disabled}\n onClick={event => {\n if (disabled || presentation === \"inline\") return;\n // Safari does not focus buttons on pointer activation; keep the closing\n // disclosure as the keyboard origin before its focused content disappears.\n if (open) event.currentTarget.focus();\n const next = !open;\n if (!controlled) setInternalOpen(next);\n openState.onOpenChange?.(next);\n }}\n >\n {trigger}\n {marker === \"end\" ? <CollapsibleMarker open={open} /> : null}\n </button> : <span className=\"hjm-collapsible__pending\"><Spinner label={pendingLabel} size=\"small\" /></span>}\n </div>\n {/* Optional persistence keeps theme changes and closing tools from erasing local\n drafts. The HTML hidden boundary removes closed content from focus and speech. */}\n {contentOpen || keepMounted ? (\n <div ref={content} onFocusCapture={() => { focusedContent.current = true; }} onBlurCapture={event => { if (event.relatedTarget instanceof Node && !event.currentTarget.contains(event.relatedTarget)) focusedContent.current = false; }} hidden={!contentOpen} id={`${id}-content`} role=\"region\" className=\"hjm-collapsible__content\">{children}</div>\n ) : null}\n </div>\n );\n});\n\n/** The decorative open/closed mark; the expanded state itself travels through the trigger's aria-expanded. */\nexport function CollapsibleMarker({ open }: Readonly<{ open: boolean }>) {\n // The shared chevron at glyph.sm: the text \"▸\" rendered about 8px and read as static text (2026-10-17 review).\n // `chevronEnd` is a logical icon, so Icon mirrors it in RTL.\n return <span aria-hidden=\"true\" className=\"hjm-collapsible__marker\" data-state={open ? \"open\" : \"closed\"}><Icon name={open ? \"chevronDown\" : \"chevronEnd\"} size=\"sm\" tone=\"secondary\" decorative /></span>;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection-rail.d.ts","sourceRoot":"","sources":["../src/collection-rail.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"collection-rail.d.ts","sourceRoot":"","sources":["../src/collection-rail.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAqC,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC/F,OAAO,EAG4B,KAAK,kBAAkB,EAAE,KAAK,qBAAqB,EACrF,MAAM,yCAAyC,CAAC;AAKjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AACpG,MAAM,MAAM,mBAAmB,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,IAAI,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC;IAClJ,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC;IAC7E,MAAM,EAAE,oBAAoB,CAAC;IAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAAC,YAAY,CAAC,EAAE,SAAS,CAAC;IACxF,6FAA6F;IAC7F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qGAAqG;IACrG,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AAEH,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,IAAI,SAAS,kBAAkB,GAAG,kBAAkB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,OAA+C,EACtK,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAa,EAAE,cAAqB,EAAE,WAAW,EAAE,GAAG,KAAK,EAAE,EAAE,mBAAmB,CAAC,IAAI,CAAC,+BA8H1I"}
|
package/dist/collection-rail.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useLayoutEffect, useRef, useState } from "react";
|
|
3
4
|
import { collectionRailRecipe, validateCollectionRail, resolveCollectionRailLayout, resolveCollectionRailViewport, getCollectionRailTargetOffset, getCollectionRailItemOffset, getCollectionRailRevealOffset, getCollectionRailKeyboardIntent, } from "@hjmds/design-contracts/collection-rail";
|
|
5
|
+
import { spacing } from "@hjmds/design-contracts/foundations";
|
|
4
6
|
import { IconButton } from "./actions.js";
|
|
5
7
|
import { Icon } from "./supplemental-display.js";
|
|
6
8
|
import { useOptionalHjmTheme } from "./provider.js";
|
|
@@ -10,7 +12,7 @@ export function CollectionRail({ label, items, renderItem, labels, density = col
|
|
|
10
12
|
if (!label.trim() || Object.values(labels).some(value => !value.trim()))
|
|
11
13
|
throw new TypeError("CollectionRail labels must not be empty");
|
|
12
14
|
const theme = useOptionalHjmTheme(), direction = theme?.environment.direction ?? "ltr";
|
|
13
|
-
const gap = collectionRailRecipe.
|
|
15
|
+
const gap = spacing[collectionRailRecipe.gapSteps[density]];
|
|
14
16
|
const viewportRef = useRef(null);
|
|
15
17
|
const detachedFocus = useRef(null);
|
|
16
18
|
useLayoutEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection-rail.js","sourceRoot":"","sources":["../src/collection-rail.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport {\n collectionRailRecipe, validateCollectionRail, resolveCollectionRailLayout, resolveCollectionRailViewport,\n getCollectionRailTargetOffset, getCollectionRailItemOffset, getCollectionRailRevealOffset,\n getCollectionRailKeyboardIntent, type CollectionRailItem, type CollectionRailDensity, type CollectionRailLayout,\n} from \"@hjmds/design-contracts/collection-rail\";\nimport { IconButton } from \"./actions.js\";\nimport { Icon } from \"./supplemental-display.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type CollectionRailLabels = Readonly<{ previous: string; next: string; navigation: string }>;\nexport type CollectionRailProps<Item extends CollectionRailItem = CollectionRailItem> = Omit<HTMLAttributes<HTMLDivElement>, \"children\"> & Readonly<{\n label: string; items: readonly Item[]; renderItem: (item: Item) => ReactNode;\n labels: CollectionRailLabels; density?: CollectionRailDensity; emptyContent?: ReactNode;\n /** Initial scroll anchor, not selection. Later collection changes reconcile by stable ID. */\n defaultStartKey?: string;\n /** Observed leading item, independent of product selection/detail state. Empty lists report null. */\n onStartKeyChange?: (key: string | null) => void;\n /**\n * Scroll to the screen edges from inside the default inset ScreenLayout body: the viewport reaches past the body\n * gutter (`--hjm-screen-body-inline`) and pads it back, so the first and last items rest on the gutter (no\n * `body-edge` + per-section gutter, spint home 2026-10-17). Place the rail directly in the body.\n */\n bleed?: boolean;\n /** Hide the button row when touch scrolling is the intended navigation. */\n showNavigation?: boolean;\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Finite all-mounted list placement; Card, inputs and Dialog keep their own state. */\nexport function CollectionRail<Item extends CollectionRailItem = CollectionRailItem>({ label, items, renderItem, labels, density = collectionRailRecipe.defaults.density,\n emptyContent, defaultStartKey, onStartKeyChange, bleed = false, showNavigation = true, layoutStyle, ...props }: CollectionRailProps<Item>) {\n validateCollectionRail(items);\n if (!label.trim() || Object.values(labels).some(value => !value.trim())) throw new TypeError(\"CollectionRail labels must not be empty\");\n const theme = useOptionalHjmTheme(), direction = theme?.environment.direction ?? \"ltr\";\n const gap = collectionRailRecipe.gap;\n const viewportRef = useRef<HTMLDivElement>(null);\n const detachedFocus = useRef<HTMLElement | null>(null);\n useLayoutEffect(() => {\n const old = detachedFocus.current;\n detachedFocus.current = null;\n // A removed card must leave a keyboard origin in this collection, without\n // moving focus away from a surviving input or an external control.\n if (old && !old.isConnected && old.ownerDocument.activeElement === old.ownerDocument.body) {\n viewportRef.current?.focus({ preventScroll: true });\n }\n });\n const anchor = useRef<string | null>(defaultStartKey ?? items[0]?.id ?? null);\n const initialized = useRef(false);\n if (!initialized.current) { validateCollectionRail(items, defaultStartKey); initialized.current = true; }\n const callback = useRef(onStartKeyChange); callback.current = onStartKeyChange;\n const current = useRef({ layout: resolveCollectionRailLayout(items.length, 0, density, gap), offset: 0 });\n const pendingOffset = useRef<number | null>(null);\n const [position, setPosition] = useState(current.current);\n const identity = JSON.stringify(items.map(item => item.id));\n const itemsRef = useRef(items); itemsRef.current = items;\n\n function publish(layout: CollectionRailLayout, offset: number) {\n const resolved = resolveCollectionRailViewport(layout, offset);\n const key = itemsRef.current[resolved.startIndex]?.id ?? null;\n if (key !== anchor.current) { anchor.current = key; callback.current?.(key); }\n current.current = { layout, offset: resolved.offset };\n setPosition(current.current);\n }\n function scrollToOffset(offset: number, animated: boolean) {\n const viewport = viewportRef.current;\n if (!viewport) return;\n const resolved = resolveCollectionRailViewport(current.current.layout, offset);\n // CSS RTL scrollLeft is negative; clamp Safari rubber-banding through the\n // shared logical resolver rather than reversing data or selection keys.\n viewport.scrollTo({ left: direction === \"rtl\" ? -resolved.offset : resolved.offset,\n behavior: animated && !theme?.environment.reducedMotion ? \"smooth\" : \"instant\" });\n pendingOffset.current = animated && !theme?.environment.reducedMotion ? resolved.offset : null;\n // Smooth scroll is a request, not an observed viewport. Publishing its\n // destination now would disable the end action and report an unseen anchor.\n publish(current.current.layout, direction === \"rtl\" ? -viewport.scrollLeft : viewport.scrollLeft);\n }\n useLayoutEffect(() => {\n const viewport = viewportRef.current;\n if (!viewport) return;\n let initialMeasurement = true;\n function measure() {\n // clientWidth includes the bleed padding; item geometry uses the gutter-aligned box inside it.\n const style = getComputedStyle(viewport!);\n const room = (parseFloat(style.paddingLeft) || 0) + (parseFloat(style.paddingRight) || 0);\n const next = resolveCollectionRailLayout(itemsRef.current.length, Math.max(0, viewport!.clientWidth - room), density, gap);\n // ResizeObserver also delivers an initial unchanged box. Re-aligning then\n // would undo a focus reveal that happened after the layout effect.\n if (!initialMeasurement && next.viewport === current.current.layout.viewport) return;\n initialMeasurement = false;\n pendingOffset.current = null;\n const index = Math.max(0, itemsRef.current.findIndex(item => item.id === anchor.current));\n let offset = next.count ? getCollectionRailItemOffset(next, index) : 0;\n const focused = document.activeElement?.closest(\"[data-collection-rail-item]\");\n const focusedIndex = focused && viewport!.contains(focused)\n ? itemsRef.current.findIndex(item => item.id === focused.getAttribute(\"data-collection-rail-item\")) : -1;\n // A narrower viewport cannot keep a distant focused action and the old\n // leading item visible together; focus exposure takes priority over anchor alignment.\n if (focusedIndex >= 0) offset = getCollectionRailRevealOffset(next, offset, focusedIndex);\n current.current = { layout: next, offset };\n // Width/direction changes keep the leading item's identity, and never\n // key/remount its input or detail owner (docs/collection-rail.md).\n viewport!.scrollTo({ left: direction === \"rtl\" ? -offset : offset, behavior: \"instant\" });\n publish(next, offset);\n }\n measure();\n const observer = new ResizeObserver(measure); observer.observe(viewport);\n return () => observer.disconnect();\n }, [identity, density, gap, direction, bleed]);\n\n function navigate(intent: \"previous\" | \"next\" | \"first\" | \"last\") {\n scrollToOffset(getCollectionRailTargetOffset(current.current.layout, pendingOffset.current ?? current.current.offset, intent), true);\n }\n const resolved = resolveCollectionRailViewport(position.layout, position.offset);\n return <div {...props} style={{ ...props.style, ...layoutStyle, minWidth: 0 }}\n data-collection-rail data-start-key={items[resolved.startIndex]?.id} dir={direction}\n onKeyDown={event => {\n props.onKeyDown?.(event);\n if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n // Item widgets own arrows/Home/End. Rail navigation belongs only to its\n // viewport and explicit controls, not an input nested in a visible card.\n if (event.target !== viewportRef.current && !(event.target instanceof Element && event.target.closest(\"[data-collection-rail-controls]\"))) return;\n const intent = getCollectionRailKeyboardIntent(event.key, direction);\n if (intent) { event.preventDefault(); navigate(intent); }\n }}>\n <div ref={viewportRef} role=\"list\" aria-label={label} tabIndex={0} data-collection-rail-viewport data-bleed={bleed || undefined}\n className=\"hjm-collection-rail__viewport\"\n style={{ overflowX: \"auto\", overscrollBehaviorX: \"contain\", minWidth: 0 }}\n onPointerDown={() => { pendingOffset.current = null; }} onWheel={() => { pendingOffset.current = null; }}\n onScroll={event => {\n const offset = direction === \"rtl\" ? -event.currentTarget.scrollLeft : event.currentTarget.scrollLeft;\n if (pendingOffset.current !== null && Math.abs(offset - pendingOffset.current) <= 0.5) pendingOffset.current = null;\n publish(current.current.layout, offset);\n }}>\n <div style={{ display: \"flex\", gap, width: \"max-content\", minWidth: \"100%\", paddingBlock: \"var(--hjm-space-xs)\" }}>\n {items.map((item, index) => <div key={item.id} role=\"listitem\" data-collection-rail-item={item.id}\n ref={node => {\n if (!node) return;\n return () => {\n const active = node.ownerDocument.activeElement;\n if (active instanceof HTMLElement && node.contains(active)) detachedFocus.current = active;\n };\n }}\n style={{ flex: \"0 0 auto\", width: position.layout.itemWidth || \"auto\", minWidth: 0 }}\n onFocusCapture={() => scrollToOffset(getCollectionRailRevealOffset(current.current.layout, current.current.offset, index), false)}>\n {renderItem(item)}\n </div>)}\n </div>\n {items.length === 0 ? emptyContent : null}\n </div>\n {showNavigation && <div data-collection-rail-controls role=\"group\" aria-label={labels.navigation}\n style={{ display: \"flex\", flexWrap: \"wrap\", justifyContent: \"flex-end\", gap: \"var(--hjm-space-xs)\", marginBlockStart: \"var(--hjm-space-sm)\" }}>\n {/* Tool actions: icon buttons named by the localized label, as Carousel (2026-10-17 review E9). */}\n <IconButton label={labels.previous} tone=\"ghost\" aria-disabled={resolved.atStart} onClick={() => navigate(\"previous\")}><Icon name=\"chevronStart\" /></IconButton>\n <IconButton label={labels.next} tone=\"ghost\" aria-disabled={resolved.atEnd} onClick={() => navigate(\"next\")}><Icon name=\"chevronEnd\" /></IconButton>\n </div>}\n </div>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"collection-rail.js","sourceRoot":"","sources":["../src/collection-rail.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { useLayoutEffect, useRef, useState, type HTMLAttributes, type ReactNode } from \"react\";\nimport {\n collectionRailRecipe, validateCollectionRail, resolveCollectionRailLayout, resolveCollectionRailViewport,\n getCollectionRailTargetOffset, getCollectionRailItemOffset, getCollectionRailRevealOffset,\n getCollectionRailKeyboardIntent, type CollectionRailItem, type CollectionRailDensity, type CollectionRailLayout,\n} from \"@hjmds/design-contracts/collection-rail\";\nimport { spacing } from \"@hjmds/design-contracts/foundations\";\nimport { IconButton } from \"./actions.js\";\nimport { Icon } from \"./supplemental-display.js\";\nimport { useOptionalHjmTheme } from \"./provider.js\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\n\nexport type CollectionRailLabels = Readonly<{ previous: string; next: string; navigation: string }>;\nexport type CollectionRailProps<Item extends CollectionRailItem = CollectionRailItem> = Omit<HTMLAttributes<HTMLDivElement>, \"children\"> & Readonly<{\n label: string; items: readonly Item[]; renderItem: (item: Item) => ReactNode;\n labels: CollectionRailLabels; density?: CollectionRailDensity; emptyContent?: ReactNode;\n /** Initial scroll anchor, not selection. Later collection changes reconcile by stable ID. */\n defaultStartKey?: string;\n /** Observed leading item, independent of product selection/detail state. Empty lists report null. */\n onStartKeyChange?: (key: string | null) => void;\n /**\n * Scroll to the screen edges from inside the default inset ScreenLayout body: the viewport reaches past the body\n * gutter (`--hjm-screen-body-inline`) and pads it back, so the first and last items rest on the gutter (no\n * `body-edge` + per-section gutter, spint home 2026-10-17). Place the rail directly in the body.\n */\n bleed?: boolean;\n /** Hide the button row when touch scrolling is the intended navigation. */\n showNavigation?: boolean;\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n\n/** Finite all-mounted list placement; Card, inputs and Dialog keep their own state. */\nexport function CollectionRail<Item extends CollectionRailItem = CollectionRailItem>({ label, items, renderItem, labels, density = collectionRailRecipe.defaults.density,\n emptyContent, defaultStartKey, onStartKeyChange, bleed = false, showNavigation = true, layoutStyle, ...props }: CollectionRailProps<Item>) {\n validateCollectionRail(items);\n if (!label.trim() || Object.values(labels).some(value => !value.trim())) throw new TypeError(\"CollectionRail labels must not be empty\");\n const theme = useOptionalHjmTheme(), direction = theme?.environment.direction ?? \"ltr\";\n const gap = spacing[collectionRailRecipe.gapSteps[density]];\n const viewportRef = useRef<HTMLDivElement>(null);\n const detachedFocus = useRef<HTMLElement | null>(null);\n useLayoutEffect(() => {\n const old = detachedFocus.current;\n detachedFocus.current = null;\n // A removed card must leave a keyboard origin in this collection, without\n // moving focus away from a surviving input or an external control.\n if (old && !old.isConnected && old.ownerDocument.activeElement === old.ownerDocument.body) {\n viewportRef.current?.focus({ preventScroll: true });\n }\n });\n const anchor = useRef<string | null>(defaultStartKey ?? items[0]?.id ?? null);\n const initialized = useRef(false);\n if (!initialized.current) { validateCollectionRail(items, defaultStartKey); initialized.current = true; }\n const callback = useRef(onStartKeyChange); callback.current = onStartKeyChange;\n const current = useRef({ layout: resolveCollectionRailLayout(items.length, 0, density, gap), offset: 0 });\n const pendingOffset = useRef<number | null>(null);\n const [position, setPosition] = useState(current.current);\n const identity = JSON.stringify(items.map(item => item.id));\n const itemsRef = useRef(items); itemsRef.current = items;\n\n function publish(layout: CollectionRailLayout, offset: number) {\n const resolved = resolveCollectionRailViewport(layout, offset);\n const key = itemsRef.current[resolved.startIndex]?.id ?? null;\n if (key !== anchor.current) { anchor.current = key; callback.current?.(key); }\n current.current = { layout, offset: resolved.offset };\n setPosition(current.current);\n }\n function scrollToOffset(offset: number, animated: boolean) {\n const viewport = viewportRef.current;\n if (!viewport) return;\n const resolved = resolveCollectionRailViewport(current.current.layout, offset);\n // CSS RTL scrollLeft is negative; clamp Safari rubber-banding through the\n // shared logical resolver rather than reversing data or selection keys.\n viewport.scrollTo({ left: direction === \"rtl\" ? -resolved.offset : resolved.offset,\n behavior: animated && !theme?.environment.reducedMotion ? \"smooth\" : \"instant\" });\n pendingOffset.current = animated && !theme?.environment.reducedMotion ? resolved.offset : null;\n // Smooth scroll is a request, not an observed viewport. Publishing its\n // destination now would disable the end action and report an unseen anchor.\n publish(current.current.layout, direction === \"rtl\" ? -viewport.scrollLeft : viewport.scrollLeft);\n }\n useLayoutEffect(() => {\n const viewport = viewportRef.current;\n if (!viewport) return;\n let initialMeasurement = true;\n function measure() {\n // clientWidth includes the bleed padding; item geometry uses the gutter-aligned box inside it.\n const style = getComputedStyle(viewport!);\n const room = (parseFloat(style.paddingLeft) || 0) + (parseFloat(style.paddingRight) || 0);\n const next = resolveCollectionRailLayout(itemsRef.current.length, Math.max(0, viewport!.clientWidth - room), density, gap);\n // ResizeObserver also delivers an initial unchanged box. Re-aligning then\n // would undo a focus reveal that happened after the layout effect.\n if (!initialMeasurement && next.viewport === current.current.layout.viewport) return;\n initialMeasurement = false;\n pendingOffset.current = null;\n const index = Math.max(0, itemsRef.current.findIndex(item => item.id === anchor.current));\n let offset = next.count ? getCollectionRailItemOffset(next, index) : 0;\n const focused = document.activeElement?.closest(\"[data-collection-rail-item]\");\n const focusedIndex = focused && viewport!.contains(focused)\n ? itemsRef.current.findIndex(item => item.id === focused.getAttribute(\"data-collection-rail-item\")) : -1;\n // A narrower viewport cannot keep a distant focused action and the old\n // leading item visible together; focus exposure takes priority over anchor alignment.\n if (focusedIndex >= 0) offset = getCollectionRailRevealOffset(next, offset, focusedIndex);\n current.current = { layout: next, offset };\n // Width/direction changes keep the leading item's identity, and never\n // key/remount its input or detail owner (docs/collection-rail.md).\n viewport!.scrollTo({ left: direction === \"rtl\" ? -offset : offset, behavior: \"instant\" });\n publish(next, offset);\n }\n measure();\n const observer = new ResizeObserver(measure); observer.observe(viewport);\n return () => observer.disconnect();\n }, [identity, density, gap, direction, bleed]);\n\n function navigate(intent: \"previous\" | \"next\" | \"first\" | \"last\") {\n scrollToOffset(getCollectionRailTargetOffset(current.current.layout, pendingOffset.current ?? current.current.offset, intent), true);\n }\n const resolved = resolveCollectionRailViewport(position.layout, position.offset);\n return <div {...props} style={{ ...props.style, ...layoutStyle, minWidth: 0 }}\n data-collection-rail data-start-key={items[resolved.startIndex]?.id} dir={direction}\n onKeyDown={event => {\n props.onKeyDown?.(event);\n if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n // Item widgets own arrows/Home/End. Rail navigation belongs only to its\n // viewport and explicit controls, not an input nested in a visible card.\n if (event.target !== viewportRef.current && !(event.target instanceof Element && event.target.closest(\"[data-collection-rail-controls]\"))) return;\n const intent = getCollectionRailKeyboardIntent(event.key, direction);\n if (intent) { event.preventDefault(); navigate(intent); }\n }}>\n <div ref={viewportRef} role=\"list\" aria-label={label} tabIndex={0} data-collection-rail-viewport data-bleed={bleed || undefined}\n className=\"hjm-collection-rail__viewport\"\n style={{ overflowX: \"auto\", overscrollBehaviorX: \"contain\", minWidth: 0 }}\n onPointerDown={() => { pendingOffset.current = null; }} onWheel={() => { pendingOffset.current = null; }}\n onScroll={event => {\n const offset = direction === \"rtl\" ? -event.currentTarget.scrollLeft : event.currentTarget.scrollLeft;\n if (pendingOffset.current !== null && Math.abs(offset - pendingOffset.current) <= 0.5) pendingOffset.current = null;\n publish(current.current.layout, offset);\n }}>\n <div style={{ display: \"flex\", gap, width: \"max-content\", minWidth: \"100%\", paddingBlock: \"var(--hjm-space-xs)\" }}>\n {items.map((item, index) => <div key={item.id} role=\"listitem\" data-collection-rail-item={item.id}\n ref={node => {\n if (!node) return;\n return () => {\n const active = node.ownerDocument.activeElement;\n if (active instanceof HTMLElement && node.contains(active)) detachedFocus.current = active;\n };\n }}\n style={{ flex: \"0 0 auto\", width: position.layout.itemWidth || \"auto\", minWidth: 0 }}\n onFocusCapture={() => scrollToOffset(getCollectionRailRevealOffset(current.current.layout, current.current.offset, index), false)}>\n {renderItem(item)}\n </div>)}\n </div>\n {items.length === 0 ? emptyContent : null}\n </div>\n {showNavigation && <div data-collection-rail-controls role=\"group\" aria-label={labels.navigation}\n style={{ display: \"flex\", flexWrap: \"wrap\", justifyContent: \"flex-end\", gap: \"var(--hjm-space-xs)\", marginBlockStart: \"var(--hjm-space-sm)\" }}>\n {/* Tool actions: icon buttons named by the localized label, as Carousel (2026-10-17 review E9). */}\n <IconButton label={labels.previous} tone=\"ghost\" aria-disabled={resolved.atStart} onClick={() => navigate(\"previous\")}><Icon name=\"chevronStart\" /></IconButton>\n <IconButton label={labels.next} tone=\"ghost\" aria-disabled={resolved.atEnd} onClick={() => navigate(\"next\")}><Icon name=\"chevronEnd\" /></IconButton>\n </div>}\n </div>;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-picker.d.ts","sourceRoot":"","sources":["../src/color-picker.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"color-picker.d.ts","sourceRoot":"","sources":["../src/color-picker.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAC3G,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChG,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjE,qGAAqG;IACrG,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC,CAAC,CAAC;AACH,gHAAgH;AAChH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,KAAa,EAAE,QAAgB,EAAE,OAAY,EAAE,WAAW,EAAE,EAAE,gBAAgB,+BAoChJ"}
|
package/dist/color-picker.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useEffect, useId, useRef, useState } from "react";
|
|
3
4
|
import { colorPickerRecipe, normalizePickerColor, pickerOpacity, withPickerOpacity } from "@hjmds/design-contracts/components/color-picker";
|
package/dist/color-picker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-picker.js","sourceRoot":"","sources":["../src/color-picker.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"color-picker.js","sourceRoot":"","sources":["../src/color-picker.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useRef, useState, type CSSProperties } from \"react\";\nimport type { HjmCompositionStyleProp } from \"./composition-style.js\";\nimport { colorPickerRecipe, normalizePickerColor, pickerOpacity, withPickerOpacity } from \"@hjmds/design-contracts/components/color-picker\";\nexport type ColorPickerLabels = Readonly<{ color: string; hex: string; opacity: string; invalid: string }>;\nexport type ColorPickerProps = Readonly<{\n label: string; labels: ColorPickerLabels; value: string; onValueChange: (value: string) => void;\n alpha?: boolean; disabled?: boolean; presets?: readonly string[];\n /** Canonical layout-only placement on the root `<fieldset>`. Controlled visual keys are excluded. */\n layoutStyle?: HjmCompositionStyleProp;\n}>;\n/** Controlled value; invalid text stays local until corrected or escaped. Native color UI supplies RGB only. */\nexport function ColorPicker({ label, labels, value, onValueChange, alpha = false, disabled = false, presets = [], layoutStyle }: ColorPickerProps) {\n const color = normalizePickerColor(value, alpha);\n // HEX is an ordered code, so isolate its LTR text even when the surrounding labels use RTL.\n const palette = [...new Set(presets.map(preset => normalizePickerColor(preset, alpha)))];\n if (![label, ...Object.values(labels)].every(text => text.trim())) throw new TypeError(\"ColorPicker labels must not be empty\");\n const id = useId();\n const [draft, setDraft] = useState(color);\n const [invalid, setInvalid] = useState(false);\n // Enter consumes this edit; its following blur must not resend a deferred controlled request.\n const draftChanged = useRef(false);\n useEffect(() => { setDraft(color); setInvalid(false); draftChanged.current = false; }, [color]);\n function emit(next: string) { if (disabled) return; draftChanged.current = false; setDraft(next); setInvalid(false); if (next !== color) onValueChange(next); }\n function commit() {\n if (disabled) return;\n let next: string;\n try {\n // A typed 3/6-digit HEX names only the hue. Keep the current opacity instead of resetting it to 100%,\n // matching the native color input; an 8-digit HEX still sets alpha explicitly (2026-09-30 review).\n const digits = draft.trim().replace(/^#/, \"\").length;\n next = alpha && (digits === 3 || digits === 6) ? normalizePickerColor(draft, false) + color.slice(7) : normalizePickerColor(draft, alpha);\n } catch { setInvalid(true); return; }\n emit(next);\n }\n return <fieldset className=\"hjm-color-picker\" style={{ ...layoutStyle, \"--hjm-color-picker-target\": `${colorPickerRecipe.minTargetSize}px` } as CSSProperties} data-hjm-color-picker disabled={disabled}>\n <legend>{label}</legend>\n <div className=\"hjm-color-picker__row\">\n <label className=\"hjm-color-picker__native\"><span>{labels.color}</span><input type=\"color\" value={color.slice(0, 7)} onChange={event => emit(event.target.value + (alpha ? color.slice(7) : \"\"))} /></label>\n <label className=\"hjm-color-picker__hex\"><span>{labels.hex}</span><input type=\"text\" dir=\"ltr\" value={draft} spellCheck={false} autoComplete=\"off\" aria-invalid={invalid || undefined} aria-describedby={invalid ? `${id}-error` : undefined}\n onChange={event => { draftChanged.current = true; setDraft(event.target.value); setInvalid(false); }} onBlur={() => { if (draftChanged.current) commit(); }}\n onKeyDown={event => { if (event.nativeEvent.isComposing || event.keyCode === 229) return; if (event.key === \"Enter\") { event.preventDefault(); commit(); } if (event.key === \"Escape\") { event.preventDefault(); draftChanged.current = false; setDraft(color); setInvalid(false); } }} /></label>\n </div>\n {invalid && <p id={`${id}-error`} role=\"alert\" className=\"hjm-color-picker__error\">{labels.invalid}</p>}\n {alpha && <label className=\"hjm-color-picker__opacity\"><span>{labels.opacity} <output>{pickerOpacity(color)}%</output></span><input type=\"range\" min={0} max={100} step={1} value={pickerOpacity(color)} aria-label={labels.opacity} aria-valuetext={`${pickerOpacity(color)}%`} onChange={event => emit(withPickerOpacity(color, Number(event.target.value)))} /></label>}\n <div className=\"hjm-color-picker__preview\" aria-hidden=\"true\" style={{ backgroundColor: color }} />\n {palette.length > 0 && <div className=\"hjm-color-picker__presets\">{palette.map(preset => <button type=\"button\" key={preset} aria-pressed={preset === color} onClick={() => emit(preset)}><span aria-hidden=\"true\" className=\"hjm-color-picker__swatch\" style={{ backgroundColor: preset }} /><bdi dir=\"ltr\">{preset}</bdi></button>)}</div>}\n </fieldset>;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.d.ts","sourceRoot":"","sources":["../src/command-palette.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"command-palette.d.ts","sourceRoot":"","sources":["../src/command-palette.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,6BAA6B,EAElC,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAEhC,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EAC1B,MAAM,oDAAoD,CAAC;AAO5D,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAA0D,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AA4CzG,MAAM,MAAM,mBAAmB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACtE,UAAU,EAAE,wBAAwB,CAAC;IACrC,MAAM,EAAE,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,EAAE,6BAA6B,CAAC,GAAG,CAAC,CAAC;IAC/C,iFAAiF;IACjF,sBAAsB,CAAC,EAAE,6BAA6B,CAAC,GAAG,CAAC,CAAC;IAC5D;;;;;OAKG;IACH,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,aAAa,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACrD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,+BAA+B,KAAK,IAAI,CAAC;IACjF,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,SAAS,CAAC;IAC3C,eAAe,CAAC,EAAE,WAAW,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,eAAO,MAAM,cAAc,EAmNrB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM,EAChC,KAAK,EAAE,mBAAmB,CAAC,GAAG,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;CAAE,KAClE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC"}
|
package/dist/command-palette.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
3
|
import { canDismissCommandPalette, commandPaletteBehaviorDefaults, commandPaletteRecipe, validateCommandPaletteDescriptor, } from "@hjmds/design-contracts/components/command-palette";
|
|
3
4
|
import { getCollectionNavigationIntent, getCollectionNavigationTarget, isComboboxResultCurrent, } from "@hjmds/design-contracts/components/collection";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-palette.js","sourceRoot":"","sources":["../src/command-palette.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n canDismissCommandPalette,\n commandPaletteBehaviorDefaults,\n commandPaletteRecipe,\n validateCommandPaletteDescriptor,\n type CommandPaletteActivateHandler,\n type CommandPaletteActivateReason,\n type CommandPaletteDescriptor,\n type CommandPaletteDismissPolicy,\n type CommandPaletteDismissReason,\n type CommandPaletteOpenChangeDetails,\n type CommandPaletteQueryState,\n type CommandPaletteSource,\n} from \"@hjmds/design-contracts/components/command-palette\";\nimport {\n getCollectionNavigationIntent,\n getCollectionNavigationTarget,\n isComboboxResultCurrent,\n} from \"@hjmds/design-contracts/components/collection\";\nimport type { CommandPaletteItemDescriptor } from \"@hjmds/design-contracts/components/command-palette\";\nimport {\n forwardRef,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { classNames, composeRefs } from \"./internal.js\";\nimport { getModalLayer, HjmPortal, renderTrigger, useModalFocus, type OverlayTrigger } from \"./modal.js\";\n\ntype ResultSection<Key extends string> = Readonly<{\n id: string;\n label: string | undefined;\n name: string | undefined;\n items: readonly CommandPaletteItemDescriptor<Key>[];\n}>;\n\n// Local filter = Native Combobox substring rule; why not prefix/contracts:\n// docs/command-palette.md \"2026-10-06\" (comments ship in dist byte budgets).\nfunction resolveResults<Key extends string>(\n source: CommandPaletteSource<Key, string>,\n query: string,\n queryState: CommandPaletteQueryState | undefined,\n emptyMessage: string | undefined,\n) {\n const external = queryState?.filtering === \"external\";\n const needle = query.trim().toLocaleLowerCase();\n const keep = (item: CommandPaletteItemDescriptor<Key>) =>\n external || `${item.label} ${item.textValue}`.toLocaleLowerCase().includes(needle);\n const sections: ResultSection<Key>[] = (source.sections\n ? source.sections.map((section) => ({\n id: section.id,\n label: section.label,\n // validateCollection's precedence.\n name: section.accessibilityLabel?.trim() || section.label?.trim() || undefined,\n items: section.items.filter(keep),\n }))\n : [{ id: \"__all\", label: undefined, name: undefined, items: source.items.filter(keep) }]\n ).filter((section) => section.items.length > 0);\n const items = sections.flatMap((section) => section.items);\n const asyncState = queryState?.asyncState ?? { status: \"idle\" as const };\n const status = asyncState.status !== \"idle\"\n ? { kind: asyncState.status, message: asyncState.message }\n : items.length > 0 || emptyMessage === undefined ? null : { kind: \"empty\" as const, message: emptyMessage };\n return {\n sections,\n items,\n current: !external || isComboboxResultCurrent(queryState.queryValue, queryState.resultQuery),\n status,\n };\n}\n\nexport type CommandPaletteProps<Key extends string = string> = Readonly<{\n descriptor: CommandPaletteDescriptor;\n source: CommandPaletteSource<Key, string>;\n query: string;\n onQueryChange: (query: string) => void;\n onActivate: CommandPaletteActivateHandler<Key>;\n /** Runs after the palette is gone, for a command that opens the next surface. */\n onActivateAfterDismiss?: CommandPaletteActivateHandler<Key>;\n /**\n * Combobox's collection state. Omitted or `filtering: \"local\"` filters\n * `source` by `query` in the renderer (label/textValue substring); pass\n * `filtering: \"external\"` with `queryValue`/`resultQuery` when the product\n * already filtered or ranked the results (server or fuzzy search).\n */\n queryState?: CommandPaletteQueryState;\n dismissPolicy?: Partial<CommandPaletteDismissPolicy>;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, details: CommandPaletteOpenChangeDetails) => void;\n trigger?: OverlayTrigger;\n renderLeading?: (itemId: Key) => ReactNode;\n portalContainer?: HTMLElement;\n className?: string;\n}>;\n\nexport const CommandPalette = forwardRef(function CommandPalette<Key extends string = string>(\n {\n descriptor,\n source,\n query,\n onQueryChange,\n onActivate,\n onActivateAfterDismiss,\n queryState,\n dismissPolicy,\n open: openProp,\n defaultOpen,\n onOpenChange,\n trigger,\n renderLeading,\n portalContainer,\n className,\n }: CommandPaletteProps<Key>,\n forwardedRef: React.Ref<HTMLDivElement>,\n) {\n validateCommandPaletteDescriptor(descriptor);\n const policy: CommandPaletteDismissPolicy = { ...commandPaletteBehaviorDefaults, ...dismissPolicy };\n const [internalOpen, setInternalOpen] = useState(defaultOpen ?? false);\n const open = openProp ?? internalOpen;\n const results = useMemo(\n () => resolveResults<Key>(source, query, queryState, descriptor.emptyMessage),\n [source, query, queryState, descriptor.emptyMessage],\n );\n // Stale external rows stay visible but inert, as in the Native Combobox.\n const enabled = results.current ? results.items.filter((item) => !item.disabled) : [];\n const [activeId, setActiveId] = useState<Key | null>(null);\n const pendingActivation = useRef<{ itemId: Key; reason: CommandPaletteActivateReason } | null>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const id = `${useId().replaceAll(\":\", \"\")}-command-palette`;\n const active = enabled.find((item) => item.id === activeId) ?? enabled[0] ?? null;\n\n useEffect(() => {\n // A new query builds a new result list; the first enabled row becomes active\n // so Enter always has an unambiguous target. Only the query resets it: products\n // often pass `source`/`queryState` as inline objects, and keying on their\n // identity snapped the active row back to the first item on every render\n // (2026-10-06 usage-guide audit). A row that disappears from the results\n // already falls back to the first enabled row through `active` above.\n setActiveId(null);\n }, [query]);\n\n const change = (next: boolean, reason: CommandPaletteOpenChangeDetails[\"reason\"]) => {\n if (openProp === undefined) setInternalOpen(next);\n onOpenChange?.(next, { reason });\n };\n const requestClose = (reason: CommandPaletteDismissReason) => {\n if (!canDismissCommandPalette(reason, policy)) return;\n change(false, reason);\n };\n const activate = (itemId: Key, reason: CommandPaletteActivateReason) => {\n onActivate(itemId, reason);\n // Running a command always closes the palette — `activation` is a dismiss\n // reason no policy can veto — and the follow-up surface opens after that.\n pendingActivation.current = { itemId, reason };\n change(false, \"activation\");\n };\n\n useModalFocus({\n active: open,\n contentRef,\n initialFocusRef: inputRef,\n ...(trigger === undefined ? {} : { fallbackReturnRef: triggerRef }),\n onEscape: () => requestClose(\"escape\"),\n });\n\n useEffect(() => {\n if (open || !pendingActivation.current) return;\n const { itemId, reason } = pendingActivation.current;\n pendingActivation.current = null;\n // A controlled owner may delay closing; wait for teardown and focus release.\n if (onActivateAfterDismiss) queueMicrotask(() => onActivateAfterDismiss(itemId, reason));\n }, [open, onActivateAfterDismiss]);\n\n const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n // IME confirmation and candidate navigation belong to the text input.\n if (event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return;\n const intent = getCollectionNavigationIntent(event.key as never);\n if (intent) {\n const target = getCollectionNavigationTarget({ items: enabled }, active?.id ?? null, intent, true);\n if (target === undefined) return;\n event.preventDefault();\n setActiveId(target as Key);\n return;\n }\n if (event.key === \"Enter\" && active) {\n event.preventDefault();\n activate(active.id as Key, \"keyboard\");\n }\n };\n\n const searchInput = (\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded\n aria-controls={`${id}-results`}\n aria-activedescendant={active ? `${id}-${active.id}` : undefined}\n aria-label={descriptor.accessibilityLabel}\n placeholder={descriptor.searchPlaceholder}\n className=\"hjm-command-palette__search\"\n value={query}\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={onKeyDown}\n />\n );\n\n const renderedTrigger = trigger === undefined\n ? null\n : renderTrigger(trigger, triggerRef, open, id, \"dialog\", () => change(true, \"trigger\"));\n if (!open) return renderedTrigger;\n\n return (\n <>\n {renderedTrigger}\n <HjmPortal {...(portalContainer === undefined ? {} : { container: portalContainer })}>\n <div\n className=\"hjm-overlay hjm-command-palette-positioner\"\n data-kind=\"command-palette\"\n style={{ zIndex: getModalLayer(0) }}\n onMouseDown={(event) => { if (event.target === event.currentTarget) requestClose(\"outside\"); }}\n >\n <div\n ref={composeRefs(contentRef, forwardedRef)}\n id={id}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={descriptor.accessibilityLabel}\n data-hjm-modal-content=\"\"\n className={classNames(\"hjm-command-palette\", className)}\n style={{ maxInlineSize: commandPaletteRecipe.content.maxWidth, maxBlockSize: commandPaletteRecipe.content.maxHeight } as CSSProperties}\n >\n {/*\n Opt-in through descriptor.closeLabel because the renderer must not\n invent untranslated copy. Reuses Dialog's close chrome instead of a\n second close-button style (styles.css is at its byte budget).\n */}\n {descriptor.closeLabel ? (\n <div className=\"hjm-command-palette__search-row\">\n {searchInput}\n <button\n type=\"button\"\n className=\"hjm-dialog__close hjm-command-palette__close\"\n aria-label={descriptor.closeLabel}\n onClick={() => requestClose(\"close-action\")}\n >\n <span aria-hidden=\"true\">×</span>\n </button>\n </div>\n ) : searchInput}\n <div id={`${id}-results`} role=\"listbox\" aria-label={descriptor.accessibilityLabel} className=\"hjm-command-palette__viewport\">\n {results.status === null ? null : (\n // Once for the whole list, never per section.\n <p\n className=\"hjm-command-palette__state\"\n data-kind={results.status.kind}\n role={results.status.kind === \"error\" ? \"alert\" : \"status\"}\n >\n {results.status.message}\n </p>\n )}\n {results.sections.map((section) => (\n <div\n key={section.id}\n className=\"hjm-command-palette__section\"\n {...(section.name === undefined ? { role: \"presentation\" } : { role: \"group\", \"aria-label\": section.name })}\n >\n {section.label ? <p className=\"hjm-command-palette__section-label\" aria-hidden=\"true\">{section.label}</p> : null}\n {section.items.map((item) => {\n // Positioning or filtering can enter a stationary cursor;\n // only mouse movement should override keyboard navigation.\n const inert = item.disabled === true || !results.current;\n return (\n <div\n key={item.id}\n id={`${id}-${item.id}`}\n role=\"option\"\n aria-selected={item.id === active?.id}\n aria-disabled={inert || undefined}\n className=\"hjm-command-palette__item\"\n data-tone={item.tone}\n onMouseDown={(event) => {\n event.preventDefault();\n if (!inert) activate(item.id as Key, \"pointer\");\n }}\n onMouseMove={() => { if (!inert) setActiveId(item.id as Key); }}\n >\n {renderLeading?.(item.id as Key)}\n <span className=\"hjm-command-palette__copy\">\n <span>{item.label}</span>\n {item.description ? <span className=\"hjm-command-palette__description\">{item.description}</span> : null}\n </span>\n {item.shortcut ? <kbd className=\"hjm-command-palette__shortcut\">{item.shortcut}</kbd> : null}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n </div>\n </HjmPortal>\n </>\n );\n}) as <Key extends string = string>(\n props: CommandPaletteProps<Key> & { ref?: React.Ref<HTMLDivElement> },\n) => React.ReactElement | null;\n"]}
|
|
1
|
+
{"version":3,"file":"command-palette.js","sourceRoot":"","sources":["../src/command-palette.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport {\n canDismissCommandPalette,\n commandPaletteBehaviorDefaults,\n commandPaletteRecipe,\n validateCommandPaletteDescriptor,\n type CommandPaletteActivateHandler,\n type CommandPaletteActivateReason,\n type CommandPaletteDescriptor,\n type CommandPaletteDismissPolicy,\n type CommandPaletteDismissReason,\n type CommandPaletteOpenChangeDetails,\n type CommandPaletteQueryState,\n type CommandPaletteSource,\n} from \"@hjmds/design-contracts/components/command-palette\";\nimport {\n getCollectionNavigationIntent,\n getCollectionNavigationTarget,\n isComboboxResultCurrent,\n} from \"@hjmds/design-contracts/components/collection\";\nimport type { CommandPaletteItemDescriptor } from \"@hjmds/design-contracts/components/command-palette\";\nimport {\n forwardRef,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { classNames, composeRefs } from \"./internal.js\";\nimport { getModalLayer, HjmPortal, renderTrigger, useModalFocus, type OverlayTrigger } from \"./modal.js\";\n\ntype ResultSection<Key extends string> = Readonly<{\n id: string;\n label: string | undefined;\n name: string | undefined;\n items: readonly CommandPaletteItemDescriptor<Key>[];\n}>;\n\n// Local filter = Native Combobox substring rule; why not prefix/contracts:\n// docs/command-palette.md \"2026-10-06\" (comments ship in dist byte budgets).\nfunction resolveResults<Key extends string>(\n source: CommandPaletteSource<Key, string>,\n query: string,\n queryState: CommandPaletteQueryState | undefined,\n emptyMessage: string | undefined,\n) {\n const external = queryState?.filtering === \"external\";\n const needle = query.trim().toLocaleLowerCase();\n const keep = (item: CommandPaletteItemDescriptor<Key>) =>\n external || `${item.label} ${item.textValue}`.toLocaleLowerCase().includes(needle);\n const sections: ResultSection<Key>[] = (source.sections\n ? source.sections.map((section) => ({\n id: section.id,\n label: section.label,\n // validateCollection's precedence.\n name: section.accessibilityLabel?.trim() || section.label?.trim() || undefined,\n items: section.items.filter(keep),\n }))\n : [{ id: \"__all\", label: undefined, name: undefined, items: source.items.filter(keep) }]\n ).filter((section) => section.items.length > 0);\n const items = sections.flatMap((section) => section.items);\n const asyncState = queryState?.asyncState ?? { status: \"idle\" as const };\n const status = asyncState.status !== \"idle\"\n ? { kind: asyncState.status, message: asyncState.message }\n : items.length > 0 || emptyMessage === undefined ? null : { kind: \"empty\" as const, message: emptyMessage };\n return {\n sections,\n items,\n current: !external || isComboboxResultCurrent(queryState.queryValue, queryState.resultQuery),\n status,\n };\n}\n\nexport type CommandPaletteProps<Key extends string = string> = Readonly<{\n descriptor: CommandPaletteDescriptor;\n source: CommandPaletteSource<Key, string>;\n query: string;\n onQueryChange: (query: string) => void;\n onActivate: CommandPaletteActivateHandler<Key>;\n /** Runs after the palette is gone, for a command that opens the next surface. */\n onActivateAfterDismiss?: CommandPaletteActivateHandler<Key>;\n /**\n * Combobox's collection state. Omitted or `filtering: \"local\"` filters\n * `source` by `query` in the renderer (label/textValue substring); pass\n * `filtering: \"external\"` with `queryValue`/`resultQuery` when the product\n * already filtered or ranked the results (server or fuzzy search).\n */\n queryState?: CommandPaletteQueryState;\n dismissPolicy?: Partial<CommandPaletteDismissPolicy>;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean, details: CommandPaletteOpenChangeDetails) => void;\n trigger?: OverlayTrigger;\n renderLeading?: (itemId: Key) => ReactNode;\n portalContainer?: HTMLElement;\n className?: string;\n}>;\n\nexport const CommandPalette = forwardRef(function CommandPalette<Key extends string = string>(\n {\n descriptor,\n source,\n query,\n onQueryChange,\n onActivate,\n onActivateAfterDismiss,\n queryState,\n dismissPolicy,\n open: openProp,\n defaultOpen,\n onOpenChange,\n trigger,\n renderLeading,\n portalContainer,\n className,\n }: CommandPaletteProps<Key>,\n forwardedRef: React.Ref<HTMLDivElement>,\n) {\n validateCommandPaletteDescriptor(descriptor);\n const policy: CommandPaletteDismissPolicy = { ...commandPaletteBehaviorDefaults, ...dismissPolicy };\n const [internalOpen, setInternalOpen] = useState(defaultOpen ?? false);\n const open = openProp ?? internalOpen;\n const results = useMemo(\n () => resolveResults<Key>(source, query, queryState, descriptor.emptyMessage),\n [source, query, queryState, descriptor.emptyMessage],\n );\n // Stale external rows stay visible but inert, as in the Native Combobox.\n const enabled = results.current ? results.items.filter((item) => !item.disabled) : [];\n const [activeId, setActiveId] = useState<Key | null>(null);\n const pendingActivation = useRef<{ itemId: Key; reason: CommandPaletteActivateReason } | null>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const id = `${useId().replaceAll(\":\", \"\")}-command-palette`;\n const active = enabled.find((item) => item.id === activeId) ?? enabled[0] ?? null;\n\n useEffect(() => {\n // A new query builds a new result list; the first enabled row becomes active\n // so Enter always has an unambiguous target. Only the query resets it: products\n // often pass `source`/`queryState` as inline objects, and keying on their\n // identity snapped the active row back to the first item on every render\n // (2026-10-06 usage-guide audit). A row that disappears from the results\n // already falls back to the first enabled row through `active` above.\n setActiveId(null);\n }, [query]);\n\n const change = (next: boolean, reason: CommandPaletteOpenChangeDetails[\"reason\"]) => {\n if (openProp === undefined) setInternalOpen(next);\n onOpenChange?.(next, { reason });\n };\n const requestClose = (reason: CommandPaletteDismissReason) => {\n if (!canDismissCommandPalette(reason, policy)) return;\n change(false, reason);\n };\n const activate = (itemId: Key, reason: CommandPaletteActivateReason) => {\n onActivate(itemId, reason);\n // Running a command always closes the palette — `activation` is a dismiss\n // reason no policy can veto — and the follow-up surface opens after that.\n pendingActivation.current = { itemId, reason };\n change(false, \"activation\");\n };\n\n useModalFocus({\n active: open,\n contentRef,\n initialFocusRef: inputRef,\n ...(trigger === undefined ? {} : { fallbackReturnRef: triggerRef }),\n onEscape: () => requestClose(\"escape\"),\n });\n\n useEffect(() => {\n if (open || !pendingActivation.current) return;\n const { itemId, reason } = pendingActivation.current;\n pendingActivation.current = null;\n // A controlled owner may delay closing; wait for teardown and focus release.\n if (onActivateAfterDismiss) queueMicrotask(() => onActivateAfterDismiss(itemId, reason));\n }, [open, onActivateAfterDismiss]);\n\n const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n // IME confirmation and candidate navigation belong to the text input.\n if (event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) return;\n const intent = getCollectionNavigationIntent(event.key as never);\n if (intent) {\n const target = getCollectionNavigationTarget({ items: enabled }, active?.id ?? null, intent, true);\n if (target === undefined) return;\n event.preventDefault();\n setActiveId(target as Key);\n return;\n }\n if (event.key === \"Enter\" && active) {\n event.preventDefault();\n activate(active.id as Key, \"keyboard\");\n }\n };\n\n const searchInput = (\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded\n aria-controls={`${id}-results`}\n aria-activedescendant={active ? `${id}-${active.id}` : undefined}\n aria-label={descriptor.accessibilityLabel}\n placeholder={descriptor.searchPlaceholder}\n className=\"hjm-command-palette__search\"\n value={query}\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={onKeyDown}\n />\n );\n\n const renderedTrigger = trigger === undefined\n ? null\n : renderTrigger(trigger, triggerRef, open, id, \"dialog\", () => change(true, \"trigger\"));\n if (!open) return renderedTrigger;\n\n return (\n <>\n {renderedTrigger}\n <HjmPortal {...(portalContainer === undefined ? {} : { container: portalContainer })}>\n <div\n className=\"hjm-overlay hjm-command-palette-positioner\"\n data-kind=\"command-palette\"\n style={{ zIndex: getModalLayer(0) }}\n onMouseDown={(event) => { if (event.target === event.currentTarget) requestClose(\"outside\"); }}\n >\n <div\n ref={composeRefs(contentRef, forwardedRef)}\n id={id}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={descriptor.accessibilityLabel}\n data-hjm-modal-content=\"\"\n className={classNames(\"hjm-command-palette\", className)}\n style={{ maxInlineSize: commandPaletteRecipe.content.maxWidth, maxBlockSize: commandPaletteRecipe.content.maxHeight } as CSSProperties}\n >\n {/*\n Opt-in through descriptor.closeLabel because the renderer must not\n invent untranslated copy. Reuses Dialog's close chrome instead of a\n second close-button style (styles.css is at its byte budget).\n */}\n {descriptor.closeLabel ? (\n <div className=\"hjm-command-palette__search-row\">\n {searchInput}\n <button\n type=\"button\"\n className=\"hjm-dialog__close hjm-command-palette__close\"\n aria-label={descriptor.closeLabel}\n onClick={() => requestClose(\"close-action\")}\n >\n <span aria-hidden=\"true\">×</span>\n </button>\n </div>\n ) : searchInput}\n <div id={`${id}-results`} role=\"listbox\" aria-label={descriptor.accessibilityLabel} className=\"hjm-command-palette__viewport\">\n {results.status === null ? null : (\n // Once for the whole list, never per section.\n <p\n className=\"hjm-command-palette__state\"\n data-kind={results.status.kind}\n role={results.status.kind === \"error\" ? \"alert\" : \"status\"}\n >\n {results.status.message}\n </p>\n )}\n {results.sections.map((section) => (\n <div\n key={section.id}\n className=\"hjm-command-palette__section\"\n {...(section.name === undefined ? { role: \"presentation\" } : { role: \"group\", \"aria-label\": section.name })}\n >\n {section.label ? <p className=\"hjm-command-palette__section-label\" aria-hidden=\"true\">{section.label}</p> : null}\n {section.items.map((item) => {\n // Positioning or filtering can enter a stationary cursor;\n // only mouse movement should override keyboard navigation.\n const inert = item.disabled === true || !results.current;\n return (\n <div\n key={item.id}\n id={`${id}-${item.id}`}\n role=\"option\"\n aria-selected={item.id === active?.id}\n aria-disabled={inert || undefined}\n className=\"hjm-command-palette__item\"\n data-tone={item.tone}\n onMouseDown={(event) => {\n event.preventDefault();\n if (!inert) activate(item.id as Key, \"pointer\");\n }}\n onMouseMove={() => { if (!inert) setActiveId(item.id as Key); }}\n >\n {renderLeading?.(item.id as Key)}\n <span className=\"hjm-command-palette__copy\">\n <span>{item.label}</span>\n {item.description ? <span className=\"hjm-command-palette__description\">{item.description}</span> : null}\n </span>\n {item.shortcut ? <kbd className=\"hjm-command-palette__shortcut\">{item.shortcut}</kbd> : null}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n </div>\n </HjmPortal>\n </>\n );\n}) as <Key extends string = string>(\n props: CommandPaletteProps<Key> & { ref?: React.Ref<HTMLDivElement> },\n) => React.ReactElement | null;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-transition.d.ts","sourceRoot":"","sources":["../src/content-transition.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"content-transition.d.ts","sourceRoot":"","sources":["../src/content-transition.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAEpH,OAAO,EAAwC,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG7F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEtE,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,CAAC,EAAE,uBAAuB,CAAC;IAAC,eAAe,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IAC3E,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAClE,mFAAmF;IACnF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2FAA2F;IAC3F,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,qEAAqE;IACrE,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC7C,CAAC;AACF;wGACwG;AACxG,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAqB,EAAE,MAAM,EAAE,cAAc,EAAE,eAA2B,EAAE,WAAW,EAAE,aAAqB,EAAE,YAAoB,EAAE,WAAW,EAAE,EAAE,sBAAsB,+BAmD1O;AACD,MAAM,MAAM,mBAAmB,GAAG;IAAE,MAAM,CAAC,EAAE,uBAAuB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,uBAAuB,CAAA;CAAE,CAAC;AACxJ,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,mBAAmB,+BAEpG"}
|