praxis-kit 0.1.0 → 1.0.2
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/{build-runtime-CJ_nQEaZ.js → build-runtime-cNkW-D62.js} +331 -207
- package/dist/contract/index.d.ts +396 -14
- package/dist/contract/index.js +66 -1
- package/dist/eslint/index.js +11 -5
- package/dist/{index-BIBd_iPD.d.ts → index-zJDSXTxL.d.ts} +366 -67
- package/dist/lit/index.d.ts +267 -55
- package/dist/lit/index.js +275 -215
- package/dist/preact/index.d.ts +296 -52
- package/dist/preact/index.js +277 -210
- package/dist/react/index.d.ts +13 -4
- package/dist/react/index.js +22 -72
- package/dist/react/legacy.d.ts +9 -4
- package/dist/react/legacy.js +14 -2
- package/dist/solid/index.d.ts +253 -40
- package/dist/solid/index.js +271 -210
- package/dist/svelte/index.d.ts +203 -33
- package/dist/svelte/index.js +270 -207
- package/dist/tailwind/index.d.ts +12 -1
- package/dist/vite-plugin/index.js +289 -199
- package/dist/vue/index.d.ts +252 -41
- package/dist/vue/index.js +277 -210
- package/dist/web/index.d.ts +287 -53
- package/dist/web/index.js +275 -215
- package/package.json +5 -5
|
@@ -11,11 +11,6 @@ function invariant(condition, message) {
|
|
|
11
11
|
if (!condition) panic(message);
|
|
12
12
|
}
|
|
13
13
|
//#endregion
|
|
14
|
-
//#region ../../lib/adapter-utils/src/runtime/define-component.ts
|
|
15
|
-
function defineContractComponent(options) {
|
|
16
|
-
return (factory) => factory(options);
|
|
17
|
-
}
|
|
18
|
-
//#endregion
|
|
19
14
|
//#region ../../lib/adapter-utils/src/runtime/assemble-compound-component.ts
|
|
20
15
|
/**
|
|
21
16
|
* Assembles a compound component by attaching sub-components to a
|
|
@@ -1010,6 +1005,59 @@ function finalizeComponent(component, defaultTag, subComponents) {
|
|
|
1010
1005
|
return assembleCompoundComponent(component, subComponents);
|
|
1011
1006
|
}
|
|
1012
1007
|
//#endregion
|
|
1008
|
+
//#region ../../lib/adapter-utils/src/runtime/is-factory-options-like.ts
|
|
1009
|
+
/**
|
|
1010
|
+
* Loosely validates one recognized `FactoryOptions` field's runtime shape.
|
|
1011
|
+
* "Loosely" because the field's declared type is itself parameterized by a
|
|
1012
|
+
* generic (Props, Variants, TPlugin, ...) that's erased at runtime — these
|
|
1013
|
+
* checks confirm the field is the right *kind* of value (object, function,
|
|
1014
|
+
* string), not that it satisfies its exact generic instantiation, which no
|
|
1015
|
+
* runtime check can ever do.
|
|
1016
|
+
*
|
|
1017
|
+
* Covers every field `FactoryOptions` itself declares — identical across
|
|
1018
|
+
* every adapter, since they all extend the same core type. Adapter-specific
|
|
1019
|
+
* additions (React's `slotComponent`/`artifact`, every adapter's own
|
|
1020
|
+
* `filterProps`, etc.) are passed in by the caller as extra entries.
|
|
1021
|
+
*/
|
|
1022
|
+
const FACTORY_OPTIONS_FIELD_VALIDATORS = {
|
|
1023
|
+
tag: (v) => v === void 0 || isString(v),
|
|
1024
|
+
name: (v) => v === void 0 || isString(v),
|
|
1025
|
+
defaults: (v) => v === void 0 || isObject(v),
|
|
1026
|
+
normalize: (v) => v === void 0 || isFunction(v),
|
|
1027
|
+
styling: (v) => v === void 0 || isObject(v),
|
|
1028
|
+
enforcement: (v) => v === void 0 || isObject(v),
|
|
1029
|
+
diagnostics: (v) => v === void 0 || isObject(v),
|
|
1030
|
+
subComponents: (v) => v === void 0 || isObject(v),
|
|
1031
|
+
onElement: (v) => v === void 0 || isFunction(v)
|
|
1032
|
+
};
|
|
1033
|
+
/**
|
|
1034
|
+
* Type guard narrowing the generic `FactoryOptions` shape down to an
|
|
1035
|
+
* adapter-specific factory options type `T` — the type each adapter's
|
|
1036
|
+
* `buildRuntime` is declared against.
|
|
1037
|
+
*
|
|
1038
|
+
* Walks every own enumerable property on `options` and checks it against
|
|
1039
|
+
* `FACTORY_OPTIONS_FIELD_VALIDATORS` plus `extraFieldValidators` (the
|
|
1040
|
+
* adapter's own additions on top of `FactoryOptions`): an unrecognized key,
|
|
1041
|
+
* or a recognized key holding a value of the wrong kind, fails the guard.
|
|
1042
|
+
* This is a genuine structural check, not a relabeled assertion — though it
|
|
1043
|
+
* necessarily stops at each field's runtime *kind*, since the field's actual
|
|
1044
|
+
* generic instantiation is erased at runtime and no guard can validate it.
|
|
1045
|
+
* That part remains the caller's responsibility, same as with any other
|
|
1046
|
+
* generic function in TypeScript.
|
|
1047
|
+
*/
|
|
1048
|
+
function isFactoryOptionsLike(options, extraFieldValidators) {
|
|
1049
|
+
if (!isObject(options)) return false;
|
|
1050
|
+
const validators = {
|
|
1051
|
+
...FACTORY_OPTIONS_FIELD_VALIDATORS,
|
|
1052
|
+
...extraFieldValidators
|
|
1053
|
+
};
|
|
1054
|
+
for (const [key, value] of Object.entries(options)) {
|
|
1055
|
+
const validate = validators[key];
|
|
1056
|
+
if (!validate || !validate(value)) return false;
|
|
1057
|
+
}
|
|
1058
|
+
return true;
|
|
1059
|
+
}
|
|
1060
|
+
//#endregion
|
|
1013
1061
|
//#region ../../lib/contract/src/aria/aria-role-policy.ts
|
|
1014
1062
|
function getImplicitRole(tag, props) {
|
|
1015
1063
|
if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
|
|
@@ -1555,72 +1603,100 @@ var InvariantBase = class {
|
|
|
1555
1603
|
}
|
|
1556
1604
|
};
|
|
1557
1605
|
//#endregion
|
|
1558
|
-
//#region ../../lib/contract/src/aria/
|
|
1559
|
-
const REQUIRED_ARIA_PROPERTIES = {
|
|
1560
|
-
combobox: ["aria-expanded"],
|
|
1561
|
-
option: ["aria-selected"],
|
|
1562
|
-
slider: ["aria-valuenow"],
|
|
1563
|
-
scrollbar: ["aria-controls", "aria-valuenow"],
|
|
1564
|
-
spinbutton: ["aria-valuenow"]
|
|
1565
|
-
};
|
|
1566
|
-
//#endregion
|
|
1567
|
-
//#region ../../lib/contract/src/aria/spec/roles/name-required.ts
|
|
1568
|
-
const NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
|
|
1569
|
-
//#endregion
|
|
1570
|
-
//#region ../../lib/contract/src/aria/spec/roles/name-prohibited.ts
|
|
1571
|
-
const NAME_PROHIBITED_ROLES = /* @__PURE__ */ new Set([
|
|
1572
|
-
"caption",
|
|
1573
|
-
"code",
|
|
1574
|
-
"deletion",
|
|
1575
|
-
"emphasis",
|
|
1576
|
-
"generic",
|
|
1577
|
-
"insertion",
|
|
1578
|
-
"none",
|
|
1579
|
-
"paragraph",
|
|
1580
|
-
"presentation",
|
|
1581
|
-
"strong",
|
|
1582
|
-
"subscript",
|
|
1583
|
-
"superscript"
|
|
1584
|
-
]);
|
|
1585
|
-
const NAME_PROHIBITED_ATTRIBUTES = ["aria-label", "aria-labelledby"];
|
|
1586
|
-
//#endregion
|
|
1587
|
-
//#region ../../lib/contract/src/aria/spec/validators/required-properties-validator.ts
|
|
1588
|
-
const NO_VIOLATIONS$1 = [{ valid: true }];
|
|
1589
|
-
function requiredAttributeByRole(roles, attribute) {
|
|
1590
|
-
return Object.fromEntries([...roles].map((role) => [role, [attribute]]));
|
|
1591
|
-
}
|
|
1606
|
+
//#region ../../lib/contract/src/aria/plan-cache.ts
|
|
1592
1607
|
/**
|
|
1593
|
-
*
|
|
1608
|
+
* Validation-plan cache machinery for `AriaPolicyEngine`: computing a cache key from a
|
|
1609
|
+
* (tag, props) usage site, and diffing/replaying the props transformation a validation pass
|
|
1610
|
+
* produced (an {@link AriaPlan}'s `removals`/`updates`) without re-running the ARIA rule
|
|
1611
|
+
* pipeline itself. Extracted because these four functions are a cohesive subsystem in their own
|
|
1612
|
+
* right — a small revalidation-caching scheme — not specifically ARIA *policy*; the actual
|
|
1613
|
+
* cache storage (an `LRUCache` instance) stays owned by `AriaPolicyEngine` itself, since it's
|
|
1614
|
+
* per-engine-instance state, not something this module needs to hold.
|
|
1615
|
+
*/
|
|
1616
|
+
/**
|
|
1617
|
+
* Cache key covering only the aria-relevant subset of props (tag + role + aria-* attrs) —
|
|
1618
|
+
* exactly what the built-in pipeline reads. Non-aria props (className, onClick, etc.) do
|
|
1619
|
+
* not affect built-in ARIA decisions and are excluded so cache hits survive re-renders
|
|
1620
|
+
* that only change non-aria props. This key alone is unsound for a policy engine's own
|
|
1621
|
+
* extra rules, which may read arbitrary props outside this set — extend it with
|
|
1622
|
+
* {@link extraRulesKeySuffix}, or bypass the cache, to account for that.
|
|
1594
1623
|
*
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1624
|
+
* Returns `null` (meaning "don't cache") when `tag` isn't a plain intrinsic string tag —
|
|
1625
|
+
* `isString(tag)` inline rather than importing `AriaPolicyEngine`'s own `isIntrinsicTag`: the
|
|
1626
|
+
* check is a one-liner, and importing it back from the engine module would be a needless
|
|
1627
|
+
* dependency in the other direction for a plan-cache module the engine itself depends on.
|
|
1597
1628
|
*/
|
|
1598
|
-
function
|
|
1599
|
-
if (!
|
|
1600
|
-
const
|
|
1601
|
-
if (
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1629
|
+
function createPlanKey(tag, props) {
|
|
1630
|
+
if (!isString(tag)) return null;
|
|
1631
|
+
const parts = [tag];
|
|
1632
|
+
if (isString(props.role)) parts.push(`role:${props.role}`);
|
|
1633
|
+
if (tag === "input" && isString(props.type)) parts.push(`type:${props.type}`);
|
|
1634
|
+
if (tag === "img") parts.push(`alt:${props.alt === "" ? "empty" : "present"}`);
|
|
1635
|
+
const ariaEntries = [];
|
|
1636
|
+
iterate.forEachEntry(props, (k, v) => {
|
|
1637
|
+
if (!k.startsWith("aria-")) return;
|
|
1638
|
+
if (!isString(v) && !isNumber(v) && typeof v !== "boolean") return;
|
|
1639
|
+
ariaEntries.push(`${k}:${String(v)}`);
|
|
1640
|
+
});
|
|
1641
|
+
if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
|
|
1642
|
+
return parts.join("|");
|
|
1643
|
+
}
|
|
1644
|
+
/**
|
|
1645
|
+
* Extends the base cache key with the props each extra rule declares it reads (`readsProps`).
|
|
1646
|
+
* Returns `null` — meaning "don't cache" — if any extra rule omits `readsProps` (it may read
|
|
1647
|
+
* arbitrary props the key can't account for) or if a declared prop's value isn't a primitive
|
|
1648
|
+
* (object/array identity isn't stably representable in a string key).
|
|
1649
|
+
*/
|
|
1650
|
+
function extraRulesKeySuffix(extraRules, props) {
|
|
1651
|
+
const parts = [];
|
|
1652
|
+
for (const rule of extraRules) {
|
|
1653
|
+
const readsProps = rule.readsProps;
|
|
1654
|
+
if (!isNonNull(readsProps)) return null;
|
|
1655
|
+
for (const propKey of readsProps) {
|
|
1656
|
+
const v = props[propKey];
|
|
1657
|
+
if (isDefined(v) && !isString(v) && !isNumber(v) && typeof v !== "boolean") return null;
|
|
1658
|
+
parts.push(`x:${propKey}:${String(v)}`);
|
|
1659
|
+
}
|
|
1612
1660
|
}
|
|
1613
|
-
return
|
|
1661
|
+
return parts.sort().join("|");
|
|
1662
|
+
}
|
|
1663
|
+
/** Diffs a validation pass's input/output props into a replayable plan: which keys were removed
|
|
1664
|
+
* entirely, and which keys were added or changed value (and to what). */
|
|
1665
|
+
function computePlan(inputProps, resultProps) {
|
|
1666
|
+
const removals = /* @__PURE__ */ new Set();
|
|
1667
|
+
const updates = {};
|
|
1668
|
+
iterate.forEachKey(inputProps, (key) => {
|
|
1669
|
+
if (!(key in resultProps)) removals.add(key);
|
|
1670
|
+
});
|
|
1671
|
+
iterate.forEachEntry(resultProps, (key, resultVal) => {
|
|
1672
|
+
if (inputProps[key] !== resultVal) updates[key] = resultVal;
|
|
1673
|
+
});
|
|
1674
|
+
return {
|
|
1675
|
+
removals,
|
|
1676
|
+
updates
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
/** Replays a cached plan's removals/updates against a fresh `props` object, without re-running
|
|
1680
|
+
* the rule pipeline that originally produced the plan. */
|
|
1681
|
+
function applyPlan(props, removals, updates) {
|
|
1682
|
+
const hasRemovals = removals.size > 0;
|
|
1683
|
+
const hasUpdates = Object.keys(updates).length > 0;
|
|
1684
|
+
if (!hasRemovals && !hasUpdates) return props;
|
|
1685
|
+
const next = {};
|
|
1686
|
+
iterate.forEachEntry(props, (k, v) => {
|
|
1687
|
+
if (!removals.has(k)) next[k] = v;
|
|
1688
|
+
});
|
|
1689
|
+
Object.assign(next, updates);
|
|
1690
|
+
return next;
|
|
1614
1691
|
}
|
|
1615
1692
|
//#endregion
|
|
1616
|
-
//#region ../../lib/contract/src/aria/spec/
|
|
1617
|
-
const
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1693
|
+
//#region ../../lib/contract/src/aria/spec/attributes/aria-relevant-tokens.ts
|
|
1694
|
+
const VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set([
|
|
1695
|
+
"additions",
|
|
1696
|
+
"removals",
|
|
1697
|
+
"text",
|
|
1698
|
+
"all"
|
|
1622
1699
|
]);
|
|
1623
|
-
const ATOMIC_REQUIREMENTS = requiredAttributeByRole(LIVE_REGION_ROLES.keys(), "aria-atomic");
|
|
1624
1700
|
//#endregion
|
|
1625
1701
|
//#region ../../lib/contract/src/aria/spec/attributes/aria-value-types.ts
|
|
1626
1702
|
const ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
|
|
@@ -1745,24 +1821,6 @@ const ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
|
|
|
1745
1821
|
}]
|
|
1746
1822
|
]);
|
|
1747
1823
|
//#endregion
|
|
1748
|
-
//#region ../../lib/contract/src/aria/spec/attributes/aria-relevant-tokens.ts
|
|
1749
|
-
const VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set([
|
|
1750
|
-
"additions",
|
|
1751
|
-
"removals",
|
|
1752
|
-
"text",
|
|
1753
|
-
"all"
|
|
1754
|
-
]);
|
|
1755
|
-
//#endregion
|
|
1756
|
-
//#region ../../lib/contract/src/aria/spec/elements/heading-implicit-levels.ts
|
|
1757
|
-
const HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
|
|
1758
|
-
["h1", 1],
|
|
1759
|
-
["h2", 2],
|
|
1760
|
-
["h3", 3],
|
|
1761
|
-
["h4", 4],
|
|
1762
|
-
["h5", 5],
|
|
1763
|
-
["h6", 6]
|
|
1764
|
-
]);
|
|
1765
|
-
//#endregion
|
|
1766
1824
|
//#region ../../lib/contract/src/aria/spec/elements/focusable.ts
|
|
1767
1825
|
function parseTabIndex(raw) {
|
|
1768
1826
|
if (typeof raw === "number") return Number.isInteger(raw) ? raw : void 0;
|
|
@@ -1813,24 +1871,156 @@ function isPotentiallyFocusable(tag, props) {
|
|
|
1813
1871
|
}
|
|
1814
1872
|
}
|
|
1815
1873
|
//#endregion
|
|
1816
|
-
//#region ../../lib/contract/src/aria/
|
|
1874
|
+
//#region ../../lib/contract/src/aria/spec/elements/heading-implicit-levels.ts
|
|
1875
|
+
const HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
|
|
1876
|
+
["h1", 1],
|
|
1877
|
+
["h2", 2],
|
|
1878
|
+
["h3", 3],
|
|
1879
|
+
["h4", 4],
|
|
1880
|
+
["h5", 5],
|
|
1881
|
+
["h6", 6]
|
|
1882
|
+
]);
|
|
1883
|
+
//#endregion
|
|
1884
|
+
//#region ../../lib/contract/src/aria/spec/validators/required-properties-validator.ts
|
|
1817
1885
|
const NO_VIOLATIONS = [{ valid: true }];
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
return isString(tag);
|
|
1886
|
+
function requiredAttributeByRole(roles, attribute) {
|
|
1887
|
+
return Object.fromEntries([...roles].map((role) => [role, [attribute]]));
|
|
1821
1888
|
}
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1889
|
+
/**
|
|
1890
|
+
* Reports missing attributes required by an element's effective ARIA role.
|
|
1891
|
+
*
|
|
1892
|
+
* Shared by validators that differ only in their role-to-attribute mapping and diagnostic
|
|
1893
|
+
* generation.
|
|
1894
|
+
*/
|
|
1895
|
+
function checkRequiredAttributes(requirement, { props, effectiveRole }) {
|
|
1896
|
+
if (!effectiveRole) return NO_VIOLATIONS;
|
|
1897
|
+
const requiredAttributes = requirement.attributesByRole[effectiveRole];
|
|
1898
|
+
if (!requiredAttributes) return NO_VIOLATIONS;
|
|
1899
|
+
const results = [];
|
|
1900
|
+
for (const attribute of requiredAttributes) {
|
|
1901
|
+
if (attribute in props) continue;
|
|
1902
|
+
results.push({
|
|
1903
|
+
valid: false,
|
|
1904
|
+
fixable: false,
|
|
1905
|
+
severity: "warning",
|
|
1906
|
+
attribute,
|
|
1907
|
+
diagnostic: requirement.diagnosticFor(attribute, effectiveRole)
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
return results;
|
|
1825
1911
|
}
|
|
1912
|
+
//#endregion
|
|
1913
|
+
//#region ../../lib/contract/src/aria/spec/roles/live-region.ts
|
|
1914
|
+
const LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
|
|
1915
|
+
["alert", "assertive"],
|
|
1916
|
+
["status", "polite"],
|
|
1917
|
+
["log", "polite"],
|
|
1918
|
+
["timer", "off"]
|
|
1919
|
+
]);
|
|
1920
|
+
const ATOMIC_REQUIREMENTS = requiredAttributeByRole(LIVE_REGION_ROLES.keys(), "aria-atomic");
|
|
1921
|
+
//#endregion
|
|
1922
|
+
//#region ../../lib/contract/src/aria/spec/roles/name-prohibited.ts
|
|
1923
|
+
const NAME_PROHIBITED_ROLES = /* @__PURE__ */ new Set([
|
|
1924
|
+
"caption",
|
|
1925
|
+
"code",
|
|
1926
|
+
"deletion",
|
|
1927
|
+
"emphasis",
|
|
1928
|
+
"generic",
|
|
1929
|
+
"insertion",
|
|
1930
|
+
"none",
|
|
1931
|
+
"paragraph",
|
|
1932
|
+
"presentation",
|
|
1933
|
+
"strong",
|
|
1934
|
+
"subscript",
|
|
1935
|
+
"superscript"
|
|
1936
|
+
]);
|
|
1937
|
+
const NAME_PROHIBITED_ATTRIBUTES = ["aria-label", "aria-labelledby"];
|
|
1938
|
+
//#endregion
|
|
1939
|
+
//#region ../../lib/contract/src/aria/spec/roles/name-required.ts
|
|
1940
|
+
const NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
|
|
1941
|
+
//#endregion
|
|
1942
|
+
//#region ../../lib/contract/src/aria/spec/roles/required-properties.ts
|
|
1943
|
+
const REQUIRED_ARIA_PROPERTIES = {
|
|
1944
|
+
combobox: ["aria-expanded"],
|
|
1945
|
+
option: ["aria-selected"],
|
|
1946
|
+
slider: ["aria-valuenow"],
|
|
1947
|
+
scrollbar: ["aria-controls", "aria-valuenow"],
|
|
1948
|
+
spinbutton: ["aria-valuenow"]
|
|
1949
|
+
};
|
|
1950
|
+
//#endregion
|
|
1951
|
+
//#region ../../lib/contract/src/aria/value-validation.ts
|
|
1952
|
+
/**
|
|
1953
|
+
* ARIA attribute value type system: what counts as a valid value for a given
|
|
1954
|
+
* {@link AriaValueType}, and how to describe what was expected when it isn't. Extracted from
|
|
1955
|
+
* `AriaPolicyEngine` — these three functions are cohesive on their own (they're describing a
|
|
1956
|
+
* type system, not policy), and `#checkAriaAttributeValues` (kept in `aria-policy-engine.ts`
|
|
1957
|
+
* alongside every other rule implementation — see that file's own pipeline) is now just a thin
|
|
1958
|
+
* caller of {@link isValidAriaValue}/{@link describeExpected}.
|
|
1959
|
+
*/
|
|
1960
|
+
/**
|
|
1961
|
+
* Strict numeric coercion for ARIA attribute values. Unlike `parseFloat`/`parseInt`, the whole
|
|
1962
|
+
* string must be a number — `"12abc"` is rejected, not read as `12` — and an empty / whitespace
|
|
1963
|
+
* string is rejected rather than coerced to `0` the way `Number("")` would.
|
|
1964
|
+
*
|
|
1965
|
+
* Exported (not local to `isValidAriaValue`) because `AriaPolicyEngine.#checkRedundantAriaLevel`
|
|
1966
|
+
* also needs it, independent of the general ARIA value-type check this module otherwise exists
|
|
1967
|
+
* for — `aria-level`'s "redundant" check is about comparing a numeric attribute value to a
|
|
1968
|
+
* known implicit level, not about validating the value's type.
|
|
1969
|
+
*/
|
|
1826
1970
|
function strictNumeric(value) {
|
|
1827
|
-
if (
|
|
1828
|
-
if (
|
|
1971
|
+
if (isNumber(value)) return Number.isFinite(value) ? value : void 0;
|
|
1972
|
+
if (!isString(value)) return void 0;
|
|
1829
1973
|
const trimmed = value.trim();
|
|
1830
1974
|
if (trimmed === "") return void 0;
|
|
1831
1975
|
const n = Number(trimmed);
|
|
1832
1976
|
return Number.isFinite(n) ? n : void 0;
|
|
1833
1977
|
}
|
|
1978
|
+
/** Returns whether `value` satisfies `type`'s own value-type constraint (boolean/tristate/
|
|
1979
|
+
* number/integer/enum) — the WAI-ARIA attribute value type system, independent of which
|
|
1980
|
+
* attribute or role it's being checked for. */
|
|
1981
|
+
function isValidAriaValue(value, type) {
|
|
1982
|
+
switch (type.kind) {
|
|
1983
|
+
case "boolean": return value === "true" || value === "false" || value === true || value === false;
|
|
1984
|
+
case "tristate": return value === "true" || value === "false" || value === "mixed" || value === true || value === false;
|
|
1985
|
+
case "number": return strictNumeric(value) !== void 0;
|
|
1986
|
+
case "integer": {
|
|
1987
|
+
const n = strictNumeric(value);
|
|
1988
|
+
if (isUndefined(n) || !Number.isInteger(n)) return false;
|
|
1989
|
+
if (isDefined(type.min) && n < type.min) return false;
|
|
1990
|
+
if (isDefined(type.max) && n > type.max) return false;
|
|
1991
|
+
return true;
|
|
1992
|
+
}
|
|
1993
|
+
case "enum": return isString(value) && type.values.has(value);
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
/** Describes what a valid value for `type` looks like, for use in an invalid-value diagnostic
|
|
1997
|
+
* message (e.g. `aria-valuenow` got `"abc"`, expected "a finite number"). */
|
|
1998
|
+
function describeExpected(type) {
|
|
1999
|
+
switch (type.kind) {
|
|
2000
|
+
case "boolean": return "\"true\" or \"false\"";
|
|
2001
|
+
case "tristate": return "\"true\", \"false\", or \"mixed\"";
|
|
2002
|
+
case "number": return "a finite number";
|
|
2003
|
+
case "integer": {
|
|
2004
|
+
const parts = ["an integer"];
|
|
2005
|
+
if (isDefined(type.min) && isDefined(type.max)) parts.push(`between ${type.min} and ${type.max}`);
|
|
2006
|
+
else if (isDefined(type.min)) parts.push(`≥ ${type.min}`);
|
|
2007
|
+
else if (isDefined(type.max)) parts.push(`≤ ${type.max}`);
|
|
2008
|
+
return parts.join(" ");
|
|
2009
|
+
}
|
|
2010
|
+
case "enum": return [...type.values].map((v) => `"${v}"`).join(", ");
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
//#endregion
|
|
2014
|
+
//#region ../../lib/contract/src/aria/aria-policy-engine.ts
|
|
2015
|
+
const VALID_RESULT = [{ valid: true }];
|
|
2016
|
+
const NO_VARIANT_KEYS = /* @__PURE__ */ new Set();
|
|
2017
|
+
function isIntrinsicTag(tag) {
|
|
2018
|
+
return isString(tag);
|
|
2019
|
+
}
|
|
2020
|
+
function omitProp(obj, key) {
|
|
2021
|
+
const { [key]: _, ...rest } = obj;
|
|
2022
|
+
return rest;
|
|
2023
|
+
}
|
|
1834
2024
|
var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
1835
2025
|
#extraRules;
|
|
1836
2026
|
#variantKeys;
|
|
@@ -1963,73 +2153,20 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
1963
2153
|
else this.warn(d);
|
|
1964
2154
|
});
|
|
1965
2155
|
}
|
|
1966
|
-
static #createPlanKey(tag, props) {
|
|
1967
|
-
if (!isIntrinsicTag(tag)) return null;
|
|
1968
|
-
const parts = [tag];
|
|
1969
|
-
if (typeof props.role === "string") parts.push(`role:${props.role}`);
|
|
1970
|
-
if (tag === "input" && typeof props.type === "string") parts.push(`type:${props.type}`);
|
|
1971
|
-
if (tag === "img") parts.push(`alt:${props.alt === "" ? "empty" : "present"}`);
|
|
1972
|
-
const ariaEntries = [];
|
|
1973
|
-
iterate.forEachEntry(props, (k, v) => {
|
|
1974
|
-
if (!k.startsWith("aria-")) return;
|
|
1975
|
-
if (!isString(v) && !isNumber(v) && typeof v !== "boolean") return;
|
|
1976
|
-
ariaEntries.push(`${k}:${String(v)}`);
|
|
1977
|
-
});
|
|
1978
|
-
if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
|
|
1979
|
-
return parts.join("|");
|
|
1980
|
-
}
|
|
1981
|
-
static #extraRulesKeySuffix(extraRules, props) {
|
|
1982
|
-
const parts = [];
|
|
1983
|
-
for (const rule of extraRules) {
|
|
1984
|
-
const readsProps = rule.readsProps;
|
|
1985
|
-
if (!isNonNull(readsProps)) return null;
|
|
1986
|
-
for (const propKey of readsProps) {
|
|
1987
|
-
const v = props[propKey];
|
|
1988
|
-
if (v !== void 0 && !isString(v) && !isNumber(v) && typeof v !== "boolean") return null;
|
|
1989
|
-
parts.push(`x:${propKey}:${String(v)}`);
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
return parts.sort().join("|");
|
|
1993
|
-
}
|
|
1994
|
-
static #computePlan(inputProps, resultProps) {
|
|
1995
|
-
const removals = /* @__PURE__ */ new Set();
|
|
1996
|
-
const updates = {};
|
|
1997
|
-
iterate.forEachKey(inputProps, (key) => {
|
|
1998
|
-
if (!(key in resultProps)) removals.add(key);
|
|
1999
|
-
});
|
|
2000
|
-
iterate.forEachEntry(resultProps, (key, resultVal) => {
|
|
2001
|
-
if (inputProps[key] !== resultVal) updates[key] = resultVal;
|
|
2002
|
-
});
|
|
2003
|
-
return {
|
|
2004
|
-
removals,
|
|
2005
|
-
updates
|
|
2006
|
-
};
|
|
2007
|
-
}
|
|
2008
|
-
static #applyPlan(props, removals, updates) {
|
|
2009
|
-
const hasRemovals = removals.size > 0;
|
|
2010
|
-
const hasUpdates = Object.keys(updates).length > 0;
|
|
2011
|
-
if (!hasRemovals && !hasUpdates) return props;
|
|
2012
|
-
const next = {};
|
|
2013
|
-
iterate.forEachEntry(props, (k, v) => {
|
|
2014
|
-
if (!removals.has(k)) next[k] = v;
|
|
2015
|
-
});
|
|
2016
|
-
Object.assign(next, updates);
|
|
2017
|
-
return next;
|
|
2018
|
-
}
|
|
2019
2156
|
validate(tag, props, extraProps) {
|
|
2020
2157
|
const ruleProps = extraProps ?? props;
|
|
2021
|
-
const baseKey =
|
|
2158
|
+
const baseKey = createPlanKey(tag, props);
|
|
2022
2159
|
let key = baseKey;
|
|
2023
2160
|
if (this.#extraRules.length > 0) {
|
|
2024
|
-
const suffix =
|
|
2161
|
+
const suffix = extraRulesKeySuffix(this.#extraRules, ruleProps);
|
|
2025
2162
|
key = isNonNull(baseKey) && isNonNull(suffix) ? `${baseKey}|${suffix}` : null;
|
|
2026
2163
|
}
|
|
2027
2164
|
if (!isNull(key)) {
|
|
2028
2165
|
const cached = this.#planCache.get(key);
|
|
2029
|
-
if (cached
|
|
2166
|
+
if (isDefined(cached)) {
|
|
2030
2167
|
if (cached.violations.length > 0) this.report(cached.violations);
|
|
2031
2168
|
return {
|
|
2032
|
-
props:
|
|
2169
|
+
props: applyPlan(props, cached.removals, cached.updates),
|
|
2033
2170
|
violations: cached.violations
|
|
2034
2171
|
};
|
|
2035
2172
|
}
|
|
@@ -2037,7 +2174,7 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2037
2174
|
const result = this.#extraRules.length ? AriaPolicyEngine.#evaluateWithRules(tag, props, this.#extraRules, extraProps, this.#variantKeys) : AriaPolicyEngine.evaluate(tag, props);
|
|
2038
2175
|
if (result.violations.length > 0) this.report(result.violations);
|
|
2039
2176
|
if (!isNull(key)) {
|
|
2040
|
-
const { removals, updates } =
|
|
2177
|
+
const { removals, updates } = computePlan(props, result.props);
|
|
2041
2178
|
const plan = {
|
|
2042
2179
|
removals,
|
|
2043
2180
|
updates,
|
|
@@ -2128,7 +2265,7 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2128
2265
|
];
|
|
2129
2266
|
static #checkInvalidRoleOverride({ tag, props, implicitRole }) {
|
|
2130
2267
|
const role = props.role;
|
|
2131
|
-
if (!implicitRole ||
|
|
2268
|
+
if (!implicitRole || isUndefined(role) || role === implicitRole) return VALID_RESULT;
|
|
2132
2269
|
if (isStrongImplicitRole(tag) && role === "region") {
|
|
2133
2270
|
const diagnostic = HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role);
|
|
2134
2271
|
return [{
|
|
@@ -2139,11 +2276,11 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2139
2276
|
diagnostic
|
|
2140
2277
|
}];
|
|
2141
2278
|
}
|
|
2142
|
-
return
|
|
2279
|
+
return VALID_RESULT;
|
|
2143
2280
|
}
|
|
2144
2281
|
static #checkRedundantRole({ tag, props, implicitRole }) {
|
|
2145
2282
|
const role = props.role;
|
|
2146
|
-
if (!implicitRole ||
|
|
2283
|
+
if (!implicitRole || isUndefined(role) || role !== implicitRole) return VALID_RESULT;
|
|
2147
2284
|
const diagnostic = HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole);
|
|
2148
2285
|
return [{
|
|
2149
2286
|
valid: false,
|
|
@@ -2154,8 +2291,8 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2154
2291
|
}];
|
|
2155
2292
|
}
|
|
2156
2293
|
static #checkStandaloneRegion({ tag, props, implicitRole }) {
|
|
2157
|
-
if (props.role !== "region") return
|
|
2158
|
-
if (!hasStandaloneRole(tag)) return
|
|
2294
|
+
if (props.role !== "region") return VALID_RESULT;
|
|
2295
|
+
if (!hasStandaloneRole(tag)) return VALID_RESULT;
|
|
2159
2296
|
const diagnostic = HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag);
|
|
2160
2297
|
return [{
|
|
2161
2298
|
valid: false,
|
|
@@ -2166,7 +2303,7 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2166
2303
|
}];
|
|
2167
2304
|
}
|
|
2168
2305
|
static #checkInvalidAriaAttributes({ tag, props, effectiveRole }) {
|
|
2169
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
2306
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return VALID_RESULT;
|
|
2170
2307
|
const results = [];
|
|
2171
2308
|
iterate.forEachEntry(props, (key) => {
|
|
2172
2309
|
if (!key.startsWith("aria-")) return;
|
|
@@ -2183,63 +2320,33 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2183
2320
|
});
|
|
2184
2321
|
return results;
|
|
2185
2322
|
}
|
|
2186
|
-
static #isValidAriaValue(value, type) {
|
|
2187
|
-
switch (type.kind) {
|
|
2188
|
-
case "boolean": return value === "true" || value === "false" || value === true || value === false;
|
|
2189
|
-
case "tristate": return value === "true" || value === "false" || value === "mixed" || value === true || value === false;
|
|
2190
|
-
case "number": return strictNumeric(value) !== void 0;
|
|
2191
|
-
case "integer": {
|
|
2192
|
-
const n = strictNumeric(value);
|
|
2193
|
-
if (n === void 0 || !Number.isInteger(n)) return false;
|
|
2194
|
-
if (type.min !== void 0 && n < type.min) return false;
|
|
2195
|
-
if (type.max !== void 0 && n > type.max) return false;
|
|
2196
|
-
return true;
|
|
2197
|
-
}
|
|
2198
|
-
case "enum": return typeof value === "string" && type.values.has(value);
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
static #describeExpected(type) {
|
|
2202
|
-
switch (type.kind) {
|
|
2203
|
-
case "boolean": return "\"true\" or \"false\"";
|
|
2204
|
-
case "tristate": return "\"true\", \"false\", or \"mixed\"";
|
|
2205
|
-
case "number": return "a finite number";
|
|
2206
|
-
case "integer": {
|
|
2207
|
-
const parts = ["an integer"];
|
|
2208
|
-
if (type.min !== void 0 && type.max !== void 0) parts.push(`between ${type.min} and ${type.max}`);
|
|
2209
|
-
else if (type.min !== void 0) parts.push(`≥ ${type.min}`);
|
|
2210
|
-
else if (type.max !== void 0) parts.push(`≤ ${type.max}`);
|
|
2211
|
-
return parts.join(" ");
|
|
2212
|
-
}
|
|
2213
|
-
case "enum": return [...type.values].map((v) => `"${v}"`).join(", ");
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2216
2323
|
static #checkAriaAttributeValues({ props, effectiveRole }) {
|
|
2217
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
2324
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return VALID_RESULT;
|
|
2218
2325
|
const results = [];
|
|
2219
2326
|
iterate.forEachEntry(props, (key, value) => {
|
|
2220
2327
|
if (!key.startsWith("aria-")) return;
|
|
2221
2328
|
const type = ARIA_VALUE_TYPES.get(key);
|
|
2222
2329
|
if (!isNonNull(type)) return;
|
|
2223
|
-
if (
|
|
2330
|
+
if (isValidAriaValue(value, type)) return;
|
|
2224
2331
|
results.push({
|
|
2225
2332
|
valid: false,
|
|
2226
2333
|
fixable: true,
|
|
2227
2334
|
severity: "warning",
|
|
2228
2335
|
attribute: key,
|
|
2229
|
-
diagnostic: AriaDiagnostics.invalidAttributeValue(key, value,
|
|
2336
|
+
diagnostic: AriaDiagnostics.invalidAttributeValue(key, value, describeExpected(type)),
|
|
2230
2337
|
fix: AriaPolicyEngine.#makeRemoveAttributeFix(key)
|
|
2231
2338
|
});
|
|
2232
2339
|
});
|
|
2233
2340
|
return results;
|
|
2234
2341
|
}
|
|
2235
2342
|
static #checkRedundantAriaLevel({ tag, props, effectiveRole }) {
|
|
2236
|
-
if (effectiveRole === "none" || effectiveRole === "presentation") return
|
|
2343
|
+
if (effectiveRole === "none" || effectiveRole === "presentation") return VALID_RESULT;
|
|
2237
2344
|
const implicitLevel = HEADING_IMPLICIT_LEVELS.get(tag);
|
|
2238
|
-
if (!isNonNull(implicitLevel)) return
|
|
2345
|
+
if (!isNonNull(implicitLevel)) return VALID_RESULT;
|
|
2239
2346
|
const raw = props["aria-level"];
|
|
2240
|
-
if (!isNonNull(raw)) return
|
|
2347
|
+
if (!isNonNull(raw)) return VALID_RESULT;
|
|
2241
2348
|
const n = strictNumeric(raw);
|
|
2242
|
-
if (n === void 0 || n !== implicitLevel) return
|
|
2349
|
+
if (n === void 0 || n !== implicitLevel) return VALID_RESULT;
|
|
2243
2350
|
return [{
|
|
2244
2351
|
valid: false,
|
|
2245
2352
|
fixable: true,
|
|
@@ -2250,7 +2357,7 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2250
2357
|
}];
|
|
2251
2358
|
}
|
|
2252
2359
|
static #checkNameProhibitedRoles({ props, effectiveRole }) {
|
|
2253
|
-
if (!effectiveRole || effectiveRole === "none" || effectiveRole === "presentation" || !NAME_PROHIBITED_ROLES.has(effectiveRole)) return
|
|
2360
|
+
if (!effectiveRole || effectiveRole === "none" || effectiveRole === "presentation" || !NAME_PROHIBITED_ROLES.has(effectiveRole)) return VALID_RESULT;
|
|
2254
2361
|
const results = [];
|
|
2255
2362
|
for (const key of NAME_PROHIBITED_ATTRIBUTES) {
|
|
2256
2363
|
if (!(key in props)) continue;
|
|
@@ -2266,9 +2373,9 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2266
2373
|
return results;
|
|
2267
2374
|
}
|
|
2268
2375
|
static #checkNameRequiredRoles({ tag, props, effectiveRole }) {
|
|
2269
|
-
if (!effectiveRole || !NAME_REQUIRED_ROLES.has(effectiveRole)) return
|
|
2270
|
-
if ("aria-label" in props || "aria-labelledby" in props) return
|
|
2271
|
-
if (tag === "img" &&
|
|
2376
|
+
if (!effectiveRole || !NAME_REQUIRED_ROLES.has(effectiveRole)) return VALID_RESULT;
|
|
2377
|
+
if ("aria-label" in props || "aria-labelledby" in props) return VALID_RESULT;
|
|
2378
|
+
if (tag === "img" && isString(props.alt) && props.alt.length > 0) return VALID_RESULT;
|
|
2272
2379
|
return [{
|
|
2273
2380
|
valid: false,
|
|
2274
2381
|
fixable: false,
|
|
@@ -2281,12 +2388,12 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2281
2388
|
diagnosticFor: (attribute, role) => AriaDiagnostics.requiredProperty(attribute, role)
|
|
2282
2389
|
};
|
|
2283
2390
|
static #checkRequiredAriaProperties(context) {
|
|
2284
|
-
if (!isNonNull(context.props.role)) return
|
|
2391
|
+
if (!isNonNull(context.props.role)) return VALID_RESULT;
|
|
2285
2392
|
return checkRequiredAttributes(AriaPolicyEngine.#requiredAriaPropertiesRule, context);
|
|
2286
2393
|
}
|
|
2287
2394
|
static #checkAriaHiddenOnFocusable({ tag, props }) {
|
|
2288
|
-
if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return
|
|
2289
|
-
if (!isPotentiallyFocusable(tag, props)) return
|
|
2395
|
+
if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return VALID_RESULT;
|
|
2396
|
+
if (!isPotentiallyFocusable(tag, props)) return VALID_RESULT;
|
|
2290
2397
|
return [{
|
|
2291
2398
|
valid: false,
|
|
2292
2399
|
fixable: false,
|
|
@@ -2296,7 +2403,7 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2296
2403
|
}];
|
|
2297
2404
|
}
|
|
2298
2405
|
static #checkPresentationalAriaAttributes({ tag, props, effectiveRole }) {
|
|
2299
|
-
if (effectiveRole !== "none" && effectiveRole !== "presentation") return
|
|
2406
|
+
if (effectiveRole !== "none" && effectiveRole !== "presentation") return VALID_RESULT;
|
|
2300
2407
|
const results = [];
|
|
2301
2408
|
iterate.forEachEntry(props, (key) => {
|
|
2302
2409
|
if (!key.startsWith("aria-")) return;
|
|
@@ -2313,10 +2420,10 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2313
2420
|
return results;
|
|
2314
2421
|
}
|
|
2315
2422
|
static #checkMissingLiveRegion({ effectiveRole, props }) {
|
|
2316
|
-
if (!effectiveRole) return
|
|
2423
|
+
if (!effectiveRole) return VALID_RESULT;
|
|
2317
2424
|
const impliedLive = LIVE_REGION_ROLES.get(effectiveRole);
|
|
2318
|
-
if (!impliedLive) return
|
|
2319
|
-
if ("aria-live" in props) return
|
|
2425
|
+
if (!impliedLive) return VALID_RESULT;
|
|
2426
|
+
if ("aria-live" in props) return VALID_RESULT;
|
|
2320
2427
|
return [{
|
|
2321
2428
|
valid: false,
|
|
2322
2429
|
fixable: true,
|
|
@@ -2356,8 +2463,8 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2356
2463
|
};
|
|
2357
2464
|
static #checkInvalidAriaRelevant({ props }) {
|
|
2358
2465
|
const relevant = props["aria-relevant"];
|
|
2359
|
-
if (relevant
|
|
2360
|
-
if (
|
|
2466
|
+
if (isUndefined(relevant)) return VALID_RESULT;
|
|
2467
|
+
if (!isString(relevant)) return VALID_RESULT;
|
|
2361
2468
|
const tokens = relevant.trim().split(/\s+/);
|
|
2362
2469
|
const invalid = tokens.filter((t) => !VALID_RELEVANT_TOKENS.has(t));
|
|
2363
2470
|
if (invalid.length > 0) return [{
|
|
@@ -2376,7 +2483,7 @@ var AriaPolicyEngine = class AriaPolicyEngine extends InvariantBase {
|
|
|
2376
2483
|
diagnostic: AriaDiagnostics.relevantSuperseded(),
|
|
2377
2484
|
fix: AriaPolicyEngine.#normalizeRelevantAllFix
|
|
2378
2485
|
}];
|
|
2379
|
-
return
|
|
2486
|
+
return VALID_RESULT;
|
|
2380
2487
|
}
|
|
2381
2488
|
};
|
|
2382
2489
|
//#endregion
|
|
@@ -4680,6 +4787,23 @@ function applyMergePolicy(key, slotVal, childVal) {
|
|
|
4680
4787
|
return policyHandlers[classifyProp(key, slotVal, childVal)](slotVal, childVal);
|
|
4681
4788
|
}
|
|
4682
4789
|
//#endregion
|
|
4790
|
+
//#region ../../adapters/react/src/shared/to-react-factory-options.ts
|
|
4791
|
+
/** React-specific additions on top of `FactoryOptions`. */
|
|
4792
|
+
const REACT_FIELD_VALIDATORS = {
|
|
4793
|
+
slotComponent: (v) => v === void 0 || isFunction(v) || isObject(v),
|
|
4794
|
+
filterProps: (v) => v === void 0 || isFunction(v),
|
|
4795
|
+
artifact: (v) => v === void 0 || isObject(v)
|
|
4796
|
+
};
|
|
4797
|
+
/**
|
|
4798
|
+
* Type guard narrowing a concrete contract `C` down to `C & ReactFactoryOptions` — the type
|
|
4799
|
+
* `buildRuntime` is declared against. Single-generic, matching `createContractComponent`'s own
|
|
4800
|
+
* `C extends ReactFactoryOptions` (Phase 2 of the `defineContract` refactor — was 6 independent
|
|
4801
|
+
* generics). See `isFactoryOptionsLike` for what this does and doesn't validate.
|
|
4802
|
+
*/
|
|
4803
|
+
function isReactFactoryOptions(options) {
|
|
4804
|
+
return isFactoryOptionsLike(options, REACT_FIELD_VALIDATORS);
|
|
4805
|
+
}
|
|
4806
|
+
//#endregion
|
|
4683
4807
|
//#region ../../adapters/react/src/shared/merge-refs.ts
|
|
4684
4808
|
function mergeRefs(...refs) {
|
|
4685
4809
|
return mergeRefsCore(...refs);
|
|
@@ -5062,4 +5186,4 @@ function buildRuntime(options, defaultSlotComponent, normalizeChildren) {
|
|
|
5062
5186
|
};
|
|
5063
5187
|
}
|
|
5064
5188
|
//#endregion
|
|
5065
|
-
export {
|
|
5189
|
+
export { getElementRef as a, Slottable as c, isReactFactoryOptions as d, finalizeComponent as f, invariant as g, isString as h, makeCloneSlotChild as i, applyDisplayName as l, isFunction as m, render as n, getPropsRef as o, SLOT_NAME as p, applySlot as r, hasWarningGetter as s, buildRuntime as t, mergeRefs as u };
|