@bunnix/components 0.9.2 → 0.9.3
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 +144 -3
- package/README.md +7 -1
- package/package.json +1 -1
- package/src/components/Dialog.mjs +1 -1
- package/src/components/ProgressBar.mjs +81 -0
- package/src/index.mjs +1 -0
- package/src/styles/controls.css +35 -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 & {});
|
|
@@ -344,6 +484,7 @@ export const NavigationBar: Component<NavigationBarProps>;
|
|
|
344
484
|
export const PageHeader: Component<PageHeaderProps>;
|
|
345
485
|
export const PageSection: Component<PageSectionProps>;
|
|
346
486
|
export const PopoverMenu: Component<PopoverMenuProps>;
|
|
487
|
+
export const ProgressBar: Component<ProgressBarProps>;
|
|
347
488
|
export const RadioCheckbox: Component<RadioCheckboxProps>;
|
|
348
489
|
export const SearchBox: Component<SearchBoxProps>;
|
|
349
490
|
export const Sidebar: Component<SidebarProps>;
|
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ You can compose your own UI using the same CSS utilities the components use:
|
|
|
101
101
|
- Typography: `text-default|primary|secondary|tertiary|quaternary`, `text-accent`, `text-destructive`, `text-sm|base|lg|xl`, `text-mono`, `whitespace-nowrap`, `whitespace-pre-line`
|
|
102
102
|
- Buttons: `btn`, `btn-flat`, `btn-outline`, `btn-destructive`, `btn-lg`, `btn-xl`, `btn-disabled`
|
|
103
103
|
- Forms: `input-lg`, `input-xl`, `rounded-full` (useful for pill inputs)
|
|
104
|
-
- Icons: `icon`, `icon-<name>`, `icon-xs|sm|lg|xl`, `icon-default|base|white|secondary|tertiary|quaternary`
|
|
104
|
+
- Icons: `icon`, `icon-<name>`, `icon-xs|sm|lg|xl`, `icon-default|base|white|secondary|tertiary|quaternary|destructive`
|
|
105
105
|
|
|
106
106
|
Example:
|
|
107
107
|
|
|
@@ -115,6 +115,12 @@ div({ class: "card row-container gap-sm items-center" }, [
|
|
|
115
115
|
]);
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
## Icon props
|
|
119
|
+
|
|
120
|
+
- `name`: icon slug (e.g. `star`) or a full class (e.g. `icon-star`). IDEs should autocomplete shipped icon names.
|
|
121
|
+
- `fill`: `default | base | white | secondary | tertiary | quaternary | destructive` or any `icon-*` utility.
|
|
122
|
+
- `size`: `xsmall | small | regular | large | xlarge` or `icon-xs | icon-sm | icon-lg | icon-xl`.
|
|
123
|
+
|
|
118
124
|
## Minimal webpack config
|
|
119
125
|
|
|
120
126
|
This is a minimal setup that works with `@bunnix/components` (ESM, CSS, and SVG assets):
|
package/package.json
CHANGED
|
@@ -136,7 +136,7 @@ export default function Dialog() {
|
|
|
136
136
|
VStack({
|
|
137
137
|
ref: panelRef,
|
|
138
138
|
gap: "regular",
|
|
139
|
-
class: "box-capsule dialog-panel shadow bg-base p-lg items-stretch dialog-appear"
|
|
139
|
+
class: "box-capsule dialog-panel shadow bg-base border-solid p-lg items-stretch dialog-appear"
|
|
140
140
|
}, [
|
|
141
141
|
HStack({ alignment: "leading", gap: "small", class: "items-center w-full" }, [
|
|
142
142
|
Text({ type: "heading4", class: "no-margin" }, dialogState.map((value) => value.title)),
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import Bunnix from "@bunnix/core";
|
|
2
|
+
import { clampSize, toSizeToken } from "../utils/sizeUtils.mjs";
|
|
3
|
+
|
|
4
|
+
const { div } = Bunnix;
|
|
5
|
+
|
|
6
|
+
export default function ProgressBar({
|
|
7
|
+
value = 0,
|
|
8
|
+
min = 0,
|
|
9
|
+
max = 100,
|
|
10
|
+
size,
|
|
11
|
+
color = "default",
|
|
12
|
+
class: className = "",
|
|
13
|
+
...rest
|
|
14
|
+
} = {}) {
|
|
15
|
+
const isState = (val) => val && typeof val.map === "function";
|
|
16
|
+
const normalizeSize = (val) =>
|
|
17
|
+
clampSize(val, ["xsmall", "small", "regular", "large", "xlarge"], "regular");
|
|
18
|
+
|
|
19
|
+
const sizeState = isState(size) ? size : null;
|
|
20
|
+
const classState = isState(className) ? className : null;
|
|
21
|
+
const colorState = isState(color) ? color : null;
|
|
22
|
+
const valueState = isState(value) ? value : null;
|
|
23
|
+
const minState = isState(min) ? min : null;
|
|
24
|
+
const maxState = isState(max) ? max : null;
|
|
25
|
+
|
|
26
|
+
const buildClass = (sizeValue, classValue) => {
|
|
27
|
+
const normalizedSize = normalizeSize(sizeValue);
|
|
28
|
+
const sizeToken = toSizeToken(normalizedSize);
|
|
29
|
+
const sizeClass = sizeToken ? `progress-bar-${sizeToken}` : "";
|
|
30
|
+
return `progress-bar ${sizeClass} ${classValue || ""}`.trim();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const buildFillClass = (colorValue) => {
|
|
34
|
+
const resolvedColor = colorValue || "default";
|
|
35
|
+
return `progress-bar-fill text-${resolvedColor}`.trim();
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const clampPercent = (val, minValue, maxValue) => {
|
|
39
|
+
const safeMin = Number.isFinite(Number(minValue)) ? Number(minValue) : 0;
|
|
40
|
+
const safeMax = Number.isFinite(Number(maxValue)) ? Number(maxValue) : 100;
|
|
41
|
+
const safeValue = Number.isFinite(Number(val)) ? Number(val) : 0;
|
|
42
|
+
|
|
43
|
+
if (safeMax <= safeMin) return 0;
|
|
44
|
+
|
|
45
|
+
const rawPercent = ((safeValue - safeMin) / (safeMax - safeMin)) * 100;
|
|
46
|
+
return Math.min(100, Math.max(0, rawPercent));
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const buildFillStyle = (val, minValue, maxValue) =>
|
|
50
|
+
`width: ${clampPercent(val, minValue, maxValue)}%;`;
|
|
51
|
+
|
|
52
|
+
const combinedClass = sizeState
|
|
53
|
+
? sizeState.map((value) => buildClass(value, classState ? classState.get() : className))
|
|
54
|
+
: classState
|
|
55
|
+
? classState.map((value) => buildClass(size, value))
|
|
56
|
+
: buildClass(size, className);
|
|
57
|
+
|
|
58
|
+
const fillClass = colorState ? colorState.map((value) => buildFillClass(value)) : buildFillClass(color);
|
|
59
|
+
|
|
60
|
+
const fillStyle = valueState
|
|
61
|
+
? valueState.map((val) =>
|
|
62
|
+
buildFillStyle(val, minState ? minState.get() : min, maxState ? maxState.get() : max)
|
|
63
|
+
)
|
|
64
|
+
: minState
|
|
65
|
+
? minState.map((val) => buildFillStyle(value, val, maxState ? maxState.get() : max))
|
|
66
|
+
: maxState
|
|
67
|
+
? maxState.map((val) => buildFillStyle(value, min, val))
|
|
68
|
+
: buildFillStyle(value, min, max);
|
|
69
|
+
|
|
70
|
+
return div(
|
|
71
|
+
{
|
|
72
|
+
class: combinedClass,
|
|
73
|
+
role: "progressbar",
|
|
74
|
+
"aria-valuemin": min,
|
|
75
|
+
"aria-valuemax": max,
|
|
76
|
+
"aria-valuenow": value,
|
|
77
|
+
...rest,
|
|
78
|
+
},
|
|
79
|
+
[div({ class: fillClass, style: fillStyle })],
|
|
80
|
+
);
|
|
81
|
+
}
|
package/src/index.mjs
CHANGED
|
@@ -17,6 +17,7 @@ export { default as NavigationBar } from "./components/NavigationBar.mjs";
|
|
|
17
17
|
export { default as PageHeader } from "./components/PageHeader.mjs";
|
|
18
18
|
export { default as PageSection } from "./components/PageSection.mjs";
|
|
19
19
|
export { default as PopoverMenu } from "./components/PopoverMenu.mjs";
|
|
20
|
+
export { default as ProgressBar } from "./components/ProgressBar.mjs";
|
|
20
21
|
export { default as RadioCheckbox } from "./components/RadioCheckbox.mjs";
|
|
21
22
|
export { default as SearchBox } from "./components/SearchBox.mjs";
|
|
22
23
|
export { default as Sidebar } from "./components/Sidebar.mjs";
|
package/src/styles/controls.css
CHANGED
|
@@ -201,6 +201,41 @@ textarea::placeholder {
|
|
|
201
201
|
color: white;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
/* Progress Bar */
|
|
205
|
+
.progress-bar {
|
|
206
|
+
width: 100%;
|
|
207
|
+
background-color: var(--alternate-background-color);
|
|
208
|
+
border-radius: var(--min-control-radius);
|
|
209
|
+
overflow: hidden;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.progress-bar-fill {
|
|
213
|
+
height: 100%;
|
|
214
|
+
width: 0%;
|
|
215
|
+
background-color: currentColor;
|
|
216
|
+
transition: width 0.2s ease;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.progress-bar-xs {
|
|
220
|
+
height: 0.25rem;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.progress-bar-sm {
|
|
224
|
+
height: 0.375rem;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.progress-bar-md {
|
|
228
|
+
height: 0.5rem;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.progress-bar-lg {
|
|
232
|
+
height: 0.75rem;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.progress-bar-xl {
|
|
236
|
+
height: 1rem;
|
|
237
|
+
}
|
|
238
|
+
|
|
204
239
|
.badge-solid.badge-dimmed {
|
|
205
240
|
background-color: var(--highlight-background-color);
|
|
206
241
|
color: var(--color-secondary);
|