@planningcenter/tapestry 4.1.0-rc.2 → 4.1.0-rc.3
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/componentRegistration.js +14 -0
- package/dist/componentRegistration.js.map +1 -1
- package/dist/components/button/BaseButton.js +4 -4
- package/dist/components/button/BaseButton.js.map +1 -1
- package/dist/components/button/DropdownButton.js +3 -3
- package/dist/components/button/DropdownButton.js.map +1 -1
- package/dist/components/button/DropdownIconButton.js +2 -2
- package/dist/components/button/DropdownIconButton.js.map +1 -1
- package/dist/components/button/IconButton.js +2 -2
- package/dist/components/button/IconButton.js.map +1 -1
- package/dist/components/button/PageHeaderActionsDropdownButton.js +3 -3
- package/dist/components/button/PageHeaderActionsDropdownButton.js.map +1 -1
- package/dist/components/dropdown/Dropdown.js +11 -11
- package/dist/components/dropdown/Dropdown.js.map +1 -1
- package/dist/components/internal/tooltip/Tooltip.js +8 -62
- package/dist/components/internal/tooltip/Tooltip.js.map +1 -1
- package/dist/reactRender.css +479 -479
- package/dist/reactRender.css.map +1 -1
- package/dist/reactRenderLegacy.css +479 -479
- package/dist/reactRenderLegacy.css.map +1 -1
- package/dist/utilities/buttonLinkShared.js +2 -2
- package/dist/utilities/buttonLinkShared.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { register as r } from './packages/tapestry-render/dist/registry.js';
|
|
2
|
+
import { DropdownButton } from './components/button/DropdownButton.js';
|
|
3
|
+
import { DropdownIconButton } from './components/button/DropdownIconButton.js';
|
|
4
|
+
import { PageHeaderActionsDropdownButton } from './components/button/PageHeaderActionsDropdownButton.js';
|
|
2
5
|
import { ComboBox, ComboBoxItem, ComboBoxSection } from './components/combo-box/ComboBox.js';
|
|
3
6
|
import { DatePicker } from './components/date-picker/DatePicker.js';
|
|
7
|
+
import { Dropdown, DropdownAction, DropdownLink, DropdownMenu, DropdownSection, DropdownSeparator, DropdownTrigger } from './components/dropdown/Dropdown.js';
|
|
4
8
|
import { NumberStepper } from './components/number-stepper/NumberStepper.js';
|
|
5
9
|
import { PageHeader } from './components/page-header/PageHeader.js';
|
|
6
10
|
import { Select } from './components/select/Select.js';
|
|
@@ -13,8 +17,18 @@ r("ComboBox", ComboBox);
|
|
|
13
17
|
r("ComboBoxItem", ComboBoxItem);
|
|
14
18
|
r("ComboBoxSection", ComboBoxSection);
|
|
15
19
|
r("DatePicker", DatePicker);
|
|
20
|
+
r("Dropdown", Dropdown);
|
|
21
|
+
r("DropdownAction", DropdownAction);
|
|
22
|
+
r("DropdownButton", DropdownButton);
|
|
23
|
+
r("DropdownIconButton", DropdownIconButton);
|
|
24
|
+
r("DropdownLink", DropdownLink);
|
|
25
|
+
r("DropdownMenu", DropdownMenu);
|
|
26
|
+
r("DropdownSection", DropdownSection);
|
|
27
|
+
r("DropdownSeparator", DropdownSeparator);
|
|
28
|
+
r("DropdownTrigger", DropdownTrigger);
|
|
16
29
|
r("NumberStepper", NumberStepper);
|
|
17
30
|
r("PageHeader", PageHeader);
|
|
31
|
+
r("PageHeaderActionsDropdownButton", PageHeaderActionsDropdownButton);
|
|
18
32
|
r("Select", Select);
|
|
19
33
|
r("Sidenav", Sidenav);
|
|
20
34
|
r("SidenavItem", SidenavItem);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"componentRegistration.js","sources":["../src/componentRegistration.ts"],"sourcesContent":["import { register } from \"@planningcenter/tapestry-render/registry\"\n\nimport {\n ComboBox,\n ComboBoxItem,\n ComboBoxSection,\n} from \"./components/combo-box/ComboBox\"\nimport { DatePicker } from \"./components/date-picker/DatePicker\"\nimport { NumberStepper } from \"./components/number-stepper/NumberStepper\"\nimport { PageHeader } from \"./components/page-header/PageHeader\"\nimport { Select } from \"./components/select/Select\"\nimport { Sidenav } from \"./components/sidenav/Sidenav\"\nimport { SidenavItem } from \"./components/sidenav/SidenavItem\"\nimport { SidenavSection } from \"./components/sidenav/SidenavSection\"\nimport { TimeField } from \"./components/time-field/TimeField\"\n\nregister(\"ComboBox\", ComboBox)\nregister(\"ComboBoxItem\", ComboBoxItem)\nregister(\"ComboBoxSection\", ComboBoxSection)\nregister(\"DatePicker\", DatePicker)\nregister(\"NumberStepper\", NumberStepper)\nregister(\"PageHeader\", PageHeader)\nregister(\"Select\", Select)\nregister(\"Sidenav\", Sidenav)\nregister(\"SidenavItem\", SidenavItem)\nregister(\"SidenavSection\", SidenavSection)\nregister(\"TimeField\", TimeField)\n"],"names":["register"],"mappings":"
|
|
1
|
+
{"version":3,"file":"componentRegistration.js","sources":["../src/componentRegistration.ts"],"sourcesContent":["import { register } from \"@planningcenter/tapestry-render/registry\"\n\nimport { DropdownButton } from \"./components/button/DropdownButton\"\nimport { DropdownIconButton } from \"./components/button/DropdownIconButton\"\nimport { PageHeaderActionsDropdownButton } from \"./components/button/PageHeaderActionsDropdownButton\"\nimport {\n ComboBox,\n ComboBoxItem,\n ComboBoxSection,\n} from \"./components/combo-box/ComboBox\"\nimport { DatePicker } from \"./components/date-picker/DatePicker\"\nimport {\n Dropdown,\n DropdownAction,\n DropdownLink,\n DropdownMenu,\n DropdownSection,\n DropdownSeparator,\n DropdownTrigger,\n} from \"./components/dropdown/Dropdown\"\nimport { NumberStepper } from \"./components/number-stepper/NumberStepper\"\nimport { PageHeader } from \"./components/page-header/PageHeader\"\nimport { Select } from \"./components/select/Select\"\nimport { Sidenav } from \"./components/sidenav/Sidenav\"\nimport { SidenavItem } from \"./components/sidenav/SidenavItem\"\nimport { SidenavSection } from \"./components/sidenav/SidenavSection\"\nimport { TimeField } from \"./components/time-field/TimeField\"\n\nregister(\"ComboBox\", ComboBox)\nregister(\"ComboBoxItem\", ComboBoxItem)\nregister(\"ComboBoxSection\", ComboBoxSection)\nregister(\"DatePicker\", DatePicker)\nregister(\"Dropdown\", Dropdown)\nregister(\"DropdownAction\", DropdownAction)\nregister(\"DropdownButton\", DropdownButton)\nregister(\"DropdownIconButton\", DropdownIconButton)\nregister(\"DropdownLink\", DropdownLink)\nregister(\"DropdownMenu\", DropdownMenu)\nregister(\"DropdownSection\", DropdownSection)\nregister(\"DropdownSeparator\", DropdownSeparator)\nregister(\"DropdownTrigger\", DropdownTrigger)\nregister(\"NumberStepper\", NumberStepper)\nregister(\"PageHeader\", PageHeader)\nregister(\"PageHeaderActionsDropdownButton\", PageHeaderActionsDropdownButton)\nregister(\"Select\", Select)\nregister(\"Sidenav\", Sidenav)\nregister(\"SidenavItem\", SidenavItem)\nregister(\"SidenavSection\", SidenavSection)\nregister(\"TimeField\", TimeField)\n"],"names":["register"],"mappings":";;;;;;;;;;;;;;;AA4BAA,CAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC;AAC9BA,CAAQ,CAAC,cAAc,EAAE,YAAY,CAAC;AACtCA,CAAQ,CAAC,iBAAiB,EAAE,eAAe,CAAC;AAC5CA,CAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;AAClCA,CAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC;AAC9BA,CAAQ,CAAC,gBAAgB,EAAE,cAAc,CAAC;AAC1CA,CAAQ,CAAC,gBAAgB,EAAE,cAAc,CAAC;AAC1CA,CAAQ,CAAC,oBAAoB,EAAE,kBAAkB,CAAC;AAClDA,CAAQ,CAAC,cAAc,EAAE,YAAY,CAAC;AACtCA,CAAQ,CAAC,cAAc,EAAE,YAAY,CAAC;AACtCA,CAAQ,CAAC,iBAAiB,EAAE,eAAe,CAAC;AAC5CA,CAAQ,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;AAChDA,CAAQ,CAAC,iBAAiB,EAAE,eAAe,CAAC;AAC5CA,CAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;AACxCA,CAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;AAClCA,CAAQ,CAAC,iCAAiC,EAAE,+BAA+B,CAAC;AAC5EA,CAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;AAC1BA,CAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;AAC5BA,CAAQ,CAAC,aAAa,EAAE,WAAW,CAAC;AACpCA,CAAQ,CAAC,gBAAgB,EAAE,cAAc,CAAC;AAC1CA,CAAQ,CAAC,WAAW,EAAE,SAAS,CAAC"}
|
|
@@ -3,7 +3,7 @@ import '../internal/tooltip/Tooltip.js';
|
|
|
3
3
|
import { TooltipTriggerContext } from '../internal/tooltip/TooltipTriggerContext.js';
|
|
4
4
|
import { COMPONENT_SIZE_CLASS_MAP, COMPONENT_KIND_CLASS_MAP, wrapStringWithSpan } from '../../utilities/buttonLinkShared.js';
|
|
5
5
|
import classNames from 'classnames';
|
|
6
|
-
import
|
|
6
|
+
import React, { forwardRef, useContext } from 'react';
|
|
7
7
|
import { mergeProps } from 'react-aria/mergeProps';
|
|
8
8
|
import { mergeRefs } from 'react-aria/mergeRefs';
|
|
9
9
|
|
|
@@ -19,10 +19,10 @@ const BaseButton = forwardRef(({ "aria-describedby": ariaDescribedBy, "aria-labe
|
|
|
19
19
|
const describedBy = [ariaDescribedBy, tooltipId].filter(Boolean).join(" ") || undefined;
|
|
20
20
|
const combinedClassName = classNames(kind && "tds-btn", size && size !== "md" && COMPONENT_SIZE_CLASS_MAP[size], kind && COMPONENT_KIND_CLASS_MAP[kind], fullWidth && "tds-btn--full-width", loading && "tds-btn--loading", className, { "tds-btn--prefix": prefix, "tds-btn--suffix": suffix });
|
|
21
21
|
const isDisabled = disabled || loading;
|
|
22
|
-
return (
|
|
23
|
-
loading &&
|
|
22
|
+
return (React.createElement("button", { type: "button", className: combinedClassName, ref: mergedRef, ...mergedProps, "aria-busy": loading || undefined, "aria-describedby": describedBy, "aria-disabled": isDisabled || undefined, disabled: isDisabled, "aria-label": loading ? loadingAriaLabel : ariaLabel },
|
|
23
|
+
loading && React.createElement(LoadingSpinner, null),
|
|
24
24
|
wrapStringWithSpan(prefix),
|
|
25
|
-
loading ?
|
|
25
|
+
loading ? React.createElement("span", null, label) : label,
|
|
26
26
|
wrapStringWithSpan(suffix)));
|
|
27
27
|
});
|
|
28
28
|
BaseButton.displayName = "BaseButton";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseButton.js","sources":["../../../src/components/button/BaseButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport { LoadingSpinner } from \"@components/internal\"\nimport { TooltipTriggerContext } from \"@components/internal/tooltip/TooltipTriggerContext\"\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n wrapStringWithSpan,\n} from \"@utilities/buttonLinkShared\"\nimport classNames from \"classnames\"\nimport React, { ButtonHTMLAttributes, forwardRef, useContext } from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { mergeRefs } from \"react-aria/mergeRefs\"\n\nexport interface BaseButtonProps extends Omit<BaseComponentProps, \"kind\"> {\n /** The visual style of the button. */\n kind?: ComponentKind\n /** The text content of the button. */\n label: React.ReactNode\n /** Whether the button is in a loading state. When true, the button is disabled and shows a loading spinner. */\n loading?: boolean\n /** Accessible label to use when the button is in loading state. */\n loadingAriaLabel?: string\n}\n\nexport type BaseButtonElementProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n keyof BaseButtonProps | \"children\"\n> &\n BaseButtonProps\n\nexport const BaseButton = forwardRef<HTMLButtonElement, BaseButtonElementProps>(\n (\n {\n \"aria-describedby\": ariaDescribedBy,\n \"aria-label\": ariaLabel,\n className,\n disabled = false,\n fullWidth,\n kind = \"secondary\",\n label,\n loading = false,\n loadingAriaLabel = \"Loading...\",\n prefix,\n size,\n suffix,\n ...restProps\n }: BaseButtonElementProps,\n ref\n ) => {\n const tooltip = useContext(TooltipTriggerContext)\n const { \"aria-describedby\": tooltipId, ...tooltipTriggerProps } =\n tooltip?.triggerProps ?? {}\n\n const mergedProps = tooltip\n ? mergeProps(restProps, tooltipTriggerProps)\n : restProps\n const mergedRef = tooltip\n ? mergeRefs<HTMLButtonElement>(ref, tooltip.ref)\n : ref\n const describedBy =\n [ariaDescribedBy, tooltipId].filter(Boolean).join(\" \") || undefined\n\n const combinedClassName = classNames(\n kind && \"tds-btn\",\n size && size !== \"md\" && COMPONENT_SIZE_CLASS_MAP[size],\n kind && COMPONENT_KIND_CLASS_MAP[kind],\n fullWidth && \"tds-btn--full-width\",\n loading && \"tds-btn--loading\",\n className,\n { \"tds-btn--prefix\": prefix, \"tds-btn--suffix\": suffix }\n )\n\n const isDisabled = disabled || loading\n\n return (\n <button\n type=\"button\"\n className={combinedClassName}\n ref={mergedRef}\n {...mergedProps}\n aria-busy={loading || undefined}\n aria-describedby={describedBy}\n aria-disabled={isDisabled || undefined}\n disabled={isDisabled}\n aria-label={loading ? loadingAriaLabel : ariaLabel}\n >\n {loading && <LoadingSpinner />}\n {wrapStringWithSpan(prefix)}\n {loading ? <span>{label}</span> : label}\n {wrapStringWithSpan(suffix)}\n </button>\n )\n }\n)\n\nBaseButton.displayName = \"BaseButton\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"BaseButton.js","sources":["../../../src/components/button/BaseButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport { LoadingSpinner } from \"@components/internal\"\nimport { TooltipTriggerContext } from \"@components/internal/tooltip/TooltipTriggerContext\"\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n wrapStringWithSpan,\n} from \"@utilities/buttonLinkShared\"\nimport classNames from \"classnames\"\nimport React, { ButtonHTMLAttributes, forwardRef, useContext } from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { mergeRefs } from \"react-aria/mergeRefs\"\n\nexport interface BaseButtonProps extends Omit<BaseComponentProps, \"kind\"> {\n /** The visual style of the button. */\n kind?: ComponentKind\n /** The text content of the button. */\n label: React.ReactNode\n /** Whether the button is in a loading state. When true, the button is disabled and shows a loading spinner. */\n loading?: boolean\n /** Accessible label to use when the button is in loading state. */\n loadingAriaLabel?: string\n}\n\nexport type BaseButtonElementProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n keyof BaseButtonProps | \"children\"\n> &\n BaseButtonProps\n\nexport const BaseButton = forwardRef<HTMLButtonElement, BaseButtonElementProps>(\n (\n {\n \"aria-describedby\": ariaDescribedBy,\n \"aria-label\": ariaLabel,\n className,\n disabled = false,\n fullWidth,\n kind = \"secondary\",\n label,\n loading = false,\n loadingAriaLabel = \"Loading...\",\n prefix,\n size,\n suffix,\n ...restProps\n }: BaseButtonElementProps,\n ref\n ) => {\n const tooltip = useContext(TooltipTriggerContext)\n const { \"aria-describedby\": tooltipId, ...tooltipTriggerProps } =\n tooltip?.triggerProps ?? {}\n\n const mergedProps = tooltip\n ? mergeProps(restProps, tooltipTriggerProps)\n : restProps\n const mergedRef = tooltip\n ? mergeRefs<HTMLButtonElement>(ref, tooltip.ref)\n : ref\n const describedBy =\n [ariaDescribedBy, tooltipId].filter(Boolean).join(\" \") || undefined\n\n const combinedClassName = classNames(\n kind && \"tds-btn\",\n size && size !== \"md\" && COMPONENT_SIZE_CLASS_MAP[size],\n kind && COMPONENT_KIND_CLASS_MAP[kind],\n fullWidth && \"tds-btn--full-width\",\n loading && \"tds-btn--loading\",\n className,\n { \"tds-btn--prefix\": prefix, \"tds-btn--suffix\": suffix }\n )\n\n const isDisabled = disabled || loading\n\n return (\n <button\n type=\"button\"\n className={combinedClassName}\n ref={mergedRef}\n {...mergedProps}\n aria-busy={loading || undefined}\n aria-describedby={describedBy}\n aria-disabled={isDisabled || undefined}\n disabled={isDisabled}\n aria-label={loading ? loadingAriaLabel : ariaLabel}\n >\n {loading && <LoadingSpinner />}\n {wrapStringWithSpan(prefix)}\n {loading ? <span>{label}</span> : label}\n {wrapStringWithSpan(suffix)}\n </button>\n )\n }\n)\n\nBaseButton.displayName = \"BaseButton\"\n"],"names":[],"mappings":";;;;;;;;;MAiCa,UAAU,GAAG,UAAU,CAClC,CACE,EACE,kBAAkB,EAAE,eAAe,EACnC,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,IAAI,GAAG,WAAW,EAClB,KAAK,EACL,OAAO,GAAG,KAAK,EACf,gBAAgB,GAAG,YAAY,EAC/B,MAAM,EACN,IAAI,EACJ,MAAM,EACN,GAAG,SAAS,EACW,EACzB,GAAG,KACD;AACF,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,qBAAqB,CAAC;AACjD,IAAA,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,GAAG,mBAAmB,EAAE,GAC7D,OAAO,EAAE,YAAY,IAAI,EAAE;IAE7B,MAAM,WAAW,GAAG;AAClB,UAAE,UAAU,CAAC,SAAS,EAAE,mBAAmB;UACzC,SAAS;IACb,MAAM,SAAS,GAAG;UACd,SAAS,CAAoB,GAAG,EAAE,OAAO,CAAC,GAAG;UAC7C,GAAG;AACP,IAAA,MAAM,WAAW,GACf,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS;IAErE,MAAM,iBAAiB,GAAG,UAAU,CAClC,IAAI,IAAI,SAAS,EACjB,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACvD,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACtC,SAAS,IAAI,qBAAqB,EAClC,OAAO,IAAI,kBAAkB,EAC7B,SAAS,EACT,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,CACzD;AAED,IAAA,MAAM,UAAU,GAAG,QAAQ,IAAI,OAAO;AAEtC,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,iBAAiB,EAC5B,GAAG,EAAE,SAAS,KACV,WAAW,EAAA,WAAA,EACJ,OAAO,IAAI,SAAS,EAAA,kBAAA,EACb,WAAW,mBACd,UAAU,IAAI,SAAS,EACtC,QAAQ,EAAE,UAAU,EAAA,YAAA,EACR,OAAO,GAAG,gBAAgB,GAAG,SAAS,EAAA;QAEjD,OAAO,IAAI,KAAA,CAAA,aAAA,CAAC,cAAc,EAAA,IAAA,CAAG;QAC7B,kBAAkB,CAAC,MAAM,CAAC;QAC1B,OAAO,GAAG,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA,IAAA,EAAO,KAAK,CAAQ,GAAG,KAAK;AACtC,QAAA,kBAAkB,CAAC,MAAM,CAAC,CACpB;AAEb,CAAC;AAGH,UAAU,CAAC,WAAW,GAAG,YAAY;;;;"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { DropdownTriggerContext } from '../dropdown/DropdownTriggerContext.js';
|
|
2
2
|
import Icon from '../../utilities/Icon.js';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
-
import
|
|
4
|
+
import React, { forwardRef, useContext } from 'react';
|
|
5
5
|
import { BaseButton } from './BaseButton.js';
|
|
6
6
|
|
|
7
7
|
function dropdownProps({ className }) {
|
|
8
8
|
return {
|
|
9
9
|
className: classNames(className, "tds-btn--dropdown"),
|
|
10
|
-
suffix:
|
|
10
|
+
suffix: React.createElement(Icon, { className: "suffix", symbol: "general#down-caret", "aria-hidden": true }),
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
@@ -20,7 +20,7 @@ function dropdownProps({ className }) {
|
|
|
20
20
|
*/
|
|
21
21
|
const DropdownButton = forwardRef((props, ref) => {
|
|
22
22
|
const contextProps = useContext(DropdownTriggerContext);
|
|
23
|
-
return (
|
|
23
|
+
return (React.createElement(BaseButton, { ref: ref, ...props, ...contextProps, ...dropdownProps(props) }));
|
|
24
24
|
});
|
|
25
25
|
DropdownButton.displayName = "DropdownButton";
|
|
26
26
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownButton.js","sources":["../../../src/components/button/DropdownButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\nexport type DropdownButtonProps = {\n /**\n * ID of the element controlled by this dropdown button. Optional when wrapped\n * in `<DropdownTrigger>` (RA's `<Pressable>` injects it from\n * `PressResponderContext`); required when used standalone to drive a custom popover.\n */\n \"aria-controls\"?: string\n /**\n * Whether the dropdown is expanded or not. Optional when wrapped in\n * `<DropdownTrigger>`; required when used standalone.\n */\n \"aria-expanded\"?: boolean\n suffix?: never\n}\n\nexport function dropdownProps({ className }: { className?: string }) {\n return {\n className: classNames(className, \"tds-btn--dropdown\"),\n suffix: <Icon className=\"suffix\" symbol=\"general#down-caret\" aria-hidden />,\n }\n}\n\n/**\n * A button that toggles a dropdown menu or popover. Appends a caret suffix\n * and wires up `aria-controls` and `aria-expanded` to the controlled element.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-dropdown-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const DropdownButton = forwardRef<\n HTMLButtonElement,\n BaseButtonElementProps & DropdownButtonProps\n>((props, ref) => {\n const contextProps = useContext(DropdownTriggerContext)\n return (\n <BaseButton\n ref={ref}\n {...props}\n {...contextProps}\n {...dropdownProps(props)}\n />\n )\n})\n\nDropdownButton.displayName = \"DropdownButton\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"DropdownButton.js","sources":["../../../src/components/button/DropdownButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\nexport type DropdownButtonProps = {\n /**\n * ID of the element controlled by this dropdown button. Optional when wrapped\n * in `<DropdownTrigger>` (RA's `<Pressable>` injects it from\n * `PressResponderContext`); required when used standalone to drive a custom popover.\n */\n \"aria-controls\"?: string\n /**\n * Whether the dropdown is expanded or not. Optional when wrapped in\n * `<DropdownTrigger>`; required when used standalone.\n */\n \"aria-expanded\"?: boolean\n suffix?: never\n}\n\nexport function dropdownProps({ className }: { className?: string }) {\n return {\n className: classNames(className, \"tds-btn--dropdown\"),\n suffix: <Icon className=\"suffix\" symbol=\"general#down-caret\" aria-hidden />,\n }\n}\n\n/**\n * A button that toggles a dropdown menu or popover. Appends a caret suffix\n * and wires up `aria-controls` and `aria-expanded` to the controlled element.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-dropdown-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const DropdownButton = forwardRef<\n HTMLButtonElement,\n BaseButtonElementProps & DropdownButtonProps\n>((props, ref) => {\n const contextProps = useContext(DropdownTriggerContext)\n return (\n <BaseButton\n ref={ref}\n {...props}\n {...contextProps}\n {...dropdownProps(props)}\n />\n )\n})\n\nDropdownButton.displayName = \"DropdownButton\"\n"],"names":[],"mappings":";;;;;;AAwBM,SAAU,aAAa,CAAC,EAAE,SAAS,EAA0B,EAAA;IACjE,OAAO;AACL,QAAA,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,mBAAmB,CAAC;QACrD,MAAM,EAAE,KAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAC,SAAS,EAAC,QAAQ,EAAC,MAAM,EAAC,oBAAoB,EAAA,aAAA,EAAA,IAAA,EAAA,CAAe;KAC5E;AACH;AAEA;;;;;;;AAOG;AACI,MAAM,cAAc,GAAG,UAAU,CAGtC,CAAC,KAAK,EAAE,GAAG,KAAI;AACf,IAAA,MAAM,YAAY,GAAG,UAAU,CAAC,sBAAsB,CAAC;AACvD,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,UAAU,IACT,GAAG,EAAE,GAAG,EAAA,GACJ,KAAK,EAAA,GACL,YAAY,KACZ,aAAa,CAAC,KAAK,CAAC,EAAA,CACxB;AAEN,CAAC;AAED,cAAc,CAAC,WAAW,GAAG,gBAAgB;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DropdownTriggerContext } from '../dropdown/DropdownTriggerContext.js';
|
|
2
|
-
import
|
|
2
|
+
import React, { forwardRef, useContext } from 'react';
|
|
3
3
|
import { dropdownProps } from './DropdownButton.js';
|
|
4
4
|
import { IconButton } from './IconButton.js';
|
|
5
5
|
|
|
@@ -14,7 +14,7 @@ import { IconButton } from './IconButton.js';
|
|
|
14
14
|
*/
|
|
15
15
|
const DropdownIconButton = forwardRef((props, ref) => {
|
|
16
16
|
const contextProps = useContext(DropdownTriggerContext);
|
|
17
|
-
return (
|
|
17
|
+
return (React.createElement(IconButton, { ref: ref, ...props, ...contextProps, ...dropdownProps(props) }));
|
|
18
18
|
});
|
|
19
19
|
DropdownIconButton.displayName = "DropdownIconButton";
|
|
20
20
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownIconButton.js","sources":["../../../src/components/button/DropdownIconButton.tsx"],"sourcesContent":["import { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { DropdownButtonProps, dropdownProps } from \"./DropdownButton\"\nimport { IconButton, IconButtonProps } from \"./IconButton\"\n\n/**\n * An icon-only button that toggles a dropdown menu or popover. Appends a\n * caret suffix to the icon and wires up `aria-controls` and `aria-expanded`\n * to the controlled element. Requires an `aria-label` for accessibility.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-dropdown-icon-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const DropdownIconButton = forwardRef<\n HTMLButtonElement,\n IconButtonProps & DropdownButtonProps\n>((props, ref) => {\n const contextProps = useContext(DropdownTriggerContext)\n return (\n <IconButton\n ref={ref}\n {...props}\n {...contextProps}\n {...dropdownProps(props)}\n />\n )\n})\n\nDropdownIconButton.displayName = \"DropdownIconButton\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"DropdownIconButton.js","sources":["../../../src/components/button/DropdownIconButton.tsx"],"sourcesContent":["import { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { DropdownButtonProps, dropdownProps } from \"./DropdownButton\"\nimport { IconButton, IconButtonProps } from \"./IconButton\"\n\n/**\n * An icon-only button that toggles a dropdown menu or popover. Appends a\n * caret suffix to the icon and wires up `aria-controls` and `aria-expanded`\n * to the controlled element. Requires an `aria-label` for accessibility.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-dropdown-icon-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const DropdownIconButton = forwardRef<\n HTMLButtonElement,\n IconButtonProps & DropdownButtonProps\n>((props, ref) => {\n const contextProps = useContext(DropdownTriggerContext)\n return (\n <IconButton\n ref={ref}\n {...props}\n {...contextProps}\n {...dropdownProps(props)}\n />\n )\n})\n\nDropdownIconButton.displayName = \"DropdownIconButton\"\n"],"names":[],"mappings":";;;;;AAMA;;;;;;;;AAQG;AACI,MAAM,kBAAkB,GAAG,UAAU,CAG1C,CAAC,KAAK,EAAE,GAAG,KAAI;AACf,IAAA,MAAM,YAAY,GAAG,UAAU,CAAC,sBAAsB,CAAC;AACvD,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,UAAU,IACT,GAAG,EAAE,GAAG,EAAA,GACJ,KAAK,EAAA,GACL,YAAY,KACZ,aAAa,CAAC,KAAK,CAAC,EAAA,CACxB;AAEN,CAAC;AAED,kBAAkB,CAAC,WAAW,GAAG,oBAAoB;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
3
|
import { BaseButton } from './BaseButton.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -12,7 +12,7 @@ import { BaseButton } from './BaseButton.js';
|
|
|
12
12
|
*/
|
|
13
13
|
const IconButton = forwardRef(({ className, icon, ...restProps }, ref) => {
|
|
14
14
|
const iconOnlyClassName = classNames("tds-btn--icononly", className);
|
|
15
|
-
return (
|
|
15
|
+
return (React.createElement(BaseButton, { ...restProps, label: icon, className: iconOnlyClassName, ref: ref }));
|
|
16
16
|
});
|
|
17
17
|
IconButton.displayName = "IconButton";
|
|
18
18
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.js","sources":["../../../src/components/button/IconButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport classNames from \"classnames\"\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\nexport type IconButtonProps = Omit<BaseButtonElementProps, \"label\"> & {\n /** Accessible label. Required for icon-only buttons to provide context about the button's purpose. */\n \"aria-label\": string\n /** The icon to display in the button. Set via story args for non-primitive values. */\n icon: React.ReactNode\n}\n\n/**\n * An icon-only button component that renders as a button element.\n * Requires an icon and aria-label for accessibility.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-icon-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ className, icon, ...restProps }: IconButtonProps, ref) => {\n const iconOnlyClassName = classNames(\"tds-btn--icononly\", className)\n\n return (\n <BaseButton\n {...restProps}\n label={icon}\n className={iconOnlyClassName}\n ref={ref}\n />\n )\n }\n)\n\nIconButton.displayName = \"IconButton\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"IconButton.js","sources":["../../../src/components/button/IconButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport classNames from \"classnames\"\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\nexport type IconButtonProps = Omit<BaseButtonElementProps, \"label\"> & {\n /** Accessible label. Required for icon-only buttons to provide context about the button's purpose. */\n \"aria-label\": string\n /** The icon to display in the button. Set via story args for non-primitive values. */\n icon: React.ReactNode\n}\n\n/**\n * An icon-only button component that renders as a button element.\n * Requires an icon and aria-label for accessibility.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-icon-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ className, icon, ...restProps }: IconButtonProps, ref) => {\n const iconOnlyClassName = classNames(\"tds-btn--icononly\", className)\n\n return (\n <BaseButton\n {...restProps}\n label={icon}\n className={iconOnlyClassName}\n ref={ref}\n />\n )\n }\n)\n\nIconButton.displayName = \"IconButton\"\n"],"names":[],"mappings":";;;;AAcA;;;;;;;AAOG;AACI,MAAM,UAAU,GAAG,UAAU,CAClC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,SAAS,EAAmB,EAAE,GAAG,KAAI;IAC1D,MAAM,iBAAiB,GAAG,UAAU,CAAC,mBAAmB,EAAE,SAAS,CAAC;AAEpE,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,UAAU,OACL,SAAS,EACb,KAAK,EAAE,IAAI,EACX,SAAS,EAAE,iBAAiB,EAC5B,GAAG,EAAE,GAAG,EAAA,CACR;AAEN,CAAC;AAGH,UAAU,CAAC,WAAW,GAAG,YAAY;;;;"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
3
|
import { DropdownButton } from './DropdownButton.js';
|
|
4
4
|
|
|
5
5
|
function needsAttentionProps({ className, needsAttention, }) {
|
|
6
6
|
return needsAttention
|
|
7
7
|
? {
|
|
8
8
|
className: classNames(className, "tds-btn--attention"),
|
|
9
|
-
prefix: (
|
|
9
|
+
prefix: (React.createElement("span", { className: "attention-icon", "aria-label": "Needs attention!" })),
|
|
10
10
|
}
|
|
11
11
|
: {
|
|
12
12
|
className,
|
|
@@ -21,7 +21,7 @@ function needsAttentionProps({ className, needsAttention, }) {
|
|
|
21
21
|
* @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-page-header-actions-dropdown-button--docs | Storybook Documentation}
|
|
22
22
|
*/
|
|
23
23
|
const PageHeaderActionsDropdownButton = forwardRef(({ className, needsAttention, ...props }, ref) => {
|
|
24
|
-
return (
|
|
24
|
+
return (React.createElement(DropdownButton, { ref: ref, ...props, kind: "secondary-page-header", ...needsAttentionProps({ className, needsAttention }) }));
|
|
25
25
|
});
|
|
26
26
|
PageHeaderActionsDropdownButton.displayName = "PageHeaderActionsDropdownButton";
|
|
27
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeaderActionsDropdownButton.js","sources":["../../../src/components/button/PageHeaderActionsDropdownButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport classNames from \"classnames\"\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButtonElementProps } from \"./BaseButton\"\nimport { DropdownButton, DropdownButtonProps } from \"./DropdownButton\"\n\nexport type PageHeaderActionsDropdownButtonProps = Omit<\n BaseButtonElementProps,\n \"kind\"\n> &\n DropdownButtonProps & {\n /** Whether the button needs attention. Adds warning styling and attention icon when true. */\n needsAttention?: boolean\n }\n\nexport function needsAttentionProps({\n className,\n needsAttention,\n}: {\n className?: string\n needsAttention?: boolean\n}) {\n return needsAttention\n ? {\n className: classNames(className, \"tds-btn--attention\"),\n prefix: (\n <span className=\"attention-icon\" aria-label=\"Needs attention!\" />\n ),\n }\n : {\n className,\n }\n}\n\n/**\n * A dropdown button styled for the page header actions area. Renders with\n * the `secondary-page-header` kind and supports an optional `needsAttention`\n * state that adds warning styling and an attention icon.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-page-header-actions-dropdown-button--docs | Storybook Documentation}\n */\nexport const PageHeaderActionsDropdownButton = forwardRef<\n HTMLButtonElement,\n PageHeaderActionsDropdownButtonProps\n>(\n (\n {\n className,\n needsAttention,\n ...props\n }: PageHeaderActionsDropdownButtonProps,\n ref\n ) => {\n return (\n <DropdownButton\n ref={ref}\n {...props}\n kind=\"secondary-page-header\"\n {...needsAttentionProps({ className, needsAttention })}\n />\n )\n }\n)\n\nPageHeaderActionsDropdownButton.displayName = \"PageHeaderActionsDropdownButton\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"PageHeaderActionsDropdownButton.js","sources":["../../../src/components/button/PageHeaderActionsDropdownButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport classNames from \"classnames\"\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButtonElementProps } from \"./BaseButton\"\nimport { DropdownButton, DropdownButtonProps } from \"./DropdownButton\"\n\nexport type PageHeaderActionsDropdownButtonProps = Omit<\n BaseButtonElementProps,\n \"kind\"\n> &\n DropdownButtonProps & {\n /** Whether the button needs attention. Adds warning styling and attention icon when true. */\n needsAttention?: boolean\n }\n\nexport function needsAttentionProps({\n className,\n needsAttention,\n}: {\n className?: string\n needsAttention?: boolean\n}) {\n return needsAttention\n ? {\n className: classNames(className, \"tds-btn--attention\"),\n prefix: (\n <span className=\"attention-icon\" aria-label=\"Needs attention!\" />\n ),\n }\n : {\n className,\n }\n}\n\n/**\n * A dropdown button styled for the page header actions area. Renders with\n * the `secondary-page-header` kind and supports an optional `needsAttention`\n * state that adds warning styling and an attention icon.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button-page-header-actions-dropdown-button--docs | Storybook Documentation}\n */\nexport const PageHeaderActionsDropdownButton = forwardRef<\n HTMLButtonElement,\n PageHeaderActionsDropdownButtonProps\n>(\n (\n {\n className,\n needsAttention,\n ...props\n }: PageHeaderActionsDropdownButtonProps,\n ref\n ) => {\n return (\n <DropdownButton\n ref={ref}\n {...props}\n kind=\"secondary-page-header\"\n {...needsAttentionProps({ className, needsAttention })}\n />\n )\n }\n)\n\nPageHeaderActionsDropdownButton.displayName = \"PageHeaderActionsDropdownButton\"\n"],"names":[],"mappings":";;;;SAiBgB,mBAAmB,CAAC,EAClC,SAAS,EACT,cAAc,GAIf,EAAA;AACC,IAAA,OAAO;AACL,UAAE;AACE,YAAA,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,oBAAoB,CAAC;YACtD,MAAM,GACJ,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,gBAAgB,EAAA,YAAA,EAAY,kBAAkB,EAAA,CAAG,CAClE;AACF;AACH,UAAE;YACE,SAAS;SACV;AACP;AAEA;;;;;;;AAOG;AACI,MAAM,+BAA+B,GAAG,UAAU,CAIvD,CACE,EACE,SAAS,EACT,cAAc,EACd,GAAG,KAAK,EAC6B,EACvC,GAAG,KACD;IACF,QACE,KAAA,CAAA,aAAA,CAAC,cAAc,EAAA,EACb,GAAG,EAAE,GAAG,EAAA,GACJ,KAAK,EACT,IAAI,EAAC,uBAAuB,EAAA,GACxB,mBAAmB,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,EAAA,CACtD;AAEN,CAAC;AAGH,+BAA+B,CAAC,WAAW,GAAG,iCAAiC;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import
|
|
2
|
+
import React from 'react';
|
|
3
3
|
import { MenuTrigger, MenuItem, Popover, Menu, MenuSection, Header, Separator, Pressable } from 'react-aria-components/Menu';
|
|
4
4
|
import { DropdownTriggerContext } from './DropdownTriggerContext.js';
|
|
5
5
|
|
|
@@ -31,7 +31,7 @@ function Dropdown({ children, onClose, onOpen }) {
|
|
|
31
31
|
else
|
|
32
32
|
onClose?.();
|
|
33
33
|
};
|
|
34
|
-
return
|
|
34
|
+
return React.createElement(MenuTrigger, { onOpenChange: handleOpenChange }, children);
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* The popover surface for a `<Dropdown>`. Wraps React Aria's `<Popover>` and
|
|
@@ -40,12 +40,12 @@ function Dropdown({ children, onClose, onOpen }) {
|
|
|
40
40
|
* @component
|
|
41
41
|
*/
|
|
42
42
|
function DropdownMenu({ children, id, placement = "bottom start", }) {
|
|
43
|
-
return (
|
|
44
|
-
|
|
43
|
+
return (React.createElement(Popover, { className: "tds-dropdown-popover", placement: placement },
|
|
44
|
+
React.createElement(Menu, { id: id }, children)));
|
|
45
45
|
}
|
|
46
46
|
function DropdownTrigger({ children, disabled }) {
|
|
47
|
-
return (
|
|
48
|
-
|
|
47
|
+
return (React.createElement(DropdownTriggerContext.Provider, { value: { disabled } },
|
|
48
|
+
React.createElement(Pressable, { isDisabled: disabled }, children)));
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* A `<Dropdown>` item that fires a callback when activated. Renders an RA
|
|
@@ -56,7 +56,7 @@ function DropdownTrigger({ children, disabled }) {
|
|
|
56
56
|
* @component
|
|
57
57
|
*/
|
|
58
58
|
function DropdownAction({ className, destructive, disabled, staffOnly, ...restProps }) {
|
|
59
|
-
return (
|
|
59
|
+
return (React.createElement(MenuItem, { ...restProps, className: classNames("tds-dropdown-item", {
|
|
60
60
|
"tds-dropdown-item--destructive": destructive,
|
|
61
61
|
"tds-dropdown-item--staff-only": staffOnly,
|
|
62
62
|
}, className), isDisabled: disabled }));
|
|
@@ -76,7 +76,7 @@ function DropdownLink({ className, destructive, external, staffOnly, ...restProp
|
|
|
76
76
|
const externalProps = external
|
|
77
77
|
? { rel: "noreferrer noopener", target: "_blank" }
|
|
78
78
|
: null;
|
|
79
|
-
return (
|
|
79
|
+
return (React.createElement(MenuItem, { ...restProps, ...externalProps, className: classNames("tds-dropdown-item", {
|
|
80
80
|
"tds-dropdown-item--destructive": destructive,
|
|
81
81
|
"tds-dropdown-item--staff-only": staffOnly,
|
|
82
82
|
}, className) }));
|
|
@@ -88,8 +88,8 @@ function DropdownLink({ className, destructive, external, staffOnly, ...restProp
|
|
|
88
88
|
* @component
|
|
89
89
|
*/
|
|
90
90
|
function DropdownSection({ children, className, title, ...restProps }) {
|
|
91
|
-
return (
|
|
92
|
-
|
|
91
|
+
return (React.createElement(MenuSection, { ...restProps, className: classNames("tds-dropdown-section", className) },
|
|
92
|
+
React.createElement(Header, { className: "tds-dropdown-section-label" }, title),
|
|
93
93
|
children));
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
@@ -99,7 +99,7 @@ function DropdownSection({ children, className, title, ...restProps }) {
|
|
|
99
99
|
* @component
|
|
100
100
|
*/
|
|
101
101
|
function DropdownSeparator() {
|
|
102
|
-
return
|
|
102
|
+
return React.createElement(Separator, { className: "tds-dropdown-separator" });
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export { Dropdown, DropdownAction, DropdownLink, DropdownMenu, DropdownSection, DropdownSeparator, DropdownTrigger };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n type ReactElement,\n type ReactNode,\n} from \"react\"\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 Separator,\n} from \"react-aria-components/Menu\"\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 * 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 /**\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\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}: DropdownMenuElementProps) {\n return (\n <Popover className=\"tds-dropdown-popover\" placement={placement}>\n <Menu id={id}>{children}</Menu>\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 DropdownLinkProps extends DropdownItemBaseProps {\n /** If `true`, sets `target=\"_blank\"` and `rel=\"noreferrer noopener\"`. */\n external?: boolean\n /** Destination URL. */\n href: string\n /**\n * Stable identifier — required by React Aria's collection model for keying\n * and focus tracking.\n */\n id: Key\n}\n\ntype AriaLinkPropsToOmit =\n | \"isDisabled\"\n | \"onAction\"\n | \"rel\"\n | \"target\"\n | \"value\"\ntype AriaLinkPropsToInclude = \"href\" | \"routerOptions\" | \"textValue\"\n\nexport type DropdownLinkElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuItemProps<T>,\n DropdownLinkProps,\n AriaLinkPropsToOmit,\n AriaLinkPropsToInclude\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 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 />\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":["React"],"mappings":";;;;;AA2CA;;;;;;;;;;;;;;;;;;;;AAoBG;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,OAAOA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAC,YAAY,EAAE,gBAAgB,EAAA,EAAG,QAAQ,CAAe;AAC9E;AAoBA;;;;;AAKG;AACG,SAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,EAAE,EACF,SAAS,GAAG,cAAc,GACD,EAAA;IACzB,QACEA,cAAA,CAAA,aAAA,CAAC,OAAO,EAAA,EAAC,SAAS,EAAC,sBAAsB,EAAC,SAAS,EAAE,SAAS,EAAA;QAC5DA,cAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAC,EAAE,EAAE,EAAE,IAAG,QAAQ,CAAQ,CACvB;AAEd;SAyBgB,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAwB,EAAA;IAC1E,QACEA,cAAA,CAAA,aAAA,CAAC,sBAAsB,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAA;QAClDA,cAAA,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,QACEA,cAAA,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;AA8BA;;;;;;;;;;AAUG;AACG,SAAU,YAAY,CAAmB,EAC7C,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,QACEA,cAAA,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,EAAA,CACD;AAEN;AAqBA;;;;;AAKG;AACG,SAAU,eAAe,CAAmB,EAChD,QAAQ,EACR,SAAS,EACT,KAAK,EACL,GAAG,SAAS,EACmB,EAAA;AAC/B,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAA,GACN,SAAS,EACb,SAAS,EAAE,UAAU,CAAC,sBAAsB,EAAE,SAAS,CAAC,EAAA;AAExD,QAAAA,cAAA,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,OAAOA,6BAAC,SAAS,EAAA,EAAC,SAAS,EAAC,wBAAwB,GAAG;AACzD;;;;"}
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sources":["../../../src/components/dropdown/Dropdown.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n type ReactElement,\n type ReactNode,\n} from \"react\"\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 Separator,\n} from \"react-aria-components/Menu\"\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 * 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 /**\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\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}: DropdownMenuElementProps) {\n return (\n <Popover className=\"tds-dropdown-popover\" placement={placement}>\n <Menu id={id}>{children}</Menu>\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 DropdownLinkProps extends DropdownItemBaseProps {\n /** If `true`, sets `target=\"_blank\"` and `rel=\"noreferrer noopener\"`. */\n external?: boolean\n /** Destination URL. */\n href: string\n /**\n * Stable identifier — required by React Aria's collection model for keying\n * and focus tracking.\n */\n id: Key\n}\n\ntype AriaLinkPropsToOmit =\n | \"isDisabled\"\n | \"onAction\"\n | \"rel\"\n | \"target\"\n | \"value\"\ntype AriaLinkPropsToInclude = \"href\" | \"routerOptions\" | \"textValue\"\n\nexport type DropdownLinkElementProps<T extends object = object> =\n CombineAriaPropsWithCustomProps<\n MenuItemProps<T>,\n DropdownLinkProps,\n AriaLinkPropsToOmit,\n AriaLinkPropsToInclude\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 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 />\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":";;;;;AA2CA;;;;;;;;;;;;;;;;;;;;AAoBG;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;AAoBA;;;;;AAKG;AACG,SAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,EAAE,EACF,SAAS,GAAG,cAAc,GACD,EAAA;IACzB,QACE,KAAA,CAAA,aAAA,CAAC,OAAO,EAAA,EAAC,SAAS,EAAC,sBAAsB,EAAC,SAAS,EAAE,SAAS,EAAA;QAC5D,KAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAC,EAAE,EAAE,EAAE,IAAG,QAAQ,CAAQ,CACvB;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;AA8BA;;;;;;;;;;AAUG;AACG,SAAU,YAAY,CAAmB,EAC7C,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,EAAA,CACD;AAEN;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;;;;"}
|
|
@@ -1,66 +1,12 @@
|
|
|
1
1
|
import { tokens } from '@planningcenter/tapestry-tokens/tokens';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
2
|
+
import 'classnames';
|
|
3
|
+
import 'react';
|
|
4
|
+
import 'react-aria/Overlay';
|
|
5
|
+
import 'react-aria/useOverlayPosition';
|
|
6
|
+
import 'react-aria/useTooltipTrigger';
|
|
7
|
+
import 'react-stately/useTooltipTriggerState';
|
|
8
|
+
import './TooltipTriggerContext.js';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
// via --tds-tooltip-arrow-size/--tds-tooltip-arrow-depth instead of its own literals.
|
|
12
|
-
const ARROW_SIZE = 10;
|
|
13
|
-
const ARROW_DEPTH = 5;
|
|
14
|
-
const FOCUS_RING_REACH = parseFloat(tokens["--t-focus-ring-offset"]) +
|
|
10
|
+
parseFloat(tokens["--t-focus-ring-offset"]) +
|
|
15
11
|
parseFloat(tokens["--t-focus-ring-width"]);
|
|
16
|
-
/**
|
|
17
|
-
* Shows a short hover/focus hint next to a trigger. Built from React Aria's
|
|
18
|
-
* tooltip hooks rather than `react-aria-components`'s `<Tooltip>`, because
|
|
19
|
-
* that component unmounts its content entirely while closed, so a screen
|
|
20
|
-
* reader's virtual cursor never gets access to the description unless real
|
|
21
|
-
* DOM focus lands on the trigger. This keeps the tooltip content always
|
|
22
|
-
* mounted and wires `aria-describedby` unconditionally, toggling only CSS
|
|
23
|
-
* visibility.
|
|
24
|
-
*/
|
|
25
|
-
function Tooltip({ children, content, placement = "bottom start", }) {
|
|
26
|
-
const triggerRef = useRef(null);
|
|
27
|
-
const overlayRef = useRef(null);
|
|
28
|
-
const tooltipId = `tds-tooltip-${useId()}`;
|
|
29
|
-
const state = useTooltipTriggerState();
|
|
30
|
-
const { triggerProps } = useTooltipTrigger({}, state, triggerRef);
|
|
31
|
-
const { tooltipProps: ariaTooltipProps } = useTooltip({ id: tooltipId }, state);
|
|
32
|
-
const { arrowProps, overlayProps, placement: resolvedPlacement, } = useOverlayPosition({
|
|
33
|
-
arrowSize: ARROW_SIZE,
|
|
34
|
-
isOpen: state.isOpen,
|
|
35
|
-
offset: ARROW_DEPTH + FOCUS_RING_REACH,
|
|
36
|
-
onClose: () => state.close(true),
|
|
37
|
-
overlayRef,
|
|
38
|
-
placement,
|
|
39
|
-
targetRef: triggerRef,
|
|
40
|
-
});
|
|
41
|
-
const contextValue = {
|
|
42
|
-
ref: triggerRef,
|
|
43
|
-
triggerProps: {
|
|
44
|
-
...triggerProps,
|
|
45
|
-
"aria-describedby": tooltipId,
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
49
|
-
React__default.createElement(TooltipTriggerContext.Provider, { value: contextValue }, children),
|
|
50
|
-
React__default.createElement(Overlay, { disableFocusManagement: true },
|
|
51
|
-
React__default.createElement("div", { ...ariaTooltipProps, ...overlayProps, ref: overlayRef, className: classNames("tds-tooltip", {
|
|
52
|
-
"tds-tooltip--open": state.isOpen,
|
|
53
|
-
}), "data-placement": resolvedPlacement, style: {
|
|
54
|
-
...overlayProps.style,
|
|
55
|
-
"--tds-tooltip-arrow-depth-raw": `${ARROW_DEPTH}px`,
|
|
56
|
-
"--tds-tooltip-arrow-size-raw": `${ARROW_SIZE}px`,
|
|
57
|
-
} },
|
|
58
|
-
content,
|
|
59
|
-
React__default.createElement("div", { className: "tds-tooltip-arrow", ...arrowProps },
|
|
60
|
-
React__default.createElement("svg", { "aria-hidden": true, className: "tds-tooltip-arrow-icon", role: "img", viewBox: `0 0 ${ARROW_SIZE} ${ARROW_DEPTH}` },
|
|
61
|
-
React__default.createElement("polygon", { points: `${ARROW_SIZE / 2},0 0,${ARROW_DEPTH} ${ARROW_SIZE},${ARROW_DEPTH}` })))))));
|
|
62
|
-
}
|
|
63
|
-
Tooltip.displayName = "Tooltip";
|
|
64
|
-
|
|
65
|
-
export { Tooltip };
|
|
66
12
|
//# sourceMappingURL=Tooltip.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.js","sources":["../../../../src/components/internal/tooltip/Tooltip.tsx"],"sourcesContent":["import { tokens } from \"@planningcenter/tapestry-tokens/tokens\"\nimport classNames from \"classnames\"\nimport React, { type ReactElement, useId, useRef } from \"react\"\nimport { Overlay } from \"react-aria/Overlay\"\nimport {\n type Placement,\n useOverlayPosition,\n} from \"react-aria/useOverlayPosition\"\nimport { useTooltip, useTooltipTrigger } from \"react-aria/useTooltipTrigger\"\nimport { useTooltipTriggerState } from \"react-stately/useTooltipTriggerState\"\n\nimport { TooltipTriggerContext } from \"./TooltipTriggerContext\"\n\n// Single source of truth for the arrow's dimensions -- index.css reads these\n// via --tds-tooltip-arrow-size/--tds-tooltip-arrow-depth instead of its own literals.\nconst ARROW_SIZE = 10\nconst ARROW_DEPTH = 5\nconst FOCUS_RING_REACH =\n parseFloat(tokens[\"--t-focus-ring-offset\"]) +\n parseFloat(tokens[\"--t-focus-ring-width\"])\n\nexport interface TooltipProps {\n /**\n * A single `BaseButton`-derived element (e.g. `IconButton`, `Button`) to\n * act as the trigger. Must be exactly one trigger — nothing enforces this\n * at runtime, so a fragment with more than one child would silently hand\n * every child the same ref and trigger props.\n */\n children: ReactElement\n /**\n * The hint text. Best used with information beyond the trigger's accessible name\n * (e.g. its `aria-label` or visible label).\n */\n content: string\n /** Where the tooltip renders relative to the trigger. Default `'bottom start'`. */\n placement?: Placement\n}\n\n/**\n * Shows a short hover/focus hint next to a trigger. Built from React Aria's\n * tooltip hooks rather than `react-aria-components`'s `<Tooltip>`, because\n * that component unmounts its content entirely while closed, so a screen\n * reader's virtual cursor never gets access to the description unless real\n * DOM focus lands on the trigger. This keeps the tooltip content always\n * mounted and wires `aria-describedby` unconditionally, toggling only CSS\n * visibility.\n */\nexport function Tooltip({\n children,\n content,\n placement = \"bottom start\",\n}: TooltipProps) {\n const triggerRef = useRef<HTMLButtonElement>(null)\n const overlayRef = useRef<HTMLDivElement>(null)\n const tooltipId = `tds-tooltip-${useId()}`\n\n const state = useTooltipTriggerState()\n const { triggerProps } = useTooltipTrigger({}, state, triggerRef)\n const { tooltipProps: ariaTooltipProps } = useTooltip(\n { id: tooltipId },\n state\n )\n\n const {\n arrowProps,\n overlayProps,\n placement: resolvedPlacement,\n } = useOverlayPosition({\n arrowSize: ARROW_SIZE,\n isOpen: state.isOpen,\n offset: ARROW_DEPTH + FOCUS_RING_REACH,\n onClose: () => state.close(true),\n overlayRef,\n placement,\n targetRef: triggerRef,\n })\n\n const contextValue = {\n ref: triggerRef,\n triggerProps: {\n ...triggerProps,\n \"aria-describedby\": tooltipId,\n },\n }\n\n return (\n <>\n <TooltipTriggerContext.Provider value={contextValue}>\n {children}\n </TooltipTriggerContext.Provider>\n <Overlay disableFocusManagement>\n <div\n {...ariaTooltipProps}\n {...overlayProps}\n ref={overlayRef}\n className={classNames(\"tds-tooltip\", {\n \"tds-tooltip--open\": state.isOpen,\n })}\n data-placement={resolvedPlacement}\n style={\n {\n ...overlayProps.style,\n \"--tds-tooltip-arrow-depth-raw\": `${ARROW_DEPTH}px`,\n \"--tds-tooltip-arrow-size-raw\": `${ARROW_SIZE}px`,\n } as React.CSSProperties\n }\n >\n {content}\n <div className=\"tds-tooltip-arrow\" {...arrowProps}>\n <svg\n aria-hidden\n className=\"tds-tooltip-arrow-icon\"\n role=\"img\"\n viewBox={`0 0 ${ARROW_SIZE} ${ARROW_DEPTH}`}\n >\n <polygon\n points={`${ARROW_SIZE / 2},0 0,${ARROW_DEPTH} ${ARROW_SIZE},${ARROW_DEPTH}`}\n />\n </svg>\n </div>\n </div>\n </Overlay>\n </>\n )\n}\n\nTooltip.displayName = \"Tooltip\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"Tooltip.js","sources":["../../../../src/components/internal/tooltip/Tooltip.tsx"],"sourcesContent":["import { tokens } from \"@planningcenter/tapestry-tokens/tokens\"\nimport classNames from \"classnames\"\nimport React, { type ReactElement, useId, useRef } from \"react\"\nimport { Overlay } from \"react-aria/Overlay\"\nimport {\n type Placement,\n useOverlayPosition,\n} from \"react-aria/useOverlayPosition\"\nimport { useTooltip, useTooltipTrigger } from \"react-aria/useTooltipTrigger\"\nimport { useTooltipTriggerState } from \"react-stately/useTooltipTriggerState\"\n\nimport { TooltipTriggerContext } from \"./TooltipTriggerContext\"\n\n// Single source of truth for the arrow's dimensions -- index.css reads these\n// via --tds-tooltip-arrow-size/--tds-tooltip-arrow-depth instead of its own literals.\nconst ARROW_SIZE = 10\nconst ARROW_DEPTH = 5\nconst FOCUS_RING_REACH =\n parseFloat(tokens[\"--t-focus-ring-offset\"]) +\n parseFloat(tokens[\"--t-focus-ring-width\"])\n\nexport interface TooltipProps {\n /**\n * A single `BaseButton`-derived element (e.g. `IconButton`, `Button`) to\n * act as the trigger. Must be exactly one trigger — nothing enforces this\n * at runtime, so a fragment with more than one child would silently hand\n * every child the same ref and trigger props.\n */\n children: ReactElement\n /**\n * The hint text. Best used with information beyond the trigger's accessible name\n * (e.g. its `aria-label` or visible label).\n */\n content: string\n /** Where the tooltip renders relative to the trigger. Default `'bottom start'`. */\n placement?: Placement\n}\n\n/**\n * Shows a short hover/focus hint next to a trigger. Built from React Aria's\n * tooltip hooks rather than `react-aria-components`'s `<Tooltip>`, because\n * that component unmounts its content entirely while closed, so a screen\n * reader's virtual cursor never gets access to the description unless real\n * DOM focus lands on the trigger. This keeps the tooltip content always\n * mounted and wires `aria-describedby` unconditionally, toggling only CSS\n * visibility.\n */\nexport function Tooltip({\n children,\n content,\n placement = \"bottom start\",\n}: TooltipProps) {\n const triggerRef = useRef<HTMLButtonElement>(null)\n const overlayRef = useRef<HTMLDivElement>(null)\n const tooltipId = `tds-tooltip-${useId()}`\n\n const state = useTooltipTriggerState()\n const { triggerProps } = useTooltipTrigger({}, state, triggerRef)\n const { tooltipProps: ariaTooltipProps } = useTooltip(\n { id: tooltipId },\n state\n )\n\n const {\n arrowProps,\n overlayProps,\n placement: resolvedPlacement,\n } = useOverlayPosition({\n arrowSize: ARROW_SIZE,\n isOpen: state.isOpen,\n offset: ARROW_DEPTH + FOCUS_RING_REACH,\n onClose: () => state.close(true),\n overlayRef,\n placement,\n targetRef: triggerRef,\n })\n\n const contextValue = {\n ref: triggerRef,\n triggerProps: {\n ...triggerProps,\n \"aria-describedby\": tooltipId,\n },\n }\n\n return (\n <>\n <TooltipTriggerContext.Provider value={contextValue}>\n {children}\n </TooltipTriggerContext.Provider>\n <Overlay disableFocusManagement>\n <div\n {...ariaTooltipProps}\n {...overlayProps}\n ref={overlayRef}\n className={classNames(\"tds-tooltip\", {\n \"tds-tooltip--open\": state.isOpen,\n })}\n data-placement={resolvedPlacement}\n style={\n {\n ...overlayProps.style,\n \"--tds-tooltip-arrow-depth-raw\": `${ARROW_DEPTH}px`,\n \"--tds-tooltip-arrow-size-raw\": `${ARROW_SIZE}px`,\n } as React.CSSProperties\n }\n >\n {content}\n <div className=\"tds-tooltip-arrow\" {...arrowProps}>\n <svg\n aria-hidden\n className=\"tds-tooltip-arrow-icon\"\n role=\"img\"\n viewBox={`0 0 ${ARROW_SIZE} ${ARROW_DEPTH}`}\n >\n <polygon\n points={`${ARROW_SIZE / 2},0 0,${ARROW_DEPTH} ${ARROW_SIZE},${ARROW_DEPTH}`}\n />\n </svg>\n </div>\n </div>\n </Overlay>\n </>\n )\n}\n\nTooltip.displayName = \"Tooltip\"\n"],"names":[],"mappings":";;;;;;;;;AAkBE,UAAU,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;AAC3C,IAAA,UAAU,CAAC,MAAM,CAAC,sBAAsB,CAAC"}
|