@rcarls/rc-search-bar 0.1.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/demo.css ADDED
@@ -0,0 +1,85 @@
1
+ *, *::before, *::after {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ :root {
6
+ color-scheme: light dark;
7
+ --rc-accent: Highlight; /* Chrome doesn't support AccentColor on the open web */
8
+ }
9
+
10
+ @supports (color: AccentColor) {
11
+ :root {
12
+ --rc-accent: AccentColor;
13
+ }
14
+ }
15
+
16
+ [data-theme="light"] { color-scheme: light; }
17
+ [data-theme="dark"] { color-scheme: dark; }
18
+
19
+ [data-theme="solarized-light"] {
20
+ color-scheme: light;
21
+ --rc-surface: #fdf6e3;
22
+ --rc-text: #657b83;
23
+ --rc-border: 1px solid #93a1a1;
24
+ --rc-shadow: 0 2px 8px rgba(0, 0, 0, .12);
25
+ }
26
+
27
+ [data-theme="solarized-dark"] {
28
+ color-scheme: dark;
29
+ --rc-surface: #002b36;
30
+ --rc-text: #839496;
31
+ --rc-border: 1px solid #586e75;
32
+ --rc-shadow: 0 2px 8px rgba(0, 0, 0, .3);
33
+ }
34
+
35
+ body {
36
+ font-family: system-ui, sans-serif;
37
+ margin: 0;
38
+ }
39
+
40
+ .demo-page {
41
+ max-width: 60rem;
42
+ margin: 0 auto;
43
+ padding: 2rem 1.5rem;
44
+ }
45
+
46
+ .demo-controls {
47
+ display: flex;
48
+ align-items: center;
49
+ gap: 1rem;
50
+ margin-bottom: 2rem;
51
+ padding-bottom: 1rem;
52
+ border-bottom: 1px solid ButtonBorder;
53
+ }
54
+
55
+ .demo-controls .demo-title {
56
+ flex: 1;
57
+ }
58
+
59
+ .demo-controls h1 {
60
+ margin: 0 0 0.15rem;
61
+ font-size: 1.5rem;
62
+ }
63
+
64
+ .demo-controls a {
65
+ font-size: 0.8rem;
66
+ }
67
+
68
+ .demo-section {
69
+ margin-bottom: 2rem;
70
+ }
71
+
72
+ .demo-section h2 {
73
+ margin: 0 0 0.5rem;
74
+ }
75
+
76
+ .theme-picker {
77
+ padding: 0.35em 0.75em;
78
+ font-family: inherit;
79
+ font-size: 0.8rem;
80
+ cursor: pointer;
81
+ border: 1px solid ButtonBorder;
82
+ border-radius: 4px;
83
+ background: Canvas;
84
+ color: CanvasText;
85
+ }
package/dist/demo.js ADDED
@@ -0,0 +1,40 @@
1
+ const THEMES = ['', 'light', 'dark', 'solarized-light', 'solarized-dark'];
2
+ const LABELS = ['Auto', 'Light', 'Dark', 'Solarized ☀', 'Solarized ☾'];
3
+
4
+ const stored = localStorage.getItem('rc-demo-theme') ?? '';
5
+ applyTheme(stored);
6
+
7
+ function applyTheme(theme) {
8
+ if (theme) {
9
+ document.documentElement.dataset.theme = theme;
10
+ } else {
11
+ delete document.documentElement.dataset.theme;
12
+ }
13
+ }
14
+
15
+ function currentIndex() {
16
+ const current = document.documentElement.dataset.theme ?? '';
17
+ const idx = THEMES.indexOf(current);
18
+ return idx === -1 ? 0 : idx;
19
+ }
20
+
21
+ function updateButtons() {
22
+ const label = LABELS[currentIndex()];
23
+ document.querySelectorAll('.theme-picker').forEach((btn) => {
24
+ btn.textContent = label;
25
+ });
26
+ }
27
+
28
+ window.cycleTheme = function () {
29
+ const next = THEMES[(currentIndex() + 1) % THEMES.length];
30
+ applyTheme(next);
31
+ localStorage.setItem('rc-demo-theme', next);
32
+ updateButtons();
33
+ };
34
+
35
+ document.addEventListener('DOMContentLoaded', () => {
36
+ updateButtons();
37
+ document.querySelectorAll('.theme-picker').forEach((btn) => {
38
+ btn.addEventListener('click', window.cycleTheme);
39
+ });
40
+ });
@@ -0,0 +1,313 @@
1
+ import { css as f, LitElement as b, html as v } from "lit";
2
+ import { property as r, state as o } from "lit/decorators.js";
3
+ import { classMap as h } from "lit/directives/class-map.js";
4
+ const g = f`
5
+ :host {
6
+ display: inline-flex;
7
+ color-scheme: inherit;
8
+ }
9
+
10
+ [hidden] {
11
+ display: none !important;
12
+ }
13
+
14
+ #root {
15
+ display: flex;
16
+ flex: 1 1 auto;
17
+ align-items: center;
18
+ min-inline-size: 0;
19
+ gap: var(--rc-search-bar-gap, 0.25em);
20
+ block-size: var(--rc-search-bar-height, 48px);
21
+ padding-inline: var(--rc-search-bar-padding-inline, 0.5em);
22
+ background: var(--rc-search-bar-bg, Field);
23
+ color: var(--rc-search-bar-color, FieldText);
24
+ border-radius: var(--rc-search-bar-radius, var(--rc-control-radius, 0));
25
+ }
26
+
27
+ :host([data-focus-visible]) #root {
28
+ outline: var(--rc-focus-ring, auto);
29
+ outline-offset: var(--rc-focus-ring-offset, 0);
30
+ }
31
+
32
+ /* No slotted search input: render no chrome at all. */
33
+ #root.empty {
34
+ block-size: auto;
35
+ padding: 0;
36
+ background: none;
37
+ border-radius: 0;
38
+ }
39
+
40
+ #leading {
41
+ display: flex;
42
+ flex: none;
43
+ align-items: center;
44
+ color: var(--rc-search-bar-icon-color, GrayText);
45
+ }
46
+
47
+ #leading.empty {
48
+ display: none;
49
+ }
50
+
51
+ ::slotted(input[type='search']) {
52
+ flex: 1 1 auto;
53
+ min-inline-size: 0;
54
+ border: none;
55
+ background: transparent;
56
+ color: var(--rc-search-bar-input-color, inherit);
57
+ font-family: var(--rc-search-bar-input-font-family, inherit);
58
+ font-size: var(--rc-search-bar-input-font-size, inherit);
59
+ outline: none;
60
+ }
61
+
62
+ #trailing {
63
+ display: flex;
64
+ flex: none;
65
+ align-items: center;
66
+ }
67
+
68
+ #trailing.empty {
69
+ display: none;
70
+ }
71
+
72
+ #clear {
73
+ display: inline-grid;
74
+ flex: none;
75
+ place-items: center;
76
+ min-inline-size: 24px;
77
+ min-block-size: 24px;
78
+ padding: 0;
79
+ border: none;
80
+ border-radius: 50%;
81
+ background: none;
82
+ color: var(--rc-search-bar-clear-color, GrayText);
83
+ font: inherit;
84
+ cursor: pointer;
85
+ }
86
+
87
+ #clear:focus-visible {
88
+ outline: var(--rc-focus-ring, auto);
89
+ outline-offset: var(--rc-focus-ring-offset, 0);
90
+ }
91
+ `;
92
+ var m = Object.defineProperty, y = Object.getOwnPropertyDescriptor, a = (c, e, i, t) => {
93
+ for (var n = t > 1 ? void 0 : t ? y(e, i) : e, l = c.length - 1, u; l >= 0; l--)
94
+ (u = c[l]) && (n = (t ? u(e, i, n) : u(n)) || n);
95
+ return t && n && m(e, i, n), n;
96
+ };
97
+ const _ = new CSSStyleSheet();
98
+ _.replaceSync(
99
+ `rc-search-bar:not([allow-native-clear]) input[type="search"]::-webkit-search-cancel-button
100
+ { -webkit-appearance: none; display: none; }`
101
+ );
102
+ let p = !1;
103
+ function I() {
104
+ p || (document.adoptedStyleSheets = [...document.adoptedStyleSheets, _], p = !0);
105
+ }
106
+ const d = class d extends b {
107
+ constructor() {
108
+ super(...arguments), this.debounce = 200, this.clearLabel = "Clear search", this.allowNativeClear = !1, this.showClearOnFocus = !1, this._value = void 0, this._defaultValue = void 0, this._valueSetByHost = !1, this._valueInitialized = !1, this._authorPlaceholder = !1, this._inputRef = null, this._debounceTimer = void 0, this._hasInput = !1, this._hasValue = !1, this._hasLeading = !1, this._hasTrailing = !1, this._inputDisabled = !1, this._disabledHost = void 0, this._focused = !1, this._lastInteractionWasPointer = !1, this._onPointerDown = () => {
109
+ this._lastInteractionWasPointer = !0;
110
+ }, this._onFocusIn = () => {
111
+ this._lastInteractionWasPointer || this.toggleAttribute("data-focus-visible", !0), this._lastInteractionWasPointer = !1;
112
+ }, this._onFocusOut = () => {
113
+ this.toggleAttribute("data-focus-visible", !1);
114
+ }, this._onInputFocus = () => {
115
+ this._focused = !0;
116
+ }, this._onInputBlur = () => {
117
+ this._focused = !1;
118
+ }, this._disabledObserver = new MutationObserver(() => {
119
+ const e = this._input();
120
+ e && (this._inputDisabled = e.disabled);
121
+ }), this._onNativeInput = (e) => {
122
+ const i = e.currentTarget;
123
+ this._valueInitialized = !0, this._hasValue = i.value.length > 0, this._scheduleInputEvent(i.value);
124
+ };
125
+ }
126
+ get disabled() {
127
+ return this._disabledHost ?? this._inputDisabled;
128
+ }
129
+ set disabled(e) {
130
+ const i = this.disabled;
131
+ this._disabledHost = e;
132
+ const t = this._input();
133
+ t && (t.disabled = e), this.requestUpdate("disabled", i);
134
+ }
135
+ get value() {
136
+ return this._input()?.value ?? this._value ?? this._defaultValue ?? "";
137
+ }
138
+ set value(e) {
139
+ const i = this.value;
140
+ this._value = e, this._valueSetByHost = !0, this._valueInitialized = !0;
141
+ const t = this._input();
142
+ t && (t.value = e), this._hasValue = e.length > 0, this.requestUpdate("value", i);
143
+ }
144
+ get defaultValue() {
145
+ return this._defaultValue;
146
+ }
147
+ set defaultValue(e) {
148
+ const i = this._defaultValue;
149
+ this._defaultValue = e;
150
+ const t = this._input();
151
+ t && e !== void 0 && !this._valueInitialized && (t.value = e, this._hasValue = e.length > 0), this.requestUpdate("defaultValue", i);
152
+ }
153
+ connectedCallback() {
154
+ super.connectedCallback(), I(), this.addEventListener("pointerdown", this._onPointerDown, { capture: !0 }), this.addEventListener("focusin", this._onFocusIn), this.addEventListener("focusout", this._onFocusOut);
155
+ const e = this._input();
156
+ e && this._bindInput(e);
157
+ }
158
+ disconnectedCallback() {
159
+ this.removeEventListener("pointerdown", this._onPointerDown, { capture: !0 }), this.removeEventListener("focusin", this._onFocusIn), this.removeEventListener("focusout", this._onFocusOut), super.disconnectedCallback(), this._focused = !1, this._cancelPendingInput();
160
+ const e = this._input();
161
+ e?.removeEventListener("input", this._onNativeInput), e?.removeEventListener("focus", this._onInputFocus), e?.removeEventListener("blur", this._onInputBlur), this._disabledObserver.disconnect();
162
+ }
163
+ updated(e) {
164
+ if (e.has("placeholder")) {
165
+ const i = this._input();
166
+ i && this._applyPlaceholder(i);
167
+ }
168
+ }
169
+ _input() {
170
+ return this._inputRef?.deref() ?? null;
171
+ }
172
+ _handleSlotChange(e) {
173
+ const t = e.target.assignedElements({ flatten: !0 }).find(
174
+ (l) => l instanceof HTMLInputElement && l.type === "search"
175
+ ) ?? null, n = this._input();
176
+ if (n && n !== t && (n.removeEventListener("input", this._onNativeInput), n.removeEventListener("focus", this._onInputFocus), n.removeEventListener("blur", this._onInputBlur)), this._disabledObserver.disconnect(), this._focused = !1, this._inputRef = t ? new WeakRef(t) : null, this._hasInput = t !== null, !t) {
177
+ this._hasValue = !1;
178
+ return;
179
+ }
180
+ queueMicrotask(() => {
181
+ t.isConnected && (this._valueSetByHost ? t.value = this._value ?? "" : t.value ? this._valueInitialized = !0 : this._defaultValue !== void 0 && !this._valueInitialized && (t.value = this._defaultValue), this._authorPlaceholder = t.hasAttribute("placeholder"), this._applyPlaceholder(t), this._disabledHost !== void 0 && (t.disabled = this._disabledHost), this._inputDisabled = t.disabled, this._hasValue = t.value.length > 0, this._bindInput(t));
182
+ });
183
+ }
184
+ _bindInput(e) {
185
+ e.addEventListener("input", this._onNativeInput), e.addEventListener("focus", this._onInputFocus), e.addEventListener("blur", this._onInputBlur), this._disabledObserver.observe(e, { attributeFilter: ["disabled"] });
186
+ }
187
+ _applyPlaceholder(e) {
188
+ this.placeholder === void 0 || this._authorPlaceholder || (e.placeholder = this.placeholder);
189
+ }
190
+ _scheduleInputEvent(e) {
191
+ if (this._cancelPendingInput(), this.debounce <= 0) {
192
+ this._dispatchInput(e);
193
+ return;
194
+ }
195
+ this._debounceTimer = setTimeout(() => {
196
+ this._debounceTimer = void 0, this._dispatchInput(e);
197
+ }, this.debounce);
198
+ }
199
+ _cancelPendingInput() {
200
+ this._debounceTimer !== void 0 && (clearTimeout(this._debounceTimer), this._debounceTimer = void 0);
201
+ }
202
+ _dispatchInput(e) {
203
+ this.dispatchEvent(
204
+ new CustomEvent("rc-search-bar-input", {
205
+ bubbles: !0,
206
+ composed: !0,
207
+ detail: { value: e }
208
+ })
209
+ );
210
+ }
211
+ _handleClear() {
212
+ const e = this._input();
213
+ e && (this._cancelPendingInput(), e.value = "", this._valueInitialized = !0, this._hasValue = !1, this.dispatchEvent(
214
+ new CustomEvent("rc-search-bar-clear", {
215
+ bubbles: !0,
216
+ composed: !0,
217
+ detail: {}
218
+ })
219
+ ), this._dispatchInput(""), e.focus());
220
+ }
221
+ render() {
222
+ return v`
223
+ <div id="root" part="root" class=${h({ empty: !this._hasInput })}>
224
+ <span
225
+ id="leading"
226
+ part="leading"
227
+ class=${h({ empty: !this._hasLeading || !this._hasInput })}
228
+ >
229
+ <slot name="leading" @slotchange=${this._onLeadingSlotChange}></slot>
230
+ </span>
231
+ <slot @slotchange=${this._handleSlotChange}></slot>
232
+ <button
233
+ id="clear"
234
+ part="clear"
235
+ type="button"
236
+ aria-label=${this.clearLabel}
237
+ ?hidden=${!this._hasInput || !this._hasValue && !(this.showClearOnFocus && this._focused)}
238
+ ?disabled=${this._inputDisabled}
239
+ @click=${this._handleClear}
240
+ >
241
+ <slot name="clear-icon"><span aria-hidden="true">&#10005;</span></slot>
242
+ </button>
243
+ <span
244
+ id="trailing"
245
+ part="trailing"
246
+ class=${h({ empty: !this._hasTrailing })}
247
+ >
248
+ <slot name="trailing" @slotchange=${this._onTrailingSlotChange}></slot>
249
+ </span>
250
+ </div>
251
+ `;
252
+ }
253
+ /** Programmatically clears the value and fires rc-search-bar-clear + rc-search-bar-input. */
254
+ clear() {
255
+ this._handleClear();
256
+ }
257
+ _onLeadingSlotChange(e) {
258
+ const i = e.target;
259
+ this._hasLeading = i.assignedElements().length > 0;
260
+ }
261
+ _onTrailingSlotChange(e) {
262
+ const i = e.target;
263
+ this._hasTrailing = i.assignedElements().length > 0;
264
+ }
265
+ };
266
+ d.styles = [g];
267
+ let s = d;
268
+ a([
269
+ r({ type: Number })
270
+ ], s.prototype, "debounce", 2);
271
+ a([
272
+ r({ type: String, attribute: "clear-label" })
273
+ ], s.prototype, "clearLabel", 2);
274
+ a([
275
+ r({ type: Boolean, attribute: "allow-native-clear", reflect: !0 })
276
+ ], s.prototype, "allowNativeClear", 2);
277
+ a([
278
+ r({ type: Boolean, attribute: "show-clear-on-focus" })
279
+ ], s.prototype, "showClearOnFocus", 2);
280
+ a([
281
+ r({ type: Boolean, reflect: !0 })
282
+ ], s.prototype, "disabled", 1);
283
+ a([
284
+ r({ type: String })
285
+ ], s.prototype, "placeholder", 2);
286
+ a([
287
+ o()
288
+ ], s.prototype, "_hasInput", 2);
289
+ a([
290
+ o()
291
+ ], s.prototype, "_hasValue", 2);
292
+ a([
293
+ o()
294
+ ], s.prototype, "_hasLeading", 2);
295
+ a([
296
+ o()
297
+ ], s.prototype, "_hasTrailing", 2);
298
+ a([
299
+ o()
300
+ ], s.prototype, "_inputDisabled", 2);
301
+ a([
302
+ o()
303
+ ], s.prototype, "_focused", 2);
304
+ a([
305
+ r({ attribute: !1 })
306
+ ], s.prototype, "value", 1);
307
+ a([
308
+ r({ type: String, attribute: "default-value" })
309
+ ], s.prototype, "defaultValue", 1);
310
+ export {
311
+ s as R
312
+ };
313
+ //# sourceMappingURL=rc-search-bar-Ssb7YNqn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-search-bar-Ssb7YNqn.js","sources":["../src/rc-search-bar.styles.ts","../src/rc-search-bar.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const searchBarStyles = css`\n :host {\n display: inline-flex;\n color-scheme: inherit;\n }\n\n [hidden] {\n display: none !important;\n }\n\n #root {\n display: flex;\n flex: 1 1 auto;\n align-items: center;\n min-inline-size: 0;\n gap: var(--rc-search-bar-gap, 0.25em);\n block-size: var(--rc-search-bar-height, 48px);\n padding-inline: var(--rc-search-bar-padding-inline, 0.5em);\n background: var(--rc-search-bar-bg, Field);\n color: var(--rc-search-bar-color, FieldText);\n border-radius: var(--rc-search-bar-radius, var(--rc-control-radius, 0));\n }\n\n :host([data-focus-visible]) #root {\n outline: var(--rc-focus-ring, auto);\n outline-offset: var(--rc-focus-ring-offset, 0);\n }\n\n /* No slotted search input: render no chrome at all. */\n #root.empty {\n block-size: auto;\n padding: 0;\n background: none;\n border-radius: 0;\n }\n\n #leading {\n display: flex;\n flex: none;\n align-items: center;\n color: var(--rc-search-bar-icon-color, GrayText);\n }\n\n #leading.empty {\n display: none;\n }\n\n ::slotted(input[type='search']) {\n flex: 1 1 auto;\n min-inline-size: 0;\n border: none;\n background: transparent;\n color: var(--rc-search-bar-input-color, inherit);\n font-family: var(--rc-search-bar-input-font-family, inherit);\n font-size: var(--rc-search-bar-input-font-size, inherit);\n outline: none;\n }\n\n #trailing {\n display: flex;\n flex: none;\n align-items: center;\n }\n\n #trailing.empty {\n display: none;\n }\n\n #clear {\n display: inline-grid;\n flex: none;\n place-items: center;\n min-inline-size: 24px;\n min-block-size: 24px;\n padding: 0;\n border: none;\n border-radius: 50%;\n background: none;\n color: var(--rc-search-bar-clear-color, GrayText);\n font: inherit;\n cursor: pointer;\n }\n\n #clear:focus-visible {\n outline: var(--rc-focus-ring, auto);\n outline-offset: var(--rc-focus-ring-offset, 0);\n }\n`;\n\nexport default searchBarStyles;\n","import { LitElement, html, type PropertyValues } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\n\nimport searchBarStyles from './rc-search-bar.styles';\n\nconst _uaClearSheet = new CSSStyleSheet();\n_uaClearSheet.replaceSync(\n `rc-search-bar:not([allow-native-clear]) input[type=\"search\"]::-webkit-search-cancel-button\n { -webkit-appearance: none; display: none; }`,\n);\nlet _uaClearSuppressed = false;\n\nfunction _suppressUaClear(): void {\n if (_uaClearSuppressed) return;\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, _uaClearSheet];\n _uaClearSuppressed = true;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-search-bar': RCSearchBar;\n }\n}\n\nexport interface RCSearchBarInputDetail {\n /** The native input's value at dispatch time. */\n value: string;\n}\n\n/**\n * Enhances a consumer-provided native `<input type=\"search\">` with leading\n * icon chrome, an accessible clear button, and debounced search events.\n *\n * The native input is required and stays in light DOM as the source of\n * truth, so form submission, `label[for]`/wrapping-label association, and\n * pre-upgrade behavior are preserved. Without a slotted search input the\n * component renders no chrome and stays inert.\n *\n * The native WebKit cancel button is suppressed by default via an\n * adopted document stylesheet. Set `allow-native-clear` to restore it.\n * When restored, the native button clears through the normal input path\n * (a debounced `rc-search-bar-input` with an empty value) and never fires\n * `rc-search-bar-clear`.\n *\n * @slot - The required native `<input type=\"search\">`\n * @slot leading - Decorative leading icon; mark it `aria-hidden=\"true\"`\n * @slot trailing - Optional trailing content after the clear button\n * @slot clear-icon - Optional glyph replacing the default clear glyph\n * @fires rc-search-bar-input - Debounced after typing, immediate on clear;\n * `detail: { value }`\n * @fires rc-search-bar-clear - When the clear button is activated\n * @cssprop [--rc-search-bar-bg=Field] - Wrapper background\n * @cssprop [--rc-search-bar-color=FieldText] - Wrapper text color\n * @cssprop [--rc-search-bar-icon-color=GrayText] - Leading icon color\n * @cssprop [--rc-search-bar-clear-color=GrayText] - Clear button glyph color\n * @cssprop [--rc-search-bar-radius=var(--rc-control-radius)] - Wrapper border radius\n * @cssprop [--rc-search-bar-height=48px] - Wrapper block size\n * @cssprop [--rc-search-bar-padding-inline=0.5em] - Wrapper horizontal padding\n * @cssprop [--rc-search-bar-gap=0.25em] - Gap between icon, input, and clear button\n * @cssprop [--rc-search-bar-input-font-size] - Input font size (inherits when unset)\n * @cssprop [--rc-search-bar-input-font-family] - Input font family (inherits when unset)\n * @cssprop [--rc-search-bar-input-color] - Input text color (inherits when unset)\n * @csspart root - The wrapper element\n * @csspart leading - Wrapper around the leading icon slot\n * @csspart trailing - Wrapper around the trailing slot\n * @csspart clear - The clear button\n */\nexport class RCSearchBar extends LitElement {\n static styles = [searchBarStyles];\n\n /** Debounce window in ms for `rc-search-bar-input`; `0` dispatches synchronously. */\n @property({ type: Number })\n debounce = 200;\n\n /** Accessible label for the clear button. */\n @property({ type: String, attribute: 'clear-label' })\n clearLabel = 'Clear search';\n\n /** When set, leaves the browser's native WebKit cancel button visible. */\n @property({ type: Boolean, attribute: 'allow-native-clear', reflect: true })\n allowNativeClear = false;\n\n /**\n * When set, the clear button is visible whenever the input is focused,\n * even with no value — matching the Apple HIG \"cancel\" pattern.\n * Consider setting `clear-label=\"Cancel\"` in this mode.\n */\n @property({ type: Boolean, attribute: 'show-clear-on-focus' })\n showClearOnFocus = false;\n\n /** Disables the component and mirrors the state to the slotted input. */\n @property({ type: Boolean, reflect: true })\n get disabled(): boolean {\n // _disabledHost holds what the host last set; fall back to what the input\n // actually reports (kept in sync by the MutationObserver).\n return this._disabledHost ?? this._inputDisabled;\n }\n set disabled(value: boolean) {\n const old = this.disabled;\n this._disabledHost = value;\n const input = this._input();\n if (input) input.disabled = value;\n this.requestUpdate('disabled', old);\n }\n\n /**\n * Placeholder mirrored onto the native input. An author `placeholder`\n * attribute already present on the input is never overwritten.\n */\n @property({ type: String })\n placeholder?: string;\n\n private _value: string | undefined = undefined;\n\n private _defaultValue: string | undefined = undefined;\n\n private _valueSetByHost = false;\n\n /** True once an author value, host write, or user input owns the value. */\n private _valueInitialized = false;\n\n private _authorPlaceholder = false;\n\n private _inputRef: WeakRef<HTMLInputElement> | null = null;\n\n private _debounceTimer: ReturnType<typeof setTimeout> | undefined = undefined;\n\n @state()\n private _hasInput = false;\n\n @state()\n private _hasValue = false;\n\n @state()\n private _hasLeading = false;\n\n @state()\n private _hasTrailing = false;\n\n @state()\n private _inputDisabled = false;\n\n // Tracks the last value written via the disabled setter so the getter and\n // Lit's reflect can return it before the input is slotted.\n private _disabledHost: boolean | undefined = undefined;\n\n @state()\n private _focused = false;\n\n private _lastInteractionWasPointer = false;\n private readonly _onPointerDown = (): void => {\n this._lastInteractionWasPointer = true;\n };\n private readonly _onFocusIn = (): void => {\n if (!this._lastInteractionWasPointer) this.toggleAttribute('data-focus-visible', true);\n this._lastInteractionWasPointer = false;\n };\n private readonly _onFocusOut = (): void => {\n this.toggleAttribute('data-focus-visible', false);\n };\n\n private readonly _onInputFocus = (): void => {\n this._focused = true;\n };\n\n private readonly _onInputBlur = (): void => {\n this._focused = false;\n };\n\n private readonly _disabledObserver = new MutationObserver(() => {\n const input = this._input();\n if (input) this._inputDisabled = input.disabled;\n });\n\n /**\n * The current search value. Reads from the native input when present.\n * Host writes are silent (no events) and win over slotted author values.\n */\n @property({ attribute: false })\n get value(): string {\n return this._input()?.value ?? this._value ?? this._defaultValue ?? '';\n }\n set value(value: string) {\n const oldValue = this.value;\n\n this._value = value;\n this._valueSetByHost = true;\n this._valueInitialized = true;\n\n const input = this._input();\n if (input) input.value = value;\n this._hasValue = value.length > 0;\n\n this.requestUpdate('value', oldValue);\n }\n\n /**\n * Initial uncontrolled value hint. Applied once, and only when neither an\n * author `value`, a host `value` write, nor user input owns the value.\n */\n @property({ type: String, attribute: 'default-value' })\n get defaultValue(): string | undefined {\n return this._defaultValue;\n }\n set defaultValue(value: string | undefined) {\n const oldValue = this._defaultValue;\n\n this._defaultValue = value;\n\n const input = this._input();\n if (input && value !== undefined && !this._valueInitialized) {\n input.value = value;\n this._hasValue = value.length > 0;\n }\n\n this.requestUpdate('defaultValue', oldValue);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n _suppressUaClear();\n\n this.addEventListener('pointerdown', this._onPointerDown, { capture: true });\n this.addEventListener('focusin', this._onFocusIn);\n this.addEventListener('focusout', this._onFocusOut);\n\n // Slot assignment survives a DOM move without re-firing slotchange, so\n // listeners are re-bound here (addEventListener is idempotent per ref).\n const input = this._input();\n if (input) this._bindInput(input);\n }\n\n override disconnectedCallback(): void {\n this.removeEventListener('pointerdown', this._onPointerDown, { capture: true });\n this.removeEventListener('focusin', this._onFocusIn);\n this.removeEventListener('focusout', this._onFocusOut);\n\n super.disconnectedCallback();\n\n this._focused = false;\n this._cancelPendingInput();\n\n const input = this._input();\n input?.removeEventListener('input', this._onNativeInput);\n input?.removeEventListener('focus', this._onInputFocus);\n input?.removeEventListener('blur', this._onInputBlur);\n\n this._disabledObserver.disconnect();\n }\n\n protected override updated(changed: PropertyValues<this>): void {\n if (changed.has('placeholder')) {\n const input = this._input();\n if (input) this._applyPlaceholder(input);\n }\n }\n\n private _input(): HTMLInputElement | null {\n return this._inputRef?.deref() ?? null;\n }\n\n private _handleSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const input =\n slot\n .assignedElements({ flatten: true })\n .find(\n (el): el is HTMLInputElement =>\n el instanceof HTMLInputElement && el.type === 'search',\n ) ?? null;\n\n const previous = this._input();\n if (previous && previous !== input) {\n previous.removeEventListener('input', this._onNativeInput);\n previous.removeEventListener('focus', this._onInputFocus);\n previous.removeEventListener('blur', this._onInputBlur);\n }\n this._disabledObserver.disconnect();\n this._focused = false;\n\n this._inputRef = input ? new WeakRef(input) : null;\n this._hasInput = input !== null;\n\n if (!input) {\n this._hasValue = false;\n\n return;\n }\n\n // Deferred reads keep framework render cycles (e.g. SolidJS) untouched.\n queueMicrotask(() => {\n if (!input.isConnected) return;\n\n if (this._valueSetByHost) {\n input.value = this._value ?? '';\n } else if (input.value) {\n // An author-provided value wins over defaultValue.\n this._valueInitialized = true;\n } else if (this._defaultValue !== undefined && !this._valueInitialized) {\n input.value = this._defaultValue;\n }\n\n this._authorPlaceholder = input.hasAttribute('placeholder');\n this._applyPlaceholder(input);\n\n if (this._disabledHost !== undefined) {\n input.disabled = this._disabledHost;\n }\n this._inputDisabled = input.disabled;\n this._hasValue = input.value.length > 0;\n\n if (\n import.meta.env.DEV &&\n !input.labels?.length &&\n !input.getAttribute('aria-label') &&\n !input.getAttribute('aria-labelledby')\n ) {\n console.warn(\n '[rc-search-bar] Slotted <input type=\"search\"> has no accessible name.',\n 'Add aria-label, wrap in <label>, or use <label for=\"...\">.',\n input,\n );\n }\n\n this._bindInput(input);\n });\n }\n\n private _bindInput(input: HTMLInputElement): void {\n input.addEventListener('input', this._onNativeInput);\n input.addEventListener('focus', this._onInputFocus);\n input.addEventListener('blur', this._onInputBlur);\n this._disabledObserver.observe(input, { attributeFilter: ['disabled'] });\n }\n\n private _applyPlaceholder(input: HTMLInputElement): void {\n if (this.placeholder === undefined || this._authorPlaceholder) return;\n\n input.placeholder = this.placeholder;\n }\n\n private readonly _onNativeInput = (e: Event): void => {\n const input = e.currentTarget as HTMLInputElement;\n\n this._valueInitialized = true;\n this._hasValue = input.value.length > 0;\n this._scheduleInputEvent(input.value);\n };\n\n private _scheduleInputEvent(value: string): void {\n this._cancelPendingInput();\n\n if (this.debounce <= 0) {\n this._dispatchInput(value);\n\n return;\n }\n\n this._debounceTimer = setTimeout(() => {\n this._debounceTimer = undefined;\n this._dispatchInput(value);\n }, this.debounce);\n }\n\n private _cancelPendingInput(): void {\n if (this._debounceTimer === undefined) return;\n\n clearTimeout(this._debounceTimer);\n this._debounceTimer = undefined;\n }\n\n private _dispatchInput(value: string): void {\n this.dispatchEvent(\n new CustomEvent<RCSearchBarInputDetail>('rc-search-bar-input', {\n bubbles: true,\n composed: true,\n detail: { value },\n }),\n );\n }\n\n private _handleClear(): void {\n const input = this._input();\n if (!input) return;\n\n this._cancelPendingInput();\n\n input.value = '';\n this._valueInitialized = true;\n this._hasValue = false;\n\n this.dispatchEvent(\n new CustomEvent('rc-search-bar-clear', {\n bubbles: true,\n composed: true,\n detail: {},\n }),\n );\n this._dispatchInput('');\n\n // Refocus before the re-render hides the button, so focus never drops\n // to <body>.\n input.focus();\n }\n\n protected override render() {\n return html`\n <div id=\"root\" part=\"root\" class=${classMap({ empty: !this._hasInput })}>\n <span\n id=\"leading\"\n part=\"leading\"\n class=${classMap({ empty: !this._hasLeading || !this._hasInput })}\n >\n <slot name=\"leading\" @slotchange=${this._onLeadingSlotChange}></slot>\n </span>\n <slot @slotchange=${this._handleSlotChange}></slot>\n <button\n id=\"clear\"\n part=\"clear\"\n type=\"button\"\n aria-label=${this.clearLabel}\n ?hidden=${!this._hasInput || (!this._hasValue && !(this.showClearOnFocus && this._focused))}\n ?disabled=${this._inputDisabled}\n @click=${this._handleClear}\n >\n <slot name=\"clear-icon\"><span aria-hidden=\"true\">&#10005;</span></slot>\n </button>\n <span\n id=\"trailing\"\n part=\"trailing\"\n class=${classMap({ empty: !this._hasTrailing })}\n >\n <slot name=\"trailing\" @slotchange=${this._onTrailingSlotChange}></slot>\n </span>\n </div>\n `;\n }\n\n /** Programmatically clears the value and fires rc-search-bar-clear + rc-search-bar-input. */\n public clear(): void {\n this._handleClear();\n }\n\n private _onLeadingSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLeading = slot.assignedElements().length > 0;\n }\n\n private _onTrailingSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasTrailing = slot.assignedElements().length > 0;\n }\n}\n\nexport default RCSearchBar;\n"],"names":["searchBarStyles","css","_uaClearSheet","_uaClearSuppressed","_suppressUaClear","_RCSearchBar","LitElement","input","value","old","oldValue","changed","el","previous","html","classMap","slot","RCSearchBar","__decorateClass","property","state"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { R as e } from "./rc-search-bar-Ssb7YNqn.js";
2
+ customElements.get("rc-search-bar") || customElements.define("rc-search-bar", e);
3
+ export {
4
+ e as RCSearchBar
5
+ };
6
+ //# sourceMappingURL=rc-search-bar-define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-search-bar-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCSearchBar } from './index.js';\n\ncustomElements.get('rc-search-bar') || customElements.define('rc-search-bar', RCSearchBar);\n\nexport * from './index.js';\n"],"names":["RCSearchBar"],"mappings":";AAEA,eAAe,IAAI,eAAe,KAAK,eAAe,OAAO,iBAAiBA,CAAW;"}
@@ -0,0 +1,5 @@
1
+ import { R as e } from "./rc-search-bar-Ssb7YNqn.js";
2
+ export {
3
+ e as RCSearchBar
4
+ };
5
+ //# sourceMappingURL=rc-search-bar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-search-bar.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1 @@
1
+ export * from './index.js';
@@ -0,0 +1 @@
1
+ export * from './rc-search-bar';
@@ -0,0 +1,123 @@
1
+ import { LitElement, PropertyValues } from 'lit';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'rc-search-bar': RCSearchBar;
5
+ }
6
+ }
7
+ export interface RCSearchBarInputDetail {
8
+ /** The native input's value at dispatch time. */
9
+ value: string;
10
+ }
11
+ /**
12
+ * Enhances a consumer-provided native `<input type="search">` with leading
13
+ * icon chrome, an accessible clear button, and debounced search events.
14
+ *
15
+ * The native input is required and stays in light DOM as the source of
16
+ * truth, so form submission, `label[for]`/wrapping-label association, and
17
+ * pre-upgrade behavior are preserved. Without a slotted search input the
18
+ * component renders no chrome and stays inert.
19
+ *
20
+ * The native WebKit cancel button is suppressed by default via an
21
+ * adopted document stylesheet. Set `allow-native-clear` to restore it.
22
+ * When restored, the native button clears through the normal input path
23
+ * (a debounced `rc-search-bar-input` with an empty value) and never fires
24
+ * `rc-search-bar-clear`.
25
+ *
26
+ * @slot - The required native `<input type="search">`
27
+ * @slot leading - Decorative leading icon; mark it `aria-hidden="true"`
28
+ * @slot trailing - Optional trailing content after the clear button
29
+ * @slot clear-icon - Optional glyph replacing the default clear glyph
30
+ * @fires rc-search-bar-input - Debounced after typing, immediate on clear;
31
+ * `detail: { value }`
32
+ * @fires rc-search-bar-clear - When the clear button is activated
33
+ * @cssprop [--rc-search-bar-bg=Field] - Wrapper background
34
+ * @cssprop [--rc-search-bar-color=FieldText] - Wrapper text color
35
+ * @cssprop [--rc-search-bar-icon-color=GrayText] - Leading icon color
36
+ * @cssprop [--rc-search-bar-clear-color=GrayText] - Clear button glyph color
37
+ * @cssprop [--rc-search-bar-radius=var(--rc-control-radius)] - Wrapper border radius
38
+ * @cssprop [--rc-search-bar-height=48px] - Wrapper block size
39
+ * @cssprop [--rc-search-bar-padding-inline=0.5em] - Wrapper horizontal padding
40
+ * @cssprop [--rc-search-bar-gap=0.25em] - Gap between icon, input, and clear button
41
+ * @cssprop [--rc-search-bar-input-font-size] - Input font size (inherits when unset)
42
+ * @cssprop [--rc-search-bar-input-font-family] - Input font family (inherits when unset)
43
+ * @cssprop [--rc-search-bar-input-color] - Input text color (inherits when unset)
44
+ * @csspart root - The wrapper element
45
+ * @csspart leading - Wrapper around the leading icon slot
46
+ * @csspart trailing - Wrapper around the trailing slot
47
+ * @csspart clear - The clear button
48
+ */
49
+ export declare class RCSearchBar extends LitElement {
50
+ static styles: import('lit').CSSResult[];
51
+ /** Debounce window in ms for `rc-search-bar-input`; `0` dispatches synchronously. */
52
+ debounce: number;
53
+ /** Accessible label for the clear button. */
54
+ clearLabel: string;
55
+ /** When set, leaves the browser's native WebKit cancel button visible. */
56
+ allowNativeClear: boolean;
57
+ /**
58
+ * When set, the clear button is visible whenever the input is focused,
59
+ * even with no value — matching the Apple HIG "cancel" pattern.
60
+ * Consider setting `clear-label="Cancel"` in this mode.
61
+ */
62
+ showClearOnFocus: boolean;
63
+ /** Disables the component and mirrors the state to the slotted input. */
64
+ get disabled(): boolean;
65
+ set disabled(value: boolean);
66
+ /**
67
+ * Placeholder mirrored onto the native input. An author `placeholder`
68
+ * attribute already present on the input is never overwritten.
69
+ */
70
+ placeholder?: string;
71
+ private _value;
72
+ private _defaultValue;
73
+ private _valueSetByHost;
74
+ /** True once an author value, host write, or user input owns the value. */
75
+ private _valueInitialized;
76
+ private _authorPlaceholder;
77
+ private _inputRef;
78
+ private _debounceTimer;
79
+ private _hasInput;
80
+ private _hasValue;
81
+ private _hasLeading;
82
+ private _hasTrailing;
83
+ private _inputDisabled;
84
+ private _disabledHost;
85
+ private _focused;
86
+ private _lastInteractionWasPointer;
87
+ private readonly _onPointerDown;
88
+ private readonly _onFocusIn;
89
+ private readonly _onFocusOut;
90
+ private readonly _onInputFocus;
91
+ private readonly _onInputBlur;
92
+ private readonly _disabledObserver;
93
+ /**
94
+ * The current search value. Reads from the native input when present.
95
+ * Host writes are silent (no events) and win over slotted author values.
96
+ */
97
+ get value(): string;
98
+ set value(value: string);
99
+ /**
100
+ * Initial uncontrolled value hint. Applied once, and only when neither an
101
+ * author `value`, a host `value` write, nor user input owns the value.
102
+ */
103
+ get defaultValue(): string | undefined;
104
+ set defaultValue(value: string | undefined);
105
+ connectedCallback(): void;
106
+ disconnectedCallback(): void;
107
+ protected updated(changed: PropertyValues<this>): void;
108
+ private _input;
109
+ private _handleSlotChange;
110
+ private _bindInput;
111
+ private _applyPlaceholder;
112
+ private readonly _onNativeInput;
113
+ private _scheduleInputEvent;
114
+ private _cancelPendingInput;
115
+ private _dispatchInput;
116
+ private _handleClear;
117
+ protected render(): import('lit').TemplateResult<1>;
118
+ /** Programmatically clears the value and fires rc-search-bar-clear + rc-search-bar-input. */
119
+ clear(): void;
120
+ private _onLeadingSlotChange;
121
+ private _onTrailingSlotChange;
122
+ }
123
+ export default RCSearchBar;
@@ -0,0 +1,2 @@
1
+ export declare const searchBarStyles: import('lit').CSSResult;
2
+ export default searchBarStyles;