praxis-kit 0.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.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/_shared/diagnostics.d.ts +312 -0
- package/dist/_shared/diagnostics.js +360 -0
- package/dist/build-runtime-CJ_nQEaZ.js +5065 -0
- package/dist/codemod/index.d.ts +2 -0
- package/dist/codemod/index.js +176520 -0
- package/dist/contract/index.d.ts +677 -0
- package/dist/contract/index.js +341 -0
- package/dist/eslint/index.d.ts +90 -0
- package/dist/eslint/index.js +1047 -0
- package/dist/guards/index.d.ts +78 -0
- package/dist/guards/index.js +118 -0
- package/dist/html/index.d.ts +151 -0
- package/dist/html/index.js +1244 -0
- package/dist/index-BIBd_iPD.d.ts +951 -0
- package/dist/lit/index.d.ts +862 -0
- package/dist/lit/index.js +4893 -0
- package/dist/preact/index.d.ts +796 -0
- package/dist/preact/index.js +5043 -0
- package/dist/react/index.d.ts +28 -0
- package/dist/react/index.js +205 -0
- package/dist/react/legacy.d.ts +29 -0
- package/dist/react/legacy.js +80 -0
- package/dist/solid/index.d.ts +728 -0
- package/dist/solid/index.js +4821 -0
- package/dist/svelte/Polymorphic.svelte +190 -0
- package/dist/svelte/_polymorphic-runtime.d.ts +102 -0
- package/dist/svelte/_polymorphic-runtime.js +371 -0
- package/dist/svelte/index.d.ts +994 -0
- package/dist/svelte/index.js +4482 -0
- package/dist/tailwind/index.d.ts +197 -0
- package/dist/tailwind/index.js +767 -0
- package/dist/tailwind/safelist.css +20 -0
- package/dist/ts-plugin/index.cjs +166 -0
- package/dist/ts-plugin/index.d.cts +9 -0
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.js +21 -0
- package/dist/vite-plugin/index.d.ts +200 -0
- package/dist/vite-plugin/index.js +2106 -0
- package/dist/vue/index.d.ts +729 -0
- package/dist/vue/index.js +4945 -0
- package/dist/web/index.d.ts +832 -0
- package/dist/web/index.js +4868 -0
- package/package.json +258 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { C as MergeRecords, E as AnyRecord, S as EmptyRecord, T as NoVariants, _ as ExtractPluginProps, a as PolymorphicProps, b as VariantMap, c as RenderCallbackProps, d as SlottableProps, f as mergeRefs, g as AnyClassPluginFactory, h as FactoryOptions, i as PolymorphicComponent, l as UnknownProps, m as AnyFactoryOptions, n as ContractProps, o as PolymorphicWithAsChild, p as defineContractComponent, r as ElementRef, s as PolymorphicWithRender, t as ReactFactoryOptions, u as Slottable, v as PolymorphicGenerics, w as NoPreset, x as ElementType, y as RecipeMap } from "../index-BIBd_iPD.js";
|
|
2
|
+
//#region ../../adapters/react/src/current/create-contract-component.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Creates a polymorphic React 19 component with praxis-kit contracts applied.
|
|
5
|
+
*
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const Button = createContractComponent({
|
|
8
|
+
* tag: 'button',
|
|
9
|
+
* name: 'Button',
|
|
10
|
+
* styling: {
|
|
11
|
+
* base: 'btn',
|
|
12
|
+
* variants: { intent: { primary: 'btn--primary', ghost: 'btn--ghost' } },
|
|
13
|
+
* defaults: { intent: 'primary' },
|
|
14
|
+
* },
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* <Button intent="ghost" as="a" href="/home">Home</Button>
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* `ref` is accepted as a plain prop (React 19) and forwarded to the rendered host element or,
|
|
21
|
+
* with `asChild`, to the consumer's own element. Pass `subComponents` to attach named
|
|
22
|
+
* sub-components (`Card.Header`) and `onElement` to run setup once the real DOM element exists.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createContractComponent<TDefault extends ElementType, Props extends UnknownProps = EmptyRecord, Variants extends Readonly<VariantMap> = NoVariants, TPreset extends RecipeMap<Variants> = NoPreset, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TAllowed extends ElementType = ElementType, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: ReactFactoryOptions<TDefault, Props, Variants, TPreset, TPlugin, TAllowed> & {
|
|
25
|
+
readonly subComponents?: TSubComponents;
|
|
26
|
+
}): MergeRecords<PolymorphicComponent<PolymorphicGenerics<TDefault, MergeRecords<Props, ExtractPluginProps<TPlugin>>, Variants, TPreset, TAllowed>>, TSubComponents>;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { type AnyFactoryOptions, type ContractProps, type ElementRef, type ElementType, type EmptyRecord, type FactoryOptions, type PolymorphicComponent, type PolymorphicGenerics, type PolymorphicProps, type PolymorphicWithAsChild, type PolymorphicWithRender, type ReactFactoryOptions, type RenderCallbackProps, Slottable, type SlottableProps, defineContractComponent, mergeRefs };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { _ as invariant, a as getElementRef, c as Slottable, d as finalizeComponent, f as SLOT_NAME, g as defineContractComponent, h as isString, i as makeCloneSlotChild, l as applyDisplayName, m as isObject, n as render, o as getPropsRef, p as isFunction, r as applySlot, s as hasWarningGetter, t as buildRuntime$1, u as mergeRefs } from "../build-runtime-CJ_nQEaZ.js";
|
|
2
|
+
import { isValidElement, useCallback, useRef } from "react";
|
|
3
|
+
//#region ../../lib/adapter-utils/src/runtime/is-factory-options-like.ts
|
|
4
|
+
/**
|
|
5
|
+
* Loosely validates one recognized `FactoryOptions` field's runtime shape.
|
|
6
|
+
* "Loosely" because the field's declared type is itself parameterized by a
|
|
7
|
+
* generic (Props, Variants, TPlugin, ...) that's erased at runtime — these
|
|
8
|
+
* checks confirm the field is the right *kind* of value (object, function,
|
|
9
|
+
* string), not that it satisfies its exact generic instantiation, which no
|
|
10
|
+
* runtime check can ever do.
|
|
11
|
+
*
|
|
12
|
+
* Covers every field `FactoryOptions` itself declares — identical across
|
|
13
|
+
* every adapter, since they all extend the same core type. Adapter-specific
|
|
14
|
+
* additions (React's `slotComponent`/`artifact`, every adapter's own
|
|
15
|
+
* `filterProps`, etc.) are passed in by the caller as extra entries.
|
|
16
|
+
*/
|
|
17
|
+
const FACTORY_OPTIONS_FIELD_VALIDATORS = {
|
|
18
|
+
tag: (v) => v === void 0 || isString(v),
|
|
19
|
+
name: (v) => v === void 0 || isString(v),
|
|
20
|
+
defaults: (v) => v === void 0 || isObject(v),
|
|
21
|
+
normalize: (v) => v === void 0 || isFunction(v),
|
|
22
|
+
styling: (v) => v === void 0 || isObject(v),
|
|
23
|
+
enforcement: (v) => v === void 0 || isObject(v),
|
|
24
|
+
diagnostics: (v) => v === void 0 || isObject(v),
|
|
25
|
+
subComponents: (v) => v === void 0 || isObject(v),
|
|
26
|
+
onElement: (v) => v === void 0 || isFunction(v)
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Type guard narrowing the generic `FactoryOptions` shape down to an
|
|
30
|
+
* adapter-specific factory options type `T` — the type each adapter's
|
|
31
|
+
* `buildRuntime` is declared against.
|
|
32
|
+
*
|
|
33
|
+
* Walks every own enumerable property on `options` and checks it against
|
|
34
|
+
* `FACTORY_OPTIONS_FIELD_VALIDATORS` plus `extraFieldValidators` (the
|
|
35
|
+
* adapter's own additions on top of `FactoryOptions`): an unrecognized key,
|
|
36
|
+
* or a recognized key holding a value of the wrong kind, fails the guard.
|
|
37
|
+
* This is a genuine structural check, not a relabeled assertion — though it
|
|
38
|
+
* necessarily stops at each field's runtime *kind*, since the field's actual
|
|
39
|
+
* generic instantiation is erased at runtime and no guard can validate it.
|
|
40
|
+
* That part remains the caller's responsibility, same as with any other
|
|
41
|
+
* generic function in TypeScript.
|
|
42
|
+
*/
|
|
43
|
+
function isFactoryOptionsLike(options, extraFieldValidators) {
|
|
44
|
+
if (!isObject(options)) return false;
|
|
45
|
+
const validators = {
|
|
46
|
+
...FACTORY_OPTIONS_FIELD_VALIDATORS,
|
|
47
|
+
...extraFieldValidators
|
|
48
|
+
};
|
|
49
|
+
for (const [key, value] of Object.entries(options)) {
|
|
50
|
+
const validate = validators[key];
|
|
51
|
+
if (!validate || !validate(value)) return false;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region ../../adapters/react/src/shared/to-react-factory-options.ts
|
|
57
|
+
/** React-specific additions on top of `FactoryOptions`. */
|
|
58
|
+
const REACT_FIELD_VALIDATORS = {
|
|
59
|
+
slotComponent: (v) => v === void 0 || isFunction(v) || isObject(v),
|
|
60
|
+
filterProps: (v) => v === void 0 || isFunction(v),
|
|
61
|
+
artifact: (v) => v === void 0 || isObject(v)
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Type guard narrowing the generic `FactoryOptions` shape down to
|
|
65
|
+
* `ReactFactoryOptions` — the type `buildRuntime` is declared against. See
|
|
66
|
+
* `isFactoryOptionsLike` for what this does and doesn't validate.
|
|
67
|
+
*/
|
|
68
|
+
function isReactFactoryOptions(options) {
|
|
69
|
+
return isFactoryOptionsLike(options, REACT_FIELD_VALIDATORS);
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region ../../adapters/react/src/shared/is-polymorphic-component.ts
|
|
73
|
+
/**
|
|
74
|
+
* Type guard narrowing a generated component's real (framework-specific)
|
|
75
|
+
* function type down to the public `PolymorphicComponent<G>` interface
|
|
76
|
+
* every adapter factory exposes.
|
|
77
|
+
*
|
|
78
|
+
* `PolymorphicComponent<G>`'s call signatures reference `G`, which is
|
|
79
|
+
* erased at runtime, so no guard can check them — the only thing this
|
|
80
|
+
* interface asserts that's actually observable at runtime is "callable" and
|
|
81
|
+
* an optional `displayName` of the right kind. That's a complete check for
|
|
82
|
+
* everything the type declares outside its (compile-time-only) call
|
|
83
|
+
* signatures.
|
|
84
|
+
*/
|
|
85
|
+
function isPolymorphicComponent(value) {
|
|
86
|
+
if (!isFunction(value)) return false;
|
|
87
|
+
if (!("displayName" in value)) return true;
|
|
88
|
+
return value.displayName === void 0 || isString(value.displayName);
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region ../../adapters/react/src/current/slot/composeRefs.ts
|
|
92
|
+
function getChildRef(element) {
|
|
93
|
+
return hasWarningGetter(element.props, "ref") ? getElementRef(element) : getPropsRef(element);
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region ../../adapters/react/src/current/slot/cloneSlotChild.ts
|
|
97
|
+
const cloneSlotChild = makeCloneSlotChild(getChildRef);
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region ../../adapters/react/src/current/slot/Slot.tsx
|
|
100
|
+
function Slot({ ref = null, children, ...slotProps }) {
|
|
101
|
+
return applySlot(children, slotProps, ref, cloneSlotChild);
|
|
102
|
+
}
|
|
103
|
+
Slot.displayName = SLOT_NAME;
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region ../../adapters/react/src/current/normalize-children.ts
|
|
106
|
+
const isNonEmptyTextChild = (child) => typeof child === "number" || typeof child === "string" && child.trim().length > 0;
|
|
107
|
+
function normalizeChildren(children) {
|
|
108
|
+
if (isValidElement(children)) return [children];
|
|
109
|
+
if (isNonEmptyTextChild(children)) return [children];
|
|
110
|
+
if (Array.isArray(children)) return children.filter((child) => isValidElement(child) || isNonEmptyTextChild(child));
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region ../../adapters/react/src/current/build-runtime.ts
|
|
115
|
+
function buildRuntime(options) {
|
|
116
|
+
return buildRuntime$1(options, Slot, normalizeChildren);
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region ../../adapters/react/src/current/create-contract-component.ts
|
|
120
|
+
/**
|
|
121
|
+
* Creates a polymorphic React 19 component with praxis-kit contracts applied.
|
|
122
|
+
*
|
|
123
|
+
* ```tsx
|
|
124
|
+
* const Button = createContractComponent({
|
|
125
|
+
* tag: 'button',
|
|
126
|
+
* name: 'Button',
|
|
127
|
+
* styling: {
|
|
128
|
+
* base: 'btn',
|
|
129
|
+
* variants: { intent: { primary: 'btn--primary', ghost: 'btn--ghost' } },
|
|
130
|
+
* defaults: { intent: 'primary' },
|
|
131
|
+
* },
|
|
132
|
+
* })
|
|
133
|
+
*
|
|
134
|
+
* <Button intent="ghost" as="a" href="/home">Home</Button>
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* `ref` is accepted as a plain prop (React 19) and forwarded to the rendered host element or,
|
|
138
|
+
* with `asChild`, to the consumer's own element. Pass `subComponents` to attach named
|
|
139
|
+
* sub-components (`Card.Header`) and `onElement` to run setup once the real DOM element exists.
|
|
140
|
+
*/
|
|
141
|
+
function createContractComponent(options) {
|
|
142
|
+
invariant(isReactFactoryOptions(options), "options is not a valid ReactFactoryOptions object");
|
|
143
|
+
const bundle = buildRuntime(options);
|
|
144
|
+
/** Captured once from the factory options so the callback ref below can remain stable. */
|
|
145
|
+
const { onElement } = options;
|
|
146
|
+
function Component({ ref, ...props }) {
|
|
147
|
+
/**
|
|
148
|
+
* Keep current on every render so the stable callback ref can always read the latest
|
|
149
|
+
* props via getProps() without re-registering.
|
|
150
|
+
*/
|
|
151
|
+
const propsRef = useRef(props);
|
|
152
|
+
propsRef.current = props;
|
|
153
|
+
const cleanupRef = useRef(void 0);
|
|
154
|
+
/**
|
|
155
|
+
* `onElement` originates from the options object closed over by createContractComponent,
|
|
156
|
+
* not from props, so it's static for the component's lifetime — this callback intentionally
|
|
157
|
+
* stays stable across renders. React only re-invokes a stable callback ref when the
|
|
158
|
+
* underlying element instance changes (mount, replacement, or unmount), so onElement is
|
|
159
|
+
* registered once for each mounted element, regardless of how many times Component re-renders.
|
|
160
|
+
*/
|
|
161
|
+
const onElementRef = useCallback((el) => {
|
|
162
|
+
if (!onElement) return;
|
|
163
|
+
if (el) {
|
|
164
|
+
/**
|
|
165
|
+
* Defensive: React currently always calls this ref with `null` before a replacement
|
|
166
|
+
* element, but that ordering isn't part of the formal callback-ref contract — clean up
|
|
167
|
+
* any existing registration first so a hypothetical el→el invocation can't leak one.
|
|
168
|
+
* Cleared right after invoking, not left to be overwritten below, so a subsequent
|
|
169
|
+
* `onElement(...)` throw doesn't leave a stale, already-invoked cleanup in place to be
|
|
170
|
+
* run a second time on unmount.
|
|
171
|
+
*/
|
|
172
|
+
cleanupRef.current?.();
|
|
173
|
+
cleanupRef.current = void 0;
|
|
174
|
+
/**
|
|
175
|
+
* The real element's actual tag is only known at runtime (`tag` default or a consumer's
|
|
176
|
+
* `as` override); `onElement`'s parameter type narrows that per-component via `TDefault`/
|
|
177
|
+
* `TAllowed`, which the DOM ref API itself can't express — see `FactoryOptions.onElement`.
|
|
178
|
+
*/
|
|
179
|
+
cleanupRef.current = onElement(el, () => propsRef.current) ?? void 0;
|
|
180
|
+
} else {
|
|
181
|
+
cleanupRef.current?.();
|
|
182
|
+
cleanupRef.current = void 0;
|
|
183
|
+
}
|
|
184
|
+
}, []);
|
|
185
|
+
const mergedRef = onElement ? mergeRefs(ref, onElementRef) : ref;
|
|
186
|
+
return render({
|
|
187
|
+
...bundle,
|
|
188
|
+
props,
|
|
189
|
+
ref: mergedRef ?? null
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
applyDisplayName(Component, options.name);
|
|
193
|
+
const assembled = finalizeComponent(Component, bundle.runtime.options.defaultTag, options.subComponents);
|
|
194
|
+
invariant(isPolymorphicComponent(assembled), "Generated component failed to satisfy the PolymorphicComponent shape");
|
|
195
|
+
/**
|
|
196
|
+
* MergeRecords is a conditional type. While these generics are still open, TypeScript cannot
|
|
197
|
+
* prove that the assembled value satisfies the same conditional expression used by the
|
|
198
|
+
* declared return type. Once the generics are instantiated at a call site, the conditional
|
|
199
|
+
* simplifies correctly. The invariant above validates the runtime shape; this assertion
|
|
200
|
+
* bridges the gap in the compiler's type reasoning.
|
|
201
|
+
*/
|
|
202
|
+
return assembled;
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
205
|
+
export { Slottable, createContractComponent, defineContractComponent, mergeRefs };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { C as MergeRecords, E as AnyRecord, S as EmptyRecord, T as NoVariants, _ as ExtractPluginProps, a as PolymorphicProps, b as VariantMap, c as RenderCallbackProps, d as SlottableProps, f as mergeRefs, g as AnyClassPluginFactory, h as FactoryOptions, i as PolymorphicComponent, l as UnknownProps, m as AnyFactoryOptions, n as ContractProps, o as PolymorphicWithAsChild, p as defineContractComponent, r as ElementRef, s as PolymorphicWithRender, t as ReactFactoryOptions, u as Slottable, v as PolymorphicGenerics, w as NoPreset, x as ElementType, y as RecipeMap } from "../index-BIBd_iPD.js";
|
|
2
|
+
//#region ../../adapters/react/src/legacy/create-contract-component.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Creates a polymorphic React component with praxis-kit contracts applied, for React 18 and
|
|
5
|
+
* earlier (use `praxis-kit/react` instead on React 19, which accepts `ref` as a plain prop).
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* const Button = createContractComponent({
|
|
9
|
+
* tag: 'button',
|
|
10
|
+
* name: 'Button',
|
|
11
|
+
* styling: {
|
|
12
|
+
* base: 'btn',
|
|
13
|
+
* variants: { intent: { primary: 'btn--primary', ghost: 'btn--ghost' } },
|
|
14
|
+
* defaults: { intent: 'primary' },
|
|
15
|
+
* },
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* <Button intent="ghost" as="a" href="/home">Home</Button>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Returns a `forwardRef` component — `ref` is forwarded to the rendered host element the same
|
|
22
|
+
* way it works in `praxis-kit/react`. Pass `subComponents` to attach named sub-components
|
|
23
|
+
* (`Card.Header`) and `onElement` to run setup once the real DOM element exists.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createContractComponent<TDefault extends ElementType, Props extends UnknownProps = EmptyRecord, Variants extends Readonly<VariantMap> = NoVariants, TPreset extends RecipeMap<Variants> = NoPreset, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TAllowed extends ElementType = ElementType, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: ReactFactoryOptions<TDefault, Props, Variants, TPreset, TPlugin, TAllowed> & {
|
|
26
|
+
readonly subComponents?: TSubComponents;
|
|
27
|
+
}): MergeRecords<PolymorphicComponent<PolymorphicGenerics<TDefault, MergeRecords<Props, ExtractPluginProps<TPlugin>>, Variants, TPreset, TAllowed>>, TSubComponents>;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { type AnyFactoryOptions, type ContractProps, type ElementRef, type ElementType, type EmptyRecord, type FactoryOptions, type PolymorphicComponent, type PolymorphicGenerics, type PolymorphicProps, type PolymorphicWithAsChild, type PolymorphicWithRender, type ReactFactoryOptions, type RenderCallbackProps, Slottable, type SlottableProps, defineContractComponent, mergeRefs };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { a as getElementRef, c as Slottable, d as finalizeComponent, f as SLOT_NAME, g as defineContractComponent, i as makeCloneSlotChild, l as applyDisplayName, n as render, o as getPropsRef, r as applySlot, s as hasWarningGetter, t as buildRuntime$1, u as mergeRefs } from "../build-runtime-CJ_nQEaZ.js";
|
|
2
|
+
import { Children, forwardRef, isValidElement, useCallback, useRef } from "react";
|
|
3
|
+
//#region ../../adapters/react/src/legacy/slot/composeRefs.ts
|
|
4
|
+
function getChildRef(element) {
|
|
5
|
+
return hasWarningGetter(element, "ref") ? getPropsRef(element) : getElementRef(element);
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region ../../adapters/react/src/legacy/slot/cloneSlotChild.ts
|
|
9
|
+
const cloneSlotChild = makeCloneSlotChild(getChildRef);
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region ../../adapters/react/src/legacy/slot/Slot.tsx
|
|
12
|
+
const Slot = forwardRef(function Slot({ children, ...slotProps }, ref) {
|
|
13
|
+
return applySlot(children, slotProps, ref, cloneSlotChild);
|
|
14
|
+
});
|
|
15
|
+
Slot.displayName = SLOT_NAME;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region ../../adapters/react/src/legacy/normalize-children.ts
|
|
18
|
+
const isNonEmptyTextChild = (child) => typeof child === "number" || typeof child === "string" && child.trim().length > 0;
|
|
19
|
+
function normalizeChildren(children) {
|
|
20
|
+
return Children.toArray(children).filter((child) => isValidElement(child) || isNonEmptyTextChild(child));
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region ../../adapters/react/src/legacy/build-runtime.ts
|
|
24
|
+
function buildRuntime(options) {
|
|
25
|
+
return buildRuntime$1(options, Slot, normalizeChildren);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region ../../adapters/react/src/legacy/create-contract-component.ts
|
|
29
|
+
/**
|
|
30
|
+
* Creates a polymorphic React component with praxis-kit contracts applied, for React 18 and
|
|
31
|
+
* earlier (use `praxis-kit/react` instead on React 19, which accepts `ref` as a plain prop).
|
|
32
|
+
*
|
|
33
|
+
* ```tsx
|
|
34
|
+
* const Button = createContractComponent({
|
|
35
|
+
* tag: 'button',
|
|
36
|
+
* name: 'Button',
|
|
37
|
+
* styling: {
|
|
38
|
+
* base: 'btn',
|
|
39
|
+
* variants: { intent: { primary: 'btn--primary', ghost: 'btn--ghost' } },
|
|
40
|
+
* defaults: { intent: 'primary' },
|
|
41
|
+
* },
|
|
42
|
+
* })
|
|
43
|
+
*
|
|
44
|
+
* <Button intent="ghost" as="a" href="/home">Home</Button>
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* Returns a `forwardRef` component — `ref` is forwarded to the rendered host element the same
|
|
48
|
+
* way it works in `praxis-kit/react`. Pass `subComponents` to attach named sub-components
|
|
49
|
+
* (`Card.Header`) and `onElement` to run setup once the real DOM element exists.
|
|
50
|
+
*/
|
|
51
|
+
function createContractComponent(options) {
|
|
52
|
+
const bundle = buildRuntime(options);
|
|
53
|
+
const { onElement } = options;
|
|
54
|
+
const Component = forwardRef(function Component(props, ref) {
|
|
55
|
+
const propsRef = useRef(props);
|
|
56
|
+
propsRef.current = props;
|
|
57
|
+
const cleanupRef = useRef(void 0);
|
|
58
|
+
const onElementRef = useCallback((el) => {
|
|
59
|
+
if (!onElement) return;
|
|
60
|
+
if (el) {
|
|
61
|
+
cleanupRef.current?.();
|
|
62
|
+
cleanupRef.current = void 0;
|
|
63
|
+
cleanupRef.current = onElement(el, () => propsRef.current) ?? void 0;
|
|
64
|
+
} else {
|
|
65
|
+
cleanupRef.current?.();
|
|
66
|
+
cleanupRef.current = void 0;
|
|
67
|
+
}
|
|
68
|
+
}, []);
|
|
69
|
+
const mergedRef = onElement ? mergeRefs(ref, onElementRef) : ref;
|
|
70
|
+
return render({
|
|
71
|
+
...bundle,
|
|
72
|
+
props,
|
|
73
|
+
ref: mergedRef
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
applyDisplayName(Component, options.name);
|
|
77
|
+
return finalizeComponent(Component, bundle.runtime.options.defaultTag, options.subComponents);
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { Slottable, createContractComponent, defineContractComponent, mergeRefs };
|