@hjmds/react 1.1.1 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +12 -6
- package/dist/actions.js.map +1 -1
- package/dist/advanced-display.d.ts +21 -0
- package/dist/advanced-display.d.ts.map +1 -1
- package/dist/advanced-display.js +11 -0
- package/dist/advanced-display.js.map +1 -1
- package/dist/advanced-navigation.d.ts +2 -23
- package/dist/advanced-navigation.d.ts.map +1 -1
- package/dist/advanced-navigation.js +3 -24
- package/dist/advanced-navigation.js.map +1 -1
- package/dist/agreement.d.ts +20 -0
- package/dist/agreement.d.ts.map +1 -0
- package/dist/agreement.js +29 -0
- package/dist/agreement.js.map +1 -0
- package/dist/anchor.d.ts +24 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +110 -0
- package/dist/anchor.js.map +1 -0
- package/dist/asset.d.ts +40 -0
- package/dist/asset.d.ts.map +1 -0
- package/dist/asset.js +26 -0
- package/dist/asset.js.map +1 -0
- package/dist/auth-screen.d.ts +29 -0
- package/dist/auth-screen.d.ts.map +1 -0
- package/dist/auth-screen.js +26 -0
- package/dist/auth-screen.js.map +1 -0
- package/dist/bottom-cta.d.ts +32 -0
- package/dist/bottom-cta.d.ts.map +1 -0
- package/dist/bottom-cta.js +30 -0
- package/dist/bottom-cta.js.map +1 -0
- package/dist/bottom-info.d.ts +16 -0
- package/dist/bottom-info.d.ts.map +1 -0
- package/dist/bottom-info.js +12 -0
- package/dist/bottom-info.js.map +1 -0
- package/dist/breadcrumb.d.ts +9 -0
- package/dist/breadcrumb.d.ts.map +1 -0
- package/dist/breadcrumb.js +12 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/calendar.d.ts +30 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +69 -0
- package/dist/calendar.js.map +1 -0
- package/dist/carousel.d.ts +20 -0
- package/dist/carousel.d.ts.map +1 -0
- package/dist/carousel.js +70 -0
- package/dist/carousel.js.map +1 -0
- package/dist/clipboard.d.ts +33 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +40 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/collapsible.d.ts +11 -0
- package/dist/collapsible.d.ts.map +1 -0
- package/dist/collapsible.js +18 -0
- package/dist/collapsible.js.map +1 -0
- package/dist/command-palette.d.ts +25 -0
- package/dist/command-palette.d.ts.map +1 -0
- package/dist/command-palette.js +82 -0
- package/dist/command-palette.js.map +1 -0
- package/dist/context-menu.d.ts +12 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +111 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/data-table.d.ts +30 -0
- package/dist/data-table.d.ts.map +1 -0
- package/dist/data-table.js +57 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-picker.d.ts +3 -1
- package/dist/date-picker.d.ts.map +1 -1
- package/dist/date-picker.js +16 -31
- package/dist/date-picker.js.map +1 -1
- package/dist/date-range.d.ts +24 -0
- package/dist/date-range.d.ts.map +1 -0
- package/dist/date-range.js +29 -0
- package/dist/date-range.js.map +1 -0
- package/dist/display.d.ts +16 -0
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +13 -1
- package/dist/display.js.map +1 -1
- package/dist/evidence.d.ts +496 -1
- package/dist/evidence.d.ts.map +1 -1
- package/dist/evidence.js +48 -2
- package/dist/evidence.js.map +1 -1
- package/dist/feedback.d.ts +18 -2
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +10 -2
- package/dist/feedback.js.map +1 -1
- package/dist/floating-action-button.d.ts +32 -0
- package/dist/floating-action-button.d.ts.map +1 -0
- package/dist/floating-action-button.js +58 -0
- package/dist/floating-action-button.js.map +1 -0
- package/dist/forms.d.ts +3 -3
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +18 -7
- package/dist/forms.js.map +1 -1
- package/dist/heading.d.ts +12 -0
- package/dist/heading.d.ts.map +1 -0
- package/dist/heading.js +25 -0
- package/dist/heading.js.map +1 -0
- package/dist/index.d.ts +36 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +1 -1
- package/dist/mentions.d.ts +28 -0
- package/dist/mentions.d.ts.map +1 -0
- package/dist/mentions.js +84 -0
- package/dist/mentions.js.map +1 -0
- package/dist/menubar.d.ts +11 -0
- package/dist/menubar.d.ts.map +1 -0
- package/dist/menubar.js +137 -0
- package/dist/menubar.js.map +1 -0
- package/dist/modal.d.ts +67 -0
- package/dist/modal.d.ts.map +1 -0
- package/dist/modal.js +307 -0
- package/dist/modal.js.map +1 -0
- package/dist/overlay-stack.d.ts +28 -0
- package/dist/overlay-stack.d.ts.map +1 -0
- package/dist/overlay-stack.js +47 -0
- package/dist/overlay-stack.js.map +1 -0
- package/dist/overlays.d.ts +26 -43
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +62 -302
- package/dist/overlays.js.map +1 -1
- package/dist/pagination.d.ts +17 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +21 -0
- package/dist/pagination.js.map +1 -0
- package/dist/popover.d.ts +25 -0
- package/dist/popover.d.ts.map +1 -0
- package/dist/popover.js +226 -0
- package/dist/popover.js.map +1 -0
- package/dist/portal.d.ts +5 -1
- package/dist/portal.d.ts.map +1 -1
- package/dist/portal.js +24 -1
- package/dist/portal.js.map +1 -1
- package/dist/provider-button.d.ts +21 -0
- package/dist/provider-button.d.ts.map +1 -0
- package/dist/provider-button.js +26 -0
- package/dist/provider-button.js.map +1 -0
- package/dist/provider.d.ts +13 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +12 -2
- package/dist/provider.js.map +1 -1
- package/dist/selection.d.ts +5 -1
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +2 -2
- package/dist/selection.js.map +1 -1
- package/dist/side-panel.d.ts +34 -0
- package/dist/side-panel.d.ts.map +1 -0
- package/dist/side-panel.js +95 -0
- package/dist/side-panel.js.map +1 -0
- package/dist/sidebar.d.ts +22 -0
- package/dist/sidebar.d.ts.map +1 -0
- package/dist/sidebar.js +29 -0
- package/dist/sidebar.js.map +1 -0
- package/dist/skip-nav.d.ts +12 -0
- package/dist/skip-nav.d.ts.map +1 -0
- package/dist/skip-nav.js +29 -0
- package/dist/skip-nav.js.map +1 -0
- package/dist/splitter.d.ts +45 -0
- package/dist/splitter.d.ts.map +1 -0
- package/dist/splitter.js +116 -0
- package/dist/splitter.js.map +1 -0
- package/dist/styles.css +1105 -26
- package/dist/supplemental-display.d.ts +12 -0
- package/dist/supplemental-display.d.ts.map +1 -1
- package/dist/supplemental-display.js +6 -2
- package/dist/supplemental-display.js.map +1 -1
- package/dist/tags-input.d.ts +60 -0
- package/dist/tags-input.d.ts.map +1 -0
- package/dist/tags-input.js +90 -0
- package/dist/tags-input.js.map +1 -0
- package/dist/text-formats.d.ts +16 -0
- package/dist/text-formats.d.ts.map +1 -0
- package/dist/text-formats.js +24 -0
- package/dist/text-formats.js.map +1 -0
- package/dist/toast.d.ts +1 -1
- package/dist/toggle-group.d.ts +13 -0
- package/dist/toggle-group.d.ts.map +1 -0
- package/dist/toggle-group.js +21 -0
- package/dist/toggle-group.js.map +1 -0
- package/dist/top-bar.d.ts +27 -0
- package/dist/top-bar.d.ts.map +1 -0
- package/dist/top-bar.js +30 -0
- package/dist/top-bar.js.map +1 -0
- package/dist/top.d.ts +15 -0
- package/dist/top.d.ts.map +1 -0
- package/dist/top.js +18 -0
- package/dist/top.js.map +1 -0
- package/dist/tour.d.ts +21 -0
- package/dist/tour.d.ts.map +1 -0
- package/dist/tour.js +122 -0
- package/dist/tour.js.map +1 -0
- package/dist/transfer-list.d.ts +24 -0
- package/dist/transfer-list.d.ts.map +1 -0
- package/dist/transfer-list.js +109 -0
- package/dist/transfer-list.js.map +1 -0
- package/dist/tree.d.ts +29 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +120 -0
- package/dist/tree.js.map +1 -0
- package/package.json +178 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"side-panel.js","sourceRoot":"","sources":["../src/side-panel.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n canDismissSidePanel,\n sidePanelBehaviorDefaults,\n sidePanelRecipe,\n type SidePanelDismissPolicy,\n type SidePanelDismissReason,\n type SidePanelEdge,\n type SidePanelOpenChangeDetails,\n type SidePanelSize,\n} from \"@hjmds/design-contracts/components/side-panel\";\nimport {\n forwardRef,\n useEffect,\n useId,\n useRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { classNames, composeRefs } from \"./internal.js\";\nimport {\n getModalLayer,\n HjmPortal,\n renderTrigger,\n useModalFocus,\n useOpenState,\n type ModalOpenState,\n} from \"./modal.js\";\n\nexport type SidePanelProps = ModalOpenState<SidePanelOpenChangeDetails> &\n Readonly<{\n title: ReactNode;\n description?: ReactNode;\n children?: ReactNode;\n footer?: ReactNode;\n /** Logical docking direction; mirrors automatically in RTL. */\n edge?: SidePanelEdge;\n size?: SidePanelSize;\n busy?: boolean;\n /**\n * The whole policy, not `Partial<...>`: the contract splits this union on\n * `modal` so that `{ modal: false, outsideDismiss: true }` cannot be\n * written at all. `Partial<SidePanelDismissPolicy>` would collapse both\n * branches into optional fields and hand that invalid combination back.\n */\n dismissPolicy?: SidePanelDismissPolicy;\n /** Localized accessible name for the close action. */\n closeLabel: string;\n initialFocusRef?: React.RefObject<HTMLElement | null>;\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n /** Fires once per visible cycle, after the panel has been removed. */\n onDismissComplete?: (detail: Readonly<{ reason: SidePanelDismissReason }>) => void;\n /** Higher-priority modals remain interactive above later lower-priority modals. */\n modalPriority?: number;\n portalContainer?: HTMLElement;\n className?: string;\n }>;\n\nexport const SidePanel = forwardRef<HTMLDivElement, SidePanelProps>(function SidePanel(\n {\n trigger,\n title,\n description,\n children,\n footer,\n edge = sidePanelRecipe.defaults.edge,\n size = sidePanelRecipe.defaults.size,\n busy = false,\n dismissPolicy = sidePanelBehaviorDefaults,\n closeLabel,\n initialFocusRef,\n returnFocusRef,\n onDismissComplete,\n modalPriority = 0,\n portalContainer,\n open: openProp,\n defaultOpen,\n onOpenChange,\n className,\n },\n forwardedRef,\n) {\n const policy = dismissPolicy;\n const modal = policy.modal;\n const [open, changeOpen] = useOpenState<SidePanelOpenChangeDetails>({\n ...(openProp === undefined ? {} : { open: openProp }),\n ...(defaultOpen === undefined ? {} : { defaultOpen }),\n ...(onOpenChange === undefined ? {} : { onOpenChange }),\n });\n const triggerRef = useRef<HTMLElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const id = useId().replaceAll(\":\", \"\");\n const contentId = `${id}-side-panel`;\n const titleId = `${id}-title`;\n const descriptionId = `${id}-description`;\n\n const dismissReasonRef = useRef<SidePanelDismissReason | undefined>(undefined);\n const wasOpenRef = useRef(open);\n const dismissCompleteRef = useRef(onDismissComplete);\n dismissCompleteRef.current = onDismissComplete;\n const requestClose = (reason: SidePanelDismissReason) => {\n if (!canDismissSidePanel(reason, busy, policy)) return;\n dismissReasonRef.current = reason;\n changeOpen(false, { reason });\n };\n useEffect(() => {\n if (open) {\n wasOpenRef.current = true;\n dismissReasonRef.current = undefined;\n return;\n }\n if (!wasOpenRef.current) return;\n /*\n No `createSheetLifecycle` counterpart, per docs/side-panel.md: that counter\n exists for Android's persistently mounted native Modal. Here the panel is\n unmounted with the render that closed it, so \"removed\" is already true when\n this effect runs — including under reduced motion, where there is no exit\n transition to wait for. An owner that closed the panel without a user\n gesture is reported as `programmatic`.\n */\n wasOpenRef.current = false;\n const reason = dismissReasonRef.current ?? \"programmatic\";\n dismissReasonRef.current = undefined;\n dismissCompleteRef.current?.({ reason });\n }, [open]);\n\n useModalFocus({\n // Only modal panels trap focus and lock scroll. A non-modal panel leaves the\n // rest of the page live and tabbable, so it must not enter the modal stack.\n active: open && modal,\n priority: modalPriority,\n contentRef,\n ...(initialFocusRef === undefined ? {} : { initialFocusRef }),\n ...(returnFocusRef === undefined ? {} : { returnFocusRef }),\n ...(trigger === undefined ? {} : { fallbackReturnRef: triggerRef }),\n onEscape: () => requestClose(\"escape\"),\n });\n\n const escapeRef = useRef(() => requestClose(\"escape\"));\n escapeRef.current = () => requestClose(\"escape\");\n useEffect(() => {\n if (!open || modal) return;\n // Escape dismisses non-modal panels too, but only while focus is inside them\n // — the live page behind keeps its own Escape handling.\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || event.defaultPrevented) return;\n // Read the ref per event: the portal mounts one commit after this effect,\n // so a value captured here would still be null for the panel's first keys.\n if (!(event.target instanceof Node) || contentRef.current?.contains(event.target) !== true) return;\n event.preventDefault();\n escapeRef.current();\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [open, modal]);\n\n const style = {\n zIndex: getModalLayer(modalPriority),\n \"--hjm-side-panel-size\": `${sidePanelRecipe.sizes[size]}px`,\n } as CSSProperties;\n const panel = (\n <div\n ref={composeRefs(contentRef, forwardedRef)}\n id={contentId}\n // A modal panel is a dialog; a non-modal one stays a complementary landmark\n // so assistive technology can move past it like any other page region.\n role={modal ? \"dialog\" : \"complementary\"}\n aria-modal={modal || undefined}\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n aria-busy={busy || undefined}\n tabIndex={-1}\n className={classNames(\"hjm-side-panel\", className)}\n data-hjm-modal-content={modal ? \"\" : undefined}\n data-edge={edge}\n data-size={size}\n data-modal={modal}\n data-state={busy ? \"busy\" : \"idle\"}\n style={modal ? undefined : style}\n >\n <header className=\"hjm-side-panel__header\">\n <div>\n <h2 id={titleId} className=\"hjm-side-panel__title\">{title}</h2>\n {description ? <p id={descriptionId} className=\"hjm-side-panel__description\">{description}</p> : null}\n </div>\n {policy.dismissible ? (\n <button\n type=\"button\"\n className=\"hjm-dialog__close\"\n aria-label={closeLabel}\n disabled={busy && !policy.dismissWhileBusy}\n onClick={() => requestClose(\"close-action\")}\n >\n ×\n </button>\n ) : null}\n </header>\n {children ? <div className=\"hjm-side-panel__body\">{children}</div> : null}\n {footer ? <footer className=\"hjm-side-panel__footer\">{footer}</footer> : null}\n </div>\n );\n\n return (\n <>\n {trigger === undefined ? null : renderTrigger(\n trigger,\n triggerRef,\n open,\n contentId,\n \"dialog\",\n () => changeOpen(true, { reason: \"trigger\" }),\n )}\n {open ? (\n <HjmPortal {...(portalContainer === undefined ? {} : { container: portalContainer })}>\n {modal ? (\n <div\n className=\"hjm-overlay hjm-side-panel-positioner\"\n data-kind=\"side-panel\"\n data-modal-priority={modalPriority}\n data-edge={edge}\n data-state=\"open\"\n style={style}\n onMouseDown={(event) => {\n if (event.target === event.currentTarget) requestClose(\"outside\");\n }}\n >\n {panel}\n </div>\n ) : panel}\n </HjmPortal>\n ) : null}\n </>\n );\n});\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type SidebarDescriptor, type SidebarItemDescriptor } from "@hjmds/design-contracts/components/sidebar";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
export type SidebarProps<Id extends string = string, GroupId extends string = string> = Readonly<{
|
|
4
|
+
descriptor: SidebarDescriptor<Id, GroupId>;
|
|
5
|
+
collapsed?: boolean;
|
|
6
|
+
defaultCollapsed?: boolean;
|
|
7
|
+
onCollapsedChange?: (collapsed: boolean) => void;
|
|
8
|
+
/** Localized names for the collapse control in both states. */
|
|
9
|
+
collapseLabels?: Readonly<{
|
|
10
|
+
collapse: string;
|
|
11
|
+
expand: string;
|
|
12
|
+
}>;
|
|
13
|
+
onNavigate?: (id: Id) => void;
|
|
14
|
+
/** Product-owned icon per item; required for the collapsed rail to stay usable. */
|
|
15
|
+
renderIcon?: (item: SidebarItemDescriptor<Id>) => ReactNode;
|
|
16
|
+
renderBadge?: (count: number, item: SidebarItemDescriptor<Id>) => ReactNode;
|
|
17
|
+
className?: string;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const Sidebar: <Id extends string = string, GroupId extends string = string>(props: SidebarProps<Id, GroupId> & {
|
|
20
|
+
ref?: React.Ref<HTMLElement>;
|
|
21
|
+
}) => React.ReactElement | null;
|
|
22
|
+
//# sourceMappingURL=sidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../src/sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC3B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAC/F,UAAU,EAAE,iBAAiB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,+DAA+D;IAC/D,cAAc,CAAC,EAAE,QAAQ,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;IAC9B,mFAAmF;IACnF,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;IAC5D,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,eAAO,MAAM,OAAO,EAqFd,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAChE,KAAK,EAAE,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;CAAE,KAChE,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC"}
|
package/dist/sidebar.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { sidebarDefaults, sidebarRecipe, validateSidebarDescriptor, } from "@hjmds/design-contracts/components/sidebar";
|
|
3
|
+
import { forwardRef, } from "react";
|
|
4
|
+
import { classNames, useControllableState } from "./internal.js";
|
|
5
|
+
export const Sidebar = forwardRef(function Sidebar({ descriptor, collapsed: controlledCollapsed, defaultCollapsed, onCollapsedChange, collapseLabels, onNavigate, renderIcon, renderBadge, className, }, forwardedRef) {
|
|
6
|
+
validateSidebarDescriptor(descriptor);
|
|
7
|
+
const [collapsed, setCollapsed] = useControllableState({
|
|
8
|
+
...(controlledCollapsed === undefined ? {} : { value: controlledCollapsed }),
|
|
9
|
+
defaultValue: defaultCollapsed ?? sidebarDefaults.collapsed,
|
|
10
|
+
...(onCollapsedChange === undefined ? {} : { onChange: onCollapsedChange }),
|
|
11
|
+
});
|
|
12
|
+
return (_jsxs("nav", { ref: forwardedRef, "aria-label": descriptor.accessibilityLabel, className: classNames("hjm-sidebar", className), "data-collapsed": collapsed || undefined, style: {
|
|
13
|
+
"--hjm-sidebar-width": `${collapsed ? sidebarRecipe.widths.collapsed : sidebarRecipe.widths.expanded}px`,
|
|
14
|
+
"--hjm-sidebar-item-height": `${sidebarRecipe.itemMinHeight}px`,
|
|
15
|
+
"--hjm-sidebar-item-radius": `${sidebarRecipe.itemRadius}px`,
|
|
16
|
+
"--hjm-sidebar-gap": `${sidebarRecipe.gap}px`,
|
|
17
|
+
"--hjm-sidebar-group-gap": `${sidebarRecipe.groupGap}px`,
|
|
18
|
+
}, children: [collapseLabels ? (_jsx("button", { type: "button", className: "hjm-sidebar__toggle", "aria-expanded": !collapsed, "aria-label": collapsed ? collapseLabels.expand : collapseLabels.collapse, onClick: () => setCollapsed(!collapsed), children: _jsx("span", { "aria-hidden": "true", children: collapsed ? "»" : "«" }) })) : null, descriptor.groups.map((group) => (_jsxs("div", { className: "hjm-sidebar__group", role: "group", "aria-label": group.label, children: [group.label ? _jsx("p", { className: "hjm-sidebar__group-label", "aria-hidden": "true", children: group.label }) : null, _jsx("ul", { className: "hjm-sidebar__list", children: group.items.map((item) => {
|
|
19
|
+
const current = descriptor.currentId === item.id;
|
|
20
|
+
return (_jsx("li", { children: _jsxs("a", { className: "hjm-sidebar__item", href: item.destination?.kind === "internal" ? item.destination.href : item.destination?.href, "aria-current": current ? "page" : undefined, "aria-disabled": item.disabled || undefined, "aria-label": collapsed ? item.label : undefined, tabIndex: item.disabled ? -1 : undefined, onClick: (event) => {
|
|
21
|
+
if (item.disabled) {
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
onNavigate?.(item.id);
|
|
26
|
+
}, children: [renderIcon ? _jsx("span", { "aria-hidden": "true", className: "hjm-sidebar__icon", children: renderIcon(item) }) : null, _jsx("span", { className: "hjm-sidebar__label", children: item.label }), item.badgeCount !== undefined ? (_jsx("span", { className: "hjm-sidebar__badge", children: renderBadge?.(item.badgeCount, item) ?? item.badgeCount })) : null] }) }, item.id));
|
|
27
|
+
}) })] }, group.id)))] }));
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.js","sourceRoot":"","sources":["../src/sidebar.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n sidebarDefaults,\n sidebarRecipe,\n validateSidebarDescriptor,\n type SidebarDescriptor,\n type SidebarItemDescriptor,\n} from \"@hjmds/design-contracts/components/sidebar\";\nimport {\n forwardRef,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { classNames, useControllableState } from \"./internal.js\";\n\nexport type SidebarProps<Id extends string = string, GroupId extends string = string> = Readonly<{\n descriptor: SidebarDescriptor<Id, GroupId>;\n collapsed?: boolean;\n defaultCollapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n /** Localized names for the collapse control in both states. */\n collapseLabels?: Readonly<{ collapse: string; expand: string }>;\n onNavigate?: (id: Id) => void;\n /** Product-owned icon per item; required for the collapsed rail to stay usable. */\n renderIcon?: (item: SidebarItemDescriptor<Id>) => ReactNode;\n renderBadge?: (count: number, item: SidebarItemDescriptor<Id>) => ReactNode;\n className?: string;\n}>;\n\nexport const Sidebar = forwardRef(function Sidebar<Id extends string = string, GroupId extends string = string>(\n {\n descriptor,\n collapsed: controlledCollapsed,\n defaultCollapsed,\n onCollapsedChange,\n collapseLabels,\n onNavigate,\n renderIcon,\n renderBadge,\n className,\n }: SidebarProps<Id, GroupId>,\n forwardedRef: React.Ref<HTMLElement>,\n) {\n validateSidebarDescriptor(descriptor);\n const [collapsed, setCollapsed] = useControllableState<boolean>({\n ...(controlledCollapsed === undefined ? {} : { value: controlledCollapsed }),\n defaultValue: defaultCollapsed ?? sidebarDefaults.collapsed,\n ...(onCollapsedChange === undefined ? {} : { onChange: onCollapsedChange }),\n });\n return (\n <nav\n ref={forwardedRef}\n aria-label={descriptor.accessibilityLabel}\n className={classNames(\"hjm-sidebar\", className)}\n data-collapsed={collapsed || undefined}\n style={{\n \"--hjm-sidebar-width\": `${collapsed ? sidebarRecipe.widths.collapsed : sidebarRecipe.widths.expanded}px`,\n \"--hjm-sidebar-item-height\": `${sidebarRecipe.itemMinHeight}px`,\n \"--hjm-sidebar-item-radius\": `${sidebarRecipe.itemRadius}px`,\n \"--hjm-sidebar-gap\": `${sidebarRecipe.gap}px`,\n \"--hjm-sidebar-group-gap\": `${sidebarRecipe.groupGap}px`,\n } as CSSProperties}\n >\n {collapseLabels ? (\n <button\n type=\"button\"\n className=\"hjm-sidebar__toggle\"\n aria-expanded={!collapsed}\n aria-label={collapsed ? collapseLabels.expand : collapseLabels.collapse}\n onClick={() => setCollapsed(!collapsed)}\n >\n <span aria-hidden=\"true\">{collapsed ? \"»\" : \"«\"}</span>\n </button>\n ) : null}\n {descriptor.groups.map((group) => (\n <div key={group.id} className=\"hjm-sidebar__group\" role=\"group\" aria-label={group.label}>\n {/*\n Collapsing is density, not content: the group label is hidden\n visually but the group keeps its accessible name.\n */}\n {group.label ? <p className=\"hjm-sidebar__group-label\" aria-hidden=\"true\">{group.label}</p> : null}\n <ul className=\"hjm-sidebar__list\">\n {group.items.map((item) => {\n const current = descriptor.currentId === item.id;\n return (\n <li key={item.id}>\n <a\n className=\"hjm-sidebar__item\"\n href={item.destination?.kind === \"internal\" ? item.destination.href : item.destination?.href}\n aria-current={current ? \"page\" : undefined}\n aria-disabled={item.disabled || undefined}\n // Collapsed labels are hidden visually, so the name comes\n // from the attribute instead of disappearing with the text.\n aria-label={collapsed ? item.label : undefined}\n tabIndex={item.disabled ? -1 : undefined}\n onClick={(event) => {\n if (item.disabled) { event.preventDefault(); return; }\n onNavigate?.(item.id);\n }}\n >\n {renderIcon ? <span aria-hidden=\"true\" className=\"hjm-sidebar__icon\">{renderIcon(item)}</span> : null}\n <span className=\"hjm-sidebar__label\">{item.label}</span>\n {item.badgeCount !== undefined ? (\n <span className=\"hjm-sidebar__badge\">{renderBadge?.(item.badgeCount, item) ?? item.badgeCount}</span>\n ) : null}\n </a>\n </li>\n );\n })}\n </ul>\n </div>\n ))}\n </nav>\n );\n}) as <Id extends string = string, GroupId extends string = string>(\n props: SidebarProps<Id, GroupId> & { ref?: React.Ref<HTMLElement> },\n) => React.ReactElement | null;\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type SkipNavDescriptor } from "@hjmds/design-contracts/components/skip-nav";
|
|
2
|
+
import { type AnchorHTMLAttributes } from "react";
|
|
3
|
+
export type SkipNavProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "children"> & SkipNavDescriptor & Readonly<{
|
|
4
|
+
className?: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare const SkipNav: import("react").ForwardRefExoticComponent<Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "children" | "href"> & Readonly<{
|
|
7
|
+
targetId: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}> & Readonly<{
|
|
10
|
+
className?: string;
|
|
11
|
+
}> & import("react").RefAttributes<HTMLAnchorElement>>;
|
|
12
|
+
//# sourceMappingURL=skip-nav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skip-nav.d.ts","sourceRoot":"","sources":["../src/skip-nav.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAc,KAAK,oBAAoB,EAAsB,MAAM,OAAO,CAAC;AAGlF,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,GAC3F,iBAAiB,GACjB,QAAQ,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO;;;;gBAFK,MAAM;sDAoC7B,CAAC"}
|
package/dist/skip-nav.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { skipNavRecipe, validateSkipNavDescriptor, } from "@hjmds/design-contracts/components/skip-nav";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import { classNames } from "./internal.js";
|
|
5
|
+
export const SkipNav = forwardRef(function SkipNav({ targetId, label, className, onClick, ...props }, forwardedRef) {
|
|
6
|
+
validateSkipNavDescriptor({ targetId, label });
|
|
7
|
+
return (_jsx("a", { ...props, ref: forwardedRef, href: `#${targetId}`, className: classNames("hjm-skip-nav", className), style: {
|
|
8
|
+
"--hjm-skip-nav-min-height": `${skipNavRecipe.minHeight}px`,
|
|
9
|
+
"--hjm-skip-nav-padding": `${skipNavRecipe.paddingHorizontal}px`,
|
|
10
|
+
"--hjm-skip-nav-radius": `${skipNavRecipe.radius}px`,
|
|
11
|
+
"--hjm-skip-nav-offset": `${skipNavRecipe.offset}px`,
|
|
12
|
+
}, onClick: (event) => {
|
|
13
|
+
onClick?.(event);
|
|
14
|
+
if (event.defaultPrevented)
|
|
15
|
+
return;
|
|
16
|
+
const target = document.getElementById(targetId);
|
|
17
|
+
if (!target)
|
|
18
|
+
return;
|
|
19
|
+
/*
|
|
20
|
+
The hash alone only scrolls; focus stays behind in the navigation, so
|
|
21
|
+
the next Tab returns to the links the user just skipped. Making the
|
|
22
|
+
target programmatically focusable moves the caret with the view.
|
|
23
|
+
*/
|
|
24
|
+
if (!target.hasAttribute("tabindex"))
|
|
25
|
+
target.setAttribute("tabindex", "-1");
|
|
26
|
+
target.focus({ preventScroll: false });
|
|
27
|
+
}, children: label }));
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=skip-nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skip-nav.js","sourceRoot":"","sources":["../src/skip-nav.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EACb,yBAAyB,GAE1B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,UAAU,EAAiD,MAAM,OAAO,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAM3C,MAAM,CAAC,MAAM,OAAO,GAAG,UAAU,CAAkC,SAAS,OAAO,CACjF,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EACjD,YAAY;IAEZ,yBAAyB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/C,OAAO,CACL,eACM,KAAK,EACT,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,IAAI,QAAQ,EAAE,EACpB,SAAS,EAAE,UAAU,CAAC,cAAc,EAAE,SAAS,CAAC,EAChD,KAAK,EAAE;YACL,2BAA2B,EAAE,GAAG,aAAa,CAAC,SAAS,IAAI;YAC3D,wBAAwB,EAAE,GAAG,aAAa,CAAC,iBAAiB,IAAI;YAChE,uBAAuB,EAAE,GAAG,aAAa,CAAC,MAAM,IAAI;YACpD,uBAAuB,EAAE,GAAG,aAAa,CAAC,MAAM,IAAI;SACpC,EAClB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YACjB,IAAI,KAAK,CAAC,gBAAgB;gBAAE,OAAO;YACnC,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB;;;;cAIE;YACF,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC;gBAAE,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC5E,MAAM,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC,YAEA,KAAK,GACJ,CACL,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import {\n skipNavRecipe,\n validateSkipNavDescriptor,\n type SkipNavDescriptor,\n} from \"@hjmds/design-contracts/components/skip-nav\";\nimport { forwardRef, type AnchorHTMLAttributes, type CSSProperties } from \"react\";\nimport { classNames } from \"./internal.js\";\n\nexport type SkipNavProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, \"href\" | \"children\"> &\n SkipNavDescriptor &\n Readonly<{ className?: string }>;\n\nexport const SkipNav = forwardRef<HTMLAnchorElement, SkipNavProps>(function SkipNav(\n { targetId, label, className, onClick, ...props },\n forwardedRef,\n) {\n validateSkipNavDescriptor({ targetId, label });\n return (\n <a\n {...props}\n ref={forwardedRef}\n href={`#${targetId}`}\n className={classNames(\"hjm-skip-nav\", className)}\n style={{\n \"--hjm-skip-nav-min-height\": `${skipNavRecipe.minHeight}px`,\n \"--hjm-skip-nav-padding\": `${skipNavRecipe.paddingHorizontal}px`,\n \"--hjm-skip-nav-radius\": `${skipNavRecipe.radius}px`,\n \"--hjm-skip-nav-offset\": `${skipNavRecipe.offset}px`,\n } as CSSProperties}\n onClick={(event) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n const target = document.getElementById(targetId);\n if (!target) return;\n /*\n The hash alone only scrolls; focus stays behind in the navigation, so\n the next Tab returns to the links the user just skipped. Making the\n target programmatically focusable moves the caret with the view.\n */\n if (!target.hasAttribute(\"tabindex\")) target.setAttribute(\"tabindex\", \"-1\");\n target.focus({ preventScroll: false });\n }}\n >\n {label}\n </a>\n );\n});\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type SplitterAxis } from "@hjmds/design-contracts/components/splitter";
|
|
2
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
3
|
+
export type SplitterProps = Readonly<{
|
|
4
|
+
/** Required accessible name for the separator. */
|
|
5
|
+
label: string;
|
|
6
|
+
min: number;
|
|
7
|
+
max: number;
|
|
8
|
+
step?: number;
|
|
9
|
+
axis?: SplitterAxis;
|
|
10
|
+
value?: number;
|
|
11
|
+
defaultValue?: number;
|
|
12
|
+
onValueChange?: (value: number) => void;
|
|
13
|
+
/** Fires once when a drag settles, for owners that persist the size. */
|
|
14
|
+
onValueChangeEnd?: (value: number) => void;
|
|
15
|
+
/** Product-owned announcement of the current size, e.g. "35%" or "320px". */
|
|
16
|
+
getValueText?: (value: number) => string;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/** The pane the value sizes, and the pane that takes the remaining space. */
|
|
19
|
+
primaryPane: ReactNode;
|
|
20
|
+
secondaryPane: ReactNode;
|
|
21
|
+
className?: string;
|
|
22
|
+
style?: CSSProperties;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const Splitter: import("react").ForwardRefExoticComponent<Readonly<{
|
|
25
|
+
/** Required accessible name for the separator. */
|
|
26
|
+
label: string;
|
|
27
|
+
min: number;
|
|
28
|
+
max: number;
|
|
29
|
+
step?: number;
|
|
30
|
+
axis?: SplitterAxis;
|
|
31
|
+
value?: number;
|
|
32
|
+
defaultValue?: number;
|
|
33
|
+
onValueChange?: (value: number) => void;
|
|
34
|
+
/** Fires once when a drag settles, for owners that persist the size. */
|
|
35
|
+
onValueChangeEnd?: (value: number) => void;
|
|
36
|
+
/** Product-owned announcement of the current size, e.g. "35%" or "320px". */
|
|
37
|
+
getValueText?: (value: number) => string;
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
/** The pane the value sizes, and the pane that takes the remaining space. */
|
|
40
|
+
primaryPane: ReactNode;
|
|
41
|
+
secondaryPane: ReactNode;
|
|
42
|
+
className?: string;
|
|
43
|
+
style?: CSSProperties;
|
|
44
|
+
}> & import("react").RefAttributes<HTMLDivElement>>;
|
|
45
|
+
//# sourceMappingURL=splitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitter.d.ts","sourceRoot":"","sources":["../src/splitter.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,YAAY,EAClB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAIL,KAAK,aAAa,EAGlB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,6EAA6E;IAC7E,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,WAAW,EAAE,SAAS,CAAC;IACvB,aAAa,EAAE,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC,CAAC;AAoBH,eAAO,MAAM,QAAQ;IAvCnB,kDAAkD;WAC3C,MAAM;SACR,MAAM;SACN,MAAM;WACJ,MAAM;WACN,YAAY;YACX,MAAM;mBACC,MAAM;oBACL,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;IACvC,wEAAwE;uBACrD,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;IAC1C,6EAA6E;mBAC9D,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM;eAC7B,OAAO;IAClB,6EAA6E;iBAChE,SAAS;mBACP,SAAS;gBACZ,MAAM;YACV,aAAa;mDA8IrB,CAAC"}
|
package/dist/splitter.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getNextSplitterValue, resolveSplitterBoundaryValue, resolveSplitterDragValue, resolveSplitterSeparatorOrientation, splitterDefaults, splitterRecipe, validateSplitterDescriptor, } from "@hjmds/design-contracts/components/splitter";
|
|
3
|
+
import { forwardRef, useRef, useState, } from "react";
|
|
4
|
+
import { classNames, composeRefs, useControllableState } from "./internal.js";
|
|
5
|
+
/*
|
|
6
|
+
The value is a percentage of the root box: `min`/`max`/`step` stay in the
|
|
7
|
+
product's own unit as the contract requires, but the pointer has to be turned
|
|
8
|
+
into that unit somehow, and only a fraction of the container is meaningful
|
|
9
|
+
without knowing the product's unit. Products that size in px pass min/max in
|
|
10
|
+
px and read the same fraction back through their own formatting.
|
|
11
|
+
*/
|
|
12
|
+
function fractionFromPointer(root, axis, clientX, clientY) {
|
|
13
|
+
const box = root.getBoundingClientRect();
|
|
14
|
+
const horizontal = axis === "horizontal";
|
|
15
|
+
const span = horizontal ? box.width : box.height;
|
|
16
|
+
if (span === 0)
|
|
17
|
+
return 0;
|
|
18
|
+
const offset = horizontal ? clientX - box.left : clientY - box.top;
|
|
19
|
+
// Logical, not physical: in RTL the primary pane starts at the right edge.
|
|
20
|
+
const flipped = horizontal && getComputedStyle(root).direction === "rtl";
|
|
21
|
+
return (flipped ? span - offset : offset) / span;
|
|
22
|
+
}
|
|
23
|
+
export const Splitter = forwardRef(function Splitter({ label, min, max, step, axis = splitterDefaults.axis, value: controlledValue, defaultValue, onValueChange, onValueChangeEnd, getValueText, disabled = false, primaryPane, secondaryPane, className, style, }, forwardedRef) {
|
|
24
|
+
const [value, setValue] = useControllableState({
|
|
25
|
+
...(controlledValue === undefined ? {} : { value: controlledValue }),
|
|
26
|
+
defaultValue: defaultValue ?? min,
|
|
27
|
+
...(onValueChange === undefined ? {} : { onChange: onValueChange }),
|
|
28
|
+
});
|
|
29
|
+
const descriptor = {
|
|
30
|
+
value,
|
|
31
|
+
min,
|
|
32
|
+
max,
|
|
33
|
+
...(step === undefined ? {} : { step }),
|
|
34
|
+
axis,
|
|
35
|
+
label,
|
|
36
|
+
...(getValueText === undefined ? {} : { valueText: getValueText(value) }),
|
|
37
|
+
};
|
|
38
|
+
validateSplitterDescriptor(descriptor);
|
|
39
|
+
const rootRef = useRef(null);
|
|
40
|
+
const [dragging, setDragging] = useState(false);
|
|
41
|
+
const commit = (next) => {
|
|
42
|
+
if (next !== value)
|
|
43
|
+
setValue(next);
|
|
44
|
+
return next;
|
|
45
|
+
};
|
|
46
|
+
const onKeyDown = (event) => {
|
|
47
|
+
if (disabled)
|
|
48
|
+
return;
|
|
49
|
+
const root = rootRef.current;
|
|
50
|
+
const flipped = axis === "horizontal" && root !== null && getComputedStyle(root).direction === "rtl";
|
|
51
|
+
const intent = arrowIntent(event.key, axis, flipped);
|
|
52
|
+
const next = event.key === "Home" || event.key === "End"
|
|
53
|
+
? resolveSplitterBoundaryValue(descriptor, event.key === "Home" ? "min" : "max")
|
|
54
|
+
: intent === undefined
|
|
55
|
+
? undefined
|
|
56
|
+
: getNextSplitterValue(descriptor, intent);
|
|
57
|
+
if (next === undefined)
|
|
58
|
+
return;
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
// Keyboard resize settles immediately: there is no drag to release, but an
|
|
61
|
+
// owner persisting the size still needs the same end signal a drag gives.
|
|
62
|
+
if (next === value)
|
|
63
|
+
return;
|
|
64
|
+
// Commit before notifying, never as the argument of an optional call:
|
|
65
|
+
// `onValueChangeEnd?.(commit(next))` skips the argument entirely when no
|
|
66
|
+
// handler is passed, so keyboard resize would silently do nothing.
|
|
67
|
+
commit(next);
|
|
68
|
+
// A step already at the boundary changes nothing, so it is not a settlement
|
|
69
|
+
// — an owner persisting on every end would otherwise write a no-op.
|
|
70
|
+
onValueChangeEnd?.(next);
|
|
71
|
+
};
|
|
72
|
+
const onPointerDown = (event) => {
|
|
73
|
+
if (disabled || event.button !== 0)
|
|
74
|
+
return;
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
77
|
+
setDragging(true);
|
|
78
|
+
};
|
|
79
|
+
const resize = (event) => {
|
|
80
|
+
const root = rootRef.current;
|
|
81
|
+
if (!dragging || !root)
|
|
82
|
+
return;
|
|
83
|
+
const fraction = fractionFromPointer(root, axis, event.clientX, event.clientY);
|
|
84
|
+
commit(resolveSplitterDragValue(descriptor, min + fraction * (max - min)));
|
|
85
|
+
};
|
|
86
|
+
const endDrag = (event) => {
|
|
87
|
+
if (!dragging)
|
|
88
|
+
return;
|
|
89
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
90
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
91
|
+
}
|
|
92
|
+
setDragging(false);
|
|
93
|
+
onValueChangeEnd?.(value);
|
|
94
|
+
};
|
|
95
|
+
const fraction = max === min ? 0 : (value - min) / (max - min);
|
|
96
|
+
return (_jsxs("div", { ref: composeRefs(rootRef, forwardedRef), className: classNames("hjm-splitter", className), "data-axis": axis, "data-dragging": dragging || undefined, style: { ...style, "--hjm-splitter-primary": `${fraction * 100}%` }, children: [_jsx("div", { className: "hjm-splitter__pane", "data-pane": "primary", children: primaryPane }), _jsx("div", { role: "separator", "aria-orientation": resolveSplitterSeparatorOrientation(axis), "aria-label": label, "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-valuetext": descriptor.valueText, "aria-disabled": disabled || undefined, tabIndex: disabled ? -1 : 0, className: "hjm-splitter__separator", style: { "--hjm-splitter-hit-target": `${splitterRecipe.separator.hitTarget}px`, "--hjm-splitter-thickness": `${splitterRecipe.separator.thickness}px` }, onKeyDown: onKeyDown, onPointerDown: onPointerDown, onPointerMove: resize, onPointerUp: endDrag, onPointerCancel: endDrag, children: _jsx("span", { className: "hjm-splitter__handle", "aria-hidden": "true" }) }), _jsx("div", { className: "hjm-splitter__pane", "data-pane": "secondary", children: secondaryPane })] }));
|
|
97
|
+
});
|
|
98
|
+
function arrowIntent(key, axis, flipped) {
|
|
99
|
+
// Only the axis the panes are arranged along resizes; the other pair of arrow
|
|
100
|
+
// keys belongs to whatever the pane content does with them. `flipped` keeps the
|
|
101
|
+
// keyboard on the same logical direction the drag uses: in RTL the primary pane
|
|
102
|
+
// grows toward the left, so ArrowLeft is the increment.
|
|
103
|
+
if (axis === "horizontal") {
|
|
104
|
+
if (key === (flipped ? "ArrowLeft" : "ArrowRight"))
|
|
105
|
+
return "increment";
|
|
106
|
+
if (key === (flipped ? "ArrowRight" : "ArrowLeft"))
|
|
107
|
+
return "decrement";
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
if (key === "ArrowDown")
|
|
111
|
+
return "increment";
|
|
112
|
+
if (key === "ArrowUp")
|
|
113
|
+
return "decrement";
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=splitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitter.js","sourceRoot":"","sources":["../src/splitter.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n getNextSplitterValue,\n resolveSplitterBoundaryValue,\n resolveSplitterDragValue,\n resolveSplitterSeparatorOrientation,\n splitterDefaults,\n splitterRecipe,\n validateSplitterDescriptor,\n type SplitterAxis,\n} from \"@hjmds/design-contracts/components/splitter\";\nimport {\n forwardRef,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type PointerEvent,\n type ReactNode,\n} from \"react\";\nimport { classNames, composeRefs, useControllableState } from \"./internal.js\";\n\nexport type SplitterProps = Readonly<{\n /** Required accessible name for the separator. */\n label: string;\n min: number;\n max: number;\n step?: number;\n axis?: SplitterAxis;\n value?: number;\n defaultValue?: number;\n onValueChange?: (value: number) => void;\n /** Fires once when a drag settles, for owners that persist the size. */\n onValueChangeEnd?: (value: number) => void;\n /** Product-owned announcement of the current size, e.g. \"35%\" or \"320px\". */\n getValueText?: (value: number) => string;\n disabled?: boolean;\n /** The pane the value sizes, and the pane that takes the remaining space. */\n primaryPane: ReactNode;\n secondaryPane: ReactNode;\n className?: string;\n style?: CSSProperties;\n}>;\n\n/*\n The value is a percentage of the root box: `min`/`max`/`step` stay in the\n product's own unit as the contract requires, but the pointer has to be turned\n into that unit somehow, and only a fraction of the container is meaningful\n without knowing the product's unit. Products that size in px pass min/max in\n px and read the same fraction back through their own formatting.\n*/\nfunction fractionFromPointer(root: HTMLElement, axis: SplitterAxis, clientX: number, clientY: number): number {\n const box = root.getBoundingClientRect();\n const horizontal = axis === \"horizontal\";\n const span = horizontal ? box.width : box.height;\n if (span === 0) return 0;\n const offset = horizontal ? clientX - box.left : clientY - box.top;\n // Logical, not physical: in RTL the primary pane starts at the right edge.\n const flipped = horizontal && getComputedStyle(root).direction === \"rtl\";\n return (flipped ? span - offset : offset) / span;\n}\n\nexport const Splitter = forwardRef<HTMLDivElement, SplitterProps>(function Splitter(\n {\n label,\n min,\n max,\n step,\n axis = splitterDefaults.axis,\n value: controlledValue,\n defaultValue,\n onValueChange,\n onValueChangeEnd,\n getValueText,\n disabled = false,\n primaryPane,\n secondaryPane,\n className,\n style,\n },\n forwardedRef,\n) {\n const [value, setValue] = useControllableState<number>({\n ...(controlledValue === undefined ? {} : { value: controlledValue }),\n defaultValue: defaultValue ?? min,\n ...(onValueChange === undefined ? {} : { onChange: onValueChange }),\n });\n const descriptor = {\n value,\n min,\n max,\n ...(step === undefined ? {} : { step }),\n axis,\n label,\n ...(getValueText === undefined ? {} : { valueText: getValueText(value) }),\n };\n validateSplitterDescriptor(descriptor);\n const rootRef = useRef<HTMLDivElement>(null);\n const [dragging, setDragging] = useState(false);\n\n const commit = (next: number) => {\n if (next !== value) setValue(next);\n return next;\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return;\n const root = rootRef.current;\n const flipped = axis === \"horizontal\" && root !== null && getComputedStyle(root).direction === \"rtl\";\n const intent = arrowIntent(event.key, axis, flipped);\n const next =\n event.key === \"Home\" || event.key === \"End\"\n ? resolveSplitterBoundaryValue(descriptor, event.key === \"Home\" ? \"min\" : \"max\")\n : intent === undefined\n ? undefined\n : getNextSplitterValue(descriptor, intent);\n if (next === undefined) return;\n event.preventDefault();\n // Keyboard resize settles immediately: there is no drag to release, but an\n // owner persisting the size still needs the same end signal a drag gives.\n if (next === value) return;\n // Commit before notifying, never as the argument of an optional call:\n // `onValueChangeEnd?.(commit(next))` skips the argument entirely when no\n // handler is passed, so keyboard resize would silently do nothing.\n commit(next);\n // A step already at the boundary changes nothing, so it is not a settlement\n // — an owner persisting on every end would otherwise write a no-op.\n onValueChangeEnd?.(next);\n };\n const onPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n if (disabled || event.button !== 0) return;\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n setDragging(true);\n };\n const resize = (event: PointerEvent<HTMLDivElement>) => {\n const root = rootRef.current;\n if (!dragging || !root) return;\n const fraction = fractionFromPointer(root, axis, event.clientX, event.clientY);\n commit(resolveSplitterDragValue(descriptor, min + fraction * (max - min)));\n };\n const endDrag = (event: PointerEvent<HTMLDivElement>) => {\n if (!dragging) return;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n setDragging(false);\n onValueChangeEnd?.(value);\n };\n\n const fraction = max === min ? 0 : (value - min) / (max - min);\n return (\n <div\n ref={composeRefs(rootRef, forwardedRef)}\n className={classNames(\"hjm-splitter\", className)}\n data-axis={axis}\n data-dragging={dragging || undefined}\n style={{ ...style, \"--hjm-splitter-primary\": `${fraction * 100}%` } as CSSProperties}\n >\n <div className=\"hjm-splitter__pane\" data-pane=\"primary\">{primaryPane}</div>\n <div\n role=\"separator\"\n // Perpendicular by contract: side-by-side panes have a vertical bar.\n aria-orientation={resolveSplitterSeparatorOrientation(axis)}\n aria-label={label}\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuetext={descriptor.valueText}\n aria-disabled={disabled || undefined}\n tabIndex={disabled ? -1 : 0}\n className=\"hjm-splitter__separator\"\n style={{ \"--hjm-splitter-hit-target\": `${splitterRecipe.separator.hitTarget}px`, \"--hjm-splitter-thickness\": `${splitterRecipe.separator.thickness}px` } as CSSProperties}\n onKeyDown={onKeyDown}\n onPointerDown={onPointerDown}\n onPointerMove={resize}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n >\n <span className=\"hjm-splitter__handle\" aria-hidden=\"true\" />\n </div>\n <div className=\"hjm-splitter__pane\" data-pane=\"secondary\">{secondaryPane}</div>\n </div>\n );\n});\n\nfunction arrowIntent(\n key: string,\n axis: SplitterAxis,\n flipped: boolean,\n): \"increment\" | \"decrement\" | undefined {\n // Only the axis the panes are arranged along resizes; the other pair of arrow\n // keys belongs to whatever the pane content does with them. `flipped` keeps the\n // keyboard on the same logical direction the drag uses: in RTL the primary pane\n // grows toward the left, so ArrowLeft is the increment.\n if (axis === \"horizontal\") {\n if (key === (flipped ? \"ArrowLeft\" : \"ArrowRight\")) return \"increment\";\n if (key === (flipped ? \"ArrowRight\" : \"ArrowLeft\")) return \"decrement\";\n return undefined;\n }\n if (key === \"ArrowDown\") return \"increment\";\n if (key === \"ArrowUp\") return \"decrement\";\n return undefined;\n}\n"]}
|