@animus-ui/system 0.1.0-next.v7 → 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.
Files changed (78) hide show
  1. package/README.md +148 -0
  2. package/dist/Animus.d.ts +36 -30
  3. package/dist/Animus.d.ts.map +1 -1
  4. package/dist/AnimusExtended.d.ts +32 -27
  5. package/dist/AnimusExtended.d.ts.map +1 -1
  6. package/dist/SystemBuilder.d.ts +38 -32
  7. package/dist/SystemBuilder.d.ts.map +1 -1
  8. package/dist/compose.d.ts +24 -0
  9. package/dist/compose.d.ts.map +1 -0
  10. package/dist/compose.js +36 -0
  11. package/dist/composeWithContext.d.ts +30 -0
  12. package/dist/composeWithContext.d.ts.map +1 -0
  13. package/dist/composeWithContext.js +79 -0
  14. package/dist/createComposedFamily-BsyI6rBc.js +230 -0
  15. package/dist/groups/index.d.ts +455 -359
  16. package/dist/groups/index.d.ts.map +1 -1
  17. package/dist/groups/index.js +139 -55
  18. package/dist/index.d.ts +14 -7
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +708 -102
  21. package/dist/keyframes.d.ts +45 -0
  22. package/dist/keyframes.d.ts.map +1 -0
  23. package/dist/runtime/createClassResolver.d.ts +10 -0
  24. package/dist/runtime/createClassResolver.d.ts.map +1 -0
  25. package/dist/runtime/createComposedFamily.d.ts +16 -0
  26. package/dist/runtime/createComposedFamily.d.ts.map +1 -0
  27. package/dist/runtime/index.d.ts +26 -0
  28. package/dist/runtime/index.d.ts.map +1 -0
  29. package/dist/runtime/resolveClasses.d.ts +59 -0
  30. package/dist/runtime/resolveClasses.d.ts.map +1 -0
  31. package/dist/runtime-entry.d.ts +10 -0
  32. package/dist/runtime-entry.d.ts.map +1 -0
  33. package/dist/runtime-entry.js +2 -0
  34. package/dist/selectors.d.ts +40 -0
  35. package/dist/selectors.d.ts.map +1 -0
  36. package/dist/size-CusLCguT.js +97 -0
  37. package/dist/theme/createTheme.d.ts +59 -0
  38. package/dist/theme/createTheme.d.ts.map +1 -0
  39. package/dist/theme/flattenScale.d.ts +21 -0
  40. package/dist/theme/flattenScale.d.ts.map +1 -0
  41. package/dist/theme/index.d.ts +5 -0
  42. package/dist/theme/index.d.ts.map +1 -0
  43. package/dist/theme/serializeTokens.d.ts +8 -0
  44. package/dist/theme/serializeTokens.d.ts.map +1 -0
  45. package/dist/theme/types.d.ts +42 -0
  46. package/dist/theme/types.d.ts.map +1 -0
  47. package/dist/theme/utils.d.ts +28 -0
  48. package/dist/theme/utils.d.ts.map +1 -0
  49. package/dist/transforms/border.d.ts +4 -0
  50. package/dist/transforms/border.d.ts.map +1 -1
  51. package/dist/transforms/createTransform.d.ts +3 -1
  52. package/dist/transforms/createTransform.d.ts.map +1 -1
  53. package/dist/transforms/grid.d.ts +12 -2
  54. package/dist/transforms/grid.d.ts.map +1 -1
  55. package/dist/transforms/index.d.ts +0 -1
  56. package/dist/transforms/index.d.ts.map +1 -1
  57. package/dist/transforms/size.d.ts +8 -0
  58. package/dist/transforms/size.d.ts.map +1 -1
  59. package/dist/types/component.d.ts +148 -24
  60. package/dist/types/component.d.ts.map +1 -1
  61. package/dist/types/config.d.ts +54 -7
  62. package/dist/types/config.d.ts.map +1 -1
  63. package/dist/types/properties.d.ts +5 -7
  64. package/dist/types/properties.d.ts.map +1 -1
  65. package/dist/types/props.d.ts +13 -25
  66. package/dist/types/props.d.ts.map +1 -1
  67. package/dist/types/shared.d.ts +0 -1
  68. package/dist/types/shared.d.ts.map +1 -1
  69. package/dist/types/theme.d.ts +77 -11
  70. package/dist/types/theme.d.ts.map +1 -1
  71. package/dist/utils/deepMerge.d.ts +5 -0
  72. package/dist/utils/deepMerge.d.ts.map +1 -0
  73. package/package.json +46 -17
  74. package/dist/PropertyBuilder.d.ts +0 -11
  75. package/dist/PropertyBuilder.d.ts.map +0 -1
  76. package/dist/size-Dge_rsuz.js +0 -70
  77. package/dist/transforms/utils.d.ts +0 -3
  78. package/dist/transforms/utils.d.ts.map +0 -1
@@ -0,0 +1,36 @@
1
+ import { createElement, forwardRef } from "react";
2
+ //#region src/compose.ts
3
+ /**
4
+ * Compose independently-authored Animus components into a sealed,
5
+ * namespaced component family with shared variant propagation via
6
+ * CSS cascade.
7
+ *
8
+ * - **Enforce**: TypeScript ensures shared keys exist on Root (the
9
+ * cascade source). Non-Root slots that have the key consume it from
10
+ * CSS inheritance; slots without the key are unaffected.
11
+ * - **Wire**: The extraction pipeline emits composed variant CSS
12
+ * rules — two per shared variant option per child (inheritance +
13
+ * override) within @layer variants.
14
+ * - **Seal**: Output components are plain ForwardRefExoticComponent —
15
+ * no `.extend()`, no builder methods. One-way door from builder-land
16
+ * to component-land.
17
+ *
18
+ * For React context propagation (portal-crossing), use
19
+ * `composeWithContext` from `@animus-ui/system/compose-with-context`.
20
+ */
21
+ function compose(slots, options) {
22
+ const familyName = options.name ?? "Composed";
23
+ const result = {};
24
+ for (const [name, SourceComponent] of Object.entries(slots)) {
25
+ const Wrapper = forwardRef((props, ref) => createElement(SourceComponent, {
26
+ ...props,
27
+ ref
28
+ }, props.children));
29
+ Wrapper.displayName = `${familyName}.${name}`;
30
+ result[name] = Wrapper;
31
+ }
32
+ if (!("Root" in result)) throw new Error("compose(): No \"Root\" slot found. The root slot key must be exactly \"Root\" (PascalCase).");
33
+ return result;
34
+ }
35
+ //#endregion
36
+ export { compose };
@@ -0,0 +1,30 @@
1
+ import { type ForwardRefExoticComponent } from 'react';
2
+ import type { AnyBrandedComponent, ComposedFamily, SharedConfig } from './types/component';
3
+ /**
4
+ * Compose components into a sealed family with shared variant propagation
5
+ * via React context. Use this when children may be rendered in portals
6
+ * or other React subtrees that escape the DOM hierarchy (where CSS
7
+ * descendant selectors cannot reach).
8
+ *
9
+ * This function uses `createContext` and `useContext` — it is client-only.
10
+ * For CSS-only propagation (RSC-safe), use `compose` from the barrel or
11
+ * `@animus-ui/system/compose`.
12
+ */
13
+ export declare function composeWithContext<Slots extends Record<string, AnyBrandedComponent>, const Shared extends SharedConfig<Slots>>(slots: Slots, options: {
14
+ shared: Shared;
15
+ name?: string;
16
+ }): ComposedFamily<Slots>;
17
+ /**
18
+ * createComposedFamilyWithContext — extraction-time replacement for composeWithContext().
19
+ *
20
+ * The transform emitter replaces `composeWithContext({ Root, Body }, { shared, name })`
21
+ * with `createComposedFamilyWithContext({ Root, Body }, { name, sharedKeys })`.
22
+ *
23
+ * Client-only: uses createContext and useContext. Files containing this function
24
+ * receive a 'use client' directive from the transform emitter.
25
+ */
26
+ export declare function createComposedFamilyWithContext(slots: Record<string, ForwardRefExoticComponent<any>>, config: {
27
+ name: string;
28
+ sharedKeys: string[];
29
+ }): Record<string, ForwardRefExoticComponent<any>>;
30
+ //# sourceMappingURL=composeWithContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composeWithContext.d.ts","sourceRoot":"","sources":["../src/composeWithContext.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,yBAAyB,EAI/B,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EACd,YAAY,EACb,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACjD,KAAK,CAAC,MAAM,SAAS,YAAY,CAAC,KAAK,CAAC,EAExC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACzC,cAAc,CAAC,KAAK,CAAC,CA8CvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,CAAC,CAAC,EACrD,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GAC7C,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAqChD"}
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { createContext, createElement, forwardRef, useContext } from "react";
3
+ //#region src/composeWithContext.ts
4
+ /**
5
+ * Compose components into a sealed family with shared variant propagation
6
+ * via React context. Use this when children may be rendered in portals
7
+ * or other React subtrees that escape the DOM hierarchy (where CSS
8
+ * descendant selectors cannot reach).
9
+ *
10
+ * This function uses `createContext` and `useContext` — it is client-only.
11
+ * For CSS-only propagation (RSC-safe), use `compose` from the barrel or
12
+ * `@animus-ui/system/compose`.
13
+ */
14
+ function composeWithContext(slots, options) {
15
+ const familyName = options.name ?? "Composed";
16
+ const sharedKeySet = new Set(Object.keys(options.shared));
17
+ const FamilyCtx = createContext({});
18
+ const result = {};
19
+ for (const [name, SourceComponent] of Object.entries(slots)) {
20
+ let Wrapper;
21
+ if (name === "Root") Wrapper = forwardRef((props, ref) => {
22
+ const shared = {};
23
+ for (const key of sharedKeySet) if (key in props) shared[key] = props[key];
24
+ return createElement(SourceComponent, {
25
+ ...props,
26
+ ref
27
+ }, createElement(FamilyCtx.Provider, { value: shared }, props.children));
28
+ });
29
+ else Wrapper = forwardRef((props, ref) => {
30
+ return createElement(SourceComponent, {
31
+ ...useContext(FamilyCtx),
32
+ ...props,
33
+ ref
34
+ });
35
+ });
36
+ Wrapper.displayName = `${familyName}.${name}`;
37
+ result[name] = Wrapper;
38
+ }
39
+ if (!("Root" in result)) throw new Error("composeWithContext(): No \"Root\" slot found. The root slot key must be exactly \"Root\" (PascalCase).");
40
+ return result;
41
+ }
42
+ /**
43
+ * createComposedFamilyWithContext — extraction-time replacement for composeWithContext().
44
+ *
45
+ * The transform emitter replaces `composeWithContext({ Root, Body }, { shared, name })`
46
+ * with `createComposedFamilyWithContext({ Root, Body }, { name, sharedKeys })`.
47
+ *
48
+ * Client-only: uses createContext and useContext. Files containing this function
49
+ * receive a 'use client' directive from the transform emitter.
50
+ */
51
+ function createComposedFamilyWithContext(slots, config) {
52
+ const { name, sharedKeys } = config;
53
+ const Ctx = createContext({});
54
+ const keySet = new Set(sharedKeys);
55
+ const result = {};
56
+ for (const [slotName, SourceComponent] of Object.entries(slots)) {
57
+ let Wrapper;
58
+ if (slotName === "Root") Wrapper = forwardRef((props, ref) => {
59
+ const shared = {};
60
+ for (const key of keySet) if (key in props) shared[key] = props[key];
61
+ return createElement(SourceComponent, {
62
+ ...props,
63
+ ref
64
+ }, createElement(Ctx.Provider, { value: shared }, props.children));
65
+ });
66
+ else Wrapper = forwardRef((props, ref) => {
67
+ return createElement(SourceComponent, {
68
+ ...useContext(Ctx),
69
+ ...props,
70
+ ref
71
+ });
72
+ });
73
+ Wrapper.displayName = `${name}.${slotName}`;
74
+ result[slotName] = Wrapper;
75
+ }
76
+ return result;
77
+ }
78
+ //#endregion
79
+ export { composeWithContext, createComposedFamilyWithContext };
@@ -0,0 +1,230 @@
1
+ import { Children, cloneElement, createElement, forwardRef, isValidElement } from "react";
2
+ import { UNITLESS_PROPERTIES } from "@animus-ui/properties";
3
+ //#region src/runtime/resolveClasses.ts
4
+ /**
5
+ * Apply unit fallback to a value for a given CSS property.
6
+ */
7
+ function applyUnitFallback(value, cssProperty) {
8
+ if (typeof value === "number") {
9
+ if (UNITLESS_PROPERTIES.has(cssProperty)) return String(value);
10
+ return `${value}px`;
11
+ }
12
+ return String(value);
13
+ }
14
+ /**
15
+ * Serialize a system prop value to a lookup key matching the Rust
16
+ * css_generator's serialize_value_key output format.
17
+ */
18
+ function serializeValueKey(value) {
19
+ if (typeof value === "number" || typeof value === "string") return String(value);
20
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) return Object.keys(value).sort().map((k) => `${k}:${value[k]}`).join("|");
21
+ return String(value);
22
+ }
23
+ /**
24
+ * Resolve a dynamic prop value through scale lookup → transform → unit fallback.
25
+ */
26
+ function resolveValue(value, dc) {
27
+ const key = String(value);
28
+ const scaleResolved = dc.scaleValues?.[key];
29
+ if (scaleResolved != null) {
30
+ const transformed = dc.transform ? dc.transform(scaleResolved) : scaleResolved;
31
+ return String(transformed);
32
+ }
33
+ return applyUnitFallback(dc.transform ? dc.transform(value) : value, dc.varName);
34
+ }
35
+ /**
36
+ * Resolve className parts from props, using extracted configuration.
37
+ * This is the shared logic between createComponent and createClassResolver.
38
+ */
39
+ function resolveClasses(baseClassName, props, config, systemPropMap, dynamicPropConfig) {
40
+ const classes = [baseClassName];
41
+ let dynStyle;
42
+ if (config.variants) for (const [prop, vc] of Object.entries(config.variants)) {
43
+ const value = props[prop] ?? vc.default;
44
+ if (value != null) {
45
+ const isDefault = !(prop in props) && vc.default != null;
46
+ classes.push(`${baseClassName}--${prop}-${isDefault ? "default" : value}`);
47
+ }
48
+ }
49
+ if (config.compounds) for (const compound of config.compounds) {
50
+ let match = true;
51
+ for (const [prop, expected] of Object.entries(compound.conditions)) {
52
+ const current = props[prop] ?? config.variants?.[prop]?.default;
53
+ if (Array.isArray(expected) ? !expected.includes(current) : current !== expected) {
54
+ match = false;
55
+ break;
56
+ }
57
+ }
58
+ if (match) classes.push(compound.className);
59
+ }
60
+ const activeStates = [];
61
+ if (config.states) {
62
+ for (const state of config.states) if (props[state]) {
63
+ classes.push(`${baseClassName}--${state}`);
64
+ activeStates.push(state);
65
+ }
66
+ }
67
+ const systemPropNames = config.systemPropNames || [];
68
+ if (systemPropNames.length > 0) {
69
+ const { customPropMap, customDynamicConfig } = config;
70
+ for (const propName of systemPropNames) {
71
+ if (!(propName in props)) continue;
72
+ const propValue = props[propName];
73
+ if (propValue == null) continue;
74
+ const key = serializeValueKey(propValue);
75
+ const cls = customPropMap?.[propName]?.[key] ?? systemPropMap?.[propName]?.[key];
76
+ if (cls) classes.push(cls);
77
+ else {
78
+ const dc = customDynamicConfig?.[propName] ?? dynamicPropConfig?.[propName];
79
+ if (dc) {
80
+ if (!dynStyle) dynStyle = {};
81
+ if (typeof propValue === "object" && propValue !== null && !Array.isArray(propValue)) for (const [bp, bpVal] of Object.entries(propValue)) {
82
+ if (bpVal == null) continue;
83
+ if (bp === "_") {
84
+ classes.push(dc.slotClass);
85
+ const finalVal = resolveValue(bpVal, dc);
86
+ dynStyle[dc.varName] = finalVal;
87
+ } else {
88
+ classes.push(`${dc.slotClass}-${bp}`);
89
+ const varName = `${dc.varName}-${bp}`;
90
+ const finalVal = resolveValue(bpVal, dc);
91
+ dynStyle[varName] = finalVal;
92
+ }
93
+ }
94
+ else {
95
+ classes.push(dc.slotClass);
96
+ const finalVal = resolveValue(propValue, dc);
97
+ dynStyle[dc.varName] = finalVal;
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ return {
104
+ classes,
105
+ dynamicStyle: dynStyle,
106
+ activeStates
107
+ };
108
+ }
109
+ //#endregion
110
+ //#region src/runtime/index.ts
111
+ /**
112
+ * Merge multiple refs (callback or object) into a single callback ref.
113
+ * Creates a new callback on each call — no memoization possible in a
114
+ * hook-free runtime (RSC compatibility). Matches @radix-ui/react-compose-refs.
115
+ */
116
+ function composeRefs(...refs) {
117
+ return (node) => {
118
+ for (const ref of refs) if (typeof ref === "function") ref(node);
119
+ else if (ref) ref.current = node;
120
+ };
121
+ }
122
+ /**
123
+ * Create a lightweight component that applies extracted CSS class names.
124
+ * Replaces Emotion's styled() for extracted components.
125
+ *
126
+ * The element parameter accepts either an HTML tag string (e.g. 'button') or
127
+ * a React component reference (e.g. NextLink). When a component reference is
128
+ * used, prop forwarding skips the HTML-attribute validity check — all
129
+ * non-filtered props are forwarded to the component.
130
+ *
131
+ * The optional systemPropMap parameter provides the shared prop→value→className
132
+ * lookup table, served as a virtual module by the Vite plugin.
133
+ *
134
+ * The optional dynamicPropConfig parameter provides CSS variable fallback
135
+ * metadata for props with detected dynamic usage.
136
+ */
137
+ function createComponent(element, className, config, systemPropMap, dynamicPropConfig) {
138
+ const variantProps = config.variants ? Object.keys(config.variants) : [];
139
+ const stateProps = config.states || [];
140
+ const systemPropNames = config.systemPropNames || [];
141
+ const filterProps = new Set([
142
+ "as",
143
+ "asChild",
144
+ ...variantProps,
145
+ ...stateProps,
146
+ ...systemPropNames
147
+ ]);
148
+ const Component = forwardRef((props, ref) => {
149
+ const { classes, dynamicStyle } = resolveClasses(className, props, config, systemPropMap, dynamicPropConfig);
150
+ if (props.className) classes.push(props.className);
151
+ if (props.asChild) {
152
+ const child = Children.only(props.children);
153
+ if (!isValidElement(child)) throw new Error(`${className}: asChild requires a single React element as children`);
154
+ const childRef = child.ref;
155
+ const mergedClassName = [classes.join(" "), child.props.className].filter(Boolean).join(" ");
156
+ const mergedStyle = dynamicStyle || props.style || child.props.style ? {
157
+ ...props.style,
158
+ ...child.props.style,
159
+ ...dynamicStyle
160
+ } : void 0;
161
+ return cloneElement(child, {
162
+ ref: composeRefs(ref, childRef),
163
+ className: mergedClassName,
164
+ ...mergedStyle ? { style: mergedStyle } : {}
165
+ });
166
+ }
167
+ const renderElement = props.as || element;
168
+ const isComponentElement = typeof renderElement !== "string";
169
+ const domProps = {
170
+ ref,
171
+ className: classes.join(" ")
172
+ };
173
+ for (const [key, value] of Object.entries(props)) {
174
+ if (key === "className") continue;
175
+ if (!(key.startsWith("data-") || key.startsWith("aria-")) && filterProps.has(key)) continue;
176
+ if (!isComponentElement) {}
177
+ domProps[key] = value;
178
+ }
179
+ if (dynamicStyle) domProps.style = props.style ? {
180
+ ...props.style,
181
+ ...dynamicStyle
182
+ } : dynamicStyle;
183
+ return createElement(renderElement, domProps);
184
+ });
185
+ Component.displayName = className;
186
+ return Object.assign(Component, { extend: () => {
187
+ throw new Error(`Cannot extend extracted component "${className}" at runtime. Extensions must be authored in source code using the builder API (e.g. import the original component and call .extend() there) so the extraction pipeline can resolve them at build time.`);
188
+ } });
189
+ }
190
+ //#endregion
191
+ //#region src/runtime/createClassResolver.ts
192
+ /**
193
+ * createClassResolver — framework-agnostic className resolution.
194
+ *
195
+ * Produced by .asClass() terminal. Same resolution logic as createComponent
196
+ * (variants, states, compounds, system props) but returns a className string
197
+ * instead of a React element.
198
+ */
199
+ function createClassResolver(className, config, systemPropMap, dynamicPropConfig) {
200
+ return (props) => {
201
+ const { classes } = resolveClasses(className, props || {}, config, systemPropMap, dynamicPropConfig);
202
+ return classes.join(" ");
203
+ };
204
+ }
205
+ //#endregion
206
+ //#region src/runtime/createComposedFamily.ts
207
+ /**
208
+ * createComposedFamily — extraction-time replacement for compose().
209
+ *
210
+ * The transform emitter replaces `compose({ Root, Body }, { shared, name })`
211
+ * with `createComposedFamily({ Root, Body }, { name })`.
212
+ *
213
+ * RSC-safe: uses only forwardRef and createElement — no createContext,
214
+ * no useContext, no hooks.
215
+ */
216
+ function createComposedFamily(slots, config) {
217
+ const { name } = config;
218
+ const result = {};
219
+ for (const [slotName, SourceComponent] of Object.entries(slots)) {
220
+ const Wrapper = forwardRef((props, ref) => createElement(SourceComponent, {
221
+ ...props,
222
+ ref
223
+ }, props.children));
224
+ Wrapper.displayName = `${name}.${slotName}`;
225
+ result[slotName] = Wrapper;
226
+ }
227
+ return result;
228
+ }
229
+ //#endregion
230
+ export { createClassResolver as n, createComponent as r, createComposedFamily as t };