@rcarls/rc-search-bar 0.1.0 → 0.3.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/README.md +40 -61
- package/dist/custom-elements.json +48 -42
- package/dist/{rc-search-bar-Ssb7YNqn.js → rc-search-bar-DVczVFvA.js} +102 -89
- package/dist/rc-search-bar-DVczVFvA.js.map +1 -0
- package/dist/rc-search-bar-define.js +1 -1
- package/dist/rc-search-bar.js +1 -1
- package/dist/types/packages/rc-search-bar/src/rc-search-bar.d.ts +22 -16
- package/package.json +9 -9
- package/dist/demo.css +0 -85
- package/dist/demo.js +0 -40
- package/dist/rc-search-bar-Ssb7YNqn.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
# `@rcarls/rc-search-bar`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
chrome, an accessible clear button, and debounced search events.
|
|
3
|
+
Search field wrapper for a native `<input type="search">` with icon chrome, clear button, and debounced events.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
truth: form submission (`name`), label association (`label[for]`, wrapping
|
|
8
|
-
`<label>`, `aria-label`), and pre-upgrade usability all keep working. Without
|
|
9
|
-
a slotted search input the component renders no chrome and stays inert.
|
|
5
|
+
Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-search-bar](https://richardcarls.github.io/rc-webcomponents/components/rc-search-bar).
|
|
10
6
|
|
|
11
7
|
---
|
|
12
8
|
|
|
@@ -40,10 +36,9 @@ import { RCSearchBar } from '@rcarls/rc-search-bar';
|
|
|
40
36
|
</search>
|
|
41
37
|
|
|
42
38
|
<script>
|
|
43
|
-
document
|
|
44
|
-
'rc-search-bar
|
|
45
|
-
(e) => console.log(e.detail.value)
|
|
46
|
-
);
|
|
39
|
+
document
|
|
40
|
+
.querySelector('rc-search-bar')
|
|
41
|
+
.addEventListener('rc-search-bar-input', (e) => console.log(e.detail.value));
|
|
47
42
|
</script>
|
|
48
43
|
```
|
|
49
44
|
|
|
@@ -56,67 +51,58 @@ The native WebKit cancel button is suppressed automatically. Set
|
|
|
56
51
|
|
|
57
52
|
---
|
|
58
53
|
|
|
59
|
-
## Controlled and uncontrolled value
|
|
60
|
-
|
|
61
|
-
- **Uncontrolled** — the input (and the user) own the value. Optionally seed
|
|
62
|
-
it with `default-value`; an author `value` attribute on the input wins over
|
|
63
|
-
`default-value`.
|
|
64
|
-
- **Controlled** — assign the `value` property. Host writes are silent (no
|
|
65
|
-
events) and win over slotted author values, including across re-slots.
|
|
66
|
-
User interaction always dispatches events.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
54
|
## API
|
|
71
55
|
|
|
72
56
|
### Properties / attributes
|
|
73
57
|
|
|
74
|
-
| Property
|
|
75
|
-
|
|
76
|
-
| `value`
|
|
77
|
-
| `defaultValue`
|
|
78
|
-
| `debounce`
|
|
79
|
-
| `clearLabel`
|
|
80
|
-
| `allowNativeClear` | `allow-native-clear`
|
|
81
|
-
| `showClearOnFocus` | `show-clear-on-focus` | `boolean`
|
|
82
|
-
| `placeholder`
|
|
58
|
+
| Property | Attribute | Type | Default | Description |
|
|
59
|
+
| ------------------ | --------------------- | --------------------- | ---------------- | --------------------------------------------------------------------------------------- |
|
|
60
|
+
| `value` | — | `string` | `''` | Current search value; reads from the native input, host writes are silent |
|
|
61
|
+
| `defaultValue` | `default-value` | `string \| undefined` | `undefined` | Initial uncontrolled value hint, applied once |
|
|
62
|
+
| `debounce` | `debounce` | `number` | `200` | Debounce window in ms for `rc-search-bar-input`; `0` dispatches synchronously |
|
|
63
|
+
| `clearLabel` | `clear-label` | `string` | `'Clear search'` | Accessible label for the clear button |
|
|
64
|
+
| `allowNativeClear` | `allow-native-clear` | `boolean` | `false` | When set, restores the browser's native WebKit cancel button |
|
|
65
|
+
| `showClearOnFocus` | `show-clear-on-focus` | `boolean` | `false` | When set, shows the clear button on focus even with no value (Apple HIG cancel pattern) |
|
|
66
|
+
| `placeholder` | `placeholder` | `string \| undefined` | `undefined` | Mirrored onto the input unless the author already set one |
|
|
83
67
|
|
|
84
68
|
### CSS custom properties
|
|
85
69
|
|
|
86
|
-
| Property
|
|
87
|
-
|
|
88
|
-
| `--rc-search-bar-
|
|
89
|
-
| `--rc-search-bar-
|
|
90
|
-
| `--rc-search-bar-
|
|
91
|
-
| `--rc-search-bar-
|
|
92
|
-
| `--rc-search-bar-
|
|
93
|
-
| `--rc-search-bar-
|
|
94
|
-
| `--rc-search-bar-
|
|
95
|
-
| `--rc-search-bar-
|
|
70
|
+
| Property | Default | Description |
|
|
71
|
+
| -------------------------------- | ------------------------------------------- | ----------------------------------------- |
|
|
72
|
+
| `--rc-search-bar-border` | `1px solid ButtonBorder` | Border; M3 theme uses elevation instead |
|
|
73
|
+
| `--rc-search-bar-shadow` | `none` | Elevation shadow; M3 sets Level 1 at rest |
|
|
74
|
+
| `--rc-search-bar-bg` | `Field` | Wrapper background |
|
|
75
|
+
| `--rc-search-bar-color` | `FieldText` | Wrapper text color |
|
|
76
|
+
| `--rc-search-bar-icon-color` | `GrayText` | Leading icon color |
|
|
77
|
+
| `--rc-search-bar-clear-color` | `GrayText` | Clear button glyph color |
|
|
78
|
+
| `--rc-search-bar-radius` | `var(--rc-control-radius, 0.125em)` | Wrapper border radius |
|
|
79
|
+
| `--rc-search-bar-height` | `var(--rc-control-block-size, 2.5rem)` | Wrapper block size |
|
|
80
|
+
| `--rc-search-bar-padding-inline` | `var(--rc-control-padding-inline, 0.75rem)` | Wrapper horizontal padding |
|
|
81
|
+
| `--rc-search-bar-gap` | `var(--rc-control-gap, 0.25em)` | Gap between icon, input, and clear button |
|
|
96
82
|
|
|
97
83
|
### CSS parts
|
|
98
84
|
|
|
99
|
-
| Part
|
|
100
|
-
|
|
101
|
-
| `root`
|
|
102
|
-
| `leading` | `span`
|
|
103
|
-
| `clear`
|
|
85
|
+
| Part | Element | Description |
|
|
86
|
+
| --------- | ------------- | ------------------------------------ |
|
|
87
|
+
| `root` | wrapper `div` | The field chrome |
|
|
88
|
+
| `leading` | `span` | Wrapper around the leading icon slot |
|
|
89
|
+
| `clear` | `button` | The clear button |
|
|
104
90
|
|
|
105
91
|
### Slots
|
|
106
92
|
|
|
107
|
-
| Slot
|
|
108
|
-
|
|
109
|
-
|
|
|
110
|
-
| `leading`
|
|
111
|
-
| `clear-icon` | Optional glyph replacing the default ✕ in the clear button
|
|
112
|
-
| `trailing`
|
|
93
|
+
| Slot | Description |
|
|
94
|
+
| ------------ | ------------------------------------------------------------------------- |
|
|
95
|
+
| _(default)_ | The required native `<input type="search">` |
|
|
96
|
+
| `leading` | Decorative leading icon; mark it `aria-hidden="true"` |
|
|
97
|
+
| `clear-icon` | Optional glyph replacing the default ✕ in the clear button |
|
|
98
|
+
| `trailing` | Optional content after the clear button (supplementary badges or actions) |
|
|
113
99
|
|
|
114
100
|
### Events
|
|
115
101
|
|
|
116
|
-
| Event
|
|
117
|
-
|
|
102
|
+
| Event | Detail | Description |
|
|
103
|
+
| --------------------- | ------------------- | ---------------------------------------------------------------------------- |
|
|
118
104
|
| `rc-search-bar-input` | `{ value: string }` | Debounced after typing; fired immediately (pending timer cancelled) on clear |
|
|
119
|
-
| `rc-search-bar-clear` | `{}`
|
|
105
|
+
| `rc-search-bar-clear` | `{}` | Fired when the clear button is activated |
|
|
120
106
|
|
|
121
107
|
---
|
|
122
108
|
|
|
@@ -138,10 +124,3 @@ The native WebKit cancel button is suppressed automatically. Set
|
|
|
138
124
|
focused (Apple HIG cancel pattern). Consider `clear-label="Cancel"` in this
|
|
139
125
|
mode. The `rc-search-bar-clear` event fires even when the value is empty,
|
|
140
126
|
allowing the host to dismiss a search overlay.
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
## Browser support
|
|
145
|
-
|
|
146
|
-
Evergreen browsers. The component is inert without JavaScript: the native
|
|
147
|
-
search input remains fully usable and form-associated before upgrade.
|
|
@@ -46,9 +46,19 @@
|
|
|
46
46
|
"declarations": [
|
|
47
47
|
{
|
|
48
48
|
"kind": "class",
|
|
49
|
-
"description": "
|
|
49
|
+
"description": "Search field wrapper for a native <input type=\"search\"> with icon chrome, clear button,\nand debounced events.\n\nThe native input is required and stays in light DOM as the source of\ntruth, so form submission, `label[for]`/wrapping-label association, and\npre-upgrade behavior are preserved. Without a slotted search input the\ncomponent renders no chrome and stays inert.\n\nThe native WebKit cancel button is suppressed by default via an\nadopted document stylesheet. Set `allow-native-clear` to restore it.\nWhen 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`.",
|
|
50
50
|
"name": "RCSearchBar",
|
|
51
51
|
"cssProperties": [
|
|
52
|
+
{
|
|
53
|
+
"description": "Wrapper border; set to `none` in M3 theme (uses elevation instead)",
|
|
54
|
+
"name": "--rc-search-bar-border",
|
|
55
|
+
"default": "1px solid ButtonBorder"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Wrapper box-shadow for elevation; M3 theme sets Level 1 at rest",
|
|
59
|
+
"name": "--rc-search-bar-shadow",
|
|
60
|
+
"default": "none"
|
|
61
|
+
},
|
|
52
62
|
{
|
|
53
63
|
"description": "Wrapper background",
|
|
54
64
|
"name": "--rc-search-bar-bg",
|
|
@@ -72,22 +82,22 @@
|
|
|
72
82
|
{
|
|
73
83
|
"description": "Wrapper border radius",
|
|
74
84
|
"name": "--rc-search-bar-radius",
|
|
75
|
-
"default": "var(--rc-control-radius)"
|
|
85
|
+
"default": "var(--rc-control-radius,0.125em)"
|
|
76
86
|
},
|
|
77
87
|
{
|
|
78
88
|
"description": "Wrapper block size",
|
|
79
89
|
"name": "--rc-search-bar-height",
|
|
80
|
-
"default": "
|
|
90
|
+
"default": "var(--rc-control-block-size,2.5rem)"
|
|
81
91
|
},
|
|
82
92
|
{
|
|
83
93
|
"description": "Wrapper horizontal padding",
|
|
84
94
|
"name": "--rc-search-bar-padding-inline",
|
|
85
|
-
"default": "0.
|
|
95
|
+
"default": "var(--rc-control-padding-inline,0.75rem)"
|
|
86
96
|
},
|
|
87
97
|
{
|
|
88
98
|
"description": "Gap between icon, input, and clear button",
|
|
89
99
|
"name": "--rc-search-bar-gap",
|
|
90
|
-
"default": "0.25em"
|
|
100
|
+
"default": "var(--rc-control-gap,0.25em)"
|
|
91
101
|
},
|
|
92
102
|
{
|
|
93
103
|
"description": "Input font size (inherits when unset)",
|
|
@@ -177,7 +187,7 @@
|
|
|
177
187
|
"text": "boolean"
|
|
178
188
|
},
|
|
179
189
|
"default": "false",
|
|
180
|
-
"description": "When set, the clear button is visible whenever the input is focused
|
|
190
|
+
"description": "When set, the clear button is visible whenever the input is focused.\n\nMatching the Apple HIG \"cancel\" pattern.\nConsider setting `clear-label=\"Cancel\"` in this mode.",
|
|
181
191
|
"attribute": "show-clear-on-focus"
|
|
182
192
|
},
|
|
183
193
|
{
|
|
@@ -196,7 +206,7 @@
|
|
|
196
206
|
"type": {
|
|
197
207
|
"text": "string | undefined"
|
|
198
208
|
},
|
|
199
|
-
"description": "Placeholder mirrored onto the native input
|
|
209
|
+
"description": "Placeholder mirrored onto the native input.\n\nConsumer `placeholder` attribute is always honored.",
|
|
200
210
|
"attribute": "placeholder"
|
|
201
211
|
},
|
|
202
212
|
{
|
|
@@ -247,7 +257,7 @@
|
|
|
247
257
|
},
|
|
248
258
|
{
|
|
249
259
|
"kind": "field",
|
|
250
|
-
"name": "
|
|
260
|
+
"name": "_$inputRef",
|
|
251
261
|
"type": {
|
|
252
262
|
"text": "WeakRef<HTMLInputElement> | null"
|
|
253
263
|
},
|
|
@@ -328,49 +338,29 @@
|
|
|
328
338
|
},
|
|
329
339
|
{
|
|
330
340
|
"kind": "field",
|
|
331
|
-
"name": "
|
|
332
|
-
"type": {
|
|
333
|
-
"text": "boolean"
|
|
334
|
-
},
|
|
335
|
-
"privacy": "private",
|
|
336
|
-
"default": "false"
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
"kind": "field",
|
|
340
|
-
"name": "_onPointerDown",
|
|
341
|
-
"privacy": "private",
|
|
342
|
-
"readonly": true
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
"kind": "field",
|
|
346
|
-
"name": "_onFocusIn",
|
|
347
|
-
"privacy": "private",
|
|
348
|
-
"readonly": true
|
|
349
|
-
},
|
|
350
|
-
{
|
|
351
|
-
"kind": "field",
|
|
352
|
-
"name": "_onFocusOut",
|
|
341
|
+
"name": "_onInputFocus",
|
|
353
342
|
"privacy": "private",
|
|
354
343
|
"readonly": true
|
|
355
344
|
},
|
|
356
345
|
{
|
|
357
346
|
"kind": "field",
|
|
358
|
-
"name": "
|
|
347
|
+
"name": "_onInputBlur",
|
|
359
348
|
"privacy": "private",
|
|
360
349
|
"readonly": true
|
|
361
350
|
},
|
|
362
351
|
{
|
|
363
352
|
"kind": "field",
|
|
364
|
-
"name": "
|
|
353
|
+
"name": "_disabledObserver",
|
|
365
354
|
"privacy": "private",
|
|
366
|
-
"readonly": true
|
|
355
|
+
"readonly": true,
|
|
356
|
+
"default": "new MutationObserver(() => { const $input = this._$input(); if ($input) { this._inputDisabled = $input.disabled; } })"
|
|
367
357
|
},
|
|
368
358
|
{
|
|
369
359
|
"kind": "field",
|
|
370
|
-
"name": "
|
|
360
|
+
"name": "_inputController",
|
|
371
361
|
"privacy": "private",
|
|
372
362
|
"readonly": true,
|
|
373
|
-
"default": "new
|
|
363
|
+
"default": "new NativeChildController<HTMLInputElement>(this, { selector: ':scope > input[type=\"search\"]', observe: true, onChange: ($input, $previousInput) => this._setupInput($input, $previousInput), onMissing: () => { if (import.meta.env.DEV) { warnMissingDirectChild(this, { selector: ':scope > input[type=\"search\"]', message: '[rc-search-bar] No direct child <input type=\"search\"> found. ' + 'Place a native search input inside <rc-search-bar>.', }); } }, })"
|
|
374
364
|
},
|
|
375
365
|
{
|
|
376
366
|
"kind": "field",
|
|
@@ -391,7 +381,7 @@
|
|
|
391
381
|
},
|
|
392
382
|
{
|
|
393
383
|
"kind": "method",
|
|
394
|
-
"name": "
|
|
384
|
+
"name": "_$input",
|
|
395
385
|
"privacy": "private",
|
|
396
386
|
"return": {
|
|
397
387
|
"type": {
|
|
@@ -403,6 +393,16 @@
|
|
|
403
393
|
"kind": "method",
|
|
404
394
|
"name": "_handleSlotChange",
|
|
405
395
|
"privacy": "private",
|
|
396
|
+
"return": {
|
|
397
|
+
"type": {
|
|
398
|
+
"text": "void"
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"kind": "method",
|
|
404
|
+
"name": "_setupInput",
|
|
405
|
+
"privacy": "private",
|
|
406
406
|
"return": {
|
|
407
407
|
"type": {
|
|
408
408
|
"text": "void"
|
|
@@ -410,9 +410,15 @@
|
|
|
410
410
|
},
|
|
411
411
|
"parameters": [
|
|
412
412
|
{
|
|
413
|
-
"name": "
|
|
413
|
+
"name": "$input",
|
|
414
414
|
"type": {
|
|
415
|
-
"text": "
|
|
415
|
+
"text": "HTMLInputElement | null"
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"name": "$previousInput",
|
|
420
|
+
"type": {
|
|
421
|
+
"text": "HTMLInputElement | null"
|
|
416
422
|
}
|
|
417
423
|
}
|
|
418
424
|
]
|
|
@@ -428,7 +434,7 @@
|
|
|
428
434
|
},
|
|
429
435
|
"parameters": [
|
|
430
436
|
{
|
|
431
|
-
"name": "input",
|
|
437
|
+
"name": "$input",
|
|
432
438
|
"type": {
|
|
433
439
|
"text": "HTMLInputElement"
|
|
434
440
|
}
|
|
@@ -446,7 +452,7 @@
|
|
|
446
452
|
},
|
|
447
453
|
"parameters": [
|
|
448
454
|
{
|
|
449
|
-
"name": "input",
|
|
455
|
+
"name": "$input",
|
|
450
456
|
"type": {
|
|
451
457
|
"text": "HTMLInputElement"
|
|
452
458
|
}
|
|
@@ -613,7 +619,7 @@
|
|
|
613
619
|
"text": "boolean"
|
|
614
620
|
},
|
|
615
621
|
"default": "false",
|
|
616
|
-
"description": "When set, the clear button is visible whenever the input is focused
|
|
622
|
+
"description": "When set, the clear button is visible whenever the input is focused.\n\nMatching the Apple HIG \"cancel\" pattern.\nConsider setting `clear-label=\"Cancel\"` in this mode.",
|
|
617
623
|
"fieldName": "showClearOnFocus"
|
|
618
624
|
},
|
|
619
625
|
{
|
|
@@ -629,7 +635,7 @@
|
|
|
629
635
|
"type": {
|
|
630
636
|
"text": "string | undefined"
|
|
631
637
|
},
|
|
632
|
-
"description": "Placeholder mirrored onto the native input
|
|
638
|
+
"description": "Placeholder mirrored onto the native input.\n\nConsumer `placeholder` attribute is always honored.",
|
|
633
639
|
"fieldName": "placeholder"
|
|
634
640
|
},
|
|
635
641
|
{
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { css as
|
|
2
|
-
import { property as r, state as
|
|
3
|
-
import { classMap as
|
|
4
|
-
|
|
1
|
+
import { css as b, LitElement as f, html as v } from "lit";
|
|
2
|
+
import { property as r, state as l } from "lit/decorators.js";
|
|
3
|
+
import { classMap as d } from "lit/directives/class-map.js";
|
|
4
|
+
import { NativeChildController as g, keyInteraction as m } from "@rcarls/rc-common";
|
|
5
|
+
const y = b`
|
|
5
6
|
:host {
|
|
6
7
|
display: inline-flex;
|
|
7
8
|
color-scheme: inherit;
|
|
@@ -16,15 +17,21 @@ const g = f`
|
|
|
16
17
|
flex: 1 1 auto;
|
|
17
18
|
align-items: center;
|
|
18
19
|
min-inline-size: 0;
|
|
19
|
-
gap: var(--rc-search-bar-gap, 0.25em);
|
|
20
|
-
block-size: var(--rc-search-bar-height,
|
|
21
|
-
padding-inline: var(--rc-search-bar-padding-inline, 0.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
gap: var(--rc-search-bar-gap, var(--rc-control-gap, 0.25em));
|
|
21
|
+
block-size: var(--rc-search-bar-height, var(--rc-control-block-size, 2.5rem));
|
|
22
|
+
padding-inline: var(--rc-search-bar-padding-inline, var(--rc-control-padding-inline, 0.75rem));
|
|
23
|
+
border: var(--rc-search-bar-border, var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder)));
|
|
24
|
+
border-radius: var(--rc-search-bar-radius, var(--rc-control-radius, var(--rc-radius-sm, 0.125em)));
|
|
25
|
+
box-shadow: var(--rc-search-bar-shadow, none);
|
|
26
|
+
background: var(--rc-search-bar-bg, var(--rc-field, Field));
|
|
27
|
+
color: var(--rc-search-bar-color, var(--rc-field-text, FieldText));
|
|
28
|
+
font-family: var(--rc-font-family, inherit);
|
|
29
|
+
font-size: var(--rc-font-size, inherit);
|
|
30
|
+
line-height: var(--rc-line-height, normal);
|
|
31
|
+
transition: background-color 120ms, border-color 120ms, box-shadow 120ms;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
:host([data-
|
|
34
|
+
:host([data-interaction-mode='keyboard']) #root:focus-within {
|
|
28
35
|
outline: var(--rc-focus-ring, auto);
|
|
29
36
|
outline-offset: var(--rc-focus-ring-offset, 0);
|
|
30
37
|
}
|
|
@@ -34,6 +41,8 @@ const g = f`
|
|
|
34
41
|
block-size: auto;
|
|
35
42
|
padding: 0;
|
|
36
43
|
background: none;
|
|
44
|
+
border: none;
|
|
45
|
+
box-shadow: none;
|
|
37
46
|
border-radius: 0;
|
|
38
47
|
}
|
|
39
48
|
|
|
@@ -51,12 +60,14 @@ const g = f`
|
|
|
51
60
|
::slotted(input[type='search']) {
|
|
52
61
|
flex: 1 1 auto;
|
|
53
62
|
min-inline-size: 0;
|
|
63
|
+
padding: 0;
|
|
54
64
|
border: none;
|
|
55
65
|
background: transparent;
|
|
56
66
|
color: var(--rc-search-bar-input-color, inherit);
|
|
57
67
|
font-family: var(--rc-search-bar-input-font-family, inherit);
|
|
58
68
|
font-size: var(--rc-search-bar-input-font-size, inherit);
|
|
59
69
|
outline: none;
|
|
70
|
+
appearance: textfield;
|
|
60
71
|
}
|
|
61
72
|
|
|
62
73
|
#trailing {
|
|
@@ -84,15 +95,19 @@ const g = f`
|
|
|
84
95
|
cursor: pointer;
|
|
85
96
|
}
|
|
86
97
|
|
|
98
|
+
#clear[inert] {
|
|
99
|
+
visibility: hidden;
|
|
100
|
+
}
|
|
101
|
+
|
|
87
102
|
#clear:focus-visible {
|
|
88
103
|
outline: var(--rc-focus-ring, auto);
|
|
89
104
|
outline-offset: var(--rc-focus-ring-offset, 0);
|
|
90
105
|
}
|
|
91
106
|
`;
|
|
92
|
-
var
|
|
93
|
-
for (var n =
|
|
94
|
-
(
|
|
95
|
-
return
|
|
107
|
+
var I = Object.defineProperty, C = Object.getOwnPropertyDescriptor, a = (c, e, t, s) => {
|
|
108
|
+
for (var n = s > 1 ? void 0 : s ? C(e, t) : e, o = c.length - 1, h; o >= 0; o--)
|
|
109
|
+
(h = c[o]) && (n = (s ? h(e, t, n) : h(n)) || n);
|
|
110
|
+
return s && n && I(e, t, n), n;
|
|
96
111
|
};
|
|
97
112
|
const _ = new CSSStyleSheet();
|
|
98
113
|
_.replaceSync(
|
|
@@ -100,85 +115,83 @@ _.replaceSync(
|
|
|
100
115
|
{ -webkit-appearance: none; display: none; }`
|
|
101
116
|
);
|
|
102
117
|
let p = !1;
|
|
103
|
-
function
|
|
118
|
+
function w() {
|
|
104
119
|
p || (document.adoptedStyleSheets = [...document.adoptedStyleSheets, _], p = !0);
|
|
105
120
|
}
|
|
106
|
-
const
|
|
121
|
+
const u = class u extends f {
|
|
107
122
|
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.
|
|
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 = () => {
|
|
123
|
+
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._onInputFocus = () => {
|
|
115
124
|
this._focused = !0;
|
|
116
125
|
}, this._onInputBlur = () => {
|
|
117
126
|
this._focused = !1;
|
|
118
127
|
}, this._disabledObserver = new MutationObserver(() => {
|
|
119
|
-
const e = this.
|
|
128
|
+
const e = this._$input();
|
|
120
129
|
e && (this._inputDisabled = e.disabled);
|
|
130
|
+
}), this._inputController = new g(this, {
|
|
131
|
+
selector: ':scope > input[type="search"]',
|
|
132
|
+
observe: !0,
|
|
133
|
+
onChange: (e, t) => this._setupInput(e, t),
|
|
134
|
+
onMissing: () => {
|
|
135
|
+
}
|
|
121
136
|
}), this._onNativeInput = (e) => {
|
|
122
|
-
const
|
|
123
|
-
this._valueInitialized = !0, this._hasValue =
|
|
137
|
+
const t = e.currentTarget;
|
|
138
|
+
this._valueInitialized = !0, this._hasValue = t.value.length > 0, this._scheduleInputEvent(t.value);
|
|
124
139
|
};
|
|
125
140
|
}
|
|
126
141
|
get disabled() {
|
|
127
142
|
return this._disabledHost ?? this._inputDisabled;
|
|
128
143
|
}
|
|
129
144
|
set disabled(e) {
|
|
130
|
-
const
|
|
145
|
+
const t = this.disabled;
|
|
131
146
|
this._disabledHost = e;
|
|
132
|
-
const
|
|
133
|
-
|
|
147
|
+
const s = this._$input();
|
|
148
|
+
s && (s.disabled = e), this.requestUpdate("disabled", t);
|
|
134
149
|
}
|
|
135
150
|
get value() {
|
|
136
|
-
return this.
|
|
151
|
+
return this._$input()?.value ?? this._value ?? this._defaultValue ?? "";
|
|
137
152
|
}
|
|
138
153
|
set value(e) {
|
|
139
|
-
const
|
|
154
|
+
const t = this.value;
|
|
140
155
|
this._value = e, this._valueSetByHost = !0, this._valueInitialized = !0;
|
|
141
|
-
const
|
|
142
|
-
|
|
156
|
+
const s = this._$input();
|
|
157
|
+
s && (s.value = e), this._hasValue = e.length > 0, this.requestUpdate("value", t);
|
|
143
158
|
}
|
|
144
159
|
get defaultValue() {
|
|
145
160
|
return this._defaultValue;
|
|
146
161
|
}
|
|
147
162
|
set defaultValue(e) {
|
|
148
|
-
const
|
|
163
|
+
const t = this._defaultValue;
|
|
149
164
|
this._defaultValue = e;
|
|
150
|
-
const
|
|
151
|
-
|
|
165
|
+
const s = this._$input();
|
|
166
|
+
s && e !== void 0 && !this._valueInitialized && (s.value = e, this._hasValue = e.length > 0), this.requestUpdate("defaultValue", t);
|
|
152
167
|
}
|
|
153
168
|
connectedCallback() {
|
|
154
|
-
super.connectedCallback(),
|
|
155
|
-
const e = this._input();
|
|
156
|
-
e && this._bindInput(e);
|
|
169
|
+
super.connectedCallback(), w();
|
|
157
170
|
}
|
|
158
171
|
disconnectedCallback() {
|
|
159
|
-
|
|
160
|
-
const e = this.
|
|
172
|
+
super.disconnectedCallback(), this._focused = !1, this._cancelPendingInput();
|
|
173
|
+
const e = this._$input();
|
|
161
174
|
e?.removeEventListener("input", this._onNativeInput), e?.removeEventListener("focus", this._onInputFocus), e?.removeEventListener("blur", this._onInputBlur), this._disabledObserver.disconnect();
|
|
162
175
|
}
|
|
163
176
|
updated(e) {
|
|
164
177
|
if (e.has("placeholder")) {
|
|
165
|
-
const
|
|
166
|
-
|
|
178
|
+
const t = this._$input();
|
|
179
|
+
t && this._applyPlaceholder(t);
|
|
167
180
|
}
|
|
168
181
|
}
|
|
169
|
-
|
|
170
|
-
return this.
|
|
182
|
+
_$input() {
|
|
183
|
+
return this._$inputRef?.deref() ?? null;
|
|
184
|
+
}
|
|
185
|
+
_handleSlotChange() {
|
|
186
|
+
this._inputController.sync();
|
|
171
187
|
}
|
|
172
|
-
|
|
173
|
-
|
|
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) {
|
|
188
|
+
_setupInput(e, t) {
|
|
189
|
+
if (t && t !== e && (t.removeEventListener("input", this._onNativeInput), t.removeEventListener("focus", this._onInputFocus), t.removeEventListener("blur", this._onInputBlur)), this._disabledObserver.disconnect(), this._focused = !1, this._$inputRef = e ? new WeakRef(e) : null, this._hasInput = e !== null, this._authorPlaceholder = e?.hasAttribute("placeholder") ?? !1, !e) {
|
|
177
190
|
this._hasValue = !1;
|
|
178
191
|
return;
|
|
179
192
|
}
|
|
180
193
|
queueMicrotask(() => {
|
|
181
|
-
|
|
194
|
+
e.isConnected && (this._valueSetByHost ? e.value = this._value ?? "" : e.value ? this._valueInitialized = !0 : this._defaultValue !== void 0 && !this._valueInitialized && (e.value = this._defaultValue), this._applyPlaceholder(e), this._disabledHost !== void 0 && (e.disabled = this._disabledHost), this._inputDisabled = e.disabled, this._hasValue = e.value.length > 0, this._bindInput(e));
|
|
182
195
|
});
|
|
183
196
|
}
|
|
184
197
|
_bindInput(e) {
|
|
@@ -209,7 +222,7 @@ const d = class d extends b {
|
|
|
209
222
|
);
|
|
210
223
|
}
|
|
211
224
|
_handleClear() {
|
|
212
|
-
const e = this.
|
|
225
|
+
const e = this._$input();
|
|
213
226
|
e && (this._cancelPendingInput(), e.value = "", this._valueInitialized = !0, this._hasValue = !1, this.dispatchEvent(
|
|
214
227
|
new CustomEvent("rc-search-bar-clear", {
|
|
215
228
|
bubbles: !0,
|
|
@@ -220,31 +233,31 @@ const d = class d extends b {
|
|
|
220
233
|
}
|
|
221
234
|
render() {
|
|
222
235
|
return v`
|
|
223
|
-
<div id="root" part="root" class=${
|
|
236
|
+
<div id="root" part="root" class=${d({ empty: !this._hasInput })} ${m({ attributeTarget: this })}>
|
|
224
237
|
<span
|
|
225
238
|
id="leading"
|
|
226
239
|
part="leading"
|
|
227
|
-
class=${
|
|
240
|
+
class=${d({ empty: !this._hasLeading || !this._hasInput })}
|
|
228
241
|
>
|
|
229
242
|
<slot name="leading" @slotchange=${this._onLeadingSlotChange}></slot>
|
|
230
243
|
</span>
|
|
244
|
+
|
|
231
245
|
<slot @slotchange=${this._handleSlotChange}></slot>
|
|
246
|
+
|
|
232
247
|
<button
|
|
233
248
|
id="clear"
|
|
234
249
|
part="clear"
|
|
235
250
|
type="button"
|
|
236
251
|
aria-label=${this.clearLabel}
|
|
237
|
-
?hidden=${!this._hasInput
|
|
252
|
+
?hidden=${!this._hasInput}
|
|
253
|
+
?inert=${this._hasInput && !this._hasValue && !(this.showClearOnFocus && this._focused)}
|
|
238
254
|
?disabled=${this._inputDisabled}
|
|
239
255
|
@click=${this._handleClear}
|
|
240
256
|
>
|
|
241
257
|
<slot name="clear-icon"><span aria-hidden="true">✕</span></slot>
|
|
242
258
|
</button>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
part="trailing"
|
|
246
|
-
class=${h({ empty: !this._hasTrailing })}
|
|
247
|
-
>
|
|
259
|
+
|
|
260
|
+
<span id="trailing" part="trailing" class=${d({ empty: !this._hasTrailing })}>
|
|
248
261
|
<slot name="trailing" @slotchange=${this._onTrailingSlotChange}></slot>
|
|
249
262
|
</span>
|
|
250
263
|
</div>
|
|
@@ -255,59 +268,59 @@ const d = class d extends b {
|
|
|
255
268
|
this._handleClear();
|
|
256
269
|
}
|
|
257
270
|
_onLeadingSlotChange(e) {
|
|
258
|
-
const
|
|
259
|
-
this._hasLeading =
|
|
271
|
+
const t = e.target;
|
|
272
|
+
this._hasLeading = t.assignedElements().length > 0;
|
|
260
273
|
}
|
|
261
274
|
_onTrailingSlotChange(e) {
|
|
262
|
-
const
|
|
263
|
-
this._hasTrailing =
|
|
275
|
+
const t = e.target;
|
|
276
|
+
this._hasTrailing = t.assignedElements().length > 0;
|
|
264
277
|
}
|
|
265
278
|
};
|
|
266
|
-
|
|
267
|
-
let
|
|
279
|
+
u.styles = [y];
|
|
280
|
+
let i = u;
|
|
268
281
|
a([
|
|
269
282
|
r({ type: Number })
|
|
270
|
-
],
|
|
283
|
+
], i.prototype, "debounce", 2);
|
|
271
284
|
a([
|
|
272
285
|
r({ type: String, attribute: "clear-label" })
|
|
273
|
-
],
|
|
286
|
+
], i.prototype, "clearLabel", 2);
|
|
274
287
|
a([
|
|
275
288
|
r({ type: Boolean, attribute: "allow-native-clear", reflect: !0 })
|
|
276
|
-
],
|
|
289
|
+
], i.prototype, "allowNativeClear", 2);
|
|
277
290
|
a([
|
|
278
291
|
r({ type: Boolean, attribute: "show-clear-on-focus" })
|
|
279
|
-
],
|
|
292
|
+
], i.prototype, "showClearOnFocus", 2);
|
|
280
293
|
a([
|
|
281
294
|
r({ type: Boolean, reflect: !0 })
|
|
282
|
-
],
|
|
295
|
+
], i.prototype, "disabled", 1);
|
|
283
296
|
a([
|
|
284
297
|
r({ type: String })
|
|
285
|
-
],
|
|
298
|
+
], i.prototype, "placeholder", 2);
|
|
286
299
|
a([
|
|
287
|
-
|
|
288
|
-
],
|
|
300
|
+
l()
|
|
301
|
+
], i.prototype, "_hasInput", 2);
|
|
289
302
|
a([
|
|
290
|
-
|
|
291
|
-
],
|
|
303
|
+
l()
|
|
304
|
+
], i.prototype, "_hasValue", 2);
|
|
292
305
|
a([
|
|
293
|
-
|
|
294
|
-
],
|
|
306
|
+
l()
|
|
307
|
+
], i.prototype, "_hasLeading", 2);
|
|
295
308
|
a([
|
|
296
|
-
|
|
297
|
-
],
|
|
309
|
+
l()
|
|
310
|
+
], i.prototype, "_hasTrailing", 2);
|
|
298
311
|
a([
|
|
299
|
-
|
|
300
|
-
],
|
|
312
|
+
l()
|
|
313
|
+
], i.prototype, "_inputDisabled", 2);
|
|
301
314
|
a([
|
|
302
|
-
|
|
303
|
-
],
|
|
315
|
+
l()
|
|
316
|
+
], i.prototype, "_focused", 2);
|
|
304
317
|
a([
|
|
305
318
|
r({ attribute: !1 })
|
|
306
|
-
],
|
|
319
|
+
], i.prototype, "value", 1);
|
|
307
320
|
a([
|
|
308
321
|
r({ type: String, attribute: "default-value" })
|
|
309
|
-
],
|
|
322
|
+
], i.prototype, "defaultValue", 1);
|
|
310
323
|
export {
|
|
311
|
-
|
|
324
|
+
i as R
|
|
312
325
|
};
|
|
313
|
-
//# sourceMappingURL=rc-search-bar-
|
|
326
|
+
//# sourceMappingURL=rc-search-bar-DVczVFvA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-search-bar-DVczVFvA.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, var(--rc-control-gap, 0.25em));\n block-size: var(--rc-search-bar-height, var(--rc-control-block-size, 2.5rem));\n padding-inline: var(--rc-search-bar-padding-inline, var(--rc-control-padding-inline, 0.75rem));\n border: var(--rc-search-bar-border, var(--rc-border, 1px solid var(--rc-border-color, ButtonBorder)));\n border-radius: var(--rc-search-bar-radius, var(--rc-control-radius, var(--rc-radius-sm, 0.125em)));\n box-shadow: var(--rc-search-bar-shadow, none);\n background: var(--rc-search-bar-bg, var(--rc-field, Field));\n color: var(--rc-search-bar-color, var(--rc-field-text, FieldText));\n font-family: var(--rc-font-family, inherit);\n font-size: var(--rc-font-size, inherit);\n line-height: var(--rc-line-height, normal);\n transition: background-color 120ms, border-color 120ms, box-shadow 120ms;\n }\n\n :host([data-interaction-mode='keyboard']) #root:focus-within {\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: none;\n box-shadow: 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 padding: 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 appearance: textfield;\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[inert] {\n visibility: hidden;\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 { NativeChildController, keyInteraction, warnMissingDirectChild } from '@rcarls/rc-common';\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) {\n return;\n }\n\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, _uaClearSheet];\n\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 * Search field wrapper for a native <input type=\"search\"> with icon chrome, clear button,\n * and debounced 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 * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-search-bar rc-search-bar docs}\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 *\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 *\n * @cssprop [--rc-search-bar-border=1px solid ButtonBorder] - Wrapper border; set to `none` in M3 theme (uses elevation instead)\n * @cssprop [--rc-search-bar-shadow=none] - Wrapper box-shadow for elevation; M3 theme sets Level 1 at rest\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,0.125em)] - Wrapper border radius\n * @cssprop [--rc-search-bar-height=var(--rc-control-block-size,2.5rem)] - Wrapper block size\n * @cssprop [--rc-search-bar-padding-inline=var(--rc-control-padding-inline,0.75rem)] - Wrapper horizontal padding\n * @cssprop [--rc-search-bar-gap=var(--rc-control-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 *\n * 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\n const $input = this._$input();\n if ($input) {\n $input.disabled = value;\n }\n\n this.requestUpdate('disabled', old);\n }\n\n /**\n * Placeholder mirrored onto the native input.\n *\n * Consumer `placeholder` attribute is always honored.\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 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\n if ($input) {\n this._inputDisabled = $input.disabled;\n }\n });\n\n private readonly _inputController = new NativeChildController<HTMLInputElement>(this, {\n selector: ':scope > input[type=\"search\"]',\n observe: true,\n onChange: ($input, $previousInput) => this._setupInput($input, $previousInput),\n onMissing: () => {\n if (import.meta.env.DEV) {\n warnMissingDirectChild(this, {\n selector: ':scope > input[type=\"search\"]',\n message:\n '[rc-search-bar] No direct child <input type=\"search\"> found. ' +\n 'Place a native search input inside <rc-search-bar>.',\n });\n }\n },\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\n if ($input) {\n $input.value = value;\n }\n\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\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\n _suppressUaClear();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n this._focused = false;\n this._cancelPendingInput();\n\n const $input = this._$input();\n\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\n if ($input) {\n this._applyPlaceholder($input);\n }\n }\n }\n\n private _$input(): HTMLInputElement | null {\n return this._$inputRef?.deref() ?? null;\n }\n\n private _handleSlotChange(): void {\n this._inputController.sync();\n }\n\n private _setupInput(\n $input: HTMLInputElement | null,\n $previousInput: HTMLInputElement | null,\n ): void {\n if ($previousInput && $previousInput !== $input) {\n $previousInput.removeEventListener('input', this._onNativeInput);\n $previousInput.removeEventListener('focus', this._onInputFocus);\n $previousInput.removeEventListener('blur', this._onInputBlur);\n }\n\n this._disabledObserver.disconnect();\n this._focused = false;\n\n this._$inputRef = $input ? new WeakRef($input) : null;\n this._hasInput = $input !== null;\n this._authorPlaceholder = $input?.hasAttribute('placeholder') ?? false;\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) {\n return;\n }\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._applyPlaceholder($input);\n\n if (this._disabledHost !== undefined) {\n $input.disabled = this._disabledHost;\n }\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\n this._disabledObserver.observe($input, { attributeFilter: ['disabled'] });\n }\n\n private _applyPlaceholder($input: HTMLInputElement): void {\n if (this.placeholder === undefined || this._authorPlaceholder) {\n return;\n }\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) {\n return;\n }\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\n if (!$input) {\n return;\n }\n\n this._cancelPendingInput();\n\n $input.value = '';\n\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 })} ${keyInteraction({ attributeTarget: this })}>\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\n <slot @slotchange=${this._handleSlotChange}></slot>\n\n <button\n id=\"clear\"\n part=\"clear\"\n type=\"button\"\n aria-label=${this.clearLabel}\n ?hidden=${!this._hasInput}\n ?inert=${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\">✕</span></slot>\n </button>\n\n <span id=\"trailing\" part=\"trailing\" class=${classMap({ empty: !this._hasTrailing })}>\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\n this._hasLeading = $slot.assignedElements().length > 0;\n }\n\n private _onTrailingSlotChange(e: Event): void {\n const $slot = e.target as HTMLSlotElement;\n\n this._hasTrailing = $slot.assignedElements().length > 0;\n }\n}\n\nexport default RCSearchBar;\n"],"names":["searchBarStyles","css","_uaClearSheet","_uaClearSuppressed","_suppressUaClear","_RCSearchBar","LitElement","$input","NativeChildController","$previousInput","value","old","oldValue","changed","html","classMap","keyInteraction","$slot","RCSearchBar","__decorateClass","property","state"],"mappings":"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"}
|
package/dist/rc-search-bar.js
CHANGED
|
@@ -9,8 +9,8 @@ export interface RCSearchBarInputDetail {
|
|
|
9
9
|
value: string;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Search field wrapper for a native <input type="search"> with icon chrome, clear button,
|
|
13
|
+
* and debounced events.
|
|
14
14
|
*
|
|
15
15
|
* The native input is required and stays in light DOM as the source of
|
|
16
16
|
* truth, so form submission, `label[for]`/wrapping-label association, and
|
|
@@ -23,21 +23,27 @@ export interface RCSearchBarInputDetail {
|
|
|
23
23
|
* (a debounced `rc-search-bar-input` with an empty value) and never fires
|
|
24
24
|
* `rc-search-bar-clear`.
|
|
25
25
|
*
|
|
26
|
+
* @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-search-bar rc-search-bar docs}
|
|
27
|
+
*
|
|
26
28
|
* @slot - The required native `<input type="search">`
|
|
27
29
|
* @slot leading - Decorative leading icon; mark it `aria-hidden="true"`
|
|
28
30
|
* @slot trailing - Optional trailing content after the clear button
|
|
29
31
|
* @slot clear-icon - Optional glyph replacing the default clear glyph
|
|
32
|
+
*
|
|
30
33
|
* @fires rc-search-bar-input - Debounced after typing, immediate on clear;
|
|
31
34
|
* `detail: { value }`
|
|
32
35
|
* @fires rc-search-bar-clear - When the clear button is activated
|
|
36
|
+
*
|
|
37
|
+
* @cssprop [--rc-search-bar-border=1px solid ButtonBorder] - Wrapper border; set to `none` in M3 theme (uses elevation instead)
|
|
38
|
+
* @cssprop [--rc-search-bar-shadow=none] - Wrapper box-shadow for elevation; M3 theme sets Level 1 at rest
|
|
33
39
|
* @cssprop [--rc-search-bar-bg=Field] - Wrapper background
|
|
34
40
|
* @cssprop [--rc-search-bar-color=FieldText] - Wrapper text color
|
|
35
41
|
* @cssprop [--rc-search-bar-icon-color=GrayText] - Leading icon color
|
|
36
42
|
* @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=
|
|
39
|
-
* @cssprop [--rc-search-bar-padding-inline=0.
|
|
40
|
-
* @cssprop [--rc-search-bar-gap=0.25em] - Gap between icon, input, and clear button
|
|
43
|
+
* @cssprop [--rc-search-bar-radius=var(--rc-control-radius,0.125em)] - Wrapper border radius
|
|
44
|
+
* @cssprop [--rc-search-bar-height=var(--rc-control-block-size,2.5rem)] - Wrapper block size
|
|
45
|
+
* @cssprop [--rc-search-bar-padding-inline=var(--rc-control-padding-inline,0.75rem)] - Wrapper horizontal padding
|
|
46
|
+
* @cssprop [--rc-search-bar-gap=var(--rc-control-gap,0.25em)] - Gap between icon, input, and clear button
|
|
41
47
|
* @cssprop [--rc-search-bar-input-font-size] - Input font size (inherits when unset)
|
|
42
48
|
* @cssprop [--rc-search-bar-input-font-family] - Input font family (inherits when unset)
|
|
43
49
|
* @cssprop [--rc-search-bar-input-color] - Input text color (inherits when unset)
|
|
@@ -55,8 +61,9 @@ export declare class RCSearchBar extends LitElement {
|
|
|
55
61
|
/** When set, leaves the browser's native WebKit cancel button visible. */
|
|
56
62
|
allowNativeClear: boolean;
|
|
57
63
|
/**
|
|
58
|
-
* When set, the clear button is visible whenever the input is focused
|
|
59
|
-
*
|
|
64
|
+
* When set, the clear button is visible whenever the input is focused.
|
|
65
|
+
*
|
|
66
|
+
* Matching the Apple HIG "cancel" pattern.
|
|
60
67
|
* Consider setting `clear-label="Cancel"` in this mode.
|
|
61
68
|
*/
|
|
62
69
|
showClearOnFocus: boolean;
|
|
@@ -64,8 +71,9 @@ export declare class RCSearchBar extends LitElement {
|
|
|
64
71
|
get disabled(): boolean;
|
|
65
72
|
set disabled(value: boolean);
|
|
66
73
|
/**
|
|
67
|
-
* Placeholder mirrored onto the native input.
|
|
68
|
-
*
|
|
74
|
+
* Placeholder mirrored onto the native input.
|
|
75
|
+
*
|
|
76
|
+
* Consumer `placeholder` attribute is always honored.
|
|
69
77
|
*/
|
|
70
78
|
placeholder?: string;
|
|
71
79
|
private _value;
|
|
@@ -74,7 +82,7 @@ export declare class RCSearchBar extends LitElement {
|
|
|
74
82
|
/** True once an author value, host write, or user input owns the value. */
|
|
75
83
|
private _valueInitialized;
|
|
76
84
|
private _authorPlaceholder;
|
|
77
|
-
private
|
|
85
|
+
private _$inputRef;
|
|
78
86
|
private _debounceTimer;
|
|
79
87
|
private _hasInput;
|
|
80
88
|
private _hasValue;
|
|
@@ -83,13 +91,10 @@ export declare class RCSearchBar extends LitElement {
|
|
|
83
91
|
private _inputDisabled;
|
|
84
92
|
private _disabledHost;
|
|
85
93
|
private _focused;
|
|
86
|
-
private _lastInteractionWasPointer;
|
|
87
|
-
private readonly _onPointerDown;
|
|
88
|
-
private readonly _onFocusIn;
|
|
89
|
-
private readonly _onFocusOut;
|
|
90
94
|
private readonly _onInputFocus;
|
|
91
95
|
private readonly _onInputBlur;
|
|
92
96
|
private readonly _disabledObserver;
|
|
97
|
+
private readonly _inputController;
|
|
93
98
|
/**
|
|
94
99
|
* The current search value. Reads from the native input when present.
|
|
95
100
|
* Host writes are silent (no events) and win over slotted author values.
|
|
@@ -105,8 +110,9 @@ export declare class RCSearchBar extends LitElement {
|
|
|
105
110
|
connectedCallback(): void;
|
|
106
111
|
disconnectedCallback(): void;
|
|
107
112
|
protected updated(changed: PropertyValues<this>): void;
|
|
108
|
-
private
|
|
113
|
+
private _$input;
|
|
109
114
|
private _handleSlotChange;
|
|
115
|
+
private _setupInput;
|
|
110
116
|
private _bindInput;
|
|
111
117
|
private _applyPlaceholder;
|
|
112
118
|
private readonly _onNativeInput;
|
package/package.json
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
7
|
-
"description": "
|
|
6
|
+
"version": "0.3.0",
|
|
7
|
+
"description": "Search field wrapper for a native <input type=\"search\"> with icon chrome, clear button, and debounced events.",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
11
|
"directory": "packages/rc-search-bar"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://github.
|
|
13
|
+
"homepage": "https://richardcarls.github.io/rc-webcomponents/components/rc-search-bar",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"files": [
|
|
@@ -37,18 +37,15 @@
|
|
|
37
37
|
],
|
|
38
38
|
"customElements": "dist/custom-elements.json",
|
|
39
39
|
"scripts": {
|
|
40
|
-
"dev": "vite",
|
|
41
40
|
"build": "tsc && vite build && cem analyze",
|
|
42
41
|
"cem:analyze": "cem analyze",
|
|
43
42
|
"preview": "vite preview",
|
|
44
|
-
"test:browser": "vitest",
|
|
45
|
-
"test:browser:chrome": "vitest --project=chromium",
|
|
46
|
-
"test:browser:firefox": "vitest --project=firefox"
|
|
47
|
-
"yalc:publish": "yalc publish --push"
|
|
43
|
+
"test:browser": "vitest --run",
|
|
44
|
+
"test:browser:chrome": "vitest --run --project=chromium",
|
|
45
|
+
"test:browser:firefox": "vitest --run --project=firefox"
|
|
48
46
|
},
|
|
49
47
|
"devDependencies": {
|
|
50
48
|
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
51
|
-
"@guanghechen/rollup-plugin-copy": "^6.0.9",
|
|
52
49
|
"@vitest/browser-playwright": "4.1.5",
|
|
53
50
|
"lit": "^3.0.0",
|
|
54
51
|
"playwright": "^1.56.0",
|
|
@@ -61,5 +58,8 @@
|
|
|
61
58
|
},
|
|
62
59
|
"peerDependencies": {
|
|
63
60
|
"lit": "^3.0.0"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@rcarls/rc-common": "workspace:*"
|
|
64
64
|
}
|
|
65
65
|
}
|
package/dist/demo.css
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
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\">✕</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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"}
|