@bunnix/components 0.10.1 → 0.10.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/package.json +1 -1
- package/src/core/buttons.css +3 -0
- package/src/core/core-mobile.css +69 -0
- package/src/core/core.css +29 -1
- package/src/core/input.css +4 -0
- package/src/core/inputs.mjs +2 -2
- package/src/core/layout.css +15 -0
- package/src/core/layout.mjs +7 -20
- package/src/core/menu.css +25 -3
- package/src/core/menu.mjs +6 -1
- package/src/core/table.css +3 -3
- package/src/core/table.mjs +3 -3
- package/src/core/utils.mjs +64 -0
package/package.json
CHANGED
package/src/core/buttons.css
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
display: flex;
|
|
6
6
|
flex-direction: row;
|
|
7
7
|
align-items: center;
|
|
8
|
+
flex-shrink: 0;
|
|
9
|
+
flex-wrap: nowrap;
|
|
8
10
|
justify-content: center;
|
|
9
11
|
cursor: pointer;
|
|
10
12
|
border-radius: var(--radius-md);
|
|
@@ -68,6 +70,7 @@
|
|
|
68
70
|
align-items: center;
|
|
69
71
|
cursor: pointer;
|
|
70
72
|
border-radius: var(--radius-md);
|
|
73
|
+
padding: 0;
|
|
71
74
|
user-select: none;
|
|
72
75
|
-webkit-user-select: none;
|
|
73
76
|
background: none;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.safe-insets {
|
|
2
|
+
padding-left: env(safe-area-inset-left);
|
|
3
|
+
padding-right: env(safe-area-inset-right);
|
|
4
|
+
padding-top: env(safe-area-inset-top);
|
|
5
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@media (max-width: 720px) {
|
|
9
|
+
:root {
|
|
10
|
+
--font-size-xlarge: 20px;
|
|
11
|
+
--font-size-large: 18px;
|
|
12
|
+
--font-size-default: 16px;
|
|
13
|
+
--font-size-small: 14px;
|
|
14
|
+
--font-size-xsmall: 12px;
|
|
15
|
+
|
|
16
|
+
--padding-sm: 10px;
|
|
17
|
+
--padding-md: 12px;
|
|
18
|
+
--padding-lg: 16px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.grid {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.table {
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.table thead {
|
|
32
|
+
display: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.table tbody tr {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
border-bottom: 1px solid var(--color-border-primary);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.table tbody tr:last-child {
|
|
42
|
+
border-bottom: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.table tbody td {
|
|
46
|
+
display: grid;
|
|
47
|
+
grid-template-columns: minmax(0.1fr, 0.3fr) 0.5fr;
|
|
48
|
+
border-bottom: none;
|
|
49
|
+
padding-top: var(--padding-md);
|
|
50
|
+
padding-bottom: 0;
|
|
51
|
+
row-gap: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.table tbody td:last-child {
|
|
55
|
+
padding-bottom: var(--padding-md);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.table tbody td[data-label]::before {
|
|
59
|
+
content: attr(data-label) ": ";
|
|
60
|
+
font-weight: var(--font-weight-heavier);
|
|
61
|
+
font-size: var(--font-size-default);
|
|
62
|
+
color: var(--color-fg-tertiary);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.checkbox {
|
|
66
|
+
width: 28px;
|
|
67
|
+
height: 28px;
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/core/core.css
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
--font-size-large: 16px;
|
|
62
62
|
--font-size-default: 14px;
|
|
63
63
|
--font-size-small: 12px;
|
|
64
|
-
--font-size-
|
|
64
|
+
--font-size-xsmall: 10px;
|
|
65
65
|
--font-weight-default: 400;
|
|
66
66
|
--font-weight-heavy: 500;
|
|
67
67
|
--font-weight-heavier: 600;
|
|
@@ -397,6 +397,27 @@ body {
|
|
|
397
397
|
flex-shrink: 0;
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
+
/* Layout positioning */
|
|
401
|
+
.sticky-top {
|
|
402
|
+
position: sticky;
|
|
403
|
+
top: 0;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.sticky-bottom {
|
|
407
|
+
position: sticky;
|
|
408
|
+
bottom: 0;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.fixed-top {
|
|
412
|
+
position: fixed;
|
|
413
|
+
top: 0;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.fixed-bottom {
|
|
417
|
+
position: fixed;
|
|
418
|
+
bottom: 0;
|
|
419
|
+
}
|
|
420
|
+
|
|
400
421
|
/* Spacing: padding */
|
|
401
422
|
.padding-none,
|
|
402
423
|
[padding="none"] {
|
|
@@ -610,6 +631,10 @@ body {
|
|
|
610
631
|
}
|
|
611
632
|
|
|
612
633
|
/* Effects */
|
|
634
|
+
.drop-shadow {
|
|
635
|
+
filter: drop-shadow(0px 1px 2px #00000033);
|
|
636
|
+
}
|
|
637
|
+
|
|
613
638
|
@media (prefers-color-scheme: dark) {
|
|
614
639
|
.dark-color-inverted,
|
|
615
640
|
[dark-color="inverted"],
|
|
@@ -618,3 +643,6 @@ body {
|
|
|
618
643
|
filter: brightness(0) invert(1);
|
|
619
644
|
}
|
|
620
645
|
}
|
|
646
|
+
|
|
647
|
+
/* Mobile overrides - must be imported last to properly override desktop values */
|
|
648
|
+
@import "./core-mobile.css";
|
package/src/core/input.css
CHANGED
package/src/core/inputs.mjs
CHANGED
|
@@ -233,7 +233,7 @@ export const TextInput = withNormalizedArgs((props, ...children) =>
|
|
|
233
233
|
export const Select = withNormalizedArgs((props, ...children) =>
|
|
234
234
|
withExtractedStyles((finalProps, ...children) =>
|
|
235
235
|
SelectCore(finalProps, ...children),
|
|
236
|
-
)({
|
|
236
|
+
)({ minHeight: 32, textSize: "1rem", ...props }, ...children),
|
|
237
237
|
);
|
|
238
238
|
|
|
239
239
|
/**
|
|
@@ -255,5 +255,5 @@ export const Select = withNormalizedArgs((props, ...children) =>
|
|
|
255
255
|
export const CheckBox = withNormalizedArgs((props, ...children) =>
|
|
256
256
|
withExtractedStyles((finalProps, ...children) =>
|
|
257
257
|
CheckBoxCore(finalProps, ...children),
|
|
258
|
-
)({
|
|
258
|
+
)({ textSize: "1rem", ...props }, ...children),
|
|
259
259
|
);
|
package/src/core/layout.css
CHANGED
|
@@ -18,3 +18,18 @@
|
|
|
18
18
|
flex-grow: 1;
|
|
19
19
|
flex-shrink: 1;
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
/* Grid Base Styles */
|
|
23
|
+
.grid {
|
|
24
|
+
--grid-gap: var(--gap-md);
|
|
25
|
+
display: grid;
|
|
26
|
+
column-gap: var(--grid-gap);
|
|
27
|
+
row-gap: var(--grid-gap);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.grid.flow {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-wrap: wrap;
|
|
33
|
+
flex-direction: row;
|
|
34
|
+
gap: var(--grid-gap);
|
|
35
|
+
}
|
package/src/core/layout.mjs
CHANGED
|
@@ -101,28 +101,16 @@ export const Spacer = withNormalizedArgs((props = {}, ...children) => {
|
|
|
101
101
|
const GridCore = (props, ...children) => {
|
|
102
102
|
let layout = props.layout ?? "fixed";
|
|
103
103
|
let columns = props.columns ?? [];
|
|
104
|
-
let gap = props.gridGap
|
|
104
|
+
let gap = props.gridGap;
|
|
105
105
|
|
|
106
106
|
delete props.layout;
|
|
107
107
|
delete props.columns;
|
|
108
108
|
delete props.gridGap;
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
let style = {};
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
"column-gap": gap,
|
|
115
|
-
"row-gap": gap,
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
if (layout === "flow") {
|
|
119
|
-
style = {
|
|
120
|
-
...style,
|
|
121
|
-
"display": "flex",
|
|
122
|
-
"flex-wrap": "wrap",
|
|
123
|
-
"flex-direction": "row",
|
|
124
|
-
"gap": gap
|
|
125
|
-
}
|
|
112
|
+
if (gap !== undefined) {
|
|
113
|
+
style["--grid-gap"] = (typeof gap === "number") ? `${gap}px` : gap;
|
|
126
114
|
}
|
|
127
115
|
|
|
128
116
|
if (layout === "fixed") {
|
|
@@ -132,14 +120,13 @@ const GridCore = (props, ...children) => {
|
|
|
132
120
|
return col.size ?? "1fr";
|
|
133
121
|
}).join(" ");
|
|
134
122
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
"grid-template-columns": columnsTemplate,
|
|
123
|
+
if (columnsTemplate) {
|
|
124
|
+
style["grid-template-columns"] = columnsTemplate;
|
|
138
125
|
}
|
|
139
126
|
}
|
|
140
127
|
|
|
141
128
|
return div(
|
|
142
|
-
{ ...props, class: `grid ${props.class ?? ""}`, style },
|
|
129
|
+
{ ...props, class: `grid ${layout} ${props.class ?? ""}`, style },
|
|
143
130
|
children
|
|
144
131
|
)
|
|
145
132
|
};
|
package/src/core/menu.css
CHANGED
|
@@ -7,9 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
.menu-items {
|
|
9
9
|
position: absolute;
|
|
10
|
-
top: 100%;
|
|
11
|
-
left: 0;
|
|
12
|
-
margin-top: 4px;
|
|
13
10
|
background-color: var(--color-bg-primary);
|
|
14
11
|
border: 1px solid var(--color-border-primary);
|
|
15
12
|
border-radius: var(--radius-md);
|
|
@@ -19,6 +16,31 @@
|
|
|
19
16
|
padding: 4px;
|
|
20
17
|
}
|
|
21
18
|
|
|
19
|
+
/* Anchor positions */
|
|
20
|
+
.menu-items--bottomLeft {
|
|
21
|
+
top: 100%;
|
|
22
|
+
left: 0;
|
|
23
|
+
margin-top: 4px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.menu-items--bottomRight {
|
|
27
|
+
top: 100%;
|
|
28
|
+
right: 0;
|
|
29
|
+
margin-top: 4px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.menu-items--topLeft {
|
|
33
|
+
bottom: 100%;
|
|
34
|
+
left: 0;
|
|
35
|
+
margin-bottom: 4px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.menu-items--topRight {
|
|
39
|
+
bottom: 100%;
|
|
40
|
+
right: 0;
|
|
41
|
+
margin-bottom: 4px;
|
|
42
|
+
}
|
|
43
|
+
|
|
22
44
|
.menu-divider {
|
|
23
45
|
height: 1px;
|
|
24
46
|
background-color: var(--color-border-primary);
|
package/src/core/menu.mjs
CHANGED
|
@@ -34,8 +34,12 @@ const MenuCore = (props, ...children) => {
|
|
|
34
34
|
// Resolve trigger
|
|
35
35
|
let trigger = props.trigger || "Menu";
|
|
36
36
|
|
|
37
|
+
// Resolve anchor position
|
|
38
|
+
let anchor = props.anchor || "bottomLeft";
|
|
39
|
+
|
|
37
40
|
delete props.items;
|
|
38
41
|
delete props.trigger;
|
|
42
|
+
delete props.anchor;
|
|
39
43
|
|
|
40
44
|
// Click outside handler
|
|
41
45
|
useEffect(() => {
|
|
@@ -79,7 +83,7 @@ const MenuCore = (props, ...children) => {
|
|
|
79
83
|
// Menu
|
|
80
84
|
Show(isOpen, (open) =>
|
|
81
85
|
open && div(
|
|
82
|
-
{ class:
|
|
86
|
+
{ class: `menu-items menu-items--${anchor}` },
|
|
83
87
|
Column(
|
|
84
88
|
{ gap: 0 },
|
|
85
89
|
...items.map((item) => {
|
|
@@ -117,6 +121,7 @@ const MenuCore = (props, ...children) => {
|
|
|
117
121
|
* @param {Function} [props.items[].action] - Optional action to run on click
|
|
118
122
|
* @param {boolean} [props.items[].divider] - If true, renders a divider
|
|
119
123
|
* @param {*} [props.trigger] - Trigger element or function that receives {isOpen, toggle}
|
|
124
|
+
* @param {string} [props.anchor="bottomLeft"] - Menu anchor position: "topLeft" | "topRight" | "bottomLeft" | "bottomRight"
|
|
120
125
|
* @param {string} [props.class] - Additional CSS classes
|
|
121
126
|
* @param {...*} children - Children elements
|
|
122
127
|
* @returns {*} Menu component
|
package/src/core/table.css
CHANGED
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
.table thead td,
|
|
11
11
|
.table th {
|
|
12
|
-
font-weight: var(--font-weight-
|
|
13
|
-
padding: var(--padding-
|
|
12
|
+
font-weight: var(--font-weight-heavier);
|
|
13
|
+
padding: calc(var(--padding-md) * 0.75) var(--padding-md);
|
|
14
14
|
border-bottom: 1px solid var(--color-border-primary);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.table td {
|
|
18
|
-
padding: var(--padding-
|
|
18
|
+
padding: calc(var(--padding-md) * 0.5) var(--padding-md);
|
|
19
19
|
border-bottom: 1px solid var(--color-border-primary);
|
|
20
20
|
}
|
|
21
21
|
|
package/src/core/table.mjs
CHANGED
|
@@ -32,7 +32,7 @@ const TableCore = withNormalizedArgs((props, ...children) => {
|
|
|
32
32
|
headers.map((h) => {
|
|
33
33
|
if (!h.key) return td("");
|
|
34
34
|
if (!(h.key in r)) return td("");
|
|
35
|
-
return td(r[h.key]);
|
|
35
|
+
return td({ "data-label": h.content }, r[h.key]);
|
|
36
36
|
}),
|
|
37
37
|
),
|
|
38
38
|
);
|
|
@@ -52,7 +52,7 @@ const TableCore = withNormalizedArgs((props, ...children) => {
|
|
|
52
52
|
// Apply default Table props at export
|
|
53
53
|
/**
|
|
54
54
|
* Data table component with column headers and row rendering.
|
|
55
|
-
*
|
|
55
|
+
*
|
|
56
56
|
* @param {Object} props - Component props
|
|
57
57
|
* @param {Array<{content: *, key: string, size?: number}>} props.headers - Column definitions with content, key for data mapping, and optional size
|
|
58
58
|
* @param {Array<Object>} props.rows - Array of data objects to render as rows (keys should match header keys)
|
|
@@ -60,7 +60,7 @@ const TableCore = withNormalizedArgs((props, ...children) => {
|
|
|
60
60
|
* @param {string} [props.class] - Additional CSS classes
|
|
61
61
|
* @param {...*} children - Child elements
|
|
62
62
|
* @returns {*} Table component
|
|
63
|
-
*
|
|
63
|
+
*
|
|
64
64
|
* @example
|
|
65
65
|
* Table({
|
|
66
66
|
* headers: [
|
package/src/core/utils.mjs
CHANGED
|
@@ -161,6 +161,70 @@ export function withExtractedStyles(fn) {
|
|
|
161
161
|
delete finalProps.marginY;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
if ("marginLeft" in props) {
|
|
165
|
+
style.marginLeft =
|
|
166
|
+
typeof props.marginLeft === "number"
|
|
167
|
+
? `${props.marginLeft}px`
|
|
168
|
+
: props.marginLeft;
|
|
169
|
+
delete finalProps.marginLeft;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if ("marginRight" in props) {
|
|
173
|
+
style.marginRight =
|
|
174
|
+
typeof props.marginRight === "number"
|
|
175
|
+
? `${props.marginRight}px`
|
|
176
|
+
: props.marginRight;
|
|
177
|
+
delete finalProps.marginRight;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if ("marginTop" in props) {
|
|
181
|
+
style.marginTop =
|
|
182
|
+
typeof props.marginTop === "number"
|
|
183
|
+
? `${props.marginTop}px`
|
|
184
|
+
: props.marginTop;
|
|
185
|
+
delete finalProps.marginTop;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if ("marginBottom" in props) {
|
|
189
|
+
style.marginBottom =
|
|
190
|
+
typeof props.marginBottom === "number"
|
|
191
|
+
? `${props.marginBottom}px`
|
|
192
|
+
: props.marginBottom;
|
|
193
|
+
delete finalProps.marginBottom;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if ("top" in props) {
|
|
197
|
+
style.top =
|
|
198
|
+
typeof props.top === "number"
|
|
199
|
+
? `${props.top}px`
|
|
200
|
+
: props.top;
|
|
201
|
+
delete finalProps.top;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if ("bottom" in props) {
|
|
205
|
+
style.bottom =
|
|
206
|
+
typeof props.bottom === "number"
|
|
207
|
+
? `${props.bottom}px`
|
|
208
|
+
: props.bottom;
|
|
209
|
+
delete finalProps.bottom;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if ("left" in props) {
|
|
213
|
+
style.left =
|
|
214
|
+
typeof props.left === "number"
|
|
215
|
+
? `${props.left}px`
|
|
216
|
+
: props.left;
|
|
217
|
+
delete finalProps.left;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if ("right" in props) {
|
|
221
|
+
style.right =
|
|
222
|
+
typeof props.right === "number"
|
|
223
|
+
? `${props.right}px`
|
|
224
|
+
: props.right;
|
|
225
|
+
delete finalProps.right;
|
|
226
|
+
}
|
|
227
|
+
|
|
164
228
|
if ("flexGrow" in props) {
|
|
165
229
|
style.flexGrow = props.flexGrow;
|
|
166
230
|
delete finalProps.flexGrow;
|