@epoch32/visage 1.1.5 → 1.3.0

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.
@@ -15,6 +15,8 @@ function parseNamedImports(importClause) {
15
15
  };
16
16
  });
17
17
  }
18
+ var VIRTUAL_PREFIX = "virtual:visage-icons";
19
+ var RESOLVED_PREFIX = `\x00${VIRTUAL_PREFIX}`;
18
20
  function visageLucide(options = {}) {
19
21
  const aliases = options.aliases ?? ["lucide-react"];
20
22
  return {
@@ -23,17 +25,33 @@ function visageLucide(options = {}) {
23
25
  config() {
24
26
  return {
25
27
  optimizeDeps: {
26
- exclude: aliases
28
+ exclude: [...aliases, VIRTUAL_PREFIX]
27
29
  }
28
30
  };
29
31
  },
30
32
  resolveId(id) {
33
+ if (id.startsWith(VIRTUAL_PREFIX)) {
34
+ return `\x00${id}`;
35
+ }
31
36
  if (aliases.includes(id)) {
32
37
  return `\x00visage-lucide:${id}`;
33
38
  }
34
39
  return null;
35
40
  },
36
41
  load(id) {
42
+ if (id.startsWith(RESOLVED_PREFIX)) {
43
+ const query = id.slice(RESOLVED_PREFIX.length);
44
+ const params = new URLSearchParams(query.startsWith("?") ? query.slice(1) : "");
45
+ const names = (params.get("icons") || "").split(",").map((s) => s.trim()).filter(Boolean);
46
+ const imports = names.map((n) => `${n} as __icon_node_${n}`).join(", ");
47
+ const exports = names.map((n) => `export const ${n} = /* @__PURE__ */ createIcon("${n}", __icon_node_${n});`).join(`
48
+ `);
49
+ return `import { createIcon } from "visage/ui";
50
+ import { ${imports} } from "lucide";
51
+
52
+ ${exports}
53
+ `;
54
+ }
37
55
  if (id.startsWith("\x00visage-lucide:")) {
38
56
  return `
39
57
  import * as lucideIcons from "lucide";
@@ -51,10 +69,6 @@ export const __getIcon = (name) => {
51
69
  export default new Proxy({}, {
52
70
  get: (_, prop) => typeof prop === "string" ? __getIcon(prop) : undefined
53
71
  });
54
-
55
- // Dynamic proxy export for all lucide icon names
56
- ${Object.keys({})};
57
- export * from "lucide";
58
72
  `;
59
73
  }
60
74
  return null;
@@ -66,20 +80,25 @@ export * from "lucide";
66
80
  let transformed = code;
67
81
  let hasMatches = false;
68
82
  for (const alias of aliases) {
69
- const regex = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*['"]${alias}['"];?`, "g");
70
- transformed = transformed.replace(regex, (_match, importClause) => {
83
+ const importRegex = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*['"]${alias}['"];?`, "g");
84
+ transformed = transformed.replace(importRegex, (_match, importClause) => {
71
85
  const imports = parseNamedImports(importClause);
72
86
  if (imports.length === 0)
73
87
  return "";
74
88
  hasMatches = true;
75
- const lucideNamedImports = imports.map((imp) => `${imp.importedName} as __icon_node_${imp.importedName}`).join(", ");
76
- const componentDeclarations = imports.map((imp) => {
77
- return `const ${imp.localName} = /* @__PURE__ */ __visageCreateIcon("${imp.importedName}", __icon_node_${imp.importedName});`;
78
- }).join(`
79
- `);
80
- return `import { createIcon as __visageCreateIcon } from "visage/ui";
81
- import { ${lucideNamedImports} } from "lucide";
82
- ${componentDeclarations}`;
89
+ const queryIcons = Array.from(new Set(imports.map((i) => i.importedName))).join(",");
90
+ const specifiers = imports.map((i) => i.importedName === i.localName ? i.importedName : `${i.importedName} as ${i.localName}`).join(", ");
91
+ return `import { ${specifiers} } from "${VIRTUAL_PREFIX}?icons=${queryIcons}";`;
92
+ });
93
+ const exportRegex = new RegExp(`export\\s*\\{([^}]+)\\}\\s*from\\s*['"]${alias}['"];?`, "g");
94
+ transformed = transformed.replace(exportRegex, (_match, exportClause) => {
95
+ const exports = parseNamedImports(exportClause);
96
+ if (exports.length === 0)
97
+ return "";
98
+ hasMatches = true;
99
+ const queryIcons = Array.from(new Set(exports.map((i) => i.importedName))).join(",");
100
+ const specifiers = exports.map((i) => i.importedName === i.localName ? i.importedName : `${i.importedName} as ${i.localName}`).join(", ");
101
+ return `export { ${specifiers} } from "${VIRTUAL_PREFIX}?icons=${queryIcons}";`;
83
102
  });
84
103
  }
85
104
  if (!hasMatches) {
@@ -6,22 +6,5 @@ export interface VisageLucideOptions {
6
6
  */
7
7
  aliases?: string[];
8
8
  }
9
- /**
10
- * Official Visage Lucide Vite Plugin
11
- *
12
- * Statically transforms `import { Icon } from "lucide-react"` at build time into
13
- * native, tree-shaken Visage SVG component instances using `createIcon` and `lucide`.
14
- *
15
- * Example:
16
- * ```ts
17
- * // vite.config.ts
18
- * import { defineConfig } from "vite";
19
- * import visage, { visageLucide } from "visage/vite";
20
- *
21
- * export default defineConfig({
22
- * plugins: [visage(), visageLucide()]
23
- * });
24
- * ```
25
- */
26
9
  export declare function visageLucide(options?: VisageLucideOptions): VisageVitePlugin;
27
10
  export default visageLucide;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epoch32/visage",
3
- "version": "1.1.5",
3
+ "version": "1.3.0",
4
4
  "description": "Lightning-fast, zero-VDOM, fine-grained reactive UI library with full TypeScript support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -308,6 +308,19 @@ export {
308
308
  type AccordionProps,
309
309
  type AccordionSingleProps,
310
310
  AccordionTrigger,
311
+ BottomBar,
312
+ BottomBarAction,
313
+ type BottomBarActionProps,
314
+ BottomBarBadge,
315
+ type BottomBarBadgeProps,
316
+ type BottomBarContextValue,
317
+ BottomBarItem,
318
+ type BottomBarItemConfig,
319
+ type BottomBarItemProps,
320
+ type BottomBarProps,
321
+ BottomBarRoot,
322
+ BottomBarSeparator,
323
+ type BottomBarSeparatorProps,
311
324
  type ColumnDef,
312
325
  Command,
313
326
  CommandDialog,
@@ -394,6 +407,7 @@ export {
394
407
  trapFocus,
395
408
  useAccordionContext,
396
409
  useAccordionItemContext,
410
+ useBottomBarContext,
397
411
  useCommandContext,
398
412
  useDialogContext,
399
413
  useDropdownMenuContext,
@@ -0,0 +1,60 @@
1
+ import type { Child } from "../../dom/render";
2
+ import type { BottomBarActionProps } from "./types";
3
+
4
+ export function BottomBarAction(props: BottomBarActionProps): Child {
5
+ const {
6
+ as: Tag = "button",
7
+ icon,
8
+ label,
9
+ disabled,
10
+ onClick,
11
+ children,
12
+ class: className,
13
+ style,
14
+ ...rest
15
+ } = props;
16
+
17
+ const defaultActionStyle = {
18
+ display: "inline-flex",
19
+ alignItems: "center",
20
+ justifyContent: "center",
21
+ width: "44px",
22
+ height: "44px",
23
+ minWidth: "44px",
24
+ minHeight: "44px",
25
+ borderRadius: "50%",
26
+ background: "linear-gradient(135deg, #ec4899 0%, #a855f7 100%)",
27
+ color: "#ffffff",
28
+ border: "none",
29
+ boxShadow: "0 4px 14px rgba(236, 72, 153, 0.45)",
30
+ cursor: "pointer",
31
+ outline: "none",
32
+ userSelect: "none",
33
+ WebkitTapHighlightColor: "transparent",
34
+ transition: "transform 0.15s ease, box-shadow 0.15s ease",
35
+ boxSizing: "border-box"
36
+ };
37
+
38
+ const combinedStyle = style ? { ...defaultActionStyle, ...style } : defaultActionStyle;
39
+
40
+ return (
41
+ <Tag
42
+ type={Tag === "button" ? "button" : undefined}
43
+ role="button"
44
+ aria-label={label ?? "Primary action"}
45
+ disabled={disabled}
46
+ class={`visage-bottom-bar-action ${className ?? ""}`.trim()}
47
+ style={combinedStyle}
48
+ onClick={onClick}
49
+ {...rest}
50
+ >
51
+ {children !== undefined
52
+ ? typeof children === "function"
53
+ ? children()
54
+ : children
55
+ : typeof icon === "function"
56
+ ? icon()
57
+ : icon}
58
+ </Tag>
59
+ );
60
+ }
@@ -0,0 +1,51 @@
1
+ import type { Child } from "../../dom/render";
2
+ import { computed } from "../../signals";
3
+ import type { BottomBarBadgeProps } from "./types";
4
+
5
+ export function BottomBarBadge(props: BottomBarBadgeProps): Child {
6
+ const { as: Tag = "span", count, children, class: className, style, ...rest } = props;
7
+
8
+ const displayContent = computed(() => {
9
+ if (children !== undefined) {
10
+ return typeof children === "function" ? children() : children;
11
+ }
12
+ if (count !== undefined) {
13
+ return typeof count === "function" ? count() : count;
14
+ }
15
+ return "";
16
+ });
17
+
18
+ const defaultBadgeStyle = {
19
+ position: "absolute",
20
+ top: "3px",
21
+ right: "8px",
22
+ minWidth: "16px",
23
+ height: "16px",
24
+ padding: "0 4px",
25
+ borderRadius: "9999px",
26
+ backgroundColor: "#ef4444",
27
+ color: "#ffffff",
28
+ fontSize: "9px",
29
+ fontWeight: 700,
30
+ lineHeight: "16px",
31
+ textAlign: "center",
32
+ display: "inline-flex",
33
+ alignItems: "center",
34
+ justifyContent: "center",
35
+ boxShadow: "0 0 0 1.5px rgba(18, 18, 24, 0.9)",
36
+ pointerEvents: "none",
37
+ boxSizing: "border-box"
38
+ };
39
+
40
+ const combinedStyle = style ? { ...defaultBadgeStyle, ...style } : defaultBadgeStyle;
41
+
42
+ return (
43
+ <Tag
44
+ class={`visage-bottom-bar-badge ${className ?? ""}`.trim()}
45
+ style={combinedStyle}
46
+ {...rest}
47
+ >
48
+ {displayContent}
49
+ </Tag>
50
+ );
51
+ }
@@ -0,0 +1,8 @@
1
+ import { createContext, useContext } from "../../signals/context";
2
+ import type { BottomBarContextValue } from "./types";
3
+
4
+ export const BottomBarContext = createContext<BottomBarContextValue | null>(null);
5
+
6
+ export function useBottomBarContext(): BottomBarContextValue | null {
7
+ return useContext(BottomBarContext);
8
+ }
@@ -0,0 +1,29 @@
1
+ import { BottomBarAction } from "./action";
2
+ import { BottomBarBadge } from "./badge";
3
+ import { BottomBarItem } from "./item";
4
+ import { BottomBarRoot } from "./root";
5
+ import { BottomBarSeparator } from "./separator";
6
+
7
+ export { BottomBarAction } from "./action";
8
+ export { BottomBarBadge } from "./badge";
9
+ export { BottomBarContext, useBottomBarContext } from "./context";
10
+ export { BottomBarItem } from "./item";
11
+ export { BottomBarRoot } from "./root";
12
+ export { BottomBarSeparator } from "./separator";
13
+ export type {
14
+ BottomBarActionProps,
15
+ BottomBarBadgeProps,
16
+ BottomBarContextValue,
17
+ BottomBarItemConfig,
18
+ BottomBarItemProps,
19
+ BottomBarProps,
20
+ BottomBarSeparatorProps
21
+ } from "./types";
22
+
23
+ export const BottomBar = Object.assign(BottomBarRoot, {
24
+ Root: BottomBarRoot,
25
+ Item: BottomBarItem,
26
+ Action: BottomBarAction,
27
+ Badge: BottomBarBadge,
28
+ Separator: BottomBarSeparator
29
+ });
@@ -0,0 +1,119 @@
1
+ import type { Child } from "../../dom/render";
2
+ import { computed } from "../../signals";
3
+ import { BottomBarBadge } from "./badge";
4
+ import { useBottomBarContext } from "./context";
5
+ import type { BottomBarItemProps } from "./types";
6
+
7
+ export function BottomBarItem(props: BottomBarItemProps): Child {
8
+ const ctx = useBottomBarContext();
9
+ const isSelected = computed(() => (ctx ? ctx.value() === props.value : false));
10
+
11
+ const handleClick = (e: MouseEvent) => {
12
+ const isDisabled =
13
+ typeof props.disabled === "function"
14
+ ? (props.disabled as () => boolean)()
15
+ : Boolean(props.disabled);
16
+ if (isDisabled) {
17
+ e.preventDefault();
18
+ return;
19
+ }
20
+
21
+ if (ctx) {
22
+ ctx.setValue(props.value);
23
+ }
24
+ if (props.onClick) {
25
+ props.onClick(e);
26
+ }
27
+ };
28
+
29
+ const {
30
+ as: Tag = "button",
31
+ value,
32
+ icon,
33
+ label,
34
+ badge,
35
+ disabled,
36
+ onClick: _oc,
37
+ children,
38
+ class: className,
39
+ style,
40
+ ...rest
41
+ } = props;
42
+
43
+ const defaultItemStyle = {
44
+ position: "relative",
45
+ display: "flex",
46
+ flexDirection: "column",
47
+ alignItems: "center",
48
+ justifyContent: "center",
49
+ minWidth: "52px",
50
+ minHeight: "44px",
51
+ padding: "6px 8px",
52
+ borderRadius: "16px",
53
+ border: "none",
54
+ background: () => (isSelected() ? "rgba(255, 255, 255, 0.08)" : "transparent"),
55
+ color: () => (isSelected() ? "#ec4899" : "rgba(255, 255, 255, 0.65)"),
56
+ cursor: "pointer",
57
+ outline: "none",
58
+ userSelect: "none",
59
+ WebkitTapHighlightColor: "transparent",
60
+ transition: "color 0.15s ease, background-color 0.15s ease, transform 0.1s ease",
61
+ boxSizing: "border-box"
62
+ };
63
+
64
+ const combinedStyle = style ? { ...defaultItemStyle, ...style } : defaultItemStyle;
65
+
66
+ return (
67
+ <Tag
68
+ type={Tag === "button" ? "button" : undefined}
69
+ role="tab"
70
+ id={ctx ? `${ctx.baseId}-item-${value}` : undefined}
71
+ aria-selected={() => isSelected()}
72
+ data-state={() => (isSelected() ? "active" : "inactive")}
73
+ data-value={value}
74
+ disabled={disabled}
75
+ class={`visage-bottom-bar-item ${className ?? ""}`.trim()}
76
+ style={combinedStyle}
77
+ onClick={handleClick}
78
+ {...rest}
79
+ >
80
+ {badge !== undefined ? (
81
+ typeof badge === "function" || typeof badge === "string" || typeof badge === "number" ? (
82
+ <BottomBarBadge count={badge as any} />
83
+ ) : (
84
+ badge
85
+ )
86
+ ) : null}
87
+
88
+ {children !== undefined ? (typeof children === "function" ? children() : children) : null}
89
+
90
+ {icon ? (
91
+ <span
92
+ class="visage-bottom-bar-icon"
93
+ style={{
94
+ display: "inline-flex",
95
+ alignItems: "center",
96
+ justifyContent: "center",
97
+ fontSize: "18px"
98
+ }}
99
+ >
100
+ {typeof icon === "function" ? icon() : icon}
101
+ </span>
102
+ ) : null}
103
+ {label ? (
104
+ <span
105
+ class="visage-bottom-bar-label"
106
+ style={{
107
+ fontSize: "10px",
108
+ fontWeight: 500,
109
+ lineHeight: 1.2,
110
+ marginTop: "3px",
111
+ letterSpacing: "0.01em"
112
+ }}
113
+ >
114
+ {typeof label === "function" ? label() : label}
115
+ </span>
116
+ ) : null}
117
+ </Tag>
118
+ );
119
+ }
@@ -0,0 +1,148 @@
1
+ import type { Child } from "../../dom/render";
2
+ import { signal } from "../../signals";
3
+ import { createControllableSignal, createId } from "../utils";
4
+ import { BottomBarContext } from "./context";
5
+ import { BottomBarItem } from "./item";
6
+ import type { BottomBarContextValue, BottomBarProps } from "./types";
7
+
8
+ export function BottomBarRoot(props: BottomBarProps): Child {
9
+ const [value, setValue] = createControllableSignal<string>({
10
+ value: props.value,
11
+ defaultValue:
12
+ props.defaultValue ?? (props.items && props.items.length > 0 ? props.items[0]?.value : ""),
13
+ onChange: props.onValueChange
14
+ });
15
+
16
+ const baseId = createId("bottom-bar");
17
+ const variant = props.variant ?? "floating";
18
+ const hideOnScroll = props.hideOnScroll ?? false;
19
+ const threshold = props.scrollThreshold ?? 20;
20
+
21
+ const isVisible = signal(true);
22
+
23
+ if (hideOnScroll && typeof window !== "undefined") {
24
+ let lastScrollY = window.scrollY || 0;
25
+ const onScroll = () => {
26
+ const currentScrollY = window.scrollY || 0;
27
+ const diff = currentScrollY - lastScrollY;
28
+ if (Math.abs(diff) < 5) return;
29
+
30
+ if (currentScrollY > threshold && diff > 0) {
31
+ if (isVisible()) isVisible.set(false);
32
+ } else if (diff < 0) {
33
+ if (!isVisible()) isVisible.set(true);
34
+ }
35
+ lastScrollY = Math.max(0, currentScrollY);
36
+ };
37
+
38
+ window.addEventListener("scroll", onScroll, { passive: true });
39
+ }
40
+
41
+ const ctx: BottomBarContextValue = {
42
+ value,
43
+ setValue,
44
+ baseId,
45
+ variant
46
+ };
47
+
48
+ const {
49
+ as: Tag = "nav",
50
+ value: _v,
51
+ defaultValue: _dv,
52
+ onValueChange: _ovc,
53
+ variant: _var,
54
+ hideOnScroll: _hos,
55
+ scrollThreshold: _st,
56
+ items,
57
+ itemClass,
58
+ itemStyle,
59
+ children,
60
+ class: className,
61
+ style,
62
+ ...rest
63
+ } = props;
64
+
65
+ const defaultFloatingStyle = {
66
+ position: "fixed",
67
+ bottom: "max(16px, env(safe-area-inset-bottom, 16px))",
68
+ left: "50%",
69
+ zIndex: 50,
70
+ display: "inline-flex",
71
+ alignItems: "center",
72
+ gap: "6px",
73
+ padding: "6px 10px",
74
+ borderRadius: "9999px",
75
+ backgroundColor: "rgba(18, 18, 24, 0.88)",
76
+ backdropFilter: "blur(20px)",
77
+ WebkitBackdropFilter: "blur(20px)",
78
+ border: "1px solid rgba(255, 255, 255, 0.1)",
79
+ boxShadow: "0 10px 30px -5px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05)",
80
+ transform: () =>
81
+ isVisible() ? "translateX(-50%) translateY(0)" : "translateX(-50%) translateY(160%)",
82
+ opacity: () => (isVisible() ? 1 : 0),
83
+ pointerEvents: () => (isVisible() ? "auto" : "none"),
84
+ transition: "transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease",
85
+ maxWidth: "calc(100vw - 32px)",
86
+ boxSizing: "border-box"
87
+ };
88
+
89
+ const defaultDockedStyle = {
90
+ position: "fixed",
91
+ bottom: 0,
92
+ left: 0,
93
+ right: 0,
94
+ zIndex: 50,
95
+ display: "flex",
96
+ justifyContent: "space-around",
97
+ alignItems: "center",
98
+ paddingTop: "8px",
99
+ paddingBottom: "max(10px, env(safe-area-inset-bottom, 10px))",
100
+ paddingLeft: "12px",
101
+ paddingRight: "12px",
102
+ backgroundColor: "rgba(18, 18, 24, 0.94)",
103
+ backdropFilter: "blur(20px)",
104
+ WebkitBackdropFilter: "blur(20px)",
105
+ borderTop: "1px solid rgba(255, 255, 255, 0.1)",
106
+ boxShadow: "0 -4px 20px rgba(0, 0, 0, 0.35)",
107
+ transform: () => (isVisible() ? "translateY(0)" : "translateY(110%)"),
108
+ opacity: () => (isVisible() ? 1 : 0),
109
+ pointerEvents: () => (isVisible() ? "auto" : "none"),
110
+ transition: "transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease",
111
+ boxSizing: "border-box"
112
+ };
113
+
114
+ const computedDefaultStyle = variant === "floating" ? defaultFloatingStyle : defaultDockedStyle;
115
+ const combinedStyle = style ? { ...computedDefaultStyle, ...style } : computedDefaultStyle;
116
+
117
+ return BottomBarContext.Provider({
118
+ value: ctx,
119
+ children: () => (
120
+ <Tag
121
+ role="toolbar"
122
+ aria-label="Mobile toolbar"
123
+ data-variant={variant}
124
+ data-state={() => (isVisible() ? "visible" : "hidden")}
125
+ class={`visage-bottom-bar visage-bottom-bar-${variant} ${className ?? ""}`.trim()}
126
+ style={combinedStyle}
127
+ {...rest}
128
+ >
129
+ {items
130
+ ? items.map((item) => (
131
+ <BottomBarItem
132
+ value={item.value}
133
+ icon={item.icon}
134
+ label={item.label}
135
+ badge={item.badge}
136
+ disabled={item.disabled}
137
+ onClick={item.onClick}
138
+ class={item.class ?? itemClass}
139
+ style={item.style ?? itemStyle}
140
+ />
141
+ ))
142
+ : typeof children === "function"
143
+ ? children()
144
+ : children}
145
+ </Tag>
146
+ )
147
+ });
148
+ }
@@ -0,0 +1,26 @@
1
+ import type { Child } from "../../dom/render";
2
+ import type { BottomBarSeparatorProps } from "./types";
3
+
4
+ export function BottomBarSeparator(props: BottomBarSeparatorProps): Child {
5
+ const { as: Tag = "div", class: className, style, ...rest } = props;
6
+
7
+ const defaultSeparatorStyle = {
8
+ width: "1px",
9
+ height: "22px",
10
+ backgroundColor: "rgba(255, 255, 255, 0.12)",
11
+ margin: "0 2px",
12
+ flexShrink: 0
13
+ };
14
+
15
+ const combinedStyle = style ? { ...defaultSeparatorStyle, ...style } : defaultSeparatorStyle;
16
+
17
+ return (
18
+ <Tag
19
+ role="separator"
20
+ aria-orientation="vertical"
21
+ class={`visage-bottom-bar-separator ${className ?? ""}`.trim()}
22
+ style={combinedStyle}
23
+ {...rest}
24
+ />
25
+ );
26
+ }
@@ -0,0 +1,79 @@
1
+ import type { Child } from "../../dom/render";
2
+ import type { ReadonlySignal } from "../../signals";
3
+
4
+ export interface BottomBarContextValue {
5
+ value: ReadonlySignal<string>;
6
+ setValue: (value: string) => void;
7
+ baseId: string;
8
+ variant: "floating" | "docked";
9
+ }
10
+
11
+ export interface BottomBarItemConfig {
12
+ value: string;
13
+ label?: Child | (() => Child);
14
+ icon?: Child | (() => Child);
15
+ badge?: Child | number | string | (() => Child | number | string | undefined);
16
+ disabled?: boolean | (() => boolean);
17
+ onClick?: (e: MouseEvent) => void;
18
+ class?: any;
19
+ style?: any;
20
+ }
21
+
22
+ export interface BottomBarProps {
23
+ value?: () => string | undefined;
24
+ defaultValue?: string;
25
+ onValueChange?: (value: string) => void;
26
+ variant?: "floating" | "docked";
27
+ hideOnScroll?: boolean;
28
+ scrollThreshold?: number;
29
+ items?: BottomBarItemConfig[];
30
+ itemClass?: any;
31
+ itemStyle?: any;
32
+ as?: string;
33
+ class?: any;
34
+ style?: any;
35
+ children?: Child | (() => Child);
36
+ [key: string]: any;
37
+ }
38
+
39
+ export interface BottomBarItemProps {
40
+ value: string;
41
+ icon?: Child | (() => Child);
42
+ label?: Child | (() => Child);
43
+ badge?: Child | number | string | (() => Child | number | string | undefined);
44
+ disabled?: boolean | (() => boolean);
45
+ onClick?: (e: MouseEvent) => void;
46
+ as?: string;
47
+ class?: any;
48
+ style?: any;
49
+ children?: Child | (() => Child);
50
+ [key: string]: any;
51
+ }
52
+
53
+ export interface BottomBarActionProps {
54
+ icon?: Child | (() => Child);
55
+ label?: string;
56
+ disabled?: boolean | (() => boolean);
57
+ onClick?: (e: MouseEvent) => void;
58
+ as?: string;
59
+ class?: any;
60
+ style?: any;
61
+ children?: Child | (() => Child);
62
+ [key: string]: any;
63
+ }
64
+
65
+ export interface BottomBarBadgeProps {
66
+ count?: Child | number | string | (() => Child | number | string | undefined);
67
+ as?: string;
68
+ class?: any;
69
+ style?: any;
70
+ children?: Child | (() => Child);
71
+ [key: string]: any;
72
+ }
73
+
74
+ export interface BottomBarSeparatorProps {
75
+ as?: string;
76
+ class?: any;
77
+ style?: any;
78
+ [key: string]: any;
79
+ }