clava 0.0.1 → 0.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/src/index.ts ADDED
@@ -0,0 +1,698 @@
1
+ import clsx, { type ClassValue as ClsxClassValue } from "clsx";
2
+
3
+ import type {
4
+ Variants,
5
+ ComputedVariants,
6
+ AnyComponent,
7
+ Component,
8
+ StyleProps,
9
+ ClassValue,
10
+ StyleValue,
11
+ StyleClassValue,
12
+ VariantValues,
13
+ Computed,
14
+ ExtendableVariants,
15
+ MergeVariants,
16
+ ModalComponent,
17
+ ComponentResult,
18
+ JSXProps,
19
+ HTMLProps,
20
+ HTMLObjProps,
21
+ OnlyVariantsComponent,
22
+ ComponentProps,
23
+ SplitProps,
24
+ OnlyVariantsSplitProps,
25
+ } from "./types.ts";
26
+
27
+ import {
28
+ htmlObjStyleToStyleValue,
29
+ htmlStyleToStyleValue,
30
+ isHTMLObjStyle,
31
+ jsxStyleToStyleValue,
32
+ styleValueToHTMLObjStyle,
33
+ styleValueToHTMLStyle,
34
+ styleValueToJSXStyle,
35
+ } from "./utils.ts";
36
+
37
+ const MODES = ["jsx", "html", "htmlObj"] as const;
38
+ type Mode = (typeof MODES)[number];
39
+
40
+ export type { ClassValue, StyleValue, StyleClassValue };
41
+
42
+ export type VariantProps<T extends Pick<AnyComponent, "getVariants">> =
43
+ ReturnType<T["getVariants"]>;
44
+
45
+ export interface CVConfig<
46
+ V extends Variants = {},
47
+ CV extends ComputedVariants = {},
48
+ E extends AnyComponent[] = [],
49
+ > {
50
+ extend?: E;
51
+ class?: ClassValue;
52
+ style?: StyleValue;
53
+ variants?: ExtendableVariants<V, E>;
54
+ computedVariants?: CV;
55
+ defaultVariants?: VariantValues<MergeVariants<V, CV, E>>;
56
+ computed?: Computed<MergeVariants<V, CV, E>>;
57
+ }
58
+
59
+ interface CreateParams<M extends Mode> {
60
+ defaultMode?: M;
61
+ transformClass?: (className: string) => string;
62
+ }
63
+
64
+ /**
65
+ * Checks if a value is a style-class object (has style properties, not just a
66
+ * class value).
67
+ */
68
+ function isStyleClassValue(value: unknown): value is StyleClassValue {
69
+ if (typeof value !== "object") return false;
70
+ if (value == null) return false;
71
+ if (Array.isArray(value)) return false;
72
+ return true;
73
+ }
74
+
75
+ /**
76
+ * Converts any style input (string, JSX object, or HTML object) to a
77
+ * normalized StyleValue.
78
+ */
79
+ function normalizeStyle(style: unknown): StyleValue {
80
+ if (typeof style === "string") {
81
+ return htmlStyleToStyleValue(style);
82
+ }
83
+ if (typeof style === "object" && style != null) {
84
+ if (isHTMLObjStyle(style as Record<string, unknown>)) {
85
+ return htmlObjStyleToStyleValue(style as Record<string, string | number>);
86
+ }
87
+ return jsxStyleToStyleValue(style as Record<string, string | number>);
88
+ }
89
+ return {};
90
+ }
91
+
92
+ /**
93
+ * Extracts class and style from a style-class value object.
94
+ */
95
+ function extractStyleClass(value: StyleClassValue): {
96
+ class: ClassValue;
97
+ style: StyleValue;
98
+ } {
99
+ const { class: cls, ...style } = value;
100
+ return { class: cls, style };
101
+ }
102
+
103
+ /**
104
+ * Processes a variant value to extract class and style.
105
+ */
106
+ function processVariantValue(value: unknown): {
107
+ class: ClassValue;
108
+ style: StyleValue;
109
+ } {
110
+ if (isStyleClassValue(value)) {
111
+ return extractStyleClass(value);
112
+ }
113
+ return { class: value as ClassValue, style: {} };
114
+ }
115
+
116
+ /**
117
+ * Gets all variant keys from a component's config, including extended
118
+ * components.
119
+ */
120
+ function collectVariantKeys(
121
+ config: CVConfig<Variants, ComputedVariants, AnyComponent[]>,
122
+ ): string[] {
123
+ const keys = new Set<string>();
124
+
125
+ // Collect from extended components
126
+ if (config.extend) {
127
+ for (const ext of config.extend) {
128
+ for (const key of ext.onlyVariants.keys) {
129
+ keys.add(key as string);
130
+ }
131
+ }
132
+ }
133
+
134
+ // Collect from variants
135
+ if (config.variants) {
136
+ for (const key of Object.keys(config.variants)) {
137
+ keys.add(key);
138
+ }
139
+ }
140
+
141
+ // Collect from computedVariants
142
+ if (config.computedVariants) {
143
+ for (const key of Object.keys(config.computedVariants)) {
144
+ keys.add(key);
145
+ }
146
+ }
147
+
148
+ return Array.from(keys);
149
+ }
150
+
151
+ /**
152
+ * Collects default variants from extended components and the current config.
153
+ * Also handles implicit boolean defaults (when only `false` key exists).
154
+ */
155
+ function collectDefaultVariants(
156
+ config: CVConfig<Variants, ComputedVariants, AnyComponent[]>,
157
+ ): Record<string, unknown> {
158
+ let defaults: Record<string, unknown> = {};
159
+
160
+ // Collect from extended components
161
+ if (config.extend) {
162
+ for (const ext of config.extend) {
163
+ const extDefaults = ext.getVariants();
164
+ defaults = { ...defaults, ...extDefaults };
165
+ }
166
+ }
167
+
168
+ // Handle implicit boolean defaults from variants
169
+ // If a variant only has a `false` key and no `true` key, default to false
170
+ if (config.variants) {
171
+ for (const [variantName, variantDef] of Object.entries(config.variants)) {
172
+ if (isStyleClassValue(variantDef)) {
173
+ const keys = Object.keys(variantDef);
174
+ const hasFalseOnly = keys.includes("false") && !keys.includes("true");
175
+ if (hasFalseOnly && defaults[variantName] === undefined) {
176
+ defaults[variantName] = false;
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ // Override with current config's defaults
183
+ if (config.defaultVariants) {
184
+ defaults = { ...defaults, ...config.defaultVariants };
185
+ }
186
+
187
+ return defaults;
188
+ }
189
+
190
+ /**
191
+ * Resolves variant values by merging defaults with provided props.
192
+ */
193
+ function resolveVariants(
194
+ config: CVConfig<Variants, ComputedVariants, AnyComponent[]>,
195
+ props: Record<string, unknown> = {},
196
+ ): Record<string, unknown> {
197
+ const defaults = collectDefaultVariants(config);
198
+ return { ...defaults, ...props };
199
+ }
200
+
201
+ /**
202
+ * Gets the value for a single variant based on the variant definition and the
203
+ * selected value.
204
+ */
205
+ function getVariantResult(
206
+ variantDef: unknown,
207
+ selectedValue: unknown,
208
+ ): { class: ClassValue; style: StyleValue } {
209
+ // Shorthand variant: `disabled: "disabled-class"` means { true: "..." }
210
+ if (!isStyleClassValue(variantDef)) {
211
+ if (selectedValue === true) {
212
+ return processVariantValue(variantDef);
213
+ }
214
+ return { class: null, style: {} };
215
+ }
216
+
217
+ // Object variant: { sm: "...", lg: "..." }
218
+ const key = String(selectedValue);
219
+ const value = (variantDef as Record<string, unknown>)[key];
220
+ if (value === undefined) return { class: null, style: {} };
221
+
222
+ return processVariantValue(value);
223
+ }
224
+
225
+ /**
226
+ * Processes extended components and returns base classes and variant classes separately.
227
+ * Base classes should come before current component's base, variant classes come after.
228
+ * When overrideVariantKeys is provided, those variant keys are excluded from the extended
229
+ * component's result (used when current component's computedVariants overrides them).
230
+ */
231
+ function processExtended(
232
+ config: CVConfig<Variants, ComputedVariants, AnyComponent[]>,
233
+ resolvedVariants: Record<string, unknown>,
234
+ overrideVariantKeys: Set<string> = new Set(),
235
+ ): {
236
+ baseClasses: ClassValue[];
237
+ variantClasses: ClassValue[];
238
+ style: StyleValue;
239
+ } {
240
+ const baseClasses: ClassValue[] = [];
241
+ const variantClasses: ClassValue[] = [];
242
+ let style: StyleValue = {};
243
+
244
+ if (config.extend) {
245
+ for (const ext of config.extend) {
246
+ // Filter out variant keys that are being overridden by current component's computedVariants
247
+ const filteredVariants = { ...resolvedVariants };
248
+ for (const key of overrideVariantKeys) {
249
+ delete filteredVariants[key];
250
+ }
251
+
252
+ // Get the result with filtered variants (excluding overridden keys)
253
+ const extResult = ext({ ...filteredVariants });
254
+
255
+ // Only merge style for non-overridden keys
256
+ const extStyle = normalizeStyle(extResult.style);
257
+ style = { ...style, ...extStyle };
258
+
259
+ // Get base class from internal property (no variants)
260
+ const baseClass = ext._baseClass;
261
+ baseClasses.push(baseClass);
262
+
263
+ // Get full class with variants
264
+ const fullClass =
265
+ "className" in extResult ? extResult.className : extResult.class;
266
+
267
+ // Extract variant portion (full class minus base class)
268
+ if (fullClass && baseClass) {
269
+ const baseClassSet = new Set(baseClass.split(" ").filter(Boolean));
270
+ const variantPortion = fullClass
271
+ .split(" ")
272
+ .filter((c: string) => c && !baseClassSet.has(c))
273
+ .join(" ");
274
+ if (variantPortion) {
275
+ variantClasses.push(variantPortion);
276
+ }
277
+ } else if (fullClass && !baseClass) {
278
+ variantClasses.push(fullClass);
279
+ }
280
+ }
281
+ }
282
+
283
+ return { baseClasses, variantClasses, style };
284
+ }
285
+
286
+ /**
287
+ * Processes all variants (not extended) and returns accumulated class and
288
+ * style.
289
+ */
290
+ function processVariants(
291
+ config: CVConfig<Variants, ComputedVariants, AnyComponent[]>,
292
+ resolvedVariants: Record<string, unknown>,
293
+ ): { classes: ClassValue[]; style: StyleValue } {
294
+ const classes: ClassValue[] = [];
295
+ let style: StyleValue = {};
296
+
297
+ // Process current component's variants
298
+ if (config.variants) {
299
+ for (const [variantName, variantDef] of Object.entries(config.variants)) {
300
+ const selectedValue = resolvedVariants[variantName];
301
+ if (selectedValue === undefined) continue;
302
+
303
+ const result = getVariantResult(variantDef, selectedValue);
304
+ classes.push(result.class);
305
+ style = { ...style, ...result.style };
306
+ }
307
+ }
308
+
309
+ // Process computedVariants
310
+ if (config.computedVariants) {
311
+ for (const [variantName, computeFn] of Object.entries(
312
+ config.computedVariants,
313
+ )) {
314
+ const selectedValue = resolvedVariants[variantName];
315
+ if (selectedValue === undefined) continue;
316
+
317
+ const computedResult = computeFn(selectedValue);
318
+ const result = processVariantValue(computedResult);
319
+ classes.push(result.class);
320
+ style = { ...style, ...result.style };
321
+ }
322
+ }
323
+
324
+ return { classes, style };
325
+ }
326
+
327
+ /**
328
+ * Processes the computed function if present.
329
+ */
330
+ function processComputed(
331
+ config: CVConfig<Variants, ComputedVariants, AnyComponent[]>,
332
+ resolvedVariants: Record<string, unknown>,
333
+ ): {
334
+ classes: ClassValue[];
335
+ style: StyleValue;
336
+ updatedVariants: Record<string, unknown>;
337
+ } {
338
+ const classes: ClassValue[] = [];
339
+ let style: StyleValue = {};
340
+ let updatedVariants = { ...resolvedVariants };
341
+
342
+ if (config.computed) {
343
+ const context = {
344
+ variants: resolvedVariants,
345
+ setVariants: (newVariants: VariantValues<Record<string, unknown>>) => {
346
+ updatedVariants = { ...updatedVariants, ...newVariants };
347
+ },
348
+ setDefaultVariants: (
349
+ newDefaults: VariantValues<Record<string, unknown>>,
350
+ ) => {
351
+ // Only apply defaults for variants not already set
352
+ for (const [key, value] of Object.entries(newDefaults)) {
353
+ if (resolvedVariants[key] === undefined) {
354
+ updatedVariants[key] = value;
355
+ }
356
+ }
357
+ },
358
+ };
359
+
360
+ const computedResult = config.computed(context);
361
+ if (computedResult != null) {
362
+ const result = processVariantValue(computedResult);
363
+ classes.push(result.class);
364
+ style = { ...style, ...result.style };
365
+ }
366
+ }
367
+
368
+ return { classes, style, updatedVariants };
369
+ }
370
+
371
+ /**
372
+ * Normalizes a key source (array or component) to an object with keys and defaults.
373
+ */
374
+ function normalizeKeySource(source: unknown): {
375
+ keys: string[];
376
+ defaults: Record<string, unknown>;
377
+ } {
378
+ if (Array.isArray(source)) {
379
+ return { keys: source as string[], defaults: {} };
380
+ }
381
+ // Components are functions with keys property, onlyVariants are objects with keys
382
+ if (
383
+ source &&
384
+ (typeof source === "object" || typeof source === "function") &&
385
+ "keys" in source
386
+ ) {
387
+ const keys = [...(source as { keys: string[] }).keys] as string[];
388
+ const defaults =
389
+ "getVariants" in source
390
+ ? (
391
+ source as { getVariants: () => Record<string, unknown> }
392
+ ).getVariants()
393
+ : {};
394
+ return { keys, defaults };
395
+ }
396
+ return { keys: [], defaults: {} };
397
+ }
398
+
399
+ /**
400
+ * Splits props into multiple groups based on key sources.
401
+ */
402
+ function splitPropsImpl(
403
+ selfKeys: string[],
404
+ selfDefaults: Record<string, unknown>,
405
+ props: Record<string, unknown>,
406
+ sources: Array<{ keys: string[]; defaults: Record<string, unknown> }>,
407
+ ): Record<string, unknown>[] {
408
+ const allUsedKeys = new Set<string>(selfKeys);
409
+ const results: Record<string, unknown>[] = [];
410
+
411
+ // Self result with defaults
412
+ const selfResult: Record<string, unknown> = {};
413
+ // First apply defaults
414
+ for (const [key, value] of Object.entries(selfDefaults)) {
415
+ if (selfKeys.includes(key)) {
416
+ selfResult[key] = value;
417
+ }
418
+ }
419
+ // Then override with props
420
+ for (const key of selfKeys) {
421
+ if (key in props) {
422
+ selfResult[key] = props[key];
423
+ }
424
+ }
425
+ results.push(selfResult);
426
+
427
+ // Process each source
428
+ for (const source of sources) {
429
+ const sourceResult: Record<string, unknown> = {};
430
+ // First apply defaults
431
+ for (const [key, value] of Object.entries(source.defaults)) {
432
+ if (source.keys.includes(key)) {
433
+ sourceResult[key] = value;
434
+ }
435
+ }
436
+ // Then override with props
437
+ for (const key of source.keys) {
438
+ allUsedKeys.add(key);
439
+ if (key in props) {
440
+ sourceResult[key] = props[key];
441
+ }
442
+ }
443
+ results.push(sourceResult);
444
+ }
445
+
446
+ // Rest - keys not used by anyone
447
+ const rest: Record<string, unknown> = {};
448
+ for (const [key, value] of Object.entries(props)) {
449
+ if (!allUsedKeys.has(key)) {
450
+ rest[key] = value;
451
+ }
452
+ }
453
+ results.push(rest);
454
+
455
+ return results;
456
+ }
457
+
458
+ export function create<M extends Mode>({
459
+ defaultMode = "jsx" as M,
460
+ transformClass = (className) => className,
461
+ }: CreateParams<M> = {}) {
462
+ const cx = (...classes: ClsxClassValue[]) => transformClass(clsx(...classes));
463
+
464
+ const cv = <
465
+ V extends Variants = {},
466
+ CV extends ComputedVariants = {},
467
+ const E extends AnyComponent[] = [],
468
+ >(
469
+ config: CVConfig<V, CV, E> = {},
470
+ ): Component<V, CV, E, StyleProps[M]> => {
471
+ type MergedVariants = MergeVariants<V, CV, E>;
472
+
473
+ const variantKeys = collectVariantKeys(
474
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
475
+ );
476
+
477
+ const getClassPropertyName = (mode: Mode) =>
478
+ mode === "jsx" ? "className" : "class";
479
+
480
+ const getPropsKeys = (mode: Mode) => [
481
+ getClassPropertyName(mode),
482
+ "style",
483
+ ...variantKeys,
484
+ ];
485
+
486
+ const computeResult = (
487
+ props: ComponentProps<MergedVariants> = {},
488
+ ): { className: string; style: StyleValue } => {
489
+ const allClasses: ClassValue[] = [];
490
+ let allStyle: StyleValue = {};
491
+
492
+ // Extract variant props from input
493
+ const variantProps: Record<string, unknown> = {};
494
+ for (const key of variantKeys) {
495
+ if (key in props) {
496
+ variantProps[key] = (props as Record<string, unknown>)[key];
497
+ }
498
+ }
499
+
500
+ // Resolve variants with defaults
501
+ let resolvedVariants = resolveVariants(
502
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
503
+ variantProps,
504
+ );
505
+
506
+ // Process computed first to potentially update variants
507
+ const computedResult = processComputed(
508
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
509
+ resolvedVariants,
510
+ );
511
+ resolvedVariants = computedResult.updatedVariants;
512
+
513
+ // Collect computedVariants keys that will override extended variants
514
+ const computedVariantKeys = new Set<string>(
515
+ config.computedVariants ? Object.keys(config.computedVariants) : [],
516
+ );
517
+
518
+ // Process extended components (separates base and variant classes)
519
+ const extendedResult = processExtended(
520
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
521
+ resolvedVariants,
522
+ computedVariantKeys,
523
+ );
524
+
525
+ // 1. Extended base classes first
526
+ allClasses.push(...extendedResult.baseClasses);
527
+ allStyle = { ...allStyle, ...extendedResult.style };
528
+
529
+ // 2. Current component's base class
530
+ allClasses.push(config.class);
531
+
532
+ // 3. Add base style
533
+ if (config.style) {
534
+ allStyle = { ...allStyle, ...config.style };
535
+ }
536
+
537
+ // 4. Extended variant classes
538
+ allClasses.push(...extendedResult.variantClasses);
539
+
540
+ // 5. Current component's variants
541
+ const variantsResult = processVariants(
542
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
543
+ resolvedVariants,
544
+ );
545
+ allClasses.push(...variantsResult.classes);
546
+ allStyle = { ...allStyle, ...variantsResult.style };
547
+
548
+ // Add computed results
549
+ allClasses.push(...computedResult.classes);
550
+ allStyle = { ...allStyle, ...computedResult.style };
551
+
552
+ // Merge class from props
553
+ if ("class" in props) {
554
+ allClasses.push(props.class);
555
+ }
556
+ if ("className" in props) {
557
+ allClasses.push(props.className);
558
+ }
559
+
560
+ // Merge style from props
561
+ if (props.style != null) {
562
+ allStyle = { ...allStyle, ...normalizeStyle(props.style) };
563
+ }
564
+
565
+ return {
566
+ className: cx(...(allClasses as ClsxClassValue[])),
567
+ style: allStyle,
568
+ };
569
+ };
570
+
571
+ type Defaults = VariantValues<MergedVariants>;
572
+
573
+ const createModalComponent = <R extends ComponentResult>(
574
+ mode: Mode,
575
+ ): ModalComponent<MergedVariants, Defaults, R> => {
576
+ const propsKeys = getPropsKeys(mode);
577
+
578
+ const component = ((props: ComponentProps<MergedVariants> = {}) => {
579
+ const { className, style } = computeResult(props);
580
+
581
+ if (mode === "jsx") {
582
+ return { className, style: styleValueToJSXStyle(style) } as R;
583
+ }
584
+ if (mode === "html") {
585
+ return {
586
+ class: className,
587
+ style: styleValueToHTMLStyle(style),
588
+ } as R;
589
+ }
590
+ // htmlObj
591
+ return {
592
+ class: className,
593
+ style: styleValueToHTMLObjStyle(style),
594
+ } as R;
595
+ }) as ModalComponent<MergedVariants, Defaults, R>;
596
+
597
+ component.class = (props: ComponentProps<MergedVariants> = {}) => {
598
+ return computeResult(props).className;
599
+ };
600
+
601
+ component.style = ((props: ComponentProps<MergedVariants> = {}) => {
602
+ const { style } = computeResult(props);
603
+ if (mode === "jsx") return styleValueToJSXStyle(style);
604
+ if (mode === "html") return styleValueToHTMLStyle(style);
605
+ return styleValueToHTMLObjStyle(style);
606
+ }) as ModalComponent<MergedVariants, Defaults, R>["style"];
607
+
608
+ component.getVariants = (
609
+ variants?: VariantValues<MergedVariants>,
610
+ ): VariantValues<MergedVariants> => {
611
+ return resolveVariants(
612
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
613
+ variants as VariantValues<Record<string, unknown>>,
614
+ ) as VariantValues<MergedVariants>;
615
+ };
616
+
617
+ component.keys = propsKeys as (keyof MergedVariants | keyof R)[];
618
+
619
+ const selfDefaults = collectDefaultVariants(
620
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
621
+ );
622
+
623
+ component.splitProps = ((
624
+ props: Record<string, unknown>,
625
+ ...sources: unknown[]
626
+ ) => {
627
+ const normalizedSources = sources.map(normalizeKeySource);
628
+ return splitPropsImpl(
629
+ propsKeys,
630
+ selfDefaults,
631
+ props,
632
+ normalizedSources,
633
+ );
634
+ }) as SplitProps<MergedVariants, VariantValues<MergedVariants>, R>;
635
+
636
+ component.onlyVariants = {
637
+ getVariants: (
638
+ variants?: VariantValues<MergedVariants>,
639
+ ): VariantValues<MergedVariants> => {
640
+ return resolveVariants(
641
+ config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
642
+ variants as VariantValues<Record<string, unknown>>,
643
+ ) as VariantValues<MergedVariants>;
644
+ },
645
+ keys: variantKeys as (keyof MergedVariants)[],
646
+ splitProps: ((
647
+ props: Record<string, unknown>,
648
+ ...sources: unknown[]
649
+ ) => {
650
+ const normalizedSources = sources.map(normalizeKeySource);
651
+ return splitPropsImpl(
652
+ variantKeys,
653
+ selfDefaults,
654
+ props,
655
+ normalizedSources,
656
+ );
657
+ }) as OnlyVariantsSplitProps<
658
+ MergedVariants,
659
+ VariantValues<MergedVariants>
660
+ >,
661
+ } as OnlyVariantsComponent<MergedVariants, VariantValues<MergedVariants>>;
662
+
663
+ // Compute base class (without variants) - includes extended base classes
664
+ const extendedBaseClasses: ClassValue[] = [];
665
+ if (config.extend) {
666
+ for (const ext of config.extend) {
667
+ extendedBaseClasses.push(ext._baseClass);
668
+ }
669
+ }
670
+ component._baseClass = cx(
671
+ ...(extendedBaseClasses as ClsxClassValue[]),
672
+ config.class as ClsxClassValue,
673
+ );
674
+
675
+ return component;
676
+ };
677
+
678
+ // Create the default modal component
679
+ const defaultComponent = createModalComponent<StyleProps[M]>(defaultMode);
680
+
681
+ // Create all modal variants
682
+ const jsxComponent = createModalComponent<JSXProps>("jsx");
683
+ const htmlComponent = createModalComponent<HTMLProps>("html");
684
+ const htmlObjComponent = createModalComponent<HTMLObjProps>("htmlObj");
685
+
686
+ // Build the final component
687
+ const component = defaultComponent as Component<V, CV, E, StyleProps[M]>;
688
+ component.jsx = jsxComponent;
689
+ component.html = htmlComponent;
690
+ component.htmlObj = htmlObjComponent;
691
+
692
+ return component;
693
+ };
694
+
695
+ return { cv, cx };
696
+ }
697
+
698
+ export const { cv, cx } = create();