praxis-kit 6.6.1 → 7.3.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.
package/dist/web/index.js CHANGED
@@ -1,8 +1,22 @@
1
+ // ../../lib/adapter-utils/src/invariant.ts
2
+ function panic(message) {
3
+ throw new Error(message);
4
+ }
5
+ function invariant(condition, message) {
6
+ if (!condition) panic(message);
7
+ }
8
+
1
9
  // ../../lib/adapter-utils/src/runtime/define-component.ts
2
10
  function defineContractComponent(options) {
3
11
  return (factory) => factory(options);
4
12
  }
5
13
 
14
+ // ../../lib/adapter-utils/src/runtime/assemble-compound-component.ts
15
+ function assembleCompoundComponent(root, subComponents) {
16
+ if (!subComponents) return root;
17
+ return Object.assign(root, subComponents);
18
+ }
19
+
6
20
  // ../../lib/primitive/src/tag/resolve-tag.ts
7
21
  function makeResolveTag(defaultTag) {
8
22
  return function tag(as) {
@@ -13,6 +27,11 @@ function makeResolveTag(defaultTag) {
13
27
  // ../../lib/primitive/src/rule/rule-brand.ts
14
28
  var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
15
29
 
30
+ // ../../lib/primitive/src/rule/dynamic.ts
31
+ function dynamic(resolve) {
32
+ return { [RULE_BRAND]: true, resolve };
33
+ }
34
+
16
35
  // ../../lib/primitive/src/guards/foundational/is-defined.ts
17
36
  function isUndefined(value) {
18
37
  return value === void 0;
@@ -26,7 +45,7 @@ function isNonNull(value) {
26
45
  return value != null;
27
46
  }
28
47
  function isNullish(value) {
29
- return isNull(value) || value === void 0;
48
+ return isNull(value) || isUndefined(value);
30
49
  }
31
50
 
32
51
  // ../../lib/primitive/src/utils/type-guards.ts
@@ -40,10 +59,13 @@ function isString(value) {
40
59
  function isNumber(value) {
41
60
  return typeof value === "number";
42
61
  }
62
+ function isFunction(value) {
63
+ return typeof value === "function";
64
+ }
43
65
 
44
66
  // ../../lib/primitive/src/rule/is-dynamic-rule.ts
45
67
  function isDynamicRule(rule) {
46
- return isObject(rule, true) && rule[RULE_BRAND] === true;
68
+ return isObject(rule, true) && Reflect.get(rule, RULE_BRAND) === true;
47
69
  }
48
70
 
49
71
  // ../../lib/primitive/src/rule/resolve-rule.ts
@@ -517,6 +539,24 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
517
539
  ]
518
540
  ]);
519
541
 
542
+ // ../../lib/primitive/src/constants/html/void-tags.ts
543
+ var VOID_TAGS = [
544
+ "area",
545
+ "base",
546
+ "br",
547
+ "col",
548
+ "embed",
549
+ "hr",
550
+ "img",
551
+ "input",
552
+ "link",
553
+ "meta",
554
+ "param",
555
+ "source",
556
+ "track",
557
+ "wbr"
558
+ ];
559
+
520
560
  // ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
521
561
  function isGlobalAriaAttribute(attr) {
522
562
  return GLOBAL_ARIA_ATTRIBUTES.has(attr);
@@ -564,17 +604,17 @@ var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default
564
604
  // ../../lib/primitive/src/guards/children/is-tag.ts
565
605
  function getAsProp(child) {
566
606
  if (!isObject(child) || !("props" in child)) return void 0;
567
- const props = child.props;
607
+ const { props } = child;
568
608
  if (!isObject(props)) return void 0;
569
- const as = props.as;
609
+ const as = Reflect.get(props, "as");
570
610
  return isString(as) && as !== "" ? as : void 0;
571
611
  }
572
612
  function getTag(child) {
573
613
  if (!isObject(child) || !("type" in child)) return void 0;
574
- const t = child.type;
614
+ const { type: t } = child;
575
615
  if (isString(t)) return t;
576
616
  if (typeof t === "function" || isObject(t)) {
577
- const defaultTag = t[COMPONENT_DEFAULT_TAG];
617
+ const defaultTag = Reflect.get(t, COMPONENT_DEFAULT_TAG);
578
618
  if (!isString(defaultTag)) return void 0;
579
619
  return getAsProp(child) ?? defaultTag;
580
620
  }
@@ -594,6 +634,28 @@ function isTag(...args) {
594
634
  return tag !== void 0 && set2.has(tag);
595
635
  }
596
636
 
637
+ // ../../lib/adapter-utils/src/runtime/is-factory-options-like.ts
638
+ var FACTORY_OPTIONS_FIELD_VALIDATORS = {
639
+ tag: (v) => v === void 0 || isString(v),
640
+ name: (v) => v === void 0 || isString(v),
641
+ defaults: (v) => v === void 0 || isObject(v),
642
+ normalize: (v) => v === void 0 || isFunction(v),
643
+ styling: (v) => v === void 0 || isObject(v),
644
+ enforcement: (v) => v === void 0 || isObject(v),
645
+ diagnostics: (v) => v === void 0 || isObject(v),
646
+ subComponents: (v) => v === void 0 || isObject(v),
647
+ onElement: (v) => v === void 0 || isFunction(v)
648
+ };
649
+ function isFactoryOptionsLike(options, extraFieldValidators) {
650
+ if (!isObject(options)) return false;
651
+ const validators = { ...FACTORY_OPTIONS_FIELD_VALIDATORS, ...extraFieldValidators };
652
+ for (const [key, value] of Object.entries(options)) {
653
+ const validate = validators[key];
654
+ if (!validate || !validate(value)) return false;
655
+ }
656
+ return true;
657
+ }
658
+
597
659
  // ../../lib/contract/src/aria/aria-role-policy.ts
598
660
  function getImplicitRole(tag, props) {
599
661
  if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
@@ -1446,7 +1508,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1446
1508
  const cached = _AriaPolicyEngine.#removeAttributeFixCache.get(attr);
1447
1509
  if (cached) return cached;
1448
1510
  const fix = {
1449
- kind: `removeAttribute:${attr}`,
1511
+ kind: "removeAttribute",
1512
+ attribute: attr,
1450
1513
  apply: ({ props }) => {
1451
1514
  if (!(attr in props)) return { applied: false, next: props };
1452
1515
  return { applied: true, next: omitProp(props, attr), previous: props };
@@ -1717,7 +1780,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1717
1780
  if (!impliedLive) return NO_VIOLATIONS2;
1718
1781
  if ("aria-live" in props) return NO_VIOLATIONS2;
1719
1782
  const injectLive = {
1720
- kind: `injectLive:${effectiveRole}`,
1783
+ kind: "injectLive",
1784
+ attribute: "aria-live",
1721
1785
  apply: (ctx) => ({
1722
1786
  applied: true,
1723
1787
  next: { ...ctx.props, "aria-live": impliedLive },
@@ -1786,6 +1850,23 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1786
1850
  }
1787
1851
  };
1788
1852
 
1853
+ // ../../lib/contract/src/aria/factories.ts
1854
+ function removeProp(props, key) {
1855
+ const next = { ...props };
1856
+ delete next[key];
1857
+ return next;
1858
+ }
1859
+ function removeAttributeFix(attribute) {
1860
+ return Object.freeze({
1861
+ kind: "removeAttribute",
1862
+ attribute,
1863
+ apply: ({ props }) => {
1864
+ if (!(attribute in props)) return { applied: false, next: props };
1865
+ return { applied: true, next: removeProp(props, attribute), previous: props };
1866
+ }
1867
+ });
1868
+ }
1869
+
1789
1870
  // ../../lib/contract/src/children/get-type-name.ts
1790
1871
  function getTypeName(value) {
1791
1872
  if (value === null) return "null";
@@ -2104,22 +2185,6 @@ import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2104
2185
 
2105
2186
  // ../core/src/html/contracts/categories.ts
2106
2187
  var METADATA_TAGS = ["script", "template"];
2107
- var VOID_TAGS = [
2108
- "area",
2109
- "base",
2110
- "br",
2111
- "col",
2112
- "embed",
2113
- "hr",
2114
- "img",
2115
- "input",
2116
- "link",
2117
- "meta",
2118
- "param",
2119
- "source",
2120
- "track",
2121
- "wbr"
2122
- ];
2123
2188
  var TEXT_ONLY_TAGS = [
2124
2189
  "option",
2125
2190
  "script",
@@ -2243,20 +2308,6 @@ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2243
2308
 
2244
2309
  // ../core/src/html/spec/validators/attribute-type-validator.ts
2245
2310
  var DEFAULT_INPUT_TYPE = "text";
2246
- function omit(props, key) {
2247
- const next = { ...props };
2248
- delete next[key];
2249
- return next;
2250
- }
2251
- function removeAttributeFix(attribute) {
2252
- return {
2253
- kind: `removeAttribute:${attribute}`,
2254
- apply: ({ props }) => {
2255
- if (!(attribute in props)) return { applied: false, next: props };
2256
- return { applied: true, next: omit(props, attribute), previous: props };
2257
- }
2258
- };
2259
- }
2260
2311
  function createInputAttributeTypeRule({
2261
2312
  attribute,
2262
2313
  allowedTypes
@@ -2709,7 +2760,7 @@ function getChildProp(child, key) {
2709
2760
  if (!isVNodeLike(child)) return void 0;
2710
2761
  const { props } = child;
2711
2762
  if (!isObject(props)) return void 0;
2712
- return props[key];
2763
+ return Reflect.get(props, key);
2713
2764
  }
2714
2765
 
2715
2766
  // ../core/src/html/contracts/aria/landmarks.ts
@@ -2762,6 +2813,13 @@ function isLabelableControl(child) {
2762
2813
  const type = getChildProp(child, "type");
2763
2814
  return !isString(type) || type !== "hidden";
2764
2815
  }
2816
+ function hasAccessibleNameProp(props) {
2817
+ return "aria-label" in props || "aria-labelledby" in props;
2818
+ }
2819
+ function isNonEmptyTextChild(child) {
2820
+ if (isNumber(child)) return true;
2821
+ return isString(child) && child.trim().length > 0;
2822
+ }
2765
2823
  var labelContract = contract([
2766
2824
  { name: "control", match: isLabelableControl, cardinality: { max: 1 } },
2767
2825
  { name: "nested-label", match: isTag("label"), cardinality: { max: 0 } },
@@ -2769,6 +2827,13 @@ var labelContract = contract([
2769
2827
  name: "other-interactive-content",
2770
2828
  match: isTag(...OTHER_INTERACTIVE_TAGS),
2771
2829
  cardinality: { max: 0 }
2830
+ },
2831
+ {
2832
+ name: "accessible-name",
2833
+ match: isNonEmptyTextChild,
2834
+ cardinality: dynamic(
2835
+ (ctx) => hasAccessibleNameProp(ctx.props) ? { min: 0 } : { min: 1 }
2836
+ )
2772
2837
  }
2773
2838
  ]);
2774
2839
 
@@ -3500,6 +3565,14 @@ function buildRuntime(options) {
3500
3565
  };
3501
3566
  }
3502
3567
 
3568
+ // ../../adapters/web/src/is-web-contract-component.ts
3569
+ function isWebContractComponent(value) {
3570
+ if (!isFunction(value)) return false;
3571
+ if (typeof HTMLElement !== "undefined" && !(value.prototype instanceof HTMLElement)) return false;
3572
+ if (!("diagnostics" in value)) return false;
3573
+ return isObject(value.diagnostics);
3574
+ }
3575
+
3503
3576
  // ../../adapters/web/src/render-to-string.ts
3504
3577
  var ssrRegistry = /* @__PURE__ */ new WeakMap();
3505
3578
  function registerForSsr(cls, bundle) {
@@ -3516,8 +3589,17 @@ function renderToString(component, props = {}, innerHTML = "") {
3516
3589
  return renderBundleToString(entry.bundle, props, innerHTML);
3517
3590
  }
3518
3591
 
3592
+ // ../../adapters/web/src/to-web-factory-options.ts
3593
+ var WEB_FIELD_VALIDATORS = {
3594
+ filterProps: (v) => v === void 0 || isFunction(v)
3595
+ };
3596
+ function isWebFactoryOptions(options) {
3597
+ return isFactoryOptionsLike(options, WEB_FIELD_VALIDATORS);
3598
+ }
3599
+
3519
3600
  // ../../adapters/web/src/create-contract-component.ts
3520
3601
  function createContractComponent(options) {
3602
+ invariant(isWebFactoryOptions(options), "options is not a valid WebFactoryOptions object");
3521
3603
  const bundle = buildRuntime(options);
3522
3604
  const looseBundle = toLooseBundle(bundle);
3523
3605
  const variantKeys = options.styling?.variants ? Object.keys(options.styling.variants) : [];
@@ -3531,8 +3613,20 @@ function createContractComponent(options) {
3531
3613
  static get observedAttributes() {
3532
3614
  return observedAttrNames;
3533
3615
  }
3616
+ // Tag registered by the consumer's own customElements.define() call is never literally
3617
+ // `dialog` (custom-element names must be hyphenated), so native `<dialog>`-specific methods
3618
+ // like showModal() won't exist on this class unless the consumer opts into "customized
3619
+ // built-ins" (`{ extends: 'dialog' }`) themselves — not something this adapter special-cases.
3620
+ _onElementCleanup;
3534
3621
  connectedCallback() {
3535
3622
  this._applyPraxis();
3623
+ if (options.onElement) {
3624
+ this._onElementCleanup = options.onElement(this, () => this._buildProps()) ?? void 0;
3625
+ }
3626
+ }
3627
+ disconnectedCallback() {
3628
+ this._onElementCleanup?.();
3629
+ this._onElementCleanup = void 0;
3536
3630
  }
3537
3631
  // Fires synchronously for every observed attribute change — no microtask
3538
3632
  // scheduling needed. The guard is implicit: this only fires for
@@ -3549,12 +3643,11 @@ function createContractComponent(options) {
3549
3643
  get _self() {
3550
3644
  return this;
3551
3645
  }
3552
- _applyPraxis() {
3646
+ // Shared by _applyPraxis and the onElement getProps accessor — both need the same
3647
+ // attribute-derived prop snapshot, just for different purposes (pipeline input vs.
3648
+ // exposing "current props" to author-supplied element wiring).
3649
+ _buildProps() {
3553
3650
  const self = this._self;
3554
- const {
3555
- childrenEvaluator,
3556
- runtime: { options: options2 }
3557
- } = bundle;
3558
3651
  const observedSet = new Set(
3559
3652
  this.constructor.observedAttributes ?? []
3560
3653
  );
@@ -3570,6 +3663,14 @@ function createContractComponent(options) {
3570
3663
  const val = self[key] ?? this.getAttribute(key);
3571
3664
  if (val != null) props[key] = val;
3572
3665
  }
3666
+ return props;
3667
+ }
3668
+ _applyPraxis() {
3669
+ const {
3670
+ childrenEvaluator,
3671
+ runtime: { options: options2 }
3672
+ } = bundle;
3673
+ const props = this._buildProps();
3573
3674
  const hostState = resolveHostState(looseBundle, props);
3574
3675
  const children = Array.from(this.childNodes);
3575
3676
  if (childrenEvaluator) {
@@ -3578,7 +3679,7 @@ function createContractComponent(options) {
3578
3679
  props: hostState.normalizedProps
3579
3680
  });
3580
3681
  }
3581
- options2.htmlChildrenEvaluatorFn?.(hostState.tag)?.evaluate(children);
3682
+ options2.htmlChildrenEvaluatorFn?.(hostState.tag)?.evaluate(children, { tag: hostState.tag, props: hostState.normalizedProps });
3582
3683
  diffAndApplyAttributes(this, hostState, this._pipelineAttrs, props);
3583
3684
  }
3584
3685
  }
@@ -3586,8 +3687,14 @@ function createContractComponent(options) {
3586
3687
  Object.defineProperty(PolymorphicWebElement, "name", { value: options.name });
3587
3688
  }
3588
3689
  Object.defineProperty(PolymorphicWebElement, "diagnostics", { value: bundle.diagnostics });
3589
- registerForSsr(PolymorphicWebElement, looseBundle);
3590
- return PolymorphicWebElement;
3690
+ const contractClass = PolymorphicWebElement;
3691
+ invariant(
3692
+ isWebContractComponent(contractClass),
3693
+ "Generated class failed to satisfy the WebContractComponent shape"
3694
+ );
3695
+ registerForSsr(contractClass, looseBundle);
3696
+ const assembled = assembleCompoundComponent(contractClass, options.subComponents);
3697
+ return assembled;
3591
3698
  }
3592
3699
  export {
3593
3700
  createContractComponent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "praxis-kit",
3
- "version": "6.6.1",
3
+ "version": "7.3.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./react": {
@@ -187,26 +187,26 @@
187
187
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
188
188
  "esbuild": "^0.28.1",
189
189
  "esbuild-plugin-solid": "^0.6.0",
190
- "@types/node": "^26.1.1",
190
+ "@types/node": "^26.1.2",
191
191
  "@types/react": "^19.2.17",
192
192
  "@types/react-dom": "^19.0.0",
193
- "@typescript-eslint/utils": "8.63.0",
193
+ "@typescript-eslint/utils": "8.65.0",
194
194
  "lit": "^3.0.0",
195
195
  "preact": "^10.25.0",
196
- "react": "^19.2.7",
197
- "react-dom": "^19.2.7",
196
+ "react": "^19.2.8",
197
+ "react-dom": "^19.2.8",
198
198
  "solid-js": "^1.9.0",
199
199
  "svelte": "^5.56.3",
200
200
  "ts-morph": "^28.0.0",
201
201
  "tsup": "^8.5.1",
202
- "tsx": "^4.22.5",
202
+ "tsx": "^4.23.1",
203
203
  "typescript": "^6.0.3",
204
204
  "vite": "^8.1.5",
205
- "vue": "^3.5.38",
205
+ "vue": "^3.5.40",
206
206
  "@praxis-kit/adapter-utils": "0.0.0",
207
+ "@praxis-kit/core": "0.0.0",
207
208
  "@praxis-kit/diagnostics": "0.0.0",
208
209
  "@praxis-kit/pipeline": "0.0.0",
209
- "@praxis-kit/core": "0.0.0",
210
210
  "@praxis-kit/primitive": "0.0.0",
211
211
  "@praxis-kit/vite-plugin": "0.0.0"
212
212
  },