@hyperfixi/core 2.3.0 → 2.4.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 (203) hide show
  1. package/README.md +8 -11
  2. package/dist/api/dom-processor.d.ts +8 -4
  3. package/dist/api/hyperscript-api.d.ts +5 -1
  4. package/dist/ast-utils/index.js +25320 -94
  5. package/dist/ast-utils/index.mjs +25320 -94
  6. package/dist/ast-utils/interchange/types.d.ts +7 -1
  7. package/dist/behaviors/index.js +54 -100
  8. package/dist/behaviors/index.mjs +54 -100
  9. package/dist/bundle-generator/index.js +44 -6
  10. package/dist/bundle-generator/index.mjs +44 -6
  11. package/dist/bundle-generator/parser-templates.d.ts +1 -1
  12. package/dist/bundle-generator/template-capabilities.d.ts +1 -1
  13. package/dist/chunks/bridge-C4d3blZX.js +2 -0
  14. package/dist/chunks/browser-modular-BwIRlrTM.js +2 -0
  15. package/dist/chunks/feature-eventsource-BpZvPy_K.js +2 -0
  16. package/dist/chunks/{feature-sockets-ClOH7vk7.js → feature-sockets-CrYvjZ4j.js} +2 -2
  17. package/dist/chunks/feature-webworker-BSYguEIW.js +2 -0
  18. package/dist/chunks/index-Beno_SBy.js +2 -0
  19. package/dist/commands/advanced/async.d.ts +6 -2
  20. package/dist/commands/advanced/js.d.ts +1 -1
  21. package/dist/commands/animation/start-view-transition.d.ts +24 -0
  22. package/dist/commands/async/fetch.d.ts +6 -1
  23. package/dist/commands/control-flow/repeat.d.ts +2 -0
  24. package/dist/commands/data/clear.d.ts +23 -0
  25. package/dist/commands/data/set.d.ts +6 -0
  26. package/dist/commands/dom/close.d.ts +19 -0
  27. package/dist/commands/dom/empty.d.ts +19 -0
  28. package/dist/commands/dom/open.d.ts +21 -0
  29. package/dist/commands/dom/reset.d.ts +19 -0
  30. package/dist/commands/dom/select.d.ts +19 -0
  31. package/dist/commands/dom/swap.d.ts +7 -4
  32. package/dist/commands/events/trigger.d.ts +1 -1
  33. package/dist/commands/execution/blur.d.ts +19 -0
  34. package/dist/commands/execution/call.d.ts +1 -2
  35. package/dist/commands/execution/focus.d.ts +19 -0
  36. package/dist/commands/helpers/element-resolution.d.ts +2 -2
  37. package/dist/commands/helpers/event-waiting.d.ts +1 -1
  38. package/dist/commands/helpers/numeric-target-parser.d.ts +7 -0
  39. package/dist/commands/index.d.ts +34 -2
  40. package/dist/commands/index.js +19374 -4848
  41. package/dist/commands/index.mjs +19342 -4849
  42. package/dist/commands/navigation/go.d.ts +3 -0
  43. package/dist/commands/navigation/scroll-to.d.ts +26 -0
  44. package/dist/commands/utility/beep.d.ts +2 -2
  45. package/dist/commands/utility/breakpoint.d.ts +19 -0
  46. package/dist/commands/utility/pick.d.ts +11 -2
  47. package/dist/compatibility/browser-bundle-modular.d.ts +2 -2
  48. package/dist/compatibility/browser-bundle-multilingual.d.ts +1 -1
  49. package/dist/compatibility/browser-bundle-semantic-complete.d.ts +3 -3
  50. package/dist/compatibility/browser-bundle.d.ts +13 -6
  51. package/dist/compatibility/browser-modular.d.ts +1 -3
  52. package/dist/core/expression-evaluator.d.ts +4 -4
  53. package/dist/core/expression-registry.d.ts +8 -0
  54. package/dist/expressions/bundles/common-expressions.d.ts +2 -2
  55. package/dist/expressions/bundles/core-expressions.d.ts +2 -2
  56. package/dist/expressions/bundles/full-expressions.d.ts +2 -2
  57. package/dist/expressions/bundles/index.d.ts +3 -3
  58. package/dist/expressions/collection/index.d.ts +35 -0
  59. package/dist/expressions/conversion/impl/index.d.ts +1 -1
  60. package/dist/expressions/index.d.ts +4 -3
  61. package/dist/expressions/index.js +1117 -1590
  62. package/dist/expressions/index.mjs +1113 -1586
  63. package/dist/expressions/logical/index.d.ts +2 -0
  64. package/dist/expressions/mathematical/index.d.ts +11 -0
  65. package/dist/expressions/shared/index.d.ts +1 -1
  66. package/dist/expressions/shared/number-utils.d.ts +1 -0
  67. package/dist/htmx/htmx-attribute-processor.d.ts +37 -1
  68. package/dist/htmx/htmx-translator.d.ts +2 -0
  69. package/dist/htmx/i18n-hooks.d.ts +15 -0
  70. package/dist/htmx/i18n-orchestrator.d.ts +15 -0
  71. package/dist/htmx/lang-resolver.d.ts +3 -0
  72. package/dist/htmx/sse.d.ts +60 -0
  73. package/dist/htmx/ws.d.ts +59 -0
  74. package/dist/hyperfixi-browser-classic-i18n.js +2 -0
  75. package/dist/hyperfixi-browser-minimal.js +1 -0
  76. package/dist/hyperfixi-browser-standard.js +2 -0
  77. package/dist/hyperfixi-browser.js +2 -0
  78. package/dist/hyperfixi-classic-i18n.js +1 -1
  79. package/dist/hyperfixi-hx-v4.js +1 -0
  80. package/dist/hyperfixi-hx.js +1 -1
  81. package/dist/hyperfixi-hybrid-complete.js +1 -1
  82. package/dist/hyperfixi-hybrid-hx.js +1 -0
  83. package/dist/hyperfixi-minimal.js +1 -1
  84. package/dist/hyperfixi-multilingual.js +1 -1
  85. package/dist/hyperfixi-standard.js +1 -1
  86. package/dist/hyperfixi.js +1 -1
  87. package/dist/hyperfixi.mjs +1 -1
  88. package/dist/index.d.ts +2 -0
  89. package/dist/index.js +43613 -45063
  90. package/dist/index.min.js +1 -1
  91. package/dist/index.mjs +43610 -45064
  92. package/dist/lib/index.d.ts +2 -2
  93. package/dist/lib/morph-adapter.d.ts +0 -13
  94. package/dist/lib/swap-executor.d.ts +0 -10
  95. package/dist/lib/view-transitions.d.ts +1 -30
  96. package/dist/lokascript-browser-classic-i18n.js +1 -1
  97. package/dist/lokascript-browser-minimal.js +1 -1
  98. package/dist/lokascript-browser-standard.js +1 -1
  99. package/dist/lokascript-browser.js +1 -1
  100. package/dist/lokascript-hybrid-complete.js +1 -1
  101. package/dist/lokascript-hybrid-hx.js +1 -1
  102. package/dist/lokascript-multilingual.js +1 -1
  103. package/dist/lsp-metadata.d.ts +9 -4
  104. package/dist/lsp-metadata.js +187 -3
  105. package/dist/lsp-metadata.mjs +185 -4
  106. package/dist/metadata.d.ts +1 -1
  107. package/dist/metadata.js +3 -3
  108. package/dist/metadata.mjs +3 -3
  109. package/dist/multilingual/bridge.d.ts +1 -1
  110. package/dist/multilingual/index.js +79 -22
  111. package/dist/multilingual/index.mjs +79 -22
  112. package/dist/parser/command-parsers/animation-commands.d.ts +1 -0
  113. package/dist/parser/command-parsers/utility-commands.d.ts +1 -0
  114. package/dist/parser/extensions.d.ts +51 -0
  115. package/dist/parser/full-parser.js +1224 -899
  116. package/dist/parser/full-parser.mjs +1224 -899
  117. package/dist/parser/helpers/ast-helpers.d.ts +1 -0
  118. package/dist/parser/helpers/parsing-helpers.d.ts +4 -0
  119. package/dist/parser/hybrid/index.js +7 -0
  120. package/dist/parser/hybrid/index.mjs +7 -0
  121. package/dist/parser/hybrid/parser-core.js +7 -0
  122. package/dist/parser/hybrid/parser-core.mjs +7 -0
  123. package/dist/parser/hybrid/tokenizer.js +7 -0
  124. package/dist/parser/hybrid/tokenizer.mjs +7 -0
  125. package/dist/parser/hybrid-parser.js +7 -0
  126. package/dist/parser/hybrid-parser.mjs +7 -0
  127. package/dist/parser/parser-types.d.ts +8 -28
  128. package/dist/parser/parser.d.ts +3 -7
  129. package/dist/parser/pratt-parser.d.ts +0 -3
  130. package/dist/parser/runtime.d.ts +4 -0
  131. package/dist/parser/semantic-integration.d.ts +17 -0
  132. package/dist/parser/types.d.ts +7 -1
  133. package/dist/reference/index.js +91 -0
  134. package/dist/reference/index.mjs +91 -0
  135. package/dist/registry/index.js +12866 -5876
  136. package/dist/registry/index.mjs +12866 -5876
  137. package/dist/registry/universal-types.d.ts +2 -1
  138. package/dist/runtime/command-adapter.d.ts +23 -16
  139. package/dist/runtime/plugin.d.ts +14 -0
  140. package/dist/runtime/runtime-base.d.ts +32 -7
  141. package/dist/runtime/runtime-factory.d.ts +3 -3
  142. package/dist/runtime/runtime.d.ts +2 -2
  143. package/dist/test-setup.d.ts +1 -0
  144. package/dist/types/base-types.d.ts +3 -0
  145. package/dist/types/feature-types.d.ts +1 -1
  146. package/dist/types/index.d.ts +2 -2
  147. package/package.json +26 -20
  148. package/vocab/htmx/ar.js +60 -0
  149. package/vocab/htmx/bn.js +49 -0
  150. package/vocab/htmx/de.js +60 -0
  151. package/vocab/htmx/en.js +21 -0
  152. package/vocab/htmx/es.js +60 -0
  153. package/vocab/htmx/fr.js +59 -0
  154. package/vocab/htmx/he.js +40 -0
  155. package/vocab/htmx/hi.js +60 -0
  156. package/vocab/htmx/id.js +57 -0
  157. package/vocab/htmx/it.js +58 -0
  158. package/vocab/htmx/ja.js +60 -0
  159. package/vocab/htmx/ko.js +60 -0
  160. package/vocab/htmx/ms.js +35 -0
  161. package/vocab/htmx/pl.js +60 -0
  162. package/vocab/htmx/pt.js +60 -0
  163. package/vocab/htmx/qu.js +60 -0
  164. package/vocab/htmx/ru.js +60 -0
  165. package/vocab/htmx/sw.js +59 -0
  166. package/vocab/htmx/th.js +49 -0
  167. package/vocab/htmx/tl.js +33 -0
  168. package/vocab/htmx/tr.js +60 -0
  169. package/vocab/htmx/uk.js +60 -0
  170. package/vocab/htmx/vi.js +51 -0
  171. package/vocab/htmx/zh.js +60 -0
  172. package/dist/bundles/test-minimal.d.ts +0 -3
  173. package/dist/bundles/test-standard.d.ts +0 -3
  174. package/dist/chunks/bridge-BlRqsZT4.js +0 -2
  175. package/dist/chunks/browser-modular-AbV0Ql4i.js +0 -2
  176. package/dist/chunks/feature-eventsource-B5F2-H1r.js +0 -2
  177. package/dist/chunks/feature-webworker-3bAp0ac9.js +0 -2
  178. package/dist/chunks/index-BDYQHwCF.js +0 -2
  179. package/dist/compatibility/browser-bundle-minimal.d.ts +0 -8
  180. package/dist/compatibility/browser-bundle-standard.d.ts +0 -8
  181. package/dist/compatibility/hyperscript-tests/test-adapter.d.ts +0 -13
  182. package/dist/core/base-expression-evaluator.d.ts +0 -74
  183. package/dist/core/binary-expression-evaluator.d.ts +0 -7
  184. package/dist/core/call-expression-evaluator.d.ts +0 -7
  185. package/dist/core/configurable-expression-evaluator.d.ts +0 -5
  186. package/dist/core/lazy-expression-evaluator.d.ts +0 -22
  187. package/dist/core/parser.d.ts +0 -21
  188. package/dist/core/selector-evaluator.d.ts +0 -15
  189. package/dist/core/template-literal-evaluator.d.ts +0 -5
  190. package/dist/expressions/comparison/index.d.ts +0 -80
  191. package/dist/expressions/comparison/utils.d.ts +0 -2
  192. package/dist/expressions/conversion/impl/bridge.d.ts +0 -117
  193. package/dist/expressions/logical/impl/pattern-matching.d.ts +0 -58
  194. package/dist/expressions/positional/impl/bridge.d.ts +0 -95
  195. package/dist/expressions/property/index.d.ts +0 -55
  196. package/dist/expressions/references/impl/bridge.d.ts +0 -54
  197. package/dist/extensions/index.d.ts +0 -3
  198. package/dist/extensions/tailwind.d.ts +0 -22
  199. package/dist/mod.d.ts +0 -63
  200. package/dist/parser/expression-parser.d.ts +0 -6
  201. package/dist/runtime/runtime-experimental.d.ts +0 -18
  202. package/dist/scripts/code-generator.d.ts +0 -64
  203. package/dist/scripts/generate-missing-commands.d.ts +0 -4
@@ -1,4 +1,4 @@
1
- export type InterchangeNode = EventNode | CommandNode | LiteralNode | IdentifierNode | SelectorNode | VariableNode | BinaryNode | UnaryNode | MemberNode | PossessiveNode | CallNode | IfNode | RepeatNode | ForEachNode | WhileNode | PositionalNode;
1
+ export type InterchangeNode = EventNode | CommandNode | LiteralNode | IdentifierNode | SelectorNode | VariableNode | BinaryNode | UnaryNode | MemberNode | PossessiveNode | CallNode | IfNode | RepeatNode | ForEachNode | WhileNode | PositionalNode | ErrorNode;
2
2
  export interface BaseNode {
3
3
  readonly type: string;
4
4
  readonly start?: number;
@@ -56,6 +56,11 @@ export interface PositionalNode extends BaseNode {
56
56
  readonly position: 'first' | 'last' | 'next' | 'previous' | 'closest' | 'parent' | 'random';
57
57
  readonly target?: InterchangeNode;
58
58
  }
59
+ export interface ErrorNode extends BaseNode {
60
+ readonly type: 'error';
61
+ readonly message: string;
62
+ readonly token?: string;
63
+ }
59
64
  export interface CommandNode extends BaseNode {
60
65
  readonly type: 'command';
61
66
  readonly name: string;
@@ -63,6 +68,7 @@ export interface CommandNode extends BaseNode {
63
68
  readonly target?: InterchangeNode;
64
69
  readonly modifiers?: Record<string, unknown>;
65
70
  readonly roles?: Readonly<Record<string, InterchangeNode>>;
71
+ readonly partial?: boolean;
66
72
  }
67
73
  export interface EventNode extends BaseNode {
68
74
  readonly type: 'event';
@@ -550,31 +550,14 @@ function longestIncreasingSubsequence(sequence) {
550
550
 
551
551
  //# debugId=3F4BCB911DEC843864756E2164756E21
552
552
 
553
- const morphlexMorph = morph;
554
- const morphlexMorphInner = morphInner;
555
553
  function toMorphlexOptions(options) {
556
- if (!options) {
557
- return { preserveChanges: true };
558
- }
559
- return {
560
- preserveChanges: options.preserveChanges ?? true,
561
- beforeNodeVisited: options.beforeNodeVisited,
562
- afterNodeVisited: options.afterNodeVisited,
563
- beforeNodeAdded: options.beforeNodeAdded
564
- ? (node) => options.beforeNodeAdded(node.parentNode, node, null)
565
- : undefined,
566
- afterNodeAdded: options.afterNodeAdded,
567
- beforeNodeRemoved: options.beforeNodeRemoved,
568
- afterNodeRemoved: options.afterNodeRemoved,
569
- };
554
+ return { preserveChanges: options?.preserveChanges ?? true };
570
555
  }
571
- const morphlexEngine = {
556
+ const morphAdapter = {
572
557
  morph(target, content, options) {
573
- const morphlexOpts = toMorphlexOptions(options);
574
- morphlexMorph(target, content, morphlexOpts);
558
+ morph(target, content, toMorphlexOptions(options));
575
559
  },
576
560
  morphInner(target, content, options) {
577
- const morphlexOpts = toMorphlexOptions(options);
578
561
  let contentEl;
579
562
  if (typeof content === 'string') {
580
563
  const wrapper = document.createElement(target.tagName);
@@ -584,71 +567,56 @@ const morphlexEngine = {
584
567
  else {
585
568
  contentEl = content;
586
569
  }
587
- morphlexMorphInner(target, contentEl, morphlexOpts);
588
- },
589
- };
590
- let currentEngine = morphlexEngine;
591
- const morphAdapter = {
592
- morph(target, content, options) {
593
- currentEngine.morph(target, content, options);
594
- },
595
- morphInner(target, content, options) {
596
- currentEngine.morphInner(target, content, options);
570
+ morphInner(target, contentEl, toMorphlexOptions(options));
597
571
  },
598
572
  };
599
573
 
600
- function isViewTransitionsSupported() {
601
- return (typeof document !== 'undefined' && typeof document.startViewTransition === 'function');
574
+ function getStartViewTransition() {
575
+ if (typeof document === 'undefined')
576
+ return undefined;
577
+ return document
578
+ .startViewTransition;
602
579
  }
603
- let config = {
604
- enabled: isViewTransitionsSupported(),
605
- defaultTimeout: 5000};
606
- let transitionQueue = [];
607
- let isProcessingQueue = false;
608
- async function processQueue() {
609
- if (isProcessingQueue || transitionQueue.length === 0) {
610
- return;
611
- }
612
- isProcessingQueue = true;
613
- while (transitionQueue.length > 0) {
614
- const item = transitionQueue.shift();
615
- try {
616
- await executeTransition(item.callback, item.options);
617
- item.resolve();
618
- }
619
- catch (error) {
620
- item.reject(error);
621
- }
622
- }
623
- isProcessingQueue = false;
580
+ function isViewTransitionsSupported() {
581
+ return typeof getStartViewTransition() === 'function';
624
582
  }
625
- async function executeTransition(callback, options) {
626
- const { skipTransition = false, timeout = config.defaultTimeout } = options;
627
- if (!config.enabled || !isViewTransitionsSupported() || skipTransition) {
583
+ const queue = [];
584
+ let processing = false;
585
+ async function runOne(callback) {
586
+ const start = getStartViewTransition();
587
+ if (!start) {
628
588
  await callback();
629
589
  return;
630
590
  }
631
- const transition = document.startViewTransition(async () => {
591
+ const transition = start(async () => {
632
592
  await callback();
633
593
  });
634
- const timeoutPromise = new Promise((_, reject) => {
635
- setTimeout(() => reject(new Error('View transition timed out')), timeout);
636
- });
594
+ await transition.finished;
595
+ }
596
+ async function drain() {
597
+ if (processing)
598
+ return;
599
+ processing = true;
637
600
  try {
638
- await Promise.race([transition.finished, timeoutPromise]);
601
+ while (queue.length > 0) {
602
+ const item = queue.shift();
603
+ try {
604
+ await runOne(item.callback);
605
+ item.resolve();
606
+ }
607
+ catch (error) {
608
+ item.reject(error);
609
+ }
610
+ }
639
611
  }
640
- catch (error) {
612
+ finally {
613
+ processing = false;
641
614
  }
642
615
  }
643
- function withViewTransition(callback, options = {}) {
616
+ function withViewTransition(callback) {
644
617
  return new Promise((resolve, reject) => {
645
- transitionQueue.push({
646
- callback,
647
- options,
648
- resolve,
649
- reject,
650
- });
651
- processQueue().catch(reject);
618
+ queue.push({ callback, resolve, reject });
619
+ drain().catch(reject);
652
620
  });
653
621
  }
654
622
 
@@ -662,18 +630,6 @@ function isHTMLElement(value) {
662
630
  'classList' in value);
663
631
  }
664
632
 
665
- function isDevMode() {
666
- if (typeof window !== 'undefined' && window.__HYPERFIXI_PROD__) {
667
- return false;
668
- }
669
- if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') {
670
- return false;
671
- }
672
- return true;
673
- }
674
- ({
675
- enabled: isDevMode()});
676
-
677
633
  function executeSwap(target, content, strategy, morphOptions) {
678
634
  const contentStr = content !== null && !isHTMLElement(content) ? content : '';
679
635
  const contentEl = isHTMLElement(content) ? content : null;
@@ -769,6 +725,20 @@ function executeSwap(target, content, strategy, morphOptions) {
769
725
  throw new Error(`[HyperFixi] swap: unknown strategy "${strategy}"`);
770
726
  }
771
727
  }
728
+ async function executeSwapWithTransition(targets, content, strategy, options = {}) {
729
+ const { morphOptions, useViewTransition = false } = options;
730
+ const performSwap = () => {
731
+ for (const target of targets) {
732
+ executeSwap(target, content, strategy, morphOptions);
733
+ }
734
+ };
735
+ if (useViewTransition && isViewTransitionsSupported()) {
736
+ await withViewTransition(performSwap);
737
+ }
738
+ else {
739
+ performSwap();
740
+ }
741
+ }
772
742
 
773
743
  function createCustomEvent(eventName, detail, options = {}) {
774
744
  return new CustomEvent(eventName, {
@@ -829,15 +799,7 @@ function createHistorySwap(config) {
829
799
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
830
800
  }
831
801
  const html = await response.text();
832
- const performSwap = () => {
833
- executeSwap(targetElement, html, strategy);
834
- };
835
- if (useViewTransition && isViewTransitionsSupported()) {
836
- await withViewTransition(performSwap);
837
- }
838
- else {
839
- performSwap();
840
- }
802
+ await executeSwapWithTransition([targetElement], html, strategy, { useViewTransition });
841
803
  targetElement.classList.remove('hx-swapping');
842
804
  if (onAfterSwap) {
843
805
  await onAfterSwap(url, html);
@@ -990,15 +952,7 @@ function createBoosted(config) {
990
952
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
991
953
  }
992
954
  const html = await response.text();
993
- const performSwap = () => {
994
- executeSwap(targetElement, html, strategy);
995
- };
996
- if (useViewTransition && isViewTransitionsSupported()) {
997
- await withViewTransition(performSwap);
998
- }
999
- else {
1000
- performSwap();
1001
- }
955
+ await executeSwapWithTransition([targetElement], html, strategy, { useViewTransition });
1002
956
  targetElement.classList.remove('hx-swapping');
1003
957
  container.classList.remove('hx-boosting');
1004
958
  if (pushUrl && method === 'GET') {
@@ -548,31 +548,14 @@ function longestIncreasingSubsequence(sequence) {
548
548
 
549
549
  //# debugId=3F4BCB911DEC843864756E2164756E21
550
550
 
551
- const morphlexMorph = morph;
552
- const morphlexMorphInner = morphInner;
553
551
  function toMorphlexOptions(options) {
554
- if (!options) {
555
- return { preserveChanges: true };
556
- }
557
- return {
558
- preserveChanges: options.preserveChanges ?? true,
559
- beforeNodeVisited: options.beforeNodeVisited,
560
- afterNodeVisited: options.afterNodeVisited,
561
- beforeNodeAdded: options.beforeNodeAdded
562
- ? (node) => options.beforeNodeAdded(node.parentNode, node, null)
563
- : undefined,
564
- afterNodeAdded: options.afterNodeAdded,
565
- beforeNodeRemoved: options.beforeNodeRemoved,
566
- afterNodeRemoved: options.afterNodeRemoved,
567
- };
552
+ return { preserveChanges: options?.preserveChanges ?? true };
568
553
  }
569
- const morphlexEngine = {
554
+ const morphAdapter = {
570
555
  morph(target, content, options) {
571
- const morphlexOpts = toMorphlexOptions(options);
572
- morphlexMorph(target, content, morphlexOpts);
556
+ morph(target, content, toMorphlexOptions(options));
573
557
  },
574
558
  morphInner(target, content, options) {
575
- const morphlexOpts = toMorphlexOptions(options);
576
559
  let contentEl;
577
560
  if (typeof content === 'string') {
578
561
  const wrapper = document.createElement(target.tagName);
@@ -582,71 +565,56 @@ const morphlexEngine = {
582
565
  else {
583
566
  contentEl = content;
584
567
  }
585
- morphlexMorphInner(target, contentEl, morphlexOpts);
586
- },
587
- };
588
- let currentEngine = morphlexEngine;
589
- const morphAdapter = {
590
- morph(target, content, options) {
591
- currentEngine.morph(target, content, options);
592
- },
593
- morphInner(target, content, options) {
594
- currentEngine.morphInner(target, content, options);
568
+ morphInner(target, contentEl, toMorphlexOptions(options));
595
569
  },
596
570
  };
597
571
 
598
- function isViewTransitionsSupported() {
599
- return (typeof document !== 'undefined' && typeof document.startViewTransition === 'function');
572
+ function getStartViewTransition() {
573
+ if (typeof document === 'undefined')
574
+ return undefined;
575
+ return document
576
+ .startViewTransition;
600
577
  }
601
- let config = {
602
- enabled: isViewTransitionsSupported(),
603
- defaultTimeout: 5000};
604
- let transitionQueue = [];
605
- let isProcessingQueue = false;
606
- async function processQueue() {
607
- if (isProcessingQueue || transitionQueue.length === 0) {
608
- return;
609
- }
610
- isProcessingQueue = true;
611
- while (transitionQueue.length > 0) {
612
- const item = transitionQueue.shift();
613
- try {
614
- await executeTransition(item.callback, item.options);
615
- item.resolve();
616
- }
617
- catch (error) {
618
- item.reject(error);
619
- }
620
- }
621
- isProcessingQueue = false;
578
+ function isViewTransitionsSupported() {
579
+ return typeof getStartViewTransition() === 'function';
622
580
  }
623
- async function executeTransition(callback, options) {
624
- const { skipTransition = false, timeout = config.defaultTimeout } = options;
625
- if (!config.enabled || !isViewTransitionsSupported() || skipTransition) {
581
+ const queue = [];
582
+ let processing = false;
583
+ async function runOne(callback) {
584
+ const start = getStartViewTransition();
585
+ if (!start) {
626
586
  await callback();
627
587
  return;
628
588
  }
629
- const transition = document.startViewTransition(async () => {
589
+ const transition = start(async () => {
630
590
  await callback();
631
591
  });
632
- const timeoutPromise = new Promise((_, reject) => {
633
- setTimeout(() => reject(new Error('View transition timed out')), timeout);
634
- });
592
+ await transition.finished;
593
+ }
594
+ async function drain() {
595
+ if (processing)
596
+ return;
597
+ processing = true;
635
598
  try {
636
- await Promise.race([transition.finished, timeoutPromise]);
599
+ while (queue.length > 0) {
600
+ const item = queue.shift();
601
+ try {
602
+ await runOne(item.callback);
603
+ item.resolve();
604
+ }
605
+ catch (error) {
606
+ item.reject(error);
607
+ }
608
+ }
637
609
  }
638
- catch (error) {
610
+ finally {
611
+ processing = false;
639
612
  }
640
613
  }
641
- function withViewTransition(callback, options = {}) {
614
+ function withViewTransition(callback) {
642
615
  return new Promise((resolve, reject) => {
643
- transitionQueue.push({
644
- callback,
645
- options,
646
- resolve,
647
- reject,
648
- });
649
- processQueue().catch(reject);
616
+ queue.push({ callback, resolve, reject });
617
+ drain().catch(reject);
650
618
  });
651
619
  }
652
620
 
@@ -660,18 +628,6 @@ function isHTMLElement(value) {
660
628
  'classList' in value);
661
629
  }
662
630
 
663
- function isDevMode() {
664
- if (typeof window !== 'undefined' && window.__HYPERFIXI_PROD__) {
665
- return false;
666
- }
667
- if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') {
668
- return false;
669
- }
670
- return true;
671
- }
672
- ({
673
- enabled: isDevMode()});
674
-
675
631
  function executeSwap(target, content, strategy, morphOptions) {
676
632
  const contentStr = content !== null && !isHTMLElement(content) ? content : '';
677
633
  const contentEl = isHTMLElement(content) ? content : null;
@@ -767,6 +723,20 @@ function executeSwap(target, content, strategy, morphOptions) {
767
723
  throw new Error(`[HyperFixi] swap: unknown strategy "${strategy}"`);
768
724
  }
769
725
  }
726
+ async function executeSwapWithTransition(targets, content, strategy, options = {}) {
727
+ const { morphOptions, useViewTransition = false } = options;
728
+ const performSwap = () => {
729
+ for (const target of targets) {
730
+ executeSwap(target, content, strategy, morphOptions);
731
+ }
732
+ };
733
+ if (useViewTransition && isViewTransitionsSupported()) {
734
+ await withViewTransition(performSwap);
735
+ }
736
+ else {
737
+ performSwap();
738
+ }
739
+ }
770
740
 
771
741
  function createCustomEvent(eventName, detail, options = {}) {
772
742
  return new CustomEvent(eventName, {
@@ -827,15 +797,7 @@ function createHistorySwap(config) {
827
797
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
828
798
  }
829
799
  const html = await response.text();
830
- const performSwap = () => {
831
- executeSwap(targetElement, html, strategy);
832
- };
833
- if (useViewTransition && isViewTransitionsSupported()) {
834
- await withViewTransition(performSwap);
835
- }
836
- else {
837
- performSwap();
838
- }
800
+ await executeSwapWithTransition([targetElement], html, strategy, { useViewTransition });
839
801
  targetElement.classList.remove('hx-swapping');
840
802
  if (onAfterSwap) {
841
803
  await onAfterSwap(url, html);
@@ -988,15 +950,7 @@ function createBoosted(config) {
988
950
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
989
951
  }
990
952
  const html = await response.text();
991
- const performSwap = () => {
992
- executeSwap(targetElement, html, strategy);
993
- };
994
- if (useViewTransition && isViewTransitionsSupported()) {
995
- await withViewTransition(performSwap);
996
- }
997
- else {
998
- performSwap();
999
- }
953
+ await executeSwapWithTransition([targetElement], html, strategy, { useViewTransition });
1000
954
  targetElement.classList.remove('hx-swapping');
1001
955
  container.classList.remove('hx-boosting');
1002
956
  if (pushUrl && method === 'GET') {
@@ -315,6 +315,12 @@ const COMMAND_IMPLEMENTATIONS_TS = {
315
315
  for (const el of targets) (el as HTMLElement).blur();
316
316
  return targets;
317
317
  }`,
318
+ empty: `
319
+ case 'empty': {
320
+ const targets = await getTarget();
321
+ for (const el of targets) (el as HTMLElement).innerHTML = '';
322
+ return targets;
323
+ }`,
318
324
  return: `
319
325
  case 'return': {
320
326
  const value = cmd.args[0] ? await evaluate(cmd.args[0], ctx) : ctx.it;
@@ -811,10 +817,31 @@ function evaluatePositional(node: ASTNode, ctx: Context): Element | null {
811
817
  switch (node.position) {
812
818
  case 'first': return elements[0] || null;
813
819
  case 'last': return elements[elements.length - 1] || null;
814
- case 'next': return ctx.me.nextElementSibling;
815
- case 'previous': return ctx.me.previousElementSibling;
816
- case 'closest': return target.value ? ctx.me.closest(target.value) : null;
817
- case 'parent': return ctx.me.parentElement;
820
+ case 'next': {
821
+ if (selector) {
822
+ let el = ctx.me.nextElementSibling;
823
+ while (el) { if (el.matches(selector)) return el; el = el.nextElementSibling; }
824
+ return null;
825
+ }
826
+ return ctx.me.nextElementSibling;
827
+ }
828
+ case 'previous': {
829
+ if (selector) {
830
+ let el = ctx.me.previousElementSibling;
831
+ while (el) { if (el.matches(selector)) return el; el = el.previousElementSibling; }
832
+ return null;
833
+ }
834
+ return ctx.me.previousElementSibling;
835
+ }
836
+ case 'closest': return selector ? ctx.me.closest(selector) : null;
837
+ case 'parent': {
838
+ if (selector) {
839
+ let el = ctx.me.parentElement;
840
+ while (el) { if (el.matches(selector)) return el; el = el.parentElement; }
841
+ return null;
842
+ }
843
+ return ctx.me.parentElement;
844
+ }
818
845
  default: return elements[0] || null;
819
846
  }
820
847
  }
@@ -1321,7 +1348,7 @@ const KEYWORDS = new Set([
1321
1348
  'repeat', 'times', 'for', 'each', 'while', 'until',
1322
1349
  'toggle', 'add', 'remove', 'put', 'set', 'get', 'call', 'return', 'append',
1323
1350
  'log', 'send', 'trigger', 'wait', 'settle', 'fetch', 'as',
1324
- 'show', 'hide', 'take', 'increment', 'decrement', 'focus', 'blur', 'go', 'transition', 'over',
1351
+ 'show', 'hide', 'take', 'increment', 'decrement', 'focus', 'blur', 'empty', 'go', 'transition', 'over',
1325
1352
  'the', 'a', 'an', 'my', 'its', 'me', 'it', 'you',
1326
1353
  'first', 'last', 'next', 'previous', 'closest', 'parent',
1327
1354
  'true', 'false', 'null', 'undefined',
@@ -1628,6 +1655,7 @@ class HybridParser {
1628
1655
  decrement: () => this.parseIncDec('decrement'),
1629
1656
  focus: () => this.parseFocusBlur('focus'),
1630
1657
  blur: () => this.parseFocusBlur('blur'),
1658
+ empty: () => this.parseEmpty(),
1631
1659
  go: () => this.parseGo(),
1632
1660
  return: () => this.parseReturn(),
1633
1661
  transition: () => this.parseTransition(),
@@ -1886,6 +1914,15 @@ class HybridParser {
1886
1914
  return { type: 'command', name, args: [], target };
1887
1915
  }
1888
1916
 
1917
+ parseEmpty() {
1918
+ this.expect('empty');
1919
+ let target;
1920
+ if (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else')) {
1921
+ target = this.parseExpression();
1922
+ }
1923
+ return { type: 'command', name: 'empty', args: [], target };
1924
+ }
1925
+
1889
1926
  parseGo() {
1890
1927
  this.expect('go');
1891
1928
  if (this.match('to')) this.advance();
@@ -1965,7 +2002,7 @@ class HybridParser {
1965
2002
  }
1966
2003
 
1967
2004
  isCommandKeyword(token) {
1968
- const cmds = ['toggle', 'add', 'remove', 'set', 'put', 'log', 'send', 'wait', 'show', 'hide', 'increment', 'decrement', 'focus', 'blur', 'go'];
2005
+ const cmds = ['toggle', 'add', 'remove', 'set', 'put', 'log', 'send', 'wait', 'show', 'hide', 'increment', 'decrement', 'focus', 'blur', 'empty', 'go'];
1969
2006
  return cmds.includes(normalizeCommand(token.value));
1970
2007
  }
1971
2008
 
@@ -2224,6 +2261,7 @@ const AVAILABLE_COMMANDS = [
2224
2261
  'put',
2225
2262
  'append',
2226
2263
  'take',
2264
+ 'empty',
2227
2265
  'set',
2228
2266
  'get',
2229
2267
  'increment',
@@ -313,6 +313,12 @@ const COMMAND_IMPLEMENTATIONS_TS = {
313
313
  for (const el of targets) (el as HTMLElement).blur();
314
314
  return targets;
315
315
  }`,
316
+ empty: `
317
+ case 'empty': {
318
+ const targets = await getTarget();
319
+ for (const el of targets) (el as HTMLElement).innerHTML = '';
320
+ return targets;
321
+ }`,
316
322
  return: `
317
323
  case 'return': {
318
324
  const value = cmd.args[0] ? await evaluate(cmd.args[0], ctx) : ctx.it;
@@ -809,10 +815,31 @@ function evaluatePositional(node: ASTNode, ctx: Context): Element | null {
809
815
  switch (node.position) {
810
816
  case 'first': return elements[0] || null;
811
817
  case 'last': return elements[elements.length - 1] || null;
812
- case 'next': return ctx.me.nextElementSibling;
813
- case 'previous': return ctx.me.previousElementSibling;
814
- case 'closest': return target.value ? ctx.me.closest(target.value) : null;
815
- case 'parent': return ctx.me.parentElement;
818
+ case 'next': {
819
+ if (selector) {
820
+ let el = ctx.me.nextElementSibling;
821
+ while (el) { if (el.matches(selector)) return el; el = el.nextElementSibling; }
822
+ return null;
823
+ }
824
+ return ctx.me.nextElementSibling;
825
+ }
826
+ case 'previous': {
827
+ if (selector) {
828
+ let el = ctx.me.previousElementSibling;
829
+ while (el) { if (el.matches(selector)) return el; el = el.previousElementSibling; }
830
+ return null;
831
+ }
832
+ return ctx.me.previousElementSibling;
833
+ }
834
+ case 'closest': return selector ? ctx.me.closest(selector) : null;
835
+ case 'parent': {
836
+ if (selector) {
837
+ let el = ctx.me.parentElement;
838
+ while (el) { if (el.matches(selector)) return el; el = el.parentElement; }
839
+ return null;
840
+ }
841
+ return ctx.me.parentElement;
842
+ }
816
843
  default: return elements[0] || null;
817
844
  }
818
845
  }
@@ -1319,7 +1346,7 @@ const KEYWORDS = new Set([
1319
1346
  'repeat', 'times', 'for', 'each', 'while', 'until',
1320
1347
  'toggle', 'add', 'remove', 'put', 'set', 'get', 'call', 'return', 'append',
1321
1348
  'log', 'send', 'trigger', 'wait', 'settle', 'fetch', 'as',
1322
- 'show', 'hide', 'take', 'increment', 'decrement', 'focus', 'blur', 'go', 'transition', 'over',
1349
+ 'show', 'hide', 'take', 'increment', 'decrement', 'focus', 'blur', 'empty', 'go', 'transition', 'over',
1323
1350
  'the', 'a', 'an', 'my', 'its', 'me', 'it', 'you',
1324
1351
  'first', 'last', 'next', 'previous', 'closest', 'parent',
1325
1352
  'true', 'false', 'null', 'undefined',
@@ -1626,6 +1653,7 @@ class HybridParser {
1626
1653
  decrement: () => this.parseIncDec('decrement'),
1627
1654
  focus: () => this.parseFocusBlur('focus'),
1628
1655
  blur: () => this.parseFocusBlur('blur'),
1656
+ empty: () => this.parseEmpty(),
1629
1657
  go: () => this.parseGo(),
1630
1658
  return: () => this.parseReturn(),
1631
1659
  transition: () => this.parseTransition(),
@@ -1884,6 +1912,15 @@ class HybridParser {
1884
1912
  return { type: 'command', name, args: [], target };
1885
1913
  }
1886
1914
 
1915
+ parseEmpty() {
1916
+ this.expect('empty');
1917
+ let target;
1918
+ if (!this.isAtEnd() && !this.match('then', 'and', 'end', 'else')) {
1919
+ target = this.parseExpression();
1920
+ }
1921
+ return { type: 'command', name: 'empty', args: [], target };
1922
+ }
1923
+
1887
1924
  parseGo() {
1888
1925
  this.expect('go');
1889
1926
  if (this.match('to')) this.advance();
@@ -1963,7 +2000,7 @@ class HybridParser {
1963
2000
  }
1964
2001
 
1965
2002
  isCommandKeyword(token) {
1966
- const cmds = ['toggle', 'add', 'remove', 'set', 'put', 'log', 'send', 'wait', 'show', 'hide', 'increment', 'decrement', 'focus', 'blur', 'go'];
2003
+ const cmds = ['toggle', 'add', 'remove', 'set', 'put', 'log', 'send', 'wait', 'show', 'hide', 'increment', 'decrement', 'focus', 'blur', 'empty', 'go'];
1967
2004
  return cmds.includes(normalizeCommand(token.value));
1968
2005
  }
1969
2006
 
@@ -2222,6 +2259,7 @@ const AVAILABLE_COMMANDS = [
2222
2259
  'put',
2223
2260
  'append',
2224
2261
  'take',
2262
+ 'empty',
2225
2263
  'set',
2226
2264
  'get',
2227
2265
  'increment',