@hyperfixi/behaviors 2.0.0 → 2.1.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.
Files changed (189) hide show
  1. package/dist/all.browser.global.js +35 -6
  2. package/dist/all.browser.global.js.map +1 -1
  3. package/dist/autodismiss.browser.global.js +3 -0
  4. package/dist/autodismiss.browser.global.js.map +1 -0
  5. package/dist/behaviors/autodismiss.cjs +177 -0
  6. package/dist/behaviors/autodismiss.cjs.map +1 -0
  7. package/dist/behaviors/autodismiss.d.cts +15 -0
  8. package/dist/behaviors/autodismiss.d.ts +15 -0
  9. package/dist/behaviors/autodismiss.js +15 -0
  10. package/dist/behaviors/autodismiss.js.map +1 -0
  11. package/dist/behaviors/clickoutside.cjs +123 -0
  12. package/dist/behaviors/clickoutside.cjs.map +1 -0
  13. package/dist/behaviors/clickoutside.d.cts +15 -0
  14. package/dist/behaviors/clickoutside.d.ts +15 -0
  15. package/dist/behaviors/clickoutside.js +15 -0
  16. package/dist/behaviors/clickoutside.js.map +1 -0
  17. package/dist/behaviors/clipboard.cjs +193 -0
  18. package/dist/behaviors/clipboard.cjs.map +1 -0
  19. package/dist/behaviors/clipboard.d.cts +15 -0
  20. package/dist/behaviors/clipboard.d.ts +15 -0
  21. package/dist/behaviors/clipboard.js +15 -0
  22. package/dist/behaviors/clipboard.js.map +1 -0
  23. package/dist/behaviors/draggable.cjs +49 -7
  24. package/dist/behaviors/draggable.cjs.map +1 -1
  25. package/dist/behaviors/draggable.d.cts +2 -1
  26. package/dist/behaviors/draggable.d.ts +2 -1
  27. package/dist/behaviors/draggable.js +2 -1
  28. package/dist/behaviors/focustrap.cjs +191 -0
  29. package/dist/behaviors/focustrap.cjs.map +1 -0
  30. package/dist/behaviors/focustrap.d.cts +15 -0
  31. package/dist/behaviors/focustrap.d.ts +15 -0
  32. package/dist/behaviors/focustrap.js +15 -0
  33. package/dist/behaviors/focustrap.js.map +1 -0
  34. package/dist/behaviors/removable.cjs +9 -2
  35. package/dist/behaviors/removable.cjs.map +1 -1
  36. package/dist/behaviors/removable.d.cts +1 -1
  37. package/dist/behaviors/removable.d.ts +1 -1
  38. package/dist/behaviors/removable.js +2 -1
  39. package/dist/behaviors/resizable.cjs +54 -7
  40. package/dist/behaviors/resizable.cjs.map +1 -1
  41. package/dist/behaviors/resizable.d.cts +1 -1
  42. package/dist/behaviors/resizable.d.ts +1 -1
  43. package/dist/behaviors/resizable.js +2 -1
  44. package/dist/behaviors/scrollreveal.cjs +149 -0
  45. package/dist/behaviors/scrollreveal.cjs.map +1 -0
  46. package/dist/behaviors/scrollreveal.d.cts +15 -0
  47. package/dist/behaviors/scrollreveal.d.ts +15 -0
  48. package/dist/behaviors/scrollreveal.js +15 -0
  49. package/dist/behaviors/scrollreveal.js.map +1 -0
  50. package/dist/behaviors/sortable.cjs +49 -7
  51. package/dist/behaviors/sortable.cjs.map +1 -1
  52. package/dist/behaviors/sortable.d.cts +1 -1
  53. package/dist/behaviors/sortable.d.ts +1 -1
  54. package/dist/behaviors/sortable.js +2 -1
  55. package/dist/behaviors/tabs.cjs +247 -0
  56. package/dist/behaviors/tabs.cjs.map +1 -0
  57. package/dist/behaviors/tabs.d.cts +15 -0
  58. package/dist/behaviors/tabs.d.ts +15 -0
  59. package/dist/behaviors/tabs.js +15 -0
  60. package/dist/behaviors/tabs.js.map +1 -0
  61. package/dist/behaviors/toggleable.cjs +36 -7
  62. package/dist/behaviors/toggleable.cjs.map +1 -1
  63. package/dist/behaviors/toggleable.d.cts +2 -1
  64. package/dist/behaviors/toggleable.d.ts +2 -1
  65. package/dist/behaviors/toggleable.js +2 -1
  66. package/dist/chunk-244WSZOL.js +67 -0
  67. package/dist/chunk-244WSZOL.js.map +1 -0
  68. package/dist/chunk-2NSKQMNM.js +99 -0
  69. package/dist/chunk-2NSKQMNM.js.map +1 -0
  70. package/dist/chunk-64DIQGQI.js +37 -0
  71. package/dist/chunk-64DIQGQI.js.map +1 -0
  72. package/dist/chunk-6TJXDCAQ.js +11 -0
  73. package/dist/chunk-6TJXDCAQ.js.map +1 -0
  74. package/dist/chunk-7JDV2THA.js +62 -0
  75. package/dist/chunk-7JDV2THA.js.map +1 -0
  76. package/dist/chunk-AFGA54SA.js +116 -0
  77. package/dist/chunk-AFGA54SA.js.map +1 -0
  78. package/dist/chunk-DYHBKDKB.js +62 -0
  79. package/dist/chunk-DYHBKDKB.js.map +1 -0
  80. package/dist/chunk-GPTHAUWN.js +58 -0
  81. package/dist/chunk-GPTHAUWN.js.map +1 -0
  82. package/dist/chunk-GVJPA2EK.js +68 -0
  83. package/dist/chunk-GVJPA2EK.js.map +1 -0
  84. package/dist/chunk-H2MCHR5A.js +89 -0
  85. package/dist/chunk-H2MCHR5A.js.map +1 -0
  86. package/dist/{chunk-2NQHIHD5.js → chunk-H5Y5ARYG.js} +6 -3
  87. package/dist/chunk-H5Y5ARYG.js.map +1 -0
  88. package/dist/chunk-JKBWIJFI.js +155 -0
  89. package/dist/chunk-JKBWIJFI.js.map +1 -0
  90. package/dist/chunk-QKDYW4VM.js +70 -0
  91. package/dist/chunk-QKDYW4VM.js.map +1 -0
  92. package/dist/chunk-RB7OB6OD.js +51 -0
  93. package/dist/chunk-RB7OB6OD.js.map +1 -0
  94. package/dist/chunk-RPERQTFU.js +75 -0
  95. package/dist/chunk-RPERQTFU.js.map +1 -0
  96. package/dist/chunk-S4QDV2MH.js +75 -0
  97. package/dist/chunk-S4QDV2MH.js.map +1 -0
  98. package/dist/chunk-WTUVPVSD.js +80 -0
  99. package/dist/chunk-WTUVPVSD.js.map +1 -0
  100. package/dist/chunk-YHQRFUWV.js +62 -0
  101. package/dist/chunk-YHQRFUWV.js.map +1 -0
  102. package/dist/chunk-ZQQZTMCJ.js +64 -0
  103. package/dist/chunk-ZQQZTMCJ.js.map +1 -0
  104. package/dist/clickoutside.browser.global.js +12 -0
  105. package/dist/clickoutside.browser.global.js.map +1 -0
  106. package/dist/clipboard.browser.global.js +3 -0
  107. package/dist/clipboard.browser.global.js.map +1 -0
  108. package/dist/core.browser.global.js +3 -3
  109. package/dist/core.browser.global.js.map +1 -1
  110. package/dist/draggable.browser.global.js +2 -2
  111. package/dist/draggable.browser.global.js.map +1 -1
  112. package/dist/focustrap.browser.global.js +9 -0
  113. package/dist/focustrap.browser.global.js.map +1 -0
  114. package/dist/index.cjs +1270 -50
  115. package/dist/index.cjs.map +1 -1
  116. package/dist/index.d.cts +13 -7
  117. package/dist/index.d.ts +13 -7
  118. package/dist/index.js +155 -48
  119. package/dist/index.js.map +1 -1
  120. package/dist/loaders.cjs +1151 -30
  121. package/dist/loaders.cjs.map +1 -1
  122. package/dist/loaders.js +9 -3
  123. package/dist/registry.d.cts +1 -1
  124. package/dist/registry.d.ts +1 -1
  125. package/dist/removable.browser.global.js +2 -2
  126. package/dist/removable.browser.global.js.map +1 -1
  127. package/dist/resizable.browser.global.js +2 -2
  128. package/dist/resizable.browser.global.js.map +1 -1
  129. package/dist/schemas/index.cjs +343 -1
  130. package/dist/schemas/index.cjs.map +1 -1
  131. package/dist/schemas/index.d.cts +45 -3
  132. package/dist/schemas/index.d.ts +45 -3
  133. package/dist/schemas/index.js +34 -4
  134. package/dist/schemas/index.js.map +1 -1
  135. package/dist/scrollreveal.browser.global.js +11 -0
  136. package/dist/scrollreveal.browser.global.js.map +1 -0
  137. package/dist/sortable.browser.global.js +2 -2
  138. package/dist/sortable.browser.global.js.map +1 -1
  139. package/dist/tabs.browser.global.js +3 -0
  140. package/dist/tabs.browser.global.js.map +1 -0
  141. package/dist/toggleable.browser.global.js +2 -2
  142. package/dist/toggleable.browser.global.js.map +1 -1
  143. package/dist/{types-CCc_2wAb.d.cts → types-DCCtVQS5.d.cts} +1 -1
  144. package/dist/{types-CCc_2wAb.d.ts → types-DCCtVQS5.d.ts} +1 -1
  145. package/package.json +45 -2
  146. package/src/behaviors/autodismiss.test.ts +61 -0
  147. package/src/behaviors/autodismiss.ts +107 -0
  148. package/src/behaviors/clickoutside.test.ts +52 -0
  149. package/src/behaviors/clickoutside.ts +77 -0
  150. package/src/behaviors/clipboard.test.ts +67 -0
  151. package/src/behaviors/clipboard.ts +130 -0
  152. package/src/behaviors/draggable.ts +62 -15
  153. package/src/behaviors/focustrap.test.ts +59 -0
  154. package/src/behaviors/focustrap.ts +158 -0
  155. package/src/behaviors/index.ts +37 -0
  156. package/src/behaviors/integration.test.ts +120 -45
  157. package/src/behaviors/removable.ts +4 -5
  158. package/src/behaviors/resizable.ts +63 -14
  159. package/src/behaviors/scrollreveal.test.ts +59 -0
  160. package/src/behaviors/scrollreveal.ts +78 -0
  161. package/src/behaviors/sortable.ts +61 -14
  162. package/src/behaviors/tabs.test.ts +81 -0
  163. package/src/behaviors/tabs.ts +196 -0
  164. package/src/behaviors/toggleable.ts +45 -13
  165. package/src/generated/metadata.ts +38 -7
  166. package/src/generated/types.ts +5 -5
  167. package/src/index.test.ts +143 -5
  168. package/src/index.ts +65 -13
  169. package/src/loaders.ts +18 -0
  170. package/src/registry.test.ts +26 -5
  171. package/src/schemas/autodismiss.schema.ts +66 -0
  172. package/src/schemas/clickoutside.schema.ts +39 -0
  173. package/src/schemas/clipboard.schema.ts +72 -0
  174. package/src/schemas/focustrap.schema.ts +53 -0
  175. package/src/schemas/index.ts +18 -0
  176. package/src/schemas/scrollreveal.schema.ts +60 -0
  177. package/src/schemas/tabs.schema.ts +66 -0
  178. package/src/schemas/types.ts +13 -1
  179. package/dist/chunk-2NQHIHD5.js.map +0 -1
  180. package/dist/chunk-3Q652JQB.js +0 -37
  181. package/dist/chunk-3Q652JQB.js.map +0 -1
  182. package/dist/chunk-HMRPQWQU.js +0 -37
  183. package/dist/chunk-HMRPQWQU.js.map +0 -1
  184. package/dist/chunk-MEP6B7XW.js +0 -37
  185. package/dist/chunk-MEP6B7XW.js.map +0 -1
  186. package/dist/chunk-URBOGGW6.js +0 -32
  187. package/dist/chunk-URBOGGW6.js.map +0 -1
  188. package/dist/chunk-WU37DFAL.js +0 -37
  189. package/dist/chunk-WU37DFAL.js.map +0 -1
package/dist/loaders.cjs CHANGED
@@ -333,6 +333,378 @@ end
333
333
  }
334
334
  });
335
335
 
336
+ // src/schemas/clipboard.schema.ts
337
+ var clipboardSchema;
338
+ var init_clipboard_schema = __esm({
339
+ "src/schemas/clipboard.schema.ts"() {
340
+ "use strict";
341
+ clipboardSchema = {
342
+ name: "Clipboard",
343
+ category: "ui",
344
+ tier: "core",
345
+ version: "1.0.0",
346
+ description: "Copies text to clipboard on click with visual feedback",
347
+ parameters: [
348
+ {
349
+ name: "text",
350
+ type: "string",
351
+ optional: true,
352
+ description: "Literal text to copy (takes priority over source)"
353
+ },
354
+ {
355
+ name: "source",
356
+ type: "selector",
357
+ optional: true,
358
+ default: "me",
359
+ description: "Element whose textContent or value is copied"
360
+ },
361
+ {
362
+ name: "feedback",
363
+ type: "selector",
364
+ optional: true,
365
+ description: "Element to show .copied feedback on (defaults to the installed element)"
366
+ },
367
+ {
368
+ name: "feedbackDuration",
369
+ type: "number",
370
+ optional: true,
371
+ default: 2e3,
372
+ description: "Duration in ms to show .copied class feedback"
373
+ }
374
+ ],
375
+ events: [
376
+ { name: "clipboard:copied", description: "Fired after text is copied successfully" },
377
+ { name: "clipboard:error", description: "Fired when clipboard write fails" }
378
+ ],
379
+ requirements: [
380
+ "navigator.clipboard.writeText() requires HTTPS or localhost",
381
+ 'Falls back to document.execCommand("copy") for older browsers'
382
+ ],
383
+ source: [
384
+ "behavior Clipboard(text, source, feedback, feedbackDuration)",
385
+ " init",
386
+ " if feedbackDuration is undefined set feedbackDuration to 2000",
387
+ " if source is undefined set source to me",
388
+ " end",
389
+ " on click",
390
+ " if text is not undefined",
391
+ " set copyText to text",
392
+ " else",
393
+ " set copyText to source's value or source's textContent",
394
+ " end",
395
+ " js(copyText) navigator.clipboard.writeText(copyText) end",
396
+ " set feedbackEl to feedback or me",
397
+ " add .copied to feedbackEl",
398
+ " wait feedbackDuration ms",
399
+ " remove .copied from feedbackEl",
400
+ " trigger clipboard:copied",
401
+ " end",
402
+ "end"
403
+ ].join("\n")
404
+ };
405
+ }
406
+ });
407
+
408
+ // src/schemas/autodismiss.schema.ts
409
+ var autoDismissSchema;
410
+ var init_autodismiss_schema = __esm({
411
+ "src/schemas/autodismiss.schema.ts"() {
412
+ "use strict";
413
+ autoDismissSchema = {
414
+ name: "AutoDismiss",
415
+ category: "ui",
416
+ tier: "core",
417
+ version: "1.0.0",
418
+ description: "Auto-removes elements after a delay with optional pause-on-hover",
419
+ parameters: [
420
+ {
421
+ name: "delay",
422
+ type: "number",
423
+ optional: true,
424
+ default: 5e3,
425
+ description: "Time in ms before the element is removed"
426
+ },
427
+ {
428
+ name: "pauseOnHover",
429
+ type: "boolean",
430
+ optional: true,
431
+ default: true,
432
+ description: "Pause the countdown when the mouse hovers over the element"
433
+ },
434
+ {
435
+ name: "effect",
436
+ type: "string",
437
+ optional: true,
438
+ default: "none",
439
+ enum: ["fade", "none"],
440
+ description: 'Transition effect before removal: "fade" or "none"'
441
+ }
442
+ ],
443
+ events: [
444
+ { name: "autodismiss:start", description: "Fired when the countdown timer starts" },
445
+ {
446
+ name: "autodismiss:dismissed",
447
+ description: "Fired before removal (cancelable via preventDefault)"
448
+ },
449
+ { name: "autodismiss:paused", description: "Fired when the timer is paused on hover" },
450
+ { name: "autodismiss:resumed", description: "Fired when the timer resumes on mouseleave" }
451
+ ],
452
+ source: [
453
+ "behavior AutoDismiss(delay, pauseOnHover, effect)",
454
+ " init",
455
+ " if delay is undefined set delay to 5000",
456
+ " if pauseOnHover is undefined set pauseOnHover to true",
457
+ ' if effect is undefined set effect to "none"',
458
+ " end",
459
+ " on load",
460
+ " trigger autodismiss:start",
461
+ " wait delay ms",
462
+ " trigger autodismiss:dismissed",
463
+ ' if effect is "fade"',
464
+ " transition opacity to 0 over 300ms",
465
+ " end",
466
+ " remove me",
467
+ " end",
468
+ "end"
469
+ ].join("\n")
470
+ };
471
+ }
472
+ });
473
+
474
+ // src/schemas/clickoutside.schema.ts
475
+ var clickOutsideSchema;
476
+ var init_clickoutside_schema = __esm({
477
+ "src/schemas/clickoutside.schema.ts"() {
478
+ "use strict";
479
+ clickOutsideSchema = {
480
+ name: "ClickOutside",
481
+ category: "ui",
482
+ tier: "core",
483
+ version: "1.0.0",
484
+ description: "Fires an event when the user clicks outside the element",
485
+ parameters: [
486
+ {
487
+ name: "active",
488
+ type: "boolean",
489
+ optional: true,
490
+ default: true,
491
+ description: "Whether the listener is active (can be toggled programmatically)"
492
+ }
493
+ ],
494
+ events: [
495
+ { name: "clickoutside", description: "Fired when a pointer press occurs outside the element" }
496
+ ],
497
+ requirements: ["Uses pointerdown instead of click to avoid timing issues with removed elements"],
498
+ source: `
499
+ behavior ClickOutside(active)
500
+ init
501
+ if active is undefined set active to true
502
+ end
503
+ on pointerdown from document
504
+ if active and not me.contains(event.target)
505
+ trigger clickoutside on me
506
+ end
507
+ end
508
+ end`.trim()
509
+ };
510
+ }
511
+ });
512
+
513
+ // src/schemas/focustrap.schema.ts
514
+ var focusTrapSchema;
515
+ var init_focustrap_schema = __esm({
516
+ "src/schemas/focustrap.schema.ts"() {
517
+ "use strict";
518
+ focusTrapSchema = {
519
+ name: "FocusTrap",
520
+ category: "ui",
521
+ tier: "core",
522
+ version: "1.0.0",
523
+ description: "Confines Tab navigation inside an element with ARIA support",
524
+ parameters: [
525
+ {
526
+ name: "active",
527
+ type: "boolean",
528
+ optional: true,
529
+ default: true,
530
+ description: "Whether the trap is active on install"
531
+ },
532
+ {
533
+ name: "initialFocus",
534
+ type: "selector",
535
+ optional: true,
536
+ description: "Element to focus when the trap activates"
537
+ },
538
+ {
539
+ name: "returnFocus",
540
+ type: "boolean",
541
+ optional: true,
542
+ default: true,
543
+ description: "Restore focus to the previously focused element on deactivation"
544
+ }
545
+ ],
546
+ events: [
547
+ { name: "focustrap:activated", description: "Fired when the trap is activated" },
548
+ { name: "focustrap:deactivated", description: "Fired when the trap is deactivated" }
549
+ ],
550
+ requirements: [
551
+ 'Sets aria-modal="true" on the element when active',
552
+ "Listens for focustrap:activate and focustrap:deactivate custom events for programmatic control"
553
+ ],
554
+ source: `
555
+ behavior FocusTrap(active, initialFocus, returnFocus)
556
+ init
557
+ if active is undefined set active to true
558
+ if returnFocus is undefined set returnFocus to true
559
+ end
560
+ -- Imperative installer handles Tab key trapping and focus management
561
+ end`.trim()
562
+ };
563
+ }
564
+ });
565
+
566
+ // src/schemas/scrollreveal.schema.ts
567
+ var scrollRevealSchema;
568
+ var init_scrollreveal_schema = __esm({
569
+ "src/schemas/scrollreveal.schema.ts"() {
570
+ "use strict";
571
+ scrollRevealSchema = {
572
+ name: "ScrollReveal",
573
+ category: "layout",
574
+ tier: "common",
575
+ version: "1.0.0",
576
+ description: "Adds a class when the element enters the viewport via IntersectionObserver",
577
+ parameters: [
578
+ {
579
+ name: "cls",
580
+ type: "string",
581
+ optional: true,
582
+ default: "revealed",
583
+ description: "CSS class added when element enters viewport"
584
+ },
585
+ {
586
+ name: "threshold",
587
+ type: "number",
588
+ optional: true,
589
+ default: 0.1,
590
+ description: "Intersection ratio threshold (0-1) for triggering"
591
+ },
592
+ {
593
+ name: "once",
594
+ type: "boolean",
595
+ optional: true,
596
+ default: true,
597
+ description: "If true, disconnect observer after first intersection"
598
+ },
599
+ {
600
+ name: "rootMargin",
601
+ type: "string",
602
+ optional: true,
603
+ default: "0px",
604
+ description: "CSS margin around the viewport for triggering earlier or later"
605
+ }
606
+ ],
607
+ events: [
608
+ { name: "scrollreveal:enter", description: "Fired when the element enters the viewport" },
609
+ { name: "scrollreveal:exit", description: "Fired when the element exits the viewport" }
610
+ ],
611
+ requirements: ["Uses IntersectionObserver API (supported in all modern browsers)"],
612
+ source: `
613
+ behavior ScrollReveal(cls, threshold, once, rootMargin)
614
+ init
615
+ if cls is undefined set cls to "revealed"
616
+ if threshold is undefined set threshold to 0.1
617
+ if once is undefined set once to true
618
+ if rootMargin is undefined set rootMargin to "0px"
619
+ end
620
+ -- Imperative installer handles IntersectionObserver setup
621
+ end`.trim()
622
+ };
623
+ }
624
+ });
625
+
626
+ // src/schemas/tabs.schema.ts
627
+ var tabsSchema;
628
+ var init_tabs_schema = __esm({
629
+ "src/schemas/tabs.schema.ts"() {
630
+ "use strict";
631
+ tabsSchema = {
632
+ name: "Tabs",
633
+ category: "ui",
634
+ tier: "core",
635
+ version: "1.0.0",
636
+ description: "WAI-ARIA compliant tabs with roving tabindex keyboard navigation. Auto-wires role, aria-selected, aria-controls, and aria-labelledby attributes.",
637
+ parameters: [
638
+ {
639
+ name: "orientation",
640
+ type: "string",
641
+ optional: true,
642
+ default: "horizontal",
643
+ enum: ["horizontal", "vertical"],
644
+ description: "Arrow key direction: horizontal (Left/Right) or vertical (Up/Down)"
645
+ },
646
+ {
647
+ name: "activeTab",
648
+ type: "number",
649
+ optional: true,
650
+ default: 0,
651
+ description: "Initial active tab index (zero-based)"
652
+ },
653
+ {
654
+ name: "wrap",
655
+ type: "boolean",
656
+ optional: true,
657
+ default: true,
658
+ description: "Wrap to first/last tab when navigating past the end"
659
+ },
660
+ {
661
+ name: "activeClass",
662
+ type: "string",
663
+ optional: true,
664
+ default: "active",
665
+ description: "CSS class applied to the active tab and its panel"
666
+ }
667
+ ],
668
+ events: [
669
+ {
670
+ name: "tabs:change",
671
+ description: "Fired before tab selection changes (cancelable via preventDefault)"
672
+ },
673
+ { name: "tabs:changed", description: "Fired after tab selection has changed" }
674
+ ],
675
+ requirements: [
676
+ 'Sets role="tablist" on the tab container',
677
+ 'Sets role="tab" on tab buttons and role="tabpanel" on content panels',
678
+ "Manages aria-selected, aria-controls, aria-labelledby, and tabindex",
679
+ "Keyboard: Arrow keys navigate, Home/End jump to first/last, Tab exits tablist"
680
+ ],
681
+ source: [
682
+ "behavior Tabs(orientation, activeTab, wrap, activeClass)",
683
+ " init",
684
+ ' if orientation is undefined set orientation to "horizontal"',
685
+ " if activeTab is undefined set activeTab to 0",
686
+ " if wrap is undefined set wrap to true",
687
+ ' if activeClass is undefined set activeClass to "active"',
688
+ " end",
689
+ " -- Imperative installer handles ARIA wiring and keyboard navigation",
690
+ "end"
691
+ ].join("\n")
692
+ };
693
+ }
694
+ });
695
+
696
+ // src/schemas/types.ts
697
+ function resolveRuntime() {
698
+ if (typeof window === "undefined") return null;
699
+ const win = window;
700
+ return win.lokascript || win.hyperfixi || null;
701
+ }
702
+ var init_types = __esm({
703
+ "src/schemas/types.ts"() {
704
+ "use strict";
705
+ }
706
+ });
707
+
336
708
  // src/behaviors/draggable.ts
337
709
  var draggable_exports = {};
338
710
  __export(draggable_exports, {
@@ -341,28 +713,64 @@ __export(draggable_exports, {
341
713
  draggableSource: () => draggableSource,
342
714
  registerDraggable: () => registerDraggable
343
715
  });
716
+ function installDraggable(element, params) {
717
+ let dragHandle = element;
718
+ if (params.dragHandle && params.dragHandle !== "me") {
719
+ if (typeof params.dragHandle === "string") {
720
+ const found = element.querySelector(params.dragHandle);
721
+ if (found instanceof HTMLElement) dragHandle = found;
722
+ } else if (params.dragHandle instanceof HTMLElement) {
723
+ dragHandle = params.dragHandle;
724
+ }
725
+ }
726
+ dragHandle.addEventListener("pointerdown", (e) => {
727
+ e.preventDefault();
728
+ e.stopPropagation();
729
+ element.dispatchEvent(new CustomEvent("draggable:start", { bubbles: true }));
730
+ const startX = element.offsetLeft;
731
+ const startY = element.offsetTop;
732
+ const xoff = e.clientX - startX;
733
+ const yoff = e.clientY - startY;
734
+ function onMove(ev) {
735
+ element.style.left = `${ev.clientX - xoff}px`;
736
+ element.style.top = `${ev.clientY - yoff}px`;
737
+ element.dispatchEvent(new CustomEvent("draggable:move", { bubbles: true }));
738
+ }
739
+ function onUp() {
740
+ document.removeEventListener("pointermove", onMove);
741
+ document.removeEventListener("pointerup", onUp);
742
+ element.dispatchEvent(new CustomEvent("draggable:end", { bubbles: true }));
743
+ }
744
+ document.addEventListener("pointermove", onMove);
745
+ document.addEventListener("pointerup", onUp);
746
+ });
747
+ }
344
748
  async function registerDraggable(hyperfixi) {
345
- const hf = hyperfixi || (typeof window !== "undefined" ? window.lokascript : null);
749
+ const hf = hyperfixi || resolveRuntime();
346
750
  if (!hf) {
347
751
  throw new Error(
348
752
  "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
349
753
  );
350
754
  }
351
- const result = hf.compileSync(draggableSchema.source, { traditional: true });
352
- if (!result.ok) {
353
- throw new Error(`Failed to compile Draggable behavior: ${JSON.stringify(result.errors)}`);
354
- }
755
+ const syntheticNode = {
756
+ type: "behavior",
757
+ name: "Draggable",
758
+ parameters: ["dragHandle"],
759
+ eventHandlers: [],
760
+ imperativeInstaller: installDraggable
761
+ };
355
762
  const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
356
- await hf.execute(result.ast, ctx);
763
+ await hf.execute(syntheticNode, ctx);
357
764
  }
358
765
  var draggableSource, draggableMetadata, draggable_default;
359
766
  var init_draggable = __esm({
360
767
  "src/behaviors/draggable.ts"() {
361
768
  "use strict";
362
769
  init_draggable_schema();
770
+ init_types();
363
771
  draggableSource = draggableSchema.source;
364
772
  draggableMetadata = draggableSchema;
365
- if (typeof window !== "undefined" && window.lokascript) {
773
+ if (resolveRuntime()) {
366
774
  registerDraggable().catch(console.error);
367
775
  }
368
776
  draggable_default = {
@@ -381,28 +789,64 @@ __export(sortable_exports, {
381
789
  sortableMetadata: () => sortableMetadata,
382
790
  sortableSource: () => sortableSource
383
791
  });
792
+ function installSortable(element, params) {
793
+ const dragClass = params.dragClass || "sorting";
794
+ const handleSelector = params.handle || null;
795
+ element.addEventListener("pointerdown", (e) => {
796
+ const target = e.target;
797
+ const item = target.closest("li");
798
+ if (!item || !element.contains(item)) return;
799
+ if (handleSelector) {
800
+ const handleEl = target.closest(handleSelector);
801
+ if (!handleEl) return;
802
+ }
803
+ e.preventDefault();
804
+ item.classList.add(dragClass);
805
+ element.dispatchEvent(new CustomEvent("sortable:start", { bubbles: true, detail: { item } }));
806
+ function onMove(ev) {
807
+ element.dispatchEvent(
808
+ new CustomEvent("sortable:move", {
809
+ bubbles: true,
810
+ detail: { clientY: ev.clientY, item }
811
+ })
812
+ );
813
+ }
814
+ function onUp() {
815
+ document.removeEventListener("pointermove", onMove);
816
+ document.removeEventListener("pointerup", onUp);
817
+ item.classList.remove(dragClass);
818
+ element.dispatchEvent(new CustomEvent("sortable:end", { bubbles: true, detail: { item } }));
819
+ }
820
+ document.addEventListener("pointermove", onMove);
821
+ document.addEventListener("pointerup", onUp);
822
+ });
823
+ }
384
824
  async function registerSortable(hyperfixi) {
385
- const hf = hyperfixi || (typeof window !== "undefined" ? window.lokascript : null);
825
+ const hf = hyperfixi || resolveRuntime();
386
826
  if (!hf) {
387
827
  throw new Error(
388
828
  "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
389
829
  );
390
830
  }
391
- const result = hf.compileSync(sortableSchema.source, { traditional: true });
392
- if (!result.ok) {
393
- throw new Error(`Failed to compile Sortable behavior: ${JSON.stringify(result.errors)}`);
394
- }
831
+ const syntheticNode = {
832
+ type: "behavior",
833
+ name: "Sortable",
834
+ parameters: ["handle", "dragClass"],
835
+ eventHandlers: [],
836
+ imperativeInstaller: installSortable
837
+ };
395
838
  const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
396
- await hf.execute(result.ast, ctx);
839
+ await hf.execute(syntheticNode, ctx);
397
840
  }
398
841
  var sortableSource, sortableMetadata, sortable_default;
399
842
  var init_sortable = __esm({
400
843
  "src/behaviors/sortable.ts"() {
401
844
  "use strict";
402
845
  init_sortable_schema();
846
+ init_types();
403
847
  sortableSource = sortableSchema.source;
404
848
  sortableMetadata = sortableSchema;
405
- if (typeof window !== "undefined" && window.lokascript) {
849
+ if (resolveRuntime()) {
406
850
  registerSortable().catch(console.error);
407
851
  }
408
852
  sortable_default = {
@@ -421,28 +865,69 @@ __export(resizable_exports, {
421
865
  resizableMetadata: () => resizableMetadata,
422
866
  resizableSource: () => resizableSource
423
867
  });
868
+ function installResizable(element, params) {
869
+ let handleEl = element;
870
+ if (params.handle && params.handle !== "me") {
871
+ if (typeof params.handle === "string") {
872
+ const found = element.querySelector(params.handle);
873
+ if (found instanceof HTMLElement) handleEl = found;
874
+ } else if (params.handle instanceof HTMLElement) {
875
+ handleEl = params.handle;
876
+ }
877
+ }
878
+ const minW = params.minWidth ?? 50;
879
+ const minH = params.minHeight ?? 50;
880
+ const maxW = params.maxWidth ?? 9999;
881
+ const maxH = params.maxHeight ?? 9999;
882
+ handleEl.addEventListener("pointerdown", (e) => {
883
+ e.preventDefault();
884
+ element.dispatchEvent(new CustomEvent("resizable:start", { bubbles: true }));
885
+ const startWidth = element.offsetWidth;
886
+ const startHeight = element.offsetHeight;
887
+ const startX = e.clientX;
888
+ const startY = e.clientY;
889
+ function onMove(ev) {
890
+ const newWidth = Math.max(minW, Math.min(maxW, startWidth + (ev.clientX - startX)));
891
+ const newHeight = Math.max(minH, Math.min(maxH, startHeight + (ev.clientY - startY)));
892
+ element.style.width = `${newWidth}px`;
893
+ element.style.height = `${newHeight}px`;
894
+ element.dispatchEvent(new CustomEvent("resizable:resize", { bubbles: true }));
895
+ }
896
+ function onUp() {
897
+ document.removeEventListener("pointermove", onMove);
898
+ document.removeEventListener("pointerup", onUp);
899
+ element.dispatchEvent(new CustomEvent("resizable:end", { bubbles: true }));
900
+ }
901
+ document.addEventListener("pointermove", onMove);
902
+ document.addEventListener("pointerup", onUp);
903
+ });
904
+ }
424
905
  async function registerResizable(hyperfixi) {
425
- const hf = hyperfixi || (typeof window !== "undefined" ? window.lokascript : null);
906
+ const hf = hyperfixi || resolveRuntime();
426
907
  if (!hf) {
427
908
  throw new Error(
428
909
  "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
429
910
  );
430
911
  }
431
- const result = hf.compileSync(resizableSchema.source, { traditional: true });
432
- if (!result.ok) {
433
- throw new Error(`Failed to compile Resizable behavior: ${JSON.stringify(result.errors)}`);
434
- }
912
+ const syntheticNode = {
913
+ type: "behavior",
914
+ name: "Resizable",
915
+ parameters: ["handle", "minWidth", "minHeight", "maxWidth", "maxHeight"],
916
+ eventHandlers: [],
917
+ imperativeInstaller: installResizable
918
+ };
435
919
  const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
436
- await hf.execute(result.ast, ctx);
920
+ await hf.execute(syntheticNode, ctx);
437
921
  }
438
922
  var resizableSource, resizableMetadata, resizable_default;
439
923
  var init_resizable = __esm({
440
924
  "src/behaviors/resizable.ts"() {
441
925
  "use strict";
442
926
  init_resizable_schema();
927
+ init_types();
443
928
  resizableSource = resizableSchema.source;
444
929
  resizableMetadata = resizableSchema;
445
- if (typeof window !== "undefined" && window.lokascript) {
930
+ if (resolveRuntime()) {
446
931
  registerResizable().catch(console.error);
447
932
  }
448
933
  resizable_default = {
@@ -462,7 +947,7 @@ __export(removable_exports, {
462
947
  removableSource: () => removableSource
463
948
  });
464
949
  async function registerRemovable(hyperfixi) {
465
- const hf = hyperfixi || (typeof window !== "undefined" ? window.lokascript : null);
950
+ const hf = hyperfixi || resolveRuntime();
466
951
  if (!hf) {
467
952
  throw new Error(
468
953
  "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
@@ -480,9 +965,10 @@ var init_removable = __esm({
480
965
  "src/behaviors/removable.ts"() {
481
966
  "use strict";
482
967
  init_removable_schema();
968
+ init_types();
483
969
  removableSource = removableSchema.source;
484
970
  removableMetadata = removableSchema;
485
- if (typeof window !== "undefined" && window.lokascript) {
971
+ if (resolveRuntime()) {
486
972
  registerRemovable().catch(console.error);
487
973
  }
488
974
  removable_default = {
@@ -501,28 +987,51 @@ __export(toggleable_exports, {
501
987
  toggleableMetadata: () => toggleableMetadata,
502
988
  toggleableSource: () => toggleableSource
503
989
  });
990
+ function installToggleable(element, params) {
991
+ const cls = params.cls || "active";
992
+ let targetEl = element;
993
+ if (params.target && params.target !== "me") {
994
+ if (typeof params.target === "string") {
995
+ const found = document.querySelector(params.target);
996
+ if (found instanceof HTMLElement) targetEl = found;
997
+ } else if (params.target instanceof HTMLElement) {
998
+ targetEl = params.target;
999
+ }
1000
+ }
1001
+ element.addEventListener("click", () => {
1002
+ const wasOn = targetEl.classList.contains(cls);
1003
+ targetEl.classList.toggle(cls);
1004
+ targetEl.dispatchEvent(
1005
+ new CustomEvent(wasOn ? "toggleable:off" : "toggleable:on", { bubbles: true })
1006
+ );
1007
+ });
1008
+ }
504
1009
  async function registerToggleable(hyperfixi) {
505
- const hf = hyperfixi || (typeof window !== "undefined" ? window.lokascript : null);
1010
+ const hf = hyperfixi || resolveRuntime();
506
1011
  if (!hf) {
507
1012
  throw new Error(
508
1013
  "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
509
1014
  );
510
1015
  }
511
- const result = hf.compileSync(toggleableSchema.source, { traditional: true });
512
- if (!result.ok) {
513
- throw new Error(`Failed to compile Toggleable behavior: ${JSON.stringify(result.errors)}`);
514
- }
1016
+ const syntheticNode = {
1017
+ type: "behavior",
1018
+ name: "Toggleable",
1019
+ parameters: ["cls", "target"],
1020
+ eventHandlers: [],
1021
+ imperativeInstaller: installToggleable
1022
+ };
515
1023
  const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
516
- await hf.execute(result.ast, ctx);
1024
+ await hf.execute(syntheticNode, ctx);
517
1025
  }
518
1026
  var toggleableSource, toggleableMetadata, toggleable_default;
519
1027
  var init_toggleable = __esm({
520
1028
  "src/behaviors/toggleable.ts"() {
521
1029
  "use strict";
522
1030
  init_toggleable_schema();
1031
+ init_types();
523
1032
  toggleableSource = toggleableSchema.source;
524
1033
  toggleableMetadata = toggleableSchema;
525
- if (typeof window !== "undefined" && window.lokascript) {
1034
+ if (resolveRuntime()) {
526
1035
  registerToggleable().catch(console.error);
527
1036
  }
528
1037
  toggleable_default = {
@@ -533,6 +1042,600 @@ var init_toggleable = __esm({
533
1042
  }
534
1043
  });
535
1044
 
1045
+ // src/behaviors/clipboard.ts
1046
+ var clipboard_exports = {};
1047
+ __export(clipboard_exports, {
1048
+ clipboardMetadata: () => clipboardMetadata,
1049
+ clipboardSource: () => clipboardSource,
1050
+ default: () => clipboard_default,
1051
+ registerClipboard: () => registerClipboard
1052
+ });
1053
+ async function copyToClipboard(text) {
1054
+ if (navigator.clipboard?.writeText) {
1055
+ await navigator.clipboard.writeText(text);
1056
+ return;
1057
+ }
1058
+ const textarea = document.createElement("textarea");
1059
+ textarea.value = text;
1060
+ textarea.style.position = "fixed";
1061
+ textarea.style.opacity = "0";
1062
+ document.body.appendChild(textarea);
1063
+ textarea.select();
1064
+ try {
1065
+ document.execCommand("copy");
1066
+ } finally {
1067
+ document.body.removeChild(textarea);
1068
+ }
1069
+ }
1070
+ function resolveElement(element, param) {
1071
+ if (!param || param === "me") return element;
1072
+ if (param instanceof HTMLElement) return param;
1073
+ if (typeof param === "string") {
1074
+ return element.querySelector(param) || document.querySelector(param) || null;
1075
+ }
1076
+ return null;
1077
+ }
1078
+ function installClipboard(element, params) {
1079
+ const feedbackDuration = typeof params.feedbackDuration === "number" ? params.feedbackDuration : 2e3;
1080
+ element.addEventListener("click", async () => {
1081
+ let copyText;
1082
+ if (params.text != null) {
1083
+ copyText = String(params.text);
1084
+ } else {
1085
+ const sourceEl = resolveElement(element, params.source) || element;
1086
+ copyText = sourceEl.value ?? sourceEl.textContent ?? "";
1087
+ }
1088
+ try {
1089
+ await copyToClipboard(copyText);
1090
+ const feedbackEl = resolveElement(element, params.feedback) || element;
1091
+ feedbackEl.classList.add("copied");
1092
+ setTimeout(() => feedbackEl.classList.remove("copied"), feedbackDuration);
1093
+ element.dispatchEvent(
1094
+ new CustomEvent("clipboard:copied", {
1095
+ bubbles: true,
1096
+ detail: { text: copyText }
1097
+ })
1098
+ );
1099
+ } catch (error) {
1100
+ element.dispatchEvent(
1101
+ new CustomEvent("clipboard:error", {
1102
+ bubbles: true,
1103
+ detail: { error }
1104
+ })
1105
+ );
1106
+ }
1107
+ });
1108
+ }
1109
+ async function registerClipboard(hyperfixi) {
1110
+ const hf = hyperfixi || resolveRuntime();
1111
+ if (!hf) {
1112
+ throw new Error(
1113
+ "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
1114
+ );
1115
+ }
1116
+ const syntheticNode = {
1117
+ type: "behavior",
1118
+ name: "Clipboard",
1119
+ parameters: ["text", "source", "feedback", "feedbackDuration"],
1120
+ eventHandlers: [],
1121
+ imperativeInstaller: installClipboard
1122
+ };
1123
+ const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
1124
+ await hf.execute(syntheticNode, ctx);
1125
+ }
1126
+ var clipboardSource, clipboardMetadata, clipboard_default;
1127
+ var init_clipboard = __esm({
1128
+ "src/behaviors/clipboard.ts"() {
1129
+ "use strict";
1130
+ init_clipboard_schema();
1131
+ init_types();
1132
+ clipboardSource = clipboardSchema.source;
1133
+ clipboardMetadata = clipboardSchema;
1134
+ if (resolveRuntime()) {
1135
+ registerClipboard().catch(console.error);
1136
+ }
1137
+ clipboard_default = {
1138
+ source: clipboardSchema.source,
1139
+ metadata: clipboardSchema,
1140
+ register: registerClipboard
1141
+ };
1142
+ }
1143
+ });
1144
+
1145
+ // src/behaviors/autodismiss.ts
1146
+ var autodismiss_exports = {};
1147
+ __export(autodismiss_exports, {
1148
+ autoDismissMetadata: () => autoDismissMetadata,
1149
+ autoDismissSource: () => autoDismissSource,
1150
+ default: () => autodismiss_default,
1151
+ registerAutoDismiss: () => registerAutoDismiss
1152
+ });
1153
+ function installAutoDismiss(element, params) {
1154
+ const delay = typeof params.delay === "number" ? params.delay : 5e3;
1155
+ const pauseOnHover = params.pauseOnHover !== false;
1156
+ const effect = params.effect === "fade" ? "fade" : "none";
1157
+ let timerId = null;
1158
+ let remaining = delay;
1159
+ let startedAt = Date.now();
1160
+ function dismiss() {
1161
+ const event = new CustomEvent("autodismiss:dismissed", {
1162
+ bubbles: true,
1163
+ cancelable: true
1164
+ });
1165
+ element.dispatchEvent(event);
1166
+ if (event.defaultPrevented) return;
1167
+ if (effect === "fade") {
1168
+ element.style.transition = "opacity 300ms";
1169
+ element.style.opacity = "0";
1170
+ setTimeout(() => element.remove(), 300);
1171
+ } else {
1172
+ element.remove();
1173
+ }
1174
+ }
1175
+ function start() {
1176
+ startedAt = Date.now();
1177
+ timerId = setTimeout(dismiss, remaining);
1178
+ }
1179
+ element.dispatchEvent(new CustomEvent("autodismiss:start", { bubbles: true }));
1180
+ start();
1181
+ if (pauseOnHover) {
1182
+ element.addEventListener("mouseenter", () => {
1183
+ if (timerId != null) {
1184
+ clearTimeout(timerId);
1185
+ timerId = null;
1186
+ remaining -= Date.now() - startedAt;
1187
+ if (remaining < 0) remaining = 0;
1188
+ element.dispatchEvent(new CustomEvent("autodismiss:paused", { bubbles: true }));
1189
+ }
1190
+ });
1191
+ element.addEventListener("mouseleave", () => {
1192
+ if (timerId == null && element.isConnected) {
1193
+ element.dispatchEvent(new CustomEvent("autodismiss:resumed", { bubbles: true }));
1194
+ start();
1195
+ }
1196
+ });
1197
+ }
1198
+ }
1199
+ async function registerAutoDismiss(hyperfixi) {
1200
+ const hf = hyperfixi || resolveRuntime();
1201
+ if (!hf) {
1202
+ throw new Error(
1203
+ "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
1204
+ );
1205
+ }
1206
+ const syntheticNode = {
1207
+ type: "behavior",
1208
+ name: "AutoDismiss",
1209
+ parameters: ["delay", "pauseOnHover", "effect"],
1210
+ eventHandlers: [],
1211
+ imperativeInstaller: installAutoDismiss
1212
+ };
1213
+ const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
1214
+ await hf.execute(syntheticNode, ctx);
1215
+ }
1216
+ var autoDismissSource, autoDismissMetadata, autodismiss_default;
1217
+ var init_autodismiss = __esm({
1218
+ "src/behaviors/autodismiss.ts"() {
1219
+ "use strict";
1220
+ init_autodismiss_schema();
1221
+ init_types();
1222
+ autoDismissSource = autoDismissSchema.source;
1223
+ autoDismissMetadata = autoDismissSchema;
1224
+ if (resolveRuntime()) {
1225
+ registerAutoDismiss().catch(console.error);
1226
+ }
1227
+ autodismiss_default = {
1228
+ source: autoDismissSchema.source,
1229
+ metadata: autoDismissSchema,
1230
+ register: registerAutoDismiss
1231
+ };
1232
+ }
1233
+ });
1234
+
1235
+ // src/behaviors/clickoutside.ts
1236
+ var clickoutside_exports = {};
1237
+ __export(clickoutside_exports, {
1238
+ clickOutsideMetadata: () => clickOutsideMetadata,
1239
+ clickOutsideSource: () => clickOutsideSource,
1240
+ default: () => clickoutside_default,
1241
+ registerClickOutside: () => registerClickOutside
1242
+ });
1243
+ function installClickOutside(element, params) {
1244
+ let active = params.active !== false;
1245
+ function onPointerDown(e) {
1246
+ if (!element.isConnected) {
1247
+ document.removeEventListener("pointerdown", onPointerDown);
1248
+ return;
1249
+ }
1250
+ if (active && !element.contains(e.target)) {
1251
+ element.dispatchEvent(new CustomEvent("clickoutside", { bubbles: true }));
1252
+ }
1253
+ }
1254
+ document.addEventListener("pointerdown", onPointerDown);
1255
+ element.addEventListener("clickoutside:activate", () => {
1256
+ active = true;
1257
+ });
1258
+ element.addEventListener("clickoutside:deactivate", () => {
1259
+ active = false;
1260
+ });
1261
+ }
1262
+ async function registerClickOutside(hyperfixi) {
1263
+ const hf = hyperfixi || resolveRuntime();
1264
+ if (!hf) {
1265
+ throw new Error(
1266
+ "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
1267
+ );
1268
+ }
1269
+ const syntheticNode = {
1270
+ type: "behavior",
1271
+ name: "ClickOutside",
1272
+ parameters: ["active"],
1273
+ eventHandlers: [],
1274
+ imperativeInstaller: installClickOutside
1275
+ };
1276
+ const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
1277
+ await hf.execute(syntheticNode, ctx);
1278
+ }
1279
+ var clickOutsideSource, clickOutsideMetadata, clickoutside_default;
1280
+ var init_clickoutside = __esm({
1281
+ "src/behaviors/clickoutside.ts"() {
1282
+ "use strict";
1283
+ init_clickoutside_schema();
1284
+ init_types();
1285
+ clickOutsideSource = clickOutsideSchema.source;
1286
+ clickOutsideMetadata = clickOutsideSchema;
1287
+ if (resolveRuntime()) {
1288
+ registerClickOutside().catch(console.error);
1289
+ }
1290
+ clickoutside_default = {
1291
+ source: clickOutsideSchema.source,
1292
+ metadata: clickOutsideSchema,
1293
+ register: registerClickOutside
1294
+ };
1295
+ }
1296
+ });
1297
+
1298
+ // src/behaviors/focustrap.ts
1299
+ var focustrap_exports = {};
1300
+ __export(focustrap_exports, {
1301
+ default: () => focustrap_default,
1302
+ focusTrapMetadata: () => focusTrapMetadata,
1303
+ focusTrapSource: () => focusTrapSource,
1304
+ registerFocusTrap: () => registerFocusTrap
1305
+ });
1306
+ function resolveElement2(container, param) {
1307
+ if (!param) return null;
1308
+ if (param instanceof HTMLElement) return param;
1309
+ if (typeof param === "string") {
1310
+ return container.querySelector(param) || document.querySelector(param) || null;
1311
+ }
1312
+ return null;
1313
+ }
1314
+ function installFocusTrap(element, params) {
1315
+ const returnFocus = params.returnFocus !== false;
1316
+ let isActive = false;
1317
+ let previouslyFocused = null;
1318
+ function getFocusableElements() {
1319
+ return Array.from(element.querySelectorAll(FOCUSABLE_SELECTOR));
1320
+ }
1321
+ function onKeyDown(e) {
1322
+ if (!isActive || e.key !== "Tab") return;
1323
+ const focusable = getFocusableElements();
1324
+ if (focusable.length === 0) {
1325
+ e.preventDefault();
1326
+ return;
1327
+ }
1328
+ e.preventDefault();
1329
+ const currentIndex = focusable.indexOf(document.activeElement);
1330
+ if (e.shiftKey) {
1331
+ const prevIndex = currentIndex <= 0 ? focusable.length - 1 : currentIndex - 1;
1332
+ focusable[prevIndex].focus();
1333
+ } else {
1334
+ const nextIndex = currentIndex >= focusable.length - 1 ? 0 : currentIndex + 1;
1335
+ focusable[nextIndex].focus();
1336
+ }
1337
+ }
1338
+ function activate() {
1339
+ if (isActive) return;
1340
+ isActive = true;
1341
+ previouslyFocused = document.activeElement;
1342
+ element.setAttribute("aria-modal", "true");
1343
+ const initialEl = resolveElement2(element, params.initialFocus);
1344
+ if (initialEl) {
1345
+ initialEl.focus();
1346
+ } else {
1347
+ const focusable = getFocusableElements();
1348
+ if (focusable.length > 0) {
1349
+ focusable[0].focus();
1350
+ }
1351
+ }
1352
+ element.dispatchEvent(new CustomEvent("focustrap:activated", { bubbles: true }));
1353
+ }
1354
+ function deactivate() {
1355
+ if (!isActive) return;
1356
+ isActive = false;
1357
+ element.removeAttribute("aria-modal");
1358
+ if (returnFocus && previouslyFocused instanceof HTMLElement) {
1359
+ previouslyFocused.focus();
1360
+ }
1361
+ previouslyFocused = null;
1362
+ element.dispatchEvent(new CustomEvent("focustrap:deactivated", { bubbles: true }));
1363
+ }
1364
+ element.addEventListener("keydown", onKeyDown);
1365
+ element.addEventListener("focustrap:activate", () => activate());
1366
+ element.addEventListener("focustrap:deactivate", () => deactivate());
1367
+ if (params.active !== false) {
1368
+ activate();
1369
+ }
1370
+ }
1371
+ async function registerFocusTrap(hyperfixi) {
1372
+ const hf = hyperfixi || resolveRuntime();
1373
+ if (!hf) {
1374
+ throw new Error(
1375
+ "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
1376
+ );
1377
+ }
1378
+ const syntheticNode = {
1379
+ type: "behavior",
1380
+ name: "FocusTrap",
1381
+ parameters: ["active", "initialFocus", "returnFocus"],
1382
+ eventHandlers: [],
1383
+ imperativeInstaller: installFocusTrap
1384
+ };
1385
+ const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
1386
+ await hf.execute(syntheticNode, ctx);
1387
+ }
1388
+ var focusTrapSource, focusTrapMetadata, FOCUSABLE_SELECTOR, focustrap_default;
1389
+ var init_focustrap = __esm({
1390
+ "src/behaviors/focustrap.ts"() {
1391
+ "use strict";
1392
+ init_focustrap_schema();
1393
+ init_types();
1394
+ focusTrapSource = focusTrapSchema.source;
1395
+ focusTrapMetadata = focusTrapSchema;
1396
+ FOCUSABLE_SELECTOR = [
1397
+ "a[href]",
1398
+ "button:not(:disabled)",
1399
+ "input:not(:disabled)",
1400
+ "select:not(:disabled)",
1401
+ "textarea:not(:disabled)",
1402
+ '[tabindex]:not([tabindex="-1"])'
1403
+ ].join(", ");
1404
+ if (resolveRuntime()) {
1405
+ registerFocusTrap().catch(console.error);
1406
+ }
1407
+ focustrap_default = {
1408
+ source: focusTrapSchema.source,
1409
+ metadata: focusTrapSchema,
1410
+ register: registerFocusTrap
1411
+ };
1412
+ }
1413
+ });
1414
+
1415
+ // src/behaviors/scrollreveal.ts
1416
+ var scrollreveal_exports = {};
1417
+ __export(scrollreveal_exports, {
1418
+ default: () => scrollreveal_default,
1419
+ registerScrollReveal: () => registerScrollReveal,
1420
+ scrollRevealMetadata: () => scrollRevealMetadata,
1421
+ scrollRevealSource: () => scrollRevealSource
1422
+ });
1423
+ function installScrollReveal(element, params) {
1424
+ const cls = typeof params.cls === "string" ? params.cls : "revealed";
1425
+ const threshold = typeof params.threshold === "number" ? params.threshold : 0.1;
1426
+ const once = params.once !== false;
1427
+ const rootMargin = typeof params.rootMargin === "string" ? params.rootMargin : "0px";
1428
+ const observer = new IntersectionObserver(
1429
+ (entries) => {
1430
+ for (const entry of entries) {
1431
+ if (entry.isIntersecting) {
1432
+ element.classList.add(cls);
1433
+ element.dispatchEvent(new CustomEvent("scrollreveal:enter", { bubbles: true }));
1434
+ if (once) {
1435
+ observer.disconnect();
1436
+ }
1437
+ } else if (!once) {
1438
+ element.classList.remove(cls);
1439
+ element.dispatchEvent(new CustomEvent("scrollreveal:exit", { bubbles: true }));
1440
+ }
1441
+ }
1442
+ },
1443
+ { threshold, rootMargin }
1444
+ );
1445
+ observer.observe(element);
1446
+ }
1447
+ async function registerScrollReveal(hyperfixi) {
1448
+ const hf = hyperfixi || resolveRuntime();
1449
+ if (!hf) {
1450
+ throw new Error(
1451
+ "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
1452
+ );
1453
+ }
1454
+ const syntheticNode = {
1455
+ type: "behavior",
1456
+ name: "ScrollReveal",
1457
+ parameters: ["cls", "threshold", "once", "rootMargin"],
1458
+ eventHandlers: [],
1459
+ imperativeInstaller: installScrollReveal
1460
+ };
1461
+ const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
1462
+ await hf.execute(syntheticNode, ctx);
1463
+ }
1464
+ var scrollRevealSource, scrollRevealMetadata, scrollreveal_default;
1465
+ var init_scrollreveal = __esm({
1466
+ "src/behaviors/scrollreveal.ts"() {
1467
+ "use strict";
1468
+ init_scrollreveal_schema();
1469
+ init_types();
1470
+ scrollRevealSource = scrollRevealSchema.source;
1471
+ scrollRevealMetadata = scrollRevealSchema;
1472
+ if (resolveRuntime()) {
1473
+ registerScrollReveal().catch(console.error);
1474
+ }
1475
+ scrollreveal_default = {
1476
+ source: scrollRevealSchema.source,
1477
+ metadata: scrollRevealSchema,
1478
+ register: registerScrollReveal
1479
+ };
1480
+ }
1481
+ });
1482
+
1483
+ // src/behaviors/tabs.ts
1484
+ var tabs_exports = {};
1485
+ __export(tabs_exports, {
1486
+ default: () => tabs_default,
1487
+ registerTabs: () => registerTabs,
1488
+ tabsMetadata: () => tabsMetadata,
1489
+ tabsSource: () => tabsSource
1490
+ });
1491
+ function ensureId(el, prefix) {
1492
+ if (!el.id) {
1493
+ el.id = `${prefix}-${++idCounter}`;
1494
+ }
1495
+ return el.id;
1496
+ }
1497
+ function installTabs(element, params) {
1498
+ const orientation = params.orientation === "vertical" ? "vertical" : "horizontal";
1499
+ const wrap = params.wrap !== false;
1500
+ const activeClass = params.activeClass || "active";
1501
+ const initialIndex = typeof params.activeTab === "number" ? params.activeTab : 0;
1502
+ const tabs = Array.from(element.querySelectorAll('[role="tab"]'));
1503
+ const panels = Array.from(element.querySelectorAll('[role="tabpanel"]'));
1504
+ if (tabs.length === 0 || panels.length === 0) return;
1505
+ const tablist = element.querySelector('[role="tablist"]') || tabs[0].parentElement;
1506
+ if (tablist && !tablist.getAttribute("role")) {
1507
+ tablist.setAttribute("role", "tablist");
1508
+ }
1509
+ if (tablist) {
1510
+ tablist.setAttribute("aria-orientation", orientation);
1511
+ }
1512
+ const count = Math.min(tabs.length, panels.length);
1513
+ for (let i = 0; i < count; i++) {
1514
+ const tabId = ensureId(tabs[i], "tab");
1515
+ const panelId = ensureId(panels[i], "tabpanel");
1516
+ tabs[i].setAttribute("aria-controls", panelId);
1517
+ panels[i].setAttribute("aria-labelledby", tabId);
1518
+ }
1519
+ let currentIndex = -1;
1520
+ function selectTab(index, previousIndex) {
1521
+ if (index === previousIndex || index < 0 || index >= count) return false;
1522
+ const detail = {
1523
+ tab: tabs[index],
1524
+ panel: panels[index],
1525
+ index,
1526
+ previousIndex
1527
+ };
1528
+ const changeEvent = new CustomEvent("tabs:change", {
1529
+ bubbles: true,
1530
+ cancelable: true,
1531
+ detail
1532
+ });
1533
+ element.dispatchEvent(changeEvent);
1534
+ if (changeEvent.defaultPrevented) return false;
1535
+ if (previousIndex >= 0 && previousIndex < count) {
1536
+ tabs[previousIndex].setAttribute("aria-selected", "false");
1537
+ tabs[previousIndex].setAttribute("tabindex", "-1");
1538
+ tabs[previousIndex].classList.remove(activeClass);
1539
+ panels[previousIndex].setAttribute("aria-hidden", "true");
1540
+ panels[previousIndex].classList.remove(activeClass);
1541
+ }
1542
+ tabs[index].setAttribute("aria-selected", "true");
1543
+ tabs[index].setAttribute("tabindex", "0");
1544
+ tabs[index].classList.add(activeClass);
1545
+ panels[index].setAttribute("aria-hidden", "false");
1546
+ panels[index].classList.add(activeClass);
1547
+ currentIndex = index;
1548
+ element.dispatchEvent(new CustomEvent("tabs:changed", { bubbles: true, detail }));
1549
+ return true;
1550
+ }
1551
+ for (let i = 0; i < count; i++) {
1552
+ tabs[i].setAttribute("aria-selected", "false");
1553
+ tabs[i].setAttribute("tabindex", "-1");
1554
+ tabs[i].classList.remove(activeClass);
1555
+ panels[i].setAttribute("aria-hidden", "true");
1556
+ panels[i].classList.remove(activeClass);
1557
+ }
1558
+ const clamped = Math.max(0, Math.min(initialIndex, count - 1));
1559
+ tabs[clamped].setAttribute("aria-selected", "true");
1560
+ tabs[clamped].setAttribute("tabindex", "0");
1561
+ tabs[clamped].classList.add(activeClass);
1562
+ panels[clamped].setAttribute("aria-hidden", "false");
1563
+ panels[clamped].classList.add(activeClass);
1564
+ currentIndex = clamped;
1565
+ for (let i = 0; i < count; i++) {
1566
+ tabs[i].addEventListener("click", () => {
1567
+ selectTab(i, currentIndex);
1568
+ tabs[i].focus();
1569
+ });
1570
+ }
1571
+ const keyTarget = tablist || element;
1572
+ keyTarget.addEventListener("keydown", (e) => {
1573
+ const isHorizontal = orientation === "horizontal";
1574
+ const nextKey = isHorizontal ? "ArrowRight" : "ArrowDown";
1575
+ const prevKey = isHorizontal ? "ArrowLeft" : "ArrowUp";
1576
+ let nextIndex = null;
1577
+ if (e.key === nextKey) {
1578
+ nextIndex = currentIndex + 1;
1579
+ if (nextIndex >= count) nextIndex = wrap ? 0 : null;
1580
+ } else if (e.key === prevKey) {
1581
+ nextIndex = currentIndex - 1;
1582
+ if (nextIndex < 0) nextIndex = wrap ? count - 1 : null;
1583
+ } else if (e.key === "Home") {
1584
+ nextIndex = 0;
1585
+ } else if (e.key === "End") {
1586
+ nextIndex = count - 1;
1587
+ }
1588
+ if (nextIndex !== null) {
1589
+ e.preventDefault();
1590
+ if (selectTab(nextIndex, currentIndex)) {
1591
+ tabs[nextIndex].focus();
1592
+ }
1593
+ }
1594
+ });
1595
+ element.addEventListener("tabs:select", ((e) => {
1596
+ const index = e.detail?.index;
1597
+ if (typeof index === "number") {
1598
+ selectTab(index, currentIndex);
1599
+ }
1600
+ }));
1601
+ }
1602
+ async function registerTabs(hyperfixi) {
1603
+ const hf = hyperfixi || resolveRuntime();
1604
+ if (!hf) {
1605
+ throw new Error(
1606
+ "LokaScript not found. Make sure @hyperfixi/core is loaded before registering behaviors."
1607
+ );
1608
+ }
1609
+ const syntheticNode = {
1610
+ type: "behavior",
1611
+ name: "Tabs",
1612
+ parameters: ["orientation", "activeTab", "wrap", "activeClass"],
1613
+ eventHandlers: [],
1614
+ imperativeInstaller: installTabs
1615
+ };
1616
+ const ctx = hf.createContext ? hf.createContext() : { locals: /* @__PURE__ */ new Map(), globals: /* @__PURE__ */ new Map() };
1617
+ await hf.execute(syntheticNode, ctx);
1618
+ }
1619
+ var tabsSource, tabsMetadata, idCounter, tabs_default;
1620
+ var init_tabs = __esm({
1621
+ "src/behaviors/tabs.ts"() {
1622
+ "use strict";
1623
+ init_tabs_schema();
1624
+ init_types();
1625
+ tabsSource = tabsSchema.source;
1626
+ tabsMetadata = tabsSchema;
1627
+ idCounter = 0;
1628
+ if (resolveRuntime()) {
1629
+ registerTabs().catch(console.error);
1630
+ }
1631
+ tabs_default = {
1632
+ source: tabsSchema.source,
1633
+ metadata: tabsSchema,
1634
+ register: registerTabs
1635
+ };
1636
+ }
1637
+ });
1638
+
536
1639
  // src/registry.ts
537
1640
  var schemas = /* @__PURE__ */ new Map();
538
1641
  var loaders = /* @__PURE__ */ new Map();
@@ -549,14 +1652,32 @@ init_sortable_schema();
549
1652
  init_resizable_schema();
550
1653
  init_removable_schema();
551
1654
  init_toggleable_schema();
1655
+ init_clipboard_schema();
1656
+ init_autodismiss_schema();
1657
+ init_clickoutside_schema();
1658
+ init_focustrap_schema();
1659
+ init_scrollreveal_schema();
1660
+ init_tabs_schema();
552
1661
  registerSchema(draggableSchema);
553
1662
  registerSchema(sortableSchema);
554
1663
  registerSchema(resizableSchema);
555
1664
  registerSchema(removableSchema);
556
1665
  registerSchema(toggleableSchema);
1666
+ registerSchema(clipboardSchema);
1667
+ registerSchema(autoDismissSchema);
1668
+ registerSchema(clickOutsideSchema);
1669
+ registerSchema(focusTrapSchema);
1670
+ registerSchema(scrollRevealSchema);
1671
+ registerSchema(tabsSchema);
557
1672
  registerLoader("Draggable", () => Promise.resolve().then(() => (init_draggable(), draggable_exports)));
558
1673
  registerLoader("Sortable", () => Promise.resolve().then(() => (init_sortable(), sortable_exports)));
559
1674
  registerLoader("Resizable", () => Promise.resolve().then(() => (init_resizable(), resizable_exports)));
560
1675
  registerLoader("Removable", () => Promise.resolve().then(() => (init_removable(), removable_exports)));
561
1676
  registerLoader("Toggleable", () => Promise.resolve().then(() => (init_toggleable(), toggleable_exports)));
1677
+ registerLoader("Clipboard", () => Promise.resolve().then(() => (init_clipboard(), clipboard_exports)));
1678
+ registerLoader("AutoDismiss", () => Promise.resolve().then(() => (init_autodismiss(), autodismiss_exports)));
1679
+ registerLoader("ClickOutside", () => Promise.resolve().then(() => (init_clickoutside(), clickoutside_exports)));
1680
+ registerLoader("FocusTrap", () => Promise.resolve().then(() => (init_focustrap(), focustrap_exports)));
1681
+ registerLoader("ScrollReveal", () => Promise.resolve().then(() => (init_scrollreveal(), scrollreveal_exports)));
1682
+ registerLoader("Tabs", () => Promise.resolve().then(() => (init_tabs(), tabs_exports)));
562
1683
  //# sourceMappingURL=loaders.cjs.map