@bunnix/components 0.9.2 → 0.9.4
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/@types/index.d.ts +203 -5
- package/README.md +73 -103
- package/package.json +1 -1
- package/src/components/ComboBox.mjs +8 -2
- package/src/components/DatePicker.mjs +234 -57
- package/src/components/Dialog.mjs +1 -1
- package/src/components/InputField.mjs +55 -6
- package/src/components/ProgressBar.mjs +81 -0
- package/src/components/TimePicker.mjs +255 -65
- package/src/index.mjs +4 -0
- package/src/styles/controls.css +72 -0
- package/src/utils/maskUtils.mjs +569 -0
package/@types/index.d.ts
CHANGED
|
@@ -11,6 +11,127 @@ export type LegacySize = "xs" | "sm" | "md" | "lg" | "xl" | "default";
|
|
|
11
11
|
export type SizeValue = Size | LegacySize;
|
|
12
12
|
export type SizeNoSmall = Exclude<SizeValue, "small" | "sm">;
|
|
13
13
|
export type SizeRegularUp = Exclude<SizeValue, "xsmall" | "xs" | "small" | "sm">;
|
|
14
|
+
export type IconNameSlug =
|
|
15
|
+
| "add"
|
|
16
|
+
| "add-circle"
|
|
17
|
+
| "alt"
|
|
18
|
+
| "archive"
|
|
19
|
+
| "at"
|
|
20
|
+
| "attestation"
|
|
21
|
+
| "bell"
|
|
22
|
+
| "bookmark"
|
|
23
|
+
| "bot"
|
|
24
|
+
| "button"
|
|
25
|
+
| "calculate"
|
|
26
|
+
| "calendar"
|
|
27
|
+
| "chart"
|
|
28
|
+
| "check"
|
|
29
|
+
| "chevron-down"
|
|
30
|
+
| "chevron-left"
|
|
31
|
+
| "chevron-right"
|
|
32
|
+
| "clip"
|
|
33
|
+
| "clock"
|
|
34
|
+
| "close"
|
|
35
|
+
| "close-circle"
|
|
36
|
+
| "cloud"
|
|
37
|
+
| "cloud-download"
|
|
38
|
+
| "cloud-upload"
|
|
39
|
+
| "columns-layout"
|
|
40
|
+
| "command"
|
|
41
|
+
| "cube"
|
|
42
|
+
| "delete"
|
|
43
|
+
| "dollar"
|
|
44
|
+
| "download"
|
|
45
|
+
| "draw"
|
|
46
|
+
| "duplicate"
|
|
47
|
+
| "edit"
|
|
48
|
+
| "exclamation-mark"
|
|
49
|
+
| "eye"
|
|
50
|
+
| "eye-open"
|
|
51
|
+
| "file"
|
|
52
|
+
| "file-html"
|
|
53
|
+
| "finger"
|
|
54
|
+
| "flag"
|
|
55
|
+
| "folder"
|
|
56
|
+
| "function"
|
|
57
|
+
| "gear"
|
|
58
|
+
| "gift"
|
|
59
|
+
| "globe"
|
|
60
|
+
| "grid"
|
|
61
|
+
| "hand"
|
|
62
|
+
| "heart"
|
|
63
|
+
| "home"
|
|
64
|
+
| "image"
|
|
65
|
+
| "inbox"
|
|
66
|
+
| "info"
|
|
67
|
+
| "key"
|
|
68
|
+
| "lamp"
|
|
69
|
+
| "link"
|
|
70
|
+
| "location"
|
|
71
|
+
| "locker"
|
|
72
|
+
| "login"
|
|
73
|
+
| "logout"
|
|
74
|
+
| "mail"
|
|
75
|
+
| "map"
|
|
76
|
+
| "markup"
|
|
77
|
+
| "merge"
|
|
78
|
+
| "more-horizontal"
|
|
79
|
+
| "more-vertical"
|
|
80
|
+
| "mouse"
|
|
81
|
+
| "palette"
|
|
82
|
+
| "password"
|
|
83
|
+
| "pencil"
|
|
84
|
+
| "people"
|
|
85
|
+
| "person"
|
|
86
|
+
| "person-add"
|
|
87
|
+
| "person-remove"
|
|
88
|
+
| "pin"
|
|
89
|
+
| "question-circle"
|
|
90
|
+
| "remove-circle"
|
|
91
|
+
| "return-arrow"
|
|
92
|
+
| "save"
|
|
93
|
+
| "search"
|
|
94
|
+
| "sections"
|
|
95
|
+
| "send"
|
|
96
|
+
| "share"
|
|
97
|
+
| "shine"
|
|
98
|
+
| "sliders"
|
|
99
|
+
| "star"
|
|
100
|
+
| "storage"
|
|
101
|
+
| "success-circle"
|
|
102
|
+
| "swap"
|
|
103
|
+
| "switch"
|
|
104
|
+
| "sync"
|
|
105
|
+
| "table"
|
|
106
|
+
| "tag"
|
|
107
|
+
| "terminal"
|
|
108
|
+
| "text"
|
|
109
|
+
| "thumb-down"
|
|
110
|
+
| "thumb-up"
|
|
111
|
+
| "timer"
|
|
112
|
+
| "toggle"
|
|
113
|
+
| "trash"
|
|
114
|
+
| "update-page"
|
|
115
|
+
| "upload"
|
|
116
|
+
| "video"
|
|
117
|
+
| "wallet"
|
|
118
|
+
| "window";
|
|
119
|
+
export type IconName =
|
|
120
|
+
| IconNameSlug
|
|
121
|
+
| `icon-${IconNameSlug}`
|
|
122
|
+
| (string & {});
|
|
123
|
+
export type IconFill =
|
|
124
|
+
| "default"
|
|
125
|
+
| "base"
|
|
126
|
+
| "white"
|
|
127
|
+
| "secondary"
|
|
128
|
+
| "tertiary"
|
|
129
|
+
| "quaternary"
|
|
130
|
+
| "destructive"
|
|
131
|
+
| `icon-${string}`
|
|
132
|
+
| (string & {});
|
|
133
|
+
export type IconSizeClass = "icon-xs" | "icon-sm" | "icon-lg" | "icon-xl";
|
|
134
|
+
export type IconSize = SizeValue | IconSizeClass | (string & {});
|
|
14
135
|
|
|
15
136
|
export interface ButtonProps extends BaseProps {
|
|
16
137
|
type?: string;
|
|
@@ -23,9 +144,9 @@ export interface ButtonProps extends BaseProps {
|
|
|
23
144
|
}
|
|
24
145
|
|
|
25
146
|
export interface IconProps extends BaseProps {
|
|
26
|
-
name?:
|
|
27
|
-
fill?:
|
|
28
|
-
size?:
|
|
147
|
+
name?: IconName;
|
|
148
|
+
fill?: IconFill;
|
|
149
|
+
size?: IconSize;
|
|
29
150
|
}
|
|
30
151
|
|
|
31
152
|
export interface TextProps extends BaseProps {
|
|
@@ -48,6 +169,25 @@ export interface TextProps extends BaseProps {
|
|
|
48
169
|
wrap?: "wrap" | "nowrap";
|
|
49
170
|
}
|
|
50
171
|
|
|
172
|
+
export interface ProgressBarProps extends BaseProps {
|
|
173
|
+
value?: number | any;
|
|
174
|
+
min?: number;
|
|
175
|
+
max?: number;
|
|
176
|
+
size?: SizeValue;
|
|
177
|
+
color?: "default"
|
|
178
|
+
| "primary"
|
|
179
|
+
| "primary-dimmed"
|
|
180
|
+
| "secondary"
|
|
181
|
+
| "tertiary"
|
|
182
|
+
| "quaternary"
|
|
183
|
+
| "destructive"
|
|
184
|
+
| "destructive-dimmed"
|
|
185
|
+
| "accent"
|
|
186
|
+
| "accent-dimmed"
|
|
187
|
+
| "white"
|
|
188
|
+
| (string & {});
|
|
189
|
+
}
|
|
190
|
+
|
|
51
191
|
export interface ContainerProps extends BaseProps {
|
|
52
192
|
type?: "main" | "content" | "page" | (string & {});
|
|
53
193
|
direction?: "row" | "column" | (string & {});
|
|
@@ -78,6 +218,33 @@ export interface BadgeProps extends BaseProps {
|
|
|
78
218
|
shape?: "capsule" | "circle" | string;
|
|
79
219
|
}
|
|
80
220
|
|
|
221
|
+
export type InputMaskType =
|
|
222
|
+
| "date" // DD/MM/YYYY
|
|
223
|
+
| "time" // HH:MM
|
|
224
|
+
| "email" // lowercase, no spaces
|
|
225
|
+
| "currency" // $ 1,234.56
|
|
226
|
+
| "decimal" // 123.45
|
|
227
|
+
| "integer" // 123
|
|
228
|
+
| "phone" // +1 (234) 567-8900
|
|
229
|
+
| "phone-br" // +55 11 99999-9999 or +55 11 9999-9999 (Brazilian phone)
|
|
230
|
+
| "credit-card" // 1234 5678 9012 3456
|
|
231
|
+
| "cpf" // 123.456.789-01 (Brazilian CPF)
|
|
232
|
+
| "cnpj" // 12.345.678/0001-90 (Brazilian CNPJ)
|
|
233
|
+
| "cep" // 12345-678 (Brazilian ZIP code)
|
|
234
|
+
| string; // Custom pattern using 9 (digit), A (letter), * (alphanumeric)
|
|
235
|
+
|
|
236
|
+
export interface InputMaskConfig {
|
|
237
|
+
type?: InputMaskType;
|
|
238
|
+
pattern?: string; // Custom pattern: 9=digit, A=letter, *=alphanumeric
|
|
239
|
+
options?: {
|
|
240
|
+
prefix?: string;
|
|
241
|
+
thousandsSeparator?: string;
|
|
242
|
+
decimalSeparator?: string;
|
|
243
|
+
decimalPlaces?: number;
|
|
244
|
+
allowNegative?: boolean;
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
81
248
|
export interface InputFieldProps extends BaseProps {
|
|
82
249
|
type?: string;
|
|
83
250
|
variant?: "regular" | "rounded" | string;
|
|
@@ -86,6 +253,8 @@ export interface InputFieldProps extends BaseProps {
|
|
|
86
253
|
placeholder?: string;
|
|
87
254
|
label?: string;
|
|
88
255
|
disabled?: boolean;
|
|
256
|
+
autocomplete?: string;
|
|
257
|
+
mask?: InputMaskType | InputMaskConfig;
|
|
89
258
|
suggestions?: string[];
|
|
90
259
|
onInput?: (event?: any) => void;
|
|
91
260
|
onChange?: (event?: any) => void;
|
|
@@ -115,6 +284,7 @@ export interface ComboBoxProps extends BaseProps {
|
|
|
115
284
|
options?: Array<string | ComboBoxOption>;
|
|
116
285
|
selection?: any;
|
|
117
286
|
size?: SizeValue;
|
|
287
|
+
label?: string;
|
|
118
288
|
onChange?: (event?: any) => void;
|
|
119
289
|
change?: (event?: any) => void;
|
|
120
290
|
}
|
|
@@ -206,14 +376,36 @@ export interface DatePickerProps extends BaseProps {
|
|
|
206
376
|
placeholder?: string;
|
|
207
377
|
range?: boolean;
|
|
208
378
|
variant?: "regular" | "rounded" | string;
|
|
209
|
-
size?:
|
|
379
|
+
size?: SizeRegularUp;
|
|
380
|
+
label?: string;
|
|
381
|
+
disabled?: boolean;
|
|
382
|
+
value?: Date | null;
|
|
383
|
+
onInput?: (event?: any) => void;
|
|
384
|
+
onChange?: (event?: { target: { value: string }; date: Date | null }) => void;
|
|
385
|
+
onFocus?: (event?: any) => void;
|
|
386
|
+
onBlur?: (event?: any) => void;
|
|
387
|
+
input?: (event?: any) => void;
|
|
388
|
+
change?: (event?: { target: { value: string }; date: Date | null }) => void;
|
|
389
|
+
focus?: (event?: any) => void;
|
|
390
|
+
blur?: (event?: any) => void;
|
|
210
391
|
}
|
|
211
392
|
|
|
212
393
|
export interface TimePickerProps extends BaseProps {
|
|
213
394
|
id?: string;
|
|
214
395
|
placeholder?: string;
|
|
215
396
|
variant?: "regular" | "rounded" | string;
|
|
216
|
-
size?:
|
|
397
|
+
size?: SizeRegularUp;
|
|
398
|
+
label?: string;
|
|
399
|
+
disabled?: boolean;
|
|
400
|
+
value?: { hours: number; minutes: number } | null;
|
|
401
|
+
onInput?: (event?: any) => void;
|
|
402
|
+
onChange?: (event?: { target: { value: string }; time: { hours: number; minutes: number } | null }) => void;
|
|
403
|
+
onFocus?: (event?: any) => void;
|
|
404
|
+
onBlur?: (event?: any) => void;
|
|
405
|
+
input?: (event?: any) => void;
|
|
406
|
+
change?: (event?: { target: { value: string }; time: { hours: number; minutes: number } | null }) => void;
|
|
407
|
+
focus?: (event?: any) => void;
|
|
408
|
+
blur?: (event?: any) => void;
|
|
217
409
|
}
|
|
218
410
|
|
|
219
411
|
export interface DropdownMenuItem {
|
|
@@ -344,6 +536,7 @@ export const NavigationBar: Component<NavigationBarProps>;
|
|
|
344
536
|
export const PageHeader: Component<PageHeaderProps>;
|
|
345
537
|
export const PageSection: Component<PageSectionProps>;
|
|
346
538
|
export const PopoverMenu: Component<PopoverMenuProps>;
|
|
539
|
+
export const ProgressBar: Component<ProgressBarProps>;
|
|
347
540
|
export const RadioCheckbox: Component<RadioCheckboxProps>;
|
|
348
541
|
export const SearchBox: Component<SearchBoxProps>;
|
|
349
542
|
export const Sidebar: Component<SidebarProps>;
|
|
@@ -362,6 +555,11 @@ export const toastState: any;
|
|
|
362
555
|
export function showToast(options?: ToastOptions): void;
|
|
363
556
|
export function hideToast(): void;
|
|
364
557
|
|
|
558
|
+
// Mask utilities
|
|
559
|
+
export function applyMask(value: string, mask: InputMaskType | InputMaskConfig): string;
|
|
560
|
+
export function validateMask(value: string, mask: InputMaskType | InputMaskConfig): boolean;
|
|
561
|
+
export function getMaskMaxLength(mask: InputMaskType | InputMaskConfig): number | null;
|
|
562
|
+
|
|
365
563
|
declare module "@bunnix/components/styles.css" {
|
|
366
564
|
const content: string;
|
|
367
565
|
export default content;
|
package/README.md
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
# @bunnix/components
|
|
2
2
|
|
|
3
|
-
Design system + UI components for Bunnix projects.
|
|
3
|
+
Design system + UI components for Bunnix projects. Ships ESM source with CSS and icon assets for modern bundlers.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- This project is currently in **alpha release candidate**. APIs and components may change until the first stable release.
|
|
7
|
-
- Icon usage & attribution:
|
|
8
|
-
- COLLECTION: Framework7 Line Icons — LICENSE: MIT License — AUTHOR: framework7io
|
|
9
|
-
- COLLECTION: Iconcino Interface Icons — LICENSE: CC0 1.0 — AUTHOR: Gabriele Malaspina
|
|
10
|
-
- Sources (copy/paste): `https://framework7.io/icons/` and `https://iconcino.com/`
|
|
5
|
+
**Status**: Alpha release candidate - APIs may change before v1.0
|
|
11
6
|
|
|
12
7
|
## Install
|
|
13
8
|
|
|
@@ -15,71 +10,78 @@ Disclaimer:
|
|
|
15
10
|
npm install @bunnix/components @bunnix/core
|
|
16
11
|
```
|
|
17
12
|
|
|
18
|
-
`@bunnix/core` is a peer dependency
|
|
13
|
+
`@bunnix/core` is a peer dependency.
|
|
19
14
|
|
|
20
|
-
##
|
|
15
|
+
## Quick Start
|
|
21
16
|
|
|
22
|
-
Import
|
|
17
|
+
Import CSS once at your app entry:
|
|
23
18
|
|
|
24
19
|
```js
|
|
25
20
|
import "@bunnix/components/styles.css";
|
|
26
21
|
```
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
Use components:
|
|
29
24
|
|
|
30
25
|
```js
|
|
31
|
-
import { Button, Icon,
|
|
32
|
-
|
|
33
|
-
export default function Example() {
|
|
34
|
-
return Button({ variant: "regular" }, [
|
|
35
|
-
Icon({ name: "star", fill: "white" }),
|
|
36
|
-
Text({ type: "text" }, "Star")
|
|
37
|
-
]);
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Component examples
|
|
42
|
-
|
|
43
|
-
Button with icon:
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
import { Button, Icon } from "@bunnix/components";
|
|
26
|
+
import { Button, Icon, InputField, DatePicker } from "@bunnix/components";
|
|
47
27
|
|
|
28
|
+
// Button with icon
|
|
48
29
|
Button({ variant: "regular" }, [
|
|
49
30
|
Icon({ name: "star", fill: "white" }),
|
|
50
31
|
"Star"
|
|
51
32
|
]);
|
|
33
|
+
|
|
34
|
+
// Input with mask
|
|
35
|
+
InputField({ label: "Phone", mask: "phone-br" });
|
|
36
|
+
|
|
37
|
+
// Date picker
|
|
38
|
+
DatePicker({ label: "Birth Date", change: (e) => console.log(e.date) });
|
|
52
39
|
```
|
|
53
40
|
|
|
54
|
-
|
|
41
|
+
## Key Features
|
|
55
42
|
|
|
56
|
-
|
|
57
|
-
|
|
43
|
+
### Input Masks
|
|
44
|
+
InputField supports 12+ built-in masks plus custom patterns:
|
|
45
|
+
- `date`, `time`, `email`, `currency`, `decimal`, `integer`
|
|
46
|
+
- `phone`, `phone-br`, `credit-card`
|
|
47
|
+
- `cpf`, `cnpj`, `cep` (Brazilian documents)
|
|
48
|
+
- Custom patterns: `{ pattern: "999.999.999-99" }` (9=digit, A=letter, *=alphanumeric)
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
]
|
|
50
|
+
```js
|
|
51
|
+
InputField({
|
|
52
|
+
label: "Price",
|
|
53
|
+
mask: { type: "currency", options: { prefix: "R$", decimalPlaces: 2 }}
|
|
64
54
|
});
|
|
65
55
|
```
|
|
66
56
|
|
|
67
|
-
|
|
57
|
+
Mask utilities available for custom use:
|
|
58
|
+
```js
|
|
59
|
+
import { applyMask, validateMask, getMaskMaxLength } from "@bunnix/components";
|
|
60
|
+
```
|
|
68
61
|
|
|
62
|
+
### Date & Time Pickers
|
|
63
|
+
Text inputs with masks that show popover calendars/selectors on focus:
|
|
69
64
|
```js
|
|
70
|
-
|
|
65
|
+
DatePicker({ label: "Date", change: (e) => console.log(e.date) });
|
|
66
|
+
TimePicker({ label: "Time", change: (e) => console.log(e.time) });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Dialog & Toast
|
|
70
|
+
```js
|
|
71
|
+
import { showDialog, showToast } from "@bunnix/components";
|
|
71
72
|
|
|
72
|
-
showDialog({ title: "Welcome", message: "
|
|
73
|
-
showToast({ message: "Saved
|
|
73
|
+
showDialog({ title: "Welcome", message: "Ready to go!" });
|
|
74
|
+
showToast({ message: "Saved", icon: "success-circle" });
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
### 30+ Components
|
|
78
|
+
Button, Icon, Text, InputField, ComboBox, DatePicker, TimePicker, SearchBox, Checkbox, ToggleSwitch, Badge, Card, Table, Sidebar, NavigationBar, Dialog, Toast, and more.
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
See `/playgrounds` for live examples of all components.
|
|
79
81
|
|
|
80
82
|
## Theming
|
|
81
83
|
|
|
82
|
-
Override CSS variables
|
|
84
|
+
Override CSS variables:
|
|
83
85
|
|
|
84
86
|
```css
|
|
85
87
|
:root {
|
|
@@ -87,98 +89,66 @@ Override CSS variables after importing the stylesheet:
|
|
|
87
89
|
--background-color: #ffffff;
|
|
88
90
|
--border-color: #e5e7eb;
|
|
89
91
|
--base-padding: 0.75rem;
|
|
90
|
-
--base-gap: 0.6rem;
|
|
91
92
|
--font-family: "Inter", system-ui, sans-serif;
|
|
92
93
|
}
|
|
93
94
|
```
|
|
94
95
|
|
|
95
|
-
## CSS
|
|
96
|
+
## CSS Utilities
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
Use the same utilities that power the components:
|
|
98
99
|
|
|
99
|
-
- Layout
|
|
100
|
-
- Surfaces
|
|
101
|
-
- Typography
|
|
102
|
-
- Buttons
|
|
103
|
-
-
|
|
104
|
-
- Icons: `icon`, `icon-<name>`, `icon-xs|sm|lg|xl`, `icon-default|base|white|secondary|tertiary|quaternary`
|
|
105
|
-
|
|
106
|
-
Example:
|
|
100
|
+
- **Layout**: `row-container`, `column-container`, `grid-flow`, `gap-xs|sm|md|lg`
|
|
101
|
+
- **Surfaces**: `box`, `card`, `shadow`, `rounded`
|
|
102
|
+
- **Typography**: `text-primary|secondary|tertiary`, `text-sm|base|lg|xl`
|
|
103
|
+
- **Buttons**: `btn`, `btn-flat`, `btn-outline`, `btn-destructive`
|
|
104
|
+
- **Icons**: `icon`, `icon-<name>`, `icon-xs|sm|lg|xl`
|
|
107
105
|
|
|
108
106
|
```js
|
|
109
107
|
import Bunnix from "@bunnix/core";
|
|
110
108
|
const { div, span } = Bunnix;
|
|
111
109
|
|
|
112
|
-
div({ class: "card row-container gap-sm
|
|
113
|
-
span({ class: "icon icon-star icon-base
|
|
114
|
-
span({ class: "text-primary
|
|
110
|
+
div({ class: "card row-container gap-sm" }, [
|
|
111
|
+
span({ class: "icon icon-star icon-base" }),
|
|
112
|
+
span({ class: "text-primary" }, "Custom card")
|
|
115
113
|
]);
|
|
116
114
|
```
|
|
117
115
|
|
|
118
|
-
##
|
|
116
|
+
## Bundler Setup
|
|
119
117
|
|
|
120
|
-
|
|
118
|
+
Works with webpack, vite, rollup, or any modern ESM bundler. Ensure your bundler:
|
|
119
|
+
- Processes CSS imports
|
|
120
|
+
- Handles CSS `url(...)` for SVG assets
|
|
121
|
+
- Supports `.mjs` extensions
|
|
121
122
|
|
|
123
|
+
Minimal webpack example:
|
|
122
124
|
```js
|
|
123
|
-
import path from "path";
|
|
124
|
-
import { fileURLToPath } from "url";
|
|
125
|
-
import HtmlWebpackPlugin from "html-webpack-plugin";
|
|
126
|
-
|
|
127
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
128
|
-
const __dirname = path.dirname(__filename);
|
|
129
|
-
|
|
130
125
|
export default {
|
|
131
|
-
entry: "./src/index.mjs",
|
|
132
|
-
output: {
|
|
133
|
-
filename: "main.js",
|
|
134
|
-
path: path.resolve(__dirname, "dist"),
|
|
135
|
-
clean: true,
|
|
136
|
-
assetModuleFilename: "images/[hash][ext][query]"
|
|
137
|
-
},
|
|
138
|
-
mode: "development",
|
|
139
126
|
module: {
|
|
140
127
|
rules: [
|
|
141
|
-
{ test:
|
|
142
|
-
{ test:
|
|
128
|
+
{ test: /\.css$/i, use: ["style-loader", "css-loader"] },
|
|
129
|
+
{ test: /\.(png|svg|jpg|jpeg|gif)$/i, type: "asset/resource" }
|
|
143
130
|
]
|
|
144
|
-
},
|
|
145
|
-
resolve: {
|
|
146
|
-
extensions: [".mjs", ".js", ".json"]
|
|
147
|
-
},
|
|
148
|
-
plugins: [
|
|
149
|
-
new HtmlWebpackPlugin({ template: "./public/index.html" })
|
|
150
|
-
],
|
|
151
|
-
devServer: {
|
|
152
|
-
static: { directory: path.join(__dirname, "public") },
|
|
153
|
-
compress: true,
|
|
154
|
-
port: 3000,
|
|
155
|
-
open: true
|
|
156
131
|
}
|
|
157
132
|
};
|
|
158
133
|
```
|
|
159
134
|
|
|
160
|
-
##
|
|
135
|
+
## Icon Attribution
|
|
136
|
+
|
|
137
|
+
- Framework7 Line Icons (MIT) - framework7io
|
|
138
|
+
- Iconcino Interface Icons (CC0 1.0) - Gabriele Malaspina
|
|
139
|
+
|
|
140
|
+
## Project Structure
|
|
161
141
|
|
|
162
142
|
```
|
|
163
143
|
src/
|
|
164
|
-
components/ #
|
|
165
|
-
styles/ #
|
|
144
|
+
components/ # Component library
|
|
145
|
+
styles/ # Design system CSS
|
|
166
146
|
icons/ # SVG assets
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
playgrounds/ #
|
|
147
|
+
utils/ # Utilities (masks, etc.)
|
|
148
|
+
index.mjs # Package exports
|
|
149
|
+
playgrounds/ # Component showcase
|
|
170
150
|
```
|
|
171
151
|
|
|
172
|
-
## Playground
|
|
173
|
-
|
|
174
|
-
The playground consumes `@bunnix/components` directly. Start it with your preferred dev server (whatever you use today), and ensure the CSS import stays at `playgrounds/src/index.mjs`.
|
|
175
|
-
|
|
176
|
-
## Publishing notes
|
|
177
|
-
|
|
178
|
-
- This package targets ESM consumers and ships source files (no dist build).
|
|
179
|
-
- Ensure `files` and `exports` in `package.json` include `src/` and CSS entries.
|
|
180
|
-
- GitHub CI should run with Node that supports ESM (Node 16+ recommended).
|
|
181
|
-
|
|
182
152
|
## License
|
|
183
153
|
|
|
184
154
|
ISC
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import Bunnix from "@bunnix/core";
|
|
2
2
|
import { clampSize, toSizeToken } from "../utils/sizeUtils.mjs";
|
|
3
|
-
const { select, option, div, span } = Bunnix;
|
|
3
|
+
const { select, option, div, label, span } = Bunnix;
|
|
4
4
|
|
|
5
5
|
export default function ComboBox({
|
|
6
6
|
options = [],
|
|
7
7
|
selection,
|
|
8
8
|
size,
|
|
9
|
+
label: labelText,
|
|
9
10
|
class: className = "",
|
|
10
11
|
onChange,
|
|
11
12
|
change,
|
|
@@ -40,7 +41,7 @@ export default function ComboBox({
|
|
|
40
41
|
return option({ value: opt.value }, opt.label ?? opt.value);
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
const selectElement = div({ class: "combobox" }, [
|
|
44
45
|
select({
|
|
45
46
|
class: `combobox-select ${sizeClass} ${className}`.trim(),
|
|
46
47
|
value: selection ?? "",
|
|
@@ -49,4 +50,9 @@ export default function ComboBox({
|
|
|
49
50
|
}, resolvedChildren),
|
|
50
51
|
span({ class: `combobox-chevron icon icon-chevron-down icon-base ${iconSizeClass}`.trim() })
|
|
51
52
|
]);
|
|
53
|
+
|
|
54
|
+
return div({ class: "column-container no-margin shrink-0 gap-0" }, [
|
|
55
|
+
labelText && label({ class: "label select-none" }, labelText),
|
|
56
|
+
selectElement
|
|
57
|
+
]);
|
|
52
58
|
}
|