praxis-kit 7.4.0 → 7.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,6 +41,9 @@ function dynamic(resolve) {
41
41
  }
42
42
 
43
43
  // ../../lib/primitive/src/guards/foundational/is-defined.ts
44
+ function isDefined(value) {
45
+ return value !== void 0;
46
+ }
44
47
  function isUndefined(value) {
45
48
  return value === void 0;
46
49
  }
@@ -798,21 +801,65 @@ function getImplicitRole(tag, props) {
798
801
  return void 0;
799
802
  }
800
803
 
801
- // ../../lib/contract/src/diagnostics/aria.ts
804
+ // ../../lib/contract/src/diagnostics/anchor-accessibility.ts
802
805
  import { DiagnosticCategory, DiagnosticCode } from "../_shared/diagnostics.js";
806
+ function createDiagnostic(input) {
807
+ return { category: DiagnosticCategory.Accessibility, ...input };
808
+ }
809
+ var AnchorAccessibilityDiagnostics = {
810
+ roleButtonWithHref() {
811
+ return createDiagnostic({
812
+ code: DiagnosticCode.A11yAnchorRoleButtonWithHref,
813
+ severity: "warning",
814
+ message: 'role="button" on an <a> with an href overrides its navigation semantics for assistive technology; use a real <button> element, or remove href, if this element should not navigate.',
815
+ rationale: 'Assistive technology announces role="button" as a button, not a link \u2014 but the element still follows the link when activated by mouse or keyboard, which is confusing and inconsistent with how a button is expected to behave.',
816
+ suggestions: [
817
+ {
818
+ title: "Use a real <button>",
819
+ description: "If this element should not navigate, render a <button> instead of an <a>."
820
+ },
821
+ {
822
+ title: 'Remove role="button"',
823
+ description: "If this element should navigate, keep the default link role."
824
+ }
825
+ ]
826
+ });
827
+ },
828
+ ariaDisabledInert() {
829
+ return createDiagnostic({
830
+ code: DiagnosticCode.A11yAnchorAriaDisabledInert,
831
+ severity: "warning",
832
+ message: "aria-disabled does not prevent an <a> from being focused, clicked, or navigated via keyboard; remove href, or prevent navigation yourself, if this link should be inert.",
833
+ rationale: "Unlike a native form control, an <a> has no disabled state the browser enforces \u2014 aria-disabled only changes what assistive technology announces, not what actually happens when the link is activated by mouse or keyboard.",
834
+ suggestions: [
835
+ {
836
+ title: "Remove href",
837
+ description: "If this element is temporarily unavailable, remove href until it can be activated."
838
+ },
839
+ {
840
+ title: "Prevent navigation when disabled",
841
+ description: "Prevent the click and keyboard activation when the link is disabled so it behaves consistently for all users."
842
+ }
843
+ ]
844
+ });
845
+ }
846
+ };
847
+
848
+ // ../../lib/contract/src/diagnostics/aria.ts
849
+ import { DiagnosticCategory as DiagnosticCategory2, DiagnosticCode as DiagnosticCode2 } from "../_shared/diagnostics.js";
803
850
  var AriaDiagnostics = {
804
851
  /** Generic bridge for violations produced by external AriaRule functions. */
805
852
  fromViolation(v) {
806
853
  return {
807
- code: DiagnosticCode.AriaViolation,
808
- category: DiagnosticCategory.ARIA,
854
+ code: DiagnosticCode2.AriaViolation,
855
+ category: DiagnosticCategory2.ARIA,
809
856
  message: v.message
810
857
  };
811
858
  },
812
859
  attributeInvalid(key, role) {
813
860
  return {
814
- code: DiagnosticCode.AriaAttributeInvalid,
815
- category: DiagnosticCategory.ARIA,
861
+ code: DiagnosticCode2.AriaAttributeInvalid,
862
+ category: DiagnosticCategory2.ARIA,
816
863
  message: `"${key}" is not valid on role="${role}". It will be removed.`,
817
864
  rationale: "Invalid ARIA attributes are ignored by assistive technology and may trigger accessibility-tree warnings in browser devtools.",
818
865
  suggestions: [
@@ -825,8 +872,8 @@ var AriaDiagnostics = {
825
872
  },
826
873
  missingLiveRegion(role, impliedLive) {
827
874
  return {
828
- code: DiagnosticCode.AriaMissingLiveRegion,
829
- category: DiagnosticCategory.ARIA,
875
+ code: DiagnosticCode2.AriaMissingLiveRegion,
876
+ category: DiagnosticCategory2.ARIA,
830
877
  message: `role="${role}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`,
831
878
  rationale: "Live-region roles announce dynamic content changes to screen readers. Without aria-live the politeness level is unspecified and announcements may be silent.",
832
879
  suggestions: [
@@ -840,8 +887,8 @@ var AriaDiagnostics = {
840
887
  },
841
888
  missingAtomic(role) {
842
889
  return {
843
- code: DiagnosticCode.AriaMissingAtomic,
844
- category: DiagnosticCategory.ARIA,
890
+ code: DiagnosticCode2.AriaMissingAtomic,
891
+ category: DiagnosticCategory2.ARIA,
845
892
  message: `role="${role}" is a live region. Consider setting aria-atomic="true" if the full region should be announced as a unit, or aria-atomic="false" if only changed nodes should be read.`,
846
893
  rationale: "aria-atomic controls whether assistive technology announces the entire live region or only the changed nodes. Omitting it leaves the behaviour browser-defined."
847
894
  };
@@ -849,8 +896,8 @@ var AriaDiagnostics = {
849
896
  relevantInvalidTokens(invalid) {
850
897
  const quoted = invalid.map((t) => `"${t}"`).join(", ");
851
898
  return {
852
- code: DiagnosticCode.AriaRelevantInvalidToken,
853
- category: DiagnosticCategory.ARIA,
899
+ code: DiagnosticCode2.AriaRelevantInvalidToken,
900
+ category: DiagnosticCategory2.ARIA,
854
901
  message: `aria-relevant contains invalid token(s): ${quoted}. Valid tokens are: additions, removals, text, all.`,
855
902
  rationale: "aria-relevant accepts a space-separated list of change types. Unrecognised tokens are silently ignored by assistive technology, making the attribute ineffective.",
856
903
  suggestions: [
@@ -863,8 +910,8 @@ var AriaDiagnostics = {
863
910
  },
864
911
  relevantSuperseded() {
865
912
  return {
866
- code: DiagnosticCode.AriaRelevantSuperseded,
867
- category: DiagnosticCategory.ARIA,
913
+ code: DiagnosticCode2.AriaRelevantSuperseded,
914
+ category: DiagnosticCategory2.ARIA,
868
915
  message: 'aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.',
869
916
  rationale: '"all" is equivalent to "additions removals text". Combining it with other tokens is redundant and may confuse readers of the markup.',
870
917
  suggestions: [
@@ -877,8 +924,8 @@ var AriaDiagnostics = {
877
924
  },
878
925
  missingAccessibleName(tag) {
879
926
  return {
880
- code: DiagnosticCode.AriaMissingAccessibleName,
881
- category: DiagnosticCategory.ARIA,
927
+ code: DiagnosticCode2.AriaMissingAccessibleName,
928
+ category: DiagnosticCategory2.ARIA,
882
929
  message: `<${tag}> has no accessible name. Add aria-label or aria-labelledby.`,
883
930
  rationale: "Elements with a landmark or interactive role must have an accessible name so that assistive technology can identify them when presenting the page outline.",
884
931
  suggestions: [
@@ -895,8 +942,8 @@ var AriaDiagnostics = {
895
942
  },
896
943
  attributeOnPresentational(attr, tag) {
897
944
  return {
898
- code: DiagnosticCode.AriaAttributeOnPresentational,
899
- category: DiagnosticCategory.ARIA,
945
+ code: DiagnosticCode2.AriaAttributeOnPresentational,
946
+ category: DiagnosticCategory2.ARIA,
900
947
  message: `"${attr}" is not allowed on a presentational <${tag}>. Presentational elements are invisible to assistive technology.`,
901
948
  rationale: 'role="none" and role="presentation" (including <img alt="">) remove an element from the accessibility tree. ARIA attributes on such elements are ignored by assistive technology.',
902
949
  suggestions: [
@@ -909,8 +956,8 @@ var AriaDiagnostics = {
909
956
  },
910
957
  ariaHiddenOnFocusable(tag) {
911
958
  return {
912
- code: DiagnosticCode.AriaHiddenOnFocusable,
913
- category: DiagnosticCategory.ARIA,
959
+ code: DiagnosticCode2.AriaHiddenOnFocusable,
960
+ category: DiagnosticCategory2.ARIA,
914
961
  message: `aria-hidden="true" must not be used on focusable <${tag}> elements. Screen reader users who navigate by keyboard will encounter the element but receive no information about it.`,
915
962
  rationale: 'aria-hidden removes an element from the accessibility tree while leaving it keyboard-reachable. This creates a "ghost" \u2014 a focusable element assistive technology cannot describe.',
916
963
  suggestions: [
@@ -928,8 +975,8 @@ var AriaDiagnostics = {
928
975
  invalidAttributeValue(attr, value, expected) {
929
976
  const got = value === null ? "null" : value === void 0 ? "undefined" : typeof value === "string" ? `"${value}"` : String(value);
930
977
  return {
931
- code: DiagnosticCode.AriaInvalidAttributeValue,
932
- category: DiagnosticCategory.ARIA,
978
+ code: DiagnosticCode2.AriaInvalidAttributeValue,
979
+ category: DiagnosticCategory2.ARIA,
933
980
  message: `"${attr}" has an invalid value (${got}). Expected: ${expected}.`,
934
981
  rationale: "ARIA attributes with invalid values are silently ignored by assistive technology, making the markup semantically inert.",
935
982
  suggestions: [
@@ -942,8 +989,8 @@ var AriaDiagnostics = {
942
989
  },
943
990
  redundantAriaLevel(tag, level) {
944
991
  return {
945
- code: DiagnosticCode.AriaRedundantLevelAttribute,
946
- category: DiagnosticCategory.ARIA,
992
+ code: DiagnosticCode2.AriaRedundantLevelAttribute,
993
+ category: DiagnosticCategory2.ARIA,
947
994
  message: `aria-level="${level}" is redundant on <${tag}>: the element already has an implicit heading level of ${level}. Remove the attribute.`,
948
995
  rationale: 'Restating the implicit aria-level adds noise without semantic value. Use aria-level only to override the native heading level (e.g. aria-level="3" on <h2>).',
949
996
  suggestions: [
@@ -956,8 +1003,8 @@ var AriaDiagnostics = {
956
1003
  },
957
1004
  requiredProperty(attr, role) {
958
1005
  return {
959
- code: DiagnosticCode.AriaRequiredProperty,
960
- category: DiagnosticCategory.ARIA,
1006
+ code: DiagnosticCode2.AriaRequiredProperty,
1007
+ category: DiagnosticCategory2.ARIA,
961
1008
  message: `"${attr}" is required for role="${role}" but is missing.`,
962
1009
  rationale: `WAI-ARIA 1.2 specifies required states and properties for certain roles. Without "${attr}", assistive technology cannot correctly communicate the element's state to users.`,
963
1010
  suggestions: [
@@ -970,8 +1017,8 @@ var AriaDiagnostics = {
970
1017
  },
971
1018
  invalidRole(role, tag) {
972
1019
  return {
973
- code: DiagnosticCode.AriaInvalidRole,
974
- category: DiagnosticCategory.ARIA,
1020
+ code: DiagnosticCode2.AriaInvalidRole,
1021
+ category: DiagnosticCategory2.ARIA,
975
1022
  message: `Invalid role "${role ?? ""}" on <${tag}>.`,
976
1023
  rationale: "An unrecognised or misapplied ARIA role is ignored by assistive technology and may degrade the accessibility of the element."
977
1024
  };
@@ -979,12 +1026,12 @@ var AriaDiagnostics = {
979
1026
  };
980
1027
 
981
1028
  // ../../lib/contract/src/diagnostics/contract.ts
982
- import { DiagnosticCategory as DiagnosticCategory2, DiagnosticCode as DiagnosticCode2 } from "../_shared/diagnostics.js";
1029
+ import { DiagnosticCategory as DiagnosticCategory3, DiagnosticCode as DiagnosticCode3 } from "../_shared/diagnostics.js";
983
1030
  var ContractDiagnostics = {
984
1031
  unexpectedChild(typeName, index, context) {
985
1032
  return {
986
- code: DiagnosticCode2.UnexpectedChild,
987
- category: DiagnosticCategory2.Contract,
1033
+ code: DiagnosticCode3.UnexpectedChild,
1034
+ category: DiagnosticCategory3.Contract,
988
1035
  component: context,
989
1036
  message: `${context}: unexpected child "${typeName}" at index ${index}.`
990
1037
  };
@@ -992,69 +1039,69 @@ var ContractDiagnostics = {
992
1039
  ambiguousChild(typeName, index, ruleNames, context) {
993
1040
  const quoted = ruleNames.map((n) => `"${n}"`).join(" and ");
994
1041
  return {
995
- code: DiagnosticCode2.AmbiguousChild,
996
- category: DiagnosticCategory2.Contract,
1042
+ code: DiagnosticCode3.AmbiguousChild,
1043
+ category: DiagnosticCategory3.Contract,
997
1044
  component: context,
998
1045
  message: `${context}: child "${typeName}" at index ${index} matches multiple child rules: ${quoted}.`
999
1046
  };
1000
1047
  },
1001
1048
  cardinalityMin(ruleName, min, context) {
1002
1049
  return {
1003
- code: DiagnosticCode2.CardinalityMin,
1004
- category: DiagnosticCategory2.Contract,
1050
+ code: DiagnosticCode3.CardinalityMin,
1051
+ category: DiagnosticCategory3.Contract,
1005
1052
  component: context,
1006
1053
  message: `${context}: "${ruleName}" requires at least ${min}.`
1007
1054
  };
1008
1055
  },
1009
1056
  cardinalityMax(ruleName, max, context) {
1010
1057
  return {
1011
- code: DiagnosticCode2.CardinalityMax,
1012
- category: DiagnosticCategory2.Contract,
1058
+ code: DiagnosticCode3.CardinalityMax,
1059
+ category: DiagnosticCategory3.Contract,
1013
1060
  component: context,
1014
1061
  message: `${context}: "${ruleName}" allows at most ${max}.`
1015
1062
  };
1016
1063
  },
1017
1064
  positionViolation(ruleName, position, index, context) {
1018
1065
  return {
1019
- code: DiagnosticCode2.PositionViolation,
1020
- category: DiagnosticCategory2.Contract,
1066
+ code: DiagnosticCode3.PositionViolation,
1067
+ category: DiagnosticCategory3.Contract,
1021
1068
  component: context,
1022
1069
  message: `${context}: "${ruleName}" must be ${position}, got index ${index}`
1023
1070
  };
1024
1071
  },
1025
1072
  unknownVariantDim(component, label2, dim) {
1026
1073
  return {
1027
- code: DiagnosticCode2.ContractUnknownVariantDim,
1028
- category: DiagnosticCategory2.Contract,
1074
+ code: DiagnosticCode3.ContractUnknownVariantDim,
1075
+ category: DiagnosticCategory3.Contract,
1029
1076
  message: `${component}: ${label2} references unknown variant "${dim}".`
1030
1077
  };
1031
1078
  },
1032
1079
  unknownVariantValue(component, label2, dim, value, valid) {
1033
1080
  return {
1034
- code: DiagnosticCode2.ContractUnknownVariantValue,
1035
- category: DiagnosticCategory2.Contract,
1081
+ code: DiagnosticCode3.ContractUnknownVariantValue,
1082
+ category: DiagnosticCategory3.Contract,
1036
1083
  message: `${component}: ${label2} sets "${dim}" to unknown value "${value}" (valid: ${valid.join(", ")}).`
1037
1084
  };
1038
1085
  },
1039
1086
  unknownRecipeKey(component, key) {
1040
1087
  return {
1041
- code: DiagnosticCode2.ContractUnknownRecipeKey,
1042
- category: DiagnosticCategory2.Contract,
1088
+ code: DiagnosticCode3.ContractUnknownRecipeKey,
1089
+ category: DiagnosticCategory3.Contract,
1043
1090
  message: `${component} Unknown recipeKey "${key}" \u2014 no preset with that name exists.`
1044
1091
  };
1045
1092
  },
1046
1093
  invalidVariantValue(component, key, value) {
1047
1094
  return {
1048
- code: DiagnosticCode2.ContractInvalidVariantValue,
1049
- category: DiagnosticCategory2.Contract,
1095
+ code: DiagnosticCode3.ContractInvalidVariantValue,
1096
+ category: DiagnosticCategory3.Contract,
1050
1097
  message: `${component} Variant "${key}=${value}" is not a defined value for the "${key}" dimension.`
1051
1098
  };
1052
1099
  },
1053
1100
  allowedAsViolation(tag, allowedAs, component) {
1054
1101
  const allowed = allowedAs.map((t) => `"${String(t)}"`).join(", ");
1055
1102
  return {
1056
- code: DiagnosticCode2.AllowedAsViolation,
1057
- category: DiagnosticCategory2.Contract,
1103
+ code: DiagnosticCode3.AllowedAsViolation,
1104
+ category: DiagnosticCategory3.Contract,
1058
1105
  component,
1059
1106
  message: `<${component}>: "as" prop received "${tag}" but only [${allowed}] are allowed.`
1060
1107
  };
@@ -1062,68 +1109,68 @@ var ContractDiagnostics = {
1062
1109
  };
1063
1110
 
1064
1111
  // ../../lib/contract/src/diagnostics/html.ts
1065
- import { DiagnosticCategory as DiagnosticCategory3, DiagnosticCode as DiagnosticCode3 } from "../_shared/diagnostics.js";
1112
+ import { DiagnosticCategory as DiagnosticCategory4, DiagnosticCode as DiagnosticCode4 } from "../_shared/diagnostics.js";
1066
1113
  var ATTRIBUTE_IGNORED_CODES = {
1067
- checked: DiagnosticCode3.HtmlInputCheckedIgnoredForType,
1068
- multiple: DiagnosticCode3.HtmlInputMultipleIgnoredForType,
1069
- maxLength: DiagnosticCode3.HtmlInputMaxLengthIgnoredForType,
1070
- minLength: DiagnosticCode3.HtmlInputMinLengthIgnoredForType,
1071
- pattern: DiagnosticCode3.HtmlInputPatternIgnoredForType,
1072
- min: DiagnosticCode3.HtmlInputMinIgnoredForType,
1073
- max: DiagnosticCode3.HtmlInputMaxIgnoredForType,
1074
- step: DiagnosticCode3.HtmlInputStepIgnoredForType,
1075
- accept: DiagnosticCode3.HtmlInputAcceptIgnoredForType,
1076
- capture: DiagnosticCode3.HtmlInputCaptureIgnoredForType,
1077
- size: DiagnosticCode3.HtmlInputSizeIgnoredForType,
1078
- alt: DiagnosticCode3.HtmlInputAltIgnoredForType,
1079
- height: DiagnosticCode3.HtmlInputHeightIgnoredForType,
1080
- width: DiagnosticCode3.HtmlInputWidthIgnoredForType
1114
+ checked: DiagnosticCode4.HtmlInputCheckedIgnoredForType,
1115
+ multiple: DiagnosticCode4.HtmlInputMultipleIgnoredForType,
1116
+ maxLength: DiagnosticCode4.HtmlInputMaxLengthIgnoredForType,
1117
+ minLength: DiagnosticCode4.HtmlInputMinLengthIgnoredForType,
1118
+ pattern: DiagnosticCode4.HtmlInputPatternIgnoredForType,
1119
+ min: DiagnosticCode4.HtmlInputMinIgnoredForType,
1120
+ max: DiagnosticCode4.HtmlInputMaxIgnoredForType,
1121
+ step: DiagnosticCode4.HtmlInputStepIgnoredForType,
1122
+ accept: DiagnosticCode4.HtmlInputAcceptIgnoredForType,
1123
+ capture: DiagnosticCode4.HtmlInputCaptureIgnoredForType,
1124
+ size: DiagnosticCode4.HtmlInputSizeIgnoredForType,
1125
+ alt: DiagnosticCode4.HtmlInputAltIgnoredForType,
1126
+ height: DiagnosticCode4.HtmlInputHeightIgnoredForType,
1127
+ width: DiagnosticCode4.HtmlInputWidthIgnoredForType
1081
1128
  };
1082
1129
  var HtmlDiagnostics = {
1083
1130
  emptyRole(tag) {
1084
1131
  return {
1085
- code: DiagnosticCode3.HtmlEmptyRole,
1086
- category: DiagnosticCategory3.HTML,
1132
+ code: DiagnosticCode4.HtmlEmptyRole,
1133
+ category: DiagnosticCategory4.HTML,
1087
1134
  severity: "warning",
1088
1135
  message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`
1089
1136
  };
1090
1137
  },
1091
1138
  implicitRoleRedundant(tag, implicitRole) {
1092
1139
  return {
1093
- code: DiagnosticCode3.HtmlImplicitRoleRedundant,
1094
- category: DiagnosticCategory3.HTML,
1140
+ code: DiagnosticCode4.HtmlImplicitRoleRedundant,
1141
+ category: DiagnosticCategory4.HTML,
1095
1142
  severity: "warning",
1096
1143
  message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
1097
1144
  };
1098
1145
  },
1099
1146
  implicitRoleOverride(tag, implicitRole, role) {
1100
1147
  return {
1101
- code: DiagnosticCode3.HtmlImplicitRoleOverride,
1102
- category: DiagnosticCategory3.HTML,
1148
+ code: DiagnosticCode4.HtmlImplicitRoleOverride,
1149
+ category: DiagnosticCategory4.HTML,
1103
1150
  severity: "error",
1104
1151
  message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
1105
1152
  };
1106
1153
  },
1107
1154
  standaloneRegionOverride(tag, implicitRole) {
1108
1155
  return {
1109
- code: DiagnosticCode3.HtmlStandaloneRegionOverride,
1110
- category: DiagnosticCategory3.HTML,
1156
+ code: DiagnosticCode4.HtmlStandaloneRegionOverride,
1157
+ category: DiagnosticCategory4.HTML,
1111
1158
  severity: "error",
1112
1159
  message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
1113
1160
  };
1114
1161
  },
1115
1162
  landmarkRoleOverride(tag, implicitRole, role) {
1116
1163
  return {
1117
- code: DiagnosticCode3.HtmlLandmarkRoleOverride,
1118
- category: DiagnosticCategory3.HTML,
1164
+ code: DiagnosticCode4.HtmlLandmarkRoleOverride,
1165
+ category: DiagnosticCategory4.HTML,
1119
1166
  severity: "error",
1120
1167
  message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
1121
1168
  };
1122
1169
  },
1123
1170
  invalidChild(child, parent, allowed) {
1124
1171
  return {
1125
- code: DiagnosticCode3.HtmlInvalidChild,
1126
- category: DiagnosticCategory3.HTML,
1172
+ code: DiagnosticCode4.HtmlInvalidChild,
1173
+ category: DiagnosticCategory4.HTML,
1127
1174
  severity: "error",
1128
1175
  message: `<${child}> is not a valid direct child of <${parent}>. Allowed: ${allowed}.`
1129
1176
  };
@@ -1131,8 +1178,8 @@ var HtmlDiagnostics = {
1131
1178
  roleNotPermitted(tag, role, allowedRoles) {
1132
1179
  const allowed = allowedRoles.length > 0 ? allowedRoles.map((r) => `"${r}"`).join(", ") : "none \u2014 no explicit role is permitted on this element";
1133
1180
  return {
1134
- code: DiagnosticCode3.HtmlRoleNotPermitted,
1135
- category: DiagnosticCategory3.HTML,
1181
+ code: DiagnosticCode4.HtmlRoleNotPermitted,
1182
+ category: DiagnosticCategory4.HTML,
1136
1183
  severity: "error",
1137
1184
  message: `role="${role}" is not permitted on <${tag}>. Allowed alternate role(s): ${allowed}.`,
1138
1185
  rationale: 'The WAI-ARIA "ARIA in HTML" specification restricts which explicit roles a native element may take. A role outside that set is ignored or produces undefined behavior in assistive technology.'
@@ -1143,8 +1190,8 @@ var HtmlDiagnostics = {
1143
1190
  input: {
1144
1191
  unsupportedType(type) {
1145
1192
  return {
1146
- code: DiagnosticCode3.HtmlInputUnsupportedType,
1147
- category: DiagnosticCategory3.HTML,
1193
+ code: DiagnosticCode4.HtmlInputUnsupportedType,
1194
+ category: DiagnosticCategory4.HTML,
1148
1195
  severity: "warning",
1149
1196
  message: `type="${type}" is not a value defined by the HTML specification. Browsers silently fall back to type="text".`,
1150
1197
  rationale: 'An unrecognized input type is not invalid markup \u2014 the spec requires the "text" fallback \u2014 but it usually means a typo, since the input keeps working while silently losing the intended type-specific behavior (validation, virtual keyboard, picker UI).',
@@ -1164,7 +1211,7 @@ var HtmlDiagnostics = {
1164
1211
  if (!code) throw new Error(`No DiagnosticCode registered for input attribute "${attribute}"`);
1165
1212
  return {
1166
1213
  code,
1167
- category: DiagnosticCategory3.HTML,
1214
+ category: DiagnosticCategory4.HTML,
1168
1215
  severity: "warning",
1169
1216
  message: `"${attribute}" is ignored on <input type="${type}">.`,
1170
1217
  rationale: `"${attribute}" only has an effect when type is one of: ${allowed}. Browsers silently ignore it on other input types.`,
@@ -1176,18 +1223,30 @@ var HtmlDiagnostics = {
1176
1223
  ]
1177
1224
  };
1178
1225
  }
1226
+ },
1227
+ // Reserved for <a>-specific facts (HTML3201–3299, see codes.ts).
1228
+ anchor: {
1229
+ dangerousHref(href) {
1230
+ return {
1231
+ code: DiagnosticCode4.HtmlAnchorDangerousHref,
1232
+ category: DiagnosticCategory4.HTML,
1233
+ severity: "warning",
1234
+ message: `href="${href}" uses a scheme that executes attacker-controlled content when navigated to. It has been removed.`,
1235
+ rationale: '"javascript:", "data:", and "vbscript:" URLs are a common XSS vector when href comes from untrusted input \u2014 none of the three are needed for legitimate navigation.'
1236
+ };
1237
+ }
1179
1238
  }
1180
1239
  };
1181
1240
 
1182
1241
  // ../../lib/contract/src/diagnostics/input-accessibility.ts
1183
- import { DiagnosticCategory as DiagnosticCategory4, DiagnosticCode as DiagnosticCode4 } from "../_shared/diagnostics.js";
1242
+ import { DiagnosticCategory as DiagnosticCategory5, DiagnosticCode as DiagnosticCode5 } from "../_shared/diagnostics.js";
1184
1243
  function accessibilityFact(input) {
1185
- return { category: DiagnosticCategory4.Accessibility, ...input };
1244
+ return { category: DiagnosticCategory5.Accessibility, ...input };
1186
1245
  }
1187
1246
  var InputAccessibilityDiagnostics = {
1188
1247
  missingAccessibleName() {
1189
1248
  return accessibilityFact({
1190
- code: DiagnosticCode4.A11yInputMissingAccessibleName,
1249
+ code: DiagnosticCode5.A11yInputMissingAccessibleName,
1191
1250
  severity: "warning",
1192
1251
  message: "This input has no accessible name. Add an associated <label>, aria-label, or aria-labelledby.",
1193
1252
  rationale: "Assistive technology announces a form field by its accessible name; without one, users of screen readers cannot tell what the field is for.",
@@ -1202,7 +1261,7 @@ var InputAccessibilityDiagnostics = {
1202
1261
  },
1203
1262
  placeholderIsNotLabel() {
1204
1263
  return accessibilityFact({
1205
- code: DiagnosticCode4.A11yInputPlaceholderNotLabel,
1264
+ code: DiagnosticCode5.A11yInputPlaceholderNotLabel,
1206
1265
  severity: "warning",
1207
1266
  message: "Placeholder text does not provide an accessible name. Add an associated <label>, aria-label, or aria-labelledby.",
1208
1267
  rationale: "Placeholder text disappears as users interact with the field and is not treated as the control's accessible name by many assistive technologies.",
@@ -1217,7 +1276,7 @@ var InputAccessibilityDiagnostics = {
1217
1276
  },
1218
1277
  passwordMissingAutocomplete() {
1219
1278
  return accessibilityFact({
1220
- code: DiagnosticCode4.A11yInputPasswordAutocomplete,
1279
+ code: DiagnosticCode5.A11yInputPasswordAutocomplete,
1221
1280
  severity: "warning",
1222
1281
  message: "Password inputs should specify an autoComplete value.",
1223
1282
  rationale: "Without an explicit autocomplete hint, password managers and browsers cannot reliably tell a sign-in field apart from a password-creation field.",
@@ -1235,7 +1294,7 @@ var InputAccessibilityDiagnostics = {
1235
1294
  },
1236
1295
  requiredReadOnlyConflict() {
1237
1296
  return accessibilityFact({
1238
- code: DiagnosticCode4.A11yInputRequiredReadOnlyConflict,
1297
+ code: DiagnosticCode5.A11yInputRequiredReadOnlyConflict,
1239
1298
  severity: "warning",
1240
1299
  message: "The required and readOnly attributes are both present. A read-only field cannot satisfy required validation through user interaction.",
1241
1300
  rationale: "This combination is valid HTML but usually indicates an unintended state. Consider using disabled instead of readOnly, or only applying required when the field is editable."
@@ -1244,28 +1303,28 @@ var InputAccessibilityDiagnostics = {
1244
1303
  };
1245
1304
 
1246
1305
  // ../../lib/contract/src/diagnostics/slot.ts
1247
- import { DiagnosticCategory as DiagnosticCategory5, DiagnosticCode as DiagnosticCode5 } from "../_shared/diagnostics.js";
1306
+ import { DiagnosticCategory as DiagnosticCategory6, DiagnosticCode as DiagnosticCode6 } from "../_shared/diagnostics.js";
1248
1307
  var SlotDiagnostics = {
1249
1308
  exclusive(name) {
1250
1309
  return {
1251
- code: DiagnosticCode5.SlotExclusive,
1252
- category: DiagnosticCategory5.Contract,
1310
+ code: DiagnosticCode6.SlotExclusive,
1311
+ category: DiagnosticCategory6.Contract,
1253
1312
  component: name,
1254
1313
  message: `${name}: "as" and "asChild" are mutually exclusive`
1255
1314
  };
1256
1315
  },
1257
1316
  singleChildRequired(name, elementTerm) {
1258
1317
  return {
1259
- code: DiagnosticCode5.SlotSingleChild,
1260
- category: DiagnosticCategory5.Contract,
1318
+ code: DiagnosticCode6.SlotSingleChild,
1319
+ category: DiagnosticCategory6.Contract,
1261
1320
  component: name,
1262
1321
  message: `${name}: asChild requires a ${elementTerm} child`
1263
1322
  };
1264
1323
  },
1265
1324
  singleChildExceeded(name, elementTerm, count) {
1266
1325
  return {
1267
- code: DiagnosticCode5.SlotSingleChild,
1268
- category: DiagnosticCategory5.Contract,
1326
+ code: DiagnosticCode6.SlotSingleChild,
1327
+ category: DiagnosticCategory6.Contract,
1269
1328
  component: name,
1270
1329
  message: `${name}: asChild requires exactly one ${elementTerm} child, got ${count}`
1271
1330
  };
@@ -1273,16 +1332,16 @@ var SlotDiagnostics = {
1273
1332
  discardedChildren(name, elementTerm, count) {
1274
1333
  const suffix = count === 1 ? "" : "ren";
1275
1334
  return {
1276
- code: DiagnosticCode5.SlotDiscardedChildren,
1277
- category: DiagnosticCategory5.Contract,
1335
+ code: DiagnosticCode6.SlotDiscardedChildren,
1336
+ category: DiagnosticCategory6.Contract,
1278
1337
  component: name,
1279
1338
  message: `${name}: asChild discarded ${count} non-element child${suffix} \u2014 only ${elementTerm}s are valid asChild children.`
1280
1339
  };
1281
1340
  },
1282
1341
  renderFnRequired(name, received) {
1283
1342
  return {
1284
- code: DiagnosticCode5.SlotRenderFn,
1285
- category: DiagnosticCategory5.Contract,
1343
+ code: DiagnosticCode6.SlotRenderFn,
1344
+ category: DiagnosticCategory6.Contract,
1286
1345
  component: name,
1287
1346
  message: `${name}: asChild requires a render function as children, got ${received}`
1288
1347
  };
@@ -2028,6 +2087,27 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
2028
2087
  };
2029
2088
 
2030
2089
  // ../../lib/contract/src/aria/factories.ts
2090
+ function invalidWithoutFix(input) {
2091
+ return {
2092
+ valid: false,
2093
+ fixable: false,
2094
+ severity: input.severity,
2095
+ ...isDefined(input.attribute) && { attribute: input.attribute },
2096
+ ...isDefined(input.message) && { message: input.message },
2097
+ ...isDefined(input.diagnostic) && { diagnostic: input.diagnostic }
2098
+ };
2099
+ }
2100
+ function invalidWithFix(input) {
2101
+ return {
2102
+ valid: false,
2103
+ fixable: true,
2104
+ severity: input.severity,
2105
+ ...isDefined(input.attribute) && { attribute: input.attribute },
2106
+ ...isDefined(input.message) && { message: input.message },
2107
+ ...isDefined(input.diagnostic) && { diagnostic: input.diagnostic },
2108
+ fix: input.fix
2109
+ };
2110
+ }
2031
2111
  function removeProp(props, key) {
2032
2112
  const next = { ...props };
2033
2113
  delete next[key];
@@ -2043,6 +2123,34 @@ function removeAttributeFix(attribute) {
2043
2123
  }
2044
2124
  });
2045
2125
  }
2126
+ function defineRuleMetadata(rule, metadata2) {
2127
+ const descriptors = {};
2128
+ for (const key of Object.keys(metadata2)) {
2129
+ descriptors[key] = { value: metadata2[key], enumerable: false };
2130
+ }
2131
+ Object.defineProperties(rule, descriptors);
2132
+ return rule;
2133
+ }
2134
+ function createRemoveAttributeRule(attribute, options) {
2135
+ const { when, severity = "warning", message, diagnostic, readsProps, tags } = options;
2136
+ const fix = removeAttributeFix(attribute);
2137
+ const rule = (context) => {
2138
+ if (!when(context)) return [];
2139
+ return [
2140
+ invalidWithFix({
2141
+ severity,
2142
+ attribute,
2143
+ ...isDefined(message) && { message },
2144
+ ...isDefined(diagnostic) && { diagnostic: diagnostic(context) },
2145
+ fix
2146
+ })
2147
+ ];
2148
+ };
2149
+ return defineRuleMetadata(rule, {
2150
+ ...isDefined(readsProps) && { readsProps },
2151
+ ...isDefined(tags) && { tags }
2152
+ });
2153
+ }
2046
2154
 
2047
2155
  // ../../lib/contract/src/children/get-type-name.ts
2048
2156
  function getTypeName(value) {
@@ -2431,6 +2539,52 @@ var P_BLOCKED_TAGS = [
2431
2539
  "ul"
2432
2540
  ];
2433
2541
 
2542
+ // ../core/src/html/anchor-rules.ts
2543
+ var DANGEROUS_URL_SCHEMES = ["javascript:", "data:", "vbscript:"];
2544
+ function normalizeForSchemeCheck(href) {
2545
+ return href.replace(/[\x00-\x20]/g, "").toLowerCase();
2546
+ }
2547
+ function isDangerousUrl(href) {
2548
+ if (!isString(href)) return false;
2549
+ const normalized = normalizeForSchemeCheck(href);
2550
+ return DANGEROUS_URL_SCHEMES.some((scheme) => normalized.startsWith(scheme));
2551
+ }
2552
+ var dangerousHrefRule = createRemoveAttributeRule("href", {
2553
+ when: ({ props }) => isDangerousUrl(props.href),
2554
+ severity: "warning",
2555
+ diagnostic: ({ props }) => HtmlDiagnostics.anchor.dangerousHref(props.href),
2556
+ readsProps: ["href"],
2557
+ tags: ["a"]
2558
+ });
2559
+ var roleButtonWithHrefRule = Object.assign(
2560
+ ({ props }) => {
2561
+ if (props.role !== "button" || !isString(props.href) || props.href.length === 0) {
2562
+ return [];
2563
+ }
2564
+ const diagnostic = AnchorAccessibilityDiagnostics.roleButtonWithHref();
2565
+ return [invalidWithoutFix({ severity: diagnostic.severity, attribute: "role", diagnostic })];
2566
+ },
2567
+ { readsProps: ["role", "href"], tags: ["a"] }
2568
+ );
2569
+ var ariaDisabledInertRule = Object.assign(
2570
+ ({ props }) => {
2571
+ const ariaDisabled = props["aria-disabled"];
2572
+ const isDisabled = ariaDisabled === true || ariaDisabled === "true";
2573
+ const hasHref = isString(props.href) && props.href.length > 0;
2574
+ if (!isDisabled || !hasHref) return [];
2575
+ const diagnostic = AnchorAccessibilityDiagnostics.ariaDisabledInert();
2576
+ return [
2577
+ invalidWithoutFix({ severity: diagnostic.severity, attribute: "aria-disabled", diagnostic })
2578
+ ];
2579
+ },
2580
+ { readsProps: ["aria-disabled", "href"], tags: ["a"] }
2581
+ );
2582
+ var ANCHOR_RULES = [
2583
+ dangerousHrefRule,
2584
+ roleButtonWithHrefRule,
2585
+ ariaDisabledInertRule
2586
+ ];
2587
+
2434
2588
  // ../core/src/html/spec/vocabulary/input.ts
2435
2589
  var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
2436
2590
  var NUMERIC_INPUT_TYPES = [
@@ -2510,12 +2664,12 @@ function createInputAttributeTypeRule({
2510
2664
  // ../core/src/html/spec/validators/mutually-exclusive-validator.ts
2511
2665
  function createMutuallyExclusiveRule({
2512
2666
  props: conflictingProps,
2513
- diagnostic: createDiagnostic
2667
+ diagnostic: createDiagnostic2
2514
2668
  }) {
2515
2669
  const [first, second] = conflictingProps;
2516
2670
  const rule = ({ tag, props }) => {
2517
2671
  if (tag !== "input" || !props[first] || !props[second]) return [];
2518
- const diagnostic = createDiagnostic();
2672
+ const diagnostic = createDiagnostic2();
2519
2673
  return [{ valid: false, fixable: false, severity: diagnostic.severity, diagnostic }];
2520
2674
  };
2521
2675
  return Object.assign(rule, { readsProps: conflictingProps, tags: ["input"] });
@@ -2895,7 +3049,8 @@ var HTML_ARIA_RULES = [
2895
3049
  landmarkRoleRule,
2896
3050
  landmarkAccessibleNameRule,
2897
3051
  roleNotPermittedRule,
2898
- ...INPUT_RULES
3052
+ ...INPUT_RULES,
3053
+ ...ANCHOR_RULES
2899
3054
  ];
2900
3055
 
2901
3056
  // ../core/src/html/contracts/helpers.ts
@@ -3305,19 +3460,6 @@ function createClassPipeline(resolved) {
3305
3460
  };
3306
3461
  }
3307
3462
 
3308
- // ../../lib/pipeline-kit/src/factory/define-pipeline.ts
3309
- function definePipeline(factory) {
3310
- const cache = /* @__PURE__ */ new WeakMap();
3311
- return (resolved) => {
3312
- let pipeline = cache.get(resolved);
3313
- if (!pipeline) {
3314
- pipeline = factory(resolved);
3315
- cache.set(resolved, pipeline);
3316
- }
3317
- return pipeline;
3318
- };
3319
- }
3320
-
3321
3463
  // ../core/src/options/resolve-factory-options.ts
3322
3464
  import { resolveDiagnostics, silentDiagnostics } from "../_shared/diagnostics.js";
3323
3465
  var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
@@ -3421,25 +3563,66 @@ function validateRenderProps(diagnostics, options, props, recipeKey) {
3421
3563
  }
3422
3564
  }
3423
3565
 
3566
+ // ../../lib/pipeline-kit/src/factory/define-pipeline.ts
3567
+ function definePipeline(factory) {
3568
+ const cache = /* @__PURE__ */ new WeakMap();
3569
+ return (resolved) => {
3570
+ let pipeline = cache.get(resolved);
3571
+ if (!pipeline) {
3572
+ pipeline = factory(resolved);
3573
+ cache.set(resolved, pipeline);
3574
+ }
3575
+ return pipeline;
3576
+ };
3577
+ }
3578
+
3579
+ // ../core/src/factory/pipelines/generic.ts
3580
+ var createTagPipeline = (resolved) => makeResolveTag(resolved.defaultTag);
3581
+ var createPropsPipeline = (resolved) => (props) => mergeProps(resolved.defaultProps, props);
3582
+ var createHtmlPropNormalizersPipeline = () => getHtmlPropNormalizers;
3583
+ var createHtmlChildrenEvaluatorPipeline = () => getHtmlChildrenEvaluator;
3584
+ var createStylingClassPipeline = (resolved) => createClassPipeline(resolved);
3585
+ var memoizedTagPipeline = definePipeline(createTagPipeline);
3586
+ var memoizedPropsPipeline = definePipeline(createPropsPipeline);
3587
+ var memoizedHtmlPropNormalizersPipeline = definePipeline(createHtmlPropNormalizersPipeline);
3588
+ var memoizedHtmlChildrenEvaluatorPipeline = definePipeline(
3589
+ createHtmlChildrenEvaluatorPipeline
3590
+ );
3591
+ var memoizedClassPipeline = definePipeline(createStylingClassPipeline);
3592
+
3593
+ // ../core/src/factory/pipelines/aria.ts
3594
+ function resolveAriaRules(resolved) {
3595
+ return [.../* @__PURE__ */ new Set([...HTML_ARIA_RULES, ...resolved.ariaRules ?? []])];
3596
+ }
3597
+ var createAriaPipeline = (resolved) => {
3598
+ const rules = resolveAriaRules(resolved);
3599
+ const engine = new AriaPolicyEngine(resolved.diagnostics, rules.length ? { rules } : void 0);
3600
+ return (tag, props) => engine.validate(tag, props);
3601
+ };
3602
+ var memoizedAriaPipeline = definePipeline(createAriaPipeline);
3603
+ function resolveAriaPassthrough(_tag, props) {
3604
+ return { props };
3605
+ }
3606
+
3424
3607
  // ../core/src/factory/plugin-invariants.ts
3425
3608
  import { throwDiagnostics } from "../_shared/diagnostics.js";
3426
3609
 
3427
3610
  // ../core/src/factory/plugin-diagnostics.ts
3428
- import { DiagnosticCategory as DiagnosticCategory6, DiagnosticCode as DiagnosticCode6 } from "../_shared/diagnostics.js";
3611
+ import { DiagnosticCategory as DiagnosticCategory7, DiagnosticCode as DiagnosticCode7 } from "../_shared/diagnostics.js";
3429
3612
  var PluginDiagnostics = {
3430
3613
  invalidShape(received) {
3431
- const got = received === null ? "null" : typeof received;
3614
+ const got = isNull(received) ? "null" : typeof received;
3432
3615
  return {
3433
- code: DiagnosticCode6.PluginInvalidShape,
3434
- category: DiagnosticCategory6.Internal,
3616
+ code: DiagnosticCode7.PluginInvalidShape,
3617
+ category: DiagnosticCategory7.Internal,
3435
3618
  message: `[praxis-kit] Plugin factory must return an object with a 'pipeline' function. Got: ${got}.`
3436
3619
  };
3437
3620
  },
3438
3621
  pipelineReturnType(received) {
3439
- const got = received === null ? "null" : Array.isArray(received) ? "array" : typeof received;
3622
+ const got = isNull(received) ? "null" : Array.isArray(received) ? "array" : typeof received;
3440
3623
  return {
3441
- code: DiagnosticCode6.PluginPipelineReturnType,
3442
- category: DiagnosticCategory6.Internal,
3624
+ code: DiagnosticCode7.PluginPipelineReturnType,
3625
+ category: DiagnosticCategory7.Internal,
3443
3626
  message: `[praxis-kit] Plugin pipeline must return a string. Got: ${got}.`
3444
3627
  };
3445
3628
  }
@@ -3447,60 +3630,41 @@ var PluginDiagnostics = {
3447
3630
 
3448
3631
  // ../core/src/factory/plugin-invariants.ts
3449
3632
  function assertPluginShape(result) {
3450
- if (result === null || typeof result !== "object")
3633
+ if (isNull(result) || !isObject(result))
3451
3634
  throwDiagnostics.error(PluginDiagnostics.invalidShape(result));
3452
3635
  const plugin = result;
3453
- if (typeof plugin.pipeline !== "function")
3454
- throwDiagnostics.error(PluginDiagnostics.invalidShape(result));
3636
+ if (!isFunction(plugin.pipeline)) throwDiagnostics.error(PluginDiagnostics.invalidShape(result));
3455
3637
  }
3456
3638
  function guardPipeline(pipeline) {
3457
3639
  if (process.env.NODE_ENV === "production") return pipeline;
3458
3640
  return function guardedPipeline(tag, props, className, recipe) {
3459
3641
  const result = pipeline(tag, props, className, recipe);
3460
- if (typeof result !== "string")
3461
- throwDiagnostics.error(PluginDiagnostics.pipelineReturnType(result));
3642
+ if (!isString(result)) throwDiagnostics.error(PluginDiagnostics.pipelineReturnType(result));
3462
3643
  return result;
3463
3644
  };
3464
3645
  }
3465
3646
 
3466
- // ../core/src/factory/create-polymorphic2.ts
3467
- var createTagPipeline = (resolved) => makeResolveTag(resolved.defaultTag);
3468
- var createPropsPipeline = (resolved) => (props) => mergeProps(resolved.defaultProps, props);
3469
- var createHtmlPropNormalizersPipeline = () => getHtmlPropNormalizers;
3470
- var createHtmlChildrenEvaluatorPipeline = () => getHtmlChildrenEvaluator;
3471
- var createStylingClassPipeline = (resolved) => createClassPipeline(resolved);
3472
- function resolveAriaRules(resolved) {
3473
- return [.../* @__PURE__ */ new Set([...HTML_ARIA_RULES, ...resolved.ariaRules ?? []])];
3474
- }
3475
- var createAriaPipeline = (resolved) => {
3476
- const rules = resolveAriaRules(resolved);
3477
- const engine = new AriaPolicyEngine(resolved.diagnostics, rules.length ? { rules } : void 0);
3478
- return (tag, props) => engine.validate(tag, props);
3479
- };
3480
- var memoizedTagPipeline = definePipeline(createTagPipeline);
3481
- var memoizedPropsPipeline = definePipeline(createPropsPipeline);
3482
- var memoizedHtmlPropNormalizersPipeline = definePipeline(createHtmlPropNormalizersPipeline);
3483
- var memoizedHtmlChildrenEvaluatorPipeline = definePipeline(createHtmlChildrenEvaluatorPipeline);
3484
- var memoizedClassPipeline = definePipeline(createStylingClassPipeline);
3485
- var memoizedAriaPipeline = definePipeline(createAriaPipeline);
3486
- function resolveAriaPassthrough(_tag, props) {
3487
- return { props };
3488
- }
3647
+ // ../core/src/factory/pipelines/styling.ts
3489
3648
  function resolveClassPlugin(factory, resolved, diagnostics) {
3490
3649
  if (!factory) return { pluginResult: void 0, classPipeline: memoizedClassPipeline(resolved) };
3491
3650
  const pluginResult = factory(resolved, diagnostics);
3492
3651
  assertPluginShape(pluginResult);
3493
3652
  return { pluginResult, classPipeline: guardPipeline(pluginResult.pipeline) };
3494
3653
  }
3495
- function createPolymorphic2(options = {}) {
3654
+
3655
+ // ../core/src/factory/create-polymorphic.ts
3656
+ function eraseResolvedShape(resolved) {
3657
+ return resolved;
3658
+ }
3659
+ function createPolymorphic(options = {}) {
3496
3660
  const baseResolved = resolveFactoryOptions(options);
3497
- const anyBaseResolved = baseResolved;
3661
+ const anyBaseResolved = eraseResolvedShape(baseResolved);
3498
3662
  const resolved = Object.freeze({
3499
3663
  ...baseResolved,
3500
3664
  htmlPropNormalizersFn: memoizedHtmlPropNormalizersPipeline(anyBaseResolved),
3501
3665
  htmlChildrenEvaluatorFn: memoizedHtmlChildrenEvaluatorPipeline(anyBaseResolved)
3502
3666
  });
3503
- const anyResolved = resolved;
3667
+ const anyResolved = eraseResolvedShape(resolved);
3504
3668
  if (process.env.NODE_ENV !== "production") {
3505
3669
  validateFactoryOptions(resolved, resolved.diagnostics);
3506
3670
  }
@@ -3541,7 +3705,7 @@ function enforceAllowedAs(tag, allowedAs, diagnostics, displayName) {
3541
3705
  // ../../lib/adapter-utils/src/runtime/build-core-runtime.ts
3542
3706
  var EMPTY_SET = /* @__PURE__ */ new Set();
3543
3707
  function buildCoreRuntime(normalized) {
3544
- const runtime = createPolymorphic2(normalized);
3708
+ const runtime = createPolymorphic(normalized);
3545
3709
  const ownedKeys = "classPlugin" in runtime ? runtime.classPlugin.ownedKeys ?? EMPTY_SET : EMPTY_SET;
3546
3710
  return { runtime, ownedKeys };
3547
3711
  }
@@ -3946,7 +4110,11 @@ function createContractComponent(options) {
3946
4110
  const onElementRef = useCallback((el) => {
3947
4111
  if (!onElement) return;
3948
4112
  if (el) {
3949
- cleanupRef.current = onElement(el, () => propsRef.current) ?? void 0;
4113
+ cleanupRef.current?.();
4114
+ cleanupRef.current = onElement(
4115
+ el,
4116
+ () => propsRef.current
4117
+ ) ?? void 0;
3950
4118
  } else {
3951
4119
  cleanupRef.current?.();
3952
4120
  cleanupRef.current = void 0;