praxis-kit 4.0.1 → 4.1.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.
@@ -1,8 +1,10 @@
1
- import { ComponentType, PropsWithChildren, ReactElement, JSX, Ref, ReactNode } from 'react';
2
- import { Except, RequireAtLeastOne, Simplify, ReadonlyDeep, NonEmptyTuple } from 'type-fest';
1
+ import { Ref, PropsWithChildren, ReactElement, ComponentType, JSX, ReactNode } from 'react';
2
+ import { RequireAtLeastOne, Simplify, ReadonlyDeep, NonEmptyTuple } from 'type-fest';
3
+ import { Diagnostics, DiagnosticInput } from './_shared/diagnostics.js';
3
4
 
4
5
  type StringMap<T = unknown> = Record<string, T>;
5
6
  type AnyRecord = StringMap<unknown>;
7
+ type EmptyRecord = Record<never, never>;
6
8
 
7
9
  type IntrinsicTag = keyof HTMLElementTagNameMap;
8
10
 
@@ -13,7 +15,6 @@ type KnownAriaRole = (typeof KNOWN_ARIA_ROLES)[number];
13
15
 
14
16
  type Booleanish = boolean | 'true' | 'false';
15
17
  type ClassName = string | string[];
16
- type EmptyRecord = Record<never, never>;
17
18
  type NonEmptyArray<T> = [T, ...T[]];
18
19
  type Numberish = number | `${number}`;
19
20
  type Primitive = string | number | boolean;
@@ -23,159 +24,6 @@ type IntrinsicProps = AnyRecord & {
23
24
  };
24
25
  type TagMap = Partial<Record<IntrinsicTag | (string & {}), ClassName>>;
25
26
 
26
- declare enum DiagnosticCategory {
27
- Contract = 0,
28
- HTML = 1,
29
- ARIA = 2,
30
- Composition = 3,
31
- Rendering = 4,
32
- Accessibility = 5,
33
- Performance = 6,
34
- Internal = 7,
35
- Deprecation = 8,
36
- Lint = 9
37
- }
38
-
39
- declare enum DiagnosticCode {
40
- MissingRequiredChild = "COMP1001",
41
- InvalidParent = "COMP1002",
42
- InvalidChild = "COMP1003",
43
- UnexpectedChild = "COMP1004",
44
- AmbiguousChild = "COMP1005",
45
- CardinalityMin = "COMP1006",
46
- CardinalityMax = "COMP1007",
47
- PositionViolation = "COMP1008",
48
- AllowedAsViolation = "COMP1009",
49
- SlotExclusive = "SLOT1001",
50
- SlotSingleChild = "SLOT1002",
51
- SlotDiscardedChildren = "SLOT1003",
52
- SlotRenderFn = "SLOT1004",
53
- MissingAriaRelationship = "ARIA2001",
54
- AriaViolation = "ARIA2002",
55
- AriaAttributeInvalid = "ARIA2003",
56
- AriaMissingLiveRegion = "ARIA2004",
57
- AriaMissingAtomic = "ARIA2005",
58
- AriaRelevantInvalidToken = "ARIA2006",
59
- AriaRelevantSuperseded = "ARIA2007",
60
- AriaInvalidRole = "ARIA2008",
61
- AriaMissingAccessibleName = "ARIA2009",
62
- AriaAttributeOnPresentational = "ARIA2010",
63
- AriaHiddenOnFocusable = "ARIA2011",
64
- AriaRequiredProperty = "ARIA2012",
65
- AriaInvalidAttributeValue = "ARIA2013",
66
- AriaRedundantLevelAttribute = "ARIA2014",
67
- InvalidHeadingHierarchy = "HTML3001",
68
- HtmlEmptyRole = "HTML3002",
69
- HtmlImplicitRoleRedundant = "HTML3003",
70
- HtmlImplicitRoleOverride = "HTML3004",
71
- HtmlStandaloneRegionOverride = "HTML3005",
72
- HtmlLandmarkRoleOverride = "HTML3006",
73
- HtmlInvalidChild = "HTML3007",
74
- InvalidRenderingTarget = "RENDER4001",
75
- LintDeadCompoundKey = "LINT5001",
76
- LintDeadCompoundValue = "LINT5002",
77
- LintDeadCompoundNonLiteral = "LINT5003",
78
- LintMissingStrict = "LINT5004",
79
- LintInvalidDefaultKey = "LINT5005",
80
- LintInvalidDefaultValue = "LINT5006",
81
- LintInvalidDefaultNonLiteral = "LINT5007",
82
- LintNegativeMin = "LINT5008",
83
- LintNegativeMax = "LINT5009",
84
- LintMaxLessThanMin = "LINT5010",
85
- LintZeroMax = "LINT5011",
86
- LintMultipleFirst = "LINT5012",
87
- LintMultipleLast = "LINT5013",
88
- LintMinSumExceedsCapacity = "LINT5014",
89
- LintCardinalityViolation = "LINT5015",
90
- LintAriaTagOverride = "LINT5016",
91
- ContractUnknownVariantDim = "COMP1010",
92
- ContractUnknownVariantValue = "COMP1011",
93
- ContractUnknownRecipeKey = "COMP1012",
94
- ContractInvalidVariantValue = "COMP1013",
95
- TailwindMultipleDisplayProps = "CSS6001",
96
- TailwindReservedLayoutLiteral = "CSS6002",
97
- TailwindDeadVariantClass = "CSS6003",
98
- PluginInvalidShape = "PLUGIN7001",
99
- PluginPipelineReturnType = "PLUGIN7002",
100
- InternalError = "INTERNAL9000"
101
- }
102
-
103
- type MetadataMap = AnyRecord;
104
- type NodeId = string;
105
-
106
- interface Diagnostic$1 {
107
- code: string;
108
- message: string;
109
- severity: 'error' | 'warning' | 'info';
110
- }
111
-
112
- type CapabilityMap = StringMap<boolean>;
113
-
114
- interface SourcePosition {
115
- line: number;
116
- col: number;
117
- }
118
- interface SourceLocation {
119
- file: string;
120
- start: SourcePosition;
121
- end?: SourcePosition;
122
- }
123
-
124
- declare enum Severity$1 {
125
- Debug = 0,
126
- Info = 1,
127
- Warning = 2,
128
- Error = 3,
129
- Fatal = 4
130
- }
131
-
132
- interface DiagnosticSuggestion {
133
- title: string;
134
- description?: string;
135
- fix?: string;
136
- }
137
-
138
- type Context = AnyRecord;
139
- type Metadata = AnyRecord;
140
- interface Diagnostic {
141
- code: DiagnosticCode;
142
- severity: Severity$1;
143
- category: DiagnosticCategory;
144
- message: string;
145
- rationale?: string;
146
- component?: string;
147
- contract?: string;
148
- location?: SourceLocation;
149
- suggestions?: DiagnosticSuggestion[];
150
- context?: Context;
151
- metadata?: Metadata;
152
- }
153
-
154
- declare enum Enforcement {
155
- Ignore = 0,
156
- Report = 1,
157
- Throw = 2
158
- }
159
- interface DiagnosticPolicy {
160
- resolve(diagnostic: Diagnostic): Enforcement;
161
- }
162
-
163
- interface DiagnosticReporter {
164
- report(diagnostic: Diagnostic): void;
165
- }
166
-
167
- type DiagnosticInput = Except<Diagnostic, 'severity'>;
168
- declare class Diagnostics {
169
- private readonly reporter;
170
- private readonly policy;
171
- readonly active: boolean;
172
- constructor(reporter: DiagnosticReporter, policy?: DiagnosticPolicy);
173
- report(diagnostic: Diagnostic): Diagnostic;
174
- warn(input: DiagnosticInput): Diagnostic;
175
- error(input: DiagnosticInput): Diagnostic;
176
- info(input: DiagnosticInput): Diagnostic;
177
- }
178
-
179
27
  type MinMax = {
180
28
  min: number;
181
29
  max: number;
@@ -203,34 +51,16 @@ type ValidResult = {
203
51
  valid: true;
204
52
  };
205
53
 
206
- type RequireAtLeastOneIfNotEmpty<T> = keyof T extends never ? EmptyRecord : RequireAtLeastOne<T>;
207
- type CompoundVariantConditionValue<V extends VariantMap, K extends keyof V> = VariantKey<V, K> | NonEmptyArray<VariantKey<V, K>>;
208
- type CompoundVariantConditions<V extends VariantMap> = Simplify<{
209
- [K in keyof V]: CompoundVariantConditionValue<V, K>;
210
- }>;
211
- type CompoundVariantRequiredConditions<V extends VariantMap> = RequireAtLeastOneIfNotEmpty<CompoundVariantConditions<V>>;
212
- type CompoundVariantBase<V extends VariantMap> = keyof V extends never ? EmptyRecord : CompoundVariantRequiredConditions<V>;
213
- type CompoundVariant<V extends VariantMap> = CompoundVariantBase<V> & {
214
- class: VariantValue;
215
- };
216
-
217
- interface CVACompounds<V extends VariantMap> {
218
- compoundVariants?: readonly CompoundVariant<V>[];
219
- }
220
-
221
- interface CVADefaults<V extends VariantMap> {
222
- defaultVariants?: DefaultVariants<V>;
223
- }
224
-
225
- interface CVAVariants<V extends VariantMap> {
226
- variants?: V;
227
- }
228
-
229
54
  type StringToBoolean<T> = T extends 'true' | 'false' ? boolean : T;
55
+
230
56
  type VariantValue = string | string[];
57
+
231
58
  type VariantStates<K extends string = string> = Record<K, VariantValue>;
59
+
232
60
  type VariantMap<V extends string = string, K extends string = string> = Record<V, VariantStates<K>>;
61
+
233
62
  type VariantKey<V extends VariantMap, K extends keyof V> = StringToBoolean<keyof V[K] & string>;
63
+
234
64
  /**
235
65
  * A partial selection of variant states authored at factory definition time.
236
66
  *
@@ -240,14 +70,17 @@ type VariantKey<V extends VariantMap, K extends keyof V> = StringToBoolean<keyof
240
70
  type VariantSelection<V extends VariantMap> = {
241
71
  [K in keyof V]?: keyof V[K];
242
72
  };
73
+
243
74
  /** The full optional prop surface exposed to callers for a given variant map. */
244
75
  type VariantProps<V extends VariantMap> = {
245
76
  [K in keyof V]?: VariantKey<V, K>;
246
77
  };
78
+
247
79
  type NormalizedVariantValue<K extends string> = string extends K ? Primitive : K extends 'true' | 'false' ? Booleanish : K extends `${number}` ? Numberish : K;
248
80
  type DefaultVariants<V extends VariantMap> = {
249
81
  [K in keyof V]?: NormalizedVariantValue<keyof V[K] & string>;
250
82
  };
83
+
251
84
  /**
252
85
  * A static, immutable map of named presets to partial variant selections.
253
86
  *
@@ -255,7 +88,9 @@ type DefaultVariants<V extends VariantMap> = {
255
88
  * avoiding the need to repeat variant combinations at each call site.
256
89
  */
257
90
  type RecipeMap<V extends VariantMap = VariantMap> = Readonly<Record<string, VariantSelection<V>>>;
91
+
258
92
  type RecipeTarget<TVariants extends VariantMap = VariantMap> = VariantSelection<TVariants>;
93
+
259
94
  interface PolymorphicGenerics<TDefault extends ElementType = ElementType, Props extends AnyRecord = AnyRecord, Variants extends Readonly<VariantMap> = Readonly<VariantMap>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TAllowed extends ElementType = ElementType> {
260
95
  default: TDefault;
261
96
  props: Props;
@@ -269,6 +104,29 @@ type AllowedOf<T extends PolymorphicGenerics> = T['allowed'];
269
104
  type DefaultOf<T extends PolymorphicGenerics> = T['default'];
270
105
  type PropsOf<T extends PolymorphicGenerics> = T['props'];
271
106
 
107
+ type RequireAtLeastOneIfNotEmpty<T> = keyof T extends never ? EmptyRecord : RequireAtLeastOne<T>;
108
+ type CompoundVariantConditionValue<V extends VariantMap, K extends keyof V> = VariantKey<V, K> | NonEmptyArray<VariantKey<V, K>>;
109
+ type CompoundVariantConditions<V extends VariantMap> = Simplify<{
110
+ [K in keyof V]: CompoundVariantConditionValue<V, K>;
111
+ }>;
112
+ type CompoundVariantRequiredConditions<V extends VariantMap> = RequireAtLeastOneIfNotEmpty<CompoundVariantConditions<V>>;
113
+ type CompoundVariantBase<V extends VariantMap> = keyof V extends never ? EmptyRecord : CompoundVariantRequiredConditions<V>;
114
+ type CompoundVariant<V extends VariantMap> = CompoundVariantBase<V> & {
115
+ class: VariantValue;
116
+ };
117
+
118
+ interface CVACompounds<V extends VariantMap> {
119
+ compoundVariants?: readonly CompoundVariant<V>[];
120
+ }
121
+
122
+ interface CVADefaults<V extends VariantMap> {
123
+ defaultVariants?: DefaultVariants<V>;
124
+ }
125
+
126
+ interface CVAVariants<V extends VariantMap> {
127
+ variants?: V;
128
+ }
129
+
272
130
  interface BaseClassOptions {
273
131
  baseClassName?: ClassName;
274
132
  }
@@ -300,7 +158,11 @@ type ClassPlugin<TProps extends AnyRecord = EmptyRecord> = Readonly<{
300
158
  }>;
301
159
 
302
160
  type ClassPluginFactory<TProps extends AnyRecord = EmptyRecord> = <V extends VariantMap>(options: ClassPipelineOptions<V>, diagnostics: Diagnostics) => ClassPlugin<TProps>;
303
- type ExtractPluginProps<TPlugin extends ClassPluginFactory<AnyRecord> | undefined> = TPlugin extends ClassPluginFactory<infer T> ? string extends keyof T ? EmptyRecord : T : EmptyRecord;
161
+ /** `ClassPluginFactory` with its plugin-owned-props generic erased the common form used
162
+ * wherever a factory's concrete plugin-props shape isn't tracked (factory generics,
163
+ * capability wiring). */
164
+ type AnyClassPluginFactory = ClassPluginFactory<AnyRecord> | undefined;
165
+ type ExtractPluginProps<TPlugin extends AnyClassPluginFactory> = TPlugin extends ClassPluginFactory<infer T> ? string extends keyof T ? EmptyRecord : T : EmptyRecord;
304
166
 
305
167
  type AriaContext = {
306
168
  readonly tag: IntrinsicTag;
@@ -360,7 +222,7 @@ type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
360
222
  readonly allowedAs?: readonly TAllowed[];
361
223
  };
362
224
 
363
- type StylingOptions<V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>, TPlugin extends ClassPluginFactory<AnyRecord> | undefined = ClassPluginFactory<AnyRecord> | undefined> = {
225
+ type StylingOptions<V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = {
364
226
  readonly base?: ClassName;
365
227
  readonly variants?: V;
366
228
  readonly defaults?: Partial<DefaultVariants<V>>;
@@ -374,8 +236,8 @@ type StylingOptions<V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPre
374
236
  type NormalizeFn<Props extends AnyRecord = AnyRecord> = {
375
237
  normalize(props: Readonly<Props & IntrinsicProps>): Props & IntrinsicProps;
376
238
  }['normalize'];
377
- type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, RecipeMap<VariantMap>, ClassPluginFactory<AnyRecord> | undefined>;
378
- type FactoryOptions<TDefault extends ElementType = ElementType, Props extends AnyRecord = EmptyRecord, V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>, TPlugin extends ClassPluginFactory<AnyRecord> | undefined = ClassPluginFactory<AnyRecord> | undefined, TAllowed extends ElementType = ElementType> = {
239
+ type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, RecipeMap<VariantMap>, AnyClassPluginFactory>;
240
+ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends AnyRecord = EmptyRecord, V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TAllowed extends ElementType = ElementType> = {
379
241
  readonly tag?: TDefault;
380
242
  readonly name?: string;
381
243
  readonly defaults?: Partial<NoInfer<Props>>;
@@ -384,6 +246,17 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
384
246
  readonly enforcement?: EnforcementOptions<TAllowed>;
385
247
  };
386
248
 
249
+ type MetadataMap = AnyRecord;
250
+ type NodeId = string;
251
+
252
+ interface Diagnostic {
253
+ code: string;
254
+ message: string;
255
+ severity: 'error' | 'warning' | 'info';
256
+ }
257
+
258
+ type CapabilityMap = StringMap<boolean>;
259
+
387
260
  declare function defineContractComponent<O extends FactoryOptions>(options: O): <R>(factory: (options: O) => R) => R;
388
261
 
389
262
  interface ComponentIdentity {
@@ -396,10 +269,15 @@ interface ComponentDefinition {
396
269
  identity: ComponentIdentity;
397
270
  capabilities: CapabilityMap;
398
271
  metadata: MetadataMap;
399
- diagnostics: Diagnostic$1[];
272
+ diagnostics: Diagnostic[];
400
273
  }
401
274
 
402
- type UnknownProps = Record<string, unknown>;
275
+ declare function mergeRefs<T>(...refs: (Ref<T> | null | undefined)[]): Ref<T> | null;
276
+
277
+ type SlottableProps = PropsWithChildren;
278
+ declare function Slottable({ children }: SlottableProps): ReactElement;
279
+
280
+ type UnknownProps = AnyRecord;
403
281
  type SlotComponent = ComponentType<UnknownProps>;
404
282
 
405
283
  /**
@@ -408,80 +286,96 @@ type SlotComponent = ComponentType<UnknownProps>;
408
286
  *
409
287
  * Typed loosely to accommodate any element tag the user chooses.
410
288
  */
411
- type RenderCallbackProps = Readonly<Record<string, unknown>>;
412
-
413
- type SlottableProps = PropsWithChildren;
414
- declare function Slottable({ children }: SlottableProps): ReactElement;
289
+ type RenderCallbackProps = Readonly<AnyRecord>;
415
290
 
416
- /** Structural subset of `CompiledComponentArtifact` consumed by the React adapter. */
417
- interface CompiledArtifact {
418
- readonly definition: ComponentDefinition;
419
- readonly precomputed?: {
420
- readonly variantLookup?: Record<string, string>;
421
- };
422
- }
423
291
  /**
424
- * Extends FactoryOptions with React-specific configuration.
425
- * slotComponent is intentionally not in core — it is a React rendering concern.
292
+ * Maps a polymorphic element type to the instance type exposed through `ref`.
293
+ *
294
+ * Intrinsic HTML elements resolve to their corresponding DOM element type;
295
+ * custom React components currently fall back to `unknown`.
426
296
  */
427
- type ReactFactoryOptions<TDefault extends ElementType, Props extends UnknownProps, Variants extends Readonly<VariantMap>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TPlugin extends ClassPluginFactory<AnyRecord> | undefined = ClassPluginFactory<AnyRecord> | undefined, TAllowed extends ElementType = ElementType> = FactoryOptions<TDefault, Props, Variants, TPreset, TPlugin, TAllowed> & {
428
- /** Component used to render the asChild slot. Defaults to the built-in Slot. */
429
- slotComponent?: SlotComponent;
430
- /**
431
- * Return true for any prop key that should be consumed but not forwarded to the DOM.
432
- * The adapter strips nothing by default — implementations decide what is safe to drop.
433
- * Receives `runtime.options.variantKeys` as a convenience if needed.
434
- */
435
- filterProps?: (key: string, variantKeys: ReadonlySet<string>) => boolean;
436
- /** Pre-compiled artifact from `@praxis-kit/runtime`'s compiler. When provided, replaces the stub
437
- * definition and enables the precomputed variant lookup fast path. */
438
- artifact?: CompiledArtifact;
439
- };
440
-
441
- /** Maps a core ElementType to its DOM instance type for ref inference. */
442
297
  type ElementRef<T extends ElementType> = T extends IntrinsicTag ? HTMLElementTagNameMap[T] : unknown;
443
- /** @internal React JSX intrinsic props for a given element type. */
298
+ /**
299
+ * React's intrinsic JSX props for a given element.
300
+ *
301
+ * Custom components intentionally fall back to `UnknownProps`; the component's
302
+ * own prop model defines their accepted props instead.
303
+ */
444
304
  type IntrinsicJSXProps<T extends ElementType> = T extends IntrinsicTag ? JSX.IntrinsicElements[T] : UnknownProps;
445
305
  /**
446
- * @internal
447
- * Removes index signatures (e.g. `[key: string]: T`) from a type, keeping only
448
- * explicitly named properties. Used to prevent fallback-to-constraint generics
449
- * like `Record<string, unknown>` or `Readonly<VariantMap>` from producing a
450
- * `[key: string]: T` member that makes `keyof` resolve to `string` which
451
- * would cause `Omit<IntrinsicJSXProps<TAs>, string>` to remove all HTML props.
306
+ * Removes index signatures while preserving explicitly named properties.
307
+ *
308
+ * This prevents generic fallback constraints such as `Record<string, unknown>`
309
+ * from collapsing `keyof T` to `string`, which would cause
310
+ * `Omit<IntrinsicJSXProps<T>, keyof ...>` to remove every intrinsic prop.
452
311
  */
453
312
  type StripIndexSignature<T> = {
454
313
  [K in keyof T as string extends K ? never : K]: T[K];
455
314
  };
315
+ /** Props explicitly declared by the component. */
456
316
  type ComponentProps<G extends PolymorphicGenerics> = StripIndexSignature<PropsOf<G>>;
317
+ /** Variant props generated from the component's variant definitions. */
457
318
  type ComponentVariants<G extends PolymorphicGenerics> = StripIndexSignature<VariantProps<VariantsOf<G>>>;
319
+ /**
320
+ * Props owned by the component itself.
321
+ *
322
+ * These take precedence over intrinsic HTML props when names overlap.
323
+ */
458
324
  type OwnedProps<G extends PolymorphicGenerics> = ComponentProps<G> & ComponentVariants<G>;
459
325
  /**
460
- * @internal
461
- * Polymorphic machinery props. Separated from `OwnedProps` so the two concerns
462
- * are distinct: user-defined props vs. the tag/ref/class system.
326
+ * Polymorphic rendering controls.
327
+ *
328
+ * These describe *how* the component renders rather than the data it owns.
463
329
  *
464
- * `asChild` and `children` are excluded typed separately in the discriminated
465
- * union below so each render mode can enforce different child constraints.
330
+ * `children` and `asChild` are intentionally omitted so each render mode
331
+ * can provide its own stricter contract.
466
332
  */
467
333
  type PolymorphicControlProps<G extends PolymorphicGenerics, TAs extends ElementType> = {
334
+ /**
335
+ * Restrict `as` to `allowedAs` when configured.
336
+ *
337
+ * Without `allowedAs`, `AllowedOf<G>` resolves to `ElementType`,
338
+ * so the intersection becomes `TAs`.
339
+ */
468
340
  as?: TAs & AllowedOf<G>;
341
+ /**
342
+ * Explicit `undefined` keeps wrapper components compatible with
343
+ * `exactOptionalPropertyTypes`.
344
+ */
469
345
  className?: ClassName | undefined;
470
346
  recipe?: keyof RecipeOf<G>;
347
+ /** Ref type follows the resolved element. */
471
348
  ref?: Ref<ElementRef<TAs>>;
472
349
  };
473
- /** @internal Full set of props owned by the component — used as the Omit key in IntrinsicPropsWithoutOwned. */
350
+ /**
351
+ * Complete set of props owned by the component.
352
+ *
353
+ * Used primarily as the exclusion list when inheriting intrinsic JSX props.
354
+ */
474
355
  type ControlProps<G extends PolymorphicGenerics, TAs extends ElementType> = OwnedProps<G> & PolymorphicControlProps<G, TAs>;
356
+ /**
357
+ * Intrinsic JSX props after removing every prop owned by the component.
358
+ *
359
+ * Component props always win over intrinsic props with the same name.
360
+ */
475
361
  type IntrinsicPropsWithoutOwned<G extends PolymorphicGenerics, TAs extends ElementType> = Omit<IntrinsicJSXProps<TAs>, keyof ControlProps<G, TAs> | 'children'>;
476
- type SharedProps<G extends PolymorphicGenerics, TAs extends ElementType> = IntrinsicPropsWithoutOwned<G, TAs> & ControlProps<G, TAs>;
477
- /** Discriminant for the normal render path: `asChild` absent or false, any children. */
362
+ /**
363
+ * Base props shared by every render mode.
364
+ *
365
+ * Render modes contribute only their discriminants (`asChild`, `render`,
366
+ * `children`, etc.).
367
+ */
368
+ type BaseProps<G extends PolymorphicGenerics, TAs extends ElementType> = IntrinsicPropsWithoutOwned<G, TAs> & ControlProps<G, TAs>;
369
+ /** Standard rendering (`asChild` absent or false). */
478
370
  type NormalRenderMode = {
479
371
  asChild?: false;
480
372
  children?: ReactNode | undefined;
481
373
  };
482
374
  /**
483
- * Discriminant for the slot render path. One or more `ReactElement` children required.
484
- * `as` is forbidden — combining `as` with `asChild` is a runtime invariant violation.
375
+ * Slot rendering.
376
+ *
377
+ * Requires one or more React elements and forbids `as`, since the child
378
+ * determines the rendered element.
485
379
  */
486
380
  type SlotRenderMode = {
487
381
  asChild: true;
@@ -489,17 +383,12 @@ type SlotRenderMode = {
489
383
  children: ReactElement | NonEmptyTuple<ReactElement>;
490
384
  };
491
385
  /**
492
- * Discriminant for the render-prop path. The callback receives all resolved props
493
- * (className, ref, filtered component props) and returns the target element.
386
+ * Render callback.
494
387
  *
495
- * This is the output form for the compile-time `asChild` transform: keeps the same
496
- * rendering flexibility as `asChild` without the `cloneElement` cost at runtime.
497
- * Unlike `asChild`, the render callback does not auto-merge conflicting event
498
- * handlers — spread position determines precedence.
388
+ * The callback receives fully resolved props (classes, refs, filtered props)
389
+ * and is responsible for rendering the target element.
499
390
  *
500
- * ```tsx
501
- * <Button render={(p) => <a href="/home" {...p} />} size="lg" />
502
- * ```
391
+ * This provides the flexibility of `asChild` without `cloneElement`.
503
392
  */
504
393
  type CallbackRenderMode = {
505
394
  render: (props: RenderCallbackProps) => ReactElement;
@@ -507,26 +396,29 @@ type CallbackRenderMode = {
507
396
  children?: never;
508
397
  };
509
398
  /**
510
- * Props for the normal render path. HTML attributes are inferred from `TAs`.
399
+ * Standard polymorphic props.
511
400
  *
512
- * `Omit + intersection` (not `Merge`) is used so TypeScript can infer `TAs` from
513
- * the `as` prop value; control props win on key conflicts.
401
+ * HTML attributes are inferred from `as`.
514
402
  */
515
- type PolymorphicProps<G extends PolymorphicGenerics, TAs extends ElementType = DefaultOf<G>> = Simplify<SharedProps<G, TAs> & NormalRenderMode>;
403
+ type PolymorphicProps<G extends PolymorphicGenerics, TAs extends ElementType = DefaultOf<G>> = Simplify<BaseProps<G, TAs> & NormalRenderMode>;
516
404
  /**
517
- * Props for the slot render path (`asChild: true`). One or more `ReactElement`
518
- * children are required. Multiple children are permitted for the Slottable
519
- * sibling pattern where one child is a `<Slottable>` wrapper.
405
+ * Slot rendering props.
406
+ *
407
+ * Requires one or more ReactElement children.
520
408
  */
521
- type PolymorphicWithAsChild<G extends PolymorphicGenerics, TAs extends ElementType = DefaultOf<G>> = Simplify<SharedProps<G, TAs> & SlotRenderMode>;
522
- type PolymorphicWithRender<G extends PolymorphicGenerics, TAs extends ElementType = DefaultOf<G>> = Simplify<SharedProps<G, TAs> & CallbackRenderMode>;
409
+ type PolymorphicWithAsChild<G extends PolymorphicGenerics, TAs extends ElementType = DefaultOf<G>> = Simplify<BaseProps<G, TAs> & SlotRenderMode>;
523
410
  /**
524
- * A polymorphic component that infers HTML attributes and ref type from the `as` prop.
411
+ * Render callback props.
412
+ */
413
+ type PolymorphicWithRender<G extends PolymorphicGenerics, TAs extends ElementType = DefaultOf<G>> = Simplify<BaseProps<G, TAs> & CallbackRenderMode>;
414
+ /**
415
+ * A polymorphic React component.
416
+ *
417
+ * Overloads form a discriminated union:
525
418
  *
526
- * Three call signatures form a discriminated union:
527
- * - `render` present render-prop path; no Slot or cloneElement at runtime
528
- * - `asChild: true` slot path; exactly one `ReactElement` child required
529
- * - `asChild?: false` → normal path; any `ReactNode` children accepted
419
+ * `render` → render callback
420
+ * `asChild` → Slot rendering
421
+ * otherwise normal rendering
530
422
  */
531
423
  type PolymorphicComponent<G extends PolymorphicGenerics> = {
532
424
  <TAs extends ElementType = DefaultOf<G>>(props: PolymorphicWithRender<G, TAs>): ReactElement;
@@ -535,6 +427,29 @@ type PolymorphicComponent<G extends PolymorphicGenerics> = {
535
427
  displayName?: string;
536
428
  };
537
429
 
538
- declare function mergeRefs<T>(...refs: (Ref<T> | null | undefined)[]): Ref<T> | null;
430
+ /** Structural subset of `CompiledComponentArtifact` consumed by the React adapter. */
431
+ interface CompiledArtifact {
432
+ readonly definition: ComponentDefinition;
433
+ readonly precomputed?: {
434
+ readonly variantLookup?: Record<string, string>;
435
+ };
436
+ }
437
+ /**
438
+ * Extends FactoryOptions with React-specific configuration.
439
+ * slotComponent is intentionally not in core — it is a React rendering concern.
440
+ */
441
+ type ReactFactoryOptions<TDefault extends ElementType, Props extends UnknownProps, Variants extends Readonly<VariantMap>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TAllowed extends ElementType = ElementType> = FactoryOptions<TDefault, Props, Variants, TPreset, TPlugin, TAllowed> & {
442
+ /** Component used to render the asChild slot. Defaults to the built-in Slot. */
443
+ slotComponent?: SlotComponent;
444
+ /**
445
+ * Return true for any prop key that should be consumed but not forwarded to the DOM.
446
+ * The adapter strips nothing by default — implementations decide what is safe to drop.
447
+ * Receives `runtime.options.variantKeys` as a convenience if needed.
448
+ */
449
+ filterProps?: (key: string, variantKeys: ReadonlySet<string>) => boolean;
450
+ /** Pre-compiled artifact from `@praxis-kit/runtime`'s compiler. When provided, replaces the stub
451
+ * definition and enables the precomputed variant lookup fast path. */
452
+ artifact?: CompiledArtifact;
453
+ };
539
454
 
540
- export { type AnyRecord as A, type ClassPluginFactory as C, type ElementType as E, type FactoryOptions as F, type PolymorphicComponent as P, type RecipeMap as R, Slottable as S, type UnknownProps as U, type VariantMap as V, type EmptyRecord as a, type ReactFactoryOptions as b, type PolymorphicGenerics as c, type ExtractPluginProps as d, type AnyFactoryOptions as e, type ElementRef as f, type PolymorphicProps as g, type PolymorphicWithAsChild as h, type PolymorphicWithRender as i, type RenderCallbackProps as j, type SlottableProps as k, defineContractComponent as l, mergeRefs as m };
455
+ export { type AnyClassPluginFactory as A, type ElementType as E, type FactoryOptions as F, type PolymorphicComponent as P, type RecipeMap as R, Slottable as S, type UnknownProps as U, type VariantMap as V, type EmptyRecord as a, type ReactFactoryOptions as b, type PolymorphicGenerics as c, type ExtractPluginProps as d, type AnyFactoryOptions as e, type ElementRef as f, type PolymorphicProps as g, type PolymorphicWithAsChild as h, type PolymorphicWithRender as i, type RenderCallbackProps as j, type SlottableProps as k, defineContractComponent as l, mergeRefs as m };