marko 6.3.24 → 6.3.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dom.js CHANGED
@@ -14,13 +14,13 @@ let empty = [], rest = Symbol(), unsafeStyleAttrReg = /[\\;]/g, replaceUnsafeSty
14
14
  } else if (value === 37 || value === 49) walker.currentNode.replaceWith(walker.currentNode = scope[decodeAccessor(currentScopeIndex++)] = new Text()), value === 49 && (scope[decodeAccessor(currentScopeIndex++)] = skipScope());
15
15
  else if (value === 38) return currentWalkIndex;
16
16
  else if (value === 47 || value === 48) currentWalkIndex = walkInternal(currentWalkIndex, walkCodes, scope[decodeAccessor(currentScopeIndex++)] = createScope(scope.$, scope.F)), value === 48 && (scope[decodeAccessor(currentScopeIndex++)] = skipScope());
17
- else if (value < 92) for (value = 20 * currentMultiplier + value - 67; value--;) walker.nextNode();
17
+ else if (value < 92) for (value = 25 * currentMultiplier + value - 67; value--;) walker.nextNode();
18
18
  else if (value < 107) for (value = 10 * currentMultiplier + value - 97; value--;) walker.nextSibling();
19
19
  else if (value < 117) {
20
20
  for (value = 10 * currentMultiplier + value - 107; value--;) walker.parentNode();
21
21
  walker.nextSibling();
22
22
  } else storedMultiplier = currentMultiplier * 10 + value - 117;
23
- }, cloneCache = {}, registeredValues = {}, curRenders, branchesEnabled, embedRenders, readyIds, isResuming, inputType = "", _dynamic_tag = function(nodeAccessor, getContent, getTagVar, inputIsArgs) {
23
+ }, cloneCache = {}, registeredValues = {}, curRenders, branchesEnabled, embedRenders, readyIds, isResuming, inputType = "", controllableScripts = {}, controllableRenders = {}, _dynamic_tag = function(nodeAccessor, getContent, getTagVar, inputIsArgs) {
24
24
  nodeAccessor = decodeAccessor(nodeAccessor);
25
25
  let childScopeAccessor = "A" + nodeAccessor, rendererAccessor = "D" + nodeAccessor;
26
26
  return enableBranches(), (scope, newRenderer, getInput) => {
@@ -595,6 +595,26 @@ function _attr_input_checked_default(scope, nodeAccessor, checked) {
595
595
  el.defaultChecked = normalizedChecked, restoreValue !== normalizedChecked && (el.checked = restoreValue);
596
596
  }
597
597
  }
598
+ /** Filled by the latches a compiled page emits, so a page carries only the
599
+ * control kinds its tags can be (`_attrs_script` resolves the kind at run time). */
600
+ /** The render pass equivalent, for a tag whose name is only known at run time;
601
+ * a statically named tag passes its claim to `_attrs` instead. */
602
+ function _enable_controllable_input() {
603
+ controllableScripts[0] = _attr_input_checked_script, controllableScripts[1] = _attr_input_checkedValue_script, controllableScripts[2] = _attr_input_value_script;
604
+ }
605
+ function _enable_controllable_textarea() {
606
+ controllableScripts[2] = _attr_input_value_script;
607
+ }
608
+ function _enable_controllable_select() {
609
+ controllableScripts[3] = _attr_select_value_script;
610
+ }
611
+ function _enable_controllable_open() {
612
+ controllableScripts[4] = _attr_details_or_dialog_open_script;
613
+ }
614
+ /** A run-time tag name can be any controllable, so its page enables them all. */
615
+ function _enable_controllable() {
616
+ _enable_controllable_input(), _enable_controllable_select(), _enable_controllable_open(), controllableRenders.INPUT = _controllable_input, controllableRenders.TEXTAREA = _controllable_textarea, controllableRenders.SELECT = _controllable_select, controllableRenders.DETAILS = controllableRenders.DIALOG = _controllable_open;
617
+ }
598
618
  function _attr_input_checked(scope, nodeAccessor, checked, checkedChange) {
599
619
  let el = scope[nodeAccessor], normalizedChecked = isNotVoid(checked);
600
620
  scope["E" + nodeAccessor] = checkedChange, scope["F" + nodeAccessor] = checkedChange ? 0 : 5, checkedChange && scope.H < runId ? el.checked = normalizedChecked : _attr_input_checked_default(scope, nodeAccessor, normalizedChecked);
@@ -692,12 +712,12 @@ function _attr_select_value_script(scope, nodeAccessor) {
692
712
  break;
693
713
  }
694
714
  }
695
- syncControllableFormInput(el, hasSelectChanged, onChange), new MutationObserver(() => {
696
- let value = scope["G" + nodeAccessor];
697
- (Array.isArray(value) ? value.length !== el.selectedOptions.length || value.some((_, i) => !value.includes(el.selectedOptions[i].value)) : el.value !== value) && onChange();
698
- }).observe(el, {
715
+ syncControllableFormInput(el, hasSelectChanged, onChange), observeOnce(scope, nodeAccessor, {
699
716
  childList: !0,
700
717
  subtree: !0
718
+ }, () => {
719
+ let value = scope["G" + nodeAccessor];
720
+ (Array.isArray(value) ? value.length !== el.selectedOptions.length || value.some((_, i) => !value.includes(el.selectedOptions[i].value)) : el.value !== value) && onChange();
701
721
  });
702
722
  }
703
723
  function setSelectValue(el, value, multiple) {
@@ -716,17 +736,20 @@ function _attr_details_or_dialog_open(scope, nodeAccessor, open, openChange) {
716
736
  }
717
737
  function _attr_details_or_dialog_open_script(scope, nodeAccessor) {
718
738
  let el = scope[nodeAccessor];
719
- new MutationObserver(() => {
739
+ observeOnce(scope, nodeAccessor, {
740
+ attributes: !0,
741
+ attributeFilter: ["open"]
742
+ }, () => {
720
743
  let openChange = scope["E" + nodeAccessor];
721
744
  if (openChange && el.open === !scope["G" + nodeAccessor]) {
722
745
  let newValue = el.open;
723
746
  el.open = !newValue, openChange(newValue), run();
724
747
  }
725
- }).observe(el, {
726
- attributes: !0,
727
- attributeFilter: ["open"]
728
748
  });
729
749
  }
750
+ function observeOnce(scope, nodeAccessor, init, callback) {
751
+ (scope["N" + nodeAccessor] ||= new MutationObserver(callback)).observe(scope[nodeAccessor], init);
752
+ }
730
753
  function syncControllableFormInput(el, hasChanged, onChange) {
731
754
  el._ = onChange, delegate("input", handleChange), el.form && delegate("reset", handleFormReset), isResuming && hasChanged(el) && queueMicrotask(onChange);
732
755
  }
@@ -759,6 +782,18 @@ function updateList(arr, val, push) {
759
782
  let index = arr.indexOf(val);
760
783
  return (push ? !~index && [...arr, val] : ~index && arr.slice(0, index).concat(arr.slice(index + 1))) || arr;
761
784
  }
785
+ function _controllable_input(scope, nodeAccessor, nextAttrs) {
786
+ return "checked" in nextAttrs || "checkedChange" in nextAttrs ? (_attr_input_checked(scope, nodeAccessor, nextAttrs.checked, nextAttrs.checkedChange), /^checked(?:Value)?(?:Change)?$/) : "checkedValue" in nextAttrs || "checkedValueChange" in nextAttrs ? (_attr_input_checkedValue(scope, nodeAccessor, nextAttrs.checkedValue, nextAttrs.checkedValueChange, nextAttrs.value), /^(?:value|checked(?:Value)?)(?:Change)?$/) : _controllable_textarea(scope, nodeAccessor, nextAttrs, _attr_input_value_dynamic_default);
787
+ }
788
+ function _controllable_textarea(scope, nodeAccessor, nextAttrs, dynamicDefault) {
789
+ if ("value" in nextAttrs || "valueChange" in nextAttrs) return _attr_input_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange, dynamicDefault), /^value(?:Change)?$/;
790
+ }
791
+ function _controllable_select(scope, nodeAccessor, nextAttrs) {
792
+ if ("value" in nextAttrs || "valueChange" in nextAttrs) return _attr_select_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange), /^value(?:Change)?$/;
793
+ }
794
+ function _controllable_open(scope, nodeAccessor, nextAttrs) {
795
+ if ("open" in nextAttrs || "openChange" in nextAttrs) return _attr_details_or_dialog_open(scope, nodeAccessor, nextAttrs.open, nextAttrs.openChange), /^open(?:Change)?$/;
796
+ }
762
797
  //#endregion
763
798
  //#region src/dom/dom.ts
764
799
  function _to_text(value) {
@@ -807,21 +842,21 @@ function _text_content(node, value) {
807
842
  let normalizedValue = _to_text(value);
808
843
  node.textContent !== normalizedValue && (node.textContent = normalizedValue);
809
844
  }
810
- function _attrs(scope, nodeAccessor, nextAttrs) {
845
+ function _attrs(scope, nodeAccessor, nextAttrs, controllable) {
811
846
  let el = scope[nodeAccessor];
812
847
  for (let i = el.attributes.length; i--;) {
813
848
  let { name } = el.attributes.item(i);
814
849
  nextAttrs && (name in nextAttrs || hasAttrAlias(el, name, nextAttrs)) || el.removeAttribute(name);
815
850
  }
816
- attrsInternal(scope, nodeAccessor, nextAttrs);
851
+ attrsInternal(scope, nodeAccessor, nextAttrs, controllable);
817
852
  }
818
- function _attrs_content(scope, nodeAccessor, nextAttrs) {
819
- _attrs(scope, nodeAccessor, nextAttrs), _attr_content(scope, nodeAccessor, nextAttrs?.content);
853
+ function _attrs_content(scope, nodeAccessor, nextAttrs, controllable) {
854
+ _attrs(scope, nodeAccessor, nextAttrs, controllable), _attr_content(scope, nodeAccessor, nextAttrs?.content);
820
855
  }
821
856
  function hasAttrAlias(element, attr, nextAttrs) {
822
857
  return attr === "checked" && element.tagName === "INPUT" && "checkedValue" in nextAttrs;
823
858
  }
824
- function _attrs_partial(scope, nodeAccessor, nextAttrs, skip) {
859
+ function _attrs_partial(scope, nodeAccessor, nextAttrs, skip, controllable) {
825
860
  let el = scope[nodeAccessor], partial = {};
826
861
  for (let i = el.attributes.length; i--;) {
827
862
  let { name } = el.attributes.item(i);
@@ -831,29 +866,16 @@ function _attrs_partial(scope, nodeAccessor, nextAttrs, skip) {
831
866
  let key = isEventHandler(name) ? `on-${getEventHandlerName(name)}` : name;
832
867
  skip[key] || (partial[key] = nextAttrs[name]);
833
868
  }
834
- attrsInternal(scope, nodeAccessor, partial);
869
+ attrsInternal(scope, nodeAccessor, partial, controllable);
835
870
  }
836
- function _attrs_partial_content(scope, nodeAccessor, nextAttrs, skip) {
837
- _attrs_partial(scope, nodeAccessor, nextAttrs, skip), _attr_content(scope, nodeAccessor, nextAttrs?.content);
871
+ function _attrs_partial_content(scope, nodeAccessor, nextAttrs, skip, controllable) {
872
+ _attrs_partial(scope, nodeAccessor, nextAttrs, skip, controllable), _attr_content(scope, nodeAccessor, nextAttrs?.content);
838
873
  }
839
- function attrsInternal(scope, nodeAccessor, nextAttrs) {
840
- let el = scope[nodeAccessor], events = scope["I" + nodeAccessor], skip;
874
+ function attrsInternal(scope, nodeAccessor, nextAttrs, controllable) {
875
+ let el = scope[nodeAccessor], events = scope["I" + nodeAccessor];
841
876
  for (let name in events) events[name] = 0;
842
- switch (scope["F" + nodeAccessor] = 5, scope["E" + nodeAccessor] = 0, nextAttrs && el.tagName) {
843
- case "INPUT":
844
- "checked" in nextAttrs || "checkedChange" in nextAttrs ? (_attr_input_checked(scope, nodeAccessor, nextAttrs.checked, nextAttrs.checkedChange), skip = /^checked(?:Value)?(?:Change)?$/) : "checkedValue" in nextAttrs || "checkedValueChange" in nextAttrs ? (_attr_input_checkedValue(scope, nodeAccessor, nextAttrs.checkedValue, nextAttrs.checkedValueChange, nextAttrs.value), skip = /^(?:value|checked(?:Value)?)(?:Change)?$/) : ("value" in nextAttrs || "valueChange" in nextAttrs) && (_attr_input_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange, _attr_input_value_dynamic_default), skip = /^value(?:Change)?$/);
845
- break;
846
- case "SELECT":
847
- ("value" in nextAttrs || "valueChange" in nextAttrs) && (_attr_select_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange), skip = /^value(?:Change)?$/);
848
- break;
849
- case "TEXTAREA":
850
- ("value" in nextAttrs || "valueChange" in nextAttrs) && (_attr_input_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange), skip = /^value(?:Change)?$/);
851
- break;
852
- case "DETAILS":
853
- case "DIALOG":
854
- ("open" in nextAttrs || "openChange" in nextAttrs) && (_attr_details_or_dialog_open(scope, nodeAccessor, nextAttrs.open, nextAttrs.openChange), skip = /^open(?:Change)?$/);
855
- break;
856
- }
877
+ scope["F" + nodeAccessor] = 5, scope["E" + nodeAccessor] = 0;
878
+ let skip = nextAttrs && (controllable || controllableRenders[el.tagName])?.(scope, nodeAccessor, nextAttrs);
857
879
  for (let name in nextAttrs) {
858
880
  let value = nextAttrs[name];
859
881
  switch (name) {
@@ -876,23 +898,7 @@ function _attr_content(scope, nodeAccessor, value) {
876
898
  }
877
899
  function _attrs_script(scope, nodeAccessor) {
878
900
  let el = scope[nodeAccessor], events = scope["I" + nodeAccessor];
879
- switch (scope["F" + nodeAccessor]) {
880
- case 0:
881
- _attr_input_checked_script(scope, nodeAccessor);
882
- break;
883
- case 1:
884
- _attr_input_checkedValue_script(scope, nodeAccessor);
885
- break;
886
- case 2:
887
- _attr_input_value_script(scope, nodeAccessor);
888
- break;
889
- case 3:
890
- _attr_select_value_script(scope, nodeAccessor);
891
- break;
892
- case 4:
893
- _attr_details_or_dialog_open_script(scope, nodeAccessor);
894
- break;
895
- }
901
+ controllableScripts[scope["F" + nodeAccessor]]?.(scope, nodeAccessor);
896
902
  for (let name in events) _on(el, name, events[name]);
897
903
  }
898
904
  function _html(scope, value, accessor) {
@@ -964,7 +970,11 @@ function _await_promise(nodeAccessor, params) {
964
970
  let thisPromise = scope[promiseAccessor] = promise.then((data) => {
965
971
  if (thisPromise === scope[promiseAccessor]) {
966
972
  let referenceNode = scope[nodeAccessor];
967
- scope[promiseAccessor] = 0, queueAsyncRender(scope, () => {
973
+ if (scope[promiseAccessor] = 0, scope.F?.H === 0) {
974
+ awaitCounter.c(), run();
975
+ return;
976
+ }
977
+ queueAsyncRender(scope, () => {
968
978
  awaitBranch = resolveAwait(scope, referenceNode, data);
969
979
  let pendingRenders = awaitBranch.W;
970
980
  if (awaitBranch.W = 0, pendingRenders?.forEach(queuePendingRender), placeholderShown.add(pendingEffects), awaitCounter.c(), awaitCounter.m) {
@@ -1359,9 +1369,9 @@ function _load_race_trigger(...triggers) {
1359
1369
  function getSelectorOrResolve(selector, resolve) {
1360
1370
  return document.querySelector(selector) || resolve();
1361
1371
  }
1362
- exports.$signal = $signal, exports.$signalReset = $signalReset, exports._assert_hoist = _assert_hoist, exports._assert_init = _assert_init, exports._attr = _attr, exports._attr_class = _attr_class, exports._attr_class_item = _attr_class_item, exports._attr_class_items = _attr_class_items, exports._attr_content = _attr_content, exports._attr_details_open = _attr_details_or_dialog_open, exports._attr_dialog_open = _attr_details_or_dialog_open, exports._attr_details_open_default = _attr_details_or_dialog_open_default, exports._attr_dialog_open_default = _attr_details_or_dialog_open_default, exports._attr_details_open_script = _attr_details_or_dialog_open_script, exports._attr_dialog_open_script = _attr_details_or_dialog_open_script, exports._attr_input_checked = _attr_input_checked, exports._attr_input_checkedValue = _attr_input_checkedValue, exports._attr_input_checkedValue_default = _attr_input_checkedValue_default, exports._attr_input_checkedValue_script = _attr_input_checkedValue_script, exports._attr_input_checked_default = _attr_input_checked_default, exports._attr_input_checked_script = _attr_input_checked_script, exports._attr_input_value = _attr_input_value, exports._attr_textarea_value = _attr_input_value, exports._attr_input_value_attribute_default = _attr_input_value_attribute_default, exports._attr_input_value_default = _attr_input_value_default, exports._attr_textarea_value_default = _attr_input_value_default, exports._attr_input_value_dynamic_default = _attr_input_value_dynamic_default, exports._attr_input_value_script = _attr_input_value_script, exports._attr_textarea_value_script = _attr_input_value_script, exports._attr_nonce = _attr_nonce, exports._attr_select_value = _attr_select_value, exports._attr_select_value_default = _attr_select_value_default, exports._attr_select_value_script = _attr_select_value_script, exports._attr_style = _attr_style, exports._attr_style_item = _attr_style_item, exports._attr_style_items = _attr_style_items, exports._attrs = _attrs, exports._attrs_content = _attrs_content, exports._attrs_partial = _attrs_partial, exports._attrs_partial_content = _attrs_partial_content, exports._attrs_script = _attrs_script, exports._await_content = _await_content, exports._await_promise = _await_promise, exports._call = _call, exports._child_setup = _child_setup, exports._closure = _closure, exports._closure_get = _closure_get, exports._const = _const, exports._content = _content, exports._content_closures = _content_closures, exports._content_resume = _content_resume, Object.defineProperty(exports, "_dynamic_tag", {
1372
+ exports.$signal = $signal, exports.$signalReset = $signalReset, exports._assert_hoist = _assert_hoist, exports._assert_init = _assert_init, exports._attr = _attr, exports._attr_class = _attr_class, exports._attr_class_item = _attr_class_item, exports._attr_class_items = _attr_class_items, exports._attr_content = _attr_content, exports._attr_details_open = _attr_details_or_dialog_open, exports._attr_dialog_open = _attr_details_or_dialog_open, exports._attr_details_open_default = _attr_details_or_dialog_open_default, exports._attr_dialog_open_default = _attr_details_or_dialog_open_default, exports._attr_details_open_script = _attr_details_or_dialog_open_script, exports._attr_dialog_open_script = _attr_details_or_dialog_open_script, exports._attr_input_checked = _attr_input_checked, exports._attr_input_checkedValue = _attr_input_checkedValue, exports._attr_input_checkedValue_default = _attr_input_checkedValue_default, exports._attr_input_checkedValue_script = _attr_input_checkedValue_script, exports._attr_input_checked_default = _attr_input_checked_default, exports._attr_input_checked_script = _attr_input_checked_script, exports._attr_input_value = _attr_input_value, exports._attr_textarea_value = _attr_input_value, exports._attr_input_value_attribute_default = _attr_input_value_attribute_default, exports._attr_input_value_default = _attr_input_value_default, exports._attr_textarea_value_default = _attr_input_value_default, exports._attr_input_value_dynamic_default = _attr_input_value_dynamic_default, exports._attr_input_value_script = _attr_input_value_script, exports._attr_textarea_value_script = _attr_input_value_script, exports._attr_nonce = _attr_nonce, exports._attr_select_value = _attr_select_value, exports._attr_select_value_default = _attr_select_value_default, exports._attr_select_value_script = _attr_select_value_script, exports._attr_style = _attr_style, exports._attr_style_item = _attr_style_item, exports._attr_style_items = _attr_style_items, exports._attrs = _attrs, exports._attrs_content = _attrs_content, exports._attrs_partial = _attrs_partial, exports._attrs_partial_content = _attrs_partial_content, exports._attrs_script = _attrs_script, exports._await_content = _await_content, exports._await_promise = _await_promise, exports._call = _call, exports._child_setup = _child_setup, exports._closure = _closure, exports._closure_get = _closure_get, exports._const = _const, exports._content = _content, exports._content_closures = _content_closures, exports._content_resume = _content_resume, exports._controllable_input = _controllable_input, exports._controllable_open = _controllable_open, exports._controllable_select = _controllable_select, exports._controllable_textarea = _controllable_textarea, Object.defineProperty(exports, "_dynamic_tag", {
1363
1373
  enumerable: !0,
1364
1374
  get: function() {
1365
1375
  return _dynamic_tag;
1366
1376
  }
1367
- }), exports._dynamic_tag_content = _dynamic_tag_content, exports._el = _el, exports._el_read = _el_read, exports._enable_catch = _enable_catch, exports._for_closure = _for_closure, exports._for_in = _for_in, exports._for_of = _for_of, exports._for_selector = _for_selector, exports._for_to = _for_to, exports._for_until = _for_until, exports._hoist = _hoist, exports._hoist_resume = _hoist_resume, exports._html = _html, exports._id = _id, exports._if = _if, exports._if_closure = _if_closure, exports._let = _let, exports._let_change = _let_change, exports._lifecycle = _lifecycle, exports._load_event_trigger = _load_event_trigger, exports._load_idle_trigger = _load_idle_trigger, exports._load_media_trigger = _load_media_trigger, exports._load_race_trigger = _load_race_trigger, exports._load_setup = _load_setup, exports._load_signal = _load_signal, exports._load_template = _load_template, exports._load_visible_trigger = _load_visible_trigger, exports._on = _on, exports._or = _or, exports._resume = _resume, exports._resume_dynamic_tag = _resume_dynamic_tag, exports._return = _return, exports._return_change = _return_change, exports._script = _script, exports._show = _show, exports._style_rule_item = _style_rule_item, exports._style_shell = _style_shell, exports._template = _template, exports._text = _text, exports._text_content = _text_content, exports._to_text = _to_text, exports._try = _try, exports._var = _var, exports._var_change = _var_change, exports._var_resume = _var_resume, exports.attrTag = attrTag, exports.attrTags = attrTags, exports.compat = compat, exports.forIn = forIn, exports.forOf = forOf, exports.forTo = forTo, exports.forUntil = forUntil, exports.init = init, exports.initEmbedded = initEmbedded, exports.ready = ready, exports.run = run;
1377
+ }), exports._dynamic_tag_content = _dynamic_tag_content, exports._el = _el, exports._el_read = _el_read, exports._enable_catch = _enable_catch, exports._enable_controllable = _enable_controllable, exports._enable_controllable_input = _enable_controllable_input, exports._enable_controllable_open = _enable_controllable_open, exports._enable_controllable_select = _enable_controllable_select, exports._enable_controllable_textarea = _enable_controllable_textarea, exports._for_closure = _for_closure, exports._for_in = _for_in, exports._for_of = _for_of, exports._for_selector = _for_selector, exports._for_to = _for_to, exports._for_until = _for_until, exports._hoist = _hoist, exports._hoist_resume = _hoist_resume, exports._html = _html, exports._id = _id, exports._if = _if, exports._if_closure = _if_closure, exports._let = _let, exports._let_change = _let_change, exports._lifecycle = _lifecycle, exports._load_event_trigger = _load_event_trigger, exports._load_idle_trigger = _load_idle_trigger, exports._load_media_trigger = _load_media_trigger, exports._load_race_trigger = _load_race_trigger, exports._load_setup = _load_setup, exports._load_signal = _load_signal, exports._load_template = _load_template, exports._load_visible_trigger = _load_visible_trigger, exports._on = _on, exports._or = _or, exports._resume = _resume, exports._resume_dynamic_tag = _resume_dynamic_tag, exports._return = _return, exports._return_change = _return_change, exports._script = _script, exports._show = _show, exports._style_rule_item = _style_rule_item, exports._style_shell = _style_shell, exports._template = _template, exports._text = _text, exports._text_content = _text_content, exports._to_text = _to_text, exports._try = _try, exports._var = _var, exports._var_change = _var_change, exports._var_resume = _var_resume, exports.attrTag = attrTag, exports.attrTags = attrTags, exports.compat = compat, exports.forIn = forIn, exports.forOf = forOf, exports.forTo = forTo, exports.forUntil = forUntil, exports.init = init, exports.initEmbedded = initEmbedded, exports.ready = ready, exports.run = run;
package/dist/dom.mjs CHANGED
@@ -14,13 +14,13 @@ let empty = [], rest = Symbol(), unsafeStyleAttrReg = /[\\;]/g, replaceUnsafeSty
14
14
  } else if (value === 37 || value === 49) walker.currentNode.replaceWith(walker.currentNode = scope[decodeAccessor(currentScopeIndex++)] = new Text()), value === 49 && (scope[decodeAccessor(currentScopeIndex++)] = skipScope());
15
15
  else if (value === 38) return currentWalkIndex;
16
16
  else if (value === 47 || value === 48) currentWalkIndex = walkInternal(currentWalkIndex, walkCodes, scope[decodeAccessor(currentScopeIndex++)] = createScope(scope.$, scope.F)), value === 48 && (scope[decodeAccessor(currentScopeIndex++)] = skipScope());
17
- else if (value < 92) for (value = 20 * currentMultiplier + value - 67; value--;) walker.nextNode();
17
+ else if (value < 92) for (value = 25 * currentMultiplier + value - 67; value--;) walker.nextNode();
18
18
  else if (value < 107) for (value = 10 * currentMultiplier + value - 97; value--;) walker.nextSibling();
19
19
  else if (value < 117) {
20
20
  for (value = 10 * currentMultiplier + value - 107; value--;) walker.parentNode();
21
21
  walker.nextSibling();
22
22
  } else storedMultiplier = currentMultiplier * 10 + value - 117;
23
- }, cloneCache = {}, registeredValues = {}, curRenders, branchesEnabled, embedRenders, readyIds, isResuming, inputType = "", _dynamic_tag = function(nodeAccessor, getContent, getTagVar, inputIsArgs) {
23
+ }, cloneCache = {}, registeredValues = {}, curRenders, branchesEnabled, embedRenders, readyIds, isResuming, inputType = "", controllableScripts = {}, controllableRenders = {}, _dynamic_tag = function(nodeAccessor, getContent, getTagVar, inputIsArgs) {
24
24
  nodeAccessor = decodeAccessor(nodeAccessor);
25
25
  let childScopeAccessor = "A" + nodeAccessor, rendererAccessor = "D" + nodeAccessor;
26
26
  return enableBranches(), (scope, newRenderer, getInput) => {
@@ -594,6 +594,26 @@ function _attr_input_checked_default(scope, nodeAccessor, checked) {
594
594
  el.defaultChecked = normalizedChecked, restoreValue !== normalizedChecked && (el.checked = restoreValue);
595
595
  }
596
596
  }
597
+ /** Filled by the latches a compiled page emits, so a page carries only the
598
+ * control kinds its tags can be (`_attrs_script` resolves the kind at run time). */
599
+ /** The render pass equivalent, for a tag whose name is only known at run time;
600
+ * a statically named tag passes its claim to `_attrs` instead. */
601
+ function _enable_controllable_input() {
602
+ controllableScripts[0] = _attr_input_checked_script, controllableScripts[1] = _attr_input_checkedValue_script, controllableScripts[2] = _attr_input_value_script;
603
+ }
604
+ function _enable_controllable_textarea() {
605
+ controllableScripts[2] = _attr_input_value_script;
606
+ }
607
+ function _enable_controllable_select() {
608
+ controllableScripts[3] = _attr_select_value_script;
609
+ }
610
+ function _enable_controllable_open() {
611
+ controllableScripts[4] = _attr_details_or_dialog_open_script;
612
+ }
613
+ /** A run-time tag name can be any controllable, so its page enables them all. */
614
+ function _enable_controllable() {
615
+ _enable_controllable_input(), _enable_controllable_select(), _enable_controllable_open(), controllableRenders.INPUT = _controllable_input, controllableRenders.TEXTAREA = _controllable_textarea, controllableRenders.SELECT = _controllable_select, controllableRenders.DETAILS = controllableRenders.DIALOG = _controllable_open;
616
+ }
597
617
  function _attr_input_checked(scope, nodeAccessor, checked, checkedChange) {
598
618
  let el = scope[nodeAccessor], normalizedChecked = isNotVoid(checked);
599
619
  scope["E" + nodeAccessor] = checkedChange, scope["F" + nodeAccessor] = checkedChange ? 0 : 5, checkedChange && scope.H < runId ? el.checked = normalizedChecked : _attr_input_checked_default(scope, nodeAccessor, normalizedChecked);
@@ -691,12 +711,12 @@ function _attr_select_value_script(scope, nodeAccessor) {
691
711
  break;
692
712
  }
693
713
  }
694
- syncControllableFormInput(el, hasSelectChanged, onChange), new MutationObserver(() => {
695
- let value = scope["G" + nodeAccessor];
696
- (Array.isArray(value) ? value.length !== el.selectedOptions.length || value.some((_, i) => !value.includes(el.selectedOptions[i].value)) : el.value !== value) && onChange();
697
- }).observe(el, {
714
+ syncControllableFormInput(el, hasSelectChanged, onChange), observeOnce(scope, nodeAccessor, {
698
715
  childList: !0,
699
716
  subtree: !0
717
+ }, () => {
718
+ let value = scope["G" + nodeAccessor];
719
+ (Array.isArray(value) ? value.length !== el.selectedOptions.length || value.some((_, i) => !value.includes(el.selectedOptions[i].value)) : el.value !== value) && onChange();
700
720
  });
701
721
  }
702
722
  function setSelectValue(el, value, multiple) {
@@ -715,17 +735,20 @@ function _attr_details_or_dialog_open(scope, nodeAccessor, open, openChange) {
715
735
  }
716
736
  function _attr_details_or_dialog_open_script(scope, nodeAccessor) {
717
737
  let el = scope[nodeAccessor];
718
- new MutationObserver(() => {
738
+ observeOnce(scope, nodeAccessor, {
739
+ attributes: !0,
740
+ attributeFilter: ["open"]
741
+ }, () => {
719
742
  let openChange = scope["E" + nodeAccessor];
720
743
  if (openChange && el.open === !scope["G" + nodeAccessor]) {
721
744
  let newValue = el.open;
722
745
  el.open = !newValue, openChange(newValue), run();
723
746
  }
724
- }).observe(el, {
725
- attributes: !0,
726
- attributeFilter: ["open"]
727
747
  });
728
748
  }
749
+ function observeOnce(scope, nodeAccessor, init, callback) {
750
+ (scope["N" + nodeAccessor] ||= new MutationObserver(callback)).observe(scope[nodeAccessor], init);
751
+ }
729
752
  function syncControllableFormInput(el, hasChanged, onChange) {
730
753
  el._ = onChange, delegate("input", handleChange), el.form && delegate("reset", handleFormReset), isResuming && hasChanged(el) && queueMicrotask(onChange);
731
754
  }
@@ -758,6 +781,18 @@ function updateList(arr, val, push) {
758
781
  let index = arr.indexOf(val);
759
782
  return (push ? !~index && [...arr, val] : ~index && arr.slice(0, index).concat(arr.slice(index + 1))) || arr;
760
783
  }
784
+ function _controllable_input(scope, nodeAccessor, nextAttrs) {
785
+ return "checked" in nextAttrs || "checkedChange" in nextAttrs ? (_attr_input_checked(scope, nodeAccessor, nextAttrs.checked, nextAttrs.checkedChange), /^checked(?:Value)?(?:Change)?$/) : "checkedValue" in nextAttrs || "checkedValueChange" in nextAttrs ? (_attr_input_checkedValue(scope, nodeAccessor, nextAttrs.checkedValue, nextAttrs.checkedValueChange, nextAttrs.value), /^(?:value|checked(?:Value)?)(?:Change)?$/) : _controllable_textarea(scope, nodeAccessor, nextAttrs, _attr_input_value_dynamic_default);
786
+ }
787
+ function _controllable_textarea(scope, nodeAccessor, nextAttrs, dynamicDefault) {
788
+ if ("value" in nextAttrs || "valueChange" in nextAttrs) return _attr_input_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange, dynamicDefault), /^value(?:Change)?$/;
789
+ }
790
+ function _controllable_select(scope, nodeAccessor, nextAttrs) {
791
+ if ("value" in nextAttrs || "valueChange" in nextAttrs) return _attr_select_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange), /^value(?:Change)?$/;
792
+ }
793
+ function _controllable_open(scope, nodeAccessor, nextAttrs) {
794
+ if ("open" in nextAttrs || "openChange" in nextAttrs) return _attr_details_or_dialog_open(scope, nodeAccessor, nextAttrs.open, nextAttrs.openChange), /^open(?:Change)?$/;
795
+ }
761
796
  //#endregion
762
797
  //#region src/dom/dom.ts
763
798
  function _to_text(value) {
@@ -806,21 +841,21 @@ function _text_content(node, value) {
806
841
  let normalizedValue = _to_text(value);
807
842
  node.textContent !== normalizedValue && (node.textContent = normalizedValue);
808
843
  }
809
- function _attrs(scope, nodeAccessor, nextAttrs) {
844
+ function _attrs(scope, nodeAccessor, nextAttrs, controllable) {
810
845
  let el = scope[nodeAccessor];
811
846
  for (let i = el.attributes.length; i--;) {
812
847
  let { name } = el.attributes.item(i);
813
848
  nextAttrs && (name in nextAttrs || hasAttrAlias(el, name, nextAttrs)) || el.removeAttribute(name);
814
849
  }
815
- attrsInternal(scope, nodeAccessor, nextAttrs);
850
+ attrsInternal(scope, nodeAccessor, nextAttrs, controllable);
816
851
  }
817
- function _attrs_content(scope, nodeAccessor, nextAttrs) {
818
- _attrs(scope, nodeAccessor, nextAttrs), _attr_content(scope, nodeAccessor, nextAttrs?.content);
852
+ function _attrs_content(scope, nodeAccessor, nextAttrs, controllable) {
853
+ _attrs(scope, nodeAccessor, nextAttrs, controllable), _attr_content(scope, nodeAccessor, nextAttrs?.content);
819
854
  }
820
855
  function hasAttrAlias(element, attr, nextAttrs) {
821
856
  return attr === "checked" && element.tagName === "INPUT" && "checkedValue" in nextAttrs;
822
857
  }
823
- function _attrs_partial(scope, nodeAccessor, nextAttrs, skip) {
858
+ function _attrs_partial(scope, nodeAccessor, nextAttrs, skip, controllable) {
824
859
  let el = scope[nodeAccessor], partial = {};
825
860
  for (let i = el.attributes.length; i--;) {
826
861
  let { name } = el.attributes.item(i);
@@ -830,29 +865,16 @@ function _attrs_partial(scope, nodeAccessor, nextAttrs, skip) {
830
865
  let key = isEventHandler(name) ? `on-${getEventHandlerName(name)}` : name;
831
866
  skip[key] || (partial[key] = nextAttrs[name]);
832
867
  }
833
- attrsInternal(scope, nodeAccessor, partial);
868
+ attrsInternal(scope, nodeAccessor, partial, controllable);
834
869
  }
835
- function _attrs_partial_content(scope, nodeAccessor, nextAttrs, skip) {
836
- _attrs_partial(scope, nodeAccessor, nextAttrs, skip), _attr_content(scope, nodeAccessor, nextAttrs?.content);
870
+ function _attrs_partial_content(scope, nodeAccessor, nextAttrs, skip, controllable) {
871
+ _attrs_partial(scope, nodeAccessor, nextAttrs, skip, controllable), _attr_content(scope, nodeAccessor, nextAttrs?.content);
837
872
  }
838
- function attrsInternal(scope, nodeAccessor, nextAttrs) {
839
- let el = scope[nodeAccessor], events = scope["I" + nodeAccessor], skip;
873
+ function attrsInternal(scope, nodeAccessor, nextAttrs, controllable) {
874
+ let el = scope[nodeAccessor], events = scope["I" + nodeAccessor];
840
875
  for (let name in events) events[name] = 0;
841
- switch (scope["F" + nodeAccessor] = 5, scope["E" + nodeAccessor] = 0, nextAttrs && el.tagName) {
842
- case "INPUT":
843
- "checked" in nextAttrs || "checkedChange" in nextAttrs ? (_attr_input_checked(scope, nodeAccessor, nextAttrs.checked, nextAttrs.checkedChange), skip = /^checked(?:Value)?(?:Change)?$/) : "checkedValue" in nextAttrs || "checkedValueChange" in nextAttrs ? (_attr_input_checkedValue(scope, nodeAccessor, nextAttrs.checkedValue, nextAttrs.checkedValueChange, nextAttrs.value), skip = /^(?:value|checked(?:Value)?)(?:Change)?$/) : ("value" in nextAttrs || "valueChange" in nextAttrs) && (_attr_input_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange, _attr_input_value_dynamic_default), skip = /^value(?:Change)?$/);
844
- break;
845
- case "SELECT":
846
- ("value" in nextAttrs || "valueChange" in nextAttrs) && (_attr_select_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange), skip = /^value(?:Change)?$/);
847
- break;
848
- case "TEXTAREA":
849
- ("value" in nextAttrs || "valueChange" in nextAttrs) && (_attr_input_value(scope, nodeAccessor, nextAttrs.value, nextAttrs.valueChange), skip = /^value(?:Change)?$/);
850
- break;
851
- case "DETAILS":
852
- case "DIALOG":
853
- ("open" in nextAttrs || "openChange" in nextAttrs) && (_attr_details_or_dialog_open(scope, nodeAccessor, nextAttrs.open, nextAttrs.openChange), skip = /^open(?:Change)?$/);
854
- break;
855
- }
876
+ scope["F" + nodeAccessor] = 5, scope["E" + nodeAccessor] = 0;
877
+ let skip = nextAttrs && (controllable || controllableRenders[el.tagName])?.(scope, nodeAccessor, nextAttrs);
856
878
  for (let name in nextAttrs) {
857
879
  let value = nextAttrs[name];
858
880
  switch (name) {
@@ -875,23 +897,7 @@ function _attr_content(scope, nodeAccessor, value) {
875
897
  }
876
898
  function _attrs_script(scope, nodeAccessor) {
877
899
  let el = scope[nodeAccessor], events = scope["I" + nodeAccessor];
878
- switch (scope["F" + nodeAccessor]) {
879
- case 0:
880
- _attr_input_checked_script(scope, nodeAccessor);
881
- break;
882
- case 1:
883
- _attr_input_checkedValue_script(scope, nodeAccessor);
884
- break;
885
- case 2:
886
- _attr_input_value_script(scope, nodeAccessor);
887
- break;
888
- case 3:
889
- _attr_select_value_script(scope, nodeAccessor);
890
- break;
891
- case 4:
892
- _attr_details_or_dialog_open_script(scope, nodeAccessor);
893
- break;
894
- }
900
+ controllableScripts[scope["F" + nodeAccessor]]?.(scope, nodeAccessor);
895
901
  for (let name in events) _on(el, name, events[name]);
896
902
  }
897
903
  function _html(scope, value, accessor) {
@@ -963,7 +969,11 @@ function _await_promise(nodeAccessor, params) {
963
969
  let thisPromise = scope[promiseAccessor] = promise.then((data) => {
964
970
  if (thisPromise === scope[promiseAccessor]) {
965
971
  let referenceNode = scope[nodeAccessor];
966
- scope[promiseAccessor] = 0, queueAsyncRender(scope, () => {
972
+ if (scope[promiseAccessor] = 0, scope.F?.H === 0) {
973
+ awaitCounter.c(), run();
974
+ return;
975
+ }
976
+ queueAsyncRender(scope, () => {
967
977
  awaitBranch = resolveAwait(scope, referenceNode, data);
968
978
  let pendingRenders = awaitBranch.W;
969
979
  if (awaitBranch.W = 0, pendingRenders?.forEach(queuePendingRender), placeholderShown.add(pendingEffects), awaitCounter.c(), awaitCounter.m) {
@@ -1359,4 +1369,4 @@ function getSelectorOrResolve(selector, resolve) {
1359
1369
  return document.querySelector(selector) || resolve();
1360
1370
  }
1361
1371
  //#endregion
1362
- export { $signal, $signalReset, _assert_hoist, _assert_init, _attr, _attr_class, _attr_class_item, _attr_class_items, _attr_content, _attr_details_or_dialog_open as _attr_details_open, _attr_details_or_dialog_open as _attr_dialog_open, _attr_details_or_dialog_open_default as _attr_details_open_default, _attr_details_or_dialog_open_default as _attr_dialog_open_default, _attr_details_or_dialog_open_script as _attr_details_open_script, _attr_details_or_dialog_open_script as _attr_dialog_open_script, _attr_input_checked, _attr_input_checkedValue, _attr_input_checkedValue_default, _attr_input_checkedValue_script, _attr_input_checked_default, _attr_input_checked_script, _attr_input_value, _attr_input_value as _attr_textarea_value, _attr_input_value_attribute_default, _attr_input_value_default, _attr_input_value_default as _attr_textarea_value_default, _attr_input_value_dynamic_default, _attr_input_value_script, _attr_input_value_script as _attr_textarea_value_script, _attr_nonce, _attr_select_value, _attr_select_value_default, _attr_select_value_script, _attr_style, _attr_style_item, _attr_style_items, _attrs, _attrs_content, _attrs_partial, _attrs_partial_content, _attrs_script, _await_content, _await_promise, _call, _child_setup, _closure, _closure_get, _const, _content, _content_closures, _content_resume, _dynamic_tag, _dynamic_tag_content, _el, _el_read, _enable_catch, _for_closure, _for_in, _for_of, _for_selector, _for_to, _for_until, _hoist, _hoist_resume, _html, _id, _if, _if_closure, _let, _let_change, _lifecycle, _load_event_trigger, _load_idle_trigger, _load_media_trigger, _load_race_trigger, _load_setup, _load_signal, _load_template, _load_visible_trigger, _on, _or, _resume, _resume_dynamic_tag, _return, _return_change, _script, _show, _style_rule_item, _style_shell, _template, _text, _text_content, _to_text, _try, _var, _var_change, _var_resume, attrTag, attrTags, compat, forIn, forOf, forTo, forUntil, init, initEmbedded, ready, run };
1372
+ export { $signal, $signalReset, _assert_hoist, _assert_init, _attr, _attr_class, _attr_class_item, _attr_class_items, _attr_content, _attr_details_or_dialog_open as _attr_details_open, _attr_details_or_dialog_open as _attr_dialog_open, _attr_details_or_dialog_open_default as _attr_details_open_default, _attr_details_or_dialog_open_default as _attr_dialog_open_default, _attr_details_or_dialog_open_script as _attr_details_open_script, _attr_details_or_dialog_open_script as _attr_dialog_open_script, _attr_input_checked, _attr_input_checkedValue, _attr_input_checkedValue_default, _attr_input_checkedValue_script, _attr_input_checked_default, _attr_input_checked_script, _attr_input_value, _attr_input_value as _attr_textarea_value, _attr_input_value_attribute_default, _attr_input_value_default, _attr_input_value_default as _attr_textarea_value_default, _attr_input_value_dynamic_default, _attr_input_value_script, _attr_input_value_script as _attr_textarea_value_script, _attr_nonce, _attr_select_value, _attr_select_value_default, _attr_select_value_script, _attr_style, _attr_style_item, _attr_style_items, _attrs, _attrs_content, _attrs_partial, _attrs_partial_content, _attrs_script, _await_content, _await_promise, _call, _child_setup, _closure, _closure_get, _const, _content, _content_closures, _content_resume, _controllable_input, _controllable_open, _controllable_select, _controllable_textarea, _dynamic_tag, _dynamic_tag_content, _el, _el_read, _enable_catch, _enable_controllable, _enable_controllable_input, _enable_controllable_open, _enable_controllable_select, _enable_controllable_textarea, _for_closure, _for_in, _for_of, _for_selector, _for_to, _for_until, _hoist, _hoist_resume, _html, _id, _if, _if_closure, _let, _let_change, _lifecycle, _load_event_trigger, _load_idle_trigger, _load_media_trigger, _load_race_trigger, _load_setup, _load_signal, _load_template, _load_visible_trigger, _on, _or, _resume, _resume_dynamic_tag, _return, _return_change, _script, _show, _style_rule_item, _style_shell, _template, _text, _text_content, _to_text, _try, _var, _var_change, _var_resume, attrTag, attrTags, compat, forIn, forOf, forTo, forUntil, init, initEmbedded, ready, run };
@@ -110,6 +110,7 @@ var accessor_prefix_debug_exports = /* @__PURE__ */ __exportAll({
110
110
  ClosureSignalIndex: () => ClosureSignalIndex$1,
111
111
  ConditionalRenderer: () => ConditionalRenderer$1,
112
112
  ControlledHandler: () => ControlledHandler$1,
113
+ ControlledObserver: () => ControlledObserver$1,
113
114
  ControlledType: () => ControlledType$1,
114
115
  ControlledValue: () => ControlledValue$1,
115
116
  DynamicHTMLLastChild: () => DynamicHTMLLastChild$1,
@@ -123,6 +124,7 @@ const BranchScopes$3 = "BranchScopes:";
123
124
  const ClosureScopes$1 = "ClosureScopes:";
124
125
  const ClosureSignalIndex$1 = "ClosureSignalIndex:";
125
126
  const ConditionalRenderer$1 = "ConditionalRenderer:";
127
+ const ControlledObserver$1 = "ControlledObserver:";
126
128
  const ControlledHandler$1 = "ControlledHandler:";
127
129
  const ControlledType$1 = "ControlledType:";
128
130
  const ControlledValue$1 = "ControlledValue:";
@@ -238,7 +240,7 @@ function isNullableExpr(expr) {
238
240
  case "|=":
239
241
  case "**=": return false;
240
242
  case "||=":
241
- case "??=": return isNullableExpr(expr.right) || isNullableExpr(expr.left);
243
+ case "??=": return isNullableExpr(expr.right);
242
244
  case "&&=": return isNullableExpr(expr.left) || isNullableExpr(expr.right);
243
245
  default: return true;
244
246
  }
@@ -246,7 +248,7 @@ function isNullableExpr(expr) {
246
248
  case "ConditionalExpression": return isNullableExpr(expr.consequent) || isNullableExpr(expr.alternate);
247
249
  case "LogicalExpression": switch (expr.operator) {
248
250
  case "||":
249
- case "??": return isNullableExpr(expr.right) || isNullableExpr(expr.left);
251
+ case "??": return isNullableExpr(expr.right);
250
252
  case "&&": return isNullableExpr(expr.left) || isNullableExpr(expr.right);
251
253
  default: return true;
252
254
  }
@@ -908,6 +910,7 @@ var accessor_prefix_exports = /* @__PURE__ */ __exportAll({
908
910
  ClosureSignalIndex: () => "C",
909
911
  ConditionalRenderer: () => "D",
910
912
  ControlledHandler: () => "E",
913
+ ControlledObserver: () => "N",
911
914
  ControlledType: () => "F",
912
915
  ControlledValue: () => "G",
913
916
  DynamicHTMLLastChild: () => "H",
@@ -2524,7 +2527,7 @@ function visitInternal(section) {
2524
2527
  }
2525
2528
  function nCodeString(code, number) {
2526
2529
  switch (code) {
2527
- case 67: return toCharString(number, code, 20);
2530
+ case 67: return toCharString(number, code, 25);
2528
2531
  case 97: return toCharString(number, code, 10);
2529
2532
  case 107: return toCharString(number, code, 10);
2530
2533
  default: throw new Error(`Unexpected walk code: ${code}`);
@@ -2540,6 +2543,16 @@ function toCharString(number, startCode, rangeSize) {
2540
2543
  result += String.fromCharCode(startCode + number);
2541
2544
  return result;
2542
2545
  }
2546
+ /** `_content` strips trailing exit codes before it walks, so a renderer that
2547
+ * reaches the runtime through it never needs them on the wire. */
2548
+ function trimTrailingExits(walks) {
2549
+ if (!_marko_compiler.types.isStringLiteral(walks)) return walks;
2550
+ const value = walks.value.replace(/[^\0-1]+$/, "");
2551
+ return value === walks.value ? walks : value ? withLeadingComment(_marko_compiler.types.stringLiteral(value), getComment(walks)) : void 0;
2552
+ }
2553
+ function getComment(node) {
2554
+ return node.leadingComments?.[0]?.value.trim() || "";
2555
+ }
2543
2556
  function getWalkString(section) {
2544
2557
  if (section.content?.endType === 1) getSteps(section).push(0, 1);
2545
2558
  visitInternal(section);
@@ -3612,7 +3625,8 @@ var dom_default = { translate: {
3612
3625
  if (childSection !== section) {
3613
3626
  const tagParamsSignal = childSection.params && initValue(childSection.params);
3614
3627
  const tagParamsIdentifier = tagParamsSignal && signalHasStatements(tagParamsSignal) ? tagParamsSignal.identifier : void 0;
3615
- const { walks, writes, decls } = getSectionMeta(childSection);
3628
+ const { writes, decls } = getSectionMeta(childSection);
3629
+ const walks = trimTrailingExits(getSectionMeta(childSection).walks);
3616
3630
  const setup = getSetup(childSection);
3617
3631
  const written = writeSignals(childSection);
3618
3632
  const setupIdentifier = setup && written.has(setup) ? setup.identifier : void 0;
@@ -4745,8 +4759,12 @@ var native_tag_default = {
4745
4759
  }
4746
4760
  if (spreadExpression) {
4747
4761
  const canHaveAttrContent = !(isTextOnly || isOpenOnly || hasChildren || staticContentAttr);
4748
- if (skipExpression) addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_partial_content" : "_attrs_partial", scopeIdentifier, visitAccessor, spreadExpression, skipExpression)));
4749
- else addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_content" : "_attrs", scopeIdentifier, visitAccessor, spreadExpression)));
4762
+ const name = tag.get("name");
4763
+ const staticName = name.isStringLiteral() ? name.node.value : void 0;
4764
+ const controllable = controllableClaimFor(staticName);
4765
+ if (skipExpression) addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_partial_content" : "_attrs_partial", scopeIdentifier, visitAccessor, spreadExpression, skipExpression, controllable && importRuntime(controllable))));
4766
+ else addStatement("render", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime(canHaveAttrContent ? "_attrs_content" : "_attrs", scopeIdentifier, visitAccessor, spreadExpression, controllable && importRuntime(controllable))));
4767
+ enableControllable(controllableScriptLatchFor(staticName));
4750
4768
  addStatement("effect", tagSection, tagExtra.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime("_attrs_script", scopeIdentifier, visitAccessor)), false);
4751
4769
  }
4752
4770
  if (staticContentAttr) addStatement("render", tagSection, staticContentAttr.value.extra?.referencedBindings, _marko_compiler.types.expressionStatement(callRuntime("_attr_content", scopeIdentifier, visitAccessor, staticContentAttr.value)), void 0, true);
@@ -5156,6 +5174,40 @@ function isDynamicControllable(controllable) {
5156
5174
  function buildUndefined$1() {
5157
5175
  return _marko_compiler.types.unaryExpression("void", _marko_compiler.types.numericLiteral(0));
5158
5176
  }
5177
+ /** How a statically named tag claims its controlled attrs during render;
5178
+ * nothing for the many tags that control nothing. */
5179
+ function controllableClaimFor(tagName) {
5180
+ switch (tagName) {
5181
+ case "input": return "_controllable_input";
5182
+ case "textarea": return "_controllable_textarea";
5183
+ case "select": return "_controllable_select";
5184
+ case "details":
5185
+ case "dialog": return "_controllable_open";
5186
+ }
5187
+ }
5188
+ /** The resume-pass latch for a tag: `_attrs_script` resolves the control kind
5189
+ * at run time, and a run-time tag name can be any of them. */
5190
+ function controllableScriptLatchFor(tagName) {
5191
+ switch (tagName) {
5192
+ case "input": return "_enable_controllable_input";
5193
+ case "textarea": return "_enable_controllable_textarea";
5194
+ case "select": return "_enable_controllable_select";
5195
+ case "details":
5196
+ case "dialog": return "_enable_controllable_open";
5197
+ case void 0: return "_enable_controllable";
5198
+ }
5199
+ }
5200
+ const enabledControllables = /* @__PURE__ */ new WeakMap();
5201
+ /** Emits the latch once per program, like `_enable_catch`. */
5202
+ function enableControllable(helper) {
5203
+ if (!helper) return;
5204
+ const program = (0, _marko_compiler_babel_utils.getProgram)().node;
5205
+ let enabled = enabledControllables.get(program);
5206
+ if (!enabled) enabledControllables.set(program, enabled = /* @__PURE__ */ new Set());
5207
+ if (enabled.has(helper)) return;
5208
+ enabled.add(helper);
5209
+ program.body.push(_marko_compiler.types.expressionStatement(callRuntime(helper)));
5210
+ }
5159
5211
  //#endregion
5160
5212
  //#region src/translator/util/is-only-child-in-parent.ts
5161
5213
  const kOnlyChildInParent = Symbol("only child in parent");
@@ -9778,13 +9830,25 @@ var dynamic_tag_default = {
9778
9830
  const argsOrInput = hasTagArgs ? _marko_compiler.types.arrayExpression(args) : args[0];
9779
9831
  if (!_marko_compiler.types.isObjectExpression(argsOrInput) || argsOrInput.properties.length) signal.extraArgs = [_marko_compiler.types.arrowFunctionExpression([], statements.length ? _marko_compiler.types.blockStatement(statements.concat(_marko_compiler.types.returnStatement(argsOrInput))) : argsOrInput)];
9780
9832
  }
9781
- if (!isClassAPI) enableDynamicTagResume(tag);
9833
+ if (!isClassAPI) {
9834
+ enableDynamicTagResume(tag);
9835
+ enableDynamicTagControllables(tag);
9836
+ }
9782
9837
  addValue(section, tagExtra.referencedBindings, signal, tagExpression);
9783
9838
  tag.remove();
9784
9839
  }
9785
9840
  }
9786
9841
  }
9787
9842
  };
9843
+ const controlledAttrs = /^(?:value|checked(?:Value)?|open)(?:Change)?$/;
9844
+ /** The name resolves at run time, so any control kind is possible. */
9845
+ function enableDynamicTagControllables(tag) {
9846
+ if (analyzeTagNameType(tag, true) === 1) return;
9847
+ for (const attr of tag.node.attributes) if (attr.type === "MarkoSpreadAttribute" || attr.type === "MarkoAttribute" && controlledAttrs.test(attr.name)) {
9848
+ enableControllable(controllableScriptLatchFor(void 0));
9849
+ return;
9850
+ }
9851
+ }
9788
9852
  function enableDynamicTagResume(tag) {
9789
9853
  const program = (0, _marko_compiler_babel_utils.getProgram)().node;
9790
9854
  if (!importedDynamicTagResume.has(program) && analyzeTagNameType(tag, true) !== 1) {
@@ -11,4 +11,7 @@ export declare function exit(path: t.NodePath<any>): void;
11
11
  export declare function enterShallow(path: t.NodePath<any>): void;
12
12
  export declare function injectWalks(tag: t.NodePath<t.MarkoTag>, name: string, expr?: Walk): void;
13
13
  export declare function visit(path: t.NodePath<t.MarkoTag | t.MarkoPlaceholder | t.Program>, code: VisitCodes): void;
14
+ /** `_content` strips trailing exit codes before it walks, so a renderer that
15
+ * reaches the runtime through it never needs them on the wire. */
16
+ export declare function trimTrailingExits(walks: t.Expression | undefined): t.ArrayExpression | t.ArrowFunctionExpression | t.AssignmentExpression | t.AwaitExpression | t.BigIntLiteral | t.BinaryExpression | t.BindExpression | t.BooleanLiteral | t.CallExpression | t.ClassExpression | t.ConditionalExpression | t.DecimalLiteral | t.DoExpression | t.FunctionExpression | t.Identifier | t.Import | t.ImportExpression | t.JSXElement | t.JSXFragment | t.LogicalExpression | t.MarkoParseError | t.MemberExpression | t.MetaProperty | t.ModuleExpression | t.NewExpression | t.NullLiteral | t.NumericLiteral | t.ObjectExpression | t.OptionalCallExpression | t.OptionalMemberExpression | t.ParenthesizedExpression | t.PipelineBareFunction | t.PipelinePrimaryTopicReference | t.PipelineTopicExpression | t.RecordExpression | t.RegExpLiteral | t.SequenceExpression | t.StringLiteral | t.Super | t.TSAsExpression | t.TSInstantiationExpression | t.TSNonNullExpression | t.TSSatisfiesExpression | t.TSTypeAssertion | t.TaggedTemplateExpression | t.TemplateLiteral | t.ThisExpression | t.TopicReference | t.TupleExpression | t.TypeCastExpression | t.UnaryExpression | t.UpdateExpression | t.YieldExpression | undefined;
14
17
  export declare function getWalkString(section: Section): t.Expression | undefined;
@@ -1,5 +1,6 @@
1
1
  import { types as t } from "@marko/compiler";
2
2
  import { type Binding } from "../../util/references";
3
+ import { type DOMRuntimeHelpers } from "../../util/runtime";
3
4
  export declare const kNativeTagBinding: unique symbol;
4
5
  export declare const kSkipEndTag: unique symbol;
5
6
  declare const kTagContentAttr: unique symbol;
@@ -20,3 +21,11 @@ declare const _default: {
20
21
  };
21
22
  };
22
23
  export default _default;
24
+ /** How a statically named tag claims its controlled attrs during render;
25
+ * nothing for the many tags that control nothing. */
26
+ export declare function controllableClaimFor(tagName: string | undefined): "_controllable_input" | "_controllable_open" | "_controllable_select" | "_controllable_textarea" | undefined;
27
+ /** The resume-pass latch for a tag: `_attrs_script` resolves the control kind
28
+ * at run time, and a run-time tag name can be any of them. */
29
+ export declare function controllableScriptLatchFor(tagName: string | undefined): "_enable_controllable" | "_enable_controllable_input" | "_enable_controllable_open" | "_enable_controllable_select" | "_enable_controllable_textarea" | undefined;
30
+ /** Emits the latch once per program, like `_enable_catch`. */
31
+ export declare function enableControllable(helper: DOMRuntimeHelpers | undefined): void;