@page-speed/forms 0.1.0 → 0.1.2
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 +52 -425
- package/dist/inputs.cjs +160 -36
- package/dist/inputs.cjs.map +1 -1
- package/dist/inputs.d.cts +143 -1
- package/dist/inputs.d.ts +143 -1
- package/dist/inputs.js +159 -36
- package/dist/inputs.js.map +1 -1
- package/package.json +1 -1
package/dist/inputs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as React6 from 'react';
|
|
2
2
|
|
|
3
3
|
function TextInput({
|
|
4
4
|
name,
|
|
@@ -22,7 +22,7 @@ function TextInput({
|
|
|
22
22
|
const baseClassName = "text-input";
|
|
23
23
|
const errorClassName = error ? "text-input--error" : "";
|
|
24
24
|
const combinedClassName = `${baseClassName} ${errorClassName} ${className}`.trim();
|
|
25
|
-
return /* @__PURE__ */
|
|
25
|
+
return /* @__PURE__ */ React6.createElement(
|
|
26
26
|
"input",
|
|
27
27
|
{
|
|
28
28
|
type,
|
|
@@ -68,7 +68,7 @@ function TextArea({
|
|
|
68
68
|
const baseClassName = "textarea";
|
|
69
69
|
const errorClassName = error ? "textarea--error" : "";
|
|
70
70
|
const combinedClassName = `${baseClassName} ${errorClassName} ${className}`.trim();
|
|
71
|
-
return /* @__PURE__ */
|
|
71
|
+
return /* @__PURE__ */ React6.createElement(
|
|
72
72
|
"textarea",
|
|
73
73
|
{
|
|
74
74
|
name,
|
|
@@ -105,8 +105,8 @@ function Checkbox({
|
|
|
105
105
|
label,
|
|
106
106
|
...props
|
|
107
107
|
}) {
|
|
108
|
-
const inputRef =
|
|
109
|
-
|
|
108
|
+
const inputRef = React6.useRef(null);
|
|
109
|
+
React6.useEffect(() => {
|
|
110
110
|
if (inputRef.current) {
|
|
111
111
|
inputRef.current.indeterminate = indeterminate;
|
|
112
112
|
}
|
|
@@ -120,7 +120,7 @@ function Checkbox({
|
|
|
120
120
|
const baseClassName = "checkbox";
|
|
121
121
|
const errorClassName = error ? "checkbox--error" : "";
|
|
122
122
|
const combinedClassName = `${baseClassName} ${errorClassName} ${className}`.trim();
|
|
123
|
-
const checkbox = /* @__PURE__ */
|
|
123
|
+
const checkbox = /* @__PURE__ */ React6.createElement(
|
|
124
124
|
"input",
|
|
125
125
|
{
|
|
126
126
|
ref: inputRef,
|
|
@@ -139,11 +139,134 @@ function Checkbox({
|
|
|
139
139
|
}
|
|
140
140
|
);
|
|
141
141
|
if (label) {
|
|
142
|
-
return /* @__PURE__ */
|
|
142
|
+
return /* @__PURE__ */ React6.createElement("label", { className: "checkbox-label" }, checkbox, /* @__PURE__ */ React6.createElement("span", { className: "checkbox-label-text" }, label));
|
|
143
143
|
}
|
|
144
144
|
return checkbox;
|
|
145
145
|
}
|
|
146
146
|
Checkbox.displayName = "Checkbox";
|
|
147
|
+
function CheckboxGroup({
|
|
148
|
+
name,
|
|
149
|
+
value = [],
|
|
150
|
+
onChange,
|
|
151
|
+
onBlur,
|
|
152
|
+
disabled = false,
|
|
153
|
+
required = false,
|
|
154
|
+
error = false,
|
|
155
|
+
className = "",
|
|
156
|
+
layout = "stacked",
|
|
157
|
+
label,
|
|
158
|
+
description,
|
|
159
|
+
options,
|
|
160
|
+
showSelectAll = false,
|
|
161
|
+
selectAllLabel = "Select all",
|
|
162
|
+
minSelections,
|
|
163
|
+
maxSelections,
|
|
164
|
+
renderOption,
|
|
165
|
+
gridColumns = 2,
|
|
166
|
+
...props
|
|
167
|
+
}) {
|
|
168
|
+
const enabledOptions = options.filter((opt) => !opt.disabled);
|
|
169
|
+
const enabledValues = enabledOptions.map((opt) => opt.value);
|
|
170
|
+
const selectedEnabledCount = value.filter(
|
|
171
|
+
(v) => enabledValues.includes(v)
|
|
172
|
+
).length;
|
|
173
|
+
const allSelected = selectedEnabledCount === enabledOptions.length;
|
|
174
|
+
const someSelected = selectedEnabledCount > 0 && !allSelected;
|
|
175
|
+
const handleChange = (optionValue, checked) => {
|
|
176
|
+
const newValues = checked ? [...value, optionValue] : value.filter((v) => v !== optionValue);
|
|
177
|
+
if (maxSelections && checked && newValues.length > maxSelections) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
onChange(newValues);
|
|
181
|
+
};
|
|
182
|
+
const handleSelectAll = (checked) => {
|
|
183
|
+
if (checked) {
|
|
184
|
+
const allValues = enabledOptions.map((opt) => opt.value);
|
|
185
|
+
onChange(allValues);
|
|
186
|
+
} else {
|
|
187
|
+
onChange([]);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const handleBlur = () => {
|
|
191
|
+
onBlur?.();
|
|
192
|
+
};
|
|
193
|
+
const baseClassName = "checkbox-group";
|
|
194
|
+
const errorClassName = error ? "checkbox-group--error" : "";
|
|
195
|
+
const layoutClassName = `checkbox-group--${layout}`;
|
|
196
|
+
const combinedClassName = `${baseClassName} ${errorClassName} ${layoutClassName} ${className}`.trim();
|
|
197
|
+
const maxReached = Boolean(maxSelections && value.length >= maxSelections);
|
|
198
|
+
return /* @__PURE__ */ React6.createElement(
|
|
199
|
+
"div",
|
|
200
|
+
{
|
|
201
|
+
className: combinedClassName,
|
|
202
|
+
role: "group",
|
|
203
|
+
"aria-invalid": error || props["aria-invalid"],
|
|
204
|
+
"aria-describedby": props["aria-describedby"],
|
|
205
|
+
"aria-required": required || props["aria-required"],
|
|
206
|
+
"aria-label": typeof label === "string" ? label : props["aria-label"],
|
|
207
|
+
style: layout === "grid" ? {
|
|
208
|
+
gridTemplateColumns: `repeat(${gridColumns}, 1fr)`
|
|
209
|
+
} : void 0
|
|
210
|
+
},
|
|
211
|
+
label && /* @__PURE__ */ React6.createElement("div", { className: "checkbox-group-label" }, label),
|
|
212
|
+
description && /* @__PURE__ */ React6.createElement("div", { className: "checkbox-group-description" }, description),
|
|
213
|
+
/* @__PURE__ */ React6.createElement("div", { className: "checkbox-options" }, showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React6.createElement("label", { className: "checkbox-option checkbox-option--select-all" }, /* @__PURE__ */ React6.createElement(
|
|
214
|
+
"input",
|
|
215
|
+
{
|
|
216
|
+
type: "checkbox",
|
|
217
|
+
checked: allSelected,
|
|
218
|
+
ref: (input) => {
|
|
219
|
+
if (input) {
|
|
220
|
+
input.indeterminate = someSelected;
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
onChange: (e) => handleSelectAll(e.target.checked),
|
|
224
|
+
onBlur: handleBlur,
|
|
225
|
+
disabled,
|
|
226
|
+
className: "checkbox-input",
|
|
227
|
+
"aria-label": selectAllLabel
|
|
228
|
+
}
|
|
229
|
+
), /* @__PURE__ */ React6.createElement("div", { className: "checkbox-content" }, /* @__PURE__ */ React6.createElement("span", { className: "checkbox-label" }, selectAllLabel))), options.map((option) => {
|
|
230
|
+
const isChecked = value.includes(option.value);
|
|
231
|
+
const isDisabled = disabled || option.disabled || maxReached && !isChecked;
|
|
232
|
+
const checkboxId = `${name}-${option.value}`;
|
|
233
|
+
return /* @__PURE__ */ React6.createElement(
|
|
234
|
+
"label",
|
|
235
|
+
{
|
|
236
|
+
key: option.value,
|
|
237
|
+
className: `checkbox-option ${isDisabled ? "checkbox-option--disabled" : ""}`,
|
|
238
|
+
htmlFor: checkboxId
|
|
239
|
+
},
|
|
240
|
+
/* @__PURE__ */ React6.createElement(
|
|
241
|
+
"input",
|
|
242
|
+
{
|
|
243
|
+
type: "checkbox",
|
|
244
|
+
id: checkboxId,
|
|
245
|
+
name,
|
|
246
|
+
value: option.value,
|
|
247
|
+
checked: isChecked,
|
|
248
|
+
onChange: (e) => handleChange(option.value, e.target.checked),
|
|
249
|
+
onBlur: handleBlur,
|
|
250
|
+
disabled: isDisabled,
|
|
251
|
+
required: required && minSelections ? value.length < minSelections : false,
|
|
252
|
+
className: "checkbox-input",
|
|
253
|
+
"aria-describedby": option.description ? `${checkboxId}-description` : props["aria-describedby"]
|
|
254
|
+
}
|
|
255
|
+
),
|
|
256
|
+
/* @__PURE__ */ React6.createElement("div", { className: "checkbox-content" }, renderOption ? renderOption(option) : /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement("span", { className: "checkbox-label" }, option.label), option.description && /* @__PURE__ */ React6.createElement(
|
|
257
|
+
"span",
|
|
258
|
+
{
|
|
259
|
+
className: "checkbox-description",
|
|
260
|
+
id: `${checkboxId}-description`
|
|
261
|
+
},
|
|
262
|
+
option.description
|
|
263
|
+
)))
|
|
264
|
+
);
|
|
265
|
+
})),
|
|
266
|
+
(minSelections || maxSelections) && /* @__PURE__ */ React6.createElement("div", { className: "checkbox-group-feedback", "aria-live": "polite" }, minSelections && value.length < minSelections && /* @__PURE__ */ React6.createElement("span", { className: "checkbox-group-feedback-min" }, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""), maxSelections && /* @__PURE__ */ React6.createElement("span", { className: "checkbox-group-feedback-max" }, value.length, "/", maxSelections, " selected"))
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
CheckboxGroup.displayName = "CheckboxGroup";
|
|
147
270
|
function Radio({
|
|
148
271
|
name,
|
|
149
272
|
value,
|
|
@@ -193,7 +316,7 @@ function Radio({
|
|
|
193
316
|
const errorClassName = error ? "radio-group--error" : "";
|
|
194
317
|
const layoutClassName = `radio-group--${layout}`;
|
|
195
318
|
const combinedClassName = `${baseClassName} ${errorClassName} ${layoutClassName} ${className}`.trim();
|
|
196
|
-
return /* @__PURE__ */
|
|
319
|
+
return /* @__PURE__ */ React6.createElement(
|
|
197
320
|
"div",
|
|
198
321
|
{
|
|
199
322
|
className: combinedClassName,
|
|
@@ -203,19 +326,19 @@ function Radio({
|
|
|
203
326
|
"aria-required": required || props["aria-required"],
|
|
204
327
|
"aria-label": typeof label === "string" ? label : props["aria-label"]
|
|
205
328
|
},
|
|
206
|
-
label && /* @__PURE__ */
|
|
207
|
-
/* @__PURE__ */
|
|
329
|
+
label && /* @__PURE__ */ React6.createElement("div", { className: "radio-group-label" }, label),
|
|
330
|
+
/* @__PURE__ */ React6.createElement("div", { className: "radio-options" }, options.map((option, index) => {
|
|
208
331
|
const isChecked = value === option.value;
|
|
209
332
|
const isDisabled = disabled || option.disabled;
|
|
210
333
|
const radioId = `${name}-${option.value}`;
|
|
211
|
-
return /* @__PURE__ */
|
|
334
|
+
return /* @__PURE__ */ React6.createElement(
|
|
212
335
|
"label",
|
|
213
336
|
{
|
|
214
337
|
key: option.value,
|
|
215
338
|
className: `radio-option ${isDisabled ? "radio-option--disabled" : ""}`,
|
|
216
339
|
htmlFor: radioId
|
|
217
340
|
},
|
|
218
|
-
/* @__PURE__ */
|
|
341
|
+
/* @__PURE__ */ React6.createElement(
|
|
219
342
|
"input",
|
|
220
343
|
{
|
|
221
344
|
type: "radio",
|
|
@@ -232,7 +355,7 @@ function Radio({
|
|
|
232
355
|
"aria-describedby": option.description ? `${radioId}-description` : props["aria-describedby"]
|
|
233
356
|
}
|
|
234
357
|
),
|
|
235
|
-
/* @__PURE__ */
|
|
358
|
+
/* @__PURE__ */ React6.createElement("div", { className: "radio-content" }, /* @__PURE__ */ React6.createElement("span", { className: "radio-label" }, option.label), option.description && /* @__PURE__ */ React6.createElement(
|
|
236
359
|
"span",
|
|
237
360
|
{
|
|
238
361
|
className: "radio-description",
|
|
@@ -264,19 +387,19 @@ function Select({
|
|
|
264
387
|
renderOption,
|
|
265
388
|
...props
|
|
266
389
|
}) {
|
|
267
|
-
const [isOpen, setIsOpen] =
|
|
268
|
-
const [searchQuery, setSearchQuery] =
|
|
269
|
-
const [focusedIndex, setFocusedIndex] =
|
|
270
|
-
const selectRef =
|
|
271
|
-
const searchInputRef =
|
|
390
|
+
const [isOpen, setIsOpen] = React6.useState(false);
|
|
391
|
+
const [searchQuery, setSearchQuery] = React6.useState("");
|
|
392
|
+
const [focusedIndex, setFocusedIndex] = React6.useState(-1);
|
|
393
|
+
const selectRef = React6.useRef(null);
|
|
394
|
+
const searchInputRef = React6.useRef(null);
|
|
272
395
|
const dropdownId = `${name}-dropdown`;
|
|
273
|
-
const allOptions =
|
|
396
|
+
const allOptions = React6.useMemo(() => {
|
|
274
397
|
if (optionGroups.length > 0) {
|
|
275
398
|
return optionGroups.flatMap((group) => group.options);
|
|
276
399
|
}
|
|
277
400
|
return options;
|
|
278
401
|
}, [options, optionGroups]);
|
|
279
|
-
const filteredOptions =
|
|
402
|
+
const filteredOptions = React6.useMemo(() => {
|
|
280
403
|
if (!searchQuery.trim()) {
|
|
281
404
|
return allOptions;
|
|
282
405
|
}
|
|
@@ -286,7 +409,7 @@ function Select({
|
|
|
286
409
|
return label.toLowerCase().includes(query);
|
|
287
410
|
});
|
|
288
411
|
}, [allOptions, searchQuery]);
|
|
289
|
-
const selectedOption =
|
|
412
|
+
const selectedOption = React6.useMemo(() => {
|
|
290
413
|
return allOptions.find((opt) => opt.value === value);
|
|
291
414
|
}, [allOptions, value]);
|
|
292
415
|
const handleSelect = (optionValue) => {
|
|
@@ -390,7 +513,7 @@ function Select({
|
|
|
390
513
|
const handleBlur = () => {
|
|
391
514
|
onBlur?.();
|
|
392
515
|
};
|
|
393
|
-
|
|
516
|
+
React6.useEffect(() => {
|
|
394
517
|
const handleClickOutside = (event) => {
|
|
395
518
|
if (selectRef.current && !selectRef.current.contains(event.target)) {
|
|
396
519
|
setIsOpen(false);
|
|
@@ -411,7 +534,7 @@ function Select({
|
|
|
411
534
|
const disabledClassName = disabled ? "select--disabled" : "";
|
|
412
535
|
const openClassName = isOpen ? "select--open" : "";
|
|
413
536
|
const combinedClassName = `${baseClassName} ${errorClassName} ${disabledClassName} ${openClassName} ${className}`.trim();
|
|
414
|
-
return /* @__PURE__ */
|
|
537
|
+
return /* @__PURE__ */ React6.createElement(
|
|
415
538
|
"div",
|
|
416
539
|
{
|
|
417
540
|
ref: selectRef,
|
|
@@ -419,7 +542,7 @@ function Select({
|
|
|
419
542
|
onKeyDown: handleKeyDown,
|
|
420
543
|
onBlur: handleBlur
|
|
421
544
|
},
|
|
422
|
-
/* @__PURE__ */
|
|
545
|
+
/* @__PURE__ */ React6.createElement(
|
|
423
546
|
"select",
|
|
424
547
|
{
|
|
425
548
|
name,
|
|
@@ -432,10 +555,10 @@ function Select({
|
|
|
432
555
|
tabIndex: -1,
|
|
433
556
|
style: { display: "none" }
|
|
434
557
|
},
|
|
435
|
-
/* @__PURE__ */
|
|
436
|
-
allOptions.map((option) => /* @__PURE__ */
|
|
558
|
+
/* @__PURE__ */ React6.createElement("option", { value: "" }, "Select..."),
|
|
559
|
+
allOptions.map((option) => /* @__PURE__ */ React6.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
|
|
437
560
|
),
|
|
438
|
-
/* @__PURE__ */
|
|
561
|
+
/* @__PURE__ */ React6.createElement(
|
|
439
562
|
"div",
|
|
440
563
|
{
|
|
441
564
|
className: "select-trigger",
|
|
@@ -449,8 +572,8 @@ function Select({
|
|
|
449
572
|
"aria-disabled": disabled,
|
|
450
573
|
tabIndex: disabled ? -1 : 0
|
|
451
574
|
},
|
|
452
|
-
/* @__PURE__ */
|
|
453
|
-
/* @__PURE__ */
|
|
575
|
+
/* @__PURE__ */ React6.createElement("span", { className: "select-value" }, selectedOption ? renderOption ? renderOption(selectedOption) : selectedOption.label : /* @__PURE__ */ React6.createElement("span", { className: "select-placeholder" }, placeholder)),
|
|
576
|
+
/* @__PURE__ */ React6.createElement("div", { className: "select-icons" }, loading && /* @__PURE__ */ React6.createElement("span", { className: "select-loading" }, "\u23F3"), clearable && value && !disabled && !loading && /* @__PURE__ */ React6.createElement(
|
|
454
577
|
"button",
|
|
455
578
|
{
|
|
456
579
|
type: "button",
|
|
@@ -460,9 +583,9 @@ function Select({
|
|
|
460
583
|
tabIndex: -1
|
|
461
584
|
},
|
|
462
585
|
"\u2715"
|
|
463
|
-
), /* @__PURE__ */
|
|
586
|
+
), /* @__PURE__ */ React6.createElement("span", { className: "select-arrow", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
|
|
464
587
|
),
|
|
465
|
-
isOpen && /* @__PURE__ */
|
|
588
|
+
isOpen && /* @__PURE__ */ React6.createElement("div", { id: dropdownId, className: "select-dropdown", role: "listbox" }, searchable && /* @__PURE__ */ React6.createElement("div", { className: "select-search" }, /* @__PURE__ */ React6.createElement(
|
|
466
589
|
"input",
|
|
467
590
|
{
|
|
468
591
|
ref: searchInputRef,
|
|
@@ -474,19 +597,19 @@ function Select({
|
|
|
474
597
|
onClick: (e) => e.stopPropagation(),
|
|
475
598
|
"aria-label": "Search options"
|
|
476
599
|
}
|
|
477
|
-
)), /* @__PURE__ */
|
|
600
|
+
)), /* @__PURE__ */ React6.createElement("div", { className: "select-options" }, filteredOptions.length === 0 ? /* @__PURE__ */ React6.createElement("div", { className: "select-no-options" }, "No options found") : optionGroups.length > 0 ? (
|
|
478
601
|
// Render grouped options
|
|
479
602
|
optionGroups.map((group, groupIndex) => {
|
|
480
603
|
const groupOptions = group.options.filter(
|
|
481
604
|
(opt) => filteredOptions.includes(opt)
|
|
482
605
|
);
|
|
483
606
|
if (groupOptions.length === 0) return null;
|
|
484
|
-
return /* @__PURE__ */
|
|
607
|
+
return /* @__PURE__ */ React6.createElement("div", { key: groupIndex, className: "select-optgroup" }, /* @__PURE__ */ React6.createElement("div", { className: "select-optgroup-label" }, group.label), groupOptions.map((option) => {
|
|
485
608
|
const globalIndex = filteredOptions.indexOf(option);
|
|
486
609
|
const isSelected = value === option.value;
|
|
487
610
|
const isFocused = globalIndex === focusedIndex;
|
|
488
611
|
const isDisabled = option.disabled;
|
|
489
|
-
return /* @__PURE__ */
|
|
612
|
+
return /* @__PURE__ */ React6.createElement(
|
|
490
613
|
"div",
|
|
491
614
|
{
|
|
492
615
|
key: option.value,
|
|
@@ -506,7 +629,7 @@ function Select({
|
|
|
506
629
|
const isSelected = value === option.value;
|
|
507
630
|
const isFocused = index === focusedIndex;
|
|
508
631
|
const isDisabled = option.disabled;
|
|
509
|
-
return /* @__PURE__ */
|
|
632
|
+
return /* @__PURE__ */ React6.createElement(
|
|
510
633
|
"div",
|
|
511
634
|
{
|
|
512
635
|
key: option.value,
|
|
@@ -524,6 +647,6 @@ function Select({
|
|
|
524
647
|
}
|
|
525
648
|
Select.displayName = "Select";
|
|
526
649
|
|
|
527
|
-
export { Checkbox, Radio, Select, TextArea, TextInput };
|
|
650
|
+
export { Checkbox, CheckboxGroup, Radio, Select, TextArea, TextInput };
|
|
528
651
|
//# sourceMappingURL=inputs.js.map
|
|
529
652
|
//# sourceMappingURL=inputs.js.map
|