@safestrong/ppa-component-library 1.7.3 → 1.8.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/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +214 -77
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +214 -77
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +31 -19
- package/package.json +13 -6
package/dist/index.d.mts
CHANGED
|
@@ -19,11 +19,13 @@ declare namespace Button {
|
|
|
19
19
|
}) => React.JSX.Element;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
declare function TextInput({ label, labelFor, icon, outerclass, ...attr }: Readonly<React.InputHTMLAttributes<HTMLInputElement> & {
|
|
22
|
+
declare function TextInput({ label, labelFor, icon, outerclass, isdarkmode, inputclass, ...attr }: Readonly<React.InputHTMLAttributes<HTMLInputElement> & {
|
|
23
23
|
label?: string;
|
|
24
24
|
labelFor?: string;
|
|
25
25
|
icon?: IconProp;
|
|
26
26
|
outerclass?: string;
|
|
27
|
+
isdarkmode?: boolean;
|
|
28
|
+
inputclass?: string;
|
|
27
29
|
}>): React.JSX.Element;
|
|
28
30
|
|
|
29
31
|
declare function Slider(attr: Readonly<React.InputHTMLAttributes<HTMLInputElement>>): React.JSX.Element;
|
|
@@ -34,6 +36,7 @@ type SingleSelect = React.InputHTMLAttributes<HTMLInputElement> & {
|
|
|
34
36
|
placeholder?: string;
|
|
35
37
|
stateaction?: (param: any) => void;
|
|
36
38
|
outerclass?: string;
|
|
39
|
+
isdarkmode?: boolean;
|
|
37
40
|
options?: {
|
|
38
41
|
label: string;
|
|
39
42
|
value: string;
|
|
@@ -113,6 +116,7 @@ type MultiSelect = {
|
|
|
113
116
|
label?: string;
|
|
114
117
|
labelHtml?: string;
|
|
115
118
|
outerclass?: string;
|
|
119
|
+
isdarkmode?: boolean;
|
|
116
120
|
options?: Option[];
|
|
117
121
|
stringOptions?: string[];
|
|
118
122
|
state: {
|
package/dist/index.d.ts
CHANGED
|
@@ -19,11 +19,13 @@ declare namespace Button {
|
|
|
19
19
|
}) => React.JSX.Element;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
declare function TextInput({ label, labelFor, icon, outerclass, ...attr }: Readonly<React.InputHTMLAttributes<HTMLInputElement> & {
|
|
22
|
+
declare function TextInput({ label, labelFor, icon, outerclass, isdarkmode, inputclass, ...attr }: Readonly<React.InputHTMLAttributes<HTMLInputElement> & {
|
|
23
23
|
label?: string;
|
|
24
24
|
labelFor?: string;
|
|
25
25
|
icon?: IconProp;
|
|
26
26
|
outerclass?: string;
|
|
27
|
+
isdarkmode?: boolean;
|
|
28
|
+
inputclass?: string;
|
|
27
29
|
}>): React.JSX.Element;
|
|
28
30
|
|
|
29
31
|
declare function Slider(attr: Readonly<React.InputHTMLAttributes<HTMLInputElement>>): React.JSX.Element;
|
|
@@ -34,6 +36,7 @@ type SingleSelect = React.InputHTMLAttributes<HTMLInputElement> & {
|
|
|
34
36
|
placeholder?: string;
|
|
35
37
|
stateaction?: (param: any) => void;
|
|
36
38
|
outerclass?: string;
|
|
39
|
+
isdarkmode?: boolean;
|
|
37
40
|
options?: {
|
|
38
41
|
label: string;
|
|
39
42
|
value: string;
|
|
@@ -113,6 +116,7 @@ type MultiSelect = {
|
|
|
113
116
|
label?: string;
|
|
114
117
|
labelHtml?: string;
|
|
115
118
|
outerclass?: string;
|
|
119
|
+
isdarkmode?: boolean;
|
|
116
120
|
options?: Option[];
|
|
117
121
|
stringOptions?: string[];
|
|
118
122
|
state: {
|
package/dist/index.js
CHANGED
|
@@ -147,25 +147,56 @@ function getBtnClass(idx) {
|
|
|
147
147
|
// src/components/TextInput.tsx
|
|
148
148
|
var import_react2 = __toESM(require("react"));
|
|
149
149
|
var import_react_fontawesome2 = require("@fortawesome/react-fontawesome");
|
|
150
|
-
var input__icon = "w-[2rem] p-[0.9rem] px-[0.7rem] text-[1.2rem] bg-[var(--color-background-icon)] text-[var(--color-icon-input)] mr-2 group-focus-within:text-[var(--color-primary)]";
|
|
150
|
+
var input__icon = "w-[2rem] p-[0.9rem] px-[0.7rem] text-[1.2rem] bg-[var(--color-background-icon)] text-[var(--color-icon-input)] mr-2 group-focus-within:text-[var(--color-primary)] ";
|
|
151
151
|
function TextInput(_a) {
|
|
152
152
|
var _b = _a, {
|
|
153
153
|
label,
|
|
154
154
|
labelFor,
|
|
155
155
|
icon,
|
|
156
|
-
outerclass
|
|
156
|
+
outerclass,
|
|
157
|
+
isdarkmode,
|
|
158
|
+
inputclass
|
|
157
159
|
} = _b, attr = __objRest(_b, [
|
|
158
160
|
"label",
|
|
159
161
|
"labelFor",
|
|
160
162
|
"icon",
|
|
161
|
-
"outerclass"
|
|
163
|
+
"outerclass",
|
|
164
|
+
"isdarkmode",
|
|
165
|
+
"inputclass"
|
|
162
166
|
]);
|
|
163
|
-
|
|
164
|
-
"
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
function getThemedClass(prefix) {
|
|
168
|
+
return `var(--color${isdarkmode ? "-dark" : ""}${prefix})`;
|
|
169
|
+
}
|
|
170
|
+
return /* @__PURE__ */ import_react2.default.createElement("div", { className: `group ${outerclass} w-full` }, label && /* @__PURE__ */ import_react2.default.createElement(
|
|
171
|
+
"label",
|
|
172
|
+
{
|
|
173
|
+
htmlFor: labelFor,
|
|
174
|
+
className: "text-input__label",
|
|
175
|
+
style: {
|
|
176
|
+
color: getThemedClass("-text-secondary")
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
label
|
|
180
|
+
), /* @__PURE__ */ import_react2.default.createElement(
|
|
181
|
+
"div",
|
|
182
|
+
{
|
|
183
|
+
className: `text-input__wrapper overflow-hidden ${attr.className}`,
|
|
184
|
+
style: {
|
|
185
|
+
borderColor: getThemedClass("-border"),
|
|
186
|
+
background: getThemedClass("-bg-surface")
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
icon && /* @__PURE__ */ import_react2.default.createElement(import_react_fontawesome2.FontAwesomeIcon, { icon, className: input__icon }),
|
|
190
|
+
/* @__PURE__ */ import_react2.default.createElement(
|
|
191
|
+
"input",
|
|
192
|
+
__spreadProps(__spreadValues({}, attr), {
|
|
193
|
+
className: `text-input w-full ${icon && "!pl-[0.3rem]"} ${inputclass}`,
|
|
194
|
+
style: {
|
|
195
|
+
color: getThemedClass("-text-primary")
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
)
|
|
199
|
+
));
|
|
169
200
|
}
|
|
170
201
|
|
|
171
202
|
// src/components/Slider.tsx
|
|
@@ -189,13 +220,15 @@ var import_react_fontawesome4 = require("@fortawesome/react-fontawesome");
|
|
|
189
220
|
var import_free_solid_svg_icons3 = require("@fortawesome/free-solid-svg-icons");
|
|
190
221
|
function SingleSelect(attr) {
|
|
191
222
|
var _b;
|
|
192
|
-
const _a = attr, { options = [], stringOptions = [] } = _a, attrInput = __objRest(_a, ["options", "stringOptions"]);
|
|
223
|
+
const _a = attr, { options = [], stringOptions = [], isdarkmode } = _a, attrInput = __objRest(_a, ["options", "stringOptions", "isdarkmode"]);
|
|
224
|
+
const inputValue = attrInput.value;
|
|
193
225
|
const [keyword, setKeyword] = (0, import_react4.useState)("");
|
|
194
226
|
const [selected, setSelected] = (0, import_react4.useState)({
|
|
195
227
|
label: "",
|
|
196
228
|
value: ""
|
|
197
229
|
});
|
|
198
230
|
function selectItem({ label, value }, e) {
|
|
231
|
+
var _a2;
|
|
199
232
|
const triggerManual = attrInput.onChange;
|
|
200
233
|
if (triggerManual) {
|
|
201
234
|
triggerManual == null ? void 0 : triggerManual({
|
|
@@ -203,14 +236,9 @@ function SingleSelect(attr) {
|
|
|
203
236
|
});
|
|
204
237
|
}
|
|
205
238
|
setSelected({ label, value });
|
|
206
|
-
|
|
207
|
-
if (stringOptions) attr.stateaction(value);
|
|
208
|
-
if (options) attr.stateaction({ label, value });
|
|
209
|
-
}
|
|
239
|
+
(_a2 = attr.stateaction) == null ? void 0 : _a2.call(attr, stringOptions ? value : { label, value });
|
|
210
240
|
setKeyword("");
|
|
211
|
-
|
|
212
|
-
e.target.blur();
|
|
213
|
-
}, 250);
|
|
241
|
+
e.currentTarget.blur();
|
|
214
242
|
}
|
|
215
243
|
function autoUpdateValue(updatedValue) {
|
|
216
244
|
if (updatedValue) {
|
|
@@ -232,40 +260,91 @@ function SingleSelect(attr) {
|
|
|
232
260
|
);
|
|
233
261
|
}, [keyword, availableOptions]);
|
|
234
262
|
(0, import_react4.useEffect)(() => {
|
|
235
|
-
|
|
236
|
-
}, [
|
|
237
|
-
|
|
238
|
-
"
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
"input",
|
|
263
|
+
inputValue && autoUpdateValue(inputValue);
|
|
264
|
+
}, [inputValue]);
|
|
265
|
+
function getThemedClass(prefix) {
|
|
266
|
+
return `var(--color${isdarkmode ? "-dark" : ""}${prefix})`;
|
|
267
|
+
}
|
|
268
|
+
const placeholderClass = `${input2} select-item-placeholder-${isdarkmode ? "dark" : ""}`;
|
|
269
|
+
const optionHoverClass = `select-item-hover${isdarkmode ? "-dark" : ""}`;
|
|
270
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: `w-full group ${attr.outerclass}` }, attrInput.label && /* @__PURE__ */ import_react4.default.createElement(
|
|
271
|
+
"label",
|
|
245
272
|
{
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
"button",
|
|
273
|
+
className: "text-input__label",
|
|
274
|
+
htmlFor: attrInput.labelHtml,
|
|
275
|
+
style: { color: getThemedClass("-text-secondary") }
|
|
276
|
+
},
|
|
277
|
+
attrInput.label
|
|
278
|
+
), /* @__PURE__ */ import_react4.default.createElement(
|
|
279
|
+
"div",
|
|
254
280
|
{
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
281
|
+
className: `${attrInput.className} text-input__wrapper relative`,
|
|
282
|
+
style: {
|
|
283
|
+
borderColor: getThemedClass("-border"),
|
|
284
|
+
background: getThemedClass("-bg-surface")
|
|
285
|
+
}
|
|
259
286
|
},
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
287
|
+
/* @__PURE__ */ import_react4.default.createElement(
|
|
288
|
+
"input",
|
|
289
|
+
__spreadProps(__spreadValues(__spreadValues({
|
|
290
|
+
type: "hidden"
|
|
291
|
+
}, attrInput), attrInput.onChange ? { onChange: attrInput.onChange } : {}), {
|
|
292
|
+
value: (_b = attrInput.value) != null ? _b : selected.value
|
|
293
|
+
})
|
|
294
|
+
),
|
|
295
|
+
/* @__PURE__ */ import_react4.default.createElement(
|
|
296
|
+
"input",
|
|
263
297
|
{
|
|
264
|
-
|
|
265
|
-
|
|
298
|
+
type: "search",
|
|
299
|
+
value: keyword,
|
|
300
|
+
autoComplete: "off",
|
|
301
|
+
onChange: (e) => setKeyword(e.target.value),
|
|
302
|
+
className: `${attrInput.name}-keyword ${placeholderClass}`,
|
|
303
|
+
placeholder: selected.value ? selected.label : attrInput.placeholder,
|
|
304
|
+
style: {
|
|
305
|
+
color: selected.value ? getThemedClass("-text-primary") : void 0
|
|
306
|
+
}
|
|
266
307
|
}
|
|
267
|
-
)
|
|
268
|
-
|
|
308
|
+
),
|
|
309
|
+
/* @__PURE__ */ import_react4.default.createElement(
|
|
310
|
+
"div",
|
|
311
|
+
{
|
|
312
|
+
className: "select-item__wrapper",
|
|
313
|
+
style: {
|
|
314
|
+
borderColor: getThemedClass("-border"),
|
|
315
|
+
background: getThemedClass("-bg-surface")
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
filteredOptions.length == 0 && keyword != "" && /* @__PURE__ */ import_react4.default.createElement(
|
|
319
|
+
"button",
|
|
320
|
+
{
|
|
321
|
+
disabled: true,
|
|
322
|
+
className: "select-item",
|
|
323
|
+
style: { color: "var(--color-danger)" }
|
|
324
|
+
},
|
|
325
|
+
"Tidak ada Item"
|
|
326
|
+
),
|
|
327
|
+
filteredOptions.map(({ label, value }) => /* @__PURE__ */ import_react4.default.createElement(
|
|
328
|
+
"button",
|
|
329
|
+
{
|
|
330
|
+
key: value,
|
|
331
|
+
type: "button",
|
|
332
|
+
className: `select-item ${optionHoverClass}`,
|
|
333
|
+
onClick: (e) => selectItem({ label, value }, e),
|
|
334
|
+
style: { color: getThemedClass("-text-secondary") }
|
|
335
|
+
},
|
|
336
|
+
label,
|
|
337
|
+
selected.value == value && /* @__PURE__ */ import_react4.default.createElement(
|
|
338
|
+
import_react_fontawesome4.FontAwesomeIcon,
|
|
339
|
+
{
|
|
340
|
+
icon: import_free_solid_svg_icons3.faCheck,
|
|
341
|
+
style: { color: "var(--color-info)" }
|
|
342
|
+
}
|
|
343
|
+
)
|
|
344
|
+
))
|
|
345
|
+
),
|
|
346
|
+
/* @__PURE__ */ import_react4.default.createElement(import_react_fontawesome4.FontAwesomeIcon, { icon: import_free_solid_svg_icons3.faChevronDown, style: { color: getThemedClass("-icon-input"), paddingRight: "0.7rem" } })
|
|
347
|
+
));
|
|
269
348
|
}
|
|
270
349
|
SingleSelect.autoFill = autoFillInput;
|
|
271
350
|
function autoFillInput(value, elName, list2) {
|
|
@@ -275,7 +354,6 @@ function autoFillInput(value, elName, list2) {
|
|
|
275
354
|
const el = document.querySelector(`.${elName}-keyword`);
|
|
276
355
|
el == null ? void 0 : el.setAttribute("placeholder", `${filtered == null ? void 0 : filtered.label}`);
|
|
277
356
|
}
|
|
278
|
-
var input__icon2 = "pr-[0.7rem] text-[var(--color-icon-input)]";
|
|
279
357
|
var input2 = "text-input peer ... w-full";
|
|
280
358
|
|
|
281
359
|
// src/components/Tooltip.tsx
|
|
@@ -422,8 +500,10 @@ function MultiSelect(_a) {
|
|
|
422
500
|
"label",
|
|
423
501
|
"labelHtml"
|
|
424
502
|
]);
|
|
425
|
-
const { options = [], stringOptions = [] } = attr;
|
|
503
|
+
const { options = [], stringOptions = [], isdarkmode } = attr;
|
|
426
504
|
const [keyword, setKeyword] = (0, import_react10.useState)("");
|
|
505
|
+
const optionHoverClass = `select-item-hover${isdarkmode ? "-dark" : ""}`;
|
|
506
|
+
const placeholderClass = `${input3} select-item-placeholder-${isdarkmode ? "dark" : ""}`;
|
|
427
507
|
const availableOptions = (0, import_react10.useMemo)(() => {
|
|
428
508
|
const isDefaultOption = options && options.length > 0;
|
|
429
509
|
if (!isDefaultOption)
|
|
@@ -451,42 +531,98 @@ function MultiSelect(_a) {
|
|
|
451
531
|
const isAllSelected = state.value.length == availableOptions.length;
|
|
452
532
|
state.select(isAllSelected ? [] : availableOptions);
|
|
453
533
|
}, [state.value]);
|
|
454
|
-
|
|
455
|
-
"
|
|
534
|
+
function getThemedClass(prefix) {
|
|
535
|
+
return `var(--color${isdarkmode ? "-dark" : ""}${prefix})`;
|
|
536
|
+
}
|
|
537
|
+
return /* @__PURE__ */ import_react10.default.createElement("div", { className: `group w-full ${attr.outerclass}` }, label && /* @__PURE__ */ import_react10.default.createElement(
|
|
538
|
+
"label",
|
|
456
539
|
{
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
"button",
|
|
540
|
+
htmlFor: labelHtml,
|
|
541
|
+
className: "text-input__label",
|
|
542
|
+
style: { color: getThemedClass("-text-secondary") }
|
|
543
|
+
},
|
|
544
|
+
label
|
|
545
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
546
|
+
"div",
|
|
465
547
|
{
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
548
|
+
className: "text-input__wrapper relative",
|
|
549
|
+
style: {
|
|
550
|
+
borderColor: getThemedClass("-border"),
|
|
551
|
+
background: getThemedClass("-bg-surface")
|
|
552
|
+
}
|
|
470
553
|
},
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
import_react_fontawesome7.FontAwesomeIcon,
|
|
554
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
555
|
+
"input",
|
|
474
556
|
{
|
|
475
|
-
|
|
476
|
-
|
|
557
|
+
type: "search",
|
|
558
|
+
value: keyword,
|
|
559
|
+
autoComplete: "off",
|
|
560
|
+
className: `${input3} ${placeholderClass}`,
|
|
561
|
+
onChange: (e) => setKeyword(e.target.value),
|
|
562
|
+
placeholder: `${state.value.length} Dipilih`,
|
|
563
|
+
style: {
|
|
564
|
+
color: state.value.length > 0 ? getThemedClass("-text-primary") : void 0
|
|
565
|
+
}
|
|
477
566
|
}
|
|
567
|
+
),
|
|
568
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
569
|
+
"div",
|
|
570
|
+
{
|
|
571
|
+
className: "select-item__wrapper select-multiple__wrapper",
|
|
572
|
+
style: {
|
|
573
|
+
borderColor: getThemedClass("-border"),
|
|
574
|
+
background: getThemedClass("-bg-surface")
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
getFiltered().length == 0 && keyword != "" && /* @__PURE__ */ import_react10.default.createElement(
|
|
578
|
+
"button",
|
|
579
|
+
{
|
|
580
|
+
disabled: true,
|
|
581
|
+
className: "select-item",
|
|
582
|
+
style: { color: "var(--color-danger)" }
|
|
583
|
+
},
|
|
584
|
+
"Tidak ada Item"
|
|
585
|
+
),
|
|
586
|
+
getFiltered().map(({ label: label2, value }) => /* @__PURE__ */ import_react10.default.createElement(
|
|
587
|
+
"button",
|
|
588
|
+
{
|
|
589
|
+
key: value,
|
|
590
|
+
type: "button",
|
|
591
|
+
onClick: () => selectItem({ label: label2, value }),
|
|
592
|
+
className: `select-item ${optionHoverClass}`,
|
|
593
|
+
style: { color: getThemedClass("-text-secondary") }
|
|
594
|
+
},
|
|
595
|
+
label2,
|
|
596
|
+
isItemExist(value) && /* @__PURE__ */ import_react10.default.createElement(
|
|
597
|
+
import_react_fontawesome7.FontAwesomeIcon,
|
|
598
|
+
{
|
|
599
|
+
icon: import_free_solid_svg_icons6.faCheck,
|
|
600
|
+
style: { color: "var(--color-info)" }
|
|
601
|
+
}
|
|
602
|
+
)
|
|
603
|
+
))
|
|
604
|
+
),
|
|
605
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
606
|
+
"button",
|
|
607
|
+
{
|
|
608
|
+
type: "button",
|
|
609
|
+
className: "cursor-pointer",
|
|
610
|
+
onClick: selectUnSelectAll
|
|
611
|
+
},
|
|
612
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
613
|
+
import_react_fontawesome7.FontAwesomeIcon,
|
|
614
|
+
{
|
|
615
|
+
icon: import_free_solid_svg_icons6.faListCheck,
|
|
616
|
+
style: {
|
|
617
|
+
color: getThemedClass("-icon-input"),
|
|
618
|
+
paddingRight: "0.7rem",
|
|
619
|
+
fontSize: "1.2rem"
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
)
|
|
478
623
|
)
|
|
479
|
-
))
|
|
480
|
-
"button",
|
|
481
|
-
{
|
|
482
|
-
type: "button",
|
|
483
|
-
className: "cursor-pointer",
|
|
484
|
-
onClick: selectUnSelectAll
|
|
485
|
-
},
|
|
486
|
-
/* @__PURE__ */ import_react10.default.createElement(import_react_fontawesome7.FontAwesomeIcon, { icon: import_free_solid_svg_icons6.faListCheck, className: input__icon3 })
|
|
487
|
-
)));
|
|
624
|
+
));
|
|
488
625
|
}
|
|
489
|
-
var input__icon3 = "pr-[0.7rem] text-[1.2rem] text-[var(--color-icon-input)]";
|
|
490
626
|
var input3 = "text-input peer ... w-full";
|
|
491
627
|
|
|
492
628
|
// src/components/ThemeToggle.tsx
|
|
@@ -529,6 +665,7 @@ function Dashboard() {
|
|
|
529
665
|
return /* @__PURE__ */ import_react12.default.createElement("div", { className: "flex items-center gap-[1rem]" }, /* @__PURE__ */ import_react12.default.createElement(
|
|
530
666
|
MultiSelect,
|
|
531
667
|
{
|
|
668
|
+
isdarkmode: true,
|
|
532
669
|
label: "Multi Select",
|
|
533
670
|
stringOptions: stringList,
|
|
534
671
|
state: { value: selectedItem, select: setSelectedItem }
|