@planningcenter/tapestry 4.1.0-rc.3 → 4.1.0-rc.5
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 +2 -0
- package/dist/componentRegistration.js.map +1 -1
- package/dist/components/button/Button.js +2 -2
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/button/LoadingButton.js +2 -2
- package/dist/components/button/LoadingButton.js.map +1 -1
- package/dist/components/field/Field.js +5 -5
- package/dist/components/field/Field.js.map +1 -1
- package/dist/components/search-input/SearchInput.js +6 -6
- package/dist/components/search-input/SearchInput.js.map +1 -1
- package/dist/reactRender.css +1361 -1361
- package/dist/reactRender.css.map +1 -1
- package/dist/reactRenderLegacy.css +1361 -1361
- package/dist/reactRenderLegacy.css.map +1 -1
- package/package.json +2 -2
|
@@ -7,6 +7,7 @@ import { DatePicker } from './components/date-picker/DatePicker.js';
|
|
|
7
7
|
import { Dropdown, DropdownAction, DropdownLink, DropdownMenu, DropdownSection, DropdownSeparator, DropdownTrigger } from './components/dropdown/Dropdown.js';
|
|
8
8
|
import { NumberStepper } from './components/number-stepper/NumberStepper.js';
|
|
9
9
|
import { PageHeader } from './components/page-header/PageHeader.js';
|
|
10
|
+
import { SearchInput } from './components/search-input/SearchInput.js';
|
|
10
11
|
import { Select } from './components/select/Select.js';
|
|
11
12
|
import { Sidenav } from './components/sidenav/Sidenav.js';
|
|
12
13
|
import { SidenavItem } from './components/sidenav/SidenavItem.js';
|
|
@@ -29,6 +30,7 @@ r("DropdownTrigger", DropdownTrigger);
|
|
|
29
30
|
r("NumberStepper", NumberStepper);
|
|
30
31
|
r("PageHeader", PageHeader);
|
|
31
32
|
r("PageHeaderActionsDropdownButton", PageHeaderActionsDropdownButton);
|
|
33
|
+
r("SearchInput", SearchInput);
|
|
32
34
|
r("Select", Select);
|
|
33
35
|
r("Sidenav", Sidenav);
|
|
34
36
|
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 { 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":"
|
|
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 { SearchInput } from \"./components/search-input/SearchInput\"\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(\"SearchInput\", SearchInput)\nregister(\"Select\", Select)\nregister(\"Sidenav\", Sidenav)\nregister(\"SidenavItem\", SidenavItem)\nregister(\"SidenavSection\", SidenavSection)\nregister(\"TimeField\", TimeField)\n"],"names":["register"],"mappings":";;;;;;;;;;;;;;;;AA6BAA,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,aAAa,EAAE,WAAW,CAAC;AACpCA,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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
2
|
import { BaseButton } from './BaseButton.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -11,7 +11,7 @@ import { BaseButton } from './BaseButton.js';
|
|
|
11
11
|
* @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}
|
|
12
12
|
*/
|
|
13
13
|
const Button = forwardRef((props, ref) => {
|
|
14
|
-
return
|
|
14
|
+
return React.createElement(BaseButton, { ...props, ref: ref });
|
|
15
15
|
});
|
|
16
16
|
Button.displayName = "Button";
|
|
17
17
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sources":["../../../src/components/button/Button.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\nexport type ButtonElementProps = Omit<BaseButtonElementProps, \"label\"> & {\n /** The text content of the button. */\n label: string\n}\n\n/**\n * A button component that renders as a button element.\n * Supports various sizes, styles, and content types.\n * Label must be a string.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonElementProps>(\n (props, ref) => {\n return <BaseButton {...props} ref={ref} />\n }\n)\n\nButton.displayName = \"Button\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"Button.js","sources":["../../../src/components/button/Button.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\nexport type ButtonElementProps = Omit<BaseButtonElementProps, \"label\"> & {\n /** The text content of the button. */\n label: string\n}\n\n/**\n * A button component that renders as a button element.\n * Supports various sizes, styles, and content types.\n * Label must be a string.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonElementProps>(\n (props, ref) => {\n return <BaseButton {...props} ref={ref} />\n }\n)\n\nButton.displayName = \"Button\"\n"],"names":[],"mappings":";;;AAWA;;;;;;;;AAQG;AACI,MAAM,MAAM,GAAG,UAAU,CAC9B,CAAC,KAAK,EAAE,GAAG,KAAI;IACb,OAAO,KAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EAAA,GAAK,KAAK,EAAE,GAAG,EAAE,GAAG,EAAA,CAAI;AAC5C,CAAC;AAGH,MAAM,CAAC,WAAW,GAAG,QAAQ;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
2
|
import { BaseButton } from './BaseButton.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -19,7 +19,7 @@ import { BaseButton } from './BaseButton.js';
|
|
|
19
19
|
* @see {@link https://planningcenter.github.io/tapestry/?path=/docs/deprecated-loadingbutton--docs | Storybook Documentation}
|
|
20
20
|
*/
|
|
21
21
|
const LoadingButton = forwardRef((props, ref) => {
|
|
22
|
-
return
|
|
22
|
+
return React.createElement(BaseButton, { ...props, ref: ref });
|
|
23
23
|
});
|
|
24
24
|
LoadingButton.displayName = "LoadingButton";
|
|
25
25
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadingButton.js","sources":["../../../src/components/button/LoadingButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\n/**\n * @deprecated Use ButtonElementProps with loading prop instead. LoadingButton will be removed in a future version.\n */\nexport interface LoadingButtonProps extends BaseButtonElementProps {\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\n/**\n * @deprecated Use Button with loading prop instead. LoadingButton will be removed in a future version.\n *\n * A loading button component that shows a loading indicator when the loading prop is true.\n * When loading, the button is automatically disabled and shows a spinner.\n * Supports all BaseButton props including prefix and suffix.\n *\n * @example\n * // Deprecated\n * <LoadingButton loading={true} label=\"Submit\" />\n *\n * // Use this instead:\n * <Button loading={true} label=\"Submit\" />\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/deprecated-loadingbutton--docs | Storybook Documentation}\n */\nexport const LoadingButton = forwardRef<HTMLButtonElement, LoadingButtonProps>(\n (props, ref) => {\n return <BaseButton {...props} ref={ref} />\n }\n)\n\nLoadingButton.displayName = \"LoadingButton\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"LoadingButton.js","sources":["../../../src/components/button/LoadingButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport React, { forwardRef } from \"react\"\n\nimport { BaseButton, BaseButtonElementProps } from \"./BaseButton\"\n\n/**\n * @deprecated Use ButtonElementProps with loading prop instead. LoadingButton will be removed in a future version.\n */\nexport interface LoadingButtonProps extends BaseButtonElementProps {\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\n/**\n * @deprecated Use Button with loading prop instead. LoadingButton will be removed in a future version.\n *\n * A loading button component that shows a loading indicator when the loading prop is true.\n * When loading, the button is automatically disabled and shows a spinner.\n * Supports all BaseButton props including prefix and suffix.\n *\n * @example\n * // Deprecated\n * <LoadingButton loading={true} label=\"Submit\" />\n *\n * // Use this instead:\n * <Button loading={true} label=\"Submit\" />\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/deprecated-loadingbutton--docs | Storybook Documentation}\n */\nexport const LoadingButton = forwardRef<HTMLButtonElement, LoadingButtonProps>(\n (props, ref) => {\n return <BaseButton {...props} ref={ref} />\n }\n)\n\nLoadingButton.displayName = \"LoadingButton\"\n"],"names":[],"mappings":";;;AAgBA;;;;;;;;;;;;;;;;AAgBG;AACI,MAAM,aAAa,GAAG,UAAU,CACrC,CAAC,KAAK,EAAE,GAAG,KAAI;IACb,OAAO,KAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EAAA,GAAK,KAAK,EAAE,GAAG,EAAE,GAAG,EAAA,CAAI;AAC5C,CAAC;AAGH,aAAa,CAAC,WAAW,GAAG,eAAe;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Icon from '../../utilities/Icon.js';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import
|
|
3
|
+
import React from 'react';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* A layout primitive that wraps a single form control with a label,
|
|
@@ -26,11 +26,11 @@ import React__default from 'react';
|
|
|
26
26
|
*/
|
|
27
27
|
function Field({ "aria-labelledby": ariaLabelledBy, children, className, description, hideLabel, id, label, }) {
|
|
28
28
|
const descriptionId = `${id}-description`;
|
|
29
|
-
return (
|
|
30
|
-
label && !ariaLabelledBy && (
|
|
29
|
+
return (React.createElement("div", { className: classNames("tds-field", className) },
|
|
30
|
+
label && !ariaLabelledBy && (React.createElement("label", { className: classNames("tds-field-label", hideLabel && "tds-field-label--hidden"), htmlFor: id }, label)),
|
|
31
31
|
children,
|
|
32
|
-
description && (
|
|
33
|
-
|
|
32
|
+
description && (React.createElement("p", { className: "tds-field-description", id: descriptionId },
|
|
33
|
+
React.createElement(Icon, { "aria-hidden": true, className: "tds-field-description-invalid-icon", symbol: "general#exclamation-triangle" }),
|
|
34
34
|
description))));
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -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 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 hideLabel,\n id,\n label,\n}: FieldProps) {\n const descriptionId = `${id}-description`\n\n return (\n <div className={classNames(\"tds-field\", className)}>\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":[
|
|
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 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 hideLabel,\n id,\n label,\n}: FieldProps) {\n const descriptionId = `${id}-description`\n\n return (\n <div className={classNames(\"tds-field\", className)}>\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":";;;;AAyBA;;;;;;;;;;;;;;;;;;;;;AAqBG;SACa,KAAK,CAAC,EACpB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,EACT,WAAW,EACX,SAAS,EACT,EAAE,EACF,KAAK,GACM,EAAA;AACX,IAAA,MAAM,aAAa,GAAG,CAAA,EAAG,EAAE,cAAc;IAEzC,QACE,6BAAK,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,EAAA;QAC/C,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;;;;"}
|
|
@@ -8,7 +8,7 @@ import { Field } from '../field/Field.js';
|
|
|
8
8
|
import Icon from '../../utilities/Icon.js';
|
|
9
9
|
import { useId } from '../../utilities/useId.js';
|
|
10
10
|
import classNames from 'classnames';
|
|
11
|
-
import
|
|
11
|
+
import React, { forwardRef, useRef, useState } from 'react';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* A search-specific input with a leading search icon and a trailing clear
|
|
@@ -61,13 +61,13 @@ const SearchInput = forwardRef(function SearchInput({ "aria-labelledby": ariaLab
|
|
|
61
61
|
const fieldLabelProps = ariaLabelledBy
|
|
62
62
|
? { "aria-labelledby": ariaLabelledBy }
|
|
63
63
|
: { hideLabel, label };
|
|
64
|
-
return (
|
|
65
|
-
|
|
64
|
+
return (React.createElement(Field, { ...fieldLabelProps, className: fieldClassName, description: description, id: inputId },
|
|
65
|
+
React.createElement("div", { className: classNames("tds-search-input-control", {
|
|
66
66
|
"tds-search-input-control--has-value": hasValue,
|
|
67
67
|
}) },
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
React.createElement(Icon, { "aria-hidden": true, className: "tds-search-input-icon", symbol: "general#search" }),
|
|
69
|
+
React.createElement("input", { ...restProps, "aria-describedby": descriptionId, "aria-invalid": invalid || undefined, "aria-labelledby": ariaLabelledBy, defaultValue: defaultValue, disabled: disabled, id: inputId, onChange: handleChange, onKeyDown: handleKeyDown, readOnly: readOnly, ref: setRefs, type: "search", value: value }),
|
|
70
|
+
React.createElement(IconButton, { "aria-label": "Clear", icon: React.createElement(Icon, { "aria-hidden": true, className: "tds-search-input-clear-icon", symbol: "general#x" }), kind: "neutral-inline", onClick: handleClear, tabIndex: -1 }))));
|
|
71
71
|
});
|
|
72
72
|
SearchInput.displayName = "SearchInput";
|
|
73
73
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput.js","sources":["../../../src/components/search-input/SearchInput.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { IconButton } from \"@components/button\"\nimport { Field } from \"@components/field\"\nimport Icon from \"@utilities/Icon\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, {\n forwardRef,\n type InputHTMLAttributes,\n useRef,\n useState,\n} from \"react\"\n\nexport type SearchInputSize = \"lg\" | \"md\"\n\ninterface SearchInputBaseProps {\n /** Helper text below the input. Styled as an error when `invalid`. */\n description?: React.ReactNode\n /** Triggers invalid state (error border, error description, aria-invalid). */\n invalid?: boolean\n /** Visual size — cascades to the icon, input, and clear button via Field's font-size custom property. Defaults to 'md'. */\n size?: SearchInputSize\n}\n\ninterface SearchInputWithLabel extends SearchInputBaseProps {\n \"aria-labelledby\"?: never\n /** If true, the label is visually hidden but remains in the DOM/AT tree. */\n hideLabel?: boolean\n /** The visible label. */\n label: React.ReactNode\n}\n\ninterface SearchInputWithAriaLabelledBy extends SearchInputBaseProps {\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type SearchInputProps =\n | SearchInputWithAriaLabelledBy\n | SearchInputWithLabel\n\n/**\n * Combines standard HTML input attributes with SearchInput's own props.\n * `type` is fixed to \"search\" and not exposed; `size` is redefined above.\n */\nexport type SearchInputElementProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n keyof SearchInputProps | \"size\" | \"type\"\n> &\n SearchInputProps\n\n/**\n * A search-specific input with a leading search icon and a trailing clear\n * (\"x\") button, built on `type=\"search\"`. Composes `Field` directly for\n * label, description, and state layout.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-searchinput--docs | Storybook Documentation}\n */\nexport const SearchInput = forwardRef<\n HTMLInputElement,\n SearchInputElementProps\n>(function SearchInput(\n {\n \"aria-labelledby\": ariaLabelledBy,\n className,\n defaultValue,\n description,\n disabled,\n hideLabel,\n id,\n invalid,\n label,\n onChange,\n onKeyDown,\n readOnly,\n size = \"md\",\n value,\n ...restProps\n }: SearchInputElementProps,\n ref\n) {\n const innerRef = useRef<HTMLInputElement | null>(null)\n const setRefs = (node: HTMLInputElement | null) => {\n innerRef.current = node\n if (typeof ref === \"function\") ref(node)\n else if (ref) {\n ;(ref as React.MutableRefObject<HTMLInputElement | null>).current = node\n }\n }\n\n const stableId = useId()\n const inputId = id || `tds-search-input-${stableId}`\n const descriptionId = description ? `${inputId}-description` : undefined\n\n const [uncontrolledHasValue, setUncontrolledHasValue] = useState(\n () => String(defaultValue ?? \"\").length > 0\n )\n const hasValue =\n value !== undefined ? String(value).length > 0 : uncontrolledHasValue\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (value === undefined) {\n setUncontrolledHasValue(event.target.value.length > 0)\n }\n onChange?.(event)\n }\n\n const handleClear = () => {\n const input = innerRef.current\n if (!input) return\n\n const nativeSetter = Object.getOwnPropertyDescriptor(\n input.constructor.prototype,\n \"value\"\n )?.set\n nativeSetter?.call(input, \"\")\n input.dispatchEvent(new Event(\"input\", { bubbles: true }))\n input.focus()\n if (value === undefined) {\n setUncontrolledHasValue(false)\n }\n }\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Escape\" && hasValue) {\n event.stopPropagation()\n }\n onKeyDown?.(event)\n }\n\n const fieldClassName = classNames(\n { \"tds-field--lg\": size === \"lg\" },\n className\n )\n\n const fieldLabelProps = ariaLabelledBy\n ? { \"aria-labelledby\": ariaLabelledBy }\n : { hideLabel, label }\n\n return (\n <Field\n {...fieldLabelProps}\n className={fieldClassName}\n description={description}\n id={inputId}\n >\n <div\n className={classNames(\"tds-search-input-control\", {\n \"tds-search-input-control--has-value\": hasValue,\n })}\n >\n <Icon\n aria-hidden\n className=\"tds-search-input-icon\"\n symbol=\"general#search\"\n />\n <input\n {...restProps}\n aria-describedby={descriptionId}\n aria-invalid={invalid || undefined}\n aria-labelledby={ariaLabelledBy}\n defaultValue={defaultValue}\n disabled={disabled}\n id={inputId}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n readOnly={readOnly}\n ref={setRefs}\n type=\"search\"\n value={value}\n />\n <IconButton\n aria-label=\"Clear\"\n icon={\n <Icon\n aria-hidden\n className=\"tds-search-input-clear-icon\"\n symbol=\"general#x\"\n />\n }\n kind=\"neutral-inline\"\n onClick={handleClear}\n tabIndex={-1}\n />\n </div>\n </Field>\n )\n})\n\nSearchInput.displayName = \"SearchInput\"\n"],"names":[
|
|
1
|
+
{"version":3,"file":"SearchInput.js","sources":["../../../src/components/search-input/SearchInput.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { IconButton } from \"@components/button\"\nimport { Field } from \"@components/field\"\nimport Icon from \"@utilities/Icon\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, {\n forwardRef,\n type InputHTMLAttributes,\n useRef,\n useState,\n} from \"react\"\n\nexport type SearchInputSize = \"lg\" | \"md\"\n\ninterface SearchInputBaseProps {\n /** Helper text below the input. Styled as an error when `invalid`. */\n description?: React.ReactNode\n /** Triggers invalid state (error border, error description, aria-invalid). */\n invalid?: boolean\n /** Visual size — cascades to the icon, input, and clear button via Field's font-size custom property. Defaults to 'md'. */\n size?: SearchInputSize\n}\n\ninterface SearchInputWithLabel extends SearchInputBaseProps {\n \"aria-labelledby\"?: never\n /** If true, the label is visually hidden but remains in the DOM/AT tree. */\n hideLabel?: boolean\n /** The visible label. */\n label: React.ReactNode\n}\n\ninterface SearchInputWithAriaLabelledBy extends SearchInputBaseProps {\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type SearchInputProps =\n | SearchInputWithAriaLabelledBy\n | SearchInputWithLabel\n\n/**\n * Combines standard HTML input attributes with SearchInput's own props.\n * `type` is fixed to \"search\" and not exposed; `size` is redefined above.\n */\nexport type SearchInputElementProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n keyof SearchInputProps | \"size\" | \"type\"\n> &\n SearchInputProps\n\n/**\n * A search-specific input with a leading search icon and a trailing clear\n * (\"x\") button, built on `type=\"search\"`. Composes `Field` directly for\n * label, description, and state layout.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-searchinput--docs | Storybook Documentation}\n */\nexport const SearchInput = forwardRef<\n HTMLInputElement,\n SearchInputElementProps\n>(function SearchInput(\n {\n \"aria-labelledby\": ariaLabelledBy,\n className,\n defaultValue,\n description,\n disabled,\n hideLabel,\n id,\n invalid,\n label,\n onChange,\n onKeyDown,\n readOnly,\n size = \"md\",\n value,\n ...restProps\n }: SearchInputElementProps,\n ref\n) {\n const innerRef = useRef<HTMLInputElement | null>(null)\n const setRefs = (node: HTMLInputElement | null) => {\n innerRef.current = node\n if (typeof ref === \"function\") ref(node)\n else if (ref) {\n ;(ref as React.MutableRefObject<HTMLInputElement | null>).current = node\n }\n }\n\n const stableId = useId()\n const inputId = id || `tds-search-input-${stableId}`\n const descriptionId = description ? `${inputId}-description` : undefined\n\n const [uncontrolledHasValue, setUncontrolledHasValue] = useState(\n () => String(defaultValue ?? \"\").length > 0\n )\n const hasValue =\n value !== undefined ? String(value).length > 0 : uncontrolledHasValue\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (value === undefined) {\n setUncontrolledHasValue(event.target.value.length > 0)\n }\n onChange?.(event)\n }\n\n const handleClear = () => {\n const input = innerRef.current\n if (!input) return\n\n const nativeSetter = Object.getOwnPropertyDescriptor(\n input.constructor.prototype,\n \"value\"\n )?.set\n nativeSetter?.call(input, \"\")\n input.dispatchEvent(new Event(\"input\", { bubbles: true }))\n input.focus()\n if (value === undefined) {\n setUncontrolledHasValue(false)\n }\n }\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Escape\" && hasValue) {\n event.stopPropagation()\n }\n onKeyDown?.(event)\n }\n\n const fieldClassName = classNames(\n { \"tds-field--lg\": size === \"lg\" },\n className\n )\n\n const fieldLabelProps = ariaLabelledBy\n ? { \"aria-labelledby\": ariaLabelledBy }\n : { hideLabel, label }\n\n return (\n <Field\n {...fieldLabelProps}\n className={fieldClassName}\n description={description}\n id={inputId}\n >\n <div\n className={classNames(\"tds-search-input-control\", {\n \"tds-search-input-control--has-value\": hasValue,\n })}\n >\n <Icon\n aria-hidden\n className=\"tds-search-input-icon\"\n symbol=\"general#search\"\n />\n <input\n {...restProps}\n aria-describedby={descriptionId}\n aria-invalid={invalid || undefined}\n aria-labelledby={ariaLabelledBy}\n defaultValue={defaultValue}\n disabled={disabled}\n id={inputId}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n readOnly={readOnly}\n ref={setRefs}\n type=\"search\"\n value={value}\n />\n <IconButton\n aria-label=\"Clear\"\n icon={\n <Icon\n aria-hidden\n className=\"tds-search-input-clear-icon\"\n symbol=\"general#x\"\n />\n }\n kind=\"neutral-inline\"\n onClick={handleClear}\n tabIndex={-1}\n />\n </div>\n </Field>\n )\n})\n\nSearchInput.displayName = \"SearchInput\"\n"],"names":[],"mappings":"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"}
|