regor 1.3.4 → 1.3.6

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.
@@ -4,8 +4,8 @@ var bindDataSymbol = Symbol(":regor");
4
4
  // src/cleanup/unbind.ts
5
5
  var unbind = (node) => {
6
6
  const stack = [node];
7
- while (stack.length > 0) {
8
- const currentNode = stack.pop();
7
+ for (let i = 0; i < stack.length; ++i) {
8
+ const currentNode = stack[i];
9
9
  unbindSingle(currentNode);
10
10
  for (let child = currentNode.lastChild; child != null; child = child.previousSibling) {
11
11
  stack.push(child);
@@ -139,24 +139,87 @@ var callUnmounted = (context) => {
139
139
 
140
140
  // src/app/ComponentHead.ts
141
141
  var ComponentHead = class {
142
+ /**
143
+ * Values provided by parent for this component instance.
144
+ *
145
+ * Sources:
146
+ * - declared props via `props: ['foo']` + attribute binding (`:foo="..."`)
147
+ * - object binding via `:context="{ ... }"`
148
+ */
142
149
  props;
150
+ /**
151
+ * Comment node that marks the beginning of this mounted component block.
152
+ * Advanced use only.
153
+ */
143
154
  start;
155
+ /**
156
+ * Comment node that marks the end of this mounted component block.
157
+ * Advanced use only.
158
+ */
144
159
  end;
160
+ /**
161
+ * Captured context chain used by this component instance.
162
+ * Used internally for lifecycle/unmount behavior.
163
+ */
145
164
  ctx;
146
- /** Automatically assigns properties defined in the :props binding to the component context when enabled. If disabled, props should be manually assigned using head.props.
147
- * Default: true */
165
+ /**
166
+ * Controls whether Regor should automatically apply incoming `head.props`
167
+ * values to the component context after `context(head)` returns.
168
+ *
169
+ * Think of it as "auto wire parent inputs into my component fields".
170
+ *
171
+ * - `true` (default):
172
+ * - If a key exists in `head.props` but does not exist on the object
173
+ * returned by `context(head)`, Regor adds that key to component context.
174
+ * - Existing ref fields can receive incoming values automatically.
175
+ * - Ref-to-ref inputs can be entangled when `head.entangle` is enabled.
176
+ * - `false`:
177
+ * - Regor does not auto-apply props.
178
+ * - You fully control mapping manually inside `context(head)`.
179
+ *
180
+ * Use `false` when you need strict custom mapping/validation/transforms
181
+ * before any value touches component state.
182
+ *
183
+ * "Missing key" is always checked against the returned component context object.
184
+ *
185
+ * Example (auto add):
186
+ * ```ts
187
+ * // Parent passes: :context="{ badge: 'pro' }"
188
+ * context(head) {
189
+ * // Returned context has no "badge" key:
190
+ * return { name: ref('Ada') }
191
+ * }
192
+ * // Resulting component context becomes:
193
+ * // { name: ref('Ada'), badge: 'pro' }
194
+ * ```
195
+ *
196
+ * Example:
197
+ * ```ts
198
+ * context(head) {
199
+ * head.autoProps = false
200
+ * const title = ref((head.props.title as string) ?? 'Untitled')
201
+ * return { title }
202
+ * }
203
+ * ```
204
+ */
148
205
  autoProps = true;
149
- /** When both autoProps and entangle are enabled,
150
- * the refs defined in the component context (without using head.props)
151
- * become entangled with the head.props refs. (parent[ref] `<==>` component[ref])
152
- * This means that changes to parent[ref] reflect in component[ref], and vice versa.
153
- * Disable this flag to isolate refs created within the component context.
154
- * Default: true */
206
+ /**
207
+ * Enables two-way ref linking between incoming props and component context
208
+ * when `autoProps` is also enabled.
209
+ *
210
+ * - `true` (default): parent and component refs stay synchronized.
211
+ * - `false`: component keeps local ref isolation.
212
+ */
155
213
  entangle = true;
156
- /** enables slot context switch to the parent
157
- * Default: false */
214
+ /**
215
+ * Enables slot context switch behavior for advanced slot scenarios.
216
+ * Default: `false`.
217
+ */
158
218
  enableSwitch = false;
159
- /** A callback invoked after auto props get assigned to the component context. */
219
+ /**
220
+ * Optional hook called after automatic prop assignment completes.
221
+ * Useful when post-assignment normalization is needed.
222
+ */
160
223
  onAutoPropsAssigned;
161
224
  /**
162
225
  * @internal
@@ -169,12 +232,28 @@ var ComponentHead = class {
169
232
  this.start = start;
170
233
  this.end = end;
171
234
  }
172
- /** use arrow syntax to be called without using head.emit.bind(head) in Binder.ts. */
235
+ /**
236
+ * Emits a custom DOM event from the component host element.
237
+ *
238
+ * Example:
239
+ * ```ts
240
+ * head.emit('saved', { id: 42 })
241
+ * ```
242
+ *
243
+ * Parent markup can listen via regular event binding:
244
+ * ```html
245
+ * <MyComp @saved="onSaved"></MyComp>
246
+ * ```
247
+ */
173
248
  emit = (event, args) => {
174
249
  this.__element.dispatchEvent(
175
250
  new CustomEvent(event, { detail: args })
176
251
  );
177
252
  };
253
+ /**
254
+ * Unmounts this component instance by removing nodes between `start` and `end`
255
+ * and calling unmount lifecycle handlers for captured contexts.
256
+ */
178
257
  unmount() {
179
258
  let next = this.start.nextSibling;
180
259
  const end = this.end;
@@ -276,6 +355,8 @@ var setSwitchOwner = (owner, switchNodes) => {
276
355
  };
277
356
 
278
357
  // src/bind/IfBinder.ts
358
+ var noopStopObserving = () => {
359
+ };
279
360
  var mount = (nodes, binder, parent, end) => {
280
361
  const childNodes = [];
281
362
  for (const x of nodes) {
@@ -400,18 +481,14 @@ var IfBinder = class {
400
481
  const parseResult = this.__binder.__parser.__parse(expression);
401
482
  const value = parseResult.value;
402
483
  const remainingElses = this.__collectElses(nextElement, refresh);
403
- const stopObserverList = [];
484
+ let stopObserver = noopStopObserving;
404
485
  const unbinder = () => {
405
486
  parseResult.stop();
406
- for (const stopObserver of stopObserverList) {
407
- stopObserver();
408
- }
409
- stopObserverList.length = 0;
487
+ stopObserver();
488
+ stopObserver = noopStopObserving;
410
489
  };
411
490
  addUnbinder(commentBegin, unbinder);
412
- const stopObserving = parseResult.subscribe ? parseResult.subscribe(refresh) : () => {
413
- };
414
- stopObserverList.push(stopObserving);
491
+ stopObserver = parseResult.subscribe(refresh);
415
492
  return [
416
493
  {
417
494
  mount: () => {
@@ -422,8 +499,9 @@ var IfBinder = class {
422
499
  },
423
500
  isTrue: () => !!value()[0],
424
501
  isMounted: false
425
- }
426
- ].concat(remainingElses);
502
+ },
503
+ ...remainingElses
504
+ ];
427
505
  }
428
506
  }
429
507
  __bindToExpression(el, expression) {
@@ -469,29 +547,31 @@ var IfBinder = class {
469
547
  });
470
548
  };
471
549
  const collectedElses = this.__collectElses(nextElement, refresh);
472
- const stopObserverList = [];
550
+ let stopObserver = noopStopObserving;
473
551
  const unbinder = () => {
474
552
  parseResult.stop();
475
- for (const stopObserver of stopObserverList) {
476
- stopObserver();
477
- }
478
- stopObserverList.length = 0;
553
+ stopObserver();
554
+ stopObserver = noopStopObserving;
479
555
  };
480
556
  addUnbinder(commentBegin, unbinder);
481
557
  refresh();
482
- const stopObserving = parseResult.subscribe ? parseResult.subscribe(refresh) : () => {
483
- };
484
- stopObserverList.push(stopObserving);
558
+ stopObserver = parseResult.subscribe(refresh);
485
559
  }
486
560
  };
487
561
 
488
562
  // src/common/common.ts
489
563
  var getNodes = (el) => {
490
- const childNodes = isTemplate(el) ? el.content.childNodes : [el];
491
- return Array.from(childNodes).filter((x) => {
492
- const tagName = x?.tagName;
493
- return tagName !== "SCRIPT" && tagName !== "STYLE";
494
- });
564
+ const source = isTemplate(el) ? el.content.childNodes : [el];
565
+ const result = [];
566
+ for (let i = 0; i < source.length; ++i) {
567
+ const node = source[i];
568
+ if (node.nodeType === 1) {
569
+ const tagName = node?.tagName;
570
+ if (tagName === "SCRIPT" || tagName === "STYLE") continue;
571
+ }
572
+ result.push(node);
573
+ }
574
+ return result;
495
575
  };
496
576
  var bindChildNodes = (binder, childNodes) => {
497
577
  for (let i = 0; i < childNodes.length; ++i) {
@@ -588,7 +668,9 @@ var capitalize = cacheStringFunction((str) => {
588
668
  });
589
669
 
590
670
  // src/directives/teleport.ts
591
- var teleportDirective = {};
671
+ var teleportDirective = {
672
+ mount: () => void 0
673
+ };
592
674
 
593
675
  // src/composition/callMounted.ts
594
676
  var callMounted = (context) => {
@@ -622,11 +704,6 @@ var isScope = (value) => {
622
704
  return scopeSymbol2 in value;
623
705
  };
624
706
 
625
- // src/composition/onUnmounted.ts
626
- var onUnmounted = (onUnmounted2, noThrow) => {
627
- peekScope(noThrow)?.onUnmounted.push(onUnmounted2);
628
- };
629
-
630
707
  // src/reactivity/refSymbols.ts
631
708
  var refSymbol = Symbol("ref");
632
709
  var srefSymbol = Symbol("sref");
@@ -637,6 +714,34 @@ var isRef = (value) => {
637
714
  return value != null && value[srefSymbol] === 1;
638
715
  };
639
716
 
717
+ // src/directives/context.ts
718
+ var contextDirective = {
719
+ collectRefObj: true,
720
+ mount: ({ parseResult }) => ({
721
+ update: ({ values }) => {
722
+ const ctx = parseResult.context;
723
+ const obj = values[0];
724
+ if (!isObject(obj)) return;
725
+ for (const item of Object.entries(obj)) {
726
+ const key = item[0];
727
+ const nextValue = item[1];
728
+ const ctxKey = ctx[key];
729
+ if (ctxKey === nextValue) continue;
730
+ if (isRef(ctxKey)) {
731
+ ctxKey(nextValue);
732
+ } else {
733
+ ctx[key] = nextValue;
734
+ }
735
+ }
736
+ }
737
+ })
738
+ };
739
+
740
+ // src/composition/onUnmounted.ts
741
+ var onUnmounted = (onUnmounted2, noThrow) => {
742
+ peekScope(noThrow)?.onUnmounted.push(onUnmounted2);
743
+ };
744
+
640
745
  // src/observer/observe.ts
641
746
  var observe = (source, observer, init, trackUnmount = true) => {
642
747
  if (!isRef(source))
@@ -653,65 +758,6 @@ var observe = (source, observer, init, trackUnmount = true) => {
653
758
  return stop;
654
759
  };
655
760
 
656
- // src/directives/props.ts
657
- var propsDirective = {
658
- collectRefObj: true,
659
- onBind: (_, parseResult) => {
660
- const stopObserving = observe(
661
- parseResult.value,
662
- () => {
663
- const value = parseResult.value();
664
- const ctx = parseResult.context;
665
- const obj = value[0];
666
- if (!isObject(obj)) {
667
- return;
668
- }
669
- for (const item of Object.entries(obj)) {
670
- const key = item[0];
671
- const value2 = item[1];
672
- const ctxKey = ctx[key];
673
- if (ctxKey === value2) continue;
674
- if (isRef(ctxKey)) {
675
- ctxKey(value2);
676
- } else {
677
- ctx[key] = value2;
678
- }
679
- }
680
- },
681
- true
682
- );
683
- return stopObserving;
684
- }
685
- };
686
-
687
- // src/directives/props-once.ts
688
- var propsOnceDirective = {
689
- collectRefObj: true,
690
- once: true,
691
- onBind: (_, parseResult) => {
692
- const value = parseResult.value();
693
- const ctx = parseResult.context;
694
- const obj = value[0];
695
- if (!isObject(obj)) {
696
- return () => {
697
- };
698
- }
699
- for (const item of Object.entries(obj)) {
700
- const key = item[0];
701
- const value2 = item[1];
702
- const ctxKey = ctx[key];
703
- if (ctxKey === value2) continue;
704
- if (isRef(ctxKey)) {
705
- ctxKey(value2);
706
- } else {
707
- ctx[key] = value2;
708
- }
709
- }
710
- return () => {
711
- };
712
- }
713
- };
714
-
715
761
  // src/reactivity/entangle.ts
716
762
  var entangle = (r1, r2) => {
717
763
  if (r1 === r2) return () => {
@@ -1038,8 +1084,8 @@ var createModelBridge = (source) => {
1038
1084
  };
1039
1085
  var singlePropDirective = {
1040
1086
  collectRefObj: true,
1041
- onBind: (_, parseResult, _expr, option, _dynamicOption, _flags) => {
1042
- if (!option) return noop;
1087
+ mount: ({ parseResult, option }) => {
1088
+ if (typeof option !== "string" || !option) return noop;
1043
1089
  const key = camelize(option);
1044
1090
  let currentSource;
1045
1091
  let bridge;
@@ -1060,43 +1106,43 @@ var singlePropDirective = {
1060
1106
  stopEntangle = entangle(source, target);
1061
1107
  currentSource = source;
1062
1108
  };
1063
- const stopObserving = observe(
1064
- parseResult.value,
1065
- () => {
1066
- const value = parseResult.refs[0] ?? parseResult.value()[0];
1067
- const ctx = parseResult.context;
1068
- const ctxKey = ctx[key];
1069
- if (!isRef(value)) {
1070
- if (bridge && ctxKey === bridge) {
1071
- bridge(value);
1072
- return;
1073
- }
1074
- resetSync();
1075
- if (isRef(ctxKey)) {
1076
- ctxKey(value);
1077
- return;
1078
- }
1079
- ctx[key] = value;
1109
+ const apply = () => {
1110
+ const value = parseResult.refs[0] ?? parseResult.value()[0];
1111
+ const ctx = parseResult.context;
1112
+ const ctxKey = ctx[key];
1113
+ if (!isRef(value)) {
1114
+ if (bridge && ctxKey === bridge) {
1115
+ bridge(value);
1080
1116
  return;
1081
1117
  }
1082
- if (isModelBridge(value)) {
1083
- if (ctxKey === value) return;
1084
- if (isRef(ctxKey)) {
1085
- syncRefs(value, ctxKey);
1086
- } else {
1087
- ctx[key] = value;
1088
- }
1118
+ resetSync();
1119
+ if (isRef(ctxKey)) {
1120
+ ctxKey(value);
1089
1121
  return;
1090
1122
  }
1091
- if (!bridge) bridge = createModelBridge(value);
1092
- ctx[key] = bridge;
1093
- syncRefs(value, bridge);
1123
+ ctx[key] = value;
1124
+ return;
1125
+ }
1126
+ if (isModelBridge(value)) {
1127
+ if (ctxKey === value) return;
1128
+ if (isRef(ctxKey)) {
1129
+ syncRefs(value, ctxKey);
1130
+ } else {
1131
+ ctx[key] = value;
1132
+ }
1133
+ return;
1134
+ }
1135
+ if (!bridge) bridge = createModelBridge(value);
1136
+ ctx[key] = bridge;
1137
+ syncRefs(value, bridge);
1138
+ };
1139
+ return {
1140
+ update: () => {
1141
+ apply();
1094
1142
  },
1095
- true
1096
- );
1097
- return () => {
1098
- stopEntangle();
1099
- stopObserving();
1143
+ unmount: () => {
1144
+ stopEntangle();
1145
+ }
1100
1146
  };
1101
1147
  }
1102
1148
  };
@@ -1117,7 +1163,10 @@ var ComponentBinder = class {
1117
1163
  __getRegisteredComponentSelector(registeredComponents) {
1118
1164
  if (this.__registeredComponentSize !== registeredComponents.size) {
1119
1165
  const names = [...registeredComponents.keys()];
1120
- this.__registeredComponentSelector = names.concat(names.map(hyphenate)).join(",");
1166
+ this.__registeredComponentSelector = [
1167
+ ...names,
1168
+ ...names.map(hyphenate)
1169
+ ].join(",");
1121
1170
  this.__registeredComponentSize = registeredComponents.size;
1122
1171
  }
1123
1172
  return this.__registeredComponentSelector;
@@ -1170,18 +1219,19 @@ var ComponentBinder = class {
1170
1219
  const endOfComponent = new Comment(" end component: " + component.tagName);
1171
1220
  componentParent.insertBefore(startOfComponent, component);
1172
1221
  component.remove();
1173
- const propsName = binder.__config.__builtInNames.props;
1174
- const propsOnceName = binder.__config.__builtInNames.propsOnce;
1222
+ const contextName = binder.__config.__builtInNames.context;
1223
+ const contextAliasName = binder.__config.__builtInNames.contextAlias;
1175
1224
  const bindName = binder.__config.__builtInNames.bind;
1176
1225
  const getProps = (component2, capturedContext2) => {
1177
1226
  const props = {};
1178
- const hasProps = component2.hasAttribute(propsName);
1179
- const hasPropsOnce = component2.hasAttribute(propsOnceName);
1227
+ const hasContext = component2.hasAttribute(contextName);
1180
1228
  parser.__scoped(capturedContext2, () => {
1181
1229
  parser.__push(props);
1182
- if (hasProps) binder.__bind(propsDirective, component2, propsName);
1183
- if (hasPropsOnce)
1184
- binder.__bind(propsOnceDirective, component2, propsOnceName);
1230
+ if (hasContext) {
1231
+ binder.__bind(contextDirective, component2, contextName);
1232
+ } else if (component2.hasAttribute(contextAliasName)) {
1233
+ binder.__bind(contextDirective, component2, contextAliasName);
1234
+ }
1185
1235
  let definedProps = registeredComponent.props;
1186
1236
  if (!definedProps || definedProps.length === 0) return;
1187
1237
  definedProps = definedProps.map(camelize);
@@ -1191,7 +1241,10 @@ var ComponentBinder = class {
1191
1241
  definedProp
1192
1242
  ])
1193
1243
  );
1194
- for (const name of definedProps.concat(definedProps.map(hyphenate))) {
1244
+ for (const name of [
1245
+ ...definedProps,
1246
+ ...definedProps.map(hyphenate)
1247
+ ]) {
1195
1248
  const value = component2.getAttribute(name);
1196
1249
  if (value === null) continue;
1197
1250
  props[camelize(name)] = value;
@@ -1236,8 +1289,20 @@ var ComponentBinder = class {
1236
1289
  if (key in componentCtx2) {
1237
1290
  const compValue = componentCtx2[key];
1238
1291
  if (compValue === propsValue) continue;
1239
- if (head2.entangle && isRef(compValue) && isRef(propsValue)) {
1240
- addUnbinder(startOfComponent, entangle(propsValue, compValue));
1292
+ if (isRef(compValue)) {
1293
+ if (isRef(propsValue)) {
1294
+ if (head2.entangle) {
1295
+ addUnbinder(
1296
+ startOfComponent,
1297
+ entangle(propsValue, compValue)
1298
+ );
1299
+ } else {
1300
+ compValue(propsValue());
1301
+ }
1302
+ } else {
1303
+ compValue(propsValue);
1304
+ }
1305
+ continue;
1241
1306
  }
1242
1307
  } else componentCtx2[key] = propsValue;
1243
1308
  }
@@ -1348,7 +1413,8 @@ var ComponentBinder = class {
1348
1413
  const inheritor = inheritorChildNodes[0];
1349
1414
  if (!inheritor) return;
1350
1415
  for (const attrName of component.getAttributeNames()) {
1351
- if (attrName === propsName || attrName === propsOnceName) continue;
1416
+ if (attrName === contextName || attrName === contextAliasName)
1417
+ continue;
1352
1418
  const value = component.getAttribute(attrName);
1353
1419
  if (attrName === "class") {
1354
1420
  inheritor.classList.add(...value.split(" "));
@@ -1471,15 +1537,14 @@ var DirectiveCollector = class {
1471
1537
  const processNode = (node) => {
1472
1538
  const attrs = node.attributes;
1473
1539
  if (!attrs || attrs.length === 0) return;
1474
- const attrsAny = attrs;
1475
1540
  for (let i = 0; i < attrs.length; ++i) {
1476
- const name = (attrsAny[i] ?? attrs.item(i))?.name;
1541
+ const name = attrs.item(i)?.name;
1477
1542
  if (!name) continue;
1478
1543
  appendDirective(node, name);
1479
1544
  }
1480
1545
  };
1481
1546
  processNode(element);
1482
- if (!isRecursive) return map;
1547
+ if (!isRecursive || !element.firstElementChild) return map;
1483
1548
  const nodes = element.querySelectorAll("*");
1484
1549
  for (const node of nodes) {
1485
1550
  processNode(node);
@@ -1489,6 +1554,8 @@ var DirectiveCollector = class {
1489
1554
  };
1490
1555
 
1491
1556
  // src/bind/DynamicBinder.ts
1557
+ var noopStopObserving2 = () => {
1558
+ };
1492
1559
  var mount2 = (nodes, parent) => {
1493
1560
  for (const x of nodes) {
1494
1561
  const node = x.cloneNode(true);
@@ -1603,19 +1670,15 @@ var DynamicBinder = class {
1603
1670
  mounted.name = name;
1604
1671
  });
1605
1672
  };
1606
- const stopObserverList = [];
1673
+ let stopObserver = noopStopObserving2;
1607
1674
  const unbinder = () => {
1608
1675
  parseResult.stop();
1609
- for (const stopObserver of stopObserverList) {
1610
- stopObserver();
1611
- }
1612
- stopObserverList.length = 0;
1676
+ stopObserver();
1677
+ stopObserver = noopStopObserving2;
1613
1678
  };
1614
1679
  addUnbinder(commentBegin, unbinder);
1615
1680
  refresh();
1616
- const stopObserving = parseResult.subscribe ? parseResult.subscribe(refresh) : () => {
1617
- };
1618
- stopObserverList.push(stopObserving);
1681
+ stopObserver = parseResult.subscribe(refresh);
1619
1682
  }
1620
1683
  };
1621
1684
 
@@ -1625,6 +1688,272 @@ var unref = (value) => {
1625
1688
  return anyValue != null && anyValue[srefSymbol] === 1 ? anyValue() : anyValue;
1626
1689
  };
1627
1690
 
1691
+ // src/directives/html.ts
1692
+ var updateHtml = (el, values) => {
1693
+ const [value, replacer] = values;
1694
+ if (isFunction(replacer)) replacer(el, value);
1695
+ else el.innerHTML = value?.toString();
1696
+ };
1697
+ var htmlDirective = {
1698
+ mount: () => ({
1699
+ update: ({ el, values }) => {
1700
+ updateHtml(el, values);
1701
+ }
1702
+ })
1703
+ };
1704
+
1705
+ // src/bind/ForBinderFastPath.ts
1706
+ var ForBinderFastPath = class _ForBinderFastPath {
1707
+ __bindings;
1708
+ constructor(bindings) {
1709
+ this.__bindings = bindings;
1710
+ }
1711
+ static __create(binder, nodes) {
1712
+ const parser = binder.__parser;
1713
+ const config = binder.__config;
1714
+ const builtInNames = config.__builtInNames;
1715
+ const blockedBuiltIns = /* @__PURE__ */ new Set([
1716
+ builtInNames.for,
1717
+ builtInNames.if,
1718
+ builtInNames.else,
1719
+ builtInNames.elseif,
1720
+ builtInNames.pre
1721
+ ]);
1722
+ const directiveMap = config.__directiveMap;
1723
+ const contextComponents = parser.__getComponents();
1724
+ if (Object.keys(contextComponents).length > 0 || config.__componentsUpperCase.size > 0) {
1725
+ return void 0;
1726
+ }
1727
+ const collector = binder.__directiveCollector;
1728
+ const bindings = [];
1729
+ let nodeIndex = 0;
1730
+ const stack = [];
1731
+ for (let i = nodes.length - 1; i >= 0; --i) {
1732
+ stack.push(nodes[i]);
1733
+ }
1734
+ while (stack.length > 0) {
1735
+ const node = stack.pop();
1736
+ if (node.nodeType === Node.ELEMENT_NODE) {
1737
+ const el = node;
1738
+ if (el.tagName === "TEMPLATE") return void 0;
1739
+ if (el.tagName.includes("-")) return void 0;
1740
+ const tagNameUpper = camelize(el.tagName).toUpperCase();
1741
+ if (config.__componentsUpperCase.has(tagNameUpper) || contextComponents[tagNameUpper]) {
1742
+ return void 0;
1743
+ }
1744
+ const attrs = el.attributes;
1745
+ for (let i = 0; i < attrs.length; ++i) {
1746
+ const attrName = attrs.item(i)?.name;
1747
+ if (!attrName) continue;
1748
+ if (blockedBuiltIns.has(attrName)) return void 0;
1749
+ const { terms, flags } = collector.__parseName(attrName);
1750
+ const [name, option] = terms;
1751
+ const directive = directiveMap[attrName] ?? directiveMap[name];
1752
+ if (!directive) continue;
1753
+ if (directive === htmlDirective) return void 0;
1754
+ bindings.push({
1755
+ nodeIndex,
1756
+ attrName,
1757
+ directive,
1758
+ option,
1759
+ flags
1760
+ });
1761
+ }
1762
+ ++nodeIndex;
1763
+ }
1764
+ const children = node.childNodes;
1765
+ for (let i = children.length - 1; i >= 0; --i) {
1766
+ stack.push(children[i]);
1767
+ }
1768
+ }
1769
+ if (bindings.length === 0) return void 0;
1770
+ return new _ForBinderFastPath(bindings);
1771
+ }
1772
+ __bind(binder, nodes) {
1773
+ const elements = [];
1774
+ const stack = [];
1775
+ for (let i = nodes.length - 1; i >= 0; --i) {
1776
+ stack.push(nodes[i]);
1777
+ }
1778
+ while (stack.length > 0) {
1779
+ const node = stack.pop();
1780
+ if (node.nodeType === Node.ELEMENT_NODE) {
1781
+ elements.push(node);
1782
+ }
1783
+ const children = node.childNodes;
1784
+ for (let i = children.length - 1; i >= 0; --i) {
1785
+ stack.push(children[i]);
1786
+ }
1787
+ }
1788
+ for (let i = 0; i < this.__bindings.length; ++i) {
1789
+ const binding = this.__bindings[i];
1790
+ const el = elements[binding.nodeIndex];
1791
+ if (!el) continue;
1792
+ binder.__bind(
1793
+ binding.directive,
1794
+ el,
1795
+ binding.attrName,
1796
+ false,
1797
+ binding.option,
1798
+ binding.flags
1799
+ );
1800
+ }
1801
+ }
1802
+ };
1803
+
1804
+ // src/bind/ForBinderKeyedDiff.ts
1805
+ var moveMountItemBefore = (item, anchor) => {
1806
+ const parent = anchor.parentNode;
1807
+ if (!parent) return;
1808
+ for (let i = 0; i < item.items.length; ++i) {
1809
+ parent.insertBefore(item.items[i], anchor);
1810
+ }
1811
+ };
1812
+ var getSequence = (arr) => {
1813
+ const len = arr.length;
1814
+ const p = arr.slice();
1815
+ const result = [];
1816
+ let u;
1817
+ let v;
1818
+ let c;
1819
+ for (let i = 0; i < len; ++i) {
1820
+ const value = arr[i];
1821
+ if (value === 0) continue;
1822
+ const j = result[result.length - 1];
1823
+ if (j === void 0 || arr[j] < value) {
1824
+ p[i] = j ?? -1;
1825
+ result.push(i);
1826
+ continue;
1827
+ }
1828
+ u = 0;
1829
+ v = result.length - 1;
1830
+ while (u < v) {
1831
+ c = u + v >> 1;
1832
+ if (arr[result[c]] < value) u = c + 1;
1833
+ else v = c;
1834
+ }
1835
+ if (value < arr[result[u]]) {
1836
+ if (u > 0) p[i] = result[u - 1];
1837
+ result[u] = i;
1838
+ }
1839
+ }
1840
+ u = result.length;
1841
+ v = result[u - 1] ?? -1;
1842
+ while (u-- > 0) {
1843
+ result[u] = v;
1844
+ v = p[v];
1845
+ }
1846
+ return result;
1847
+ };
1848
+ var ForBinderKeyedDiff = class {
1849
+ /**
1850
+ * Applies keyed patch and returns the next ordered mount list.
1851
+ * Returns `undefined` when keyed mode is not safe for this update.
1852
+ */
1853
+ static __patch(options) {
1854
+ const {
1855
+ oldItems,
1856
+ newValues,
1857
+ getKey,
1858
+ isSameValue,
1859
+ mountNewValue,
1860
+ removeMountItem,
1861
+ endAnchor
1862
+ } = options;
1863
+ const oldLen = oldItems.length;
1864
+ const newLen = newValues.length;
1865
+ const newKeys = new Array(newLen);
1866
+ const keySeen = /* @__PURE__ */ new Set();
1867
+ for (let i2 = 0; i2 < newLen; ++i2) {
1868
+ const key = getKey(newValues[i2]);
1869
+ if (key === void 0 || keySeen.has(key)) return void 0;
1870
+ keySeen.add(key);
1871
+ newKeys[i2] = key;
1872
+ }
1873
+ const newMountItems = new Array(newLen);
1874
+ let i = 0;
1875
+ let e1 = oldLen - 1;
1876
+ let e2 = newLen - 1;
1877
+ while (i <= e1 && i <= e2) {
1878
+ const oldItem = oldItems[i];
1879
+ if (getKey(oldItem.value) !== newKeys[i]) break;
1880
+ if (!isSameValue(oldItem.value, newValues[i])) break;
1881
+ oldItem.value = newValues[i];
1882
+ newMountItems[i] = oldItem;
1883
+ ++i;
1884
+ }
1885
+ while (i <= e1 && i <= e2) {
1886
+ const oldItem = oldItems[e1];
1887
+ if (getKey(oldItem.value) !== newKeys[e2]) break;
1888
+ if (!isSameValue(oldItem.value, newValues[e2])) break;
1889
+ oldItem.value = newValues[e2];
1890
+ newMountItems[e2] = oldItem;
1891
+ --e1;
1892
+ --e2;
1893
+ }
1894
+ if (i > e1) {
1895
+ for (let k = e2; k >= i; --k) {
1896
+ const anchor = k + 1 < newLen ? newMountItems[k + 1].items[0] : endAnchor;
1897
+ newMountItems[k] = mountNewValue(k, newValues[k], anchor);
1898
+ }
1899
+ return newMountItems;
1900
+ }
1901
+ if (i > e2) {
1902
+ for (let k = i; k <= e1; ++k) removeMountItem(oldItems[k]);
1903
+ return newMountItems;
1904
+ }
1905
+ const s1 = i;
1906
+ const s2 = i;
1907
+ const toBePatched = e2 - s2 + 1;
1908
+ const newIndexToOldIndexMap = new Array(toBePatched).fill(0);
1909
+ const keyToNewIndexMap = /* @__PURE__ */ new Map();
1910
+ for (let k = s2; k <= e2; ++k) {
1911
+ keyToNewIndexMap.set(newKeys[k], k);
1912
+ }
1913
+ let moved = false;
1914
+ let maxNewIndexSoFar = 0;
1915
+ for (let k = s1; k <= e1; ++k) {
1916
+ const oldItem = oldItems[k];
1917
+ const newIndex = keyToNewIndexMap.get(getKey(oldItem.value));
1918
+ if (newIndex === void 0) {
1919
+ removeMountItem(oldItem);
1920
+ continue;
1921
+ }
1922
+ if (!isSameValue(oldItem.value, newValues[newIndex])) {
1923
+ removeMountItem(oldItem);
1924
+ continue;
1925
+ }
1926
+ oldItem.value = newValues[newIndex];
1927
+ newMountItems[newIndex] = oldItem;
1928
+ newIndexToOldIndexMap[newIndex - s2] = k + 1;
1929
+ if (newIndex >= maxNewIndexSoFar) maxNewIndexSoFar = newIndex;
1930
+ else moved = true;
1931
+ }
1932
+ const increasingNewIndexSequence = moved ? getSequence(newIndexToOldIndexMap) : [];
1933
+ let seqIdx = increasingNewIndexSequence.length - 1;
1934
+ for (let k = toBePatched - 1; k >= 0; --k) {
1935
+ const newIndex = s2 + k;
1936
+ const anchor = newIndex + 1 < newLen ? newMountItems[newIndex + 1].items[0] : endAnchor;
1937
+ if (newIndexToOldIndexMap[k] === 0) {
1938
+ newMountItems[newIndex] = mountNewValue(
1939
+ newIndex,
1940
+ newValues[newIndex],
1941
+ anchor
1942
+ );
1943
+ continue;
1944
+ }
1945
+ const item = newMountItems[newIndex];
1946
+ if (!moved) continue;
1947
+ if (seqIdx >= 0 && increasingNewIndexSequence[seqIdx] === k) {
1948
+ --seqIdx;
1949
+ } else if (item) {
1950
+ moveMountItemBefore(item, anchor);
1951
+ }
1952
+ }
1953
+ return newMountItems;
1954
+ }
1955
+ };
1956
+
1628
1957
  // src/bind/MountList.ts
1629
1958
  var MountList = class {
1630
1959
  __list = [];
@@ -1704,6 +2033,8 @@ var MountList = class {
1704
2033
  // src/bind/ForBinder.ts
1705
2034
  var forMarker = Symbol("r-for");
1706
2035
  var noIndexRef = (_) => -1;
2036
+ var noopStopObserving3 = () => {
2037
+ };
1707
2038
  var ForBinder = class _ForBinder {
1708
2039
  __binder;
1709
2040
  __for;
@@ -1773,6 +2104,7 @@ var ForBinder = class _ForBinder {
1773
2104
  el.removeAttribute(nameKey);
1774
2105
  el.removeAttribute(nameKeyBind);
1775
2106
  const nodes = getNodes(el);
2107
+ const fastPath = ForBinderFastPath.__create(this.__binder, nodes);
1776
2108
  const parent = el.parentNode;
1777
2109
  if (!parent) return;
1778
2110
  const title = `${this.__for} => ${forPath}`;
@@ -1792,6 +2124,7 @@ var ForBinder = class _ForBinder {
1792
2124
  const rowContexts = singleCapturedContext ? [void 0, capturedContext[0]] : void 0;
1793
2125
  const getKey = this.__createKeyGetter(keyExpression);
1794
2126
  const areEqual = (a, b) => getKey(a) === getKey(b);
2127
+ const isSameValue = (a, b) => a === b;
1795
2128
  const mountNewValue = (i2, newValue, nextSibling) => {
1796
2129
  const result = config.createContext(newValue, i2);
1797
2130
  const mountItem = MountList.__createItem(result.index, newValue);
@@ -1804,7 +2137,8 @@ var ForBinder = class _ForBinder {
1804
2137
  insertParent.insertBefore(node, nextSibling);
1805
2138
  childNodes.push(node);
1806
2139
  }
1807
- bindChildNodes(binder, childNodes);
2140
+ if (fastPath) fastPath.__bind(binder, childNodes);
2141
+ else bindChildNodes(binder, childNodes);
1808
2142
  start = start.nextSibling;
1809
2143
  while (start !== nextSibling) {
1810
2144
  mountItem.items.push(start);
@@ -1856,16 +2190,51 @@ var ForBinder = class _ForBinder {
1856
2190
  mountList.__removeAllAfter(0);
1857
2191
  return;
1858
2192
  }
2193
+ const iterableValues = [];
2194
+ for (const value2 of this.__getIterable(newValues[0])) {
2195
+ iterableValues.push(value2);
2196
+ }
2197
+ const patched = ForBinderKeyedDiff.__patch({
2198
+ oldItems: mountList.__list,
2199
+ newValues: iterableValues,
2200
+ getKey,
2201
+ isSameValue,
2202
+ mountNewValue: (index, value2, nextSibling) => mountNewValue(index, value2, nextSibling),
2203
+ removeMountItem: (item) => {
2204
+ for (let k = 0; k < item.items.length; ++k) {
2205
+ removeNode(item.items[k]);
2206
+ }
2207
+ },
2208
+ endAnchor: commentEnd
2209
+ });
2210
+ if (patched) {
2211
+ mountList.__list = patched;
2212
+ mountList.__valueMap.clear();
2213
+ for (let k = 0; k < patched.length; ++k) {
2214
+ const item = patched[k];
2215
+ item.order = k;
2216
+ item.index(k);
2217
+ const key = getKey(item.value);
2218
+ if (key !== void 0) {
2219
+ mountList.__valueMap.set(key, item);
2220
+ }
2221
+ }
2222
+ return;
2223
+ }
1859
2224
  let i2 = 0;
1860
2225
  let firstRemovalOrInsertionIndex = Number.MAX_SAFE_INTEGER;
1861
2226
  const initialLength = len;
1862
2227
  const forGrowThreshold = this.__binder.__config.forGrowThreshold;
1863
2228
  const shouldGrowList = () => mountList.__length < initialLength + forGrowThreshold;
1864
- for (const newValue of this.__getIterable(newValues[0])) {
2229
+ for (const newValue of iterableValues) {
1865
2230
  const modify = () => {
1866
2231
  if (i2 < len) {
1867
2232
  const mountItem = mountList.__get(i2++);
1868
- if (areEqual(mountItem.value, newValue)) return;
2233
+ if (areEqual(mountItem.value, newValue)) {
2234
+ if (isSameValue(mountItem.value, newValue)) return;
2235
+ replace(i2 - 1, newValue);
2236
+ return;
2237
+ }
1869
2238
  const newValueMountPosition = mountList.__lookupValueOrderIfMounted(
1870
2239
  getKey(newValue)
1871
2240
  );
@@ -1915,24 +2284,21 @@ var ForBinder = class _ForBinder {
1915
2284
  mountList.__removeAllAfter(j);
1916
2285
  updateIndexes(firstRemovalOrInsertionIndex);
1917
2286
  };
1918
- const observeTailChanges = () => {
1919
- stopObserving = parseResult.subscribe ? parseResult.subscribe(updateDom) : () => {
1920
- };
1921
- };
1922
2287
  const unbinder = () => {
1923
2288
  parseResult.stop();
1924
2289
  stopObserving();
2290
+ stopObserving = noopStopObserving3;
1925
2291
  };
1926
2292
  const parseResult = parser.__parse(config.list);
1927
2293
  const value = parseResult.value;
1928
- let stopObserving;
2294
+ let stopObserving = noopStopObserving3;
1929
2295
  let i = 0;
1930
2296
  const mountList = new MountList(getKey);
1931
2297
  for (const item of this.__getIterable(value()[0])) {
1932
2298
  mountList.__push(mountNewValue(i++, item, commentEnd));
1933
2299
  }
1934
2300
  addUnbinder(commentBegin, unbinder);
1935
- observeTailChanges();
2301
+ stopObserving = parseResult.subscribe(updateDom);
1936
2302
  }
1937
2303
  static __forPathRegex = /\{?\[?\(?([^)}\]]+)\)?\]?\}?([^)]+)?\s+\b(?:in|of)\b\s+(.*)\s*$/;
1938
2304
  __parseForPath(forPath) {
@@ -2111,97 +2477,108 @@ var Binder = class {
2111
2477
  __bindToExpression(config, el, valueExpression, option, flags) {
2112
2478
  if (el.nodeType !== Node.ELEMENT_NODE || valueExpression == null) return;
2113
2479
  if (this.__handleTeleport(config, el, valueExpression)) return;
2114
- const result = this.__parser.__parse(
2480
+ const dynamicOption = this.__parseDynamicOption(option, config.once);
2481
+ const result = this.__parseExpression(config, valueExpression);
2482
+ const stops = this.__createBindStops(result, dynamicOption);
2483
+ addUnbinder(el, stops.stop);
2484
+ const payload = this.__createDirectivePayload(
2485
+ el,
2486
+ valueExpression,
2487
+ result,
2488
+ dynamicOption,
2489
+ option,
2490
+ flags
2491
+ );
2492
+ const mountedUpdate = this.__mountDirective(config, payload, stops);
2493
+ if (!mountedUpdate) return;
2494
+ const emitChange = this.__createEmitter(
2495
+ payload,
2496
+ result,
2497
+ dynamicOption,
2498
+ option,
2499
+ mountedUpdate
2500
+ );
2501
+ emitChange();
2502
+ if (!config.once) {
2503
+ stops.result = result.subscribe(emitChange);
2504
+ if (dynamicOption) {
2505
+ stops.dynamic = dynamicOption.subscribe(emitChange);
2506
+ }
2507
+ }
2508
+ }
2509
+ __parseDynamicOption(option, once) {
2510
+ const dynamicOptionExpression = isOptionDynamic(option, this.__dynamic);
2511
+ if (!dynamicOptionExpression) return void 0;
2512
+ return this.__parser.__parse(
2513
+ camelize(dynamicOptionExpression),
2514
+ void 0,
2515
+ void 0,
2516
+ void 0,
2517
+ once
2518
+ );
2519
+ }
2520
+ __parseExpression(config, valueExpression) {
2521
+ return this.__parser.__parse(
2115
2522
  valueExpression,
2116
2523
  config.isLazy,
2117
2524
  config.isLazyKey,
2118
2525
  config.collectRefObj,
2119
2526
  config.once
2120
2527
  );
2121
- const stopObserverList = [];
2122
- const hasOnChange = !!config.onChange;
2123
- const unbinder = () => {
2124
- result.stop();
2125
- dynamicOption?.stop();
2126
- for (let i = 0; i < stopObserverList.length; ++i) {
2127
- stopObserverList[i]();
2528
+ }
2529
+ __createBindStops(result, dynamicOption) {
2530
+ const stops = {
2531
+ stop: () => {
2532
+ result.stop();
2533
+ dynamicOption?.stop();
2534
+ stops.result?.();
2535
+ stops.dynamic?.();
2536
+ stops.mounted?.();
2537
+ stops.result = void 0;
2538
+ stops.dynamic = void 0;
2539
+ stops.mounted = void 0;
2128
2540
  }
2129
- stopObserverList.length = 0;
2130
2541
  };
2131
- addUnbinder(el, unbinder);
2132
- const dynamicOptionExpression = isOptionDynamic(option, this.__dynamic);
2133
- let dynamicOption;
2134
- if (dynamicOptionExpression) {
2135
- dynamicOption = this.__parser.__parse(
2136
- camelize(dynamicOptionExpression),
2137
- void 0,
2138
- void 0,
2139
- void 0,
2140
- config.once
2141
- );
2542
+ return stops;
2543
+ }
2544
+ __createDirectivePayload(el, expr, result, dynamicOption, option, flags) {
2545
+ return {
2546
+ el,
2547
+ expr,
2548
+ values: result.value(),
2549
+ previousValues: void 0,
2550
+ option: dynamicOption ? dynamicOption.value()[0] : option,
2551
+ previousOption: void 0,
2552
+ flags,
2553
+ parseResult: result,
2554
+ dynamicOption
2555
+ };
2556
+ }
2557
+ __mountDirective(config, payload, stops) {
2558
+ const mounted = config.mount(payload);
2559
+ if (typeof mounted === "function") {
2560
+ stops.mounted = mounted;
2561
+ return void 0;
2142
2562
  }
2143
- const dynamicOpt = dynamicOption;
2144
- const hasDynamicOption = dynamicOpt != null;
2145
- let previousValues = result.value();
2146
- let previousOption = hasDynamicOption ? dynamicOption.value()[0] : option;
2147
- if (!config.once && hasOnChange) {
2148
- const stopObserving = result.subscribe ? result.subscribe(() => {
2149
- const preValues = previousValues;
2150
- const preOption = previousOption;
2151
- const nextValues = result.value();
2152
- const nextOption = hasDynamicOption ? dynamicOpt.value()[0] : option;
2153
- previousValues = nextValues;
2154
- previousOption = nextOption;
2155
- config.onChange?.(
2156
- el,
2157
- nextValues,
2158
- preValues,
2159
- nextOption,
2160
- preOption,
2161
- flags
2162
- );
2163
- }) : () => {
2164
- };
2165
- stopObserverList.push(stopObserving);
2166
- if (dynamicOpt) {
2167
- const stopObserving2 = dynamicOpt.subscribe ? dynamicOpt.subscribe(() => {
2168
- const preOption = previousOption;
2169
- const nextValues = result.value();
2170
- const nextOption = dynamicOpt.value()[0];
2171
- previousValues = nextValues;
2172
- previousOption = nextOption;
2173
- config.onChange?.(
2174
- el,
2175
- nextValues,
2176
- preOption,
2177
- nextOption,
2178
- preOption,
2179
- flags
2180
- );
2181
- }) : () => {
2182
- };
2183
- stopObserverList.push(stopObserving2);
2184
- }
2563
+ if (mounted?.unmount) {
2564
+ stops.mounted = mounted.unmount;
2185
2565
  }
2186
- if (config.onBind)
2187
- stopObserverList.push(
2188
- config.onBind(
2189
- el,
2190
- result,
2191
- valueExpression,
2192
- option,
2193
- dynamicOption,
2194
- flags
2195
- )
2196
- );
2197
- config.onChange?.(
2198
- el,
2199
- previousValues,
2200
- void 0,
2201
- previousOption,
2202
- void 0,
2203
- flags
2204
- );
2566
+ return mounted?.update;
2567
+ }
2568
+ __createEmitter(payload, result, dynamicOption, option, mountedUpdate) {
2569
+ let previousValues;
2570
+ let previousOption;
2571
+ return () => {
2572
+ const nextValues = result.value();
2573
+ const nextOption = dynamicOption ? dynamicOption.value()[0] : option;
2574
+ payload.values = nextValues;
2575
+ payload.previousValues = previousValues;
2576
+ payload.option = nextOption;
2577
+ payload.previousOption = previousOption;
2578
+ previousValues = nextValues;
2579
+ previousOption = nextOption;
2580
+ mountedUpdate(payload);
2581
+ };
2205
2582
  }
2206
2583
  };
2207
2584
 
@@ -2238,38 +2615,50 @@ var booleanAttributes = {
2238
2615
  function includeBooleanAttr(value) {
2239
2616
  return !!value || value === "";
2240
2617
  }
2241
- var attrDirective = {
2242
- onChange: (el, values, previousValues, option, previousOption, flags) => {
2243
- if (option) {
2244
- if (flags && flags.includes("camel")) option = camelize(option);
2245
- patchAttribute(el, option, values[0], previousOption);
2246
- return;
2247
- }
2248
- const len = values.length;
2249
- for (let i = 0; i < len; ++i) {
2250
- const next = values[i];
2251
- if (isArray(next)) {
2252
- const previousKey = previousValues?.[i]?.[0];
2253
- const key = next[0];
2254
- const value = next[1];
2255
- patchAttribute(el, key, value, previousKey);
2256
- } else if (isObject(next)) {
2257
- for (const item of Object.entries(next)) {
2258
- const key = item[0];
2259
- const value = item[1];
2260
- const p = previousValues?.[i];
2261
- const previousKey = p && key in p ? key : void 0;
2262
- patchAttribute(el, key, value, previousKey);
2263
- }
2264
- } else {
2265
- const previousKey = previousValues?.[i];
2266
- const key = values[i++];
2267
- const value = values[i];
2618
+ var updateAttr = (el, values, previousValues, option, previousOption, flags) => {
2619
+ if (option) {
2620
+ if (flags && flags.includes("camel")) option = camelize(option);
2621
+ patchAttribute(el, option, values[0], previousOption);
2622
+ return;
2623
+ }
2624
+ const len = values.length;
2625
+ for (let i = 0; i < len; ++i) {
2626
+ const next = values[i];
2627
+ if (isArray(next)) {
2628
+ const previousKey = previousValues?.[i]?.[0];
2629
+ const key = next[0];
2630
+ const value = next[1];
2631
+ patchAttribute(el, key, value, previousKey);
2632
+ } else if (isObject(next)) {
2633
+ for (const item of Object.entries(next)) {
2634
+ const key = item[0];
2635
+ const value = item[1];
2636
+ const p = previousValues?.[i];
2637
+ const previousKey = p && key in p ? key : void 0;
2268
2638
  patchAttribute(el, key, value, previousKey);
2269
2639
  }
2640
+ } else {
2641
+ const previousKey = previousValues?.[i];
2642
+ const key = values[i++];
2643
+ const value = values[i];
2644
+ patchAttribute(el, key, value, previousKey);
2270
2645
  }
2271
2646
  }
2272
2647
  };
2648
+ var attrDirective = {
2649
+ mount: () => ({
2650
+ update: ({ el, values, previousValues, option, previousOption, flags }) => {
2651
+ updateAttr(
2652
+ el,
2653
+ values,
2654
+ previousValues,
2655
+ option,
2656
+ previousOption,
2657
+ flags
2658
+ );
2659
+ }
2660
+ })
2661
+ };
2273
2662
  var patchAttribute = (el, key, value, previousKey) => {
2274
2663
  if (previousKey && previousKey !== key) {
2275
2664
  el.removeAttribute(previousKey);
@@ -2303,23 +2692,28 @@ var patchAttribute = (el, key, value, previousKey) => {
2303
2692
  };
2304
2693
 
2305
2694
  // src/directives/class.ts
2306
- var classDirective = {
2307
- onChange: (el, values, previousValues) => {
2308
- const len = values.length;
2309
- for (let i = 0; i < len; ++i) {
2310
- const next = values[i];
2311
- const previous = previousValues?.[i];
2312
- if (isArray(next)) {
2313
- const len2 = next.length;
2314
- for (let j = 0; j < len2; ++j) {
2315
- patchClass(el, next[j], previous?.[j]);
2316
- }
2317
- } else {
2318
- patchClass(el, next, previous);
2695
+ var updateClass = (el, values, previousValues) => {
2696
+ const len = values.length;
2697
+ for (let i = 0; i < len; ++i) {
2698
+ const next = values[i];
2699
+ const previous = previousValues?.[i];
2700
+ if (isArray(next)) {
2701
+ const len2 = next.length;
2702
+ for (let j = 0; j < len2; ++j) {
2703
+ patchClass(el, next[j], previous?.[j]);
2319
2704
  }
2705
+ } else {
2706
+ patchClass(el, next, previous);
2320
2707
  }
2321
2708
  }
2322
2709
  };
2710
+ var classDirective = {
2711
+ mount: () => ({
2712
+ update: ({ el, values, previousValues }) => {
2713
+ updateClass(el, values, previousValues);
2714
+ }
2715
+ })
2716
+ };
2323
2717
  var patchClass = (el, next, prev) => {
2324
2718
  const classList = el.classList;
2325
2719
  const isClassString = isString(next);
@@ -2347,15 +2741,6 @@ var patchClass = (el, next, prev) => {
2347
2741
  }
2348
2742
  };
2349
2743
 
2350
- // src/directives/html.ts
2351
- var htmlDirective = {
2352
- onChange: (el, values) => {
2353
- const [value, replacer] = values;
2354
- if (isFunction(replacer)) replacer(el, value);
2355
- else el.innerHTML = value?.toString();
2356
- }
2357
- };
2358
-
2359
2744
  // src/common/looseEqual.ts
2360
2745
  function looseCompareArrays(a, b) {
2361
2746
  if (a.length !== b.length) return false;
@@ -2428,12 +2813,12 @@ var resume = (source) => {
2428
2813
 
2429
2814
  // src/directives/model.ts
2430
2815
  var modelDirective = {
2431
- onChange: (el, values) => {
2432
- updateDomElementValue(el, values[0]);
2433
- },
2434
- onBind: (el, parseResult, _expr, _option, _dynamicOption, flags) => {
2435
- return attachDOMChangeListener(el, parseResult, flags);
2436
- }
2816
+ mount: ({ el, parseResult, flags }) => ({
2817
+ update: ({ values }) => {
2818
+ updateDomElementValue(el, values[0]);
2819
+ },
2820
+ unmount: attachDOMChangeListener(el, parseResult, flags)
2821
+ })
2437
2822
  };
2438
2823
  var updateDomElementValue = (el, value) => {
2439
2824
  const isAnInput = isInput(el);
@@ -2739,65 +3124,74 @@ var getFlags2 = (flags) => {
2739
3124
  }
2740
3125
  return result;
2741
3126
  };
3127
+ var bindOn = (el, parseResult, option, dynamicOption, flags) => {
3128
+ if (dynamicOption) {
3129
+ const values2 = parseResult.value();
3130
+ const option2 = unref(dynamicOption.value()[0]);
3131
+ if (!isString(option2)) return () => {
3132
+ };
3133
+ return attachEventListener(
3134
+ el,
3135
+ camelize(option2),
3136
+ () => parseResult.value()[0],
3137
+ flags?.join(",") ?? values2[1]
3138
+ );
3139
+ } else if (option) {
3140
+ const values2 = parseResult.value();
3141
+ return attachEventListener(
3142
+ el,
3143
+ camelize(option),
3144
+ () => parseResult.value()[0],
3145
+ flags?.join(",") ?? values2[1]
3146
+ );
3147
+ }
3148
+ const unbinders = [];
3149
+ const unbinder = () => {
3150
+ unbinders.forEach((x) => x());
3151
+ };
3152
+ const values = parseResult.value();
3153
+ const len = values.length;
3154
+ for (let i = 0; i < len; ++i) {
3155
+ let next = values[i];
3156
+ if (isFunction(next)) next = next();
3157
+ if (isObject(next)) {
3158
+ for (const item of Object.entries(next)) {
3159
+ const eventType = item[0];
3160
+ const method = () => {
3161
+ let obj = parseResult.value()[i];
3162
+ if (isFunction(obj)) obj = obj();
3163
+ obj = obj[eventType];
3164
+ if (isFunction(obj)) obj = obj();
3165
+ return obj;
3166
+ };
3167
+ const flags2 = next[eventType + "_flags"];
3168
+ unbinders.push(attachEventListener(el, eventType, method, flags2));
3169
+ }
3170
+ } else {
3171
+ warning(2 /* BindingRequiresObjectExpressions */, "r-on", el);
3172
+ }
3173
+ }
3174
+ return unbinder;
3175
+ };
2742
3176
  var onDirective = {
2743
3177
  isLazy: (i, d) => d === -1 && i % 2 === 0,
2744
3178
  isLazyKey: (key, d) => d === 0 && !key.endsWith("_flags"),
2745
3179
  once: false,
2746
3180
  collectRefObj: true,
2747
- onBind: (el, parseResult, _expr, option, dynamicOption, flags) => {
2748
- if (dynamicOption) {
2749
- const values2 = parseResult.value();
2750
- const option2 = unref(dynamicOption.value()[0]);
2751
- if (!isString(option2)) return () => {
2752
- };
2753
- return attachEventListener(
2754
- el,
2755
- camelize(option2),
2756
- () => parseResult.value()[0],
2757
- flags?.join(",") ?? values2[1]
2758
- );
2759
- } else if (option) {
2760
- const values2 = parseResult.value();
2761
- return attachEventListener(
2762
- el,
2763
- camelize(option),
2764
- () => parseResult.value()[0],
2765
- flags?.join(",") ?? values2[1]
2766
- );
2767
- }
2768
- const unbinders = [];
2769
- const unbinder = () => {
2770
- unbinders.forEach((x) => x());
2771
- };
2772
- const values = parseResult.value();
2773
- const len = values.length;
2774
- for (let i = 0; i < len; ++i) {
2775
- let next = values[i];
2776
- if (isFunction(next)) next = next();
2777
- if (isObject(next)) {
2778
- for (const item of Object.entries(next)) {
2779
- const eventType = item[0];
2780
- const method = () => {
2781
- let obj = parseResult.value()[i];
2782
- if (isFunction(obj)) obj = obj();
2783
- obj = obj[eventType];
2784
- if (isFunction(obj)) obj = obj();
2785
- return obj;
2786
- };
2787
- const flags2 = next[eventType + "_flags"];
2788
- unbinders.push(attachEventListener(el, eventType, method, flags2));
2789
- }
2790
- } else {
2791
- warning(2 /* BindingRequiresObjectExpressions */, "r-on", el);
2792
- }
2793
- }
2794
- return unbinder;
3181
+ mount: ({ el, parseResult, option, dynamicOption, flags }) => {
3182
+ return bindOn(
3183
+ el,
3184
+ parseResult,
3185
+ option,
3186
+ dynamicOption,
3187
+ flags
3188
+ );
2795
3189
  }
2796
3190
  };
2797
3191
  var getShouldExecuteEvent = (eventType, flags) => {
2798
3192
  if (eventType.startsWith("keydown") || eventType.startsWith("keyup") || eventType.startsWith("keypress")) {
2799
3193
  flags ??= "";
2800
- const parts = eventType.split(".").concat(flags.split(","));
3194
+ const parts = [...eventType.split("."), ...flags.split(",")];
2801
3195
  eventType = parts[0];
2802
3196
  const keyType = parts[1];
2803
3197
  const isCtrl = parts.includes("ctrl");
@@ -2870,34 +3264,39 @@ var attachEventListener = (el, eventType, method, flags) => {
2870
3264
  };
2871
3265
 
2872
3266
  // src/directives/prop.ts
2873
- var propDirective = {
2874
- onChange: (el, values, _previousValues, option, _previousOption, flags) => {
2875
- if (option) {
2876
- if (flags && flags.includes("camel")) option = camelize(option);
2877
- patchProp(el, option, values[0]);
2878
- return;
2879
- }
2880
- const len = values.length;
2881
- for (let i = 0; i < len; ++i) {
2882
- const next = values[i];
2883
- if (isArray(next)) {
2884
- const key = next[0];
2885
- const value = next[1];
2886
- patchProp(el, key, value);
2887
- } else if (isObject(next)) {
2888
- for (const item of Object.entries(next)) {
2889
- const key = item[0];
2890
- const value = item[1];
2891
- patchProp(el, key, value);
2892
- }
2893
- } else {
2894
- const key = values[i++];
2895
- const value = values[i];
3267
+ var updatePropBinding = (el, values, option, flags) => {
3268
+ if (option) {
3269
+ if (flags && flags.includes("camel")) option = camelize(option);
3270
+ patchProp(el, option, values[0]);
3271
+ return;
3272
+ }
3273
+ const len = values.length;
3274
+ for (let i = 0; i < len; ++i) {
3275
+ const next = values[i];
3276
+ if (isArray(next)) {
3277
+ const key = next[0];
3278
+ const value = next[1];
3279
+ patchProp(el, key, value);
3280
+ } else if (isObject(next)) {
3281
+ for (const item of Object.entries(next)) {
3282
+ const key = item[0];
3283
+ const value = item[1];
2896
3284
  patchProp(el, key, value);
2897
3285
  }
3286
+ } else {
3287
+ const key = values[i++];
3288
+ const value = values[i];
3289
+ patchProp(el, key, value);
2898
3290
  }
2899
3291
  }
2900
3292
  };
3293
+ var propDirective = {
3294
+ mount: () => ({
3295
+ update: ({ el, values, option, flags }) => {
3296
+ updatePropBinding(el, values, option, flags);
3297
+ }
3298
+ })
3299
+ };
2901
3300
  function includeBooleanAttr2(value) {
2902
3301
  return !!value || value === "";
2903
3302
  }
@@ -2952,7 +3351,8 @@ var patchProp = (el, key, value) => {
2952
3351
  // src/directives/ref.ts
2953
3352
  var refDirective = {
2954
3353
  once: true,
2955
- onBind: (el, result, expr) => {
3354
+ mount: ({ el, parseResult, expr }) => {
3355
+ const result = parseResult;
2956
3356
  const value = result.value()[0];
2957
3357
  const isAnArray = isArray(value);
2958
3358
  const sref2 = result.refs[0];
@@ -2969,37 +3369,47 @@ var refDirective = {
2969
3369
  };
2970
3370
 
2971
3371
  // src/directives/show.ts
3372
+ var updateShow = (el, values) => {
3373
+ const data = getBindData(el).data;
3374
+ let originalDisplay = data._ord;
3375
+ if (isUndefined(originalDisplay)) {
3376
+ originalDisplay = data._ord = el.style.display;
3377
+ }
3378
+ const isVisible = !!values[0];
3379
+ if (isVisible) el.style.display = originalDisplay;
3380
+ else el.style.display = "none";
3381
+ };
2972
3382
  var showDirective = {
2973
- onChange: (el, values) => {
2974
- const data = getBindData(el).data;
2975
- let originalDisplay = data._ord;
2976
- if (isUndefined(originalDisplay)) {
2977
- originalDisplay = data._ord = el.style.display;
3383
+ mount: () => ({
3384
+ update: ({ el, values }) => {
3385
+ updateShow(el, values);
2978
3386
  }
2979
- const isVisible = !!values[0];
2980
- if (isVisible) el.style.display = originalDisplay;
2981
- else el.style.display = "none";
2982
- }
3387
+ })
2983
3388
  };
2984
3389
 
2985
3390
  // src/directives/style.ts
2986
- var styleDirective = {
2987
- onChange: (el, values, previousValues) => {
2988
- const len = values.length;
2989
- for (let i = 0; i < len; ++i) {
2990
- const next = values[i];
2991
- const previous = previousValues?.[i];
2992
- if (isArray(next)) {
2993
- const len2 = next.length;
2994
- for (let j = 0; j < len2; ++j) {
2995
- patchStyle(el, next[j], previous?.[j]);
2996
- }
2997
- } else {
2998
- patchStyle(el, next, previous);
3391
+ var updateStyle = (el, values, previousValues) => {
3392
+ const len = values.length;
3393
+ for (let i = 0; i < len; ++i) {
3394
+ const next = values[i];
3395
+ const previous = previousValues?.[i];
3396
+ if (isArray(next)) {
3397
+ const len2 = next.length;
3398
+ for (let j = 0; j < len2; ++j) {
3399
+ patchStyle(el, next[j], previous?.[j]);
2999
3400
  }
3401
+ } else {
3402
+ patchStyle(el, next, previous);
3000
3403
  }
3001
3404
  }
3002
3405
  };
3406
+ var styleDirective = {
3407
+ mount: () => ({
3408
+ update: ({ el, values, previousValues }) => {
3409
+ updateStyle(el, values, previousValues);
3410
+ }
3411
+ })
3412
+ };
3003
3413
  var patchStyle = (el, next, prev) => {
3004
3414
  const style = el.style;
3005
3415
  const isCssString = isString(next);
@@ -3107,18 +3517,25 @@ var flattenContent = (value, weakMap = /* @__PURE__ */ new WeakMap()) => {
3107
3517
  };
3108
3518
 
3109
3519
  // src/directives/text.ts
3520
+ var updateText = (el, values) => {
3521
+ const value = values[0];
3522
+ el.textContent = isSet(value) ? JSON.stringify(flatten([...value])) : isMap(value) ? JSON.stringify(flatten([...value])) : isObject(value) ? JSON.stringify(flatten(value)) : value?.toString() ?? "";
3523
+ };
3110
3524
  var textDirective = {
3111
- onChange: (el, values) => {
3112
- const value = values[0];
3113
- el.textContent = isSet(value) ? JSON.stringify(flatten([...value])) : isMap(value) ? JSON.stringify(flatten([...value])) : isObject(value) ? JSON.stringify(flatten(value)) : value?.toString() ?? "";
3114
- }
3525
+ mount: () => ({
3526
+ update: ({ el, values }) => {
3527
+ updateText(el, values);
3528
+ }
3529
+ })
3115
3530
  };
3116
3531
 
3117
3532
  // src/directives/value.ts
3118
3533
  var valueDirective = {
3119
- onChange: (el, values) => {
3120
- patchProp(el, "value", values[0]);
3121
- }
3534
+ mount: () => ({
3535
+ update: ({ el, values }) => {
3536
+ patchProp(el, "value", values[0]);
3537
+ }
3538
+ })
3122
3539
  };
3123
3540
 
3124
3541
  // src/app/RegorConfig.ts
@@ -3214,6 +3631,7 @@ var RegorConfig = class _RegorConfig {
3214
3631
  [`${prefix}show`]: showDirective,
3215
3632
  [`${prefix}model`]: modelDirective,
3216
3633
  ":style": styleDirective,
3634
+ [`${prefix}style`]: styleDirective,
3217
3635
  [`${prefix}bind:style`]: styleDirective,
3218
3636
  ":class": classDirective,
3219
3637
  [`${prefix}bind:class`]: classDirective,
@@ -3229,8 +3647,8 @@ var RegorConfig = class _RegorConfig {
3229
3647
  pre: `${prefix}pre`,
3230
3648
  inherit: `${prefix}inherit`,
3231
3649
  text: `${prefix}text`,
3232
- props: ":props",
3233
- propsOnce: ":props-once",
3650
+ context: ":context",
3651
+ contextAlias: `${prefix}context`,
3234
3652
  bind: `${prefix}bind`,
3235
3653
  on: `${prefix}on`,
3236
3654
  keyBind: ":key",
@@ -4921,6 +5339,7 @@ var regorEval = (expr, contexts, globalContext, isLazy, isLazyKey, context, coll
4921
5339
 
4922
5340
  // src/parser/Parser.ts
4923
5341
  var astCache = {};
5342
+ var isComponentMap = (value) => !!value;
4924
5343
  var Parser = class {
4925
5344
  __contexts;
4926
5345
  __config;
@@ -4932,7 +5351,7 @@ var Parser = class {
4932
5351
  this.__contexts = [context, ...this.__contexts];
4933
5352
  }
4934
5353
  __getComponents() {
4935
- const obj = this.__contexts.map((x) => x.components).filter((x) => !!x).reverse().reduce((p, c) => {
5354
+ const obj = this.__contexts.map((x) => x.components).filter(isComponentMap).reverse().reduce((p, c) => {
4936
5355
  for (const [key, value] of Object.entries(c)) {
4937
5356
  p[key.toUpperCase()] = value;
4938
5357
  }
@@ -4943,7 +5362,7 @@ var Parser = class {
4943
5362
  __getComponentSelectors() {
4944
5363
  const selectors = [];
4945
5364
  const seen = /* @__PURE__ */ new Set();
4946
- const componentsList = this.__contexts.map((x) => x.components).filter((x) => !!x).reverse();
5365
+ const componentsList = this.__contexts.map((x) => x.components).filter(isComponentMap).reverse();
4947
5366
  for (const components of componentsList) {
4948
5367
  for (const key of Object.keys(components)) {
4949
5368
  if (seen.has(key)) continue;
@@ -4954,12 +5373,12 @@ var Parser = class {
4954
5373
  return selectors;
4955
5374
  }
4956
5375
  __parse(expression, isLazy, isLazyKey, collectRefObj, once) {
4957
- const value = sref([]);
5376
+ let currentValues = [];
4958
5377
  const stopObserverList = [];
4959
5378
  const subscribers = /* @__PURE__ */ new Set();
4960
5379
  const clearObservers = () => {
4961
- for (const stopObserver of stopObserverList) {
4962
- stopObserver();
5380
+ for (let i = 0; i < stopObserverList.length; ++i) {
5381
+ stopObserverList[i]();
4963
5382
  }
4964
5383
  stopObserverList.length = 0;
4965
5384
  };
@@ -4969,13 +5388,13 @@ var Parser = class {
4969
5388
  };
4970
5389
  const subscribe = (observer, init) => {
4971
5390
  subscribers.add(observer);
4972
- if (init) observer(value());
5391
+ if (init) observer(currentValues);
4973
5392
  return () => {
4974
5393
  subscribers.delete(observer);
4975
5394
  };
4976
5395
  };
4977
5396
  const result = {
4978
- value,
5397
+ value: () => currentValues,
4979
5398
  stop: unbinder,
4980
5399
  subscribe,
4981
5400
  refs: [],
@@ -4996,7 +5415,7 @@ var Parser = class {
4996
5415
  context,
4997
5416
  collectRefObj
4998
5417
  );
4999
- if (collectRefs2) refs.push(...r.refs);
5418
+ if (collectRefs2 && r.refs.length > 0) refs.push(...r.refs);
5000
5419
  return { value: r.value, refs: r.refs, ref: r.ref };
5001
5420
  } catch (e) {
5002
5421
  warning(6 /* ErrorLog */, `evaluation error: ${expression}`, e);
@@ -5009,36 +5428,37 @@ var Parser = class {
5009
5428
  const contexts = this.__contexts.slice();
5010
5429
  const elements = ast.elements;
5011
5430
  const len = elements.length;
5431
+ const expressionRefs = new Array(len);
5432
+ result.refs = expressionRefs;
5012
5433
  const refresh = () => {
5013
5434
  refs.length = 0;
5014
- uniqueRefs.clear();
5015
- clearObservers();
5016
- const values = new Array(len);
5017
- const expressionRefs = new Array(len);
5435
+ if (!once) {
5436
+ uniqueRefs.clear();
5437
+ clearObservers();
5438
+ }
5439
+ const nextValues = new Array(len);
5018
5440
  for (let i = 0; i < len; ++i) {
5019
5441
  const expr = elements[i];
5020
5442
  if (isLazy?.(i, -1)) {
5021
- values[i] = (e) => evaluate(expr, contexts, false, { $event: e }).value;
5443
+ nextValues[i] = (e) => evaluate(expr, contexts, false, { $event: e }).value;
5022
5444
  continue;
5023
5445
  }
5024
5446
  const evaluated = evaluate(expr, contexts, true);
5025
- values[i] = evaluated.value;
5447
+ nextValues[i] = evaluated.value;
5026
5448
  expressionRefs[i] = evaluated.ref;
5027
5449
  }
5028
5450
  if (!once) {
5029
5451
  for (const r of refs) {
5030
5452
  if (uniqueRefs.has(r)) continue;
5031
5453
  uniqueRefs.add(r);
5032
- const stopObserving = observe(r, refresh);
5033
- stopObserverList.push(stopObserving);
5454
+ stopObserverList.push(observe(r, refresh));
5034
5455
  }
5035
5456
  }
5036
- result.refs = expressionRefs;
5037
- value(values);
5457
+ currentValues = nextValues;
5038
5458
  if (subscribers.size !== 0) {
5039
5459
  for (const subscriber of subscribers) {
5040
5460
  if (!subscribers.has(subscriber)) continue;
5041
- subscriber(values);
5461
+ subscriber(currentValues);
5042
5462
  }
5043
5463
  }
5044
5464
  };