@tachui/primitives 0.8.0-alpha

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 (49) hide show
  1. package/LICENSE +363 -0
  2. package/README.md +458 -0
  3. package/dist/BasicInput-CWFHw9rL.js +390 -0
  4. package/dist/Divider-DWgDKavU.js +474 -0
  5. package/dist/HTML-aWcvQ0VC.js +321 -0
  6. package/dist/Picker-DrZ7ibdt.js +1675 -0
  7. package/dist/Text-DYyFBJ6i.js +165 -0
  8. package/dist/controls/Button.d.ts +250 -0
  9. package/dist/controls/Button.d.ts.map +1 -0
  10. package/dist/controls/Link.d.ts +365 -0
  11. package/dist/controls/Link.d.ts.map +1 -0
  12. package/dist/controls/Picker.d.ts +153 -0
  13. package/dist/controls/Picker.d.ts.map +1 -0
  14. package/dist/controls/Toggle.d.ts +207 -0
  15. package/dist/controls/Toggle.d.ts.map +1 -0
  16. package/dist/controls/index.d.ts +8 -0
  17. package/dist/controls/index.d.ts.map +1 -0
  18. package/dist/controls/index.js +18 -0
  19. package/dist/display/HTML.d.ts +120 -0
  20. package/dist/display/HTML.d.ts.map +1 -0
  21. package/dist/display/Image.d.ts +192 -0
  22. package/dist/display/Image.d.ts.map +1 -0
  23. package/dist/display/Text.d.ts +269 -0
  24. package/dist/display/Text.d.ts.map +1 -0
  25. package/dist/display/index.d.ts +7 -0
  26. package/dist/display/index.d.ts.map +1 -0
  27. package/dist/display/index.js +21 -0
  28. package/dist/forms/BasicForm.d.ts +141 -0
  29. package/dist/forms/BasicForm.d.ts.map +1 -0
  30. package/dist/forms/BasicInput.d.ts +116 -0
  31. package/dist/forms/BasicInput.d.ts.map +1 -0
  32. package/dist/forms/index.d.ts +6 -0
  33. package/dist/forms/index.d.ts.map +1 -0
  34. package/dist/forms/index.js +10 -0
  35. package/dist/index.d.ts +11 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +485 -0
  38. package/dist/layout/Divider.d.ts +168 -0
  39. package/dist/layout/Divider.d.ts.map +1 -0
  40. package/dist/layout/Spacer.d.ts +35 -0
  41. package/dist/layout/Spacer.d.ts.map +1 -0
  42. package/dist/layout/Stack.d.ts +74 -0
  43. package/dist/layout/Stack.d.ts.map +1 -0
  44. package/dist/layout/index.d.ts +7 -0
  45. package/dist/layout/index.d.ts.map +1 -0
  46. package/dist/layout/index.js +15 -0
  47. package/dist/validation.d.ts +91 -0
  48. package/dist/validation.d.ts.map +1 -0
  49. package/package.json +82 -0
@@ -0,0 +1,1675 @@
1
+ import { withModifiers as T, ComponentWithCSSClasses as K, createSignal as z, useLifecycle as X, createEffect as W, isSignal as l, ColorAsset as A, h as a, text as p, ConcatenatedComponent as R, createComputed as Z } from "@tachui/core";
2
+ import { T as V } from "./Text-DYyFBJ6i.js";
3
+ var q = Object.defineProperty, J = (s, e, t) => e in s ? q(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t, v = (s, e, t) => J(s, typeof e != "symbol" ? e + "" : e, t);
4
+ const Q = {
5
+ colors: {
6
+ primary: "#007AFF",
7
+ secondary: "#5856D6",
8
+ destructive: "#FF3B30",
9
+ background: "#F2F2F7",
10
+ surface: "#FFFFFF",
11
+ onPrimary: "#FFFFFF",
12
+ onSecondary: "#FFFFFF",
13
+ onSurface: "#000000",
14
+ border: "#C7C7CC",
15
+ disabled: "#8E8E93"
16
+ },
17
+ spacing: {
18
+ small: 8,
19
+ medium: 12,
20
+ large: 16
21
+ },
22
+ borderRadius: {
23
+ small: 6,
24
+ medium: 8,
25
+ large: 12
26
+ },
27
+ typography: {
28
+ small: { size: 14, weight: "500" },
29
+ medium: { size: 16, weight: "500" },
30
+ large: { size: 18, weight: "600" }
31
+ }
32
+ };
33
+ class ee extends K {
34
+ constructor(e, t = Q) {
35
+ super(), this.props = e, v(this, "type", "component"), v(this, "id"), v(this, "mounted", !1), v(this, "cleanup", []), v(this, "stateSignal"), v(this, "setState"), v(this, "theme"), this.id = `button-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, this.theme = t;
36
+ const [i, r] = z("normal");
37
+ this.stateSignal = i, this.setState = r, this.setupDOMEventListeners();
38
+ }
39
+ /**
40
+ * Set up DOM event listeners for button interactions
41
+ */
42
+ setupDOMEventListeners() {
43
+ X(this, {
44
+ onDOMReady: (e, t) => {
45
+ t instanceof HTMLButtonElement && (this.attachInteractionEvents(t), this.setupReactiveStyles(t));
46
+ }
47
+ });
48
+ }
49
+ /**
50
+ * Set up reactive style updates based on state changes
51
+ */
52
+ setupReactiveStyles(e) {
53
+ const t = W(() => {
54
+ this.stateSignal(), this.isEnabled(), this.isLoading();
55
+ const { tint: i, backgroundColor: r, foregroundColor: n } = this.props;
56
+ i && l(i) ? i() : i instanceof A && i.resolve(), r && l(r) ? r() : r instanceof A && r.resolve(), n && l(n) ? n() : n instanceof A && n.resolve();
57
+ const o = this.getButtonStyles();
58
+ this.applyStylesToElement(e, o);
59
+ });
60
+ this.cleanup.push(() => {
61
+ t && typeof t.dispose == "function" && t.dispose();
62
+ });
63
+ }
64
+ /**
65
+ * Apply computed styles to the button element, respecting modifier-applied styles
66
+ */
67
+ applyStylesToElement(e, t) {
68
+ Object.entries(t).forEach(([i, r]) => {
69
+ const n = this.camelToKebabCase(i);
70
+ if (typeof r == "string" || typeof r == "number") {
71
+ const o = e.style.getPropertyValue(n);
72
+ n === "transform" ? e.style.setProperty(n, String(r)) : o && o !== "" && o !== "inherit" || e.style.setProperty(n, String(r));
73
+ }
74
+ });
75
+ }
76
+ /**
77
+ * Convert camelCase to kebab-case for CSS properties
78
+ */
79
+ camelToKebabCase(e) {
80
+ return e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
81
+ }
82
+ /**
83
+ * Resolve color value from string, signal, or asset
84
+ */
85
+ resolveColorValue(e) {
86
+ if (e) {
87
+ if (typeof e == "string")
88
+ return e;
89
+ if (l(e))
90
+ return e();
91
+ if (e instanceof A)
92
+ return e.resolve();
93
+ }
94
+ }
95
+ /**
96
+ * Attach interaction event listeners to the button element
97
+ */
98
+ attachInteractionEvents(e) {
99
+ const t = () => {
100
+ const c = this.isEnabled();
101
+ return typeof c == "boolean" ? c : c();
102
+ };
103
+ let i = null;
104
+ const r = (c) => {
105
+ t() && c.button === 0 && (this.setState("pressed"), i = () => {
106
+ this.stateSignal() === "pressed" && this.setState("normal"), i && (document.removeEventListener("mouseup", i), i = null);
107
+ }, document.addEventListener("mouseup", i));
108
+ }, n = () => {
109
+ t() && this.stateSignal() === "pressed" && (this.setState("normal"), i && (document.removeEventListener("mouseup", i), i = null));
110
+ }, o = () => {
111
+ t() && (this.setState("normal"), i && (document.removeEventListener("mouseup", i), i = null));
112
+ }, d = () => {
113
+ t() && this.stateSignal() !== "pressed" && this.setState("focused");
114
+ }, u = () => {
115
+ t() && this.stateSignal() === "focused" && this.setState("normal");
116
+ }, y = (c) => {
117
+ t() && (c.key === " " || c.key === "Enter") && (c.preventDefault(), this.setState("pressed"));
118
+ }, f = (c) => {
119
+ t() && (c.key === " " || c.key === "Enter") && (c.preventDefault(), this.setState("normal"), this.props.action?.());
120
+ };
121
+ e.addEventListener("mousedown", r), e.addEventListener("mouseup", n), e.addEventListener("mouseleave", o), e.addEventListener("focus", d), e.addEventListener("blur", u), e.addEventListener("keydown", y), e.addEventListener("keyup", f), this.cleanup.push(() => {
122
+ e.removeEventListener("mousedown", r), e.removeEventListener("mouseup", n), e.removeEventListener("mouseleave", o), e.removeEventListener("focus", d), e.removeEventListener("blur", u), e.removeEventListener("keydown", y), e.removeEventListener("keyup", f), i && (document.removeEventListener("mouseup", i), i = null);
123
+ });
124
+ }
125
+ /**
126
+ * Check if button is enabled
127
+ */
128
+ isEnabled() {
129
+ const { isEnabled: e } = this.props;
130
+ return e === void 0 ? !0 : typeof e == "boolean" || l(e) ? e : !0;
131
+ }
132
+ /**
133
+ * Render the button component
134
+ */
135
+ render() {
136
+ const e = this.isEnabled(), t = [];
137
+ this.props.systemImage && t.push(
138
+ a(
139
+ "span",
140
+ {
141
+ class: "button-icon",
142
+ style: {
143
+ marginRight: "8px",
144
+ fontSize: "1.2em"
145
+ }
146
+ },
147
+ p(this.props.systemImage)
148
+ )
149
+ ), t.push(
150
+ a(
151
+ "span",
152
+ {
153
+ class: "button-title"
154
+ },
155
+ p(this.props.title || "")
156
+ )
157
+ );
158
+ const i = ["tachui-button"];
159
+ return [{
160
+ type: "element",
161
+ tag: "button",
162
+ props: {
163
+ className: this.createClassString(this.props, i),
164
+ type: "button",
165
+ disabled: typeof e == "boolean" ? !e : () => !e(),
166
+ // Invert enabled to disabled
167
+ onClick: this.props.action ? () => {
168
+ try {
169
+ this.props.action?.();
170
+ } catch (o) {
171
+ console.error("Button action error:", o);
172
+ }
173
+ } : void 0,
174
+ // Pass through debug label for debug system
175
+ ...this.props.debugLabel && { debugLabel: this.props.debugLabel }
176
+ },
177
+ children: t,
178
+ // Attach component metadata for modifier processing
179
+ componentMetadata: {
180
+ id: this.id,
181
+ type: "Button"
182
+ // Note: modifiers are attached automatically by the modifier system
183
+ }
184
+ }];
185
+ }
186
+ /**
187
+ * Check if button is in loading state
188
+ */
189
+ isLoading() {
190
+ const { isLoading: e } = this.props;
191
+ return e === void 0 ? !1 : typeof e == "boolean" ? e : l(e) ? e() : !1;
192
+ }
193
+ /**
194
+ * Check if the button has color-related modifiers applied
195
+ */
196
+ hasColorModifiers() {
197
+ let e = this.modifiers;
198
+ return !e && this.modifierBuilder && (e = this.modifierBuilder.modifiers), !e && this.modifiableComponent && (e = this.modifiableComponent.modifiers), !e || !Array.isArray(e) ? !1 : e.some((t) => t.type === "appearance" || t.constructor?.name === "AppearanceModifier" ? t.properties && (t.properties.foregroundColor !== void 0 || t.properties.color !== void 0) : t.properties ? ["foregroundColor", "color", "textColor"].some((r) => t.properties[r] !== void 0) : !1);
199
+ }
200
+ /**
201
+ * Check if the button has typography-related modifiers applied
202
+ */
203
+ hasTypographyModifiers() {
204
+ let e = this.modifiers;
205
+ return !e && this.modifierBuilder && (e = this.modifierBuilder.modifiers), !e && this.modifiableComponent && (e = this.modifiableComponent.modifiers), !e || !Array.isArray(e) ? !1 : e.some((i) => i.type === "typography" || i.constructor?.name === "TypographyModifier" ? i.properties && (i.properties.transform !== void 0 || i.properties.textTransform !== void 0) : !1);
206
+ }
207
+ /**
208
+ * Get computed button styles based on variant, size, role, and state
209
+ */
210
+ // biome-ignore lint/suspicious/noExplicitAny: CSS styles require flexible property types
211
+ getButtonStyles() {
212
+ const {
213
+ variant: e,
214
+ size: t,
215
+ role: i = "none",
216
+ tint: r,
217
+ backgroundColor: n,
218
+ foregroundColor: o
219
+ } = this.props, d = this.stateSignal(), u = this.isLoading(), y = this.isEnabled(), f = this.hasColorModifiers(), c = this.hasTypographyModifiers(), C = {
220
+ // Only set color property if no modifiers will handle it
221
+ // This prevents conflicts between Button styles and AppearanceModifier
222
+ ...!f && !o && !e && { color: "inherit" },
223
+ // Only set text-related properties if no typography modifiers will handle them
224
+ // This prevents conflicts between Button styles and TypographyModifier
225
+ ...!c && {
226
+ fontStyle: "inherit",
227
+ lineHeight: "inherit",
228
+ textTransform: "inherit",
229
+ textDecoration: "inherit",
230
+ textIndent: "inherit",
231
+ textShadow: "inherit",
232
+ wordSpacing: "inherit",
233
+ textOrientation: "inherit",
234
+ writingMode: "inherit",
235
+ direction: "inherit"
236
+ }
237
+ // Let modifiers control: fontFamily, fontSize, fontWeight, letterSpacing, textAlign
238
+ };
239
+ if (t) {
240
+ const k = this.theme.spacing[t] || this.theme.spacing.medium, j = this.theme.borderRadius[t] || this.theme.borderRadius.medium, H = this.theme.typography[t] || this.theme.typography.medium, Y = {
241
+ small: "32px",
242
+ medium: "40px",
243
+ large: "48px"
244
+ };
245
+ C.padding = `${k}px ${k * 2}px`, C.borderRadius = `${j}px`, C.fontSize = `${H.size}px`, C.fontWeight = H.weight, C.minHeight = Y[t];
246
+ }
247
+ let g = "transparent", S = "transparent", _ = "1px", L;
248
+ const G = this.resolveColorValue(r), D = this.resolveColorValue(n), O = this.resolveColorValue(o);
249
+ if (e) {
250
+ const k = G || this.theme.colors.primary;
251
+ switch (e) {
252
+ case "filled":
253
+ i === "destructive" ? g = this.theme.colors.destructive : i === "cancel" ? g = this.theme.colors.secondary : g = k, L = this.theme.colors.onPrimary;
254
+ break;
255
+ case "outlined":
256
+ S = i === "destructive" ? this.theme.colors.destructive : k, L = i === "destructive" ? this.theme.colors.destructive : k;
257
+ break;
258
+ case "bordered":
259
+ g = this.theme.colors.background, S = this.theme.colors.border;
260
+ break;
261
+ case "borderedProminent":
262
+ g = this.theme.colors.surface, S = this.theme.colors.primary, _ = "2px";
263
+ break;
264
+ }
265
+ }
266
+ D && (g = D), O && (L = O);
267
+ let F = "1", P = "auto", M, B = "none";
268
+ y ? u ? (F = "0.6", P = "none") : d === "pressed" ? (g = this.darkenColor(g, 0.1), S = this.darkenColor(S, 0.1), M = "scale(0.95)") : d === "focused" && (B = "0 0 0 3px #007AFF40") : (g = this.theme.colors.disabled, S = this.theme.colors.disabled, L = this.theme.colors.disabled, F = "0.6", P = "none");
269
+ const h = {
270
+ ...C
271
+ // Size-based styles (only if size provided)
272
+ };
273
+ return e && (h.backgroundColor = g, h.borderColor = S, h.borderWidth = _, L !== void 0 && (h.color = L)), D && (h.backgroundColor = D), O && (h.color = O), h.cursor = y ? "pointer" : "not-allowed", h.opacity = F, h.pointerEvents = P, h.transform = M !== void 0 ? M : "none", h.boxShadow = B, h.transition = "all 0.2s ease", h;
274
+ }
275
+ /**
276
+ * Handle button press with proper state management
277
+ */
278
+ async handlePress() {
279
+ if (!(!this.isEnabled() || this.isLoading()) && (this.triggerHapticFeedback(), this.setState("pressed"), setTimeout(() => {
280
+ this.isEnabled() && this.setState("normal");
281
+ }, 150), this.props.action))
282
+ try {
283
+ const e = this.props.action();
284
+ e && typeof e.then == "function" && await e;
285
+ } catch (e) {
286
+ console.error("Button action failed:", e);
287
+ }
288
+ }
289
+ /**
290
+ * Trigger haptic feedback (mobile Safari support)
291
+ */
292
+ triggerHapticFeedback() {
293
+ if (this.props.hapticFeedback !== !1 && typeof window < "u" && "navigator" in window) {
294
+ const e = window.navigator;
295
+ e.vibrate && e.vibrate(10);
296
+ }
297
+ }
298
+ /**
299
+ * Helper to darken a color for pressed states
300
+ */
301
+ darkenColor(e, t) {
302
+ if (e === "transparent") return e;
303
+ if (e.startsWith("#")) {
304
+ const i = e.slice(1), r = parseInt(i, 16), n = Math.max(0, Math.floor((r >> 16) * (1 - t))), o = Math.max(0, Math.floor((r >> 8 & 255) * (1 - t))), d = Math.max(0, Math.floor((r & 255) * (1 - t)));
305
+ return `#${(n << 16 | o << 8 | d).toString(16).padStart(6, "0")}`;
306
+ }
307
+ return e;
308
+ }
309
+ // ============================================================================
310
+ // Concatenation Support (Phase 3.1)
311
+ // ============================================================================
312
+ /**
313
+ * Concatenate this button with another concatenatable component
314
+ */
315
+ concat(e) {
316
+ const t = this.toSegment(), i = e.toSegment(), r = {
317
+ totalSegments: e instanceof R ? e.segments.length + 1 : 2,
318
+ accessibilityRole: e instanceof R ? this.mergeAccessibilityRoles(
319
+ "composite",
320
+ e.metadata.accessibilityRole
321
+ ) : this.determineAccessibilityRole(e),
322
+ semanticStructure: "inline"
323
+ // Buttons are typically inline in concatenation
324
+ };
325
+ return new R([t, i], r);
326
+ }
327
+ /**
328
+ * Convert this button to a segment for concatenation
329
+ */
330
+ toSegment() {
331
+ return {
332
+ id: this.id,
333
+ component: this,
334
+ modifiers: [],
335
+ // Buttons don't typically have concatenation-specific modifiers
336
+ render: () => {
337
+ const e = this.render();
338
+ return Array.isArray(e) ? e[0] : e;
339
+ }
340
+ };
341
+ }
342
+ /**
343
+ * Check if this component supports concatenation
344
+ */
345
+ isConcatenatable() {
346
+ return !0;
347
+ }
348
+ /**
349
+ * Determine accessibility role for concatenation
350
+ */
351
+ determineAccessibilityRole(e) {
352
+ switch (e.constructor.name) {
353
+ case "EnhancedText":
354
+ return "composite";
355
+ // Button + Text = composite (interactive content)
356
+ case "EnhancedImage":
357
+ return "composite";
358
+ // Button + Image = composite (interactive content)
359
+ case "EnhancedButton":
360
+ case "EnhancedLink":
361
+ return "composite";
362
+ // Button + Interactive = composite
363
+ default:
364
+ return "composite";
365
+ }
366
+ }
367
+ /**
368
+ * Merge accessibility roles when combining components
369
+ */
370
+ mergeAccessibilityRoles(e, t) {
371
+ return "composite";
372
+ }
373
+ }
374
+ function E(s, e, t = {}) {
375
+ const i = {
376
+ ...t,
377
+ title: s,
378
+ ...e && { action: e }
379
+ }, r = new ee(i);
380
+ return T(r);
381
+ }
382
+ const he = {
383
+ /**
384
+ * Filled button (primary)
385
+ */
386
+ Filled: (s, e, t = {}) => E(s, e, { ...t, variant: "filled" }),
387
+ /**
388
+ * Outlined button
389
+ */
390
+ Outlined: (s, e, t = {}) => E(s, e, { ...t, variant: "outlined" }),
391
+ /**
392
+ * Plain button (text only)
393
+ */
394
+ Plain: (s, e, t = {}) => E(s, e, { ...t, variant: "plain" }),
395
+ /**
396
+ * Bordered button
397
+ */
398
+ Bordered: (s, e, t = {}) => E(s, e, { ...t, variant: "bordered" }),
399
+ /**
400
+ * Destructive button
401
+ */
402
+ Destructive: (s, e, t = {}) => E(s, e, { ...t, role: "destructive" }),
403
+ /**
404
+ * Cancel button
405
+ */
406
+ Cancel: (s, e, t = {}) => E(s, e, { ...t, role: "cancel" })
407
+ }, te = `
408
+ @keyframes spin {
409
+ from { transform: rotate(0deg); }
410
+ to { transform: rotate(360deg); }
411
+ }
412
+ `;
413
+ if (typeof document < "u") {
414
+ const s = document.createElement("style");
415
+ s.textContent = te, document.head.appendChild(s);
416
+ }
417
+ var ie = Object.defineProperty, se = (s, e, t) => e in s ? ie(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t, I = (s, e, t) => se(s, typeof e != "symbol" ? e + "" : e, t);
418
+ class U {
419
+ constructor(e) {
420
+ I(this, "type", "component"), I(this, "id"), I(this, "props"), this.props = e, this.id = `enhanced-link-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
421
+ }
422
+ resolveValue(e) {
423
+ return l(e) ? e() : e;
424
+ }
425
+ getDestination() {
426
+ const e = this.resolveValue(this.props.destination);
427
+ return e instanceof URL ? e.toString() : e;
428
+ }
429
+ getTarget() {
430
+ const e = this.resolveValue(this.props.target);
431
+ if (e)
432
+ return e;
433
+ const t = this.resolveValue(this.props.destination), i = t instanceof URL ? t.toString() : t;
434
+ return this.isExternalURL(i) ? "_blank" : "_self";
435
+ }
436
+ getRoutingMode() {
437
+ return this.resolveValue(this.props.routingMode) || "auto";
438
+ }
439
+ getRel() {
440
+ const e = this.resolveValue(this.props.rel), t = this.getTarget(), i = this.getDestination(), n = this.isExternalURL(i) && t === "_blank" ? "noopener noreferrer" : "";
441
+ return e && n ? `${e} ${n}`.trim() : e || n;
442
+ }
443
+ getDownload() {
444
+ return this.resolveValue(this.props.download);
445
+ }
446
+ isDisabled() {
447
+ return this.resolveValue(this.props.disabled) || !1;
448
+ }
449
+ getAccessibilityLabel() {
450
+ return this.resolveValue(this.props.accessibilityLabel);
451
+ }
452
+ getAccessibilityHint() {
453
+ return this.resolveValue(this.props.accessibilityHint);
454
+ }
455
+ getAccessibilityRole() {
456
+ return this.resolveValue(this.props.accessibilityRole);
457
+ }
458
+ shouldUseInternalRouting(e) {
459
+ const t = this.getRoutingMode();
460
+ return t === "internal" ? !0 : t === "external" ? !1 : t === "spa" ? !0 : !(this.isSpecialScheme(e) || this.isExternalURL(e));
461
+ }
462
+ isSpecialScheme(e) {
463
+ return /^(mailto|tel|sms|ftp|file):/.test(e);
464
+ }
465
+ async handleClick(e) {
466
+ if (this.isDisabled()) {
467
+ e.preventDefault();
468
+ return;
469
+ }
470
+ if (this.props.onPress)
471
+ try {
472
+ this.props.onPress(e);
473
+ } catch (n) {
474
+ console.error("Link onPress error:", n);
475
+ }
476
+ const t = this.getDestination();
477
+ if (this.isSpecialScheme(t) || (e.preventDefault(), this.props.openURLAction && this.props.openURLAction(t) === "handled"))
478
+ return;
479
+ if (this.props.onBeforeNavigation)
480
+ try {
481
+ if (!await this.props.onBeforeNavigation(t))
482
+ return;
483
+ } catch (n) {
484
+ throw console.error("Link onBeforeNavigation error:", n), n;
485
+ }
486
+ const i = this.getTarget(), r = this.getRoutingMode();
487
+ if (this.shouldUseInternalRouting(t)) {
488
+ if (this.props.onInternalNavigation)
489
+ try {
490
+ if (await this.props.onInternalNavigation(t))
491
+ return;
492
+ } catch (n) {
493
+ console.error("Link onInternalNavigation error:", n);
494
+ }
495
+ r === "spa" ? this.handleSPANavigation(t) : i === "_blank" ? window.open(t, i) : window.location.href = t;
496
+ } else
497
+ i === "_blank" || i === "_top" || i === "_parent" ? window.open(t, i) : window.location.href = t;
498
+ }
499
+ handleSPANavigation(e) {
500
+ typeof window < "u" && window.history && window.history.pushState ? (window.history.pushState(null, "", e), window.dispatchEvent(new PopStateEvent("popstate"))) : window.location.href = e;
501
+ }
502
+ isExternalURL(e) {
503
+ try {
504
+ return new URL(e, window.location.href).hostname !== window.location.hostname;
505
+ } catch {
506
+ return !1;
507
+ }
508
+ }
509
+ renderContent() {
510
+ if (this.props.label) {
511
+ const n = this.props.label().render();
512
+ return Array.isArray(n) ? n : [n];
513
+ }
514
+ if (this.props.children)
515
+ return this.renderChildren();
516
+ let e;
517
+ this.props.text ? e = this.props.text : l(this.props.destination) ? e = Z(() => this.getDestination()) : e = this.getDestination();
518
+ const i = V(e).render();
519
+ return Array.isArray(i) ? i : [i];
520
+ }
521
+ renderChildren() {
522
+ const { children: e } = this.props;
523
+ return e ? Array.isArray(e) ? e.map((t) => this.renderChild(t)).flat() : this.renderChild(e) : [];
524
+ }
525
+ renderChild(e) {
526
+ if (typeof e == "string") {
527
+ const i = V(e).render();
528
+ return Array.isArray(i) ? i : [i];
529
+ } else {
530
+ const t = e.render();
531
+ return Array.isArray(t) ? t : [t];
532
+ }
533
+ }
534
+ render() {
535
+ const e = this.renderContent(), t = this.isDisabled(), i = {
536
+ id: this.id,
537
+ "data-component": "enhanced-link"
538
+ };
539
+ l(this.props.destination) ? i.href = () => this.getDestination() : i.href = this.getDestination(), this.props.target && (l(this.props.target) ? i.target = () => this.getTarget() : i.target = this.getTarget());
540
+ const r = this.getRel();
541
+ r && (l(this.props.rel) || l(this.props.target) ? i.rel = () => this.getRel() : i.rel = r);
542
+ const n = this.getDownload();
543
+ n !== void 0 && (l(this.props.download) ? i.download = () => this.getDownload() : n === !0 ? i.download = !0 : typeof n == "string" && (i.download = n));
544
+ const o = this.getAccessibilityLabel();
545
+ o && (l(this.props.accessibilityLabel) ? i["aria-label"] = () => this.getAccessibilityLabel() : i["aria-label"] = o);
546
+ const d = this.getAccessibilityHint();
547
+ d && (l(this.props.accessibilityHint) ? i["aria-describedby"] = () => this.getAccessibilityHint() : i["aria-describedby"] = d);
548
+ const u = this.getAccessibilityRole();
549
+ return u && (l(this.props.accessibilityRole) ? i.role = () => this.getAccessibilityRole() : i.role = u), t && (i["aria-disabled"] = "true", i.tabindex = "-1"), i.onclick = (f) => this.handleClick(f), i.style = {
550
+ textDecoration: "none",
551
+ color: "inherit",
552
+ cursor: t ? "not-allowed" : "pointer",
553
+ opacity: t ? 0.6 : 1
554
+ }, a("a", i, ...e);
555
+ }
556
+ // Concatenation support
557
+ concat(e) {
558
+ const t = this.toSegment(), i = e.toSegment(), r = {
559
+ totalSegments: 2,
560
+ accessibilityRole: "composite",
561
+ semanticStructure: "inline"
562
+ };
563
+ return new R([t, i], r);
564
+ }
565
+ toSegment() {
566
+ return {
567
+ id: this.id,
568
+ component: this,
569
+ modifiers: [],
570
+ render: () => this.render()
571
+ };
572
+ }
573
+ isConcatenatable() {
574
+ return !0;
575
+ }
576
+ }
577
+ function ue(s, e) {
578
+ if (e !== void 0) {
579
+ const r = {
580
+ text: s,
581
+ destination: e
582
+ }, n = new U(r);
583
+ return T(n);
584
+ }
585
+ const t = s, i = new U(t);
586
+ return T(i);
587
+ }
588
+ const x = {
589
+ /**
590
+ * Create an external link that opens in a new tab
591
+ */
592
+ external(s, e, t = {}) {
593
+ return {
594
+ destination: s,
595
+ children: e,
596
+ target: "_blank",
597
+ routingMode: "external",
598
+ rel: "noopener noreferrer external",
599
+ accessibilityHint: "Opens in a new tab",
600
+ ...t
601
+ };
602
+ },
603
+ /**
604
+ * Create an internal link for same-domain navigation
605
+ */
606
+ internal(s, e, t = {}) {
607
+ return {
608
+ destination: s,
609
+ children: e,
610
+ routingMode: "internal",
611
+ target: "_self",
612
+ ...t
613
+ };
614
+ },
615
+ /**
616
+ * Create a SPA link using History API
617
+ */
618
+ spa(s, e, t = {}) {
619
+ return {
620
+ destination: s,
621
+ children: e,
622
+ routingMode: "spa",
623
+ target: "_self",
624
+ accessibilityHint: "Navigates within the app",
625
+ ...t
626
+ };
627
+ },
628
+ /**
629
+ * Create an email link with optional subject and body
630
+ */
631
+ email(s, e, t, i) {
632
+ let r = `mailto:${s}`;
633
+ const n = new URLSearchParams();
634
+ return e && n.append("subject", e), t && n.append("body", t), n.toString() && (r += `?${n.toString()}`), {
635
+ destination: r,
636
+ children: i || s,
637
+ accessibilityLabel: `Send email to ${s}`,
638
+ accessibilityHint: "Opens your email app"
639
+ };
640
+ },
641
+ /**
642
+ * Create a phone link with formatted display
643
+ */
644
+ phone(s, e) {
645
+ return {
646
+ destination: `tel:${s.replace(/[^\d+]/g, "")}`,
647
+ children: e || s,
648
+ accessibilityLabel: `Call ${s}`,
649
+ accessibilityHint: "Opens your phone app"
650
+ };
651
+ },
652
+ /**
653
+ * Create a download link
654
+ */
655
+ download(s, e, t) {
656
+ return {
657
+ destination: s,
658
+ children: t || `Download ${e || "file"}`,
659
+ download: e || !0,
660
+ accessibilityLabel: `Download ${e || "file"}`,
661
+ accessibilityHint: "Downloads file to your device"
662
+ };
663
+ },
664
+ /**
665
+ * Social media link utilities
666
+ */
667
+ social: {
668
+ twitter(s, e) {
669
+ return x.external(
670
+ `https://twitter.com/${s}`,
671
+ e || `@${s}`,
672
+ { accessibilityLabel: `Visit ${s} on Twitter` }
673
+ );
674
+ },
675
+ github(s, e) {
676
+ return x.external(
677
+ `https://github.com/${s}`,
678
+ e || s,
679
+ { accessibilityLabel: `Visit ${s} on GitHub` }
680
+ );
681
+ },
682
+ linkedin(s, e) {
683
+ return x.external(
684
+ `https://linkedin.com/in/${s}`,
685
+ e || s,
686
+ { accessibilityLabel: `Visit ${s} on LinkedIn` }
687
+ );
688
+ },
689
+ instagram(s, e) {
690
+ return x.external(
691
+ `https://instagram.com/${s}`,
692
+ e || `@${s}`,
693
+ { accessibilityLabel: `Visit ${s} on Instagram` }
694
+ );
695
+ },
696
+ facebook(s, e) {
697
+ return x.external(
698
+ `https://facebook.com/${s}`,
699
+ e || s,
700
+ { accessibilityLabel: `Visit ${s} on Facebook` }
701
+ );
702
+ }
703
+ },
704
+ /**
705
+ * App store link utilities
706
+ */
707
+ appStore: {
708
+ ios(s, e) {
709
+ return x.external(
710
+ `https://apps.apple.com/app/id${s}`,
711
+ e || "Download from App Store",
712
+ {
713
+ accessibilityLabel: "Download from the iOS App Store",
714
+ accessibilityHint: "Opens App Store app or website"
715
+ }
716
+ );
717
+ },
718
+ android(s, e) {
719
+ return x.external(
720
+ `https://play.google.com/store/apps/details?id=${s}`,
721
+ e || "Get it on Google Play",
722
+ {
723
+ accessibilityLabel: "Download from Google Play Store",
724
+ accessibilityHint: "Opens Google Play Store app or website"
725
+ }
726
+ );
727
+ }
728
+ },
729
+ /**
730
+ * Create a custom OpenURL action
731
+ */
732
+ openURLAction(s) {
733
+ return (e) => s(e) ? "handled" : "systemAction";
734
+ }
735
+ };
736
+ var ne = Object.defineProperty, re = (s, e, t) => e in s ? ne(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t, w = (s, e, t) => re(s, typeof e != "symbol" ? e + "" : e, t);
737
+ class oe {
738
+ constructor(e) {
739
+ this.props = e, w(this, "type", "component"), w(this, "id"), w(this, "mounted", !1), w(this, "cleanup", []), w(this, "toggleElement", null), w(this, "setIsAnimating"), w(this, "handleToggle", async (i) => {
740
+ if (i.preventDefault(), this.isDisabled()) return;
741
+ const r = !this.getIsOn();
742
+ this.props.animated !== !1 && (this.setIsAnimating(!0), setTimeout(() => {
743
+ this.setIsAnimating(!1);
744
+ }, 200)), this.props.onToggle && this.props.onToggle(r);
745
+ }), this.id = `toggle-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
746
+ const [, t] = z(!1);
747
+ this.setIsAnimating = t, W(() => {
748
+ const i = this.getIsOn();
749
+ this.toggleElement && this.toggleElement.checked !== i && (this.toggleElement.checked = i);
750
+ });
751
+ }
752
+ /**
753
+ * Get current toggle state
754
+ */
755
+ getIsOn() {
756
+ const { isOn: e } = this.props;
757
+ return l(e) ? e() : e;
758
+ }
759
+ // /**
760
+ // * Get toggle state as signal or static value for DOM renderer
761
+ // */
762
+ // private getIsOnForDOM(): boolean | (() => boolean) {
763
+ // const { isOn } = this.props
764
+ // if (isSignal(isOn)) {
765
+ // return isOn as () => boolean
766
+ // }
767
+ // return isOn as boolean
768
+ // }
769
+ /**
770
+ * Check if toggle is disabled
771
+ */
772
+ isDisabled() {
773
+ const { disabled: e } = this.props;
774
+ return typeof e == "boolean" ? e : l(e) ? e() : !1;
775
+ }
776
+ // /**
777
+ // * Get disabled state as signal or static value for DOM renderer
778
+ // */
779
+ // private getDisabledForDOM(): boolean | (() => boolean) {
780
+ // const { disabled } = this.props
781
+ // if (typeof disabled === 'boolean') return disabled
782
+ // if (isSignal(disabled)) return disabled as () => boolean
783
+ // return false
784
+ // }
785
+ /**
786
+ * Resolve label content
787
+ */
788
+ resolveLabel() {
789
+ const { label: e } = this.props;
790
+ return e ? typeof e == "string" ? e : typeof e == "function" || l(e) ? e() : e : null;
791
+ }
792
+ /**
793
+ * Helper to render component content safely
794
+ */
795
+ renderComponentContent(e) {
796
+ const t = e.render();
797
+ return Array.isArray(t) ? t : [t];
798
+ }
799
+ /**
800
+ * Get toggle size styles
801
+ */
802
+ getSizeStyles() {
803
+ const { size: e = "medium" } = this.props;
804
+ switch (e) {
805
+ case "small":
806
+ return {
807
+ width: "36px",
808
+ height: "20px",
809
+ thumbSize: "16px",
810
+ fontSize: "14px"
811
+ };
812
+ case "large":
813
+ return {
814
+ width: "56px",
815
+ height: "32px",
816
+ thumbSize: "28px",
817
+ fontSize: "18px"
818
+ };
819
+ default:
820
+ return {
821
+ width: "46px",
822
+ height: "26px",
823
+ thumbSize: "22px",
824
+ fontSize: "16px"
825
+ };
826
+ }
827
+ }
828
+ /**
829
+ * Render switch variant
830
+ */
831
+ renderSwitch() {
832
+ const e = this.getIsOn(), t = this.isDisabled(), i = this.getSizeStyles(), {
833
+ color: r = "#007AFF",
834
+ offColor: n = "#e2e8f0",
835
+ thumbColor: o = "#ffffff",
836
+ animated: d = !0
837
+ } = this.props, u = e ? r : n, y = e ? `translateX(${parseInt(i.width) - parseInt(i.thumbSize) - 2}px)` : "translateX(2px)";
838
+ return a(
839
+ "div",
840
+ {
841
+ style: {
842
+ position: "relative",
843
+ display: "inline-block"
844
+ }
845
+ },
846
+ // Hidden input for form integration
847
+ a("input", {
848
+ ref: (f) => {
849
+ this.toggleElement = f, f && !this.mounted && (f.addEventListener("change", this.handleToggle), this.cleanup.push(() => {
850
+ f.removeEventListener("change", this.handleToggle);
851
+ }));
852
+ },
853
+ type: "checkbox",
854
+ checked: e,
855
+ disabled: t,
856
+ style: {
857
+ position: "absolute",
858
+ opacity: 0,
859
+ width: "100%",
860
+ height: "100%",
861
+ margin: 0,
862
+ cursor: t ? "not-allowed" : "pointer"
863
+ },
864
+ "aria-label": this.props.accessibilityLabel,
865
+ "aria-describedby": this.props.accessibilityHint ? `${this.id}-hint` : void 0
866
+ }),
867
+ // Switch track
868
+ a(
869
+ "div",
870
+ {
871
+ style: {
872
+ width: i.width,
873
+ height: i.height,
874
+ backgroundColor: u,
875
+ borderRadius: i.height,
876
+ position: "relative",
877
+ cursor: t ? "not-allowed" : "pointer",
878
+ opacity: t ? 0.5 : 1,
879
+ transition: d ? "background-color 0.2s ease" : "none",
880
+ border: "1px solid rgba(0,0,0,0.1)",
881
+ boxShadow: "inset 0 1px 2px rgba(0,0,0,0.1)"
882
+ },
883
+ onClick: this.handleToggle
884
+ },
885
+ // Switch thumb
886
+ a("div", {
887
+ style: {
888
+ width: i.thumbSize,
889
+ height: i.thumbSize,
890
+ backgroundColor: o,
891
+ borderRadius: "50%",
892
+ position: "absolute",
893
+ top: "50%",
894
+ transform: `translateY(-50%) ${y}`,
895
+ transition: d ? "transform 0.2s ease" : "none",
896
+ boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
897
+ border: "1px solid rgba(0,0,0,0.1)"
898
+ }
899
+ })
900
+ )
901
+ );
902
+ }
903
+ /**
904
+ * Render checkbox variant
905
+ */
906
+ renderCheckbox() {
907
+ const e = this.getIsOn(), t = this.isDisabled(), i = this.getSizeStyles(), { color: r = "#007AFF" } = this.props;
908
+ return a(
909
+ "div",
910
+ {
911
+ style: {
912
+ position: "relative",
913
+ display: "inline-block"
914
+ }
915
+ },
916
+ // Hidden input
917
+ a("input", {
918
+ ref: (n) => {
919
+ this.toggleElement = n, n && !this.mounted && (n.addEventListener("change", this.handleToggle), this.cleanup.push(() => {
920
+ n.removeEventListener("change", this.handleToggle);
921
+ }));
922
+ },
923
+ type: "checkbox",
924
+ checked: e,
925
+ disabled: t,
926
+ style: {
927
+ position: "absolute",
928
+ opacity: 0,
929
+ width: "100%",
930
+ height: "100%",
931
+ margin: 0,
932
+ cursor: t ? "not-allowed" : "pointer"
933
+ }
934
+ }),
935
+ // Checkbox visual
936
+ a(
937
+ "div",
938
+ {
939
+ style: {
940
+ width: i.thumbSize,
941
+ height: i.thumbSize,
942
+ border: `2px solid ${e ? r : "#d1d5db"}`,
943
+ borderRadius: "4px",
944
+ backgroundColor: e ? r : "#ffffff",
945
+ display: "flex",
946
+ alignItems: "center",
947
+ justifyContent: "center",
948
+ cursor: t ? "not-allowed" : "pointer",
949
+ opacity: t ? 0.5 : 1,
950
+ transition: "all 0.2s ease"
951
+ },
952
+ onClick: this.handleToggle
953
+ },
954
+ ...e ? [
955
+ // Checkmark
956
+ a("div", {
957
+ style: {
958
+ width: "6px",
959
+ height: "10px",
960
+ border: "2px solid white",
961
+ borderTop: "none",
962
+ borderLeft: "none",
963
+ transform: "rotate(45deg) translateY(-1px)",
964
+ opacity: e ? 1 : 0,
965
+ transition: "opacity 0.1s ease"
966
+ }
967
+ })
968
+ ] : []
969
+ )
970
+ );
971
+ }
972
+ /**
973
+ * Render button variant
974
+ */
975
+ renderButton() {
976
+ const e = this.getIsOn(), t = this.isDisabled(), i = this.getSizeStyles(), { color: r = "#007AFF", offColor: n = "#f3f4f6" } = this.props;
977
+ return a(
978
+ "button",
979
+ {
980
+ ref: (o) => {
981
+ o && !this.mounted && (o.addEventListener("click", this.handleToggle), this.cleanup.push(() => {
982
+ o.removeEventListener("click", this.handleToggle);
983
+ }));
984
+ },
985
+ type: "button",
986
+ disabled: t,
987
+ style: {
988
+ padding: "8px 16px",
989
+ backgroundColor: e ? r : n,
990
+ color: e ? "#ffffff" : "#374151",
991
+ border: `1px solid ${e ? r : "#d1d5db"}`,
992
+ borderRadius: "6px",
993
+ fontSize: i.fontSize,
994
+ fontWeight: "500",
995
+ cursor: t ? "not-allowed" : "pointer",
996
+ opacity: t ? 0.5 : 1,
997
+ transition: "all 0.2s ease",
998
+ outline: "none"
999
+ },
1000
+ "aria-pressed": e,
1001
+ "aria-label": this.props.accessibilityLabel
1002
+ },
1003
+ p(e ? "ON" : "OFF")
1004
+ );
1005
+ }
1006
+ /**
1007
+ * Render toggle control based on variant
1008
+ */
1009
+ renderToggleControl() {
1010
+ const { variant: e = "switch" } = this.props;
1011
+ switch (e) {
1012
+ case "checkbox":
1013
+ return this.renderCheckbox();
1014
+ case "button":
1015
+ return this.renderButton();
1016
+ default:
1017
+ return this.renderSwitch();
1018
+ }
1019
+ }
1020
+ /**
1021
+ * Render label content
1022
+ */
1023
+ renderLabel() {
1024
+ const e = this.resolveLabel();
1025
+ if (!e) return null;
1026
+ const t = this.getSizeStyles();
1027
+ return a(
1028
+ "span",
1029
+ {
1030
+ style: {
1031
+ fontSize: t.fontSize,
1032
+ color: this.isDisabled() ? "#9ca3af" : "#374151",
1033
+ cursor: this.isDisabled() ? "not-allowed" : "pointer"
1034
+ },
1035
+ onClick: this.isDisabled() ? void 0 : this.handleToggle
1036
+ },
1037
+ ...typeof e == "string" ? [p(e)] : this.renderComponentContent(e)
1038
+ );
1039
+ }
1040
+ render() {
1041
+ const {
1042
+ labelPosition: e = "trailing",
1043
+ spacing: t = 8,
1044
+ accessibilityHint: i
1045
+ } = this.props, r = this.renderLabel(), n = this.renderToggleControl(), o = e === "leading" && r ? [r, n] : r ? [n, r] : [n];
1046
+ return a(
1047
+ "div",
1048
+ {
1049
+ style: {
1050
+ display: "flex",
1051
+ alignItems: "center",
1052
+ gap: r ? `${t}px` : "0",
1053
+ cursor: this.isDisabled() ? "not-allowed" : "pointer"
1054
+ },
1055
+ "aria-describedby": i ? `${this.id}-hint` : void 0
1056
+ },
1057
+ ...o,
1058
+ ...i ? [
1059
+ a(
1060
+ "div",
1061
+ {
1062
+ id: `${this.id}-hint`,
1063
+ style: {
1064
+ fontSize: "12px",
1065
+ color: "#6b7280",
1066
+ marginTop: "4px",
1067
+ display: "block",
1068
+ width: "100%"
1069
+ }
1070
+ },
1071
+ p(i)
1072
+ )
1073
+ ] : []
1074
+ );
1075
+ }
1076
+ }
1077
+ function m(s, e = {}) {
1078
+ const t = { ...e, isOn: s }, i = new oe(t);
1079
+ return T(i);
1080
+ }
1081
+ function N(s, e, t = {}) {
1082
+ return m(e, { ...t, label: s });
1083
+ }
1084
+ const fe = {
1085
+ /**
1086
+ * Switch toggle (default)
1087
+ */
1088
+ Switch(s, e = {}) {
1089
+ return m(s, { ...e, variant: "switch" });
1090
+ },
1091
+ /**
1092
+ * Checkbox toggle
1093
+ */
1094
+ Checkbox(s, e = {}) {
1095
+ return m(s, { ...e, variant: "checkbox" });
1096
+ },
1097
+ /**
1098
+ * Button toggle
1099
+ */
1100
+ Button(s, e = {}) {
1101
+ return m(s, { ...e, variant: "button" });
1102
+ },
1103
+ /**
1104
+ * Small toggle
1105
+ */
1106
+ Small(s, e = {}) {
1107
+ return m(s, { ...e, size: "small" });
1108
+ },
1109
+ /**
1110
+ * Large toggle
1111
+ */
1112
+ Large(s, e = {}) {
1113
+ return m(s, { ...e, size: "large" });
1114
+ },
1115
+ /**
1116
+ * Custom color toggle
1117
+ */
1118
+ CustomColor(s, e, t = {}) {
1119
+ return m(s, { ...t, color: e });
1120
+ },
1121
+ /**
1122
+ * Toggle with leading label
1123
+ */
1124
+ WithLeadingLabel(s, e, t = {}) {
1125
+ return m(e, { ...t, label: s, labelPosition: "leading" });
1126
+ },
1127
+ /**
1128
+ * Toggle with trailing label (default)
1129
+ */
1130
+ WithTrailingLabel(s, e, t = {}) {
1131
+ return m(e, { ...t, label: s, labelPosition: "trailing" });
1132
+ }
1133
+ }, ge = {
1134
+ /**
1135
+ * Create a toggle group with multiple options
1136
+ */
1137
+ createGroup(s, e = {}) {
1138
+ return s.map(
1139
+ (t) => N(t.label, t.isOn, {
1140
+ ...e,
1141
+ onToggle: t.onToggle
1142
+ })
1143
+ );
1144
+ },
1145
+ /**
1146
+ * Create exclusive toggle group (radio-like behavior)
1147
+ */
1148
+ createExclusiveGroup(s, e, t, i = {}) {
1149
+ const r = () => l(e) ? e() : e;
1150
+ return s.map(
1151
+ (n) => N(n.label, r() === n.key, {
1152
+ ...i,
1153
+ onToggle: (o) => {
1154
+ o && t && t(n.key);
1155
+ }
1156
+ })
1157
+ );
1158
+ },
1159
+ /**
1160
+ * Batch toggle operations
1161
+ */
1162
+ batch: {
1163
+ /**
1164
+ * Toggle all items in a group
1165
+ */
1166
+ toggleAll(s, e) {
1167
+ s.forEach((t) => {
1168
+ t.onToggle && t.onToggle(e);
1169
+ });
1170
+ },
1171
+ /**
1172
+ * Get state of all toggles in a group
1173
+ */
1174
+ getStates(s) {
1175
+ return s.map((e) => l(e.isOn) ? e.isOn() : e.isOn);
1176
+ },
1177
+ /**
1178
+ * Check if all toggles are on
1179
+ */
1180
+ allOn(s) {
1181
+ return this.getStates(s).every((e) => e);
1182
+ },
1183
+ /**
1184
+ * Check if any toggle is on
1185
+ */
1186
+ anyOn(s) {
1187
+ return this.getStates(s).some((e) => e);
1188
+ }
1189
+ }
1190
+ };
1191
+ var ae = Object.defineProperty, le = (s, e, t) => e in s ? ae(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t, b = (s, e, t) => le(s, typeof e != "symbol" ? e + "" : e, t);
1192
+ class de {
1193
+ constructor(e) {
1194
+ this.props = e, b(this, "type", "component"), b(this, "id"), b(this, "mounted", !1), b(this, "cleanup", []), b(this, "isOpen"), b(this, "setIsOpen"), b(this, "searchTerm"), b(this, "setSearchTerm"), b(this, "handleSelection", (o) => {
1195
+ this.props.onSelectionChange && this.props.onSelectionChange(o), (this.props.variant === "dropdown" || this.props.variant === "menu") && this.setIsOpen(!1), this.setSearchTerm("");
1196
+ }), b(this, "toggleOpen", () => {
1197
+ this.isDisabled() || this.setIsOpen(!this.isOpen());
1198
+ }), this.id = `picker-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1199
+ const [t, i] = z(!1), [r, n] = z("");
1200
+ if (this.isOpen = t, this.setIsOpen = i, this.searchTerm = r, this.setSearchTerm = n, typeof window < "u") {
1201
+ const o = (d) => {
1202
+ const u = document.getElementById(this.id);
1203
+ u && !u.contains(d.target) && this.setIsOpen(!1);
1204
+ };
1205
+ document.addEventListener("click", o), this.cleanup.push(() => {
1206
+ document.removeEventListener("click", o);
1207
+ });
1208
+ }
1209
+ }
1210
+ /**
1211
+ * Get current selection value
1212
+ */
1213
+ getSelection() {
1214
+ const { selection: e } = this.props;
1215
+ return l(e) ? e() : e;
1216
+ }
1217
+ /**
1218
+ * Get current options
1219
+ */
1220
+ getOptions() {
1221
+ const { options: e } = this.props;
1222
+ return l(e) ? e() : e;
1223
+ }
1224
+ /**
1225
+ * Filter options based on search term
1226
+ */
1227
+ getFilteredOptions() {
1228
+ const e = this.getOptions(), t = this.searchTerm().toLowerCase();
1229
+ return !t || !this.props.searchable ? e : e.filter(
1230
+ (i) => i.label.toLowerCase().includes(t) || i.description?.toLowerCase().includes(t)
1231
+ );
1232
+ }
1233
+ /**
1234
+ * Check if picker is disabled
1235
+ */
1236
+ isDisabled() {
1237
+ const { disabled: e } = this.props;
1238
+ return typeof e == "boolean" ? e : l(e) ? e() : !1;
1239
+ }
1240
+ /**
1241
+ * Get selected option
1242
+ */
1243
+ getSelectedOption() {
1244
+ const e = this.getSelection();
1245
+ return this.getOptions().find((i) => i.value === e) || null;
1246
+ }
1247
+ /**
1248
+ * Get picker size styles
1249
+ */
1250
+ getSizeStyles() {
1251
+ const { size: e = "medium" } = this.props;
1252
+ switch (e) {
1253
+ case "small":
1254
+ return {
1255
+ fontSize: "14px",
1256
+ padding: "6px 12px",
1257
+ minHeight: "32px"
1258
+ };
1259
+ case "large":
1260
+ return {
1261
+ fontSize: "18px",
1262
+ padding: "12px 16px",
1263
+ minHeight: "48px"
1264
+ };
1265
+ default:
1266
+ return {
1267
+ fontSize: "16px",
1268
+ padding: "8px 12px",
1269
+ minHeight: "40px"
1270
+ };
1271
+ }
1272
+ }
1273
+ /**
1274
+ * Render dropdown variant
1275
+ */
1276
+ renderDropdown() {
1277
+ const e = this.getSelectedOption(), t = this.getFilteredOptions(), i = this.getSizeStyles(), r = this.isOpen();
1278
+ return a(
1279
+ "div",
1280
+ {
1281
+ id: this.id,
1282
+ style: {
1283
+ position: "relative",
1284
+ display: "inline-block",
1285
+ minWidth: "200px"
1286
+ }
1287
+ },
1288
+ // Trigger button
1289
+ a(
1290
+ "button",
1291
+ {
1292
+ type: "button",
1293
+ onClick: this.toggleOpen,
1294
+ disabled: this.isDisabled(),
1295
+ style: {
1296
+ ...i,
1297
+ width: "100%",
1298
+ display: "flex",
1299
+ alignItems: "center",
1300
+ justifyContent: "space-between",
1301
+ backgroundColor: "#ffffff",
1302
+ border: "1px solid #d1d5db",
1303
+ borderRadius: "6px",
1304
+ cursor: this.isDisabled() ? "not-allowed" : "pointer",
1305
+ opacity: this.isDisabled() ? 0.6 : 1,
1306
+ ...r && {
1307
+ borderColor: this.props.tint || "#007AFF",
1308
+ boxShadow: `0 0 0 1px ${this.props.tint || "#007AFF"}`
1309
+ }
1310
+ }
1311
+ },
1312
+ a(
1313
+ "span",
1314
+ {
1315
+ style: {
1316
+ color: e ? "#1a1a1a" : "#6b7280"
1317
+ }
1318
+ },
1319
+ p(
1320
+ e?.label || this.props.placeholder || "Select an option"
1321
+ )
1322
+ ),
1323
+ a(
1324
+ "span",
1325
+ {
1326
+ style: {
1327
+ fontSize: "12px",
1328
+ color: "#6b7280",
1329
+ transform: r ? "rotate(180deg)" : "rotate(0deg)",
1330
+ transition: "transform 0.2s"
1331
+ }
1332
+ },
1333
+ p("▼")
1334
+ )
1335
+ ),
1336
+ ...r ? [
1337
+ a(
1338
+ "div",
1339
+ {
1340
+ style: {
1341
+ position: "absolute",
1342
+ top: "100%",
1343
+ left: "0",
1344
+ right: "0",
1345
+ zIndex: 1e3,
1346
+ backgroundColor: "#ffffff",
1347
+ border: "1px solid #d1d5db",
1348
+ borderRadius: "6px",
1349
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
1350
+ maxHeight: "200px",
1351
+ overflowY: "auto",
1352
+ marginTop: "2px"
1353
+ }
1354
+ },
1355
+ ...this.props.searchable ? [
1356
+ a(
1357
+ "div",
1358
+ {
1359
+ style: {
1360
+ padding: "8px",
1361
+ borderBottom: "1px solid #e5e7eb"
1362
+ }
1363
+ },
1364
+ a("input", {
1365
+ type: "text",
1366
+ placeholder: "Search options...",
1367
+ value: this.searchTerm(),
1368
+ onInput: (n) => {
1369
+ const o = n.target;
1370
+ this.setSearchTerm(o.value);
1371
+ },
1372
+ style: {
1373
+ width: "100%",
1374
+ padding: "6px 8px",
1375
+ border: "1px solid #d1d5db",
1376
+ borderRadius: "4px",
1377
+ fontSize: "14px"
1378
+ }
1379
+ })
1380
+ )
1381
+ ] : [],
1382
+ ...t.map(
1383
+ (n) => a(
1384
+ "button",
1385
+ {
1386
+ type: "button",
1387
+ key: String(n.value),
1388
+ onClick: () => this.handleSelection(n.value),
1389
+ disabled: n.disabled,
1390
+ style: {
1391
+ width: "100%",
1392
+ padding: "8px 12px",
1393
+ textAlign: "left",
1394
+ backgroundColor: n.value === this.getSelection() ? "#f3f4f6" : "transparent",
1395
+ border: "none",
1396
+ cursor: n.disabled ? "not-allowed" : "pointer",
1397
+ opacity: n.disabled ? 0.5 : 1,
1398
+ fontSize: "14px",
1399
+ display: "flex",
1400
+ alignItems: "center",
1401
+ gap: "8px",
1402
+ ":hover": {
1403
+ backgroundColor: "#f9fafb"
1404
+ }
1405
+ }
1406
+ },
1407
+ ...n.icon ? [
1408
+ a(
1409
+ "span",
1410
+ { style: { fontSize: "16px" } },
1411
+ p(n.icon)
1412
+ )
1413
+ ] : [],
1414
+ a(
1415
+ "div",
1416
+ {},
1417
+ a("div", {}, p(n.label)),
1418
+ ...n.description ? [
1419
+ a(
1420
+ "div",
1421
+ {
1422
+ style: {
1423
+ fontSize: "12px",
1424
+ color: "#6b7280",
1425
+ marginTop: "2px"
1426
+ }
1427
+ },
1428
+ p(n.description)
1429
+ )
1430
+ ] : []
1431
+ )
1432
+ )
1433
+ ),
1434
+ ...t.length === 0 ? [
1435
+ a(
1436
+ "div",
1437
+ {
1438
+ style: {
1439
+ padding: "12px",
1440
+ textAlign: "center",
1441
+ color: "#6b7280",
1442
+ fontSize: "14px"
1443
+ }
1444
+ },
1445
+ p("No options found")
1446
+ )
1447
+ ] : []
1448
+ )
1449
+ ] : []
1450
+ );
1451
+ }
1452
+ /**
1453
+ * Render segmented variant
1454
+ */
1455
+ renderSegmented() {
1456
+ const e = this.getOptions(), t = this.getSelection(), i = this.getSizeStyles();
1457
+ return a(
1458
+ "div",
1459
+ {
1460
+ style: {
1461
+ display: "flex",
1462
+ backgroundColor: "#f3f4f6",
1463
+ borderRadius: "8px",
1464
+ padding: "2px"
1465
+ },
1466
+ role: "radiogroup",
1467
+ "aria-label": this.props.accessibilityLabel
1468
+ },
1469
+ ...e.map(
1470
+ (r, n) => a(
1471
+ "button",
1472
+ {
1473
+ type: "button",
1474
+ key: String(r.value),
1475
+ onClick: () => this.handleSelection(r.value),
1476
+ disabled: r.disabled || this.isDisabled(),
1477
+ role: "radio",
1478
+ "aria-checked": r.value === t,
1479
+ style: {
1480
+ ...i,
1481
+ flex: 1,
1482
+ border: "none",
1483
+ borderRadius: "6px",
1484
+ backgroundColor: r.value === t ? "#ffffff" : "transparent",
1485
+ color: r.value === t ? "#1a1a1a" : "#6b7280",
1486
+ fontWeight: r.value === t ? "600" : "400",
1487
+ cursor: r.disabled || this.isDisabled() ? "not-allowed" : "pointer",
1488
+ opacity: r.disabled || this.isDisabled() ? 0.5 : 1,
1489
+ boxShadow: r.value === t ? "0 1px 2px rgba(0, 0, 0, 0.1)" : "none",
1490
+ transition: "all 0.2s",
1491
+ margin: "0",
1492
+ ...n === 0 && { marginRight: "1px" },
1493
+ ...n === e.length - 1 && { marginLeft: "1px" }
1494
+ }
1495
+ },
1496
+ ...r.icon ? [
1497
+ a(
1498
+ "span",
1499
+ {
1500
+ style: {
1501
+ marginRight: "6px",
1502
+ fontSize: "14px"
1503
+ }
1504
+ },
1505
+ p(r.icon)
1506
+ )
1507
+ ] : [],
1508
+ p(r.label)
1509
+ )
1510
+ )
1511
+ );
1512
+ }
1513
+ /**
1514
+ * Render wheel variant (simplified)
1515
+ */
1516
+ renderWheel() {
1517
+ const e = this.getOptions(), t = this.getSelection();
1518
+ return a(
1519
+ "select",
1520
+ {
1521
+ value: String(t),
1522
+ onChange: (i) => {
1523
+ const r = i.target, n = e.find(
1524
+ (o) => String(o.value) === r.value
1525
+ );
1526
+ n && this.handleSelection(n.value);
1527
+ },
1528
+ disabled: this.isDisabled(),
1529
+ style: {
1530
+ ...this.getSizeStyles(),
1531
+ minWidth: "200px",
1532
+ backgroundColor: "#ffffff",
1533
+ border: "1px solid #d1d5db",
1534
+ borderRadius: "6px",
1535
+ cursor: this.isDisabled() ? "not-allowed" : "pointer",
1536
+ opacity: this.isDisabled() ? 0.6 : 1
1537
+ }
1538
+ },
1539
+ ...e.map(
1540
+ (i) => a(
1541
+ "option",
1542
+ {
1543
+ key: String(i.value),
1544
+ value: String(i.value),
1545
+ disabled: i.disabled
1546
+ },
1547
+ p(i.label)
1548
+ )
1549
+ )
1550
+ );
1551
+ }
1552
+ render() {
1553
+ const {
1554
+ variant: e = "dropdown",
1555
+ accessibilityLabel: t,
1556
+ accessibilityHint: i
1557
+ } = this.props, r = {
1558
+ "aria-label": t,
1559
+ "aria-describedby": i ? `${this.id}-hint` : void 0
1560
+ };
1561
+ let n;
1562
+ switch (e) {
1563
+ case "segmented":
1564
+ n = this.renderSegmented();
1565
+ break;
1566
+ case "wheel":
1567
+ n = this.renderWheel();
1568
+ break;
1569
+ default:
1570
+ n = this.renderDropdown();
1571
+ break;
1572
+ }
1573
+ return a(
1574
+ "div",
1575
+ r,
1576
+ n,
1577
+ ...i ? [
1578
+ a(
1579
+ "div",
1580
+ {
1581
+ id: `${this.id}-hint`,
1582
+ style: {
1583
+ fontSize: "12px",
1584
+ color: "#6b7280",
1585
+ marginTop: "4px"
1586
+ }
1587
+ },
1588
+ p(i)
1589
+ )
1590
+ ] : []
1591
+ );
1592
+ }
1593
+ }
1594
+ function $(s, e, t = {}) {
1595
+ const i = { ...t, selection: s, options: e }, r = new de(i);
1596
+ return T(r);
1597
+ }
1598
+ const be = {
1599
+ /**
1600
+ * Dropdown picker (default)
1601
+ */
1602
+ // biome-ignore lint/suspicious/noExplicitAny: Generic dropdown picker requires flexible type
1603
+ Dropdown(s, e, t = {}) {
1604
+ return $(s, e, { ...t, variant: "dropdown" });
1605
+ },
1606
+ /**
1607
+ * Segmented picker
1608
+ */
1609
+ // biome-ignore lint/suspicious/noExplicitAny: Generic segmented picker requires flexible type
1610
+ Segmented(s, e, t = {}) {
1611
+ return $(s, e, { ...t, variant: "segmented" });
1612
+ },
1613
+ /**
1614
+ * Wheel picker (native select)
1615
+ */
1616
+ // biome-ignore lint/suspicious/noExplicitAny: Generic wheel picker requires flexible type
1617
+ Wheel(s, e, t = {}) {
1618
+ return $(s, e, { ...t, variant: "wheel" });
1619
+ },
1620
+ /**
1621
+ * Menu picker
1622
+ */
1623
+ // biome-ignore lint/suspicious/noExplicitAny: Generic menu picker requires flexible type
1624
+ Menu(s, e, t = {}) {
1625
+ return $(s, e, { ...t, variant: "menu" });
1626
+ }
1627
+ }, me = {
1628
+ /**
1629
+ * Create options from simple array
1630
+ */
1631
+ fromArray(s, e) {
1632
+ return s.map((t) => ({
1633
+ value: t,
1634
+ label: String(e && typeof t == "object" && t !== null ? t[e] : t)
1635
+ }));
1636
+ },
1637
+ /**
1638
+ * Create options from enum
1639
+ */
1640
+ fromEnum(s) {
1641
+ return Object.entries(s).map(([e, t]) => ({
1642
+ value: t,
1643
+ label: e.replace(/([A-Z])/g, " $1").trim()
1644
+ }));
1645
+ },
1646
+ /**
1647
+ * Group options by category
1648
+ */
1649
+ grouped(s) {
1650
+ return s.reduce(
1651
+ (e, t) => {
1652
+ const i = t.category || "Other";
1653
+ return e[i] || (e[i] = []), e[i].push(t), e;
1654
+ },
1655
+ {}
1656
+ );
1657
+ }
1658
+ };
1659
+ export {
1660
+ E as B,
1661
+ ee as E,
1662
+ ue as L,
1663
+ $ as P,
1664
+ m as T,
1665
+ he as a,
1666
+ x as b,
1667
+ oe as c,
1668
+ Q as d,
1669
+ fe as e,
1670
+ ge as f,
1671
+ N as g,
1672
+ de as h,
1673
+ be as i,
1674
+ me as j
1675
+ };