@planningcenter/tapestry 4.6.0-rc.6 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DataTable/ActiveFilters.d.ts +6 -2
- package/dist/components/DataTable/ActiveFilters.d.ts.map +1 -1
- package/dist/components/DataTable/ActiveFilters.js +24 -6
- package/dist/components/DataTable/ActiveFilters.js.map +1 -1
- package/dist/components/DataTable/DataTable.d.ts +4 -3
- package/dist/components/DataTable/DataTable.d.ts.map +1 -1
- package/dist/components/DataTable/DataTable.js +2 -2
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/DataTable/FilterTypes.d.ts +2 -2
- package/dist/components/DataTable/FilterTypes.d.ts.map +1 -1
- package/dist/components/DataTable/OperatorSelect.d.ts +9 -0
- package/dist/components/DataTable/OperatorSelect.d.ts.map +1 -0
- package/dist/components/DataTable/OperatorSelect.js +33 -0
- package/dist/components/DataTable/OperatorSelect.js.map +1 -0
- package/dist/components/button/Button.d.ts +12 -5
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/Button.js +0 -1
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/field/Field.d.ts +3 -1
- package/dist/components/field/Field.d.ts.map +1 -1
- package/dist/components/field/Field.js +2 -2
- package/dist/components/field/Field.js.map +1 -1
- package/dist/components/input/Input.d.ts +12 -3
- package/dist/components/input/Input.d.ts.map +1 -1
- package/dist/components/input/Input.js +2 -2
- package/dist/components/input/Input.js.map +1 -1
- package/dist/components/input-text-base/InputTextBase.d.ts +3 -1
- package/dist/components/input-text-base/InputTextBase.d.ts.map +1 -1
- package/dist/components/input-text-base/InputTextBase.js +2 -2
- package/dist/components/input-text-base/InputTextBase.js.map +1 -1
- package/dist/components/search-input/SearchInput.d.ts +2 -0
- package/dist/components/search-input/SearchInput.d.ts.map +1 -1
- package/dist/components/search-input/SearchInput.js +2 -2
- package/dist/components/search-input/SearchInput.js.map +1 -1
- package/dist/components/select/Select.d.ts +2 -0
- package/dist/components/select/Select.d.ts.map +1 -1
- package/dist/components/select/Select.js +2 -2
- package/dist/components/select/Select.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/packages/tapestry-render/dist/{buildComponent-DDhu-82j.js → buildComponent-C5PfOgH9.js} +343 -351
- package/dist/packages/tapestry-render/dist/buildComponent-C5PfOgH9.js.map +1 -0
- package/dist/packages/tapestry-render/dist/index.js +2 -2
- package/dist/packages/tapestry-render/dist/index.js.map +1 -1
- package/dist/packages/tapestry-render/dist/legacy.js +2 -2
- package/dist/packages/tapestry-render/dist/legacy.js.map +1 -1
- package/dist/reactRender.css +958 -958
- package/dist/reactRender.css.map +1 -1
- package/dist/reactRenderLegacy.css +958 -958
- package/dist/reactRenderLegacy.css.map +1 -1
- package/dist/unstable.css +4219 -4219
- package/dist/unstable.css.map +1 -1
- package/package.json +3 -3
- package/dist/packages/tapestry-render/dist/buildComponent-DDhu-82j.js.map +0 -1
|
@@ -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
|
|
1
|
+
{"version":3,"file":"Field.js","sources":["../../../src/components/field/Field.tsx"],"sourcesContent":["import Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, { ReactNode } from \"react\"\n\ninterface FieldBaseProps {\n children: ReactNode\n className?: string\n description?: ReactNode\n /** If true, sets `data-flex-expand` on the wrapper so it grows/shrinks to fill a `Flex` row. */\n expand?: boolean\n id: string\n}\n\ninterface FieldLabeledProps extends FieldBaseProps {\n \"aria-labelledby\"?: never\n hideLabel?: boolean\n label: ReactNode\n}\n\ninterface FieldExternallyLabeledProps extends FieldBaseProps {\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type FieldProps = FieldExternallyLabeledProps | FieldLabeledProps\n\n/**\n * A layout primitive that wraps a single form control with a label,\n * optional description, and state-driven styling (required, invalid, disabled).\n *\n * **Reach for a Tapestry form component first** — `Input`, `Checkbox`, `Radio`,\n * `ToggleSwitch`, `Select`, `ComboBox`, `DatePicker`, `TimeField`. Those\n * components handle their own label / description / state styling internally.\n *\n * **Use `Field` directly only when no Tapestry component fits your control** —\n * a custom widget, a third-party input, or an in-progress design.\n *\n * **Wiring contract** — Field renders children completely untouched. The caller\n * is responsible for:\n * - Setting `id` on the control to match the `id` prop passed to Field.\n * - Setting `aria-describedby=\"{id}-description\"` on the control when\n * `description` is provided.\n * - Setting `aria-labelledby` on the control when using `aria-labelledby` mode.\n * - Setting state attributes (`required`, `disabled`, `aria-invalid`) directly\n * on the control — Field's CSS detects them via `:has()`.\n *\n * @component\n */\nexport function Field({\n \"aria-labelledby\": ariaLabelledBy,\n children,\n className,\n description,\n expand,\n hideLabel,\n id,\n label,\n}: FieldProps) {\n const descriptionId = `${id}-description`\n\n return (\n <div\n className={classNames(\"tds-field\", className)}\n data-flex-expand={expand || undefined}\n >\n {label && !ariaLabelledBy && (\n <label\n className={classNames(\n \"tds-field-label\",\n hideLabel && \"tds-field-label--hidden\"\n )}\n htmlFor={id}\n >\n {label}\n </label>\n )}\n {children}\n {description && (\n <p className=\"tds-field-description\" id={descriptionId}>\n <Icon\n aria-hidden\n className=\"tds-field-description-invalid-icon\"\n symbol=\"general#exclamation-triangle\"\n />\n {description}\n </p>\n )}\n </div>\n )\n}\n"],"names":[],"mappings":";;;;AA2BA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,KAAK,CAAC,EACpB,iBAAiB,EAAE,cAAc,EACjC,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,KAAK,GACM,EAAA;AACX,IAAA,MAAM,aAAa,GAAG,CAAA,EAAG,EAAE,cAAc;AAEzC,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,EAAA,kBAAA,EAC3B,MAAM,IAAI,SAAS,EAAA;QAEpC,KAAK,IAAI,CAAC,cAAc,KACvB,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EACE,SAAS,EAAE,UAAU,CACnB,iBAAiB,EACjB,SAAS,IAAI,yBAAyB,CACvC,EACD,OAAO,EAAE,EAAE,EAAA,EAEV,KAAK,CACA,CACT;QACA,QAAQ;QACR,WAAW,KACV,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,uBAAuB,EAAC,EAAE,EAAE,aAAa,EAAA;YACpD,KAAA,CAAA,aAAA,CAAC,IAAI,yBAEH,SAAS,EAAC,oCAAoC,EAC9C,MAAM,EAAC,8BAA8B,EAAA,CACrC;AACD,YAAA,WAAW,CACV,CACL,CACG;AAEV;;;;"}
|
|
@@ -3,8 +3,6 @@ import React, { type InputHTMLAttributes } from "react";
|
|
|
3
3
|
export type InputSize = "lg" | "md";
|
|
4
4
|
export type InputType = "email" | "number" | "password" | "search" | "tel" | "text" | "url";
|
|
5
5
|
interface InputBaseProps {
|
|
6
|
-
/** If true, the input width grows to fit content. */
|
|
7
|
-
autoWidth?: boolean;
|
|
8
6
|
/** Helper text displayed below the input. Styled as an error when `invalid`. */
|
|
9
7
|
description?: React.ReactNode;
|
|
10
8
|
/** Whether the input is in an invalid state. */
|
|
@@ -16,6 +14,17 @@ interface InputBaseProps {
|
|
|
16
14
|
/** Supported input types — defaults to 'text' */
|
|
17
15
|
type?: InputType;
|
|
18
16
|
}
|
|
17
|
+
interface InputWithAutoWidth {
|
|
18
|
+
/** If true, the input width grows to fit content. Mutually exclusive with `expand`. */
|
|
19
|
+
autoWidth?: boolean;
|
|
20
|
+
expand?: never;
|
|
21
|
+
}
|
|
22
|
+
interface InputWithExpand {
|
|
23
|
+
autoWidth?: never;
|
|
24
|
+
/** If true, sets `data-flex-expand` so the input grows/shrinks to fill a `Flex` row. Mutually exclusive with `autoWidth`. */
|
|
25
|
+
expand?: boolean;
|
|
26
|
+
}
|
|
27
|
+
type InputSizingProps = InputWithAutoWidth | InputWithExpand;
|
|
19
28
|
interface InputWithVisibleLabel extends InputBaseProps {
|
|
20
29
|
/** If true, the label is visually hidden and set as aria-label. */
|
|
21
30
|
hideLabel?: false;
|
|
@@ -38,7 +47,7 @@ export type InputProps = InputWithAriaLabelledBy | InputWithHiddenLabel | InputW
|
|
|
38
47
|
* Combines standard HTML input attributes with custom Input props.
|
|
39
48
|
* Omits 'size' and 'type' from HTML attributes to avoid conflict with our strict types.
|
|
40
49
|
*/
|
|
41
|
-
export type InputElementProps = Omit<InputHTMLAttributes<HTMLInputElement>, keyof InputProps | "size" | "type"> & InputProps;
|
|
50
|
+
export type InputElementProps = Omit<InputHTMLAttributes<HTMLInputElement>, keyof InputProps | keyof InputSizingProps | "size" | "type"> & InputProps & InputSizingProps;
|
|
42
51
|
/**
|
|
43
52
|
* A text input component that renders as an HTML `<input>` with a label and
|
|
44
53
|
* optional description. Supports the standard text-like input types
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../src/components/input/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAIpB,OAAO,KAAK,EAAE,EAAc,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAA;AAEnE,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,CAAA;AAEnC,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,KAAK,GACL,MAAM,GACN,KAAK,CAAA;AAET,UAAU,cAAc;IACtB,
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../src/components/input/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAIpB,OAAO,KAAK,EAAE,EAAc,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAA;AAEnE,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,CAAA;AAEnC,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,KAAK,GACL,MAAM,GACN,KAAK,CAAA;AAET,UAAU,cAAc;IACtB,gFAAgF;IAChF,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,6BAA6B;IAC7B,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,iDAAiD;IACjD,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAED,UAAU,kBAAkB;IAC1B,uFAAuF;IACvF,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,KAAK,CAAA;CACf;AAED,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,6HAA6H;IAC7H,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,KAAK,gBAAgB,GAAG,kBAAkB,GAAG,eAAe,CAAA;AAE5D,UAAU,qBAAsB,SAAQ,cAAc;IACpD,mEAAmE;IACnE,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,oCAAoC;IACpC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;CACvB;AAED,UAAU,oBAAqB,SAAQ,cAAc;IACnD,mEAAmE;IACnE,SAAS,EAAE,IAAI,CAAA;IACf,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;CACd;AAED,UAAU,uBAAwB,SAAQ,cAAc;IACtD,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,MAAM,UAAU,GAClB,uBAAuB,GACvB,oBAAoB,GACpB,qBAAqB,CAAA;AAEzB;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,UAAU,GAAG,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAC5D,GACC,UAAU,GACV,gBAAgB,CAAA;AAElB;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,4FA6EjB,CAAA"}
|
|
@@ -12,7 +12,7 @@ import React__default, { forwardRef } from 'react';
|
|
|
12
12
|
* @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-input--docs | Storybook Documentation}
|
|
13
13
|
* @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}
|
|
14
14
|
*/
|
|
15
|
-
const Input = forwardRef(function Input({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, autoComplete, autoWidth, className, description, hideLabel, id, invalid, label, onFocus, selectTextOnFocus, size = "md", type = "text", ...restProps }, ref) {
|
|
15
|
+
const Input = forwardRef(function Input({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, autoComplete, autoWidth, className, description, expand, hideLabel, id, invalid, label, onFocus, selectTextOnFocus, size = "md", type = "text", ...restProps }, ref) {
|
|
16
16
|
const autoCompleteBlockingProps = autoComplete === "off"
|
|
17
17
|
? {
|
|
18
18
|
"data-1p-ignore": true,
|
|
@@ -33,7 +33,7 @@ const Input = forwardRef(function Input({ "aria-label": ariaLabel, "aria-labelle
|
|
|
33
33
|
}
|
|
34
34
|
: onFocus;
|
|
35
35
|
const wrapperClassName = classNames({ "tds-input--auto-width": autoWidth }, className);
|
|
36
|
-
return (React__default.createElement(InputTextBase, { className: wrapperClassName, description: description, hideLabel: hideLabel || !!ariaLabelledBy, id: id, invalid: invalid, label: label, size: size }, ({ descriptionId, inputId }) => (React__default.createElement("input", { ...restProps, ...autoCompleteBlockingProps, "aria-describedby": descriptionId, "aria-invalid": invalid || undefined, "aria-label": hideLabel ? ariaLabel || label : ariaLabel, "aria-labelledby": ariaLabelledBy, autoComplete: autoComplete, id: inputId, onFocus: handleFocus, ref: ref, type: type }))));
|
|
36
|
+
return (React__default.createElement(InputTextBase, { className: wrapperClassName, description: description, expand: expand, hideLabel: hideLabel || !!ariaLabelledBy, id: id, invalid: invalid, label: label, size: size }, ({ descriptionId, inputId }) => (React__default.createElement("input", { ...restProps, ...autoCompleteBlockingProps, "aria-describedby": descriptionId, "aria-invalid": invalid || undefined, "aria-label": hideLabel ? ariaLabel || label : ariaLabel, "aria-labelledby": ariaLabelledBy, autoComplete: autoComplete, id: inputId, onFocus: handleFocus, ref: ref, type: type }))));
|
|
37
37
|
});
|
|
38
38
|
Input.displayName = "Input";
|
|
39
39
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","sources":["../../../src/components/input/Input.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { InputTextBase } from \"@components/input-text-base\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, type InputHTMLAttributes } from \"react\"\n\nexport type InputSize = \"lg\" | \"md\"\n\nexport type InputType =\n | \"email\"\n | \"number\"\n | \"password\"\n | \"search\"\n | \"tel\"\n | \"text\"\n | \"url\"\n\ninterface InputBaseProps {\n /**
|
|
1
|
+
{"version":3,"file":"Input.js","sources":["../../../src/components/input/Input.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { InputTextBase } from \"@components/input-text-base\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, type InputHTMLAttributes } from \"react\"\n\nexport type InputSize = \"lg\" | \"md\"\n\nexport type InputType =\n | \"email\"\n | \"number\"\n | \"password\"\n | \"search\"\n | \"tel\"\n | \"text\"\n | \"url\"\n\ninterface InputBaseProps {\n /** Helper text displayed below the input. Styled as an error when `invalid`. */\n description?: React.ReactNode\n /** Whether the input is in an invalid state. */\n invalid?: boolean\n /** If true, all text is selected when the input receives focus. */\n selectTextOnFocus?: boolean\n /** The size of the input. */\n size?: InputSize\n /** Supported input types — defaults to 'text' */\n type?: InputType\n}\n\ninterface InputWithAutoWidth {\n /** If true, the input width grows to fit content. Mutually exclusive with `expand`. */\n autoWidth?: boolean\n expand?: never\n}\n\ninterface InputWithExpand {\n autoWidth?: never\n /** If true, sets `data-flex-expand` so the input grows/shrinks to fill a `Flex` row. Mutually exclusive with `autoWidth`. */\n expand?: boolean\n}\n\ntype InputSizingProps = InputWithAutoWidth | InputWithExpand\n\ninterface InputWithVisibleLabel extends InputBaseProps {\n /** If true, the label is visually hidden and set as aria-label. */\n hideLabel?: false\n /** The label text for the input. */\n label: React.ReactNode\n}\n\ninterface InputWithHiddenLabel extends InputBaseProps {\n /** If true, the label is visually hidden and set as aria-label. */\n hideLabel: true\n /** The label text for the input. Must be a string when hidden. */\n label: string\n}\n\ninterface InputWithAriaLabelledBy extends InputBaseProps {\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type InputProps =\n | InputWithAriaLabelledBy\n | InputWithHiddenLabel\n | InputWithVisibleLabel\n\n/**\n * Combines standard HTML input attributes with custom Input props.\n * Omits 'size' and 'type' from HTML attributes to avoid conflict with our strict types.\n */\nexport type InputElementProps = Omit<\n InputHTMLAttributes<HTMLInputElement>,\n keyof InputProps | keyof InputSizingProps | \"size\" | \"type\"\n> &\n InputProps &\n InputSizingProps\n\n/**\n * A text input component that renders as an HTML `<input>` with a label and\n * optional description. Supports the standard text-like input types\n * (`text`, `email`, `password`, `search`, `tel`, `url`, `number`), invalid\n * state, and `lg`/`md` sizing.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-input--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const Input = forwardRef<HTMLInputElement, InputElementProps>(\n function Input(\n {\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n autoComplete,\n autoWidth,\n className,\n description,\n expand,\n hideLabel,\n id,\n invalid,\n label,\n onFocus,\n selectTextOnFocus,\n size = \"md\",\n type = \"text\",\n ...restProps\n }: InputElementProps,\n ref\n ) {\n const autoCompleteBlockingProps =\n autoComplete === \"off\"\n ? {\n \"data-1p-ignore\": true,\n \"data-bwignore\": true,\n \"data-form-type\": \"other\",\n \"data-lpignore\": true,\n }\n : {}\n\n const handleFocus = selectTextOnFocus\n ? (event: React.FocusEvent<HTMLInputElement>) => {\n try {\n event.currentTarget.select()\n } catch {\n // Some input types (e.g. number) do not support text selection.\n }\n onFocus?.(event)\n }\n : onFocus\n\n const wrapperClassName = classNames(\n { \"tds-input--auto-width\": autoWidth },\n className\n )\n\n return (\n <InputTextBase\n className={wrapperClassName}\n description={description}\n expand={expand}\n hideLabel={hideLabel || !!ariaLabelledBy}\n id={id}\n invalid={invalid}\n label={label}\n size={size}\n >\n {({ descriptionId, inputId }) => (\n <input\n {...restProps}\n {...autoCompleteBlockingProps}\n aria-describedby={descriptionId}\n aria-invalid={invalid || undefined}\n aria-label={hideLabel ? ariaLabel || (label as string) : ariaLabel}\n aria-labelledby={ariaLabelledBy}\n autoComplete={autoComplete}\n id={inputId}\n onFocus={handleFocus}\n ref={ref}\n type={type}\n />\n )}\n </InputTextBase>\n )\n }\n)\n\nInput.displayName = \"Input\"\n"],"names":["React"],"mappings":";;;;AAgFA;;;;;;;;;AASG;AACI,MAAM,KAAK,GAAG,UAAU,CAC7B,SAAS,KAAK,CACZ,EACE,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,OAAO,EACP,KAAK,EACL,OAAO,EACP,iBAAiB,EACjB,IAAI,GAAG,IAAI,EACX,IAAI,GAAG,MAAM,EACb,GAAG,SAAS,EACM,EACpB,GAAG,EAAA;AAEH,IAAA,MAAM,yBAAyB,GAC7B,YAAY,KAAK;AACf,UAAE;AACE,YAAA,gBAAgB,EAAE,IAAI;AACtB,YAAA,eAAe,EAAE,IAAI;AACrB,YAAA,gBAAgB,EAAE,OAAO;AACzB,YAAA,eAAe,EAAE,IAAI;AACtB;UACD,EAAE;IAER,MAAM,WAAW,GAAG;AAClB,UAAE,CAAC,KAAyC,KAAI;AAC5C,YAAA,IAAI;AACF,gBAAA,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE;YAC9B;AAAE,YAAA,MAAM;;YAER;AACA,YAAA,OAAO,GAAG,KAAK,CAAC;QAClB;UACA,OAAO;AAEX,IAAA,MAAM,gBAAgB,GAAG,UAAU,CACjC,EAAE,uBAAuB,EAAE,SAAS,EAAE,EACtC,SAAS,CACV;IAED,QACEA,6BAAC,aAAa,EAAA,EACZ,SAAS,EAAE,gBAAgB,EAC3B,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,IAAI,CAAC,CAAC,cAAc,EACxC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,IAET,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,MAC1BA,cAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAA,GACM,SAAS,KACT,yBAAyB,EAAA,kBAAA,EACX,aAAa,EAAA,cAAA,EACjB,OAAO,IAAI,SAAS,EAAA,YAAA,EACtB,SAAS,GAAG,SAAS,IAAK,KAAgB,GAAG,SAAS,EAAA,iBAAA,EACjD,cAAc,EAC/B,YAAY,EAAE,YAAY,EAC1B,EAAE,EAAE,OAAO,EACX,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,IAAI,EAAA,CACV,CACH,CACa;AAEpB,CAAC;AAGH,KAAK,CAAC,WAAW,GAAG,OAAO;;;;"}
|
|
@@ -5,6 +5,8 @@ interface InputTextBaseProps {
|
|
|
5
5
|
inputId: string;
|
|
6
6
|
}) => React.ReactNode;
|
|
7
7
|
description?: React.ReactNode;
|
|
8
|
+
/** If true, sets `data-flex-expand` on the wrapper so it grows/shrinks to fill a `Flex` row. */
|
|
9
|
+
expand?: boolean;
|
|
8
10
|
hideLabel?: boolean;
|
|
9
11
|
id?: string;
|
|
10
12
|
invalid?: boolean;
|
|
@@ -12,6 +14,6 @@ interface InputTextBaseProps {
|
|
|
12
14
|
size?: "md" | "lg";
|
|
13
15
|
}
|
|
14
16
|
export type InputTextBaseElementProps = Omit<React.HTMLAttributes<HTMLDivElement>, keyof InputTextBaseProps> & InputTextBaseProps;
|
|
15
|
-
export declare function InputTextBase({ children, className, description, hideLabel, id, label, invalid, size, }: InputTextBaseElementProps): React.JSX.Element;
|
|
17
|
+
export declare function InputTextBase({ children, className, description, expand, hideLabel, id, label, invalid, size, }: InputTextBaseElementProps): React.JSX.Element;
|
|
16
18
|
export {};
|
|
17
19
|
//# sourceMappingURL=InputTextBase.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputTextBase.d.ts","sourceRoot":"","sources":["../../../src/components/input-text-base/InputTextBase.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE;QAChB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,OAAO,EAAE,MAAM,CAAA;KAChB,KAAK,KAAK,CAAC,SAAS,CAAA;IACrB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EACpC,MAAM,kBAAkB,CACzB,GACC,kBAAkB,CAAA;AAEpB,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,WAAW,EACX,SAAS,EACT,EAAE,EACF,KAAK,EACL,OAAO,EACP,IAAI,GACL,EAAE,yBAAyB,qBAiC3B"}
|
|
1
|
+
{"version":3,"file":"InputTextBase.d.ts","sourceRoot":"","sources":["../../../src/components/input-text-base/InputTextBase.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE;QAChB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,OAAO,EAAE,MAAM,CAAA;KAChB,KAAK,KAAK,CAAC,SAAS,CAAA;IACrB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC1C,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EACpC,MAAM,kBAAkB,CACzB,GACC,kBAAkB,CAAA;AAEpB,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,KAAK,EACL,OAAO,EACP,IAAI,GACL,EAAE,yBAAyB,qBAiC3B"}
|
|
@@ -3,7 +3,7 @@ import { useId } from '../../utilities/useId.js';
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
|
|
6
|
-
function InputTextBase({ children, className, description, hideLabel, id, label, invalid, size, }) {
|
|
6
|
+
function InputTextBase({ children, className, description, expand, hideLabel, id, label, invalid, size, }) {
|
|
7
7
|
const combinedClassName = classNames("tds-input", className, {
|
|
8
8
|
"tds-input--invalid": invalid,
|
|
9
9
|
"tds-input--lg": size === "lg",
|
|
@@ -14,7 +14,7 @@ function InputTextBase({ children, className, description, hideLabel, id, label,
|
|
|
14
14
|
const descriptionId = resolvedDescription
|
|
15
15
|
? `${inputId}-description`
|
|
16
16
|
: undefined;
|
|
17
|
-
return (React.createElement("div", { className: combinedClassName },
|
|
17
|
+
return (React.createElement("div", { className: combinedClassName, "data-flex-expand": expand || undefined },
|
|
18
18
|
!hideLabel && label ? React.createElement("label", { htmlFor: inputId }, label) : null,
|
|
19
19
|
children({
|
|
20
20
|
descriptionId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputTextBase.js","sources":["../../../src/components/input-text-base/InputTextBase.tsx"],"sourcesContent":["import Icon from \"@utilities/Icon\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport * as React from \"react\"\n\ninterface InputTextBaseProps {\n children: (props: {\n descriptionId?: string\n inputId: string\n }) => React.ReactNode\n description?: React.ReactNode\n hideLabel?: boolean\n id?: string\n invalid?: boolean\n label?: React.ReactNode\n size?: \"md\" | \"lg\"\n}\n\nexport type InputTextBaseElementProps = Omit<\n React.HTMLAttributes<HTMLDivElement>,\n keyof InputTextBaseProps\n> &\n InputTextBaseProps\n\nexport function InputTextBase({\n children,\n className,\n description,\n hideLabel,\n id,\n label,\n invalid,\n size,\n}: InputTextBaseElementProps) {\n const combinedClassName = classNames(\"tds-input\", className, {\n \"tds-input--invalid\": invalid,\n \"tds-input--lg\": size === \"lg\",\n })\n\n const stableId = useId()\n const inputId = id || `tds-input-${stableId}`\n const resolvedDescription =\n description || (invalid ? \"This field is required\" : undefined)\n const descriptionId = resolvedDescription\n ? `${inputId}-description`\n : undefined\n\n return (\n <div className={combinedClassName}>\n {!hideLabel && label ? <label htmlFor={inputId}>{label}</label> : null}\n {children({\n descriptionId,\n inputId,\n })}\n {resolvedDescription && (\n <p id={descriptionId} className=\"tds-input-description\">\n <Icon\n className=\"tds-input-description-invalid-icon\"\n symbol=\"general#exclamation-triangle\"\n aria-hidden\n />\n {resolvedDescription}\n </p>\n )}\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"InputTextBase.js","sources":["../../../src/components/input-text-base/InputTextBase.tsx"],"sourcesContent":["import Icon from \"@utilities/Icon\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport * as React from \"react\"\n\ninterface InputTextBaseProps {\n children: (props: {\n descriptionId?: string\n inputId: string\n }) => React.ReactNode\n description?: React.ReactNode\n /** If true, sets `data-flex-expand` on the wrapper so it grows/shrinks to fill a `Flex` row. */\n expand?: boolean\n hideLabel?: boolean\n id?: string\n invalid?: boolean\n label?: React.ReactNode\n size?: \"md\" | \"lg\"\n}\n\nexport type InputTextBaseElementProps = Omit<\n React.HTMLAttributes<HTMLDivElement>,\n keyof InputTextBaseProps\n> &\n InputTextBaseProps\n\nexport function InputTextBase({\n children,\n className,\n description,\n expand,\n hideLabel,\n id,\n label,\n invalid,\n size,\n}: InputTextBaseElementProps) {\n const combinedClassName = classNames(\"tds-input\", className, {\n \"tds-input--invalid\": invalid,\n \"tds-input--lg\": size === \"lg\",\n })\n\n const stableId = useId()\n const inputId = id || `tds-input-${stableId}`\n const resolvedDescription =\n description || (invalid ? \"This field is required\" : undefined)\n const descriptionId = resolvedDescription\n ? `${inputId}-description`\n : undefined\n\n return (\n <div className={combinedClassName} data-flex-expand={expand || undefined}>\n {!hideLabel && label ? <label htmlFor={inputId}>{label}</label> : null}\n {children({\n descriptionId,\n inputId,\n })}\n {resolvedDescription && (\n <p id={descriptionId} className=\"tds-input-description\">\n <Icon\n className=\"tds-input-description-invalid-icon\"\n symbol=\"general#exclamation-triangle\"\n aria-hidden\n />\n {resolvedDescription}\n </p>\n )}\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;AA0BM,SAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,WAAW,EACX,MAAM,EACN,SAAS,EACT,EAAE,EACF,KAAK,EACL,OAAO,EACP,IAAI,GACsB,EAAA;AAC1B,IAAA,MAAM,iBAAiB,GAAG,UAAU,CAAC,WAAW,EAAE,SAAS,EAAE;AAC3D,QAAA,oBAAoB,EAAE,OAAO;QAC7B,eAAe,EAAE,IAAI,KAAK,IAAI;AAC/B,KAAA,CAAC;AAEF,IAAA,MAAM,QAAQ,GAAG,KAAK,EAAE;AACxB,IAAA,MAAM,OAAO,GAAG,EAAE,IAAI,CAAA,UAAA,EAAa,QAAQ,EAAE;AAC7C,IAAA,MAAM,mBAAmB,GACvB,WAAW,KAAK,OAAO,GAAG,wBAAwB,GAAG,SAAS,CAAC;IACjE,MAAM,aAAa,GAAG;UAClB,CAAA,EAAG,OAAO,CAAA,YAAA;UACV,SAAS;IAEb,QACE,6BAAK,SAAS,EAAE,iBAAiB,EAAA,kBAAA,EAAoB,MAAM,IAAI,SAAS,EAAA;AACrE,QAAA,CAAC,SAAS,IAAI,KAAK,GAAG,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAO,OAAO,EAAE,OAAO,IAAG,KAAK,CAAS,GAAG,IAAI;AACrE,QAAA,QAAQ,CAAC;YACR,aAAa;YACb,OAAO;SACR,CAAC;QACD,mBAAmB,KAClB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAG,EAAE,EAAE,aAAa,EAAE,SAAS,EAAC,uBAAuB,EAAA;YACrD,KAAA,CAAA,aAAA,CAAC,IAAI,IACH,SAAS,EAAC,oCAAoC,EAC9C,MAAM,EAAC,8BAA8B,EAAA,aAAA,EAAA,IAAA,EAAA,CAErC;AACD,YAAA,mBAAmB,CAClB,CACL,CACG;AAEV;;;;"}
|
|
@@ -4,6 +4,8 @@ export type SearchInputSize = "lg" | "md";
|
|
|
4
4
|
interface SearchInputBaseProps {
|
|
5
5
|
/** Helper text below the input. Styled as an error when `invalid`. */
|
|
6
6
|
description?: React.ReactNode;
|
|
7
|
+
/** If true, sets `data-flex-expand` so the field grows/shrinks to fill a `Flex` row. */
|
|
8
|
+
expand?: boolean;
|
|
7
9
|
/** Triggers invalid state (error border, error description, aria-invalid). */
|
|
8
10
|
invalid?: boolean;
|
|
9
11
|
/** Visual size — cascades to the icon, input, and clear button via Field's font-size custom property. Defaults to 'md'. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput.d.ts","sourceRoot":"","sources":["../../../src/components/search-input/SearchInput.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAOpB,OAAO,KAAK,EAAE,EAEZ,KAAK,mBAAmB,EAGzB,MAAM,OAAO,CAAA;AAEd,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,CAAA;AAEzC,UAAU,oBAAoB;IAC5B,sEAAsE;IACtE,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2HAA2H;IAC3H,IAAI,CAAC,EAAE,eAAe,CAAA;CACvB;AAED,UAAU,oBAAqB,SAAQ,oBAAoB;IACzD,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yBAAyB;IACzB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;CACvB;AAED,UAAU,6BAA8B,SAAQ,oBAAoB;IAClE,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,MAAM,gBAAgB,GACxB,6BAA6B,GAC7B,oBAAoB,CAAA;AAExB;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CACzC,GACC,gBAAgB,CAAA;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"SearchInput.d.ts","sourceRoot":"","sources":["../../../src/components/search-input/SearchInput.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAOpB,OAAO,KAAK,EAAE,EAEZ,KAAK,mBAAmB,EAGzB,MAAM,OAAO,CAAA;AAEd,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,CAAA;AAEzC,UAAU,oBAAoB;IAC5B,sEAAsE;IACtE,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,wFAAwF;IACxF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2HAA2H;IAC3H,IAAI,CAAC,EAAE,eAAe,CAAA;CACvB;AAED,UAAU,oBAAqB,SAAQ,oBAAoB;IACzD,iBAAiB,CAAC,EAAE,KAAK,CAAA;IACzB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yBAAyB;IACzB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;CACvB;AAED,UAAU,6BAA8B,SAAQ,oBAAoB;IAClE,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,MAAM,gBAAgB,GACxB,6BAA6B,GAC7B,oBAAoB,CAAA;AAExB;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CACzC,GACC,gBAAgB,CAAA;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,kGAmItB,CAAA"}
|
|
@@ -19,7 +19,7 @@ import React, { forwardRef, useRef, useState } from 'react';
|
|
|
19
19
|
* @component
|
|
20
20
|
* @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-searchinput--docs | Storybook Documentation}
|
|
21
21
|
*/
|
|
22
|
-
const SearchInput = forwardRef(function SearchInput({ "aria-labelledby": ariaLabelledBy, className, defaultValue, description, disabled, hideLabel, id, invalid, label, onChange, onKeyDown, readOnly, size = "md", value, ...restProps }, ref) {
|
|
22
|
+
const SearchInput = forwardRef(function SearchInput({ "aria-labelledby": ariaLabelledBy, className, defaultValue, description, disabled, expand, hideLabel, id, invalid, label, onChange, onKeyDown, readOnly, size = "md", value, ...restProps }, ref) {
|
|
23
23
|
const innerRef = useRef(null);
|
|
24
24
|
const setRefs = (node) => {
|
|
25
25
|
innerRef.current = node;
|
|
@@ -62,7 +62,7 @@ const SearchInput = forwardRef(function SearchInput({ "aria-labelledby": ariaLab
|
|
|
62
62
|
const fieldLabelProps = ariaLabelledBy
|
|
63
63
|
? { "aria-labelledby": ariaLabelledBy }
|
|
64
64
|
: { hideLabel, label };
|
|
65
|
-
return (React.createElement(Field, { ...fieldLabelProps, className: fieldClassName, description: description, id: inputId },
|
|
65
|
+
return (React.createElement(Field, { ...fieldLabelProps, className: fieldClassName, description: description, expand: expand, id: inputId },
|
|
66
66
|
React.createElement("div", { className: classNames("tds-search-input-control", {
|
|
67
67
|
"tds-search-input-control--has-value": hasValue,
|
|
68
68
|
}) },
|
|
@@ -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":[],"mappings":";;;;;;;;;;;;;
|
|
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 /** If true, sets `data-flex-expand` so the field grows/shrinks to fill a `Flex` row. */\n expand?: boolean\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 expand,\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 expand={expand}\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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"}
|
|
@@ -86,6 +86,8 @@ interface SelectBaseProps {
|
|
|
86
86
|
* and no description is provided.
|
|
87
87
|
*/
|
|
88
88
|
description?: React.ReactNode;
|
|
89
|
+
/** If true, sets `data-flex-expand` so the select grows/shrinks to fill a `Flex` row. */
|
|
90
|
+
expand?: boolean;
|
|
89
91
|
/**
|
|
90
92
|
* Whether the select is in an invalid state. Shows the default description
|
|
91
93
|
* if none is provided.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/select/Select.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/select/Select.tsx"],"names":[],"mappings":"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"}
|
|
@@ -26,7 +26,7 @@ function normalizeSelectValue(value) {
|
|
|
26
26
|
* @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}
|
|
27
27
|
*/
|
|
28
28
|
const Select = forwardRef(function Select(props, ref) {
|
|
29
|
-
const { "aria-label": userAriaLabel, "aria-labelledby": userAriaLabelledBy, className, complex, defaultValue, description, hideLabel, id, invalid, label, onChange, options, placeholder, required, size, value, ...restProps } = props;
|
|
29
|
+
const { "aria-label": userAriaLabel, "aria-labelledby": userAriaLabelledBy, className, complex, defaultValue, description, expand, hideLabel, id, invalid, label, onChange, options, placeholder, required, size, value, ...restProps } = props;
|
|
30
30
|
const triggerRef = useRef(null);
|
|
31
31
|
const stableId = useId();
|
|
32
32
|
const controlId = id || `tds-select-${stableId}`;
|
|
@@ -66,7 +66,7 @@ const Select = forwardRef(function Select(props, ref) {
|
|
|
66
66
|
};
|
|
67
67
|
const handleComplexLabelClick = () => triggerRef.current?.focus();
|
|
68
68
|
const SelectComponent = complex ? SelectPopover : SelectNative;
|
|
69
|
-
return (React.createElement("div", { className: computedClassName },
|
|
69
|
+
return (React.createElement("div", { className: computedClassName, "data-flex-expand": expand || undefined },
|
|
70
70
|
showLabel &&
|
|
71
71
|
(complex ? (
|
|
72
72
|
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- mirrors native label click-to-focus; keyboard users interact with the combobox directly
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.js","sources":["../../../src/components/select/Select.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport Icon from \"@utilities/Icon\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, type SelectHTMLAttributes, useRef } from \"react\"\n\nimport { SelectNative } from \"./SelectNative\"\nimport { SelectPopover } from \"./SelectPopover\"\n\n// ---------------------------------------------------------------------------\n// Shared types\n// ---------------------------------------------------------------------------\n\nexport type SelectSize = \"lg\" | \"md\"\n\n/**\n * String-labelled option variant. Valid in both native (`complex={false}`)\n * and complex (`complex={true}`) modes. The `label` doubles as the type-ahead\n * search target.\n */\nexport interface SelectOptionWithTextLabel {\n /** Arbitrary `data-*` attributes are forwarded to the rendered option. */\n [key: `data-${string}`]: boolean | number | string | undefined\n /** Whether this option is non-interactive. */\n disabled?: boolean\n divider?: never\n /** Displayed as the option content and used for type-ahead matching. */\n label: string\n textValue?: never\n /** Unique identifier for the option. */\n value: string\n}\n\n/**\n * Rich-content option variant. The popover (`complex={true}`) renders the\n * `label` node directly; the native `<select>` (`complex={false}`) falls back\n * to `textValue` for the visible text. Requires a plain-text `textValue` so\n * type-ahead matching, screen reader announcements, and the native fallback\n * all have something stable to use.\n */\nexport interface SelectOptionWithNodeLabel {\n /** Arbitrary `data-*` attributes are forwarded to the rendered option. */\n [key: `data-${string}`]: boolean | number | string | undefined\n /** Whether this option is non-interactive. */\n disabled?: boolean\n divider?: never\n /**\n * Option content. Rendered as JSX in complex mode; in native mode, the\n * visible text comes from `textValue` instead.\n */\n label: React.ReactNode\n /**\n * Plain-text fallback for type-ahead matching, screen reader\n * announcements, and the native `<select>`'s visible option text when\n * `label` is a React node.\n */\n textValue: string\n /** Unique identifier for the option. */\n value: string\n}\n\n/**\n * Visual-separator option variant. Renders a divider line between options\n * (or between groups of options). Carries no value of its own.\n */\nexport interface SelectOptionDivider {\n disabled?: never\n /** Renders a visual separator between options. */\n divider: true\n label?: never\n textValue?: never\n value?: never\n}\n\nexport type SelectOption =\n | SelectOptionDivider\n | SelectOptionWithNodeLabel\n | SelectOptionWithTextLabel\n\n/**\n * A group entry in `Select`'s `options` array. Renders a heading above its\n * `options` and nests them visually beneath it.\n */\nexport interface SelectOptionsGroup {\n /**\n * Whether all options in this group are non-interactive. Disables every\n * nested option regardless of its own `disabled` flag.\n */\n disabled?: boolean\n /** Visible heading displayed above the group's options. */\n label: string\n /** The selectable options nested under this group. */\n options: SelectOption[]\n}\n\nexport type SelectItem = SelectOption | SelectOptionsGroup\n\n// ---------------------------------------------------------------------------\n// Select component props\n// ---------------------------------------------------------------------------\n\ninterface SelectBaseProps {\n /**\n * When true, renders as a popover listbox instead of a native `<select>`.\n * Enables rich content in options (icons, descriptions).\n */\n complex?: boolean\n /**\n * Helper text displayed below the select. Styled as error text when\n * `invalid`. Defaults to `\"Please select an option\"` when `invalid` is true\n * and no description is provided.\n */\n description?: React.ReactNode\n /**\n * Whether the select is in an invalid state. Shows the default description\n * if none is provided.\n */\n invalid?: boolean\n /** A flat or mixed array of options and option groups. */\n options: SelectItem[]\n /** Placeholder text shown when no option is selected. Defaults to `\"Select an option\"`. */\n placeholder?: string\n /** The size of the select. */\n size?: SelectSize\n}\n\ninterface SelectWithVisibleLabel extends SelectBaseProps {\n /** If true, the label is visually hidden and set as aria-label. */\n hideLabel?: false\n /**\n * The label text for the select. Required unless `aria-label` or\n * `aria-labelledby` is provided.\n */\n label: string\n}\n\ninterface SelectWithHiddenLabel extends SelectBaseProps {\n /** If true, the label is visually hidden and set as aria-label. */\n hideLabel: true\n /** The label text for the select. Must be a string when hidden. */\n label: string\n}\n\ninterface SelectWithAriaLabel extends SelectBaseProps {\n /** Accessible label for the select. Use when no visible label exists. */\n \"aria-label\": string\n hideLabel?: never\n label?: never\n}\n\ninterface SelectWithAriaLabelledBy extends SelectBaseProps {\n /**\n * ID of an external label element. Use instead of `label` when a visible\n * label exists elsewhere on the page.\n */\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type SelectProps =\n | SelectWithAriaLabel\n | SelectWithAriaLabelledBy\n | SelectWithHiddenLabel\n | SelectWithVisibleLabel\n\ntype BaseSelectElementProps = Omit<\n SelectHTMLAttributes<HTMLSelectElement>,\n keyof SelectProps | \"multiple\" | \"size\"\n>\n\nexport type NativeSelectElementProps = BaseSelectElementProps &\n SelectProps & {\n complex?: false\n }\n\nexport type ComplexSelectElementProps = BaseSelectElementProps &\n SelectProps & {\n complex: true\n }\n\nexport type SelectElementProps =\n | NativeSelectElementProps\n | ComplexSelectElementProps\n\nfunction normalizeSelectValue(\n value:\n | NativeSelectElementProps[\"defaultValue\"]\n | NativeSelectElementProps[\"value\"]\n | ComplexSelectElementProps[\"defaultValue\"]\n | ComplexSelectElementProps[\"value\"]\n) {\n if (value === undefined || value === null) return undefined\n if (Array.isArray(value)) return value[0]\n return String(value)\n}\n\n// ---------------------------------------------------------------------------\n// Select (public)\n// ---------------------------------------------------------------------------\n\n/**\n * A select component for choosing a single value from a list of options.\n * By default renders a native `<select>`; set `complex` to render a popover\n * listbox that supports rich option content (icons, descriptions). Supports\n * option groups, dividers, invalid state, and `lg`/`md` sizing.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-select--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const Select = forwardRef<HTMLSelectElement, SelectElementProps>(\n function Select(props: SelectElementProps, ref) {\n const {\n \"aria-label\": userAriaLabel,\n \"aria-labelledby\": userAriaLabelledBy,\n className,\n complex,\n defaultValue,\n description,\n hideLabel,\n id,\n invalid,\n label,\n onChange,\n options,\n placeholder,\n required,\n size,\n value,\n ...restProps\n } = props\n\n const triggerRef = useRef<HTMLButtonElement>(null)\n const stableId = useId()\n const controlId = id || `tds-select-${stableId}`\n const labelId = `${controlId}-label`\n const resolvedDescription =\n description || (invalid ? \"Please select an option\" : undefined)\n const descriptionId = resolvedDescription\n ? `${controlId}-description`\n : undefined\n const computedClassName = classNames(\n \"tds-select\",\n {\n \"tds-select--invalid\": invalid,\n \"tds-select--lg\": size === \"lg\",\n \"tds-select--required\": required,\n },\n className\n )\n\n const normalizedDefaultValue = normalizeSelectValue(defaultValue)\n const normalizedValue = normalizeSelectValue(value)\n\n const computedDefaultValue =\n normalizedDefaultValue === undefined && normalizedValue === undefined\n ? \"\"\n : normalizedDefaultValue\n const effectivePlaceholder =\n normalizedDefaultValue !== undefined && normalizedDefaultValue !== \"\"\n ? null\n : placeholder || \"Select an option\"\n const showLabel = !!label && !hideLabel\n const computedAriaLabel = userAriaLabel ?? (hideLabel ? label : undefined)\n const computedAriaLabelledBy =\n userAriaLabelledBy ??\n (computedAriaLabel || !showLabel ? undefined : labelId)\n\n const sharedControlProps = {\n ...restProps,\n \"aria-describedby\": descriptionId,\n \"aria-label\": computedAriaLabel,\n \"aria-labelledby\": computedAriaLabelledBy,\n defaultValue: computedDefaultValue,\n invalid,\n options,\n placeholder: effectivePlaceholder,\n required,\n value: normalizedValue,\n }\n\n const handleComplexLabelClick = () => triggerRef.current?.focus()\n\n const SelectComponent = complex ? SelectPopover : SelectNative\n\n return (\n <div className={computedClassName}>\n {showLabel &&\n (complex ? (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- mirrors native label click-to-focus; keyboard users interact with the combobox directly\n <div\n className=\"tds-select-label\"\n id={labelId}\n onClick={handleComplexLabelClick}\n >\n {label}\n </div>\n ) : (\n <label htmlFor={controlId} id={labelId}>\n {label}\n </label>\n ))}\n <SelectComponent\n {...sharedControlProps}\n ref={ref}\n id={controlId}\n onChange={onChange}\n {...(complex && { triggerRef })}\n />\n {resolvedDescription && descriptionId && (\n <p className=\"tds-select-description\" id={descriptionId}>\n <Icon\n aria-hidden\n className=\"tds-select-description-invalid-icon\"\n symbol=\"general#exclamation-triangle\"\n />\n {resolvedDescription}\n </p>\n )}\n </div>\n )\n }\n)\n\nSelect.displayName = \"Select\"\n"],"names":[],"mappings":";;;;;;;AA0LA,SAAS,oBAAoB,CAC3B,KAIsC,EAAA;AAEtC,IAAA,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;AAAE,QAAA,OAAO,SAAS;AAC3D,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,KAAK,CAAC,CAAC,CAAC;AACzC,IAAA,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB;AAEA;AACA;AACA;AAEA;;;;;;;;;AASG;AACI,MAAM,MAAM,GAAG,UAAU,CAC9B,SAAS,MAAM,CAAC,KAAyB,EAAE,GAAG,EAAA;AAC5C,IAAA,MAAM,EACJ,YAAY,EAAE,aAAa,EAC3B,iBAAiB,EAAE,kBAAkB,EACrC,SAAS,EACT,OAAO,EACP,YAAY,EACZ,WAAW,EACX,SAAS,EACT,EAAE,EACF,OAAO,EACP,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAW,EACX,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,GAAG,SAAS,EACb,GAAG,KAAK;AAET,IAAA,MAAM,UAAU,GAAG,MAAM,CAAoB,IAAI,CAAC;AAClD,IAAA,MAAM,QAAQ,GAAG,KAAK,EAAE;AACxB,IAAA,MAAM,SAAS,GAAG,EAAE,IAAI,CAAA,WAAA,EAAc,QAAQ,EAAE;AAChD,IAAA,MAAM,OAAO,GAAG,CAAA,EAAG,SAAS,QAAQ;AACpC,IAAA,MAAM,mBAAmB,GACvB,WAAW,KAAK,OAAO,GAAG,yBAAyB,GAAG,SAAS,CAAC;IAClE,MAAM,aAAa,GAAG;UAClB,CAAA,EAAG,SAAS,CAAA,YAAA;UACZ,SAAS;AACb,IAAA,MAAM,iBAAiB,GAAG,UAAU,CAClC,YAAY,EACZ;AACE,QAAA,qBAAqB,EAAE,OAAO;QAC9B,gBAAgB,EAAE,IAAI,KAAK,IAAI;AAC/B,QAAA,sBAAsB,EAAE,QAAQ;KACjC,EACD,SAAS,CACV;AAED,IAAA,MAAM,sBAAsB,GAAG,oBAAoB,CAAC,YAAY,CAAC;AACjE,IAAA,MAAM,eAAe,GAAG,oBAAoB,CAAC,KAAK,CAAC;IAEnD,MAAM,oBAAoB,GACxB,sBAAsB,KAAK,SAAS,IAAI,eAAe,KAAK;AAC1D,UAAE;UACA,sBAAsB;IAC5B,MAAM,oBAAoB,GACxB,sBAAsB,KAAK,SAAS,IAAI,sBAAsB,KAAK;AACjE,UAAE;AACF,UAAE,WAAW,IAAI,kBAAkB;IACvC,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS;AACvC,IAAA,MAAM,iBAAiB,GAAG,aAAa,KAAK,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;IAC1E,MAAM,sBAAsB,GAC1B,kBAAkB;AAClB,SAAC,iBAAiB,IAAI,CAAC,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEzD,IAAA,MAAM,kBAAkB,GAAG;AACzB,QAAA,GAAG,SAAS;AACZ,QAAA,kBAAkB,EAAE,aAAa;AACjC,QAAA,YAAY,EAAE,iBAAiB;AAC/B,QAAA,iBAAiB,EAAE,sBAAsB;AACzC,QAAA,YAAY,EAAE,oBAAoB;QAClC,OAAO;QACP,OAAO;AACP,QAAA,WAAW,EAAE,oBAAoB;QACjC,QAAQ;AACR,QAAA,KAAK,EAAE,eAAe;KACvB;IAED,MAAM,uBAAuB,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE;IAEjE,MAAM,eAAe,GAAG,OAAO,GAAG,aAAa,GAAG,YAAY;AAE9D,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,iBAAiB,EAAA;QAC9B,SAAS;aACP,OAAO;;AAEN,YAAA,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAC,kBAAkB,EAC5B,EAAE,EAAE,OAAO,EACX,OAAO,EAAE,uBAAuB,EAAA,EAE/B,KAAK,CACF,KAEN,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAO,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAA,EACnC,KAAK,CACA,CACT,CAAC;QACJ,KAAA,CAAA,aAAA,CAAC,eAAe,OACV,kBAAkB,EACtB,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,SAAS,EACb,QAAQ,EAAE,QAAQ,EAAA,IACb,OAAO,IAAI,EAAE,UAAU,EAAE,CAAC,EAAA,CAC/B;QACD,mBAAmB,IAAI,aAAa,KACnC,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,wBAAwB,EAAC,EAAE,EAAE,aAAa,EAAA;YACrD,KAAA,CAAA,aAAA,CAAC,IAAI,yBAEH,SAAS,EAAC,qCAAqC,EAC/C,MAAM,EAAC,8BAA8B,EAAA,CACrC;AACD,YAAA,mBAAmB,CAClB,CACL,CACG;AAEV,CAAC;AAGH,MAAM,CAAC,WAAW,GAAG,QAAQ;;;;"}
|
|
1
|
+
{"version":3,"file":"Select.js","sources":["../../../src/components/select/Select.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport Icon from \"@utilities/Icon\"\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, type SelectHTMLAttributes, useRef } from \"react\"\n\nimport { SelectNative } from \"./SelectNative\"\nimport { SelectPopover } from \"./SelectPopover\"\n\n// ---------------------------------------------------------------------------\n// Shared types\n// ---------------------------------------------------------------------------\n\nexport type SelectSize = \"lg\" | \"md\"\n\n/**\n * String-labelled option variant. Valid in both native (`complex={false}`)\n * and complex (`complex={true}`) modes. The `label` doubles as the type-ahead\n * search target.\n */\nexport interface SelectOptionWithTextLabel {\n /** Arbitrary `data-*` attributes are forwarded to the rendered option. */\n [key: `data-${string}`]: boolean | number | string | undefined\n /** Whether this option is non-interactive. */\n disabled?: boolean\n divider?: never\n /** Displayed as the option content and used for type-ahead matching. */\n label: string\n textValue?: never\n /** Unique identifier for the option. */\n value: string\n}\n\n/**\n * Rich-content option variant. The popover (`complex={true}`) renders the\n * `label` node directly; the native `<select>` (`complex={false}`) falls back\n * to `textValue` for the visible text. Requires a plain-text `textValue` so\n * type-ahead matching, screen reader announcements, and the native fallback\n * all have something stable to use.\n */\nexport interface SelectOptionWithNodeLabel {\n /** Arbitrary `data-*` attributes are forwarded to the rendered option. */\n [key: `data-${string}`]: boolean | number | string | undefined\n /** Whether this option is non-interactive. */\n disabled?: boolean\n divider?: never\n /**\n * Option content. Rendered as JSX in complex mode; in native mode, the\n * visible text comes from `textValue` instead.\n */\n label: React.ReactNode\n /**\n * Plain-text fallback for type-ahead matching, screen reader\n * announcements, and the native `<select>`'s visible option text when\n * `label` is a React node.\n */\n textValue: string\n /** Unique identifier for the option. */\n value: string\n}\n\n/**\n * Visual-separator option variant. Renders a divider line between options\n * (or between groups of options). Carries no value of its own.\n */\nexport interface SelectOptionDivider {\n disabled?: never\n /** Renders a visual separator between options. */\n divider: true\n label?: never\n textValue?: never\n value?: never\n}\n\nexport type SelectOption =\n | SelectOptionDivider\n | SelectOptionWithNodeLabel\n | SelectOptionWithTextLabel\n\n/**\n * A group entry in `Select`'s `options` array. Renders a heading above its\n * `options` and nests them visually beneath it.\n */\nexport interface SelectOptionsGroup {\n /**\n * Whether all options in this group are non-interactive. Disables every\n * nested option regardless of its own `disabled` flag.\n */\n disabled?: boolean\n /** Visible heading displayed above the group's options. */\n label: string\n /** The selectable options nested under this group. */\n options: SelectOption[]\n}\n\nexport type SelectItem = SelectOption | SelectOptionsGroup\n\n// ---------------------------------------------------------------------------\n// Select component props\n// ---------------------------------------------------------------------------\n\ninterface SelectBaseProps {\n /**\n * When true, renders as a popover listbox instead of a native `<select>`.\n * Enables rich content in options (icons, descriptions).\n */\n complex?: boolean\n /**\n * Helper text displayed below the select. Styled as error text when\n * `invalid`. Defaults to `\"Please select an option\"` when `invalid` is true\n * and no description is provided.\n */\n description?: React.ReactNode\n /** If true, sets `data-flex-expand` so the select grows/shrinks to fill a `Flex` row. */\n expand?: boolean\n /**\n * Whether the select is in an invalid state. Shows the default description\n * if none is provided.\n */\n invalid?: boolean\n /** A flat or mixed array of options and option groups. */\n options: SelectItem[]\n /** Placeholder text shown when no option is selected. Defaults to `\"Select an option\"`. */\n placeholder?: string\n /** The size of the select. */\n size?: SelectSize\n}\n\ninterface SelectWithVisibleLabel extends SelectBaseProps {\n /** If true, the label is visually hidden and set as aria-label. */\n hideLabel?: false\n /**\n * The label text for the select. Required unless `aria-label` or\n * `aria-labelledby` is provided.\n */\n label: string\n}\n\ninterface SelectWithHiddenLabel extends SelectBaseProps {\n /** If true, the label is visually hidden and set as aria-label. */\n hideLabel: true\n /** The label text for the select. Must be a string when hidden. */\n label: string\n}\n\ninterface SelectWithAriaLabel extends SelectBaseProps {\n /** Accessible label for the select. Use when no visible label exists. */\n \"aria-label\": string\n hideLabel?: never\n label?: never\n}\n\ninterface SelectWithAriaLabelledBy extends SelectBaseProps {\n /**\n * ID of an external label element. Use instead of `label` when a visible\n * label exists elsewhere on the page.\n */\n \"aria-labelledby\": string\n hideLabel?: never\n label?: never\n}\n\nexport type SelectProps =\n | SelectWithAriaLabel\n | SelectWithAriaLabelledBy\n | SelectWithHiddenLabel\n | SelectWithVisibleLabel\n\ntype BaseSelectElementProps = Omit<\n SelectHTMLAttributes<HTMLSelectElement>,\n keyof SelectProps | \"multiple\" | \"size\"\n>\n\nexport type NativeSelectElementProps = BaseSelectElementProps &\n SelectProps & {\n complex?: false\n }\n\nexport type ComplexSelectElementProps = BaseSelectElementProps &\n SelectProps & {\n complex: true\n }\n\nexport type SelectElementProps =\n | NativeSelectElementProps\n | ComplexSelectElementProps\n\nfunction normalizeSelectValue(\n value:\n | NativeSelectElementProps[\"defaultValue\"]\n | NativeSelectElementProps[\"value\"]\n | ComplexSelectElementProps[\"defaultValue\"]\n | ComplexSelectElementProps[\"value\"]\n) {\n if (value === undefined || value === null) return undefined\n if (Array.isArray(value)) return value[0]\n return String(value)\n}\n\n// ---------------------------------------------------------------------------\n// Select (public)\n// ---------------------------------------------------------------------------\n\n/**\n * A select component for choosing a single value from a list of options.\n * By default renders a native `<select>`; set `complex` to render a popover\n * listbox that supports rich option content (icons, descriptions). Supports\n * option groups, dividers, invalid state, and `lg`/`md` sizing.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/components-select--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const Select = forwardRef<HTMLSelectElement, SelectElementProps>(\n function Select(props: SelectElementProps, ref) {\n const {\n \"aria-label\": userAriaLabel,\n \"aria-labelledby\": userAriaLabelledBy,\n className,\n complex,\n defaultValue,\n description,\n expand,\n hideLabel,\n id,\n invalid,\n label,\n onChange,\n options,\n placeholder,\n required,\n size,\n value,\n ...restProps\n } = props\n\n const triggerRef = useRef<HTMLButtonElement>(null)\n const stableId = useId()\n const controlId = id || `tds-select-${stableId}`\n const labelId = `${controlId}-label`\n const resolvedDescription =\n description || (invalid ? \"Please select an option\" : undefined)\n const descriptionId = resolvedDescription\n ? `${controlId}-description`\n : undefined\n const computedClassName = classNames(\n \"tds-select\",\n {\n \"tds-select--invalid\": invalid,\n \"tds-select--lg\": size === \"lg\",\n \"tds-select--required\": required,\n },\n className\n )\n\n const normalizedDefaultValue = normalizeSelectValue(defaultValue)\n const normalizedValue = normalizeSelectValue(value)\n\n const computedDefaultValue =\n normalizedDefaultValue === undefined && normalizedValue === undefined\n ? \"\"\n : normalizedDefaultValue\n const effectivePlaceholder =\n normalizedDefaultValue !== undefined && normalizedDefaultValue !== \"\"\n ? null\n : placeholder || \"Select an option\"\n const showLabel = !!label && !hideLabel\n const computedAriaLabel = userAriaLabel ?? (hideLabel ? label : undefined)\n const computedAriaLabelledBy =\n userAriaLabelledBy ??\n (computedAriaLabel || !showLabel ? undefined : labelId)\n\n const sharedControlProps = {\n ...restProps,\n \"aria-describedby\": descriptionId,\n \"aria-label\": computedAriaLabel,\n \"aria-labelledby\": computedAriaLabelledBy,\n defaultValue: computedDefaultValue,\n invalid,\n options,\n placeholder: effectivePlaceholder,\n required,\n value: normalizedValue,\n }\n\n const handleComplexLabelClick = () => triggerRef.current?.focus()\n\n const SelectComponent = complex ? SelectPopover : SelectNative\n\n return (\n <div className={computedClassName} data-flex-expand={expand || undefined}>\n {showLabel &&\n (complex ? (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -- mirrors native label click-to-focus; keyboard users interact with the combobox directly\n <div\n className=\"tds-select-label\"\n id={labelId}\n onClick={handleComplexLabelClick}\n >\n {label}\n </div>\n ) : (\n <label htmlFor={controlId} id={labelId}>\n {label}\n </label>\n ))}\n <SelectComponent\n {...sharedControlProps}\n ref={ref}\n id={controlId}\n onChange={onChange}\n {...(complex && { triggerRef })}\n />\n {resolvedDescription && descriptionId && (\n <p className=\"tds-select-description\" id={descriptionId}>\n <Icon\n aria-hidden\n className=\"tds-select-description-invalid-icon\"\n symbol=\"general#exclamation-triangle\"\n />\n {resolvedDescription}\n </p>\n )}\n </div>\n )\n }\n)\n\nSelect.displayName = \"Select\"\n"],"names":[],"mappings":"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"}
|
package/dist/index.css
CHANGED
|
@@ -2894,7 +2894,7 @@ tds-sidenav-section:not(.hydrated) > [slot="ssr"]{
|
|
|
2894
2894
|
:is(.tds-button-group > .tds-btn):is(.tds-btn--interaction,.tds-btn--neutral,.tds-btn--staff-only):not(:last-child)::after{
|
|
2895
2895
|
inset-inline-end:calc(var(--tds-btn-border-width) * -1);
|
|
2896
2896
|
}
|
|
2897
|
-
:is(.tds-button-group > .tds-btn):hover{
|
|
2897
|
+
:is(.tds-button-group > .tds-btn):hover,:is(.tds-button-group > .tds-btn):focus{
|
|
2898
2898
|
--tds-button-group-item-z-index:2;
|
|
2899
2899
|
}
|
|
2900
2900
|
:is(.tds-button-group > .tds-btn):focus-visible{
|