@planningcenter/tapestry 4.0.0-rc.6 → 4.0.0-rc.8
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/search-input/SearchInput.d.ts +39 -0
- package/dist/components/search-input/SearchInput.d.ts.map +1 -0
- package/dist/components/search-input/SearchInput.js +74 -0
- package/dist/components/search-input/SearchInput.js.map +1 -0
- package/dist/components/search-input/index.d.ts +4 -0
- package/dist/components/search-input/index.d.ts.map +1 -0
- package/dist/index.css +13 -268
- package/dist/index.css.map +1 -1
- package/dist/reactRender.css +1394 -1512
- package/dist/reactRender.css.map +1 -1
- package/dist/reactRenderLegacy.css +1394 -1512
- package/dist/reactRenderLegacy.css.map +1 -1
- package/dist/unstable.css +3201 -3319
- package/dist/unstable.css.map +1 -1
- package/dist/unstable.d.ts +1 -0
- package/dist/unstable.d.ts.map +1 -1
- package/dist/unstable.js +1 -0
- package/dist/unstable.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "./index.css";
|
|
2
|
+
import React, { type InputHTMLAttributes } from "react";
|
|
3
|
+
export type SearchInputSize = "lg" | "md";
|
|
4
|
+
interface SearchInputBaseProps {
|
|
5
|
+
/** Helper text below the input. Styled as an error when `invalid`. */
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
/** Triggers invalid state (error border, error description, aria-invalid). */
|
|
8
|
+
invalid?: boolean;
|
|
9
|
+
/** Visual size — cascades to the icon, input, and clear button via Field's font-size custom property. Defaults to 'md'. */
|
|
10
|
+
size?: SearchInputSize;
|
|
11
|
+
}
|
|
12
|
+
interface SearchInputWithLabel extends SearchInputBaseProps {
|
|
13
|
+
"aria-labelledby"?: never;
|
|
14
|
+
/** If true, the label is visually hidden but remains in the DOM/AT tree. */
|
|
15
|
+
hideLabel?: boolean;
|
|
16
|
+
/** The visible label. */
|
|
17
|
+
label: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
interface SearchInputWithAriaLabelledBy extends SearchInputBaseProps {
|
|
20
|
+
"aria-labelledby": string;
|
|
21
|
+
hideLabel?: never;
|
|
22
|
+
label?: never;
|
|
23
|
+
}
|
|
24
|
+
export type SearchInputProps = SearchInputWithAriaLabelledBy | SearchInputWithLabel;
|
|
25
|
+
/**
|
|
26
|
+
* Combines standard HTML input attributes with SearchInput's own props.
|
|
27
|
+
* `type` is fixed to "search" and not exposed; `size` is redefined above.
|
|
28
|
+
*/
|
|
29
|
+
export type SearchInputElementProps = Omit<InputHTMLAttributes<HTMLInputElement>, keyof SearchInputProps | "size" | "type"> & SearchInputProps;
|
|
30
|
+
/**
|
|
31
|
+
* A search-specific input with a leading search icon and a trailing clear
|
|
32
|
+
* ("x") button, built on `type="search"`. Composes `Field` directly for
|
|
33
|
+
* label, description, and state layout.
|
|
34
|
+
*
|
|
35
|
+
* @component
|
|
36
|
+
*/
|
|
37
|
+
export declare const SearchInput: React.ForwardRefExoticComponent<SearchInputElementProps & React.RefAttributes<HTMLInputElement>>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=SearchInput.d.ts.map
|
|
@@ -0,0 +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;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,kGAiItB,CAAA"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import '../button/Button.js';
|
|
2
|
+
import '../button/DropdownButton.js';
|
|
3
|
+
import '../button/DropdownIconButton.js';
|
|
4
|
+
import { IconButton } from '../button/IconButton.js';
|
|
5
|
+
import '../button/LoadingButton.js';
|
|
6
|
+
import '../button/PageHeaderActionsDropdownButton.js';
|
|
7
|
+
import { Field } from '../field/Field.js';
|
|
8
|
+
import Icon from '../../utilities/Icon.js';
|
|
9
|
+
import { useId } from '../../utilities/useId.js';
|
|
10
|
+
import classNames from 'classnames';
|
|
11
|
+
import React__default, { forwardRef, useRef, useState } from 'react';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A search-specific input with a leading search icon and a trailing clear
|
|
15
|
+
* ("x") button, built on `type="search"`. Composes `Field` directly for
|
|
16
|
+
* label, description, and state layout.
|
|
17
|
+
*
|
|
18
|
+
* @component
|
|
19
|
+
*/
|
|
20
|
+
const SearchInput = forwardRef(function SearchInput({ "aria-labelledby": ariaLabelledBy, className, defaultValue, description, disabled, hideLabel, id, invalid, label, onChange, onKeyDown, readOnly, size = "md", value, ...restProps }, ref) {
|
|
21
|
+
const innerRef = useRef(null);
|
|
22
|
+
const setRefs = (node) => {
|
|
23
|
+
innerRef.current = node;
|
|
24
|
+
if (typeof ref === "function")
|
|
25
|
+
ref(node);
|
|
26
|
+
else if (ref) {
|
|
27
|
+
ref.current = node;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const stableId = useId();
|
|
31
|
+
const inputId = id || `tds-search-input-${stableId}`;
|
|
32
|
+
const descriptionId = description ? `${inputId}-description` : undefined;
|
|
33
|
+
const [uncontrolledHasValue, setUncontrolledHasValue] = useState(() => String(defaultValue ?? "").length > 0);
|
|
34
|
+
const hasValue = value !== undefined ? String(value).length > 0 : uncontrolledHasValue;
|
|
35
|
+
const handleChange = (event) => {
|
|
36
|
+
if (value === undefined) {
|
|
37
|
+
setUncontrolledHasValue(event.target.value.length > 0);
|
|
38
|
+
}
|
|
39
|
+
onChange?.(event);
|
|
40
|
+
};
|
|
41
|
+
const handleClear = () => {
|
|
42
|
+
const input = innerRef.current;
|
|
43
|
+
if (!input)
|
|
44
|
+
return;
|
|
45
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(input.constructor.prototype, "value")?.set;
|
|
46
|
+
nativeSetter?.call(input, "");
|
|
47
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
48
|
+
input.focus();
|
|
49
|
+
if (value === undefined) {
|
|
50
|
+
setUncontrolledHasValue(false);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const handleKeyDown = (event) => {
|
|
54
|
+
if (event.key === "Escape" && hasValue) {
|
|
55
|
+
event.stopPropagation();
|
|
56
|
+
}
|
|
57
|
+
onKeyDown?.(event);
|
|
58
|
+
};
|
|
59
|
+
const fieldClassName = classNames({ "tds-field--lg": size === "lg" }, className);
|
|
60
|
+
const fieldLabelProps = ariaLabelledBy
|
|
61
|
+
? { "aria-labelledby": ariaLabelledBy }
|
|
62
|
+
: { hideLabel, label };
|
|
63
|
+
return (React__default.createElement(Field, { ...fieldLabelProps, className: fieldClassName, description: description, id: inputId },
|
|
64
|
+
React__default.createElement("div", { className: classNames("tds-search-input-control", {
|
|
65
|
+
"tds-search-input-control--has-value": hasValue,
|
|
66
|
+
}) },
|
|
67
|
+
React__default.createElement(Icon, { "aria-hidden": true, className: "tds-search-input-icon", symbol: "general#search" }),
|
|
68
|
+
React__default.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 }),
|
|
69
|
+
React__default.createElement(IconButton, { "aria-label": "Clear", icon: React__default.createElement(Icon, { "aria-hidden": true, className: "tds-search-input-clear-icon", symbol: "general#x" }), kind: "neutral-inline", onClick: handleClear, tabIndex: -1 }))));
|
|
70
|
+
});
|
|
71
|
+
SearchInput.displayName = "SearchInput";
|
|
72
|
+
|
|
73
|
+
export { SearchInput };
|
|
74
|
+
//# sourceMappingURL=SearchInput.js.map
|
|
@@ -0,0 +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 */\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":["React"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/search-input/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,YAAY,EACV,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,GAChB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
|