@bunnix/components 0.9.0 → 0.9.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.
Files changed (42) hide show
  1. package/@types/index.d.ts +134 -30
  2. package/README.md +2 -2
  3. package/package.json +1 -1
  4. package/src/components/AccordionGroup.mjs +2 -1
  5. package/src/components/Badge.mjs +18 -4
  6. package/src/components/Button.mjs +7 -9
  7. package/src/components/Card.mjs +37 -0
  8. package/src/components/Checkbox.mjs +5 -7
  9. package/src/components/CodeBlock.mjs +31 -0
  10. package/src/components/ComboBox.mjs +22 -14
  11. package/src/components/Container.mjs +8 -10
  12. package/src/components/DatePicker.mjs +13 -15
  13. package/src/components/Dialog.mjs +35 -4
  14. package/src/components/DropdownMenu.mjs +16 -14
  15. package/src/components/HStack.mjs +11 -3
  16. package/src/components/Icon.mjs +9 -5
  17. package/src/components/InputField.mjs +12 -4
  18. package/src/components/NavigationBar.mjs +55 -25
  19. package/src/components/PageHeader.mjs +11 -8
  20. package/src/components/PageSection.mjs +20 -10
  21. package/src/components/PopoverMenu.mjs +94 -50
  22. package/src/components/RadioCheckbox.mjs +5 -7
  23. package/src/components/SearchBox.mjs +12 -21
  24. package/src/components/Sidebar.mjs +142 -67
  25. package/src/components/Table.mjs +145 -96
  26. package/src/components/Text.mjs +52 -21
  27. package/src/components/TimePicker.mjs +13 -15
  28. package/src/components/ToastNotification.mjs +16 -13
  29. package/src/components/ToggleSwitch.mjs +5 -7
  30. package/src/components/VStack.mjs +7 -6
  31. package/src/index.mjs +2 -0
  32. package/src/styles/buttons.css +8 -0
  33. package/src/styles/colors.css +8 -0
  34. package/src/styles/controls.css +61 -0
  35. package/src/styles/layout.css +64 -5
  36. package/src/styles/media.css +11 -0
  37. package/src/styles/menu.css +39 -21
  38. package/src/styles/table.css +2 -2
  39. package/src/styles/typography.css +25 -0
  40. package/src/styles/variables.css +3 -0
  41. package/src/utils/iconUtils.mjs +10 -0
  42. package/src/utils/sizeUtils.mjs +87 -0
package/@types/index.d.ts CHANGED
@@ -6,10 +6,16 @@ export interface BaseProps {
6
6
  [key: string]: unknown;
7
7
  }
8
8
 
9
+ export type Size = "xsmall" | "small" | "regular" | "large" | "xlarge";
10
+ export type LegacySize = "xs" | "sm" | "md" | "lg" | "xl" | "default";
11
+ export type SizeValue = Size | LegacySize;
12
+ export type SizeNoSmall = Exclude<SizeValue, "small" | "sm">;
13
+ export type SizeRegularUp = Exclude<SizeValue, "xsmall" | "xs" | "small" | "sm">;
14
+
9
15
  export interface ButtonProps extends BaseProps {
10
16
  type?: string;
11
17
  variant?: string;
12
- size?: "sm" | "md" | "lg" | "xl" | string;
18
+ size?: SizeValue;
13
19
  href?: string;
14
20
  disabled?: boolean;
15
21
  onClick?: (event?: any) => void;
@@ -19,28 +25,53 @@ export interface ButtonProps extends BaseProps {
19
25
  export interface IconProps extends BaseProps {
20
26
  name?: string;
21
27
  fill?: string;
22
- size?: "xs" | "sm" | "md" | "lg" | "xl" | string;
28
+ size?: SizeValue | `icon-${string}`;
23
29
  }
24
30
 
25
31
  export interface TextProps extends BaseProps {
26
- type?: "text" | "paragraph" | "heading1" | "heading2" | "heading3" | "heading4" | string;
27
- color?: string;
28
- design?: "regular" | "mono" | string;
32
+ type?: "text" | "paragraph" | "heading1" | "heading2" | "heading3" | "heading4";
33
+ color?: "default"
34
+ | "primary"
35
+ | "primary-dimmed"
36
+ | "secondary"
37
+ | "tertiary"
38
+ | "quaternary"
39
+ | "destructive"
40
+ | "destructive-dimmed"
41
+ | "accent"
42
+ | "accent-dimmed"
43
+ | "white"
44
+ | (string & {});
45
+ design?: "regular" | "mono";
46
+ weight?: "regular" | "semibold" | "bold";
47
+ size?: SizeValue;
48
+ wrap?: "wrap" | "nowrap";
29
49
  }
30
50
 
31
51
  export interface ContainerProps extends BaseProps {
32
- type?: "main" | "content" | "page" | string;
33
- direction?: "horizontal" | "vertical" | string;
52
+ type?: "main" | "content" | "page" | (string & {});
53
+ direction?: "row" | "column" | (string & {});
34
54
  }
35
55
 
36
- export interface StackProps extends BaseProps {
56
+ export interface CardProps extends BaseProps {
57
+ direction?: "horizontal" | "vertical" | string;
37
58
  alignment?: "leading" | "middle" | "trailing" | string;
38
- gap?: "small" | "regular" | "large" | string;
59
+ }
60
+
61
+ export interface HStackProps extends BaseProps {
62
+ alignment?: "leading" | "middle" | "trailing" | (string & {});
63
+ verticalAlignment?: "top" | "center" | "bottom" | (string & {});
64
+ gap?: "xsmall" | "small" | "regular" | "large" | (string & {});
65
+ }
66
+
67
+ export interface VStackProps extends BaseProps {
68
+ alignment?: "leading" | "middle" | "trailing" | (string & {});
69
+ gap?: "xsmall" | "small" | "regular" | "large" | (string & {});
39
70
  }
40
71
 
41
72
  export interface BadgeProps extends BaseProps {
42
73
  tone?: "base" | "success" | "info" | "warning" | "danger" | "accent" | "dimmed" | string;
43
- size?: "xs" | "sm" | "md" | string;
74
+ size?: SizeValue;
44
75
  variant?: "solid" | "soft" | "outline" | string;
45
76
  icon?: string;
46
77
  overlap?: boolean;
@@ -50,6 +81,7 @@ export interface BadgeProps extends BaseProps {
50
81
  export interface InputFieldProps extends BaseProps {
51
82
  type?: string;
52
83
  variant?: "regular" | "rounded" | string;
84
+ size?: SizeRegularUp;
53
85
  value?: string;
54
86
  placeholder?: string;
55
87
  label?: string;
@@ -67,6 +99,13 @@ export interface InputFieldProps extends BaseProps {
67
99
  keydown?: (event?: any) => void;
68
100
  }
69
101
 
102
+ export interface CodeBlockProps extends BaseProps {
103
+ html?: string;
104
+ language?: string;
105
+ overflowX?: "auto" | "scroll" | "hidden" | string;
106
+ wrap?: boolean;
107
+ }
108
+
70
109
  export interface ComboBoxOption {
71
110
  value: string;
72
111
  label?: string;
@@ -75,14 +114,14 @@ export interface ComboBoxOption {
75
114
  export interface ComboBoxProps extends BaseProps {
76
115
  options?: Array<string | ComboBoxOption>;
77
116
  selection?: any;
78
- size?: "sm" | "md" | "lg" | "xl" | string;
117
+ size?: SizeValue;
79
118
  onChange?: (event?: any) => void;
80
119
  change?: (event?: any) => void;
81
120
  }
82
121
 
83
122
  export interface CheckboxProps extends BaseProps {
84
123
  labelText?: string;
85
- size?: "sm" | "md" | "lg" | "xl" | string;
124
+ size?: SizeValue;
86
125
  onCheck?: (checked: boolean) => void;
87
126
  check?: (checked: boolean) => void;
88
127
  onChange?: (event?: any) => void;
@@ -90,7 +129,7 @@ export interface CheckboxProps extends BaseProps {
90
129
 
91
130
  export interface RadioCheckboxProps extends BaseProps {
92
131
  labelText?: string;
93
- size?: "sm" | "md" | "lg" | "xl" | string;
132
+ size?: SizeValue;
94
133
  onCheck?: (checked: boolean) => void;
95
134
  check?: (checked: boolean) => void;
96
135
  onChange?: (event?: any) => void;
@@ -98,7 +137,7 @@ export interface RadioCheckboxProps extends BaseProps {
98
137
 
99
138
  export interface ToggleSwitchProps extends BaseProps {
100
139
  labelText?: string;
101
- size?: "sm" | "md" | "lg" | "xl" | string;
140
+ size?: SizeValue;
102
141
  onChange?: (event?: any) => void;
103
142
  }
104
143
 
@@ -115,7 +154,7 @@ export interface SearchBoxProps extends BaseProps {
115
154
  placeholder?: string;
116
155
  onInput?: (event?: any) => void;
117
156
  input?: (event?: any) => void;
118
- size?: "sm" | "md" | "lg" | "xl" | string;
157
+ size?: SizeValue;
119
158
  variant?: "regular" | "rounded" | string;
120
159
  onSelect?: (item?: SearchBoxItem) => void;
121
160
  select?: (item?: SearchBoxItem) => void;
@@ -124,9 +163,13 @@ export interface SearchBoxProps extends BaseProps {
124
163
  export interface SidebarItem {
125
164
  id?: string;
126
165
  label?: string;
166
+ /**
167
+ * Icon name. Accepts either a full icon class (e.g. "icon-person")
168
+ * or a bare name (e.g. "person"), which will be prefixed with "icon-".
169
+ */
127
170
  icon?: string;
128
171
  href?: string | null;
129
- badge?: string | number | { value?: string | number; tone?: string; variant?: string; size?: string };
172
+ badge?: string | number | { value?: string | number; tone?: string; variant?: string; size?: SizeValue };
130
173
  children?: SidebarItem[];
131
174
  isExpanded?: boolean;
132
175
  isHeader?: boolean;
@@ -136,15 +179,18 @@ export interface SidebarItem {
136
179
 
137
180
  export interface SidebarProps extends BaseProps {
138
181
  items?: SidebarItem[];
139
- selection?: string;
182
+ selection?: string | any;
183
+ /** @deprecated Use onItemSelect instead. */
140
184
  onSelect?: (id?: string) => void;
141
185
  onItemSelect?: (id?: string) => void;
142
186
  searchable?: boolean;
143
187
  searchProps?: Record<string, unknown>;
188
+ leading?: BunnixChildren | (() => BunnixChildren);
189
+ trailing?: BunnixChildren | (() => BunnixChildren);
144
190
  }
145
191
 
146
192
  export interface NavigationBarProps extends BaseProps {
147
- title?: string | (() => BunnixChildren);
193
+ title?: string | any;
148
194
  leading?: BunnixChildren | (() => BunnixChildren);
149
195
  trailing?: BunnixChildren | (() => BunnixChildren);
150
196
  searchable?: boolean;
@@ -160,18 +206,22 @@ export interface DatePickerProps extends BaseProps {
160
206
  placeholder?: string;
161
207
  range?: boolean;
162
208
  variant?: "regular" | "rounded" | string;
163
- size?: "md" | "lg" | "xl" | string;
209
+ size?: SizeNoSmall;
164
210
  }
165
211
 
166
212
  export interface TimePickerProps extends BaseProps {
167
213
  id?: string;
168
214
  placeholder?: string;
169
215
  variant?: "regular" | "rounded" | string;
170
- size?: "md" | "lg" | "xl" | string;
216
+ size?: SizeNoSmall;
171
217
  }
172
218
 
173
219
  export interface DropdownMenuItem {
174
220
  title?: string;
221
+ /**
222
+ * Icon name. Accepts either a full icon class (e.g. "icon-person")
223
+ * or a bare name (e.g. "person"), which will be prefixed with "icon-".
224
+ */
175
225
  icon?: string;
176
226
  destructive?: boolean;
177
227
  isSeparator?: boolean;
@@ -185,16 +235,16 @@ export interface DropdownMenuProps extends BaseProps {
185
235
  id?: string;
186
236
  align?: "left" | "right" | string;
187
237
  placeholder?: string;
188
- size?: "sm" | "md" | "lg" | "xl" | string;
238
+ size?: SizeValue;
189
239
  onSelect?: (item?: DropdownMenuItem) => void;
190
240
  }
191
241
 
192
242
  export interface PopoverMenuProps extends BaseProps {
193
- trigger?: BunnixChildren;
194
- items?: DropdownMenuItem[];
243
+ trigger?: BunnixChildren | (() => BunnixChildren);
244
+ menuItems?: DropdownMenuItem[];
195
245
  id?: string;
196
246
  align?: "left" | "right" | string;
197
- size?: "sm" | "md" | "lg" | "xl" | string;
247
+ size?: SizeValue;
198
248
  onSelect?: (item?: DropdownMenuItem) => void;
199
249
  }
200
250
 
@@ -209,6 +259,8 @@ export interface DialogConfirmation {
209
259
  export interface ShowDialogOptions {
210
260
  title?: string;
211
261
  message?: string;
262
+ minWidth?: number | string | null;
263
+ minHeight?: number | string | null;
212
264
  confirmation?: DialogConfirmation;
213
265
  content?: (args: { setConfirmDisabled: (disabled: boolean) => void }) => BunnixChildren;
214
266
  }
@@ -217,38 +269,90 @@ export interface ToastOptions {
217
269
  message?: string;
218
270
  duration?: number;
219
271
  anchor?: "topRight" | "topLeft" | "bottomRight" | "bottomLeft" | string;
220
- size?: "md" | "lg" | "xl" | string;
272
+ size?: SizeNoSmall;
273
+ /**
274
+ * Icon name. Accepts either a full icon class (e.g. "icon-bell")
275
+ * or a bare name (e.g. "bell"), which will be prefixed with "icon-".
276
+ */
221
277
  icon?: string;
222
278
  }
223
279
 
280
+ export interface PageHeaderProps extends BaseProps {
281
+ title?: string;
282
+ description?: string;
283
+ trailing?: BunnixChildren | (() => BunnixChildren);
284
+ }
285
+
286
+ export interface PageSectionProps extends BaseProps {
287
+ title?: string;
288
+ stickyOffset?: string | number;
289
+ gap?: "small" | "regular" | "large" | string;
290
+ trailing?: BunnixChildren | (() => BunnixChildren);
291
+ }
292
+
293
+ export interface TableColumn {
294
+ field: string;
295
+ label: string;
296
+ size?: "auto" | number | string;
297
+ }
298
+
299
+ export interface TableSortableConfig {
300
+ field: string;
301
+ sortType?: "string" | "number" | "date";
302
+ sorted?: boolean;
303
+ direction?: "asc" | "desc";
304
+ }
305
+
306
+ export interface TableSearchableConfig {
307
+ field: string;
308
+ searchText?: string | any;
309
+ }
310
+
311
+ export interface TableProps extends BaseProps {
312
+ columns?: Array<TableColumn>;
313
+ data?: Array<any> | any;
314
+ key?: string;
315
+ renderCell?: (columnIndex: number, field: string, row: any, column?: TableColumn) => any;
316
+ cell?: (columnIndex: number, field: string, row: any, column?: TableColumn) => any;
317
+ searchable?: TableSearchableConfig;
318
+ sortable?: Array<TableSortableConfig>;
319
+ selection?: (keys: Array<string>) => void;
320
+ sort?: (field?: string) => ((a: any, b: any) => number) | null;
321
+ variant?: "regular" | "background" | "bordered" | string;
322
+ interactive?: boolean;
323
+ hideHeaders?: boolean;
324
+ }
325
+
224
326
  export type Component<P = BaseProps> = (props?: P, children?: BunnixChildren) => any;
225
327
 
226
328
  export const AccordionGroup: Component<BaseProps>;
227
329
  export const Badge: Component<BadgeProps>;
228
330
  export const Button: Component<ButtonProps>;
331
+ export const Card: Component<CardProps>;
229
332
  export const Checkbox: Component<CheckboxProps>;
333
+ export const CodeBlock: Component<CodeBlockProps>;
230
334
  export const ComboBox: Component<ComboBoxProps>;
231
335
  export const Container: Component<ContainerProps>;
232
336
  export const DatePicker: Component<DatePickerProps>;
233
337
  export const Dialog: Component<BaseProps>;
234
338
  export const DropdownMenu: Component<DropdownMenuProps>;
235
339
  export const Grid: Component<BaseProps>;
236
- export const HStack: Component<StackProps>;
340
+ export const HStack: Component<HStackProps>;
237
341
  export const Icon: Component<IconProps>;
238
342
  export const InputField: Component<InputFieldProps>;
239
343
  export const NavigationBar: Component<NavigationBarProps>;
240
- export const PageHeader: Component<BaseProps>;
241
- export const PageSection: Component<BaseProps>;
344
+ export const PageHeader: Component<PageHeaderProps>;
345
+ export const PageSection: Component<PageSectionProps>;
242
346
  export const PopoverMenu: Component<PopoverMenuProps>;
243
347
  export const RadioCheckbox: Component<RadioCheckboxProps>;
244
348
  export const SearchBox: Component<SearchBoxProps>;
245
349
  export const Sidebar: Component<SidebarProps>;
246
- export const Table: Component<BaseProps>;
350
+ export const Table: Component<TableProps>;
247
351
  export const Text: Component<TextProps>;
248
352
  export const TimePicker: Component<TimePickerProps>;
249
353
  export const ToastNotification: Component<BaseProps>;
250
354
  export const ToggleSwitch: Component<ToggleSwitchProps>;
251
- export const VStack: Component<StackProps>;
355
+ export const VStack: Component<VStackProps>;
252
356
 
253
357
  export const dialogState: any;
254
358
  export function showDialog(options?: ShowDialogOptions): void;
package/README.md CHANGED
@@ -98,10 +98,10 @@ You can compose your own UI using the same CSS utilities the components use:
98
98
 
99
99
  - Layout: `row-container`, `column-container`, `grid-flow`, `gap-xs|sm|md|lg`, `items-start|center|end|stretch`, `justify-start|center|end`, `w-full`, `h-full`, `spacer-h`, `spacer-v`
100
100
  - Surfaces: `box`, `box-sm`, `box-control`, `box-capsule`, `card`, `shadow`, `rounded|rounded-sm|rounded-full`
101
- - Typography: `text-primary|secondary|tertiary|quaternary`, `text-accent`, `text-destructive`, `text-sm|base|lg|xl`, `text-mono`, `whitespace-nowrap`, `whitespace-pre-line`
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-base|white|secondary|tertiary|quaternary`
104
+ - Icons: `icon`, `icon-<name>`, `icon-xs|sm|lg|xl`, `icon-default|base|white|secondary|tertiary|quaternary`
105
105
 
106
106
  Example:
107
107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunnix/components",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Bunnix components: a set of bunnix ready components for modern web apps.",
5
5
  "keywords": [
6
6
  "bunnix",
@@ -1,4 +1,5 @@
1
1
  import Bunnix, { useState } from "@bunnix/core";
2
+ import { resolveIconClass } from "../utils/iconUtils.mjs";
2
3
  const { div, button, span, p } = Bunnix;
3
4
 
4
5
  export default function AccordionGroup({ items = [], class: className = "", initialIndex } = {}) {
@@ -16,7 +17,7 @@ export default function AccordionGroup({ items = [], class: className = "", init
16
17
  { class: `accordion-group ${className}`.trim() },
17
18
  items.map((item, index) => {
18
19
  const isOpen = openIndex.map((value) => value === index);
19
- const iconClass = item.icon ? item.icon : "icon-add";
20
+ const iconClass = resolveIconClass(item.icon) || "icon-add";
20
21
  const description = item.description ?? item.content ?? "";
21
22
 
22
23
  return div({ class: isOpen.map((open) => `accordion-item hoverable ${open ? "accordion-open" : ""}`) }, [
@@ -1,4 +1,5 @@
1
1
  import Bunnix from "@bunnix/core";
2
+ import { clampSize, toSizeToken } from "../utils/sizeUtils.mjs";
2
3
  import Icon from "./Icon.mjs";
3
4
 
4
5
  const { span } = Bunnix;
@@ -16,7 +17,9 @@ const toneClassMap = {
16
17
  const sizeClassMap = {
17
18
  xs: "badge-xs",
18
19
  sm: "badge-sm",
19
- md: "badge-md"
20
+ md: "badge-md",
21
+ lg: "badge-lg",
22
+ xl: "badge-xl"
20
23
  };
21
24
 
22
25
  const variantClassMap = {
@@ -27,17 +30,28 @@ const variantClassMap = {
27
30
 
28
31
  export default function Badge({
29
32
  tone = "base",
30
- size = "sm",
33
+ size = "small",
31
34
  variant = "solid",
32
35
  icon,
33
36
  overlap = false,
34
37
  shape = "capsule",
35
38
  class: className = ""
36
39
  } = {}, children) {
40
+ // Badge supports all sizes
41
+ const normalizeSize = (value) => clampSize(value, ["xsmall", "small", "regular", "large", "xlarge"], "small");
42
+ const normalizedSize = normalizeSize(size);
43
+ const sizeToken = toSizeToken(normalizedSize);
44
+
37
45
  const toneClass = toneClassMap[tone] || toneClassMap.base;
38
- const sizeClass = sizeClassMap[size] || sizeClassMap.sm;
46
+ const sizeClass = sizeClassMap[sizeToken] || sizeClassMap.sm;
39
47
  const variantClass = variantClassMap[variant] || variantClassMap.solid;
40
- const iconSize = size === "md" ? "lg" : size === "xs" ? "xs" : "sm";
48
+ const iconSize = normalizedSize === "regular"
49
+ ? "large"
50
+ : normalizedSize === "xsmall"
51
+ ? "xsmall"
52
+ : normalizedSize === "xlarge"
53
+ ? "xlarge"
54
+ : "small";
41
55
  const overlapClass = overlap ? "badge-overlap" : "";
42
56
  const shapeClass = shape === "circle" ? "badge-circle" : "";
43
57
  const combinedClass = `badge ${toneClass} ${sizeClass} ${variantClass} ${overlapClass} ${shapeClass} ${className}`.trim();
@@ -1,4 +1,5 @@
1
1
  import Bunnix from "@bunnix/core";
2
+ import { clampSize, toSizeToken } from "../utils/sizeUtils.mjs";
2
3
  const { button, a } = Bunnix;
3
4
 
4
5
  export default function Button({
@@ -12,12 +13,8 @@ export default function Button({
12
13
  class: className = "",
13
14
  ...rest
14
15
  } = {}, children) {
15
- const normalizeSize = (value) => {
16
- if (!value || value === "default" || value === "regular" || value === "md") return "md";
17
- if (value === "sm") return "sm";
18
- if (value === "lg" || value === "xl") return value;
19
- return value;
20
- };
16
+ // Button supports all sizes
17
+ const normalizeSize = (value) => clampSize(value, ["xsmall", "small", "regular", "large", "xlarge"], "regular");
21
18
 
22
19
  const variantState = variant && typeof variant.map === "function" ? variant : null;
23
20
  const sizeState = size && typeof size.map === "function" ? size : null;
@@ -28,13 +25,14 @@ export default function Button({
28
25
 
29
26
  const buildClass = (variantValue, sizeValue, disabledValue) => {
30
27
  const normalizedSize = normalizeSize(sizeValue);
28
+ const sizeToken = toSizeToken(normalizedSize);
31
29
  const baseClass = isHyperlink ? "" : "btn";
32
30
  const variantClass = (isHyperlink || variantValue === "regular") ? "" : `btn-${variantValue}`;
33
- const sizeClass = (!isHyperlink && normalizedSize && normalizedSize !== "md" && (normalizedSize === "lg" || normalizedSize === "xl"))
34
- ? `btn-${normalizedSize}`
31
+ const sizeClass = (!isHyperlink && sizeToken && sizeToken !== "md")
32
+ ? `btn-${sizeToken}`
35
33
  : "";
36
34
  const disabledClass = disabledValue ? "btn-disabled" : "";
37
- return `${baseClass} ${variantClass} ${sizeClass} ${disabledClass} ${className}`.trim();
35
+ return `row-container justify-start shrink-0 no-selectable ${baseClass} ${variantClass} ${sizeClass} ${disabledClass} ${className}`.trim();
38
36
  };
39
37
 
40
38
  const combinedClass = variantState
@@ -0,0 +1,37 @@
1
+ import Bunnix from "@bunnix/core";
2
+
3
+ const { div } = Bunnix;
4
+
5
+ const directionClassMap = {
6
+ horizontal: "row-container",
7
+ vertical: "column-container"
8
+ };
9
+
10
+ export default function Card({
11
+ direction,
12
+ alignment,
13
+ class: className = "",
14
+ ...rest
15
+ } = {}, children) {
16
+ const directionClass = directionClassMap[direction] || "";
17
+ const rowAlignmentMap = {
18
+ leading: "justify-start",
19
+ middle: "justify-center",
20
+ trailing: "justify-end"
21
+ };
22
+ const columnAlignmentMap = {
23
+ leading: "items-start",
24
+ middle: "items-center",
25
+ trailing: "items-end"
26
+ };
27
+ const alignmentClass = alignment
28
+ ? direction === "vertical"
29
+ ? columnAlignmentMap[alignment] || ""
30
+ : direction === "horizontal"
31
+ ? rowAlignmentMap[alignment] || ""
32
+ : ""
33
+ : "";
34
+ const combinedClass = `card ${directionClass} ${alignmentClass} ${className}`.trim();
35
+
36
+ return div({ class: combinedClass, ...rest }, children);
37
+ }
@@ -1,4 +1,5 @@
1
1
  import Bunnix from "@bunnix/core";
2
+ import { clampSize, toSizeToken } from "../utils/sizeUtils.mjs";
2
3
  const { label, input, span } = Bunnix;
3
4
 
4
5
  export default function Checkbox({
@@ -10,14 +11,11 @@ export default function Checkbox({
10
11
  class: className = "",
11
12
  ...inputProps
12
13
  }) {
13
- const normalizeSize = (value) => {
14
- if (!value || value === "default" || value === "regular" || value === "md") return "md";
15
- if (value === "sm") return "sm";
16
- if (value === "lg" || value === "xl") return value;
17
- return value;
18
- };
14
+ // Checkbox supports all sizes
15
+ const normalizeSize = (value) => clampSize(value, ["xsmall", "small", "regular", "large", "xlarge"], "regular");
19
16
  const normalizedSize = normalizeSize(size);
20
- const sizeClass = normalizedSize === "lg" ? "checkbox-lg" : normalizedSize === "xl" ? "checkbox-xl" : "";
17
+ const sizeToken = toSizeToken(normalizedSize);
18
+ const sizeClass = sizeToken === "xl" ? "checkbox-xl" : sizeToken === "lg" ? "checkbox-lg" : "";
21
19
  const nativeChange = onChange ?? inputProps.change;
22
20
  const checkHandler = onCheck ?? check;
23
21
 
@@ -0,0 +1,31 @@
1
+ import Bunnix from "@bunnix/core";
2
+
3
+ const { div, pre, code } = Bunnix;
4
+
5
+ export default function CodeBlock({
6
+ html,
7
+ language,
8
+ overflowX = "auto",
9
+ wrap = false,
10
+ class: className = "",
11
+ ...rest
12
+ } = {}, children) {
13
+ const languageClass = language ? `language-${language}` : "";
14
+ const wrapClass = wrap ? "codeblock-wrap" : "";
15
+ const codeChildren = html ? null : children;
16
+ const codeProps = {
17
+ class: `codeblock-code ${languageClass}`.trim()
18
+ };
19
+ if (html !== null && html !== undefined) {
20
+ codeProps.innerHTML = html;
21
+ }
22
+
23
+ return div({ class: `codeblock ${className}`.trim(), ...rest }, [
24
+ pre({
25
+ class: `codeblock-pre ${wrapClass}`.trim(),
26
+ style: { overflowX, overflowY: "auto" }
27
+ }, [
28
+ code(codeProps, codeChildren)
29
+ ])
30
+ ]);
31
+ }
@@ -1,5 +1,6 @@
1
1
  import Bunnix from "@bunnix/core";
2
- const { select, option } = Bunnix;
2
+ import { clampSize, toSizeToken } from "../utils/sizeUtils.mjs";
3
+ const { select, option, div, span } = Bunnix;
3
4
 
4
5
  export default function ComboBox({
5
6
  options = [],
@@ -10,14 +11,18 @@ export default function ComboBox({
10
11
  change,
11
12
  ...rest
12
13
  } = {}, children) {
13
- const normalizeSize = (value) => {
14
- if (!value || value === "default" || value === "regular" || value === "md") return "md";
15
- if (value === "sm") return "sm";
16
- if (value === "lg" || value === "xl") return value;
17
- return value;
18
- };
14
+ // ComboBox supports all sizes
15
+ const normalizeSize = (value) => clampSize(value, ["xsmall", "small", "regular", "large", "xlarge"], "regular");
19
16
  const normalizedSize = normalizeSize(size);
20
- const sizeClass = normalizedSize === "lg" ? "input-lg" : normalizedSize === "xl" ? "input-xl" : "";
17
+ const sizeToken = toSizeToken(normalizedSize);
18
+ const sizeClass = sizeToken === "xl" ? "input-xl" : sizeToken === "lg" ? "input-lg" : "";
19
+ const iconSizeClass = sizeToken === "sm"
20
+ ? "icon-sm"
21
+ : sizeToken === "lg"
22
+ ? "icon-lg"
23
+ : sizeToken === "xl"
24
+ ? "icon-xl"
25
+ : "";
21
26
  const selectionState = selection && typeof selection.map === "function" ? selection : null;
22
27
  const handleChangeExternal = onChange ?? change;
23
28
 
@@ -35,10 +40,13 @@ export default function ComboBox({
35
40
  return option({ value: opt.value }, opt.label ?? opt.value);
36
41
  });
37
42
 
38
- return select({
39
- class: `${sizeClass} ${className}`.trim(),
40
- value: selection ?? "",
41
- change: handleChange,
42
- ...rest
43
- }, resolvedChildren);
43
+ return div({ class: "combobox" }, [
44
+ select({
45
+ class: `combobox-select ${sizeClass} ${className}`.trim(),
46
+ value: selection ?? "",
47
+ change: handleChange,
48
+ ...rest
49
+ }, resolvedChildren),
50
+ span({ class: `combobox-chevron icon icon-chevron-down icon-base ${iconSizeClass}`.trim() })
51
+ ]);
44
52
  }
@@ -5,23 +5,21 @@ const { div } = Bunnix;
5
5
  const typeClassMap = {
6
6
  main: "main-container",
7
7
  content: "main-content",
8
- page: "page-layout"
8
+ page: "page-layout",
9
9
  };
10
10
 
11
11
  const directionClassMap = {
12
- horizontal: "row-container",
13
- vertical: "column-container"
12
+ row: "row-container",
13
+ column: "column-container",
14
14
  };
15
15
 
16
- export default function Container({
17
- type,
18
- direction,
19
- class: className = "",
20
- ...rest
21
- } = {}, children) {
16
+ export default function Container(
17
+ { type = "box", direction = "column", class: className = "", ...rest } = {},
18
+ ...children
19
+ ) {
22
20
  const typeClass = typeClassMap[type] || "";
23
21
  const directionClass = directionClassMap[direction] || "";
24
22
  const combinedClass = `${typeClass} ${directionClass} ${className}`.trim();
25
23
 
26
- return div({ class: combinedClass, ...rest }, children);
24
+ return div({ class: combinedClass, ...rest }, ...children);
27
25
  }