praxis-kit 7.3.0 → 7.4.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,11 +1,48 @@
1
1
  import { RequireAtLeastOne, Simplify, ReadonlyDeep } from 'type-fest';
2
2
  import { Diagnostics, DiagnosticInput, DiagnosticsMode } from '../_shared/diagnostics.js';
3
3
 
4
+ /**
5
+ * A string-keyed object whose values are of type `T`.
6
+ */
4
7
  type StringMap<T = unknown> = Record<string, T>;
8
+ /**
9
+ * A string-keyed object with values of unknown type.
10
+ */
5
11
  type AnyRecord = StringMap<unknown>;
12
+ /**
13
+ * An object type with no named properties.
14
+ *
15
+ * Unlike `{}`, this excludes arbitrary properties during type operations while
16
+ * still satisfying `extends object`.
17
+ */
6
18
  type EmptyRecord = Record<never, never>;
7
- /** A compound component's named sub-components, e.g. `{ Header, Content, Footer }`. */
19
+ /**
20
+ * A compound component's named sub-components, for example
21
+ * `{ Header, Content, Footer }`.
22
+ */
8
23
  type SubComponentMap = Readonly<AnyRecord>;
24
+ /**
25
+ * Default `Variants` type for components that declare no variants.
26
+ *
27
+ * Structurally identical to `Readonly<EmptyRecord>`, but named separately so
28
+ * editor hovers remain self-descriptive.
29
+ */
30
+ type NoVariants = Readonly<EmptyRecord>;
31
+ /**
32
+ * Default `TPreset` type for components that declare no named presets.
33
+ *
34
+ * Structurally identical to `Readonly<EmptyRecord>`, but named separately so
35
+ * editor hovers remain self-descriptive.
36
+ */
37
+ type NoPreset = Readonly<EmptyRecord>;
38
+ /**
39
+ * Fallback for `ExtractPluginProps<TPlugin>` when a plugin contributes no
40
+ * props, including the no-plugin case.
41
+ *
42
+ * Structurally identical to `EmptyRecord`, but named separately so editor
43
+ * hovers remain self-descriptive.
44
+ */
45
+ type NoPluginProps = EmptyRecord;
9
46
 
10
47
  type IntrinsicTag = keyof HTMLElementTagNameMap;
11
48
 
@@ -171,7 +208,7 @@ type ClassPluginFactory<TProps extends AnyRecord = EmptyRecord> = <V extends Var
171
208
  * wherever a factory's concrete plugin-props shape isn't tracked (factory generics,
172
209
  * capability wiring). */
173
210
  type AnyClassPluginFactory = ClassPluginFactory<AnyRecord> | undefined;
174
- type ExtractPluginProps<TPlugin extends AnyClassPluginFactory> = TPlugin extends ClassPluginFactory<infer T> ? string extends keyof T ? EmptyRecord : T : EmptyRecord;
211
+ type ExtractPluginProps<TPlugin extends AnyClassPluginFactory> = TPlugin extends ClassPluginFactory<infer T> ? string extends keyof T ? NoPluginProps : T : NoPluginProps;
175
212
 
176
213
  type AriaContext = {
177
214
  readonly tag: IntrinsicTag;
@@ -235,6 +272,12 @@ type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
235
272
  * `@praxis-kit/diagnostics`.
236
273
  */
237
274
  readonly diagnostics?: Diagnostics | DiagnosticsMode;
275
+ /**
276
+ * ARIA/accessibility rules evaluated against the resolved tag and props on every render.
277
+ * Each rule is a function receiving the current context and returning zero or more
278
+ * violations, some of which can carry an auto-applicable fix (see `createRemoveAttributeRule`
279
+ * and friends in `praxis-kit/contract`).
280
+ */
238
281
  readonly aria?: readonly AriaRule[];
239
282
  /**
240
283
  * Rules that need `AriaPolicyEngine`'s fix-application/caching machinery
@@ -246,6 +289,11 @@ type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
246
289
  * misleading `aria` name to get the machinery it needs.
247
290
  */
248
291
  readonly rules?: readonly AriaRule[];
292
+ /**
293
+ * Declares which children are valid, by name, match predicate, and cardinality (e.g. "at
294
+ * least 1, at most 4 `Button` children"). Open by default — children matching no rule are
295
+ * still allowed unless `exclusiveChildren` is set.
296
+ */
249
297
  readonly children?: readonly ChildRuleInput[];
250
298
  /**
251
299
  * When true, only children matching a `children` rule (or text, per `allowText`)
@@ -258,19 +306,49 @@ type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
258
306
  * or any listed rule. Default: true.
259
307
  */
260
308
  readonly allowText?: boolean;
309
+ /**
310
+ * Prop transforms composed with the component's own `normalize` (from `FactoryOptions`) and
311
+ * run before it. Unlike `normalize`, these live in the enforcement bucket because they
312
+ * typically encode a built-in HTML/ARIA fact rather than component-specific behavior.
313
+ */
261
314
  readonly props?: readonly PropNormalizer[];
262
315
  /** Restricts the `as` prop to this set of tags. Violations route through diagnostics. */
263
316
  readonly allowedAs?: readonly TAllowed[];
264
317
  };
265
318
 
266
319
  type StylingOptions<V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = {
320
+ /** Class applied to every instance regardless of variant selection. */
267
321
  readonly base?: ClassName;
322
+ /**
323
+ * Named variant groups (e.g. `intent`, `size`), each mapping its possible values to a
324
+ * class string. A consumer selects a value per group as a prop (`<Button intent="primary">`).
325
+ */
268
326
  readonly variants?: V;
327
+ /** Value used for a variant group when the consumer doesn't pass one explicitly. */
269
328
  readonly defaults?: Partial<DefaultVariants<V>>;
329
+ /**
330
+ * Applies an extra class only when a specific *combination* of variant selections matches —
331
+ * for cases `variants` alone can't express (e.g. `intent: 'primary'` + `size: 'lg'` together
332
+ * need a class neither variant would add on its own).
333
+ */
270
334
  readonly compounds?: readonly CompoundVariant<V>[];
335
+ /**
336
+ * Named bundles of variant values, selectable as a single unit via the `recipe` prop (e.g.
337
+ * `<Button recipe="cta">` instead of setting `intent`/`size` individually).
338
+ */
271
339
  readonly presets?: TPreset;
340
+ /** Maps a resolved tag directly to a raw class string, independent of the variant system. */
272
341
  readonly tags?: Readonly<TagMap>;
342
+ /**
343
+ * A `ClassPluginFactory` (e.g. the Tailwind layout pipeline) that extends class resolution
344
+ * with its own owned props, layered on top of `variants`/`presets`/`tags`.
345
+ */
273
346
  readonly plugin?: TPlugin;
347
+ /**
348
+ * A cache-key → resolved-class-string lookup for every statically-known variant
349
+ * combination, skipping runtime class computation entirely when a match is found. Normally
350
+ * generated by a build-time class-extraction plugin rather than hand-authored.
351
+ */
274
352
  readonly precomputedClasses?: Readonly<Record<string, string>>;
275
353
  };
276
354
 
@@ -279,11 +357,21 @@ type NormalizeFn<Props extends AnyRecord = AnyRecord> = {
279
357
  }['normalize'];
280
358
  type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, RecipeMap<VariantMap>, AnyClassPluginFactory>;
281
359
  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> = {
360
+ /** The intrinsic tag the component renders by default. Overridable per instance via `as`. */
282
361
  readonly tag?: TDefault;
362
+ /** Display name used in diagnostics, dev tools, and generated component naming. */
283
363
  readonly name?: string;
364
+ /** Values used for the component's own (non-variant) props when the consumer omits them. */
284
365
  readonly defaults?: Partial<NoInfer<Props>>;
366
+ /**
367
+ * A pure `(props) => props` transform run on every render, after `enforcement.props`'s
368
+ * normalizers see the same input. Use this for component-specific prop shaping — anything
369
+ * that depends on live instance state or the real DOM element belongs in `onElement` instead.
370
+ */
285
371
  readonly normalize?: NormalizeFn<NoInfer<Props>>;
372
+ /** Variant groups, base classes, presets, and the optional class-resolution plugin. */
286
373
  readonly styling?: StylingOptions<V, TPreset, TPlugin>;
374
+ /** ARIA rules, child-content contracts, and other runtime validation for this component. */
287
375
  readonly enforcement?: EnforcementOptions<TAllowed>;
288
376
  /**
289
377
  * Adapter-resolved diagnostics default, spread in by `resolveAdapterCommonOptions`. Not meant to
@@ -316,6 +404,18 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
316
404
  readonly onElement?: (element: Element, getProps: () => Readonly<Props>) => void | (() => void);
317
405
  };
318
406
 
407
+ /**
408
+ * Determines whether a prop should be stripped before forwarding to the
409
+ * rendered element.
410
+ *
411
+ * Returning `true` excludes the prop from the output; returning `false`
412
+ * keeps it. This is the inverse polarity of `shouldForwardProp`-style
413
+ * predicates (Emotion/styled-components), where `true` means include.
414
+ *
415
+ * @param key - The prop name being evaluated.
416
+ * @param variantKeys - The set of configured variant prop names.
417
+ * @returns `true` to strip the prop; `false` to forward it.
418
+ */
319
419
  type FilterPredicate = (key: string, variantKeys: ReadonlySet<string>) => boolean;
320
420
 
321
421
  declare function defineContractComponent<O extends FactoryOptions>(options: O): <R>(factory: (options: O) => R) => R;
@@ -326,7 +426,7 @@ declare function defineContractComponent<O extends FactoryOptions>(options: O):
326
426
  * Identical shape to LitFactoryOptions — a plain HTMLElement subclass with
327
427
  * no framework dependency. Light DOM only; Shadow DOM is out of scope.
328
428
  */
329
- type WebFactoryOptions<TDefault extends ElementType = ElementType, TProps extends AnyRecord = EmptyRecord, TVariants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<TVariants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = FactoryOptions<TDefault, TProps, TVariants, TPreset, TPlugin> & {
429
+ type WebFactoryOptions<TDefault extends ElementType = ElementType, TProps extends AnyRecord = EmptyRecord, TVariants extends Readonly<VariantMap> = NoVariants, TPreset extends RecipeMap<TVariants> = NoPreset, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = FactoryOptions<TDefault, TProps, TVariants, TPreset, TPlugin> & {
330
430
  readonly filterProps?: FilterPredicate;
331
431
  };
332
432
 
@@ -337,7 +437,7 @@ type UnknownProps = AnyRecord;
337
437
  * Describes the public contract without exposing HTMLElement's internal members.
338
438
  * Variant key instance properties are typed via TVariants.
339
439
  */
340
- type WebContractComponent<TVariants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPluginProps extends AnyRecord = EmptyRecord> = {
440
+ type WebContractComponent<TVariants extends Readonly<VariantMap> = NoVariants, TPluginProps extends AnyRecord = EmptyRecord> = {
341
441
  new (): HTMLElement & {
342
442
  as: string | undefined;
343
443
  recipe: string | undefined;
@@ -378,7 +478,7 @@ type WebContractComponent<TVariants extends Readonly<VariantMap> = Readonly<Empt
378
478
  * For non-reactive attributes (`aria-*`, `role`, `data-*`) call `element.update()`
379
479
  * after setting them to trigger an explicit pipeline re-run.
380
480
  */
381
- declare function createContractComponent<TDefault extends ElementType, TProps extends UnknownProps = EmptyRecord, TVariants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<TVariants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: WebFactoryOptions<TDefault, TProps, TVariants, TPreset, TPlugin> & {
481
+ declare function createContractComponent<TDefault extends ElementType, TProps extends UnknownProps = EmptyRecord, TVariants extends Readonly<VariantMap> = NoVariants, TPreset extends RecipeMap<TVariants> = NoPreset, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: WebFactoryOptions<TDefault, TProps, TVariants, TPreset, TPlugin> & {
382
482
  readonly subComponents?: TSubComponents;
383
483
  }): WebContractComponent<TVariants, ExtractPluginProps<TPlugin>> & TSubComponents;
384
484
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "praxis-kit",
3
- "version": "7.3.0",
3
+ "version": "7.4.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./react": {
@@ -205,9 +205,9 @@
205
205
  "vue": "^3.5.40",
206
206
  "@praxis-kit/adapter-utils": "0.0.0",
207
207
  "@praxis-kit/core": "0.0.0",
208
- "@praxis-kit/diagnostics": "0.0.0",
209
- "@praxis-kit/pipeline": "0.0.0",
210
208
  "@praxis-kit/primitive": "0.0.0",
209
+ "@praxis-kit/pipeline": "0.0.0",
210
+ "@praxis-kit/diagnostics": "0.0.0",
211
211
  "@praxis-kit/vite-plugin": "0.0.0"
212
212
  },
213
213
  "publishConfig": {