-
-
Notifications
You must be signed in to change notification settings - Fork 260
Expand file tree
/
Copy pathSearch.svelte
More file actions
200 lines (178 loc) · 4.94 KB
/
Copy pathSearch.svelte
File metadata and controls
200 lines (178 loc) · 4.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
<script>
/**
* @template [T=any]
* @template [Icon=any]
* @event {null} expand
* @event {null} collapse
* @restProps {input}
*/
/**
* Specify the value of the search input.
* @type {T}
* @bindable writable
*/
export let value = /** @type {T} */ ("");
/**
* Specify the size of the search input.
* @type {"xs" | "sm" | "lg" | "xl"}
*/
export let size = "xl";
/** Specify the class name passed to the outer div element */
export let searchClass = "";
/** Set to `true` to display the skeleton state */
export let skeleton = false;
/** Set to `true` to enable the light variant */
export let light = false;
/** Set to `true` to disable the search input */
export let disabled = false;
/** Set to `true` to enable the expandable variant */
export let expandable = false;
/**
* Set to `true to expand the search input.
* @bindable writable
*/
export let expanded = false;
/**
* Set to `true` to use the fluid variant.
* Inherited from the parent `FluidForm` context,
* so it does not need to be set when used inside `FluidForm`.
* Cannot be combined with the expandable variant.
*/
export let fluid = false;
/** Specify the `placeholder` attribute of the search input */
export let placeholder = "Search...";
/**
* Specify the `autocomplete` attribute.
* @type {"on" | "off"}
*/
export let autocomplete = "off";
/** Set to `true` to auto focus the search element */
export let autofocus = false;
/** Specify the close button label text */
export let closeButtonLabelText = "Clear search input";
/** Specify the label text */
export let labelText = "";
/**
* Specify the icon to render.
* @type {Icon}
*/
export let icon = /** @type {Icon} */ (IconSearch);
/** Set an id for the input element */
export let id = `ccs-${Math.random().toString(36)}`;
/**
* Obtain a reference to the input HTML element.
* @bindable readonly
*/
export let ref = null;
import { createEventDispatcher, getContext } from "svelte";
import Close from "../icons/Close.svelte";
import IconSearch from "../icons/IconSearch.svelte";
import SearchSkeleton from "./SearchSkeleton.svelte";
const dispatch = createEventDispatcher();
const formContext = getContext("carbon:Form");
let searchRef = null;
let prevExpanded = expanded;
$: isFluid = !expandable && (fluid || !!formContext?.isFluid);
$: if (expanded && ref) ref.focus();
$: if (expanded !== prevExpanded) {
dispatch(expanded ? "expand" : "collapse");
prevExpanded = expanded;
}
</script>
<!-- svelte-ignore a11y-autofocus -->
{#if skeleton}
<SearchSkeleton
{size}
{...$$restProps}
on:click
on:mouseover
on:mouseenter
on:mouseleave
/>
{:else}
<div
role="search"
aria-labelledby="{id}-search"
class:bx--search={true}
class:bx--search--light={light}
class:bx--search--disabled={disabled}
class:bx--search--xs={size === "xs"}
class:bx--search--sm={size === "sm"}
class:bx--search--lg={size === "lg"}
class:bx--search--xl={size === "xl"}
class:bx--search--expandable={expandable}
class:bx--search--expanded={expanded}
class:bx--search--fluid={isFluid}
class={searchClass}
>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
bind:this={searchRef}
class:bx--search-magnifier={true}
on:click={() => {
if (expandable) expanded = true;
}}
>
<svelte:component this={icon} class="bx--search-magnifier-icon" />
</div>
<label
id="{id}-search"
for={id}
class:bx--label={true}
class:bx--label--slotted={isFluid && $$slots.labelChildren}
>
<slot name="labelChildren"> {labelText} </slot>
</label>
<!-- svelte-ignore a11y-autofocus -->
<input
bind:this={ref}
bind:value
type="text"
role="searchbox"
class:bx--search-input={true}
autofocus={autofocus === true ? true : undefined}
{autocomplete}
{disabled}
{id}
{placeholder}
{...$$restProps}
on:change
on:input
on:focus
on:focus={() => {
if (expandable) expanded = true;
}}
on:blur
on:blur={() => {
if (expanded && (value === "" || value == null)) {
expanded = false;
}
}}
on:keydown
on:keydown={(event) => {
if (event.key === "Escape") {
value = "";
dispatch("clear");
}
}}
on:keyup
on:paste
>
<button
type="button"
aria-label={closeButtonLabelText}
{disabled}
class:bx--search-close={true}
class:bx--search-close--hidden={value === "" || value == null}
on:click
on:click={() => {
value = "";
ref.focus();
dispatch("clear");
}}
>
<svelte:component this={Close} size={size === "xl" ? 20 : 16} />
</button>
</div>
{/if}