@yugnex/nexui 2.0.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.
- package/LICENSE +59 -0
- package/css/nexui-base.css +157 -0
- package/css/nexui-icons.css +86 -0
- package/css/nexui-tokens.css +113 -0
- package/css/nexui.css +16 -0
- package/dist/assets/geometry.d.ts +98 -0
- package/dist/assets/geometry.d.ts.map +1 -0
- package/dist/assets/geometry.js +114 -0
- package/dist/assets/geometry.js.map +1 -0
- package/dist/assets/typography.d.ts +3 -0
- package/dist/assets/typography.d.ts.map +1 -0
- package/dist/assets/typography.js +178 -0
- package/dist/assets/typography.js.map +1 -0
- package/dist/core/compiler.d.ts +30 -0
- package/dist/core/compiler.d.ts.map +1 -0
- package/dist/core/compiler.js +124 -0
- package/dist/core/compiler.js.map +1 -0
- package/dist/core/cx.d.ts +7 -0
- package/dist/core/cx.d.ts.map +1 -0
- package/dist/core/cx.js +34 -0
- package/dist/core/cx.js.map +1 -0
- package/dist/core/matrix.d.ts +118 -0
- package/dist/core/matrix.d.ts.map +1 -0
- package/dist/core/matrix.js +180 -0
- package/dist/core/matrix.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives/avatar.d.ts +8 -0
- package/dist/primitives/avatar.d.ts.map +1 -0
- package/dist/primitives/avatar.js +146 -0
- package/dist/primitives/avatar.js.map +1 -0
- package/dist/primitives/badge.d.ts +8 -0
- package/dist/primitives/badge.d.ts.map +1 -0
- package/dist/primitives/badge.js +88 -0
- package/dist/primitives/badge.js.map +1 -0
- package/dist/primitives/button.d.ts +10 -0
- package/dist/primitives/button.d.ts.map +1 -0
- package/dist/primitives/button.js +137 -0
- package/dist/primitives/button.js.map +1 -0
- package/dist/primitives/checkbox.d.ts +13 -0
- package/dist/primitives/checkbox.d.ts.map +1 -0
- package/dist/primitives/checkbox.js +107 -0
- package/dist/primitives/checkbox.js.map +1 -0
- package/dist/primitives/input.d.ts +14 -0
- package/dist/primitives/input.d.ts.map +1 -0
- package/dist/primitives/input.js +177 -0
- package/dist/primitives/input.js.map +1 -0
- package/dist/primitives/panel.d.ts +9 -0
- package/dist/primitives/panel.d.ts.map +1 -0
- package/dist/primitives/panel.js +101 -0
- package/dist/primitives/panel.js.map +1 -0
- package/dist/primitives/progress.d.ts +8 -0
- package/dist/primitives/progress.d.ts.map +1 -0
- package/dist/primitives/progress.js +105 -0
- package/dist/primitives/progress.js.map +1 -0
- package/dist/primitives/separator.d.ts +8 -0
- package/dist/primitives/separator.d.ts.map +1 -0
- package/dist/primitives/separator.js +69 -0
- package/dist/primitives/separator.js.map +1 -0
- package/dist/primitives/skeleton.d.ts +8 -0
- package/dist/primitives/skeleton.d.ts.map +1 -0
- package/dist/primitives/skeleton.js +61 -0
- package/dist/primitives/skeleton.js.map +1 -0
- package/dist/primitives/spinner.d.ts +8 -0
- package/dist/primitives/spinner.d.ts.map +1 -0
- package/dist/primitives/spinner.js +64 -0
- package/dist/primitives/spinner.js.map +1 -0
- package/dist/primitives/status-ring.d.ts +8 -0
- package/dist/primitives/status-ring.d.ts.map +1 -0
- package/dist/primitives/status-ring.js +101 -0
- package/dist/primitives/status-ring.js.map +1 -0
- package/dist/primitives/switch.d.ts +12 -0
- package/dist/primitives/switch.d.ts.map +1 -0
- package/dist/primitives/switch.js +124 -0
- package/dist/primitives/switch.js.map +1 -0
- package/dist/primitives/text-stream.d.ts +23 -0
- package/dist/primitives/text-stream.d.ts.map +1 -0
- package/dist/primitives/text-stream.js +167 -0
- package/dist/primitives/text-stream.js.map +1 -0
- package/dist/tokens/colors.d.ts +127 -0
- package/dist/tokens/colors.d.ts.map +1 -0
- package/dist/tokens/colors.js +135 -0
- package/dist/tokens/colors.js.map +1 -0
- package/dist/tokens/motion.d.ts +37 -0
- package/dist/tokens/motion.d.ts.map +1 -0
- package/dist/tokens/motion.js +93 -0
- package/dist/tokens/motion.js.map +1 -0
- package/dist/tokens/shadows.d.ts +34 -0
- package/dist/tokens/shadows.d.ts.map +1 -0
- package/dist/tokens/shadows.js +45 -0
- package/dist/tokens/shadows.js.map +1 -0
- package/dist/tokens/spacing.d.ts +69 -0
- package/dist/tokens/spacing.d.ts.map +1 -0
- package/dist/tokens/spacing.js +71 -0
- package/dist/tokens/spacing.js.map +1 -0
- package/dist/tokens/type.d.ts +166 -0
- package/dist/tokens/type.d.ts.map +1 -0
- package/dist/tokens/type.js +215 -0
- package/dist/tokens/type.js.map +1 -0
- package/fonts/NexuiIcons.woff2 +0 -0
- package/fonts/NexuiMono-Regular.otf +0 -0
- package/fonts/NexuiMono-Regular.woff2 +0 -0
- package/fonts/NexuiSans-Bold.otf +0 -0
- package/fonts/NexuiSans-Bold.woff2 +0 -0
- package/fonts/NexuiSans-Medium.otf +0 -0
- package/fonts/NexuiSans-Medium.woff2 +0 -0
- package/fonts/NexuiSans-Regular.otf +0 -0
- package/fonts/NexuiSans-Regular.woff2 +0 -0
- package/native/Cargo.toml +16 -0
- package/native/src/lib.rs +127 -0
- package/nexui-utils.css +485 -0
- package/package.json +58 -0
- package/src/assets/geometry.ts +144 -0
- package/src/assets/typography.ts +184 -0
- package/src/core/compiler.ts +139 -0
- package/src/core/cx.ts +50 -0
- package/src/core/matrix.ts +195 -0
- package/src/index.ts +78 -0
- package/src/primitives/avatar.ts +159 -0
- package/src/primitives/badge.ts +98 -0
- package/src/primitives/button.ts +149 -0
- package/src/primitives/checkbox.ts +113 -0
- package/src/primitives/input.ts +187 -0
- package/src/primitives/panel.ts +111 -0
- package/src/primitives/progress.ts +112 -0
- package/src/primitives/separator.ts +73 -0
- package/src/primitives/skeleton.ts +68 -0
- package/src/primitives/spinner.ts +71 -0
- package/src/primitives/status-ring.ts +109 -0
- package/src/primitives/switch.ts +134 -0
- package/src/primitives/text-stream.ts +187 -0
- package/src/tokens/colors.ts +149 -0
- package/src/tokens/motion.ts +97 -0
- package/src/tokens/shadows.ts +58 -0
- package/src/tokens/spacing.ts +79 -0
- package/src/tokens/type.ts +224 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// @yugnex/nexui — Layout Matrix
|
|
2
|
+
// Encodes layout intent as a composable 32-bit bitmask.
|
|
3
|
+
// Bits 0-3: padding · Bits 4-7: flex/display · Bits 8-11: border-radius
|
|
4
|
+
// Bits 12-15: gap · Bits 16-19: width · Bits 20-23: overflow
|
|
5
|
+
// Compose with bitwise OR: PAD_MD | FLEX_ROW | ALIGN_CENTER | RAD_MD
|
|
6
|
+
|
|
7
|
+
export const enum LayoutMatrix {
|
|
8
|
+
// Padding (bits 0-3)
|
|
9
|
+
PAD_NONE = 0x0,
|
|
10
|
+
PAD_XS = 0x1, // 0.25rem / 4px
|
|
11
|
+
PAD_SM = 0x2, // 0.5rem / 8px
|
|
12
|
+
PAD_MD = 0x3, // 0.75rem / 12px
|
|
13
|
+
PAD_LG = 0x4, // 1rem / 16px
|
|
14
|
+
PAD_XL = 0x5, // 1.5rem / 24px
|
|
15
|
+
PAD_2XL = 0x6, // 2rem / 32px
|
|
16
|
+
|
|
17
|
+
// Display / Flex direction (bits 4-7)
|
|
18
|
+
FLEX_ROW = 0x10, // display:flex; flex-direction:row
|
|
19
|
+
FLEX_COL = 0x20, // display:flex; flex-direction:column
|
|
20
|
+
GRID_2 = 0x30, // display:grid; grid-template-columns:repeat(2,1fr)
|
|
21
|
+
GRID_3 = 0x40, // display:grid; grid-template-columns:repeat(3,1fr)
|
|
22
|
+
GRID_4 = 0x50, // display:grid; grid-template-columns:repeat(4,1fr)
|
|
23
|
+
|
|
24
|
+
// Alignment (bits 5-6 override when used with FLEX_*)
|
|
25
|
+
ALIGN_START = 0x60, // align-items:flex-start
|
|
26
|
+
ALIGN_CENTER = 0x70, // align-items:center
|
|
27
|
+
ALIGN_END = 0x80, // align-items:flex-end
|
|
28
|
+
ALIGN_STRETCH = 0x90, // align-items:stretch
|
|
29
|
+
|
|
30
|
+
// Justify content (bits 6-7 secondary)
|
|
31
|
+
JUSTIFY_START = 0xA0, // justify-content:flex-start
|
|
32
|
+
JUSTIFY_CENTER = 0xB0, // justify-content:center
|
|
33
|
+
JUSTIFY_END = 0xC0, // justify-content:flex-end
|
|
34
|
+
JUSTIFY_BET = 0xD0, // justify-content:space-between
|
|
35
|
+
JUSTIFY_AROUND = 0xE0, // justify-content:space-around
|
|
36
|
+
JUSTIFY_EVEN = 0xF0, // justify-content:space-evenly
|
|
37
|
+
|
|
38
|
+
// Border radius (bits 8-11)
|
|
39
|
+
RAD_NONE = 0x000,
|
|
40
|
+
RAD_XS = 0x100, // 2px
|
|
41
|
+
RAD_SM = 0x200, // 4px
|
|
42
|
+
RAD_MD = 0x300, // 6px
|
|
43
|
+
RAD_LG = 0x400, // 8px
|
|
44
|
+
RAD_XL = 0x500, // 12px
|
|
45
|
+
RAD_2XL = 0x600, // 16px
|
|
46
|
+
RAD_FULL = 0x700, // 9999px
|
|
47
|
+
|
|
48
|
+
// Gap (bits 12-15)
|
|
49
|
+
GAP_NONE = 0x0000,
|
|
50
|
+
GAP_XS = 0x1000, // 0.25rem / 4px
|
|
51
|
+
GAP_SM = 0x2000, // 0.5rem / 8px
|
|
52
|
+
GAP_MD = 0x3000, // 1rem / 16px
|
|
53
|
+
GAP_LG = 0x4000, // 1.5rem / 24px
|
|
54
|
+
GAP_XL = 0x5000, // 2rem / 32px
|
|
55
|
+
|
|
56
|
+
// Width (bits 16-19)
|
|
57
|
+
W_AUTO = 0x00000,
|
|
58
|
+
W_FULL = 0x10000, // width:100%
|
|
59
|
+
W_SCREEN = 0x20000, // width:100vw
|
|
60
|
+
W_FIT = 0x30000, // width:fit-content
|
|
61
|
+
W_MIN = 0x40000, // width:min-content
|
|
62
|
+
W_MAX = 0x50000, // width:max-content
|
|
63
|
+
|
|
64
|
+
// Overflow (bits 20-23)
|
|
65
|
+
OVERFLOW_VIS = 0x000000, // overflow:visible (default)
|
|
66
|
+
OVERFLOW_HIDDEN = 0x100000, // overflow:hidden
|
|
67
|
+
OVERFLOW_AUTO = 0x200000, // overflow:auto
|
|
68
|
+
OVERFLOW_SCROLL = 0x300000, // overflow:scroll
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Maps bitmask bits to CSS strings — used by the compiler
|
|
72
|
+
export const MATRIX_PAD_MAP: Record<number, string> = {
|
|
73
|
+
0x1: "padding:0.25rem;",
|
|
74
|
+
0x2: "padding:0.5rem;",
|
|
75
|
+
0x3: "padding:0.75rem;",
|
|
76
|
+
0x4: "padding:1rem;",
|
|
77
|
+
0x5: "padding:1.5rem;",
|
|
78
|
+
0x6: "padding:2rem;",
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const MATRIX_DISPLAY_MAP: Record<number, string> = {
|
|
82
|
+
0x10: "display:flex;flex-direction:row;",
|
|
83
|
+
0x20: "display:flex;flex-direction:column;",
|
|
84
|
+
0x30: "display:grid;grid-template-columns:repeat(2,1fr);",
|
|
85
|
+
0x40: "display:grid;grid-template-columns:repeat(3,1fr);",
|
|
86
|
+
0x50: "display:grid;grid-template-columns:repeat(4,1fr);",
|
|
87
|
+
0x60: "align-items:flex-start;",
|
|
88
|
+
0x70: "align-items:center;",
|
|
89
|
+
0x80: "align-items:flex-end;",
|
|
90
|
+
0x90: "align-items:stretch;",
|
|
91
|
+
0xA0: "justify-content:flex-start;",
|
|
92
|
+
0xB0: "justify-content:center;",
|
|
93
|
+
0xC0: "justify-content:flex-end;",
|
|
94
|
+
0xD0: "justify-content:space-between;",
|
|
95
|
+
0xE0: "justify-content:space-around;",
|
|
96
|
+
0xF0: "justify-content:space-evenly;",
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const MATRIX_RADIUS_MAP: Record<number, string> = {
|
|
100
|
+
0x100: "border-radius:2px;",
|
|
101
|
+
0x200: "border-radius:4px;",
|
|
102
|
+
0x300: "border-radius:6px;",
|
|
103
|
+
0x400: "border-radius:8px;",
|
|
104
|
+
0x500: "border-radius:12px;",
|
|
105
|
+
0x600: "border-radius:16px;",
|
|
106
|
+
0x700: "border-radius:9999px;",
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const MATRIX_GAP_MAP: Record<number, string> = {
|
|
110
|
+
0x1000: "gap:0.25rem;",
|
|
111
|
+
0x2000: "gap:0.5rem;",
|
|
112
|
+
0x3000: "gap:1rem;",
|
|
113
|
+
0x4000: "gap:1.5rem;",
|
|
114
|
+
0x5000: "gap:2rem;",
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const MATRIX_WIDTH_MAP: Record<number, string> = {
|
|
118
|
+
0x10000: "width:100%;",
|
|
119
|
+
0x20000: "width:100vw;",
|
|
120
|
+
0x30000: "width:fit-content;",
|
|
121
|
+
0x40000: "width:min-content;",
|
|
122
|
+
0x50000: "width:max-content;",
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const MATRIX_OVERFLOW_MAP: Record<number, string> = {
|
|
126
|
+
0x100000: "overflow:hidden;",
|
|
127
|
+
0x200000: "overflow:auto;",
|
|
128
|
+
0x300000: "overflow:scroll;",
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Theme token maps — CSS custom property to value
|
|
132
|
+
export const NEXUI_THEMES = {
|
|
133
|
+
void: {
|
|
134
|
+
"--nx-bg-void": "#05070C",
|
|
135
|
+
"--nx-bg-base": "#0D1117",
|
|
136
|
+
"--nx-bg-surface": "#161B22",
|
|
137
|
+
"--nx-bg-elevated": "#1C2128",
|
|
138
|
+
"--nx-bg-overlay": "#21262D",
|
|
139
|
+
"--nx-border": "rgba(255,255,255,0.08)",
|
|
140
|
+
"--nx-border-strong": "rgba(255,255,255,0.16)",
|
|
141
|
+
"--nx-border-focus": "rgba(232,144,16,0.60)",
|
|
142
|
+
"--nx-text": "#E6EDF3",
|
|
143
|
+
"--nx-text-2": "#8B949E",
|
|
144
|
+
"--nx-text-3": "#6E7681",
|
|
145
|
+
"--nx-text-4": "#484F58",
|
|
146
|
+
"--nx-text-inv": "#05070C",
|
|
147
|
+
"--nx-accent": "#E89010",
|
|
148
|
+
"--nx-accent-dim": "rgba(232,144,16,0.09)",
|
|
149
|
+
"--nx-accent-border": "rgba(232,144,16,0.22)",
|
|
150
|
+
"--nx-accent-text": "#F5B342",
|
|
151
|
+
"--nx-live": "#0FD4C6",
|
|
152
|
+
"--nx-live-dim": "rgba(15,212,198,0.09)",
|
|
153
|
+
"--nx-live-border": "rgba(15,212,198,0.22)",
|
|
154
|
+
"--nx-success": "#22C55E",
|
|
155
|
+
"--nx-success-dim": "rgba(34,197,94,0.10)",
|
|
156
|
+
"--nx-error": "#EF4444",
|
|
157
|
+
"--nx-error-dim": "rgba(239,68,68,0.10)",
|
|
158
|
+
"--nx-warning": "#EAB308",
|
|
159
|
+
"--nx-warning-dim": "rgba(234,179,8,0.10)",
|
|
160
|
+
"--nx-font-sans": "'NexuiSans','Inter',system-ui,-apple-system,sans-serif",
|
|
161
|
+
"--nx-font-mono": "'NexuiMono','JetBrains Mono','Fira Code',ui-monospace,monospace",
|
|
162
|
+
},
|
|
163
|
+
terminal: {
|
|
164
|
+
"--nx-bg-void": "#000000",
|
|
165
|
+
"--nx-bg-base": "#050505",
|
|
166
|
+
"--nx-bg-surface": "#0C0E12",
|
|
167
|
+
"--nx-bg-elevated": "#111418",
|
|
168
|
+
"--nx-bg-overlay": "#161B22",
|
|
169
|
+
"--nx-border": "#1E293B",
|
|
170
|
+
"--nx-border-strong": "#2D3748",
|
|
171
|
+
"--nx-border-focus": "rgba(16,185,129,0.60)",
|
|
172
|
+
"--nx-text": "#10B981",
|
|
173
|
+
"--nx-text-2": "#6EE7B7",
|
|
174
|
+
"--nx-text-3": "#34D399",
|
|
175
|
+
"--nx-text-4": "#065F46",
|
|
176
|
+
"--nx-text-inv": "#000000",
|
|
177
|
+
"--nx-accent": "#E89010",
|
|
178
|
+
"--nx-accent-dim": "rgba(232,144,16,0.09)",
|
|
179
|
+
"--nx-accent-border": "rgba(232,144,16,0.22)",
|
|
180
|
+
"--nx-accent-text": "#F5B342",
|
|
181
|
+
"--nx-live": "#10B981",
|
|
182
|
+
"--nx-live-dim": "rgba(16,185,129,0.09)",
|
|
183
|
+
"--nx-live-border": "rgba(16,185,129,0.22)",
|
|
184
|
+
"--nx-success": "#10B981",
|
|
185
|
+
"--nx-success-dim": "rgba(16,185,129,0.10)",
|
|
186
|
+
"--nx-error": "#EF4444",
|
|
187
|
+
"--nx-error-dim": "rgba(239,68,68,0.10)",
|
|
188
|
+
"--nx-warning": "#EAB308",
|
|
189
|
+
"--nx-warning-dim": "rgba(234,179,8,0.10)",
|
|
190
|
+
"--nx-font-sans": "'NexuiMono','JetBrains Mono',ui-monospace,monospace",
|
|
191
|
+
"--nx-font-mono": "'NexuiMono','JetBrains Mono',ui-monospace,monospace",
|
|
192
|
+
},
|
|
193
|
+
} as const;
|
|
194
|
+
|
|
195
|
+
export type NexuiTheme = keyof typeof NEXUI_THEMES;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// @yugnex/nexui — Main Entry Point v2.0
|
|
2
|
+
|
|
3
|
+
export * from "./tokens/colors";
|
|
4
|
+
export * from "./tokens/spacing";
|
|
5
|
+
export * from "./tokens/motion";
|
|
6
|
+
export * from "./tokens/shadows";
|
|
7
|
+
export * from "./tokens/type";
|
|
8
|
+
export * from "./core/matrix";
|
|
9
|
+
export * from "./core/compiler";
|
|
10
|
+
export * from "./core/cx";
|
|
11
|
+
export * from "./assets/typography";
|
|
12
|
+
export * from "./assets/geometry";
|
|
13
|
+
|
|
14
|
+
export { NexPanel } from "./primitives/panel";
|
|
15
|
+
export { NexStatusRing } from "./primitives/status-ring";
|
|
16
|
+
export { NexTextStream } from "./primitives/text-stream";
|
|
17
|
+
export { NexButton } from "./primitives/button";
|
|
18
|
+
export { NexBadge } from "./primitives/badge";
|
|
19
|
+
export { NexInput } from "./primitives/input";
|
|
20
|
+
export { NexAvatar } from "./primitives/avatar";
|
|
21
|
+
export { NexProgress } from "./primitives/progress";
|
|
22
|
+
export { NexSwitch } from "./primitives/switch";
|
|
23
|
+
export { NexCheckbox } from "./primitives/checkbox";
|
|
24
|
+
export { NexSkeleton } from "./primitives/skeleton";
|
|
25
|
+
export { NexSeparator } from "./primitives/separator";
|
|
26
|
+
export { NexSpinner } from "./primitives/spinner";
|
|
27
|
+
|
|
28
|
+
import { nexui_compiler } from "./core/compiler";
|
|
29
|
+
import { NexuiTypographySheet } from "./assets/typography";
|
|
30
|
+
import { NexPanel } from "./primitives/panel";
|
|
31
|
+
import { NexStatusRing } from "./primitives/status-ring";
|
|
32
|
+
import { NexTextStream } from "./primitives/text-stream";
|
|
33
|
+
import { NexButton } from "./primitives/button";
|
|
34
|
+
import { NexBadge } from "./primitives/badge";
|
|
35
|
+
import { NexInput } from "./primitives/input";
|
|
36
|
+
import { NexAvatar } from "./primitives/avatar";
|
|
37
|
+
import { NexProgress } from "./primitives/progress";
|
|
38
|
+
import { NexSwitch } from "./primitives/switch";
|
|
39
|
+
import { NexCheckbox } from "./primitives/checkbox";
|
|
40
|
+
import { NexSkeleton } from "./primitives/skeleton";
|
|
41
|
+
import { NexSeparator } from "./primitives/separator";
|
|
42
|
+
import { NexSpinner } from "./primitives/spinner";
|
|
43
|
+
import type { NexuiTheme } from "./core/matrix";
|
|
44
|
+
|
|
45
|
+
const ELEMENTS: Array<[string, CustomElementConstructor]> = [
|
|
46
|
+
["nex-panel", NexPanel],
|
|
47
|
+
["nex-status-ring", NexStatusRing],
|
|
48
|
+
["nex-text-stream", NexTextStream],
|
|
49
|
+
["nex-button", NexButton],
|
|
50
|
+
["nex-badge", NexBadge],
|
|
51
|
+
["nex-input", NexInput],
|
|
52
|
+
["nex-avatar", NexAvatar],
|
|
53
|
+
["nex-progress", NexProgress],
|
|
54
|
+
["nex-switch", NexSwitch],
|
|
55
|
+
["nex-checkbox", NexCheckbox],
|
|
56
|
+
["nex-skeleton", NexSkeleton],
|
|
57
|
+
["nex-separator", NexSeparator],
|
|
58
|
+
["nex-spinner", NexSpinner],
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
export async function initializeNexuiEngine(defaultTheme: NexuiTheme = "void"): Promise<void> {
|
|
62
|
+
if (typeof window === "undefined") return;
|
|
63
|
+
if (!document.getElementById("yugnex-nexui-typography")) {
|
|
64
|
+
const s = document.createElement("style");
|
|
65
|
+
s.id = "yugnex-nexui-typography";
|
|
66
|
+
s.textContent = NexuiTypographySheet;
|
|
67
|
+
document.head.appendChild(s);
|
|
68
|
+
}
|
|
69
|
+
nexui_compiler.mountGlobalTheme(defaultTheme);
|
|
70
|
+
for (const [tag, ctor] of ELEMENTS) {
|
|
71
|
+
if (!customElements.get(tag)) customElements.define(tag, ctor);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function setNexuiTheme(theme: NexuiTheme): void {
|
|
76
|
+
nexui_compiler.switchTheme(theme);
|
|
77
|
+
window.dispatchEvent(new CustomEvent("nexui:theme-change", { detail: { theme } }));
|
|
78
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// @yugnex/nexui — NexAvatar Web Component
|
|
2
|
+
// User avatar: image with initials fallback + optional status indicator.
|
|
3
|
+
// Attributes:
|
|
4
|
+
// src: image URL
|
|
5
|
+
// name: full name — used for initials and alt text
|
|
6
|
+
// size: xs | sm | md | lg | xl (default: md)
|
|
7
|
+
// status: online | away | busy | offline (optional)
|
|
8
|
+
// shape: circle | square (default: circle)
|
|
9
|
+
|
|
10
|
+
import { nexui_compiler } from "../core/compiler";
|
|
11
|
+
|
|
12
|
+
function getInitials(name: string): string {
|
|
13
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
14
|
+
if (parts.length === 0) return "?";
|
|
15
|
+
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
16
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Deterministic hue from name string for initials background
|
|
20
|
+
function nameToHue(name: string): number {
|
|
21
|
+
let hash = 0;
|
|
22
|
+
for (let i = 0; i < name.length; i++) {
|
|
23
|
+
hash = (hash * 31 + name.charCodeAt(i)) >>> 0;
|
|
24
|
+
}
|
|
25
|
+
return hash % 360;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class NexAvatar extends HTMLElement {
|
|
29
|
+
static get observedAttributes() {
|
|
30
|
+
return ["src", "name", "size", "status", "shape"];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
constructor() {
|
|
34
|
+
super();
|
|
35
|
+
this.attachShadow({ mode: "open" });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
connectedCallback() {
|
|
39
|
+
this.render();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
attributeChangedCallback() {
|
|
43
|
+
this.render();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private render() {
|
|
47
|
+
if (!this.shadowRoot) return;
|
|
48
|
+
|
|
49
|
+
const src = this.getAttribute("src") ?? "";
|
|
50
|
+
const name = this.getAttribute("name") ?? "";
|
|
51
|
+
const size = this.getAttribute("size") ?? "md";
|
|
52
|
+
const status = this.getAttribute("status") ?? "";
|
|
53
|
+
const shape = this.getAttribute("shape") ?? "circle";
|
|
54
|
+
const themeCSS = nexui_compiler.getThemeCSS(nexui_compiler.getActiveTheme(), ":host");
|
|
55
|
+
|
|
56
|
+
const sizeMap: Record<string, { px: number; fs: number; dot: number; }> = {
|
|
57
|
+
xs: { px: 20, fs: 8, dot: 5 },
|
|
58
|
+
sm: { px: 28, fs: 11, dot: 7 },
|
|
59
|
+
md: { px: 36, fs: 14, dot: 9 },
|
|
60
|
+
lg: { px: 48, fs: 18, dot: 11 },
|
|
61
|
+
xl: { px: 64, fs: 24, dot: 13 },
|
|
62
|
+
};
|
|
63
|
+
const s = sizeMap[size] ?? sizeMap.md;
|
|
64
|
+
|
|
65
|
+
const borderRadius = shape === "square"
|
|
66
|
+
? `${Math.round(s.px * 0.2)}px`
|
|
67
|
+
: "50%";
|
|
68
|
+
|
|
69
|
+
const initials = name ? getInitials(name) : "?";
|
|
70
|
+
const hue = nameToHue(name || "?");
|
|
71
|
+
const fallbackBg = `hsl(${hue}, 35%, 22%)`;
|
|
72
|
+
const fallbackFg = `hsl(${hue}, 70%, 72%)`;
|
|
73
|
+
|
|
74
|
+
const statusColor: Record<string, string> = {
|
|
75
|
+
online: "#22C55E",
|
|
76
|
+
away: "#EAB308",
|
|
77
|
+
busy: "#EF4444",
|
|
78
|
+
offline: "#484F58",
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const dotColor = statusColor[status] ?? "";
|
|
82
|
+
const dotBorder = size === "xs" ? "1px" : "2px";
|
|
83
|
+
|
|
84
|
+
const imgContent = src
|
|
85
|
+
? `<img src="${src}" alt="${name ? `Avatar of ${name}` : "User avatar"}" loading="lazy" />`
|
|
86
|
+
: `<span class="initials" aria-hidden="true">${initials}</span>`;
|
|
87
|
+
|
|
88
|
+
this.shadowRoot.innerHTML = `
|
|
89
|
+
<style>
|
|
90
|
+
${themeCSS}
|
|
91
|
+
:host {
|
|
92
|
+
display: inline-block;
|
|
93
|
+
position: relative;
|
|
94
|
+
width: ${s.px}px;
|
|
95
|
+
height: ${s.px}px;
|
|
96
|
+
flex-shrink: 0;
|
|
97
|
+
}
|
|
98
|
+
.avatar {
|
|
99
|
+
width: ${s.px}px;
|
|
100
|
+
height: ${s.px}px;
|
|
101
|
+
border-radius: ${borderRadius};
|
|
102
|
+
background: ${fallbackBg};
|
|
103
|
+
border: 1px solid var(--nx-border, rgba(255,255,255,0.08));
|
|
104
|
+
overflow: hidden;
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
user-select: none;
|
|
109
|
+
}
|
|
110
|
+
img {
|
|
111
|
+
width: 100%;
|
|
112
|
+
height: 100%;
|
|
113
|
+
object-fit: cover;
|
|
114
|
+
display: block;
|
|
115
|
+
}
|
|
116
|
+
.initials {
|
|
117
|
+
font-family: var(--nx-font-sans, system-ui, sans-serif);
|
|
118
|
+
font-size: ${s.fs}px;
|
|
119
|
+
font-weight: 600;
|
|
120
|
+
color: ${fallbackFg};
|
|
121
|
+
line-height: 1;
|
|
122
|
+
letter-spacing: 0.02em;
|
|
123
|
+
}
|
|
124
|
+
${status ? `.dot {
|
|
125
|
+
position: absolute;
|
|
126
|
+
bottom: 0;
|
|
127
|
+
right: 0;
|
|
128
|
+
width: ${s.dot}px;
|
|
129
|
+
height: ${s.dot}px;
|
|
130
|
+
border-radius: 50%;
|
|
131
|
+
background: ${dotColor};
|
|
132
|
+
border: ${dotBorder} solid var(--nx-bg-base, #0D1117);
|
|
133
|
+
}` : ""}
|
|
134
|
+
</style>
|
|
135
|
+
<div class="avatar" role="img" aria-label="${name ? `Avatar of ${name}` : "User avatar"}" part="avatar">
|
|
136
|
+
${imgContent}
|
|
137
|
+
</div>
|
|
138
|
+
${status ? `<span class="dot" aria-label="${status}" title="${status}"></span>` : ""}
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
// Hide initials when image loads successfully
|
|
142
|
+
if (src) {
|
|
143
|
+
const img = this.shadowRoot.querySelector<HTMLImageElement>("img");
|
|
144
|
+
const initialsEl = this.shadowRoot.querySelector<HTMLSpanElement>(".initials");
|
|
145
|
+
if (img && initialsEl) {
|
|
146
|
+
img.addEventListener("error", () => {
|
|
147
|
+
img.style.display = "none";
|
|
148
|
+
// Create and append initials span if image fails
|
|
149
|
+
const span = document.createElement("span");
|
|
150
|
+
span.className = "initials";
|
|
151
|
+
span.setAttribute("aria-hidden", "true");
|
|
152
|
+
span.textContent = initials;
|
|
153
|
+
span.style.cssText = `font-family:var(--nx-font-sans,system-ui,sans-serif);font-size:${s.fs}px;font-weight:600;color:${fallbackFg};line-height:1;letter-spacing:0.02em;`;
|
|
154
|
+
img.parentElement?.appendChild(span);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// @yugnex/nexui — NexBadge Web Component
|
|
2
|
+
// Inline status chip for labels, counts, and state indicators.
|
|
3
|
+
// Attributes:
|
|
4
|
+
// variant: default | accent | live | success | error | warning | muted
|
|
5
|
+
// size: sm | md
|
|
6
|
+
// dot: boolean — shows a pulsing presence dot before the text
|
|
7
|
+
|
|
8
|
+
import { nexui_compiler } from "../core/compiler";
|
|
9
|
+
|
|
10
|
+
export class NexBadge extends HTMLElement {
|
|
11
|
+
static get observedAttributes() {
|
|
12
|
+
return ["variant", "size", "dot"];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
this.attachShadow({ mode: "open" });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
connectedCallback() {
|
|
21
|
+
this.render();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
attributeChangedCallback() {
|
|
25
|
+
this.render();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private render() {
|
|
29
|
+
if (!this.shadowRoot) return;
|
|
30
|
+
|
|
31
|
+
const variant = this.getAttribute("variant") ?? "default";
|
|
32
|
+
const size = this.getAttribute("size") ?? "md";
|
|
33
|
+
const showDot = this.getAttribute("dot") === "true";
|
|
34
|
+
const themeCSS = nexui_compiler.getThemeCSS(nexui_compiler.getActiveTheme(), ":host");
|
|
35
|
+
|
|
36
|
+
const variantCSS: Record<string, string> = {
|
|
37
|
+
default: `background:var(--nx-bg-elevated,#1C2128); color:var(--nx-text-2,#8B949E); border:1px solid var(--nx-border,rgba(255,255,255,0.08));`,
|
|
38
|
+
accent: `background:var(--nx-accent-dim,rgba(232,144,16,0.09)); color:var(--nx-accent-text,#F5B342); border:1px solid var(--nx-accent-border,rgba(232,144,16,0.22));`,
|
|
39
|
+
live: `background:var(--nx-live-dim,rgba(15,212,198,0.09)); color:var(--nx-live,#0FD4C6); border:1px solid var(--nx-live-border,rgba(15,212,198,0.22));`,
|
|
40
|
+
success: `background:var(--nx-success-dim,rgba(34,197,94,0.10)); color:var(--nx-success,#22C55E); border:1px solid rgba(34,197,94,0.25);`,
|
|
41
|
+
error: `background:var(--nx-error-dim,rgba(239,68,68,0.10)); color:var(--nx-error,#EF4444); border:1px solid rgba(239,68,68,0.25);`,
|
|
42
|
+
warning: `background:var(--nx-warning-dim,rgba(234,179,8,0.10)); color:var(--nx-warning,#EAB308); border:1px solid rgba(234,179,8,0.25);`,
|
|
43
|
+
muted: `background:rgba(255,255,255,0.04); color:var(--nx-text-3,#6E7681); border:1px solid transparent;`,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const dotColor: Record<string, string> = {
|
|
47
|
+
default: "var(--nx-text-4,#484F58)",
|
|
48
|
+
accent: "var(--nx-accent,#E89010)",
|
|
49
|
+
live: "var(--nx-live,#0FD4C6)",
|
|
50
|
+
success: "var(--nx-success,#22C55E)",
|
|
51
|
+
error: "var(--nx-error,#EF4444)",
|
|
52
|
+
warning: "var(--nx-warning,#EAB308)",
|
|
53
|
+
muted: "var(--nx-text-4,#484F58)",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const sizeCSS = size === "sm"
|
|
57
|
+
? `font-size:10px; padding:2px 6px; border-radius:4px; gap:4px;`
|
|
58
|
+
: `font-size:11px; padding:3px 8px; border-radius:5px; gap:5px;`;
|
|
59
|
+
|
|
60
|
+
const dotSize = size === "sm" ? 5 : 6;
|
|
61
|
+
|
|
62
|
+
this.shadowRoot.innerHTML = `
|
|
63
|
+
<style>
|
|
64
|
+
${themeCSS}
|
|
65
|
+
:host {
|
|
66
|
+
display: inline-flex;
|
|
67
|
+
}
|
|
68
|
+
.badge {
|
|
69
|
+
display: inline-flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
font-family: var(--nx-font-mono, ui-monospace, monospace);
|
|
72
|
+
font-weight: 500;
|
|
73
|
+
letter-spacing: 0.04em;
|
|
74
|
+
white-space: nowrap;
|
|
75
|
+
line-height: 1;
|
|
76
|
+
${sizeCSS}
|
|
77
|
+
${variantCSS[variant] ?? variantCSS.default}
|
|
78
|
+
}
|
|
79
|
+
.dot {
|
|
80
|
+
width: ${dotSize}px;
|
|
81
|
+
height: ${dotSize}px;
|
|
82
|
+
border-radius: 50%;
|
|
83
|
+
background: ${dotColor[variant] ?? dotColor.default};
|
|
84
|
+
flex-shrink: 0;
|
|
85
|
+
animation: ${variant === "live" ? "nx-pulse 2s ease-in-out infinite" : "none"};
|
|
86
|
+
}
|
|
87
|
+
@keyframes nx-pulse {
|
|
88
|
+
0%, 100% { opacity: 1; }
|
|
89
|
+
50% { opacity: 0.35; }
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
92
|
+
<span class="badge" part="badge">
|
|
93
|
+
${showDot ? '<span class="dot" aria-hidden="true"></span>' : ""}
|
|
94
|
+
<slot></slot>
|
|
95
|
+
</span>
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// @yugnex/nexui — NexButton Web Component
|
|
2
|
+
// Attributes:
|
|
3
|
+
// variant: primary | secondary | ghost | danger | outline | accent | live
|
|
4
|
+
// size: sm | md | lg
|
|
5
|
+
// loading: boolean
|
|
6
|
+
// disabled: boolean (native HTML attribute)
|
|
7
|
+
// icon-only: boolean (square aspect ratio)
|
|
8
|
+
|
|
9
|
+
import { nexui_compiler } from "../core/compiler";
|
|
10
|
+
|
|
11
|
+
export class NexButton extends HTMLElement {
|
|
12
|
+
private btn: HTMLButtonElement | null = null;
|
|
13
|
+
|
|
14
|
+
static get observedAttributes() {
|
|
15
|
+
return ["variant", "size", "loading", "disabled", "icon-only", "type"];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
this.attachShadow({ mode: "open" });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
connectedCallback() {
|
|
24
|
+
this.render();
|
|
25
|
+
this.setupDelegation();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
attributeChangedCallback() {
|
|
29
|
+
this.render();
|
|
30
|
+
this.setupDelegation();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Forward clicks from the host element to the internal button
|
|
34
|
+
private setupDelegation() {
|
|
35
|
+
this.onclick = (e) => {
|
|
36
|
+
if (this.hasAttribute("disabled") || this.getAttribute("loading") === "true") {
|
|
37
|
+
e.stopImmediatePropagation();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private render() {
|
|
44
|
+
if (!this.shadowRoot) return;
|
|
45
|
+
|
|
46
|
+
const variant = this.getAttribute("variant") ?? "primary";
|
|
47
|
+
const size = this.getAttribute("size") ?? "md";
|
|
48
|
+
const loading = this.getAttribute("loading") === "true";
|
|
49
|
+
const disabled = this.hasAttribute("disabled") || loading;
|
|
50
|
+
const iconOnly = this.getAttribute("icon-only") === "true";
|
|
51
|
+
const type = this.getAttribute("type") ?? "button";
|
|
52
|
+
const themeCSS = nexui_compiler.getThemeCSS(nexui_compiler.getActiveTheme(), ":host");
|
|
53
|
+
|
|
54
|
+
const sizeStyles: Record<string, string> = {
|
|
55
|
+
sm: `font-size:11px; padding:${iconOnly ? "5px" : "5px 10px"}; min-height:28px; border-radius:5px; gap:6px;`,
|
|
56
|
+
md: `font-size:13px; padding:${iconOnly ? "7px" : "7px 14px"}; min-height:34px; border-radius:6px; gap:8px;`,
|
|
57
|
+
lg: `font-size:14px; padding:${iconOnly ? "9px" : "9px 18px"}; min-height:40px; border-radius:7px; gap:10px;`,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const variantStyles: Record<string, string> = {
|
|
61
|
+
primary: `background:var(--nx-accent,#E89010); color:#000; border:none;`,
|
|
62
|
+
secondary: `background:var(--nx-bg-elevated,#1C2128); color:var(--nx-text,#E6EDF3); border:1px solid var(--nx-border-strong,rgba(255,255,255,0.16));`,
|
|
63
|
+
ghost: `background:transparent; color:var(--nx-text,#E6EDF3); border:none;`,
|
|
64
|
+
outline: `background:transparent; color:var(--nx-text,#E6EDF3); border:1px solid var(--nx-border-strong,rgba(255,255,255,0.16));`,
|
|
65
|
+
danger: `background:var(--nx-error,#EF4444); color:#fff; border:none;`,
|
|
66
|
+
accent: `background:var(--nx-accent-dim,rgba(232,144,16,0.09)); color:var(--nx-accent-text,#F5B342); border:1px solid var(--nx-accent-border,rgba(232,144,16,0.22));`,
|
|
67
|
+
live: `background:var(--nx-live-dim,rgba(15,212,198,0.09)); color:var(--nx-live,#0FD4C6); border:1px solid var(--nx-live-border,rgba(15,212,198,0.22));`,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const hoverStyles: Record<string, string> = {
|
|
71
|
+
primary: `filter:brightness(1.1);`,
|
|
72
|
+
secondary: `background:var(--nx-bg-overlay,#21262D);`,
|
|
73
|
+
ghost: `background:rgba(255,255,255,0.06);`,
|
|
74
|
+
outline: `background:rgba(255,255,255,0.04); border-color:rgba(255,255,255,0.24);`,
|
|
75
|
+
danger: `filter:brightness(1.1);`,
|
|
76
|
+
accent: `background:rgba(232,144,16,0.14);`,
|
|
77
|
+
live: `background:rgba(15,212,198,0.14);`,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const iconSize = size === "sm" ? 12 : size === "lg" ? 16 : 14;
|
|
81
|
+
|
|
82
|
+
this.shadowRoot.innerHTML = `
|
|
83
|
+
<style>
|
|
84
|
+
${themeCSS}
|
|
85
|
+
:host {
|
|
86
|
+
display: inline-block;
|
|
87
|
+
}
|
|
88
|
+
button {
|
|
89
|
+
display: inline-flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
justify-content: center;
|
|
92
|
+
font-family: var(--nx-font-sans, system-ui, sans-serif);
|
|
93
|
+
font-weight: 500;
|
|
94
|
+
letter-spacing: 0.01em;
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
user-select: none;
|
|
97
|
+
white-space: nowrap;
|
|
98
|
+
text-decoration: none;
|
|
99
|
+
transition: background 150ms ease, color 150ms ease, border-color 150ms ease, filter 150ms ease, opacity 150ms ease, box-shadow 150ms ease;
|
|
100
|
+
${sizeStyles[size] ?? sizeStyles.md}
|
|
101
|
+
${variantStyles[variant] ?? variantStyles.primary}
|
|
102
|
+
${iconOnly ? `aspect-ratio: 1; padding: ${size === "sm" ? "5px" : size === "lg" ? "9px" : "7px"};` : ""}
|
|
103
|
+
}
|
|
104
|
+
button:hover:not(:disabled):not(.loading) {
|
|
105
|
+
${hoverStyles[variant] ?? ""}
|
|
106
|
+
}
|
|
107
|
+
button:active:not(:disabled):not(.loading) {
|
|
108
|
+
transform: translateY(1px);
|
|
109
|
+
filter: brightness(0.95);
|
|
110
|
+
}
|
|
111
|
+
button:focus-visible {
|
|
112
|
+
outline: none;
|
|
113
|
+
box-shadow: 0 0 0 2px var(--nx-bg-base, #0D1117), 0 0 0 4px var(--nx-accent, #E89010);
|
|
114
|
+
}
|
|
115
|
+
button:disabled, button.loading {
|
|
116
|
+
opacity: 0.45;
|
|
117
|
+
cursor: not-allowed;
|
|
118
|
+
}
|
|
119
|
+
.spinner {
|
|
120
|
+
width: ${iconSize}px;
|
|
121
|
+
height: ${iconSize}px;
|
|
122
|
+
border: 1.5px solid transparent;
|
|
123
|
+
border-top-color: currentColor;
|
|
124
|
+
border-radius: 50%;
|
|
125
|
+
animation: nx-spin 600ms linear infinite;
|
|
126
|
+
flex-shrink: 0;
|
|
127
|
+
}
|
|
128
|
+
@keyframes nx-spin {
|
|
129
|
+
to { transform: rotate(360deg); }
|
|
130
|
+
}
|
|
131
|
+
::slotted(svg) {
|
|
132
|
+
width: ${iconSize}px;
|
|
133
|
+
height: ${iconSize}px;
|
|
134
|
+
flex-shrink: 0;
|
|
135
|
+
}
|
|
136
|
+
</style>
|
|
137
|
+
<button
|
|
138
|
+
type="${type}"
|
|
139
|
+
${disabled ? "disabled" : ""}
|
|
140
|
+
${loading ? 'class="loading"' : ""}
|
|
141
|
+
part="button"
|
|
142
|
+
>
|
|
143
|
+
${loading ? '<span class="spinner" aria-hidden="true"></span>' : ""}
|
|
144
|
+
<slot></slot>
|
|
145
|
+
</button>
|
|
146
|
+
`;
|
|
147
|
+
this.btn = this.shadowRoot.querySelector("button");
|
|
148
|
+
}
|
|
149
|
+
}
|