@planningcenter/tapestry 4.9.0-rc.0 → 4.9.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,16 +22,6 @@ export type DropdownElementProps = DropdownProps;
22
22
  * `<DropdownAction>`, `<DropdownLink>`, `<DropdownSection>`, and
23
23
  * `<DropdownSeparator>` items.
24
24
  *
25
- * **Dropdown vs Select.** Use `Dropdown` to trigger an action ("Edit",
26
- * "Delete") or navigate ("Go to documentation"). Use `Select` to collect a
27
- * value that is bound to form data or component state. They look visually
28
- * similar but follow different ARIA patterns (Menu vs Combobox/Listbox) and
29
- * are not interchangeable.
30
- *
31
- * **Dropdown vs Popover.** A flat list of actions or links → `Dropdown`.
32
- * Anything else anchored to a button (a form, a list, plain text) →
33
- * `Popover`. They're peers, not alternatives for the same content.
34
- *
35
25
  * Built on React Aria's `MenuTrigger` primitive; popover positioning and menu
36
26
  * identity live on `<DropdownMenu>`.
37
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.d.ts","sourceRoot":"","sources":["../../../src/components/dropdown/Dropdown.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Dropdown.d.ts","sourceRoot":"","sources":["../../../src/components/dropdown/Dropdown.tsx"],"names":[],"mappings":"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"}
@@ -14,16 +14,6 @@ import { DropdownTriggerContext } from './DropdownTriggerContext.js';
14
14
  * `<DropdownAction>`, `<DropdownLink>`, `<DropdownSection>`, and
15
15
  * `<DropdownSeparator>` items.
16
16
  *
17
- * **Dropdown vs Select.** Use `Dropdown` to trigger an action ("Edit",
18
- * "Delete") or navigate ("Go to documentation"). Use `Select` to collect a
19
- * value that is bound to form data or component state. They look visually
20
- * similar but follow different ARIA patterns (Menu vs Combobox/Listbox) and
21
- * are not interchangeable.
22
- *
23
- * **Dropdown vs Popover.** A flat list of actions or links → `Dropdown`.
24
- * Anything else anchored to a button (a form, a list, plain text) →
25
- * `Popover`. They're peers, not alternatives for the same content.
26
- *
27
17
  * Built on React Aria's `MenuTrigger` primitive; popover positioning and menu
28
18
  * identity live on `<DropdownMenu>`.
29
19
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Dropdown.js","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { Slot } from \"@radix-ui/react-slot\"\nimport type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n type ReactElement,\n type ReactNode,\n type RefObject,\n useContext,\n useRef,\n} from \"react\"\nimport { FocusScope, useInteractOutside, usePreventScroll } from \"react-aria\"\nimport type {\n Key,\n MenuItemProps,\n MenuSectionProps,\n PopoverProps,\n} from \"react-aria-components\"\nimport {\n Header,\n Menu,\n MenuItem,\n MenuSection,\n MenuTrigger,\n Popover,\n Pressable,\n RootMenuTriggerStateContext,\n Separator,\n} from \"react-aria-components/Menu\"\nimport { PopoverContext } from \"react-aria-components/Popover\"\n\nimport { DropdownTriggerContext } from \"./DropdownTriggerContext\"\n\nexport type DropdownPlacement = NonNullable<PopoverProps[\"placement\"]>\n\nexport interface DropdownProps {\n /**\n * A `<DropdownTrigger>` followed by a `<DropdownMenu>` containing the items.\n */\n children: ReactNode\n /** Fires when the menu closes. */\n onClose?: () => void\n /** Fires when the menu opens. Useful for analytics or lazy data prep. */\n onOpen?: () => void\n}\n\nexport type DropdownElementProps = DropdownProps\n\n/**\n * An action menu — a button that, when activated, reveals a list of actions or\n * navigation links. Composed of a `<DropdownTrigger>` wrapping a Tapestry\n * dropdown-trigger button (`DropdownButton`, `DropdownIconButton`, or\n * `PageHeaderActionsDropdownButton`) and a `<DropdownMenu>` containing\n * `<DropdownAction>`, `<DropdownLink>`, `<DropdownSection>`, and\n * `<DropdownSeparator>` items.\n *\n * **Dropdown vs Select.** Use `Dropdown` to trigger an action (\"Edit\",\n * \"Delete\") or navigate (\"Go to documentation\"). Use `Select` to collect a\n * value that is bound to form data or component state. They look visually\n * similar but follow different ARIA patterns (Menu vs Combobox/Listbox) and\n * are not interchangeable.\n *\n * **Dropdown vs Popover.** A flat list of actions or links → `Dropdown`.\n * Anything else anchored to a button (a form, a list, plain text) →\n * `Popover`. They're peers, not alternatives for the same content.\n *\n * Built on React Aria's `MenuTrigger` primitive; popover positioning and menu\n * identity live on `<DropdownMenu>`.\n *\n * @component\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/menu/ | W3C APG Menu Pattern}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport function Dropdown({ children, onClose, onOpen }: DropdownElementProps) {\n const handleOpenChange = (isOpen: boolean) => {\n if (isOpen) onOpen?.()\n else onClose?.()\n }\n\n return <MenuTrigger onOpenChange={handleOpenChange}>{children}</MenuTrigger>\n}\n\nexport interface DropdownMenuProps {\n /** Arbitrary `data-*` attributes are forwarded to the menu element. */\n [key: `data-${string}`]: boolean | number | string | undefined\n /**\n * `<DropdownAction>` / `<DropdownLink>` / `<DropdownSection>` /\n * `<DropdownSeparator>` elements.\n */\n children: ReactNode\n /** Override for the underlying `<Menu>` element id. */\n id?: string\n /**\n * Popover position relative to the trigger. Uses React Aria's\n * space-separated format (e.g., `\"bottom start\"`, `\"top end\"`,\n * `\"left top\"`). Defaults to `\"bottom start\"`.\n */\n placement?: DropdownPlacement\n}\n\nexport type DropdownMenuElementProps = DropdownMenuProps\n\nfunction useMenuTriggerRef() {\n const popoverContext = useContext(PopoverContext)\n return popoverContext && \"triggerRef\" in popoverContext\n ? popoverContext.triggerRef\n : undefined\n}\n\nfunction isTouchOnTrigger({\n event,\n menuTriggerRef,\n pointerType,\n}: {\n event: PointerEvent\n menuTriggerRef: RefObject<Element | null> | undefined\n pointerType: string | null\n}) {\n const isTouch = pointerType === \"touch\"\n const isOnMenuTrigger =\n event.target instanceof Node &&\n Boolean(menuTriggerRef?.current?.contains(event.target))\n return isTouch && isOnMenuTrigger\n}\n\n/**\n * The popover surface for a `<Dropdown>`. Wraps React Aria's `<Popover>` and\n * `<Menu>` and contains the menu items.\n *\n * @component\n */\nexport function DropdownMenu({\n children,\n id,\n placement = \"bottom start\",\n ...dataAttributes\n}: DropdownMenuElementProps) {\n const popoverRef = useRef<HTMLElement>(null)\n const state = useContext(RootMenuTriggerStateContext)\n const menuTriggerRef = useMenuTriggerRef()\n const lastPointerType = useRef<string | null>(null)\n\n useInteractOutside({\n isDisabled: !state?.isOpen,\n onInteractOutside: (event) => {\n const triggerWillToggleClosed = isTouchOnTrigger({\n event,\n menuTriggerRef,\n pointerType: lastPointerType.current,\n })\n if (triggerWillToggleClosed) return\n\n state?.close()\n },\n onInteractOutsideStart: (event) => {\n lastPointerType.current = event.pointerType\n },\n ref: popoverRef,\n })\n usePreventScroll({ isDisabled: !state?.isOpen })\n\n return (\n <Popover\n className=\"tds-dropdown-popover\"\n isNonModal\n placement={placement}\n ref={popoverRef}\n shouldCloseOnInteractOutside={() => false}\n >\n <FocusScope contain>\n <Menu {...dataAttributes} id={id}>\n {children}\n </Menu>\n </FocusScope>\n </Popover>\n )\n}\n\nexport interface DropdownTriggerProps {\n /**\n * A single Tapestry dropdown-trigger button element (`DropdownButton`,\n * `DropdownIconButton`, or `PageHeaderActionsDropdownButton`).\n */\n children: ReactElement\n /**\n * Whether the trigger is disabled. This is the single source of truth for the\n * trigger's disabled state — a `disabled` set directly on the child button\n * does not win.\n */\n disabled?: boolean\n}\n\n/**\n * Wraps a single Tapestry dropdown-trigger button and bridges it to React\n * Aria's `MenuTrigger` via `<Pressable>`.\n * Uses context to pass `disabled` to the trigger button.\n *\n * @component\n */\ntype PressableChild = ComponentProps<typeof Pressable>[\"children\"]\n\nexport function DropdownTrigger({ children, disabled }: DropdownTriggerProps) {\n return (\n <DropdownTriggerContext.Provider value={{ disabled }}>\n <Pressable isDisabled={disabled}>{children as PressableChild}</Pressable>\n </DropdownTriggerContext.Provider>\n )\n}\n\nexport interface DropdownItemBaseProps {\n /** Applies destructive styling. */\n destructive?: boolean\n /** Applies staff-only visual treatment. */\n staffOnly?: boolean\n}\n\nexport interface DropdownActionProps extends DropdownItemBaseProps {\n /**\n * Disables the item. Renamed to React Aria's `isDisabled` inside the\n * wrapper. Disabled items are skipped by keyboard traversal and won't fire\n * `onAction`.\n */\n disabled?: boolean\n /**\n * Stable identifier — required by React Aria's collection model for keying\n * and focus tracking.\n */\n id: Key\n /**\n * Callback fired when the item is activated.\n *\n * React Aria closes the menu and returns focus to the trigger after this\n * runs, which can override a focus change made here — e.g. focusing a\n * nearby input. If `onAction` needs to move focus elsewhere, wrap that\n * part in `queueMicrotask` to defer it until after React Aria's\n * focus-restore has finished: `queueMicrotask(() => inputRef.current?.focus())`.\n */\n onAction: () => void\n}\n\ntype AriaActionPropsToOmit =\n | \"href\"\n | \"isDisabled\"\n | \"rel\"\n | \"routerOptions\"\n | \"target\"\n | \"value\"\ntype AriaActionPropsToInclude = \"textValue\"\n\nexport type DropdownActionElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuItemProps<T>,\n DropdownActionProps,\n AriaActionPropsToOmit,\n AriaActionPropsToInclude\n >\n\n/**\n * A `<Dropdown>` item that fires a callback when activated. Renders an RA\n * `<MenuItem>` (`role=\"menuitem\"`). Children are passed through and can use\n * the slot convention (`slot=\"label\" | \"prefix\" | \"suffix\" | \"description\"`)\n * for structured content.\n *\n * @component\n */\nexport function DropdownAction<T extends object>({\n className,\n destructive,\n disabled,\n staffOnly,\n ...restProps\n}: DropdownActionElementProps<T>) {\n return (\n <MenuItem\n {...restProps}\n className={classNames(\n \"tds-dropdown-item\",\n {\n \"tds-dropdown-item--destructive\": destructive,\n \"tds-dropdown-item--staff-only\": staffOnly,\n },\n className\n )}\n isDisabled={disabled}\n />\n )\n}\n\nexport interface DropdownLinkBaseProps extends DropdownItemBaseProps {\n /** If `true`, sets `target=\"_blank\"` and `rel=\"noreferrer noopener\"`. */\n external?: boolean\n /**\n * Stable identifier — required by React Aria's collection model for keying\n * and focus tracking.\n */\n id: Key\n}\n\nexport interface DropdownLinkAsChildProps extends DropdownLinkBaseProps {\n /**\n * Merge menu item behavior onto a single child element (e.g. a router\n * `Link`) instead of rendering an `<a>`. When true, `href` must not be set.\n * **Not supported in Rails.**\n */\n asChild: true\n href?: never\n}\n\nexport interface DropdownLinkHrefProps extends DropdownLinkBaseProps {\n asChild?: false\n /** Destination URL. */\n href: string\n}\n\nexport type DropdownLinkProps = DropdownLinkAsChildProps | DropdownLinkHrefProps\n\ntype AriaLinkPropsToOmit =\n | \"isDisabled\"\n | \"onAction\"\n | \"rel\"\n | \"render\"\n | \"target\"\n | \"value\"\ntype AriaLinkPropsToInclude = \"routerOptions\" | \"textValue\"\n\nexport type DropdownLinkElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuItemProps<T>,\n DropdownLinkProps,\n AriaLinkPropsToOmit,\n AriaLinkPropsToInclude\n >\n\n/** Strips RAC-injected `undefined` values (e.g. `href`) that would otherwise clobber a child's own prop of the same name via `Slot`. */\nfunction omitUndefinedValues<T extends object>(props: T): Partial<T> {\n return Object.fromEntries(\n Object.entries(props).filter(([, value]) => value !== undefined)\n ) as Partial<T>\n}\n\n/**\n * A `<Dropdown>` item that navigates to a URL. Renders an RA `<MenuItem>` as\n * an anchor (`<a role=\"menuitem\" href=\"…\">`). Pass `external` to open in a\n * new tab with `rel=\"noreferrer noopener\"`.\n *\n * `disabled` is intentionally not accepted — HTML has no native disabled state\n * for anchors, and a \"disabled link\" has no accessible analog. If a link\n * shouldn't be activatable, omit it.\n *\n * @component\n */\nexport function DropdownLink<T extends object>({\n asChild = false,\n children,\n className,\n destructive,\n external,\n staffOnly,\n ...restProps\n}: DropdownLinkElementProps<T>) {\n const externalProps = external\n ? { rel: \"noreferrer noopener\", target: \"_blank\" as const }\n : null\n return (\n <MenuItem\n {...restProps}\n {...externalProps}\n className={classNames(\n \"tds-dropdown-item\",\n {\n \"tds-dropdown-item--destructive\": destructive,\n \"tds-dropdown-item--staff-only\": staffOnly,\n },\n className\n )}\n render={\n asChild\n ? (props) => (\n <Slot {...omitUndefinedValues(props)}>\n {children as ReactElement}\n </Slot>\n )\n : undefined\n }\n >\n {asChild ? undefined : children}\n </MenuItem>\n )\n}\n\nexport interface DropdownSectionProps {\n /** The items rendered within the section. */\n children: ReactNode\n /**\n * Heading rendered above the section's items. Required — RA renders the\n * section as `role=\"group\"` and the heading provides the group's\n * accessible name via `aria-labelledby`.\n */\n title: string\n}\n\nexport type DropdownSectionElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuSectionProps<T>,\n DropdownSectionProps,\n \"value\",\n never\n >\n\n/**\n * A grouped section within a `<Dropdown>`. Renders an RA `<MenuSection>`\n * (`role=\"group\"`) with an optional `<Header>` heading when `title` is set.\n *\n * @component\n */\nexport function DropdownSection<T extends object>({\n children,\n className,\n title,\n ...restProps\n}: DropdownSectionElementProps<T>) {\n return (\n <MenuSection\n {...restProps}\n className={classNames(\"tds-dropdown-section\", className)}\n >\n <Header className=\"tds-dropdown-section-label\">{title}</Header>\n {children}\n </MenuSection>\n )\n}\n\nexport type DropdownSeparatorElementProps = Record<string, never>\n\n/**\n * A divider between items in a `<Dropdown>`. Renders an RA `<Separator>`\n * (`role=\"separator\"`).\n *\n * @component\n */\nexport function DropdownSeparator() {\n return <Separator className=\"tds-dropdown-separator\" />\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Dropdown.js","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { Slot } from \"@radix-ui/react-slot\"\nimport type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n type ReactElement,\n type ReactNode,\n type RefObject,\n useContext,\n useRef,\n} from \"react\"\nimport { FocusScope, useInteractOutside, usePreventScroll } from \"react-aria\"\nimport type {\n Key,\n MenuItemProps,\n MenuSectionProps,\n PopoverProps,\n} from \"react-aria-components\"\nimport {\n Header,\n Menu,\n MenuItem,\n MenuSection,\n MenuTrigger,\n Popover,\n Pressable,\n RootMenuTriggerStateContext,\n Separator,\n} from \"react-aria-components/Menu\"\nimport { PopoverContext } from \"react-aria-components/Popover\"\n\nimport { DropdownTriggerContext } from \"./DropdownTriggerContext\"\n\nexport type DropdownPlacement = NonNullable<PopoverProps[\"placement\"]>\n\nexport interface DropdownProps {\n /**\n * A `<DropdownTrigger>` followed by a `<DropdownMenu>` containing the items.\n */\n children: ReactNode\n /** Fires when the menu closes. */\n onClose?: () => void\n /** Fires when the menu opens. Useful for analytics or lazy data prep. */\n onOpen?: () => void\n}\n\nexport type DropdownElementProps = DropdownProps\n\n/**\n * An action menu — a button that, when activated, reveals a list of actions or\n * navigation links. Composed of a `<DropdownTrigger>` wrapping a Tapestry\n * dropdown-trigger button (`DropdownButton`, `DropdownIconButton`, or\n * `PageHeaderActionsDropdownButton`) and a `<DropdownMenu>` containing\n * `<DropdownAction>`, `<DropdownLink>`, `<DropdownSection>`, and\n * `<DropdownSeparator>` items.\n *\n * Built on React Aria's `MenuTrigger` primitive; popover positioning and menu\n * identity live on `<DropdownMenu>`.\n *\n * @component\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/menu/ | W3C APG Menu Pattern}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport function Dropdown({ children, onClose, onOpen }: DropdownElementProps) {\n const handleOpenChange = (isOpen: boolean) => {\n if (isOpen) onOpen?.()\n else onClose?.()\n }\n\n return <MenuTrigger onOpenChange={handleOpenChange}>{children}</MenuTrigger>\n}\n\nexport interface DropdownMenuProps {\n /** Arbitrary `data-*` attributes are forwarded to the menu element. */\n [key: `data-${string}`]: boolean | number | string | undefined\n /**\n * `<DropdownAction>` / `<DropdownLink>` / `<DropdownSection>` /\n * `<DropdownSeparator>` elements.\n */\n children: ReactNode\n /** Override for the underlying `<Menu>` element id. */\n id?: string\n /**\n * Popover position relative to the trigger. Uses React Aria's\n * space-separated format (e.g., `\"bottom start\"`, `\"top end\"`,\n * `\"left top\"`). Defaults to `\"bottom start\"`.\n */\n placement?: DropdownPlacement\n}\n\nexport type DropdownMenuElementProps = DropdownMenuProps\n\nfunction useMenuTriggerRef() {\n const popoverContext = useContext(PopoverContext)\n return popoverContext && \"triggerRef\" in popoverContext\n ? popoverContext.triggerRef\n : undefined\n}\n\nfunction isTouchOnTrigger({\n event,\n menuTriggerRef,\n pointerType,\n}: {\n event: PointerEvent\n menuTriggerRef: RefObject<Element | null> | undefined\n pointerType: string | null\n}) {\n const isTouch = pointerType === \"touch\"\n const isOnMenuTrigger =\n event.target instanceof Node &&\n Boolean(menuTriggerRef?.current?.contains(event.target))\n return isTouch && isOnMenuTrigger\n}\n\n/**\n * The popover surface for a `<Dropdown>`. Wraps React Aria's `<Popover>` and\n * `<Menu>` and contains the menu items.\n *\n * @component\n */\nexport function DropdownMenu({\n children,\n id,\n placement = \"bottom start\",\n ...dataAttributes\n}: DropdownMenuElementProps) {\n const popoverRef = useRef<HTMLElement>(null)\n const state = useContext(RootMenuTriggerStateContext)\n const menuTriggerRef = useMenuTriggerRef()\n const lastPointerType = useRef<string | null>(null)\n\n useInteractOutside({\n isDisabled: !state?.isOpen,\n onInteractOutside: (event) => {\n const triggerWillToggleClosed = isTouchOnTrigger({\n event,\n menuTriggerRef,\n pointerType: lastPointerType.current,\n })\n if (triggerWillToggleClosed) return\n\n state?.close()\n },\n onInteractOutsideStart: (event) => {\n lastPointerType.current = event.pointerType\n },\n ref: popoverRef,\n })\n usePreventScroll({ isDisabled: !state?.isOpen })\n\n return (\n <Popover\n className=\"tds-dropdown-popover\"\n isNonModal\n placement={placement}\n ref={popoverRef}\n shouldCloseOnInteractOutside={() => false}\n >\n <FocusScope contain>\n <Menu {...dataAttributes} id={id}>\n {children}\n </Menu>\n </FocusScope>\n </Popover>\n )\n}\n\nexport interface DropdownTriggerProps {\n /**\n * A single Tapestry dropdown-trigger button element (`DropdownButton`,\n * `DropdownIconButton`, or `PageHeaderActionsDropdownButton`).\n */\n children: ReactElement\n /**\n * Whether the trigger is disabled. This is the single source of truth for the\n * trigger's disabled state — a `disabled` set directly on the child button\n * does not win.\n */\n disabled?: boolean\n}\n\n/**\n * Wraps a single Tapestry dropdown-trigger button and bridges it to React\n * Aria's `MenuTrigger` via `<Pressable>`.\n * Uses context to pass `disabled` to the trigger button.\n *\n * @component\n */\ntype PressableChild = ComponentProps<typeof Pressable>[\"children\"]\n\nexport function DropdownTrigger({ children, disabled }: DropdownTriggerProps) {\n return (\n <DropdownTriggerContext.Provider value={{ disabled }}>\n <Pressable isDisabled={disabled}>{children as PressableChild}</Pressable>\n </DropdownTriggerContext.Provider>\n )\n}\n\nexport interface DropdownItemBaseProps {\n /** Applies destructive styling. */\n destructive?: boolean\n /** Applies staff-only visual treatment. */\n staffOnly?: boolean\n}\n\nexport interface DropdownActionProps extends DropdownItemBaseProps {\n /**\n * Disables the item. Renamed to React Aria's `isDisabled` inside the\n * wrapper. Disabled items are skipped by keyboard traversal and won't fire\n * `onAction`.\n */\n disabled?: boolean\n /**\n * Stable identifier — required by React Aria's collection model for keying\n * and focus tracking.\n */\n id: Key\n /**\n * Callback fired when the item is activated.\n *\n * React Aria closes the menu and returns focus to the trigger after this\n * runs, which can override a focus change made here — e.g. focusing a\n * nearby input. If `onAction` needs to move focus elsewhere, wrap that\n * part in `queueMicrotask` to defer it until after React Aria's\n * focus-restore has finished: `queueMicrotask(() => inputRef.current?.focus())`.\n */\n onAction: () => void\n}\n\ntype AriaActionPropsToOmit =\n | \"href\"\n | \"isDisabled\"\n | \"rel\"\n | \"routerOptions\"\n | \"target\"\n | \"value\"\ntype AriaActionPropsToInclude = \"textValue\"\n\nexport type DropdownActionElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuItemProps<T>,\n DropdownActionProps,\n AriaActionPropsToOmit,\n AriaActionPropsToInclude\n >\n\n/**\n * A `<Dropdown>` item that fires a callback when activated. Renders an RA\n * `<MenuItem>` (`role=\"menuitem\"`). Children are passed through and can use\n * the slot convention (`slot=\"label\" | \"prefix\" | \"suffix\" | \"description\"`)\n * for structured content.\n *\n * @component\n */\nexport function DropdownAction<T extends object>({\n className,\n destructive,\n disabled,\n staffOnly,\n ...restProps\n}: DropdownActionElementProps<T>) {\n return (\n <MenuItem\n {...restProps}\n className={classNames(\n \"tds-dropdown-item\",\n {\n \"tds-dropdown-item--destructive\": destructive,\n \"tds-dropdown-item--staff-only\": staffOnly,\n },\n className\n )}\n isDisabled={disabled}\n />\n )\n}\n\nexport interface DropdownLinkBaseProps extends DropdownItemBaseProps {\n /** If `true`, sets `target=\"_blank\"` and `rel=\"noreferrer noopener\"`. */\n external?: boolean\n /**\n * Stable identifier — required by React Aria's collection model for keying\n * and focus tracking.\n */\n id: Key\n}\n\nexport interface DropdownLinkAsChildProps extends DropdownLinkBaseProps {\n /**\n * Merge menu item behavior onto a single child element (e.g. a router\n * `Link`) instead of rendering an `<a>`. When true, `href` must not be set.\n * **Not supported in Rails.**\n */\n asChild: true\n href?: never\n}\n\nexport interface DropdownLinkHrefProps extends DropdownLinkBaseProps {\n asChild?: false\n /** Destination URL. */\n href: string\n}\n\nexport type DropdownLinkProps = DropdownLinkAsChildProps | DropdownLinkHrefProps\n\ntype AriaLinkPropsToOmit =\n | \"isDisabled\"\n | \"onAction\"\n | \"rel\"\n | \"render\"\n | \"target\"\n | \"value\"\ntype AriaLinkPropsToInclude = \"routerOptions\" | \"textValue\"\n\nexport type DropdownLinkElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuItemProps<T>,\n DropdownLinkProps,\n AriaLinkPropsToOmit,\n AriaLinkPropsToInclude\n >\n\n/** Strips RAC-injected `undefined` values (e.g. `href`) that would otherwise clobber a child's own prop of the same name via `Slot`. */\nfunction omitUndefinedValues<T extends object>(props: T): Partial<T> {\n return Object.fromEntries(\n Object.entries(props).filter(([, value]) => value !== undefined)\n ) as Partial<T>\n}\n\n/**\n * A `<Dropdown>` item that navigates to a URL. Renders an RA `<MenuItem>` as\n * an anchor (`<a role=\"menuitem\" href=\"…\">`). Pass `external` to open in a\n * new tab with `rel=\"noreferrer noopener\"`.\n *\n * `disabled` is intentionally not accepted — HTML has no native disabled state\n * for anchors, and a \"disabled link\" has no accessible analog. If a link\n * shouldn't be activatable, omit it.\n *\n * @component\n */\nexport function DropdownLink<T extends object>({\n asChild = false,\n children,\n className,\n destructive,\n external,\n staffOnly,\n ...restProps\n}: DropdownLinkElementProps<T>) {\n const externalProps = external\n ? { rel: \"noreferrer noopener\", target: \"_blank\" as const }\n : null\n return (\n <MenuItem\n {...restProps}\n {...externalProps}\n className={classNames(\n \"tds-dropdown-item\",\n {\n \"tds-dropdown-item--destructive\": destructive,\n \"tds-dropdown-item--staff-only\": staffOnly,\n },\n className\n )}\n render={\n asChild\n ? (props) => (\n <Slot {...omitUndefinedValues(props)}>\n {children as ReactElement}\n </Slot>\n )\n : undefined\n }\n >\n {asChild ? undefined : children}\n </MenuItem>\n )\n}\n\nexport interface DropdownSectionProps {\n /** The items rendered within the section. */\n children: ReactNode\n /**\n * Heading rendered above the section's items. Required — RA renders the\n * section as `role=\"group\"` and the heading provides the group's\n * accessible name via `aria-labelledby`.\n */\n title: string\n}\n\nexport type DropdownSectionElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuSectionProps<T>,\n DropdownSectionProps,\n \"value\",\n never\n >\n\n/**\n * A grouped section within a `<Dropdown>`. Renders an RA `<MenuSection>`\n * (`role=\"group\"`) with an optional `<Header>` heading when `title` is set.\n *\n * @component\n */\nexport function DropdownSection<T extends object>({\n children,\n className,\n title,\n ...restProps\n}: DropdownSectionElementProps<T>) {\n return (\n <MenuSection\n {...restProps}\n className={classNames(\"tds-dropdown-section\", className)}\n >\n <Header className=\"tds-dropdown-section-label\">{title}</Header>\n {children}\n </MenuSection>\n )\n}\n\nexport type DropdownSeparatorElementProps = Record<string, never>\n\n/**\n * A divider between items in a `<Dropdown>`. Renders an RA `<Separator>`\n * (`role=\"separator\"`).\n *\n * @component\n */\nexport function DropdownSeparator() {\n return <Separator className=\"tds-dropdown-separator\" />\n}\n"],"names":[],"mappings":";;;;;;;;AAkDA;;;;;;;;;;;;;;AAcG;AACG,SAAU,QAAQ,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAwB,EAAA;AAC1E,IAAA,MAAM,gBAAgB,GAAG,CAAC,MAAe,KAAI;AAC3C,QAAA,IAAI,MAAM;YAAE,MAAM,IAAI;;YACjB,OAAO,IAAI;AAClB,IAAA,CAAC;IAED,OAAO,KAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAC,YAAY,EAAE,gBAAgB,EAAA,EAAG,QAAQ,CAAe;AAC9E;AAsBA,SAAS,iBAAiB,GAAA;AACxB,IAAA,MAAM,cAAc,GAAG,UAAU,CAAC,cAAc,CAAC;AACjD,IAAA,OAAO,cAAc,IAAI,YAAY,IAAI;UACrC,cAAc,CAAC;UACf,SAAS;AACf;AAEA,SAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,cAAc,EACd,WAAW,GAKZ,EAAA;AACC,IAAA,MAAM,OAAO,GAAG,WAAW,KAAK,OAAO;AACvC,IAAA,MAAM,eAAe,GACnB,KAAK,CAAC,MAAM,YAAY,IAAI;AAC5B,QAAA,OAAO,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1D,OAAO,OAAO,IAAI,eAAe;AACnC;AAEA;;;;;AAKG;AACG,SAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,EAAE,EACF,SAAS,GAAG,cAAc,EAC1B,GAAG,cAAc,EACQ,EAAA;AACzB,IAAA,MAAM,UAAU,GAAG,MAAM,CAAc,IAAI,CAAC;AAC5C,IAAA,MAAM,KAAK,GAAG,UAAU,CAAC,2BAA2B,CAAC;AACrD,IAAA,MAAM,cAAc,GAAG,iBAAiB,EAAE;AAC1C,IAAA,MAAM,eAAe,GAAG,MAAM,CAAgB,IAAI,CAAC;AAEnD,IAAA,kBAAkB,CAAC;AACjB,QAAA,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM;AAC1B,QAAA,iBAAiB,EAAE,CAAC,KAAK,KAAI;YAC3B,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;gBAC/C,KAAK;gBACL,cAAc;gBACd,WAAW,EAAE,eAAe,CAAC,OAAO;AACrC,aAAA,CAAC;AACF,YAAA,IAAI,uBAAuB;gBAAE;YAE7B,KAAK,EAAE,KAAK,EAAE;QAChB,CAAC;AACD,QAAA,sBAAsB,EAAE,CAAC,KAAK,KAAI;AAChC,YAAA,eAAe,CAAC,OAAO,GAAG,KAAK,CAAC,WAAW;QAC7C,CAAC;AACD,QAAA,GAAG,EAAE,UAAU;AAChB,KAAA,CAAC;IACF,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAEhD,QACE,oBAAC,OAAO,EAAA,EACN,SAAS,EAAC,sBAAsB,EAChC,UAAU,EAAA,IAAA,EACV,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,UAAU,EACf,4BAA4B,EAAE,MAAM,KAAK,EAAA;QAEzC,KAAA,CAAA,aAAA,CAAC,UAAU,IAAC,OAAO,EAAA,IAAA,EAAA;AACjB,YAAA,KAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAA,GAAK,cAAc,EAAE,EAAE,EAAE,EAAE,EAAA,EAC7B,QAAQ,CACJ,CACI,CACL;AAEd;SAyBgB,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAwB,EAAA;IAC1E,QACE,KAAA,CAAA,aAAA,CAAC,sBAAsB,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAA;QAClD,KAAA,CAAA,aAAA,CAAC,SAAS,EAAA,EAAC,UAAU,EAAE,QAAQ,IAAG,QAA0B,CAAa,CACzC;AAEtC;AAkDA;;;;;;;AAOG;AACG,SAAU,cAAc,CAAmB,EAC/C,SAAS,EACT,WAAW,EACX,QAAQ,EACR,SAAS,EACT,GAAG,SAAS,EACkB,EAAA;IAC9B,QACE,KAAA,CAAA,aAAA,CAAC,QAAQ,EAAA,EAAA,GACH,SAAS,EACb,SAAS,EAAE,UAAU,CACnB,mBAAmB,EACnB;AACE,YAAA,gCAAgC,EAAE,WAAW;AAC7C,YAAA,+BAA+B,EAAE,SAAS;SAC3C,EACD,SAAS,CACV,EACD,UAAU,EAAE,QAAQ,EAAA,CACpB;AAEN;AA+CA;AACA,SAAS,mBAAmB,CAAmB,KAAQ,EAAA;IACrD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,SAAS,CAAC,CACnD;AACjB;AAEA;;;;;;;;;;AAUG;AACG,SAAU,YAAY,CAAmB,EAC7C,OAAO,GAAG,KAAK,EACf,QAAQ,EACR,SAAS,EACT,WAAW,EACX,QAAQ,EACR,SAAS,EACT,GAAG,SAAS,EACgB,EAAA;IAC5B,MAAM,aAAa,GAAG;UAClB,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,QAAiB;UACvD,IAAI;AACR,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,QAAQ,EAAA,EAAA,GACH,SAAS,EAAA,GACT,aAAa,EACjB,SAAS,EAAE,UAAU,CACnB,mBAAmB,EACnB;AACE,YAAA,gCAAgC,EAAE,WAAW;AAC7C,YAAA,+BAA+B,EAAE,SAAS;AAC3C,SAAA,EACD,SAAS,CACV,EACD,MAAM,EACJ;AACE,cAAE,CAAC,KAAK,MACJ,KAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAA,GAAK,mBAAmB,CAAC,KAAK,CAAC,EAAA,EACjC,QAAwB,CACpB;AAEX,cAAE,SAAS,EAAA,EAGd,OAAO,GAAG,SAAS,GAAG,QAAQ,CACtB;AAEf;AAqBA;;;;;AAKG;AACG,SAAU,eAAe,CAAmB,EAChD,QAAQ,EACR,SAAS,EACT,KAAK,EACL,GAAG,SAAS,EACmB,EAAA;AAC/B,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAA,GACN,SAAS,EACb,SAAS,EAAE,UAAU,CAAC,sBAAsB,EAAE,SAAS,CAAC,EAAA;AAExD,QAAA,KAAA,CAAA,aAAA,CAAC,MAAM,EAAA,EAAC,SAAS,EAAC,4BAA4B,EAAA,EAAE,KAAK,CAAU;QAC9D,QAAQ,CACG;AAElB;AAIA;;;;;AAKG;SACa,iBAAiB,GAAA;AAC/B,IAAA,OAAO,oBAAC,SAAS,EAAA,EAAC,SAAS,EAAC,wBAAwB,GAAG;AACzD;;;;"}
@@ -22,13 +22,6 @@ export type FieldProps = FieldExternallyLabeledProps | FieldLabeledProps;
22
22
  * A layout primitive that wraps a single form control with a label,
23
23
  * optional description, and state-driven styling (required, invalid, disabled).
24
24
  *
25
- * **Reach for a Tapestry form component first** — `Input`, `Checkbox`, `Radio`,
26
- * `ToggleSwitch`, `Select`, `ComboBox`, `DatePicker`, `TimeField`. Those
27
- * components handle their own label / description / state styling internally.
28
- *
29
- * **Use `Field` directly only when no Tapestry component fits your control** —
30
- * a custom widget, a third-party input, or an in-progress design.
31
- *
32
25
  * **Wiring contract** — Field renders children completely untouched. The caller
33
26
  * is responsible for:
34
27
  * - Setting `id` on the control to match the `id` prop passed to Field.
@@ -1 +1 @@
1
- {"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../../../src/components/field/Field.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAExC,UAAU,cAAc;IACtB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;CACX;AAED,UAAU,iBAAkB,SAAQ,cAAc;IAChD,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,SAAS,CAAA;CACjB;AAED,UAAU,2BAA4B,SAAQ,cAAc;IAC1D,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,MAAM,UAAU,GAAG,2BAA2B,GAAG,iBAAiB,CAAA;AAExE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,KAAK,CAAC,EACpB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,KAAK,GACN,EAAE,UAAU,qBAgCZ"}
1
+ {"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../../../src/components/field/Field.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAExC,UAAU,cAAc;IACtB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;CACX;AAED,UAAU,iBAAkB,SAAQ,cAAc;IAChD,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,SAAS,CAAA;CACjB;AAED,UAAU,2BAA4B,SAAQ,cAAc;IAC1D,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,MAAM,UAAU,GAAG,2BAA2B,GAAG,iBAAiB,CAAA;AAExE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,EACpB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,KAAK,GACN,EAAE,UAAU,qBAgCZ"}
@@ -6,13 +6,6 @@ import React from 'react';
6
6
  * A layout primitive that wraps a single form control with a label,
7
7
  * optional description, and state-driven styling (required, invalid, disabled).
8
8
  *
9
- * **Reach for a Tapestry form component first** — `Input`, `Checkbox`, `Radio`,
10
- * `ToggleSwitch`, `Select`, `ComboBox`, `DatePicker`, `TimeField`. Those
11
- * components handle their own label / description / state styling internally.
12
- *
13
- * **Use `Field` directly only when no Tapestry component fits your control** —
14
- * a custom widget, a third-party input, or an in-progress design.
15
- *
16
9
  * **Wiring contract** — Field renders children completely untouched. The caller
17
10
  * is responsible for:
18
11
  * - Setting `id` on the control to match the `id` prop passed to Field.
@@ -1 +1 @@
1
- {"version":3,"file":"Field.js","sources":["../../../src/components/field/Field.tsx"],"sourcesContent":["import Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, { ReactNode } from \"react\"\n\ninterface FieldBaseProps {\n children: ReactNode\n className?: string\n description?: ReactNode\n /** If true, sets `data-flex-expand` on the wrapper so it grows/shrinks to fill a `Flex` row. */\n expand?: boolean\n id: string\n}\n\ninterface FieldLabeledProps extends FieldBaseProps {\n \"aria-labelledby\"?: never\n hideLabel?: boolean\n label: ReactNode\n}\n\ninterface FieldExternallyLabeledProps extends FieldBaseProps {\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type FieldProps = FieldExternallyLabeledProps | FieldLabeledProps\n\n/**\n * A layout primitive that wraps a single form control with a label,\n * optional description, and state-driven styling (required, invalid, disabled).\n *\n * **Reach for a Tapestry form component first** — `Input`, `Checkbox`, `Radio`,\n * `ToggleSwitch`, `Select`, `ComboBox`, `DatePicker`, `TimeField`. Those\n * components handle their own label / description / state styling internally.\n *\n * **Use `Field` directly only when no Tapestry component fits your control** —\n * a custom widget, a third-party input, or an in-progress design.\n *\n * **Wiring contract** — Field renders children completely untouched. The caller\n * is responsible for:\n * - Setting `id` on the control to match the `id` prop passed to Field.\n * - Setting `aria-describedby=\"{id}-description\"` on the control when\n * `description` is provided.\n * - Setting `aria-labelledby` on the control when using `aria-labelledby` mode.\n * - Setting state attributes (`required`, `disabled`, `aria-invalid`) directly\n * on the control — Field's CSS detects them via `:has()`.\n *\n * @component\n */\nexport function Field({\n \"aria-labelledby\": ariaLabelledBy,\n children,\n className,\n description,\n expand,\n hideLabel,\n id,\n label,\n}: FieldProps) {\n const descriptionId = `${id}-description`\n\n return (\n <div\n className={classNames(\"tds-field\", className)}\n data-flex-expand={expand || undefined}\n >\n {label && !ariaLabelledBy && (\n <label\n className={classNames(\n \"tds-field-label\",\n hideLabel && \"tds-field-label--hidden\"\n )}\n htmlFor={id}\n >\n {label}\n </label>\n )}\n {children}\n {description && (\n <p className=\"tds-field-description\" id={descriptionId}>\n <Icon\n aria-hidden\n className=\"tds-field-description-invalid-icon\"\n symbol=\"general#exclamation-triangle\"\n />\n {description}\n </p>\n )}\n </div>\n )\n}\n"],"names":[],"mappings":";;;;AA2BA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,KAAK,CAAC,EACpB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,KAAK,GACM,EAAA;AACX,IAAA,MAAM,aAAa,GAAG,CAAA,EAAG,EAAE,cAAc;AAEzC,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,EAAA,kBAAA,EAC3B,MAAM,IAAI,SAAS,EAAA;QAEpC,KAAK,IAAI,CAAC,cAAc,KACvB,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EACE,SAAS,EAAE,UAAU,CACnB,iBAAiB,EACjB,SAAS,IAAI,yBAAyB,CACvC,EACD,OAAO,EAAE,EAAE,EAAA,EAEV,KAAK,CACA,CACT;QACA,QAAQ;QACR,WAAW,KACV,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,uBAAuB,EAAC,EAAE,EAAE,aAAa,EAAA;YACpD,KAAA,CAAA,aAAA,CAAC,IAAI,yBAEH,SAAS,EAAC,oCAAoC,EAC9C,MAAM,EAAC,8BAA8B,EAAA,CACrC;AACD,YAAA,WAAW,CACV,CACL,CACG;AAEV;;;;"}
1
+ {"version":3,"file":"Field.js","sources":["../../../src/components/field/Field.tsx"],"sourcesContent":["import Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, { ReactNode } from \"react\"\n\ninterface FieldBaseProps {\n children: ReactNode\n className?: string\n description?: ReactNode\n /** If true, sets `data-flex-expand` on the wrapper so it grows/shrinks to fill a `Flex` row. */\n expand?: boolean\n id: string\n}\n\ninterface FieldLabeledProps extends FieldBaseProps {\n \"aria-labelledby\"?: never\n hideLabel?: boolean\n label: ReactNode\n}\n\ninterface FieldExternallyLabeledProps extends FieldBaseProps {\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type FieldProps = FieldExternallyLabeledProps | FieldLabeledProps\n\n/**\n * A layout primitive that wraps a single form control with a label,\n * optional description, and state-driven styling (required, invalid, disabled).\n *\n * **Wiring contract** — Field renders children completely untouched. The caller\n * is responsible for:\n * - Setting `id` on the control to match the `id` prop passed to Field.\n * - Setting `aria-describedby=\"{id}-description\"` on the control when\n * `description` is provided.\n * - Setting `aria-labelledby` on the control when using `aria-labelledby` mode.\n * - Setting state attributes (`required`, `disabled`, `aria-invalid`) directly\n * on the control — Field's CSS detects them via `:has()`.\n *\n * @component\n */\nexport function Field({\n \"aria-labelledby\": ariaLabelledBy,\n children,\n className,\n description,\n expand,\n hideLabel,\n id,\n label,\n}: FieldProps) {\n const descriptionId = `${id}-description`\n\n return (\n <div\n className={classNames(\"tds-field\", className)}\n data-flex-expand={expand || undefined}\n >\n {label && !ariaLabelledBy && (\n <label\n className={classNames(\n \"tds-field-label\",\n hideLabel && \"tds-field-label--hidden\"\n )}\n htmlFor={id}\n >\n {label}\n </label>\n )}\n {children}\n {description && (\n <p className=\"tds-field-description\" id={descriptionId}>\n <Icon\n aria-hidden\n className=\"tds-field-description-invalid-icon\"\n symbol=\"general#exclamation-triangle\"\n />\n {description}\n </p>\n )}\n </div>\n )\n}\n"],"names":[],"mappings":";;;;AA2BA;;;;;;;;;;;;;;AAcG;AACG,SAAU,KAAK,CAAC,EACpB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,KAAK,GACM,EAAA;AACX,IAAA,MAAM,aAAa,GAAG,CAAA,EAAG,EAAE,cAAc;AAEzC,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,EAAA,kBAAA,EAC3B,MAAM,IAAI,SAAS,EAAA;QAEpC,KAAK,IAAI,CAAC,cAAc,KACvB,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EACE,SAAS,EAAE,UAAU,CACnB,iBAAiB,EACjB,SAAS,IAAI,yBAAyB,CACvC,EACD,OAAO,EAAE,EAAE,EAAA,EAEV,KAAK,CACA,CACT;QACA,QAAQ;QACR,WAAW,KACV,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,uBAAuB,EAAC,EAAE,EAAE,aAAa,EAAA;YACpD,KAAA,CAAA,aAAA,CAAC,IAAI,yBAEH,SAAS,EAAC,oCAAoC,EAC9C,MAAM,EAAC,8BAA8B,EAAA,CACrC;AACD,YAAA,WAAW,CACV,CACL,CACG;AAEV;;;;"}
@@ -13,8 +13,7 @@ export type LinkProps = Simplify<Omit<Extract<BaseLinkElementProps, {
13
13
  }>;
14
14
  /**
15
15
  * A link component that renders as an HTML `<a>` element with button-like
16
- * styling. Use for navigation; for actions that don't change the URL, use
17
- * `Button` instead.
16
+ * styling. Use for navigation.
18
17
  *
19
18
  * @component
20
19
  * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/links-link--docs | Storybook Documentation}
@@ -1 +1 @@
1
- {"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../../src/components/link/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,CAAA;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,KAAqB,MAAM,OAAO,CAAA;AAEzC,OAAO,EAAY,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAE3D,MAAM,MAAM,SAAS,GACjB,QAAQ,CACN,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE;IAAE,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,GAAG;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CACF,GACD,QAAQ,CACN,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,GAAG;IAChE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CACF,CAAA;AAEL;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,qFAKhB,CAAA"}
1
+ {"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../../src/components/link/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,CAAA;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,KAAqB,MAAM,OAAO,CAAA;AAEzC,OAAO,EAAY,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAE3D,MAAM,MAAM,SAAS,GACjB,QAAQ,CACN,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE;IAAE,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,GAAG;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CACF,GACD,QAAQ,CACN,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,GAAG;IAChE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CACF,CAAA;AAEL;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,qFAKhB,CAAA"}
@@ -3,8 +3,7 @@ import { BaseLink } from './BaseLink.js';
3
3
 
4
4
  /**
5
5
  * A link component that renders as an HTML `<a>` element with button-like
6
- * styling. Use for navigation; for actions that don't change the URL, use
7
- * `Button` instead.
6
+ * styling. Use for navigation.
8
7
  *
9
8
  * @component
10
9
  * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/links-link--docs | Storybook Documentation}
@@ -1 +1 @@
1
- {"version":3,"file":"Link.js","sources":["../../../src/components/link/Link.tsx"],"sourcesContent":["import \"../button/btn.css\"\n\nimport { Simplify } from \"@utilities/typeUtils\"\nimport React, { forwardRef } from \"react\"\n\nimport { BaseLink, BaseLinkElementProps } from \"./BaseLink\"\n\nexport type LinkProps =\n | Simplify<\n Omit<Extract<BaseLinkElementProps, { asChild?: false }>, \"label\"> & {\n label?: string\n }\n >\n | Simplify<\n Omit<Extract<BaseLinkElementProps, { asChild: true }>, \"label\"> & {\n label?: string\n }\n >\n\n/**\n * A link component that renders as an HTML `<a>` element with button-like\n * styling. Use for navigation; for actions that don't change the URL, use\n * `Button` instead.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/links-link--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n (props: LinkProps, ref) => {\n // eslint-disable-next-line tapestry/valid-href\n return <BaseLink ref={ref} {...props} />\n }\n)\n\nLink.displayName = \"Link\"\n"],"names":["React"],"mappings":";;;AAmBA;;;;;;;;AAQG;AACI,MAAM,IAAI,GAAG,UAAU,CAC5B,CAAC,KAAgB,EAAE,GAAG,KAAI;;IAExB,OAAOA,cAAA,CAAA,aAAA,CAAC,QAAQ,EAAA,EAAC,GAAG,EAAE,GAAG,EAAA,GAAM,KAAK,EAAA,CAAI;AAC1C,CAAC;AAGH,IAAI,CAAC,WAAW,GAAG,MAAM;;;;"}
1
+ {"version":3,"file":"Link.js","sources":["../../../src/components/link/Link.tsx"],"sourcesContent":["import \"../button/btn.css\"\n\nimport { Simplify } from \"@utilities/typeUtils\"\nimport React, { forwardRef } from \"react\"\n\nimport { BaseLink, BaseLinkElementProps } from \"./BaseLink\"\n\nexport type LinkProps =\n | Simplify<\n Omit<Extract<BaseLinkElementProps, { asChild?: false }>, \"label\"> & {\n label?: string\n }\n >\n | Simplify<\n Omit<Extract<BaseLinkElementProps, { asChild: true }>, \"label\"> & {\n label?: string\n }\n >\n\n/**\n * A link component that renders as an HTML `<a>` element with button-like\n * styling. Use for navigation.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/links-link--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n (props: LinkProps, ref) => {\n // eslint-disable-next-line tapestry/valid-href\n return <BaseLink ref={ref} {...props} />\n }\n)\n\nLink.displayName = \"Link\"\n"],"names":["React"],"mappings":";;;AAmBA;;;;;;;AAOG;AACI,MAAM,IAAI,GAAG,UAAU,CAC5B,CAAC,KAAgB,EAAE,GAAG,KAAI;;IAExB,OAAOA,cAAA,CAAA,aAAA,CAAC,QAAQ,EAAA,EAAC,GAAG,EAAE,GAAG,EAAA,GAAM,KAAK,EAAA,CAAI;AAC1C,CAAC;AAGH,IAAI,CAAC,WAAW,GAAG,MAAM;;;;"}
@@ -16,13 +16,8 @@ export interface PopoverProps {
16
16
  }
17
17
  export type PopoverElementProps = PopoverProps;
18
18
  /**
19
- * A generic popover surface anchored to a trigger button. Unlike `Dropdown`
20
- * (a semantic `role="menu"` action list), `Popover` renders arbitrary content
21
- * — a search field, a form, a list, plain text.
22
- *
23
- * **Rule of thumb:** a flat list of actions or links → `Dropdown`. Anything
24
- * else anchored to a button → `Popover`. Owns the screen until resolved →
25
- * `Modal`.
19
+ * A generic popover surface anchored to a trigger button. Renders arbitrary
20
+ * content — a search field, a form, a list, plain text.
26
21
  *
27
22
  * @component
28
23
  * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/overlays-popover--docs | Storybook Documentation}
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/components/popover/Popover.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAGpB,OAAO,KAAK,EAAE,EAGZ,KAAK,YAAY,EACjB,KAAK,SAAS,EAOf,MAAM,OAAO,CAAA;AAGd,OAAO,KAAK,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AASrF,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,QAAQ,EAAE,SAAS,CAAA;IACnB,kFAAkF;IAClF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,wFAAwF;IACxF,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAA;AAE9C;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,IAAI,GACL,EAAE,mBAAmB,qBAUrB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,QAAQ,EAAE,YAAY,CAAA;CACvB;AAED,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,CAAA;AAI5D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,0BAA0B,qBAEtE;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,IAAI,CAE5C;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yBAAyB;IACzB,QAAQ,EAAE,SAAS,CAAA;IACnB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;CAC1C;AAED,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,CAAA;AAE5D;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,EAC7B,YAAY,EAAE,SAAS,EACvB,QAAQ,EACR,SAAS,EACT,WAAW,EACX,KAAY,EACZ,MAAM,EACN,SAA0B,GAC3B,EAAE,0BAA0B,qBAgE5B"}
1
+ {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/components/popover/Popover.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAGpB,OAAO,KAAK,EAAE,EAGZ,KAAK,YAAY,EACjB,KAAK,SAAS,EAOf,MAAM,OAAO,CAAA;AAGd,OAAO,KAAK,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AASrF,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,QAAQ,EAAE,SAAS,CAAA;IACnB,kFAAkF;IAClF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,wFAAwF;IACxF,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAA;AAE9C;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,IAAI,GACL,EAAE,mBAAmB,qBAUrB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,QAAQ,EAAE,YAAY,CAAA;CACvB;AAED,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,CAAA;AAI5D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,0BAA0B,qBAEtE;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,IAAI,CAE5C;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yBAAyB;IACzB,QAAQ,EAAE,SAAS,CAAA;IACnB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAA;CAC1C;AAED,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,CAAA;AAE5D;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,EAC7B,YAAY,EAAE,SAAS,EACvB,QAAQ,EACR,SAAS,EACT,WAAW,EACX,KAAY,EACZ,MAAM,EACN,SAA0B,GAC3B,EAAE,0BAA0B,qBAgE5B"}
@@ -5,13 +5,8 @@ import { OverlayTriggerStateContext } from 'react-aria-components/Dialog';
5
5
  import { DialogTrigger, PopoverContext, Popover as Popover$1, Dialog, Pressable } from 'react-aria-components/Popover';
6
6
 
7
7
  /**
8
- * A generic popover surface anchored to a trigger button. Unlike `Dropdown`
9
- * (a semantic `role="menu"` action list), `Popover` renders arbitrary content
10
- * — a search field, a form, a list, plain text.
11
- *
12
- * **Rule of thumb:** a flat list of actions or links → `Dropdown`. Anything
13
- * else anchored to a button → `Popover`. Owns the screen until resolved →
14
- * `Modal`.
8
+ * A generic popover surface anchored to a trigger button. Renders arbitrary
9
+ * content — a search field, a form, a list, plain text.
15
10
  *
16
11
  * @component
17
12
  * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/overlays-popover--docs | Storybook Documentation}
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.js","sources":["../../../src/components/popover/Popover.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n createContext,\n type ReactElement,\n type ReactNode,\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\"\nimport { FocusScope, useInteractOutside, usePreventScroll } from \"react-aria\"\nimport { OverlayTriggerStateContext } from \"react-aria-components/Dialog\"\nimport type { PopoverProps as AriaPopoverProps } from \"react-aria-components/Popover\"\nimport {\n Dialog,\n DialogTrigger,\n Popover as AriaPopover,\n PopoverContext as AriaPopoverContext,\n Pressable,\n} from \"react-aria-components/Popover\"\n\nexport interface PopoverProps {\n /** A `<PopoverTrigger>` followed by a `<PopoverContent>`. */\n children: ReactNode\n /** Initial open state for the uncontrolled case. Useful for stories and tests. */\n defaultOpen?: boolean\n /**\n * Fires whenever the surface opens or closes — trigger press, Escape,\n * outside press, or `close()`. Required when `open` is set.\n */\n onOpenChange?: (open: boolean) => void\n /** Controlled open state. Renamed from React Aria's `isOpen`. Omit for uncontrolled. */\n open?: boolean\n}\n\nexport type PopoverElementProps = PopoverProps\n\n/**\n * A generic popover surface anchored to a trigger button. Unlike `Dropdown`\n * (a semantic `role=\"menu\"` action list), `Popover` renders arbitrary content\n * — a search field, a form, a list, plain text.\n *\n * **Rule of thumb:** a flat list of actions or links → `Dropdown`. Anything\n * else anchored to a button → `Popover`. Owns the screen until resolved →\n * `Modal`.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/overlays-popover--docs | Storybook Documentation}\n */\nexport function Popover({\n children,\n defaultOpen,\n onOpenChange,\n open,\n}: PopoverElementProps) {\n return (\n <DialogTrigger\n defaultOpen={defaultOpen}\n isOpen={open}\n onOpenChange={onOpenChange}\n >\n {children}\n </DialogTrigger>\n )\n}\n\nexport interface PopoverTriggerProps {\n /**\n * Exactly one Tapestry button element — `Button`, `IconButton`,\n * `DropdownButton`, `DropdownIconButton`, `ActionsDropdownIconButton`, or\n * `PageHeaderActionsDropdownButton`. Receives `aria-expanded`,\n * `aria-controls`, `id`, and press wiring via `Pressable` — the same RAC\n * mechanism `Dropdown`'s trigger already uses. Must render a real `<button>`.\n */\n children: ReactElement\n}\n\nexport type PopoverTriggerElementProps = PopoverTriggerProps\n\ntype PressableChild = ComponentProps<typeof Pressable>[\"children\"]\n\n/**\n * Wraps a single Tapestry button and bridges it to React Aria's\n * `DialogTrigger` via `<Pressable>`.\n *\n * @component\n */\nexport function PopoverTrigger({ children }: PopoverTriggerElementProps) {\n return <Pressable>{children as PressableChild}</Pressable>\n}\n\nconst PopoverCloseContext = createContext<() => void>(() => {})\n\n/**\n * Returns the enclosing `<PopoverContent>`'s `close` function. Call it from\n * any descendant to close the surface — e.g. a plain `<Button onClick={close}>`.\n */\nexport function usePopoverClose(): () => void {\n return useContext(PopoverCloseContext)\n}\n\nexport interface PopoverContentProps {\n /**\n * Accessible name for the surface. Defaults to the trigger's accessible\n * name (React Aria points `aria-labelledby` at the trigger's id). Set this\n * when the surface needs a different name than the trigger.\n */\n \"aria-label\"?: string\n /** Arbitrary content. */\n children: ReactNode\n /** Appended to `tds-popover` on the positioned surface. */\n className?: string\n /** Shift along the trigger's edge, in pixels. Defaults to `0`. */\n crossOffset?: number\n /**\n * Defaults to `true`. When `true`, the surface hides outside content from\n * assistive tech and sits over a click-blocking underlay — the right\n * default for most popovers. Set to `false` for lighter-weight dismissal\n * behavior (maps to React Aria's `isNonModal`, whose own doc comment scopes\n * it to \"components such as combobox\" — this is why it isn't the default).\n * `<Dialog>` always renders regardless of this prop; `modal` only toggles\n * the underlay and outside-content handling, not whether a dialog role\n * exists.\n *\n * `modal={false}` still blocks page scroll while open — React Aria's own\n * scroll-close behavior for non-modal popovers can't be disabled, so\n * scrolling is locked instead, the same way `Dropdown`'s menu does.\n */\n modal?: boolean\n /** Distance from the trigger, in pixels. Defaults to `8`. */\n offset?: number\n /**\n * Position relative to the trigger, in React Aria's space-separated form.\n * Defaults to `'bottom start'`. Flips automatically when there isn't room.\n */\n placement?: AriaPopoverProps[\"placement\"]\n}\n\nexport type PopoverContentElementProps = PopoverContentProps\n\n/**\n * The popover surface for a `<Popover>`. Wraps React Aria's `<Popover>` and\n * `<Dialog>` and contains arbitrary content.\n *\n * On close, focus returns to the popover's own trigger — even when it was\n * opened programmatically via `open` or `defaultOpen` rather than by pressing\n * the trigger.\n *\n * @component\n */\nexport function PopoverContent({\n \"aria-label\": ariaLabel,\n children,\n className,\n crossOffset,\n modal = true,\n offset,\n placement = \"bottom start\",\n}: PopoverContentElementProps) {\n const popoverRef = useRef<HTMLElement>(null)\n const state = useContext(OverlayTriggerStateContext)\n const close = useCallback(() => state?.close(), [state])\n\n const popoverContext = useContext(AriaPopoverContext)\n const triggerRef =\n popoverContext && \"triggerRef\" in popoverContext\n ? popoverContext.triggerRef\n : undefined\n\n const isOpen = Boolean(state?.isOpen)\n // Portaled children (e.g. a ComboBox listbox) sit outside `popoverRef` in\n // the DOM, but their events still bubble through the React tree, so count\n // presses that reach the content as inside.\n const pressedInsideRef = useRef(false)\n const markPressedInside = () => {\n pressedInsideRef.current = true\n }\n useInteractOutside({\n isDisabled: modal || !isOpen,\n onInteractOutside: (event) => {\n if (pressedInsideRef.current) return\n if (triggerRef?.current?.contains(event.target as Node)) return\n close()\n },\n onInteractOutsideStart: () => {\n pressedInsideRef.current = false\n },\n ref: popoverRef,\n })\n usePreventScroll({ isDisabled: modal || !isOpen })\n\n const isOpenRef = useRef(isOpen)\n useLayoutEffect(() => {\n isOpenRef.current = isOpen\n }, [isOpen])\n\n return (\n <AriaPopover\n className={classNames(\"tds-popover\", className)}\n crossOffset={crossOffset}\n isNonModal={!modal}\n offset={offset}\n placement={placement}\n ref={popoverRef}\n shouldCloseOnInteractOutside={modal ? undefined : () => false}\n >\n <FocusScope contain={!modal && isOpen}>\n <Dialog\n aria-label={ariaLabel}\n className=\"tds-popover-content\"\n // Mouse: React Aria's test-only fallback (jsdom lacks PointerEvent)\n onMouseDownCapture={markPressedInside}\n onPointerDownCapture={markPressedInside}\n >\n <FocusTriggerOnClose isOpenRef={isOpenRef} triggerRef={triggerRef} />\n <PopoverCloseContext.Provider value={close}>\n {children}\n </PopoverCloseContext.Provider>\n </Dialog>\n </FocusScope>\n </AriaPopover>\n )\n}\n\nfunction FocusTriggerOnClose({\n isOpenRef,\n triggerRef,\n}: {\n isOpenRef: RefObject<boolean>\n triggerRef?: RefObject<Element | null>\n}) {\n useEffect(\n () => () => {\n const trigger = triggerRef?.current\n if (\n !isOpenRef.current &&\n document.activeElement === document.body &&\n trigger instanceof HTMLElement &&\n trigger.isConnected\n ) {\n trigger.focus({ preventScroll: true })\n }\n },\n [isOpenRef, triggerRef]\n )\n return null\n}\n"],"names":["React","AriaPopoverContext","AriaPopover"],"mappings":"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"}
1
+ {"version":3,"file":"Popover.js","sources":["../../../src/components/popover/Popover.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n createContext,\n type ReactElement,\n type ReactNode,\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\"\nimport { FocusScope, useInteractOutside, usePreventScroll } from \"react-aria\"\nimport { OverlayTriggerStateContext } from \"react-aria-components/Dialog\"\nimport type { PopoverProps as AriaPopoverProps } from \"react-aria-components/Popover\"\nimport {\n Dialog,\n DialogTrigger,\n Popover as AriaPopover,\n PopoverContext as AriaPopoverContext,\n Pressable,\n} from \"react-aria-components/Popover\"\n\nexport interface PopoverProps {\n /** A `<PopoverTrigger>` followed by a `<PopoverContent>`. */\n children: ReactNode\n /** Initial open state for the uncontrolled case. Useful for stories and tests. */\n defaultOpen?: boolean\n /**\n * Fires whenever the surface opens or closes — trigger press, Escape,\n * outside press, or `close()`. Required when `open` is set.\n */\n onOpenChange?: (open: boolean) => void\n /** Controlled open state. Renamed from React Aria's `isOpen`. Omit for uncontrolled. */\n open?: boolean\n}\n\nexport type PopoverElementProps = PopoverProps\n\n/**\n * A generic popover surface anchored to a trigger button. Renders arbitrary\n * content — a search field, a form, a list, plain text.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/overlays-popover--docs | Storybook Documentation}\n */\nexport function Popover({\n children,\n defaultOpen,\n onOpenChange,\n open,\n}: PopoverElementProps) {\n return (\n <DialogTrigger\n defaultOpen={defaultOpen}\n isOpen={open}\n onOpenChange={onOpenChange}\n >\n {children}\n </DialogTrigger>\n )\n}\n\nexport interface PopoverTriggerProps {\n /**\n * Exactly one Tapestry button element — `Button`, `IconButton`,\n * `DropdownButton`, `DropdownIconButton`, `ActionsDropdownIconButton`, or\n * `PageHeaderActionsDropdownButton`. Receives `aria-expanded`,\n * `aria-controls`, `id`, and press wiring via `Pressable` — the same RAC\n * mechanism `Dropdown`'s trigger already uses. Must render a real `<button>`.\n */\n children: ReactElement\n}\n\nexport type PopoverTriggerElementProps = PopoverTriggerProps\n\ntype PressableChild = ComponentProps<typeof Pressable>[\"children\"]\n\n/**\n * Wraps a single Tapestry button and bridges it to React Aria's\n * `DialogTrigger` via `<Pressable>`.\n *\n * @component\n */\nexport function PopoverTrigger({ children }: PopoverTriggerElementProps) {\n return <Pressable>{children as PressableChild}</Pressable>\n}\n\nconst PopoverCloseContext = createContext<() => void>(() => {})\n\n/**\n * Returns the enclosing `<PopoverContent>`'s `close` function. Call it from\n * any descendant to close the surface — e.g. a plain `<Button onClick={close}>`.\n */\nexport function usePopoverClose(): () => void {\n return useContext(PopoverCloseContext)\n}\n\nexport interface PopoverContentProps {\n /**\n * Accessible name for the surface. Defaults to the trigger's accessible\n * name (React Aria points `aria-labelledby` at the trigger's id). Set this\n * when the surface needs a different name than the trigger.\n */\n \"aria-label\"?: string\n /** Arbitrary content. */\n children: ReactNode\n /** Appended to `tds-popover` on the positioned surface. */\n className?: string\n /** Shift along the trigger's edge, in pixels. Defaults to `0`. */\n crossOffset?: number\n /**\n * Defaults to `true`. When `true`, the surface hides outside content from\n * assistive tech and sits over a click-blocking underlay — the right\n * default for most popovers. Set to `false` for lighter-weight dismissal\n * behavior (maps to React Aria's `isNonModal`, whose own doc comment scopes\n * it to \"components such as combobox\" — this is why it isn't the default).\n * `<Dialog>` always renders regardless of this prop; `modal` only toggles\n * the underlay and outside-content handling, not whether a dialog role\n * exists.\n *\n * `modal={false}` still blocks page scroll while open — React Aria's own\n * scroll-close behavior for non-modal popovers can't be disabled, so\n * scrolling is locked instead, the same way `Dropdown`'s menu does.\n */\n modal?: boolean\n /** Distance from the trigger, in pixels. Defaults to `8`. */\n offset?: number\n /**\n * Position relative to the trigger, in React Aria's space-separated form.\n * Defaults to `'bottom start'`. Flips automatically when there isn't room.\n */\n placement?: AriaPopoverProps[\"placement\"]\n}\n\nexport type PopoverContentElementProps = PopoverContentProps\n\n/**\n * The popover surface for a `<Popover>`. Wraps React Aria's `<Popover>` and\n * `<Dialog>` and contains arbitrary content.\n *\n * On close, focus returns to the popover's own trigger — even when it was\n * opened programmatically via `open` or `defaultOpen` rather than by pressing\n * the trigger.\n *\n * @component\n */\nexport function PopoverContent({\n \"aria-label\": ariaLabel,\n children,\n className,\n crossOffset,\n modal = true,\n offset,\n placement = \"bottom start\",\n}: PopoverContentElementProps) {\n const popoverRef = useRef<HTMLElement>(null)\n const state = useContext(OverlayTriggerStateContext)\n const close = useCallback(() => state?.close(), [state])\n\n const popoverContext = useContext(AriaPopoverContext)\n const triggerRef =\n popoverContext && \"triggerRef\" in popoverContext\n ? popoverContext.triggerRef\n : undefined\n\n const isOpen = Boolean(state?.isOpen)\n // Portaled children (e.g. a ComboBox listbox) sit outside `popoverRef` in\n // the DOM, but their events still bubble through the React tree, so count\n // presses that reach the content as inside.\n const pressedInsideRef = useRef(false)\n const markPressedInside = () => {\n pressedInsideRef.current = true\n }\n useInteractOutside({\n isDisabled: modal || !isOpen,\n onInteractOutside: (event) => {\n if (pressedInsideRef.current) return\n if (triggerRef?.current?.contains(event.target as Node)) return\n close()\n },\n onInteractOutsideStart: () => {\n pressedInsideRef.current = false\n },\n ref: popoverRef,\n })\n usePreventScroll({ isDisabled: modal || !isOpen })\n\n const isOpenRef = useRef(isOpen)\n useLayoutEffect(() => {\n isOpenRef.current = isOpen\n }, [isOpen])\n\n return (\n <AriaPopover\n className={classNames(\"tds-popover\", className)}\n crossOffset={crossOffset}\n isNonModal={!modal}\n offset={offset}\n placement={placement}\n ref={popoverRef}\n shouldCloseOnInteractOutside={modal ? undefined : () => false}\n >\n <FocusScope contain={!modal && isOpen}>\n <Dialog\n aria-label={ariaLabel}\n className=\"tds-popover-content\"\n // Mouse: React Aria's test-only fallback (jsdom lacks PointerEvent)\n onMouseDownCapture={markPressedInside}\n onPointerDownCapture={markPressedInside}\n >\n <FocusTriggerOnClose isOpenRef={isOpenRef} triggerRef={triggerRef} />\n <PopoverCloseContext.Provider value={close}>\n {children}\n </PopoverCloseContext.Provider>\n </Dialog>\n </FocusScope>\n </AriaPopover>\n )\n}\n\nfunction FocusTriggerOnClose({\n isOpenRef,\n triggerRef,\n}: {\n isOpenRef: RefObject<boolean>\n triggerRef?: RefObject<Element | null>\n}) {\n useEffect(\n () => () => {\n const trigger = triggerRef?.current\n if (\n !isOpenRef.current &&\n document.activeElement === document.body &&\n trigger instanceof HTMLElement &&\n trigger.isConnected\n ) {\n trigger.focus({ preventScroll: true })\n }\n },\n [isOpenRef, triggerRef]\n )\n return null\n}\n"],"names":["React","AriaPopoverContext","AriaPopover"],"mappings":"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"}