@shohojdhara/atomix 0.3.6 → 0.3.7
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/README.md +3 -3
- package/dist/charts.js +50 -142
- package/dist/charts.js.map +1 -1
- package/dist/core.js +179 -274
- package/dist/core.js.map +1 -1
- package/dist/forms.js +50 -142
- package/dist/forms.js.map +1 -1
- package/dist/heavy.js +179 -274
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +669 -703
- package/dist/index.esm.js +966 -1649
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1211 -1890
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +163 -334
- package/dist/theme.js +774 -1473
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AtomixGlass/AtomixGlass.tsx +128 -356
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
- package/src/components/Button/Button.tsx +85 -167
- package/src/lib/composables/useAtomixGlass.ts +7 -7
- package/src/lib/config/loader.ts +2 -3
- package/src/lib/constants/components.ts +7 -0
- package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
- package/src/lib/hooks/useThemeTokens.ts +105 -0
- package/src/lib/theme/config/configLoader.ts +60 -219
- package/src/lib/theme/config/loader.ts +15 -21
- package/src/lib/theme/constants/constants.ts +1 -1
- package/src/lib/theme/core/ThemeRegistry.ts +75 -279
- package/src/lib/theme/core/composeTheme.ts +14 -64
- package/src/lib/theme/core/createTheme.ts +54 -40
- package/src/lib/theme/core/createThemeObject.ts +2 -2
- package/src/lib/theme/core/index.ts +15 -1
- package/src/lib/theme/errors/errors.ts +1 -1
- package/src/lib/theme/generators/generateCSSNested.ts +130 -0
- package/src/lib/theme/generators/index.ts +6 -0
- package/src/lib/theme/index.ts +35 -10
- package/src/lib/theme/runtime/ThemeApplicator.ts +1 -1
- package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +4 -4
- package/src/lib/theme/runtime/ThemeProvider.tsx +261 -554
- package/src/lib/theme/runtime/index.ts +1 -0
- package/src/lib/theme/runtime/useThemeTokens.ts +131 -0
- package/src/lib/theme/utils/componentTheming.ts +132 -0
- package/src/lib/theme/utils/naming.ts +100 -0
- package/src/lib/theme/utils/themeUtils.ts +6 -6
- package/src/lib/utils/componentUtils.ts +1 -1
- package/src/lib/utils/memoryMonitor.ts +3 -3
- package/src/lib/utils/themeNaming.ts +135 -0
package/dist/index.esm.js
CHANGED
|
@@ -15,6 +15,11 @@ import { createPortal } from "react-dom";
|
|
|
15
15
|
UTILITY: "u-",
|
|
16
16
|
LAYOUT: "l-",
|
|
17
17
|
OBJECT: "o-"
|
|
18
|
+
}, THEME_NAMING = {
|
|
19
|
+
BUTTON_PREFIX: "btn",
|
|
20
|
+
ICON_ELEMENT: "icon",
|
|
21
|
+
LABEL_ELEMENT: "label",
|
|
22
|
+
SPINNER_ELEMENT: "spinner"
|
|
18
23
|
}, BUTTON = {
|
|
19
24
|
BASE_CLASS: "c-btn",
|
|
20
25
|
ICON_CLASS: "c-btn__icon",
|
|
@@ -1885,7 +1890,7 @@ const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevP
|
|
|
1885
1890
|
timestamp: Date.now()
|
|
1886
1891
|
}),
|
|
1887
1892
|
// Development mode: log cache size
|
|
1888
|
-
"production"
|
|
1893
|
+
"undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
|
|
1889
1894
|
})(cacheKey, url), setShaderMapUrl(url);
|
|
1890
1895
|
};
|
|
1891
1896
|
"undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
|
|
@@ -2198,9 +2203,9 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2198
2203
|
childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS && (extractedRadius = childRadius,
|
|
2199
2204
|
extractionSource = "React children");
|
|
2200
2205
|
}
|
|
2201
|
-
null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : process.env
|
|
2206
|
+
null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : "undefined" == typeof process || process.env;
|
|
2202
2207
|
} catch (error) {
|
|
2203
|
-
"production"
|
|
2208
|
+
"undefined" != typeof process && "production" === process.env?.NODE_ENV || !debugCornerRadius || console.error("[AtomixGlass] Error extracting corner radius:", error);
|
|
2204
2209
|
}
|
|
2205
2210
|
};
|
|
2206
2211
|
extractRadius();
|
|
@@ -2275,7 +2280,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2275
2280
|
// For image backgrounds, assume medium luminance
|
|
2276
2281
|
totalLuminance += .5, validSamples++, hasValidBackground = !0);
|
|
2277
2282
|
} catch (styleError) {
|
|
2278
|
-
process.env
|
|
2283
|
+
"undefined" == typeof process || process.env;
|
|
2279
2284
|
}
|
|
2280
2285
|
// Move to parent element for next iteration
|
|
2281
2286
|
if (!currentElement) break;
|
|
@@ -2314,7 +2319,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2314
2319
|
}
|
|
2315
2320
|
} catch (error) {
|
|
2316
2321
|
// Enhanced error logging with context
|
|
2317
|
-
"development"
|
|
2322
|
+
"undefined" != typeof process && "development" !== process.env?.NODE_ENV || console.warn("AtomixGlass: Error detecting background brightness:", error);
|
|
2318
2323
|
const result = !1;
|
|
2319
2324
|
if (element && element.parentElement) {
|
|
2320
2325
|
const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
|
|
@@ -2371,7 +2376,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2371
2376
|
};
|
|
2372
2377
|
// Calculate offset relative to this container
|
|
2373
2378
|
// React 18 automatically batches these updates
|
|
2374
|
-
setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "production"
|
|
2379
|
+
setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "undefined" != typeof process && "production" === process.env?.NODE_ENV || !enablePerformanceMonitoring || performance.now();
|
|
2375
2380
|
}), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects, enablePerformanceMonitoring ]);
|
|
2376
2381
|
// Subscribe to shared mouse tracker
|
|
2377
2382
|
useEffect((() => {
|
|
@@ -2511,10 +2516,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2511
2516
|
saturationBoost: validatedSaturationBoost + .4 * mouseInfluence
|
|
2512
2517
|
};
|
|
2513
2518
|
// Validate and apply object config values with proper clamping
|
|
2514
|
-
return process.env
|
|
2519
|
+
return "undefined" == typeof process || process.env, finalConfig;
|
|
2515
2520
|
}
|
|
2516
2521
|
// Debug logging for non-object configs
|
|
2517
|
-
return process.env
|
|
2522
|
+
return "undefined" == typeof process || process.env, baseConfig;
|
|
2518
2523
|
}), [ overLight, getEffectiveOverLight, mouseOffset, isHovered, isActive, validateConfigValue, debugOverLight ]), handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
|
|
2519
2524
|
!onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
|
|
2520
2525
|
}), [ onClick ]), handleMouseMove = useCallback((_e => {}), []);
|
|
@@ -2625,7 +2630,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2625
2630
|
* <div>Content with debug logging enabled</div>
|
|
2626
2631
|
* </AtomixGlass>
|
|
2627
2632
|
*/ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, cornerRadius: cornerRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, disableEffects: disableEffects = !1, enableLiquidBlur: enableLiquidBlur = !1, enableBorderEffect: enableBorderEffect = !0, enableOverLightLayers: enableOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, enablePerformanceMonitoring: enablePerformanceMonitoring = !1, debugCornerRadius: debugCornerRadius = !1, debugOverLight: debugOverLight = !1}) {
|
|
2628
|
-
const glassRef = useRef(null), contentRef = useRef(null),
|
|
2633
|
+
const glassRef = useRef(null), contentRef = useRef(null), {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveCornerRadius: effectiveCornerRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveDisableEffects: effectiveDisableEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
|
|
2629
2634
|
glassRef: glassRef,
|
|
2630
2635
|
contentRef: contentRef,
|
|
2631
2636
|
cornerRadius: cornerRadius,
|
|
@@ -2642,143 +2647,51 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2642
2647
|
debugOverLight: debugOverLight,
|
|
2643
2648
|
enablePerformanceMonitoring: enablePerformanceMonitoring,
|
|
2644
2649
|
children: children
|
|
2645
|
-
}), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight
|
|
2646
|
-
// Read CSS custom properties once on mount and cache them
|
|
2647
|
-
useEffect((() => {
|
|
2648
|
-
if ("undefined" != typeof window && glassRef.current) try {
|
|
2649
|
-
const computedStyle = window.getComputedStyle(glassRef.current);
|
|
2650
|
-
// Cache opacity values
|
|
2651
|
-
if (!opacityCacheRef.current) {
|
|
2652
|
-
const opacity50Value = computedStyle.getPropertyValue("--atomix-opacity-50").trim(), opacity40Value = computedStyle.getPropertyValue("--atomix-opacity-40").trim(), opacity80Value = computedStyle.getPropertyValue("--atomix-opacity-80").trim(), opacity0Value = computedStyle.getPropertyValue("--atomix-opacity-0").trim(), parseOpacity = (value, defaultValue) => {
|
|
2653
|
-
if (!value) return defaultValue;
|
|
2654
|
-
const parsed = parseFloat(value);
|
|
2655
|
-
return isNaN(parsed) ? defaultValue : parsed;
|
|
2656
|
-
};
|
|
2657
|
-
opacityCacheRef.current = {
|
|
2658
|
-
opacity50: parseOpacity(opacity50Value, .5),
|
|
2659
|
-
opacity40: parseOpacity(opacity40Value, .4),
|
|
2660
|
-
opacity80: parseOpacity(opacity80Value, .8),
|
|
2661
|
-
opacity0: parseOpacity(opacity0Value, 0)
|
|
2662
|
-
};
|
|
2663
|
-
}
|
|
2664
|
-
// Cache RGB color values from design tokens
|
|
2665
|
-
if (!rgbCacheRef.current) {
|
|
2666
|
-
// Try to read from design tokens, fallback to defaults
|
|
2667
|
-
const whiteRgbValue = computedStyle.getPropertyValue("--atomix-light-rgb").trim() || computedStyle.getPropertyValue("--atomix-white-rgb").trim() || "", blackRgbValue = computedStyle.getPropertyValue("--atomix-dark-rgb").trim() || computedStyle.getPropertyValue("--atomix-black-rgb").trim() || "";
|
|
2668
|
-
rgbCacheRef.current = {
|
|
2669
|
-
whiteRgb: whiteRgbValue || "255, 255, 255",
|
|
2670
|
-
// Fallback to white RGB
|
|
2671
|
-
blackRgb: blackRgbValue || "0, 0, 0"
|
|
2672
|
-
};
|
|
2673
|
-
}
|
|
2674
|
-
} catch (error) {
|
|
2675
|
-
// Fallback to defaults if reading fails
|
|
2676
|
-
opacityCacheRef.current || (opacityCacheRef.current = {
|
|
2677
|
-
opacity50: .5,
|
|
2678
|
-
opacity40: .4,
|
|
2679
|
-
opacity80: .8,
|
|
2680
|
-
opacity0: 0
|
|
2681
|
-
}), rgbCacheRef.current || (rgbCacheRef.current = {
|
|
2682
|
-
whiteRgb: "255, 255, 255",
|
|
2683
|
-
blackRgb: "0, 0, 0"
|
|
2684
|
-
});
|
|
2685
|
-
}
|
|
2686
|
-
}), []);
|
|
2687
|
-
// Calculate base style with transforms (only dynamic values)
|
|
2688
|
-
const baseStyle = useMemo((() => ({
|
|
2650
|
+
}), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight, baseStyle = {
|
|
2689
2651
|
...style,
|
|
2690
2652
|
...0 !== elasticity && !effectiveDisableEffects && {
|
|
2691
2653
|
transform: transformStyle
|
|
2692
2654
|
}
|
|
2693
|
-
}
|
|
2694
|
-
position:
|
|
2695
|
-
top:
|
|
2696
|
-
left:
|
|
2697
|
-
}
|
|
2698
|
-
width: "fixed" !==
|
|
2699
|
-
height: "fixed" !==
|
|
2700
|
-
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
}), [ isHovered, isActive, isOverLight, overLightOpacity ]), gradientIsOverLight = gradientCalculations.isOverLight, gradientMx = gradientCalculations.mx, gradientMy = gradientCalculations.my, gradientBorderGradientAngle = gradientCalculations.borderGradientAngle, gradientBorderStop1 = gradientCalculations.borderStop1, gradientBorderStop2 = gradientCalculations.borderStop2, gradientBorderOpacity1 = gradientCalculations.borderOpacity1, gradientBorderOpacity2 = gradientCalculations.borderOpacity2, gradientBorderOpacity3 = gradientCalculations.borderOpacity3, gradientBorderOpacity4 = gradientCalculations.borderOpacity4, gradientHover1X = gradientCalculations.hover1X, gradientHover1Y = gradientCalculations.hover1Y, gradientHover2X = gradientCalculations.hover2X, gradientHover2Y = gradientCalculations.hover2Y, gradientHover3X = gradientCalculations.hover3X, gradientHover3Y = gradientCalculations.hover3Y, gradientBaseX = gradientCalculations.baseX, gradientBaseY = gradientCalculations.baseY, positionStylesPosition = positionStyles.position, positionStylesTop = positionStyles.top, positionStylesLeft = positionStyles.left, adjustedSizeWidth = adjustedSize.width, adjustedSizeHeight = adjustedSize.height, baseStyleTransform = baseStyle.transform, opacityValuesHover1 = opacityValues.hover1, opacityValuesHover2 = opacityValues.hover2, opacityValuesHover3 = opacityValues.hover3, opacityValuesBase = opacityValues.base, opacityValuesOver = opacityValues.over, glassVars = useMemo((() => {
|
|
2734
|
-
// RGB color values for rgba() functions
|
|
2735
|
-
// Note: CSS doesn't support rgba(var(--rgb), opacity) syntax - this is a CSS specification
|
|
2736
|
-
// limitation, not a browser support issue. We read RGB values from design tokens at mount
|
|
2737
|
-
// and cache them for performance. Falls back to defaults if tokens are not available.
|
|
2738
|
-
// Uses design tokens: --atomix-light-rgb / --atomix-white-rgb and --atomix-dark-rgb / --atomix-black-rgb
|
|
2739
|
-
const whiteColor = rgbCacheRef.current?.whiteRgb || "255, 255, 255", blackColor = rgbCacheRef.current?.blackRgb || "0, 0, 0";
|
|
2740
|
-
return {
|
|
2741
|
-
// Standard CSS custom properties for dynamic values
|
|
2742
|
-
"--atomix-glass-radius": `${effectiveCornerRadius}px`,
|
|
2743
|
-
"--atomix-glass-transform": baseStyleTransform || "none",
|
|
2744
|
-
"--atomix-glass-position": positionStylesPosition,
|
|
2745
|
-
"--atomix-glass-top": "fixed" !== positionStylesTop ? `${positionStylesTop}px` : "0",
|
|
2746
|
-
"--atomix-glass-left": "fixed" !== positionStylesLeft ? `${positionStylesLeft}px` : "0",
|
|
2747
|
-
"--atomix-glass-width": "fixed" !== baseStylePosition ? adjustedSizeWidth : `${adjustedSizeWidth}px`,
|
|
2748
|
-
"--atomix-glass-height": "fixed" !== baseStylePosition ? adjustedSizeHeight : `${adjustedSizeHeight}px`,
|
|
2749
|
-
// Border width: Use spacing token for consistency
|
|
2750
|
-
"--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
|
|
2751
|
-
"--atomix-glass-blend-mode": gradientIsOverLight ? "multiply" : "overlay",
|
|
2752
|
-
// Dynamic gradients and backgrounds
|
|
2753
|
-
// Note: RGB values use design token-aligned constants (white: 255,255,255; black: 0,0,0)
|
|
2754
|
-
"--atomix-glass-border-gradient-1": `linear-gradient(${gradientBorderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${gradientBorderOpacity1}) ${gradientBorderStop1}%, rgba(${whiteColor}, ${gradientBorderOpacity2}) ${gradientBorderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
2755
|
-
"--atomix-glass-border-gradient-2": `linear-gradient(${gradientBorderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${gradientBorderOpacity3}) ${gradientBorderStop1}%, rgba(${whiteColor}, ${gradientBorderOpacity4}) ${gradientBorderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
2756
|
-
"--atomix-glass-hover-1-opacity": opacityValuesHover1,
|
|
2757
|
-
"--atomix-glass-hover-1-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover1X}% ${gradientHover1Y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover1X}% ${gradientHover1Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
|
|
2758
|
-
"--atomix-glass-hover-2-opacity": opacityValuesHover2,
|
|
2759
|
-
"--atomix-glass-hover-2-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover2X}% ${gradientHover2Y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover2X}% ${gradientHover2Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
|
|
2760
|
-
"--atomix-glass-hover-3-opacity": opacityValuesHover3,
|
|
2761
|
-
"--atomix-glass-hover-3-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientHover3X}% ${gradientHover3Y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${gradientHover3X}% ${gradientHover3Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
|
|
2762
|
-
"--atomix-glass-base-opacity": opacityValuesBase,
|
|
2763
|
-
"--atomix-glass-base-gradient": gradientIsOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + gradientMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + gradientMy * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + Math.abs(gradientMx) * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
|
|
2764
|
-
"--atomix-glass-overlay-opacity": opacityValuesOver,
|
|
2765
|
-
"--atomix-glass-overlay-gradient": gradientIsOverLight ? `radial-gradient(circle at ${gradientBaseX}% ${gradientBaseY}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + Math.abs(gradientMx) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + Math.abs(gradientMy) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
|
|
2766
|
-
};
|
|
2767
|
-
}), [
|
|
2768
|
-
// Position styles - only specific properties
|
|
2769
|
-
positionStylesPosition, positionStylesTop, positionStylesLeft,
|
|
2770
|
-
// Adjusted size - only specific properties
|
|
2771
|
-
adjustedSizeWidth, adjustedSizeHeight,
|
|
2772
|
-
// Base style - only transform property
|
|
2773
|
-
baseStyleTransform, baseStylePosition,
|
|
2774
|
-
// Other values
|
|
2775
|
-
effectiveCornerRadius, effectiveReducedMotion,
|
|
2776
|
-
// Gradient calculations - extracted properties
|
|
2777
|
-
gradientIsOverLight, gradientMx, gradientMy, gradientBorderGradientAngle, gradientBorderStop1, gradientBorderStop2, gradientBorderOpacity1, gradientBorderOpacity2, gradientBorderOpacity3, gradientBorderOpacity4, gradientHover1X, gradientHover1Y, gradientHover2X, gradientHover2Y, gradientHover3X, gradientHover3Y, gradientBaseX, gradientBaseY,
|
|
2778
|
-
// Opacity values - extracted properties
|
|
2779
|
-
opacityValuesHover1, opacityValuesHover2, opacityValuesHover3, opacityValuesBase, opacityValuesOver ]);
|
|
2780
|
-
// Build className with state modifiers
|
|
2781
|
-
return jsxs("div", {
|
|
2655
|
+
}, componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveDisableEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = {
|
|
2656
|
+
position: style.position || "absolute",
|
|
2657
|
+
top: style.top || 0,
|
|
2658
|
+
left: style.left || 0
|
|
2659
|
+
}, adjustedSize = {
|
|
2660
|
+
width: "fixed" !== style.position ? "100%" : style.width ? style.width : Math.max(glassSize.width, 0),
|
|
2661
|
+
height: "fixed" !== style.position ? "100%" : style.height ? style.height : Math.max(glassSize.height, 0)
|
|
2662
|
+
}, mx = mouseOffset.x, my = mouseOffset.y, GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), borderOpacity1 = GRADIENT.BORDER_OPACITY.BASE_1 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity2 = GRADIENT.BORDER_OPACITY.BASE_2 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, borderOpacity3 = GRADIENT.BORDER_OPACITY.BASE_3 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, borderOpacity4 = GRADIENT.BORDER_OPACITY.BASE_4 + Math.abs(mx) * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, hover1X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1, hover1Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1, hover2X = GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2, hover2Y = GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2, hover3X = GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3, hover3Y = GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3, baseX = GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER, baseY = GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER, overLightOpacity = overLightConfig.opacity, opacityValues = {
|
|
2663
|
+
hover1: isHovered || isActive ? .5 : 0,
|
|
2664
|
+
hover2: isActive ? .5 : 0,
|
|
2665
|
+
hover3: isHovered ? .4 : isActive ? .8 : 0,
|
|
2666
|
+
base: isOverLight ? overLightOpacity || .4 : 0,
|
|
2667
|
+
over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
|
|
2668
|
+
}, whiteColor = "255, 255, 255", glassVars = {
|
|
2669
|
+
// Standard CSS custom properties for dynamic values
|
|
2670
|
+
"--atomix-glass-radius": `${effectiveCornerRadius}px`,
|
|
2671
|
+
"--atomix-glass-transform": transformStyle || "none",
|
|
2672
|
+
"--atomix-glass-position": positionStyles.position,
|
|
2673
|
+
"--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
|
|
2674
|
+
"--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
|
|
2675
|
+
"--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
|
|
2676
|
+
"--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
|
|
2677
|
+
// Border width: Use spacing token for consistency
|
|
2678
|
+
"--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
|
|
2679
|
+
"--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
|
|
2680
|
+
// Dynamic gradients and backgrounds
|
|
2681
|
+
"--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacity1}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacity2}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
2682
|
+
"--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacity3}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacity4}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
2683
|
+
"--atomix-glass-hover-1-opacity": opacityValues.hover1,
|
|
2684
|
+
"--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hover1X}% ${hover1Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hover1X}% ${hover1Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
|
|
2685
|
+
"--atomix-glass-hover-2-opacity": opacityValues.hover2,
|
|
2686
|
+
"--atomix-glass-hover-2-gradient": isOverLight ? `radial-gradient(circle at ${hover2X}% ${hover2Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hover2X}% ${hover2Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
|
|
2687
|
+
"--atomix-glass-hover-3-opacity": opacityValues.hover3,
|
|
2688
|
+
"--atomix-glass-hover-3-gradient": isOverLight ? `radial-gradient(circle at ${hover3X}% ${hover3Y}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(0, 0, 0, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hover3X}% ${hover3Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
|
|
2689
|
+
"--atomix-glass-base-opacity": opacityValues.base,
|
|
2690
|
+
"--atomix-glass-base-gradient": isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + Math.abs(mx) * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
|
|
2691
|
+
"--atomix-glass-overlay-opacity": opacityValues.over,
|
|
2692
|
+
"--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${baseX}% ${baseY}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + Math.abs(mx) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(0, 0, 0, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + Math.abs(my) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
|
|
2693
|
+
};
|
|
2694
|
+
return jsxs("div", {
|
|
2782
2695
|
className: componentClassName,
|
|
2783
2696
|
style: glassVars,
|
|
2784
2697
|
role: role || (onClick ? "button" : void 0),
|
|
@@ -3642,11 +3555,103 @@ const Spinner = memo((({size: size = "md", variant: variant = "primary", fullsc
|
|
|
3642
3555
|
|
|
3643
3556
|
Spinner.displayName = "Spinner";
|
|
3644
3557
|
|
|
3558
|
+
/**
|
|
3559
|
+
* Theme Naming Utility
|
|
3560
|
+
*
|
|
3561
|
+
* Provides consistent naming conventions for CSS classes, CSS variables,
|
|
3562
|
+
* and JavaScript properties throughout the theme system.
|
|
3563
|
+
*/
|
|
3564
|
+
class ThemeNaming {
|
|
3565
|
+
/**
|
|
3566
|
+
* Set the global prefix for all theme tokens
|
|
3567
|
+
* @param newPrefix - New prefix to use
|
|
3568
|
+
*/
|
|
3569
|
+
static setPrefix(newPrefix) {
|
|
3570
|
+
this.prefix = newPrefix;
|
|
3571
|
+
}
|
|
3572
|
+
/**
|
|
3573
|
+
* Get the current prefix
|
|
3574
|
+
*/ static getPrefix() {
|
|
3575
|
+
return this.prefix;
|
|
3576
|
+
}
|
|
3577
|
+
/**
|
|
3578
|
+
* Convert camelCase to kebab-case for CSS variables
|
|
3579
|
+
* @param str - String to convert
|
|
3580
|
+
*/ static camelToKebab(str) {
|
|
3581
|
+
return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
|
|
3582
|
+
}
|
|
3583
|
+
/**
|
|
3584
|
+
* Convert kebab-case to camelCase for JavaScript properties
|
|
3585
|
+
* @param str - String to convert
|
|
3586
|
+
*/ static kebabToCamel(str) {
|
|
3587
|
+
return str.replace(/-([a-z])/g, (g => g[1].toUpperCase()));
|
|
3588
|
+
}
|
|
3589
|
+
/**
|
|
3590
|
+
* Create a CSS variable name
|
|
3591
|
+
* @param token - Token name in camelCase
|
|
3592
|
+
*/ static cssVar(token) {
|
|
3593
|
+
return `--${this.prefix}-${this.camelToKebab(token)}`;
|
|
3594
|
+
}
|
|
3595
|
+
/**
|
|
3596
|
+
* Create a BEM CSS class name
|
|
3597
|
+
* @param block - Block name
|
|
3598
|
+
* @param element - Element name (optional)
|
|
3599
|
+
* @param modifier - Modifier name (optional)
|
|
3600
|
+
*/ static bemClass(block, element, modifier) {
|
|
3601
|
+
let className = `c-${block}`;
|
|
3602
|
+
return element && (className += `__${element}`), modifier && (className += `--${modifier}`),
|
|
3603
|
+
className;
|
|
3604
|
+
}
|
|
3605
|
+
/**
|
|
3606
|
+
* Create a variant class name
|
|
3607
|
+
* @param component - Component name
|
|
3608
|
+
* @param variant - Variant name
|
|
3609
|
+
*/ static variantClass(component, variant) {
|
|
3610
|
+
return `c-${component}--${variant}`;
|
|
3611
|
+
}
|
|
3612
|
+
/**
|
|
3613
|
+
* Create a size class name
|
|
3614
|
+
* @param component - Component name
|
|
3615
|
+
* @param size - Size name
|
|
3616
|
+
*/ static sizeClass(component, size) {
|
|
3617
|
+
return `c-${component}--${size}`;
|
|
3618
|
+
}
|
|
3619
|
+
/**
|
|
3620
|
+
* Create a state class name
|
|
3621
|
+
* @param component - Component name
|
|
3622
|
+
* @param state - State name
|
|
3623
|
+
*/ static stateClass(component, state) {
|
|
3624
|
+
return `c-${component}--${state}`;
|
|
3625
|
+
}
|
|
3626
|
+
/**
|
|
3627
|
+
* Create a utility class name
|
|
3628
|
+
* @param utility - Utility name
|
|
3629
|
+
*/ static utilityClass(utility) {
|
|
3630
|
+
return `u-${utility}`;
|
|
3631
|
+
}
|
|
3632
|
+
/**
|
|
3633
|
+
* Create a layout class name
|
|
3634
|
+
* @param layout - Layout name
|
|
3635
|
+
*/ static layoutClass(layout) {
|
|
3636
|
+
return `l-${layout}`;
|
|
3637
|
+
}
|
|
3638
|
+
/**
|
|
3639
|
+
* Create an object class name
|
|
3640
|
+
* @param object - Object name
|
|
3641
|
+
*/ static objectClass(object) {
|
|
3642
|
+
return `o-${object}`;
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3646
|
+
ThemeNaming.prefix = "atomix";
|
|
3647
|
+
|
|
3645
3648
|
const Button = React.memo( forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, ariaExpanded: ariaExpanded, ariaControls: ariaControls, tabIndex: tabIndex, style: style, LinkComponent: LinkComponent, ...props}, ref) => {
|
|
3646
|
-
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement =
|
|
3649
|
+
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsx(Icon, {
|
|
3647
3650
|
name: iconName,
|
|
3648
3651
|
size: iconSize
|
|
3649
|
-
}) : icon
|
|
3652
|
+
}) : icon;
|
|
3653
|
+
// Determine if we should render as a link
|
|
3654
|
+
useButton({
|
|
3650
3655
|
variant: variant,
|
|
3651
3656
|
size: size,
|
|
3652
3657
|
disabled: isDisabled,
|
|
@@ -3657,20 +3662,8 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
3657
3662
|
block: block,
|
|
3658
3663
|
active: active,
|
|
3659
3664
|
selected: selected
|
|
3660
|
-
})
|
|
3661
|
-
|
|
3662
|
-
size: size,
|
|
3663
|
-
disabled: isDisabled,
|
|
3664
|
-
rounded: rounded,
|
|
3665
|
-
iconOnly: iconOnly,
|
|
3666
|
-
glass: glass,
|
|
3667
|
-
loading: loading,
|
|
3668
|
-
fullWidth: fullWidth,
|
|
3669
|
-
block: block,
|
|
3670
|
-
active: active,
|
|
3671
|
-
selected: selected,
|
|
3672
|
-
className: className
|
|
3673
|
-
})), [ variant, size, isDisabled, rounded, iconOnly, glass, loading, fullWidth, block, active, selected, className, generateButtonClass ]), handleClickEvent = useCallback((event => {
|
|
3665
|
+
});
|
|
3666
|
+
const buttonClass = [ BUTTON.BASE_CLASS, ThemeNaming.variantClass(THEME_NAMING.BUTTON_PREFIX, variant), "md" !== size ? ThemeNaming.sizeClass(THEME_NAMING.BUTTON_PREFIX, size) : "", iconOnly ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT) : "", rounded ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "rounded") : "", isDisabled ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "disabled") : "", glass ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "glass") : "", loading ? BUTTON.CLASSES.LOADING : "", fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", block ? BUTTON.CLASSES.BLOCK : "", active ? BUTTON.CLASSES.ACTIVE : "", selected ? BUTTON.CLASSES.SELECTED : "", className ].filter(Boolean).join(" "), handleClickEvent = useCallback((event => {
|
|
3674
3667
|
isDisabled ? event.preventDefault() : onClick?.(event);
|
|
3675
3668
|
}), [ isDisabled, onClick ]), handleMouseEnter = useCallback((event => {
|
|
3676
3669
|
isDisabled || onHover?.(event);
|
|
@@ -3678,28 +3671,23 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
3678
3671
|
isDisabled || onFocus?.(event);
|
|
3679
3672
|
}), [ isDisabled, onFocus ]), handleBlurEvent = useCallback((event => {
|
|
3680
3673
|
isDisabled || onBlur?.(event);
|
|
3681
|
-
}), [ isDisabled, onBlur ]), buttonText =
|
|
3682
|
-
|
|
3683
|
-
className:
|
|
3684
|
-
"aria-hidden": "true",
|
|
3685
|
-
children: iconElement
|
|
3686
|
-
}), spinnerElement = loading && jsx("span", {
|
|
3687
|
-
className: BUTTON.SPINNER_CLASS,
|
|
3674
|
+
}), [ isDisabled, onBlur ]), buttonText = loading && loadingText ? loadingText : label || children, spinnerSize = "sm" === size ? "sm" : "lg" === size ? "md" : "sm", buttonContent = jsxs(Fragment, {
|
|
3675
|
+
children: [ loading && jsx("span", {
|
|
3676
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
|
|
3688
3677
|
"aria-hidden": "true",
|
|
3689
3678
|
children: jsx(Spinner, {
|
|
3690
3679
|
size: spinnerSize,
|
|
3691
3680
|
variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
|
|
3692
3681
|
})
|
|
3693
|
-
}),
|
|
3694
|
-
className:
|
|
3682
|
+
}), iconElement && !loading && jsx("span", {
|
|
3683
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
|
|
3684
|
+
"aria-hidden": "true",
|
|
3685
|
+
children: iconElement
|
|
3686
|
+
}), !iconOnly && buttonText && jsx("span", {
|
|
3687
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
|
|
3695
3688
|
children: buttonText
|
|
3696
|
-
})
|
|
3697
|
-
|
|
3698
|
-
children: [ labelElement, spinnerElement, iconSpan ]
|
|
3699
|
-
} : {
|
|
3700
|
-
children: [ spinnerElement, iconSpan, labelElement ]
|
|
3701
|
-
});
|
|
3702
|
-
}), [ iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant ]), buttonProps = useMemo((() => ({
|
|
3689
|
+
}) ]
|
|
3690
|
+
}), buttonProps = {
|
|
3703
3691
|
ref: ref,
|
|
3704
3692
|
className: buttonClass,
|
|
3705
3693
|
type: "button" !== Component || shouldRenderAsLink ? void 0 : type,
|
|
@@ -3717,8 +3705,16 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
3717
3705
|
tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
|
|
3718
3706
|
style: style,
|
|
3719
3707
|
...props
|
|
3720
|
-
}
|
|
3721
|
-
|
|
3708
|
+
}, defaultGlassProps = {
|
|
3709
|
+
displacementScale: 20,
|
|
3710
|
+
blurAmount: 0,
|
|
3711
|
+
saturation: 200,
|
|
3712
|
+
elasticity: 0
|
|
3713
|
+
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3714
|
+
...defaultGlassProps,
|
|
3715
|
+
...glass
|
|
3716
|
+
};
|
|
3717
|
+
// Handle click with loading check
|
|
3722
3718
|
// Render as anchor if href is provided
|
|
3723
3719
|
if (shouldRenderAsLink) {
|
|
3724
3720
|
const {ref: _, ...buttonPropsWithoutRef} = buttonProps, anchorButtonProps = {
|
|
@@ -3738,22 +3734,10 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
3738
3734
|
...linkProps,
|
|
3739
3735
|
children: buttonContent
|
|
3740
3736
|
});
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
saturation: 200,
|
|
3746
|
-
elasticity: 0
|
|
3747
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3748
|
-
...defaultGlassProps,
|
|
3749
|
-
...glass
|
|
3750
|
-
};
|
|
3751
|
-
return jsx(AtomixGlass, {
|
|
3752
|
-
...glassProps,
|
|
3753
|
-
children: linkElement
|
|
3754
|
-
});
|
|
3755
|
-
}
|
|
3756
|
-
return linkElement;
|
|
3737
|
+
return glass ? jsx(AtomixGlass, {
|
|
3738
|
+
...glassProps,
|
|
3739
|
+
children: linkElement
|
|
3740
|
+
}) : linkElement;
|
|
3757
3741
|
}
|
|
3758
3742
|
// Fallback to regular anchor tag
|
|
3759
3743
|
const anchorElement = jsx("a", {
|
|
@@ -3764,46 +3748,20 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
|
|
|
3764
3748
|
rel: "_blank" === target ? "noopener noreferrer" : void 0,
|
|
3765
3749
|
children: buttonContent
|
|
3766
3750
|
});
|
|
3767
|
-
|
|
3768
|
-
const defaultGlassProps = {
|
|
3769
|
-
displacementScale: 20,
|
|
3770
|
-
blurAmount: 0,
|
|
3771
|
-
saturation: 200,
|
|
3772
|
-
elasticity: 0
|
|
3773
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3774
|
-
...defaultGlassProps,
|
|
3775
|
-
...glass
|
|
3776
|
-
};
|
|
3777
|
-
return jsx(AtomixGlass, {
|
|
3778
|
-
...glassProps,
|
|
3779
|
-
children: anchorElement
|
|
3780
|
-
});
|
|
3781
|
-
}
|
|
3782
|
-
return anchorElement;
|
|
3783
|
-
}
|
|
3784
|
-
// Default button rendering
|
|
3785
|
-
if (glass) {
|
|
3786
|
-
const defaultGlassProps = {
|
|
3787
|
-
displacementScale: 20,
|
|
3788
|
-
blurAmount: 0,
|
|
3789
|
-
saturation: 200,
|
|
3790
|
-
elasticity: 0
|
|
3791
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3792
|
-
...defaultGlassProps,
|
|
3793
|
-
...glass
|
|
3794
|
-
};
|
|
3795
|
-
return jsx(AtomixGlass, {
|
|
3751
|
+
return glass ? jsx(AtomixGlass, {
|
|
3796
3752
|
...glassProps,
|
|
3797
|
-
children:
|
|
3798
|
-
|
|
3799
|
-
children: buttonContent
|
|
3800
|
-
})
|
|
3801
|
-
});
|
|
3753
|
+
children: anchorElement
|
|
3754
|
+
}) : anchorElement;
|
|
3802
3755
|
}
|
|
3803
|
-
|
|
3756
|
+
// Default button rendering
|
|
3757
|
+
const buttonElement = jsx(Component, {
|
|
3804
3758
|
...buttonProps,
|
|
3805
3759
|
children: buttonContent
|
|
3806
3760
|
});
|
|
3761
|
+
return glass ? jsx(AtomixGlass, {
|
|
3762
|
+
...glassProps,
|
|
3763
|
+
children: buttonElement
|
|
3764
|
+
}) : buttonElement;
|
|
3807
3765
|
})));
|
|
3808
3766
|
|
|
3809
3767
|
Button.displayName = "Button";
|
|
@@ -11104,62 +11062,6 @@ function useHero(initialProps) {
|
|
|
11104
11062
|
};
|
|
11105
11063
|
}
|
|
11106
11064
|
|
|
11107
|
-
/**
|
|
11108
|
-
* CSS Variable Mapper
|
|
11109
|
-
*
|
|
11110
|
-
* Utilities for generating and managing CSS custom properties from SCSS tokens
|
|
11111
|
-
* and component configurations.
|
|
11112
|
-
*/
|
|
11113
|
-
/**
|
|
11114
|
-
* Generate CSS variable name from parts
|
|
11115
|
-
*
|
|
11116
|
-
* @example
|
|
11117
|
-
* generateCSSVariableName('button', 'bg', { prefix: 'atomix' })
|
|
11118
|
-
* // Returns: '--atomix-button-bg'
|
|
11119
|
-
*/ function generateCSSVariableName(component, property, options = {}) {
|
|
11120
|
-
const {prefix: prefix = "atomix", separator: separator = "-", includeComponent: includeComponent = !0} = options, parts = [ prefix ];
|
|
11121
|
-
return includeComponent && parts.push(component), parts.push(property), `--${parts.join(separator)}`;
|
|
11122
|
-
}
|
|
11123
|
-
|
|
11124
|
-
/**
|
|
11125
|
-
* Generate CSS variables object from configuration
|
|
11126
|
-
*
|
|
11127
|
-
* @example
|
|
11128
|
-
* const vars = generateComponentCSSVars({
|
|
11129
|
-
* component: 'button',
|
|
11130
|
-
* properties: { bg: '#000', color: '#fff' }
|
|
11131
|
-
* })
|
|
11132
|
-
* // Returns: { '--atomix-button-bg': '#000', '--atomix-button-color': '#fff' }
|
|
11133
|
-
*/ function generateComponentCSSVars(config, options = {}) {
|
|
11134
|
-
const vars = {}, {component: component, properties: properties, parts: parts, states: states, variants: variants} = config;
|
|
11135
|
-
// Base properties
|
|
11136
|
-
return Object.entries(properties).forEach((([key, value]) => {
|
|
11137
|
-
const varName = generateCSSVariableName(component, key, options);
|
|
11138
|
-
vars[varName] = String(value);
|
|
11139
|
-
})),
|
|
11140
|
-
// Part properties
|
|
11141
|
-
parts && Object.entries(parts).forEach((([partName, partProps]) => {
|
|
11142
|
-
Object.entries(partProps).forEach((([key, value]) => {
|
|
11143
|
-
const varName = generateCSSVariableName(component, `${partName}-${key}`, options);
|
|
11144
|
-
vars[varName] = String(value);
|
|
11145
|
-
}));
|
|
11146
|
-
})),
|
|
11147
|
-
// State properties
|
|
11148
|
-
states && Object.entries(states).forEach((([stateName, stateProps]) => {
|
|
11149
|
-
Object.entries(stateProps).forEach((([key, value]) => {
|
|
11150
|
-
const varName = generateCSSVariableName(component, `${stateName}-${key}`, options);
|
|
11151
|
-
vars[varName] = String(value);
|
|
11152
|
-
}));
|
|
11153
|
-
})),
|
|
11154
|
-
// Variant properties
|
|
11155
|
-
variants && Object.entries(variants).forEach((([variantName, variantProps]) => {
|
|
11156
|
-
Object.entries(variantProps).forEach((([key, value]) => {
|
|
11157
|
-
const varName = generateCSSVariableName(component, `${variantName}-${key}`, options);
|
|
11158
|
-
vars[varName] = String(value);
|
|
11159
|
-
}));
|
|
11160
|
-
})), vars;
|
|
11161
|
-
}
|
|
11162
|
-
|
|
11163
11065
|
/**
|
|
11164
11066
|
* Map SCSS tokens to CSS custom properties
|
|
11165
11067
|
*
|
|
@@ -11322,7 +11224,7 @@ function mergeComponentProps(baseProps, customization) {
|
|
|
11322
11224
|
/**
|
|
11323
11225
|
* Create data attributes for debugging
|
|
11324
11226
|
*/ function createDebugAttrs(componentName, variant) {
|
|
11325
|
-
return "development" !== process.env
|
|
11227
|
+
return "undefined" == typeof process || "development" !== process.env?.NODE_ENV ? {} : {
|
|
11326
11228
|
"data-component": componentName,
|
|
11327
11229
|
...variant && {
|
|
11328
11230
|
"data-variant": variant
|
|
@@ -18180,6 +18082,7 @@ const components = Object.freeze( Object.defineProperty({
|
|
|
18180
18082
|
TESTIMONIAL: TESTIMONIAL,
|
|
18181
18083
|
TEXTAREA: TEXTAREA,
|
|
18182
18084
|
THEME_COLORS: THEME_COLORS,
|
|
18085
|
+
THEME_NAMING: THEME_NAMING,
|
|
18183
18086
|
TODO: TODO,
|
|
18184
18087
|
TOGGLE: TOGGLE,
|
|
18185
18088
|
TOOLTIP: TOOLTIP,
|
|
@@ -18652,13 +18555,6 @@ function createTokens(overrides) {
|
|
|
18652
18555
|
* @param coefficient - Amount to emphasize (0-1), default 0.15
|
|
18653
18556
|
* @returns Emphasized hex color
|
|
18654
18557
|
*/
|
|
18655
|
-
/**
|
|
18656
|
-
* Check if a theme is a JS theme (created with createTheme)
|
|
18657
|
-
*/
|
|
18658
|
-
function isJSTheme(theme) {
|
|
18659
|
-
return theme && "object" == typeof theme && !0 === theme.__isJSTheme;
|
|
18660
|
-
}
|
|
18661
|
-
|
|
18662
18558
|
/**
|
|
18663
18559
|
* Theme Adapter
|
|
18664
18560
|
*
|
|
@@ -18678,7 +18574,8 @@ function isJSTheme(theme) {
|
|
|
18678
18574
|
* const tokens = themeToDesignTokens(theme);
|
|
18679
18575
|
* // Returns: { 'primary': '#7c3aed', ... }
|
|
18680
18576
|
* ```
|
|
18681
|
-
*/
|
|
18577
|
+
*/
|
|
18578
|
+
function themeToDesignTokens(theme) {
|
|
18682
18579
|
const tokens = {};
|
|
18683
18580
|
// Convert palette colors
|
|
18684
18581
|
if (theme.palette) {
|
|
@@ -18818,158 +18715,10 @@ function isJSTheme(theme) {
|
|
|
18818
18715
|
};
|
|
18819
18716
|
}
|
|
18820
18717
|
|
|
18821
|
-
/**
|
|
18822
|
-
* Config Loader
|
|
18823
|
-
*
|
|
18824
|
-
* Load design tokens from atomix.config.ts and convert to flat token format.
|
|
18825
|
-
*/
|
|
18826
|
-
/**
|
|
18827
|
-
* Convert nested config tokens to flat DesignTokens format
|
|
18828
|
-
*
|
|
18829
|
-
* Handles conversion from atomix.config.ts structure to flat tokens.
|
|
18830
|
-
* Maps config structure to actual DesignTokens key names.
|
|
18831
|
-
*/ function flattenConfigTokens(tokens, prefix = "atomix") {
|
|
18832
|
-
const flat = {};
|
|
18833
|
-
// Colors
|
|
18834
|
-
return tokens.colors && Object.entries(tokens.colors).forEach((([key, value]) => {
|
|
18835
|
-
var _context;
|
|
18836
|
-
// Simple color: 'primary': '#7AFFD7'
|
|
18837
|
-
// Map directly to DesignTokens keys (e.g., 'primary', 'secondary', 'error')
|
|
18838
|
-
// Only map if it's a valid semantic color key
|
|
18839
|
-
if ("string" == typeof value) _includesInstanceProperty(_context = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context, key) && (flat[key] = value); else if (value && "object" == typeof value)
|
|
18840
|
-
// Color scale or palette
|
|
18841
|
-
if ("main" in value) {
|
|
18842
|
-
var _context2;
|
|
18843
|
-
// PaletteColorOptions: { main: '#7AFFD7', light?: '#...', dark?: '#...' }
|
|
18844
|
-
const palette = value, baseKey = key;
|
|
18845
|
-
// Map main to base color (e.g., primary, secondary, error)
|
|
18846
|
-
_includesInstanceProperty(_context2 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context2, key) && (flat[baseKey] = palette.main,
|
|
18847
|
-
// Map light/dark to appropriate scale values
|
|
18848
|
-
// light typically maps to step 3, dark to step 9
|
|
18849
|
-
palette.light && (flat[`${key}-3`] = palette.light), palette.dark && (flat[`${key}-9`] = palette.dark));
|
|
18850
|
-
} else
|
|
18851
|
-
// Color scale: { 1: '#fff', 2: '#eee', ..., 6: '#main', ... }
|
|
18852
|
-
// Or full scale: { 1: '#...', 2: '#...', ..., 10: '#...' }
|
|
18853
|
-
Object.entries(value).forEach((([scaleKey, scaleValue]) => {
|
|
18854
|
-
if ("string" == typeof scaleValue)
|
|
18855
|
-
// Map scale keys to DesignTokens format
|
|
18856
|
-
if ("main" === scaleKey || "6" === scaleKey) {
|
|
18857
|
-
var _context3, _context4;
|
|
18858
|
-
// Main color maps to base key (e.g., 'primary')
|
|
18859
|
-
_includesInstanceProperty(_context3 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context3, key) && (flat[key] = scaleValue),
|
|
18860
|
-
// Also map to step 6 if it's a scale color
|
|
18861
|
-
_includesInstanceProperty(_context4 = [ "primary", "red", "green", "blue", "yellow", "gray" ]).call(_context4, key) && (flat[`${key}-6`] = scaleValue);
|
|
18862
|
-
} else {
|
|
18863
|
-
// Map scale numbers (1-10) to DesignTokens format
|
|
18864
|
-
const scaleNum = parseInt(scaleKey, 10);
|
|
18865
|
-
!isNaN(scaleNum) && scaleNum >= 1 && scaleNum <= 10 && (flat[`${key}-${scaleKey}`] = scaleValue);
|
|
18866
|
-
}
|
|
18867
|
-
}));
|
|
18868
|
-
})),
|
|
18869
|
-
// Spacing
|
|
18870
|
-
tokens.spacing && Object.entries(tokens.spacing).forEach((([key, value]) => {
|
|
18871
|
-
flat[`spacing-${key}`] = String(value);
|
|
18872
|
-
})),
|
|
18873
|
-
// Border Radius
|
|
18874
|
-
tokens.borderRadius && Object.entries(tokens.borderRadius).forEach((([key, value]) => {
|
|
18875
|
-
// Map to DesignTokens format
|
|
18876
|
-
"sm" === key || "base" === key || "" === key ? flat["border-radius-sm"] = String(value) : "md" === key || "default" === key ? flat["border-radius"] = String(value) : "lg" === key ? flat["border-radius-lg"] = String(value) : flat[`border-radius-${key}`] = String(value);
|
|
18877
|
-
})),
|
|
18878
|
-
// Typography
|
|
18879
|
-
tokens.typography && (
|
|
18880
|
-
// Font Families
|
|
18881
|
-
tokens.typography.fontFamilies && Object.entries(tokens.typography.fontFamilies).forEach((([key, value]) => {
|
|
18882
|
-
// Map to DesignTokens format
|
|
18883
|
-
"sans" === key || "base" === key ? (flat["font-sans-serif"] = String(value), flat["body-font-family"] = String(value)) : "mono" === key ? flat["font-monospace"] = String(value) : flat[`font-family-${key}`] = String(value);
|
|
18884
|
-
})),
|
|
18885
|
-
// Font Sizes
|
|
18886
|
-
tokens.typography.fontSizes && Object.entries(tokens.typography.fontSizes).forEach((([key, value]) => {
|
|
18887
|
-
flat[`font-size-${key}`] = String(value);
|
|
18888
|
-
})),
|
|
18889
|
-
// Font Weights
|
|
18890
|
-
tokens.typography.fontWeights && Object.entries(tokens.typography.fontWeights).forEach((([key, value]) => {
|
|
18891
|
-
flat[`font-weight-${key}`] = String(value);
|
|
18892
|
-
})),
|
|
18893
|
-
// Line Heights
|
|
18894
|
-
tokens.typography.lineHeights && Object.entries(tokens.typography.lineHeights).forEach((([key, value]) => {
|
|
18895
|
-
"base" === key || "default" === key ? flat["line-height-base"] = String(value) : flat[`line-height-${key}`] = String(value);
|
|
18896
|
-
}))),
|
|
18897
|
-
// Shadows
|
|
18898
|
-
tokens.shadows && Object.entries(tokens.shadows).forEach((([key, value]) => {
|
|
18899
|
-
flat[`shadow-${key}`] = String(value);
|
|
18900
|
-
})),
|
|
18901
|
-
// Z-Index
|
|
18902
|
-
tokens.zIndex && Object.entries(tokens.zIndex).forEach((([key, value]) => {
|
|
18903
|
-
flat[`z-index-${key}`] = String(value);
|
|
18904
|
-
})),
|
|
18905
|
-
// Transitions
|
|
18906
|
-
tokens.transitions && tokens.transitions.durations && Object.entries(tokens.transitions.durations).forEach((([key, value]) => {
|
|
18907
|
-
flat[`transition-${key}`] = String(value);
|
|
18908
|
-
})), flat;
|
|
18909
|
-
}
|
|
18910
|
-
|
|
18911
|
-
/**
|
|
18912
|
-
* Load theme tokens from atomix.config.ts
|
|
18913
|
-
*
|
|
18914
|
-
* Loads atomix.config.ts and extracts theme tokens.
|
|
18915
|
-
* Config file is required - throws error if not found.
|
|
18916
|
-
*
|
|
18917
|
-
* @param configPath - Optional custom config path (default: 'atomix.config.ts')
|
|
18918
|
-
* @returns Partial DesignTokens from config
|
|
18919
|
-
* @throws Error if config file is not found or cannot be loaded
|
|
18920
|
-
*
|
|
18921
|
-
* @example
|
|
18922
|
-
* ```typescript
|
|
18923
|
-
* const tokens = await loadThemeFromConfig();
|
|
18924
|
-
* const css = createTheme(tokens);
|
|
18925
|
-
* injectTheme(css);
|
|
18926
|
-
* ```
|
|
18927
|
-
*/ async function loadThemeFromConfig(configPath = "atomix.config.ts") {
|
|
18928
|
-
// In browser environments, config loading is not supported
|
|
18929
|
-
if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
18930
|
-
// Load config using the existing loader (required)
|
|
18931
|
-
const {loadAtomixConfig: loadAtomixConfig} = await Promise.resolve().then((() => loader)), config = loadAtomixConfig({
|
|
18932
|
-
configPath: configPath,
|
|
18933
|
-
required: !0
|
|
18934
|
-
});
|
|
18935
|
-
if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
|
|
18936
|
-
// Extract tokens from config
|
|
18937
|
-
const tokens = config.theme.tokens || config.theme.extend || {};
|
|
18938
|
-
if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
|
|
18939
|
-
// Convert nested structure to flat tokens
|
|
18940
|
-
return flattenConfigTokens(tokens, config.prefix || "atomix");
|
|
18941
|
-
}
|
|
18942
|
-
|
|
18943
|
-
/**
|
|
18944
|
-
* Load theme tokens from atomix.config.ts (synchronous version)
|
|
18945
|
-
*
|
|
18946
|
-
* Synchronous version that uses require() instead of dynamic import.
|
|
18947
|
-
* Only works in Node.js environment.
|
|
18948
|
-
* Config file is required - throws error if not found.
|
|
18949
|
-
*
|
|
18950
|
-
* @param configPath - Optional custom config path
|
|
18951
|
-
* @returns Partial DesignTokens from config
|
|
18952
|
-
* @throws Error if config file is not found or cannot be loaded
|
|
18953
|
-
*/ function loadThemeFromConfigSync(configPath = "atomix.config.ts") {
|
|
18954
|
-
// In browser environments, config loading is not supported
|
|
18955
|
-
if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
18956
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
18957
|
-
const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
|
|
18958
|
-
configPath: configPath,
|
|
18959
|
-
required: !0
|
|
18960
|
-
});
|
|
18961
|
-
if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
|
|
18962
|
-
// Extract tokens from config
|
|
18963
|
-
const tokens = config.theme.tokens || config.theme.extend || {};
|
|
18964
|
-
if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
|
|
18965
|
-
// Convert nested structure to flat tokens
|
|
18966
|
-
return flattenConfigTokens(tokens, config.prefix || "atomix");
|
|
18967
|
-
}
|
|
18968
|
-
|
|
18969
18718
|
/**
|
|
18970
18719
|
* Core Theme Functions
|
|
18971
18720
|
*
|
|
18972
|
-
*
|
|
18721
|
+
* Simplified theme system that handles both DesignTokens and Theme objects.
|
|
18973
18722
|
* Config-first approach: loads from atomix.config.ts when no input is provided.
|
|
18974
18723
|
* Config file is required for automatic loading.
|
|
18975
18724
|
*/
|
|
@@ -19003,43 +18752,68 @@ function isJSTheme(theme) {
|
|
|
19003
18752
|
* const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
|
|
19004
18753
|
* ```
|
|
19005
18754
|
*/ function createTheme(input, options) {
|
|
19006
|
-
|
|
19007
|
-
|
|
18755
|
+
// Determine tokens based on input
|
|
18756
|
+
let tokens;
|
|
19008
18757
|
if (input)
|
|
19009
|
-
//
|
|
19010
|
-
tokens =
|
|
19011
|
-
|
|
19012
|
-
|
|
19013
|
-
|
|
19014
|
-
|
|
19015
|
-
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
|
|
19019
|
-
|
|
18758
|
+
// Use DesignTokens directly
|
|
18759
|
+
tokens =
|
|
18760
|
+
// Helper functions to simplify main function
|
|
18761
|
+
function(input) {
|
|
18762
|
+
return !0 === input?.__isJSTheme || input?.palette && input?.typography;
|
|
18763
|
+
}
|
|
18764
|
+
/**
|
|
18765
|
+
* Theme Composition Utilities
|
|
18766
|
+
*
|
|
18767
|
+
* Simplified utilities for composing, merging, and extending themes.
|
|
18768
|
+
*/
|
|
18769
|
+
// ============================================================================
|
|
18770
|
+
// Deep Merge Utility
|
|
18771
|
+
// ============================================================================
|
|
18772
|
+
/**
|
|
18773
|
+
* Check if value is an object
|
|
18774
|
+
*/ (input) ? themeToDesignTokens(input) : input;
|
|
18775
|
+
// Merge with defaults and generate CSS
|
|
18776
|
+
else {
|
|
18777
|
+
// Check if we're in a browser environment
|
|
18778
|
+
if ("undefined" != typeof window) throw new Error("createTheme: No input provided and config loading is not available in browser environment. Please provide tokens explicitly or use Node.js/SSR environment.");
|
|
18779
|
+
// Load from config when no input provided
|
|
18780
|
+
// Using dynamic import in a way that's more compatible with bundlers
|
|
18781
|
+
let loadThemeFromConfigSync, loadAtomixConfig;
|
|
18782
|
+
try {
|
|
18783
|
+
// Use dynamic require but only in Node.js environments
|
|
18784
|
+
// This approach allows bundlers to properly handle external dependencies
|
|
18785
|
+
const configLoaderModule = require("../config/configLoader"), loaderModule = require("../../config/loader");
|
|
18786
|
+
// Get prefix from config if needed
|
|
18787
|
+
if (loadThemeFromConfigSync = configLoaderModule.loadThemeFromConfigSync, loadAtomixConfig = loaderModule.loadAtomixConfig,
|
|
18788
|
+
tokens = loadThemeFromConfigSync(), !options?.prefix) try {
|
|
18789
|
+
const config = loadAtomixConfig({
|
|
18790
|
+
configPath: "atomix.config.ts",
|
|
18791
|
+
required: !1
|
|
18792
|
+
});
|
|
18793
|
+
options = {
|
|
18794
|
+
...options,
|
|
18795
|
+
prefix: config?.prefix || "atomix"
|
|
18796
|
+
};
|
|
18797
|
+
} catch (error) {
|
|
18798
|
+
// If config loading fails, use default prefix
|
|
18799
|
+
options = {
|
|
18800
|
+
...options,
|
|
18801
|
+
prefix: "atomix"
|
|
18802
|
+
};
|
|
18803
|
+
}
|
|
19020
18804
|
} catch (error) {
|
|
19021
|
-
|
|
18805
|
+
throw new Error("createTheme: No input provided and config loading is not available in this environment. Please provide tokens explicitly.");
|
|
19022
18806
|
}
|
|
19023
|
-
tokens = configTokens;
|
|
19024
18807
|
}
|
|
19025
|
-
|
|
19026
|
-
|
|
18808
|
+
const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
|
|
18809
|
+
// Get prefix from options or use default
|
|
18810
|
+
return generateCSSVariables$1(allTokens, {
|
|
19027
18811
|
...options,
|
|
19028
|
-
prefix:
|
|
18812
|
+
prefix: prefix
|
|
19029
18813
|
});
|
|
19030
18814
|
}
|
|
19031
18815
|
|
|
19032
|
-
|
|
19033
|
-
* Theme Composition Utilities
|
|
19034
|
-
*
|
|
19035
|
-
* Utilities for composing, merging, and extending themes.
|
|
19036
|
-
*/
|
|
19037
|
-
// ============================================================================
|
|
19038
|
-
// Deep Merge Utility
|
|
19039
|
-
// ============================================================================
|
|
19040
|
-
/**
|
|
19041
|
-
* Check if value is an object
|
|
19042
|
-
*/ function isObject(item) {
|
|
18816
|
+
function isObject(item) {
|
|
19043
18817
|
return item && "object" == typeof item && !Array.isArray(item) && "function" != typeof item;
|
|
19044
18818
|
}
|
|
19045
18819
|
|
|
@@ -19098,65 +18872,14 @@ function isJSTheme(theme) {
|
|
|
19098
18872
|
* });
|
|
19099
18873
|
* ```
|
|
19100
18874
|
*/ function extendTheme(baseTheme, extension) {
|
|
19101
|
-
|
|
19102
|
-
|
|
19103
|
-
|
|
19104
|
-
* Extract theme options from a complete Theme object
|
|
19105
|
-
*/
|
|
19106
|
-
function(theme) {
|
|
19107
|
-
return {
|
|
19108
|
-
name: theme.name,
|
|
19109
|
-
class: theme.class,
|
|
19110
|
-
description: theme.description,
|
|
19111
|
-
author: theme.author,
|
|
19112
|
-
version: theme.version,
|
|
19113
|
-
tags: theme.tags,
|
|
19114
|
-
supportsDarkMode: theme.supportsDarkMode,
|
|
19115
|
-
status: theme.status,
|
|
19116
|
-
a11y: theme.a11y,
|
|
19117
|
-
color: theme.color,
|
|
19118
|
-
features: theme.features,
|
|
19119
|
-
dependencies: theme.dependencies,
|
|
19120
|
-
palette: {
|
|
19121
|
-
primary: theme.palette.primary,
|
|
19122
|
-
secondary: theme.palette.secondary,
|
|
19123
|
-
error: theme.palette.error,
|
|
19124
|
-
warning: theme.palette.warning,
|
|
19125
|
-
info: theme.palette.info,
|
|
19126
|
-
success: theme.palette.success,
|
|
19127
|
-
background: theme.palette.background,
|
|
19128
|
-
text: theme.palette.text
|
|
19129
|
-
},
|
|
19130
|
-
typography: {
|
|
19131
|
-
fontFamily: theme.typography.fontFamily,
|
|
19132
|
-
fontSize: theme.typography.fontSize,
|
|
19133
|
-
fontWeightLight: theme.typography.fontWeightLight,
|
|
19134
|
-
fontWeightRegular: theme.typography.fontWeightRegular,
|
|
19135
|
-
fontWeightMedium: theme.typography.fontWeightMedium,
|
|
19136
|
-
fontWeightSemiBold: theme.typography.fontWeightSemiBold,
|
|
19137
|
-
fontWeightBold: theme.typography.fontWeightBold,
|
|
19138
|
-
h1: theme.typography.h1,
|
|
19139
|
-
h2: theme.typography.h2,
|
|
19140
|
-
h3: theme.typography.h3,
|
|
19141
|
-
h4: theme.typography.h4,
|
|
19142
|
-
h5: theme.typography.h5,
|
|
19143
|
-
h6: theme.typography.h6,
|
|
19144
|
-
body1: theme.typography.body1,
|
|
19145
|
-
body2: theme.typography.body2
|
|
19146
|
-
},
|
|
19147
|
-
shadows: theme.shadows,
|
|
19148
|
-
transitions: theme.transitions,
|
|
19149
|
-
zIndex: theme.zIndex,
|
|
19150
|
-
custom: theme.custom
|
|
19151
|
-
};
|
|
19152
|
-
}
|
|
19153
|
-
// ============================================================================
|
|
19154
|
-
// Default Theme Values
|
|
19155
|
-
// ============================================================================
|
|
19156
|
-
(baseTheme) : baseTheme;
|
|
19157
|
-
return createThemeObject(mergeTheme(baseOptions, extension));
|
|
18875
|
+
return createThemeObject(mergeTheme(baseTheme.__isJSTheme ? {
|
|
18876
|
+
...baseTheme
|
|
18877
|
+
} : baseTheme, extension));
|
|
19158
18878
|
}
|
|
19159
18879
|
|
|
18880
|
+
// ============================================================================
|
|
18881
|
+
// Default Theme Values
|
|
18882
|
+
// ============================================================================
|
|
19160
18883
|
const DEFAULT_PALETTE = {
|
|
19161
18884
|
primary: {
|
|
19162
18885
|
main: "#7c3aed",
|
|
@@ -19418,7 +19141,10 @@ function createThemeObject(...options) {
|
|
|
19418
19141
|
"number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
|
|
19419
19142
|
// If it's an array, use it as a scale
|
|
19420
19143
|
Array.isArray(spacingInput) ? (...values) => 0 === values.length ? "0px" : values.map((value => `${spacingInput[value] || value}px`)).join(" ") : (...values) => 0 === values.length ? "0px" : values.map((value => 4 * value + "px")).join(" ");
|
|
19421
|
-
}
|
|
19144
|
+
}
|
|
19145
|
+
/**
|
|
19146
|
+
* Check if a theme is a JS theme (created with createTheme)
|
|
19147
|
+
*/ (mergedOptions.spacing), breakpoints = function(breakpointsInput) {
|
|
19422
19148
|
const values = {
|
|
19423
19149
|
xs: 0,
|
|
19424
19150
|
sm: 576,
|
|
@@ -19478,694 +19204,71 @@ function createThemeObject(...options) {
|
|
|
19478
19204
|
}
|
|
19479
19205
|
|
|
19480
19206
|
/**
|
|
19481
|
-
*
|
|
19482
|
-
|
|
19483
|
-
|
|
19484
|
-
|
|
19207
|
+
* Create a new theme registry
|
|
19208
|
+
*/ function createThemeRegistry() {
|
|
19209
|
+
return {};
|
|
19210
|
+
}
|
|
19211
|
+
|
|
19485
19212
|
/**
|
|
19486
|
-
*
|
|
19487
|
-
*
|
|
19488
|
-
* @param
|
|
19489
|
-
* @
|
|
19490
|
-
*/
|
|
19213
|
+
* Register a theme
|
|
19214
|
+
* @param registry - Theme registry object
|
|
19215
|
+
* @param id - Theme identifier
|
|
19216
|
+
* @param metadata - Theme metadata
|
|
19217
|
+
*/ function registerTheme(registry, id, metadata) {
|
|
19218
|
+
registry[id] = metadata;
|
|
19219
|
+
}
|
|
19220
|
+
|
|
19491
19221
|
/**
|
|
19492
|
-
*
|
|
19493
|
-
|
|
19494
|
-
|
|
19495
|
-
|
|
19496
|
-
|
|
19497
|
-
|
|
19498
|
-
return {
|
|
19499
|
-
valid: 0 === errors.length,
|
|
19500
|
-
errors: errors,
|
|
19501
|
-
warnings: []
|
|
19502
|
-
};
|
|
19222
|
+
* Unregister a theme
|
|
19223
|
+
* @param registry - Theme registry object
|
|
19224
|
+
* @param id - Theme identifier
|
|
19225
|
+
*/ function unregisterTheme(registry, id) {
|
|
19226
|
+
const exists = id in registry;
|
|
19227
|
+
return delete registry[id], exists;
|
|
19503
19228
|
}
|
|
19504
19229
|
|
|
19505
19230
|
/**
|
|
19506
|
-
*
|
|
19507
|
-
|
|
19508
|
-
|
|
19509
|
-
|
|
19510
|
-
return
|
|
19511
|
-
{
|
|
19512
|
-
valid: 0 === errors.length,
|
|
19513
|
-
errors: errors,
|
|
19514
|
-
warnings: []
|
|
19515
|
-
};
|
|
19231
|
+
* Check if a theme is registered
|
|
19232
|
+
* @param registry - Theme registry object
|
|
19233
|
+
* @param id - Theme identifier
|
|
19234
|
+
*/ function hasTheme(registry, id) {
|
|
19235
|
+
return id in registry;
|
|
19516
19236
|
}
|
|
19517
19237
|
|
|
19518
19238
|
/**
|
|
19519
|
-
*
|
|
19520
|
-
|
|
19239
|
+
* Get theme metadata
|
|
19240
|
+
* @param registry - Theme registry object
|
|
19241
|
+
* @param id - Theme identifier
|
|
19242
|
+
*/ function getTheme(registry, id) {
|
|
19243
|
+
return registry[id];
|
|
19244
|
+
}
|
|
19245
|
+
|
|
19521
19246
|
/**
|
|
19522
|
-
*
|
|
19523
|
-
*
|
|
19524
|
-
|
|
19525
|
-
|
|
19526
|
-
*/
|
|
19527
|
-
/**
|
|
19528
|
-
* Theme error codes
|
|
19529
|
-
*/
|
|
19530
|
-
var ThemeErrorCode, LogLevel;
|
|
19531
|
-
|
|
19532
|
-
!function(ThemeErrorCode) {
|
|
19533
|
-
/** Theme not found in registry */
|
|
19534
|
-
ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
|
|
19535
|
-
/** Theme failed to load */
|
|
19536
|
-
ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
|
|
19537
|
-
/** Theme validation failed */
|
|
19538
|
-
ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
|
|
19539
|
-
/** Configuration loading failed */
|
|
19540
|
-
ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
|
|
19541
|
-
/** Configuration validation failed */
|
|
19542
|
-
ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
|
|
19543
|
-
/** Circular dependency detected */
|
|
19544
|
-
ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
|
|
19545
|
-
/** Missing dependency */
|
|
19546
|
-
ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
|
|
19547
|
-
/** Storage operation failed */
|
|
19548
|
-
ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
|
|
19549
|
-
/** Invalid theme name */
|
|
19550
|
-
ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
|
|
19551
|
-
/** CSS injection failed */
|
|
19552
|
-
ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
|
|
19553
|
-
/** Unknown error */
|
|
19554
|
-
ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
|
19555
|
-
}(ThemeErrorCode || (ThemeErrorCode = {}));
|
|
19556
|
-
|
|
19557
|
-
/**
|
|
19558
|
-
* Custom error class for theme-related errors
|
|
19559
|
-
*/
|
|
19560
|
-
class ThemeError extends Error {
|
|
19561
|
-
constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
|
|
19562
|
-
super(message), this.name = "ThemeError", this.code = code, this.context = context,
|
|
19563
|
-
this.timestamp = Date.now(),
|
|
19564
|
-
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
19565
|
-
Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
|
|
19566
|
-
}
|
|
19567
|
-
/**
|
|
19568
|
-
* Convert error to JSON for logging
|
|
19569
|
-
*/ toJSON() {
|
|
19570
|
-
return {
|
|
19571
|
-
name: this.name,
|
|
19572
|
-
message: this.message,
|
|
19573
|
-
code: this.code,
|
|
19574
|
-
context: this.context,
|
|
19575
|
-
timestamp: this.timestamp,
|
|
19576
|
-
stack: this.stack
|
|
19577
|
-
};
|
|
19578
|
-
}
|
|
19247
|
+
* Get all registered theme metadata
|
|
19248
|
+
* @param registry - Theme registry object
|
|
19249
|
+
*/ function getAllThemes(registry) {
|
|
19250
|
+
return Object.values(registry);
|
|
19579
19251
|
}
|
|
19580
19252
|
|
|
19581
19253
|
/**
|
|
19582
|
-
*
|
|
19583
|
-
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
}(LogLevel || (LogLevel = {}));
|
|
19587
|
-
|
|
19588
|
-
/**
|
|
19589
|
-
* Theme Logger
|
|
19590
|
-
*
|
|
19591
|
-
* Centralized logging for the theme system.
|
|
19592
|
-
* Replaces console statements with structured logging.
|
|
19593
|
-
*/
|
|
19594
|
-
class ThemeLogger {
|
|
19595
|
-
constructor(config = {}) {
|
|
19596
|
-
this.config = {
|
|
19597
|
-
level: config.level ?? ("production" === process.env.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
|
|
19598
|
-
enableConsole: config.enableConsole ?? !0,
|
|
19599
|
-
onError: config.onError,
|
|
19600
|
-
onWarn: config.onWarn,
|
|
19601
|
-
onInfo: config.onInfo,
|
|
19602
|
-
onDebug: config.onDebug
|
|
19603
|
-
};
|
|
19604
|
-
}
|
|
19605
|
-
/**
|
|
19606
|
-
* Log an error
|
|
19607
|
-
*/ error(message, error, context) {
|
|
19608
|
-
if (this.config.level < LogLevel.ERROR) return;
|
|
19609
|
-
const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
|
|
19610
|
-
this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
|
|
19611
|
-
error: errorObj,
|
|
19612
|
-
context: {
|
|
19613
|
-
...context,
|
|
19614
|
-
...themeError.context
|
|
19615
|
-
},
|
|
19616
|
-
code: themeError.code
|
|
19617
|
-
}), this.config.onError?.(themeError, context);
|
|
19618
|
-
}
|
|
19619
|
-
/**
|
|
19620
|
-
* Log a warning
|
|
19621
|
-
*/ warn(message, context) {
|
|
19622
|
-
this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
|
|
19623
|
-
this.config.onWarn?.(message, context));
|
|
19624
|
-
}
|
|
19625
|
-
/**
|
|
19626
|
-
* Log an info message
|
|
19627
|
-
*/ info(message, context) {
|
|
19628
|
-
this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
|
|
19629
|
-
this.config.onInfo?.(message, context));
|
|
19630
|
-
}
|
|
19631
|
-
/**
|
|
19632
|
-
* Log a debug message
|
|
19633
|
-
*/ debug(message, context) {
|
|
19634
|
-
this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
|
|
19635
|
-
}
|
|
19254
|
+
* Get all registered theme IDs
|
|
19255
|
+
* @param registry - Theme registry object
|
|
19256
|
+
*/ function getThemeIds(registry) {
|
|
19257
|
+
return Object.keys(registry);
|
|
19636
19258
|
}
|
|
19637
19259
|
|
|
19638
19260
|
/**
|
|
19639
|
-
*
|
|
19640
|
-
|
|
19641
|
-
|
|
19642
|
-
|
|
19643
|
-
* Get or create default logger
|
|
19644
|
-
*/ function getLogger() {
|
|
19645
|
-
return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
|
|
19261
|
+
* Clear all registered themes
|
|
19262
|
+
* @param registry - Theme registry object
|
|
19263
|
+
*/ function clearThemes(registry) {
|
|
19264
|
+
Object.keys(registry).forEach((key => delete registry[key]));
|
|
19646
19265
|
}
|
|
19647
19266
|
|
|
19648
19267
|
/**
|
|
19649
|
-
*
|
|
19650
|
-
*
|
|
19651
|
-
|
|
19652
|
-
|
|
19653
|
-
/**
|
|
19654
|
-
* Default storage key for theme persistence
|
|
19655
|
-
*/ const DEFAULT_ATOMIX_CONFIG_PATH = "atomix.config.ts";
|
|
19656
|
-
|
|
19657
|
-
/**
|
|
19658
|
-
* Default data attribute name for theme
|
|
19659
|
-
*/ process.env.NODE_ENV;
|
|
19660
|
-
|
|
19661
|
-
/**
|
|
19662
|
-
* Integration default class names
|
|
19663
|
-
*/
|
|
19664
|
-
const DEFAULT_INTEGRATION_CLASS_NAMES = {
|
|
19665
|
-
theme: "data-theme",
|
|
19666
|
-
colorMode: "data-atomix-color-mode"
|
|
19667
|
-
}, DEFAULT_INTEGRATION_CSS_VARIABLES = {
|
|
19668
|
-
colorMode: "--storybook-color-mode"
|
|
19669
|
-
}, DEFAULT_SASS_CONFIG = {
|
|
19670
|
-
style: "expanded",
|
|
19671
|
-
sourceMap: !0,
|
|
19672
|
-
loadPaths: [ "src" ]
|
|
19673
|
-
};
|
|
19674
|
-
|
|
19675
|
-
/**
|
|
19676
|
-
* Integration default CSS variables
|
|
19677
|
-
*/
|
|
19678
|
-
/**
|
|
19679
|
-
* Theme Configuration Loader
|
|
19680
|
-
*
|
|
19681
|
-
* Loads and validates the theme configuration from atomix.config.ts
|
|
19682
|
-
*/
|
|
19683
|
-
/**
|
|
19684
|
-
* Cache for loaded configuration
|
|
19685
|
-
*/
|
|
19686
|
-
let cachedConfig = null;
|
|
19687
|
-
|
|
19688
|
-
/**
|
|
19689
|
-
* Logger instance
|
|
19690
|
-
*/ const logger = getLogger();
|
|
19691
|
-
|
|
19692
|
-
/**
|
|
19693
|
-
* Load theme configuration from atomix.config.ts
|
|
19694
|
-
*
|
|
19695
|
-
* @param options - Loader options
|
|
19696
|
-
* @returns Loaded and validated theme configuration
|
|
19697
|
-
*
|
|
19698
|
-
* @example
|
|
19699
|
-
* ```typescript
|
|
19700
|
-
* import { loadThemeConfig } from '@shohojdhara/atomix/theme/config';
|
|
19701
|
-
* const config = loadThemeConfig();
|
|
19702
|
-
* ```
|
|
19703
|
-
*/
|
|
19704
|
-
/**
|
|
19705
|
-
* Theme Registry
|
|
19706
|
-
*
|
|
19707
|
-
* Manages theme registration, discovery, and dependency resolution
|
|
19708
|
-
*/
|
|
19709
|
-
class ThemeRegistry {
|
|
19710
|
-
constructor() {
|
|
19711
|
-
this.entries = new Map, this.config = null, this.initialized = !1;
|
|
19712
|
-
}
|
|
19713
|
-
/**
|
|
19714
|
-
* Initialize registry from config
|
|
19715
|
-
*/ async initialize(config) {
|
|
19716
|
-
if (!this.initialized) {
|
|
19717
|
-
// Load config if not provided
|
|
19718
|
-
if (config) this.config = config; else try {
|
|
19719
|
-
this.config = function(options = {}) {
|
|
19720
|
-
const {configPath: configPath = DEFAULT_ATOMIX_CONFIG_PATH, validate: validate = !0, env: env = ("undefined" != typeof process && process.env && "production" === process.env.NODE_ENV ? "production" : "development")} = options;
|
|
19721
|
-
// Return cached config if available
|
|
19722
|
-
if (cachedConfig) return cachedConfig;
|
|
19723
|
-
// Try to load config dynamically
|
|
19724
|
-
let config;
|
|
19725
|
-
try {
|
|
19726
|
-
// In browser/Vite environment, we can't load config dynamically
|
|
19727
|
-
if ("undefined" != typeof window) throw new Error("Theme config loading not supported in browser environment");
|
|
19728
|
-
// In ESM environments, require might be undefined.
|
|
19729
|
-
let nodeRequire, configModule;
|
|
19730
|
-
try {
|
|
19731
|
-
nodeRequire = require;
|
|
19732
|
-
} catch {
|
|
19733
|
-
// require is not defined
|
|
19734
|
-
}
|
|
19735
|
-
if (!nodeRequire) throw new Error("Theme config loading not supported in this environment (require is undefined)");
|
|
19736
|
-
// Try require (Node.js/CommonJS)
|
|
19737
|
-
try {
|
|
19738
|
-
// Try relative path first
|
|
19739
|
-
try {
|
|
19740
|
-
configModule = nodeRequire("../../../../atomix.config");
|
|
19741
|
-
} catch {
|
|
19742
|
-
// If relative path fails, try to resolve from process.cwd()
|
|
19743
|
-
const path = nodeRequire("path"), fs = nodeRequire("fs");
|
|
19744
|
-
let configFilePath = path.resolve(process.cwd(), configPath);
|
|
19745
|
-
// If atomix.config.ts not found at the root, use the default path
|
|
19746
|
-
if (fs.existsSync(configFilePath) || configPath !== DEFAULT_ATOMIX_CONFIG_PATH || (configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH)),
|
|
19747
|
-
!fs.existsSync(configFilePath)) throw new Error(`Config file not found: ${configFilePath}`);
|
|
19748
|
-
{
|
|
19749
|
-
const resolvedPath = nodeRequire.resolve(configFilePath);
|
|
19750
|
-
nodeRequire.cache && nodeRequire.cache[resolvedPath] && delete nodeRequire.cache[resolvedPath],
|
|
19751
|
-
configModule = nodeRequire(configFilePath);
|
|
19752
|
-
}
|
|
19753
|
-
}
|
|
19754
|
-
} catch (requireError) {
|
|
19755
|
-
const errorMessage = requireError instanceof Error ? requireError.message : String(requireError);
|
|
19756
|
-
throw new ThemeError(`Cannot load config: ${errorMessage}`, ThemeErrorCode.CONFIG_LOAD_FAILED, {
|
|
19757
|
-
configPath: configPath,
|
|
19758
|
-
error: errorMessage
|
|
19759
|
-
});
|
|
19760
|
-
}
|
|
19761
|
-
const rawConfig = configModule.default || configModule, finalConfig =
|
|
19762
|
-
/**
|
|
19763
|
-
* Apply environment-specific overrides to configuration
|
|
19764
|
-
*
|
|
19765
|
-
* @param config - Base configuration
|
|
19766
|
-
* @param env - Environment name
|
|
19767
|
-
* @returns Configuration with environment overrides applied
|
|
19768
|
-
*/
|
|
19769
|
-
function(config, env) {
|
|
19770
|
-
const overridden = {
|
|
19771
|
-
...config
|
|
19772
|
-
};
|
|
19773
|
-
// Production overrides
|
|
19774
|
-
return "production" === env && overridden.runtime && (overridden.runtime = {
|
|
19775
|
-
...overridden.runtime,
|
|
19776
|
-
useMinified: !0,
|
|
19777
|
-
lazy: !0
|
|
19778
|
-
}),
|
|
19779
|
-
// Development overrides
|
|
19780
|
-
"development" === env && (overridden.runtime && (overridden.runtime = {
|
|
19781
|
-
...overridden.runtime,
|
|
19782
|
-
useMinified: !1,
|
|
19783
|
-
lazy: !1
|
|
19784
|
-
}), overridden.build && (overridden.build = {
|
|
19785
|
-
...overridden.build,
|
|
19786
|
-
sass: {
|
|
19787
|
-
...overridden.build.sass,
|
|
19788
|
-
sourceMap: !0
|
|
19789
|
-
}
|
|
19790
|
-
})),
|
|
19791
|
-
// Test overrides
|
|
19792
|
-
"test" === env && overridden.runtime && (overridden.runtime = {
|
|
19793
|
-
...overridden.runtime,
|
|
19794
|
-
enablePersistence: !1,
|
|
19795
|
-
preload: []
|
|
19796
|
-
}), overridden;
|
|
19797
|
-
}({
|
|
19798
|
-
themes: rawConfig.theme?.themes || {},
|
|
19799
|
-
build: rawConfig.build || {},
|
|
19800
|
-
runtime: rawConfig.runtime || {},
|
|
19801
|
-
integration: rawConfig.integration || {},
|
|
19802
|
-
dependencies: rawConfig.dependencies || {},
|
|
19803
|
-
validated: !1,
|
|
19804
|
-
// Will be set after validation
|
|
19805
|
-
// Store tokens for generator
|
|
19806
|
-
__tokens: rawConfig.theme?.tokens,
|
|
19807
|
-
__extend: rawConfig.theme?.extend
|
|
19808
|
-
}, env);
|
|
19809
|
-
// Process the AtomixConfig structure
|
|
19810
|
-
// Validate if requested
|
|
19811
|
-
let validationResult = null;
|
|
19812
|
-
validate && (validationResult = function(config) {
|
|
19813
|
-
const errors = [], warnings = [];
|
|
19814
|
-
// Validate top-level structure
|
|
19815
|
-
if (!config || "object" != typeof config) return errors.push("Configuration must be an object"),
|
|
19816
|
-
{
|
|
19817
|
-
valid: !1,
|
|
19818
|
-
errors: errors,
|
|
19819
|
-
warnings: warnings
|
|
19820
|
-
};
|
|
19821
|
-
// Validate themes
|
|
19822
|
-
if (config.themes && "object" == typeof config.themes) {
|
|
19823
|
-
const themeErrors =
|
|
19824
|
-
/**
|
|
19825
|
-
* Validate themes object
|
|
19826
|
-
*/
|
|
19827
|
-
function(themes) {
|
|
19828
|
-
const errors = [], warnings = [];
|
|
19829
|
-
0 === Object.keys(themes).length && warnings.push("No themes defined in configuration");
|
|
19830
|
-
for (const [themeId, theme] of Object.entries(themes))
|
|
19831
|
-
// Validate theme ID
|
|
19832
|
-
if (themeId && "string" == typeof themeId)
|
|
19833
|
-
// Validate theme object
|
|
19834
|
-
if (theme && "object" == typeof theme)
|
|
19835
|
-
// Validate theme type
|
|
19836
|
-
if (!theme.type || "css" !== theme.type && "js" !== theme.type) errors.push(`Theme "${themeId}" must have type "css" or "js"`); else {
|
|
19837
|
-
// Validate CSS theme
|
|
19838
|
-
if (
|
|
19839
|
-
// Validate required fields
|
|
19840
|
-
theme.name && "string" == typeof theme.name || errors.push(`Theme "${themeId}" must have a "name" string`),
|
|
19841
|
-
"css" === theme.type) {
|
|
19842
|
-
const cssErrors = validateCSSTheme();
|
|
19843
|
-
errors.push(...cssErrors.errors), warnings.push(...cssErrors.warnings);
|
|
19844
|
-
}
|
|
19845
|
-
// Validate JS theme
|
|
19846
|
-
if ("js" === theme.type) {
|
|
19847
|
-
const jsErrors = validateJSTheme(themeId, theme);
|
|
19848
|
-
errors.push(...jsErrors.errors), warnings.push(...jsErrors.warnings);
|
|
19849
|
-
}
|
|
19850
|
-
// Validate accessibility (only critical checks)
|
|
19851
|
-
theme.a11y?.contrastTarget && ("number" != typeof theme.a11y.contrastTarget || theme.a11y.contrastTarget < 1 || theme.a11y.contrastTarget > 21) && warnings.push(`Theme "${themeId}" has invalid contrast target: ${theme.a11y.contrastTarget}`);
|
|
19852
|
-
} else errors.push(`Theme "${themeId}" must be an object`); else errors.push(`Invalid theme ID: ${themeId}`);
|
|
19853
|
-
return {
|
|
19854
|
-
valid: 0 === errors.length,
|
|
19855
|
-
errors: errors,
|
|
19856
|
-
warnings: warnings
|
|
19857
|
-
};
|
|
19858
|
-
}(config.themes);
|
|
19859
|
-
errors.push(...themeErrors.errors), warnings.push(...themeErrors.warnings);
|
|
19860
|
-
}
|
|
19861
|
-
// Validate build config (only if provided)
|
|
19862
|
-
else errors.push('Configuration must have a "themes" object');
|
|
19863
|
-
if (config.build) {
|
|
19864
|
-
const buildErrors = function(build) {
|
|
19865
|
-
const errors = [];
|
|
19866
|
-
// Only validate structure if provided
|
|
19867
|
-
return build.output && "object" != typeof build.output && errors.push("Build output must be an object"),
|
|
19868
|
-
build.sass && "object" != typeof build.sass && errors.push("Build sass config must be an object"),
|
|
19869
|
-
{
|
|
19870
|
-
valid: 0 === errors.length,
|
|
19871
|
-
errors: errors,
|
|
19872
|
-
warnings: []
|
|
19873
|
-
};
|
|
19874
|
-
}
|
|
19875
|
-
/**
|
|
19876
|
-
* Validate runtime configuration
|
|
19877
|
-
*/ (config.build);
|
|
19878
|
-
errors.push(...buildErrors.errors), warnings.push(...buildErrors.warnings);
|
|
19879
|
-
}
|
|
19880
|
-
// Validate runtime config (only if provided)
|
|
19881
|
-
if (config.runtime) {
|
|
19882
|
-
const runtimeErrors = function(runtime) {
|
|
19883
|
-
const errors = [];
|
|
19884
|
-
return runtime.basePath && "string" != typeof runtime.basePath && errors.push("Runtime basePath must be a string"),
|
|
19885
|
-
runtime.defaultTheme && "string" != typeof runtime.defaultTheme && errors.push("Runtime defaultTheme must be a string"),
|
|
19886
|
-
runtime.preload && !Array.isArray(runtime.preload) && errors.push("Runtime preload must be an array"),
|
|
19887
|
-
runtime.storageKey && "string" != typeof runtime.storageKey && errors.push("Runtime storageKey must be a string"),
|
|
19888
|
-
{
|
|
19889
|
-
valid: 0 === errors.length,
|
|
19890
|
-
errors: errors,
|
|
19891
|
-
warnings: []
|
|
19892
|
-
};
|
|
19893
|
-
}
|
|
19894
|
-
/**
|
|
19895
|
-
* Validate integration configuration
|
|
19896
|
-
*/ (config.runtime);
|
|
19897
|
-
errors.push(...runtimeErrors.errors), warnings.push(...runtimeErrors.warnings);
|
|
19898
|
-
}
|
|
19899
|
-
// Validate integration config (only if provided)
|
|
19900
|
-
if (config.integration) {
|
|
19901
|
-
const integrationErrors = function(integration) {
|
|
19902
|
-
const errors = [];
|
|
19903
|
-
// Only validate structure if provided
|
|
19904
|
-
return integration.classNames && "object" != typeof integration.classNames && errors.push("Integration classNames must be an object"),
|
|
19905
|
-
{
|
|
19906
|
-
valid: 0 === errors.length,
|
|
19907
|
-
errors: errors,
|
|
19908
|
-
warnings: []
|
|
19909
|
-
};
|
|
19910
|
-
}
|
|
19911
|
-
/**
|
|
19912
|
-
* Validate dependencies
|
|
19913
|
-
*/ (config.integration);
|
|
19914
|
-
errors.push(...integrationErrors.errors), warnings.push(...integrationErrors.warnings);
|
|
19915
|
-
}
|
|
19916
|
-
// Validate dependencies
|
|
19917
|
-
if (config.dependencies) {
|
|
19918
|
-
const depErrors = function(dependencies, themes) {
|
|
19919
|
-
const errors = [], warnings = [];
|
|
19920
|
-
for (const [themeId, deps] of Object.entries(dependencies))
|
|
19921
|
-
// Check if theme exists
|
|
19922
|
-
if (themes[themeId])
|
|
19923
|
-
// Validate dependencies array
|
|
19924
|
-
if (Array.isArray(deps))
|
|
19925
|
-
// Check if all dependencies exist
|
|
19926
|
-
for (const dep of deps) themes[dep] || errors.push(`Theme "${themeId}" depends on non-existent theme: ${dep}`); else errors.push(`Dependencies for "${themeId}" must be an array`); else warnings.push(`Dependencies defined for non-existent theme: ${themeId}`);
|
|
19927
|
-
return {
|
|
19928
|
-
valid: 0 === errors.length,
|
|
19929
|
-
errors: errors,
|
|
19930
|
-
warnings: warnings
|
|
19931
|
-
};
|
|
19932
|
-
}(config.dependencies, config.themes || {});
|
|
19933
|
-
errors.push(...depErrors.errors), warnings.push(...depErrors.warnings);
|
|
19934
|
-
}
|
|
19935
|
-
return {
|
|
19936
|
-
valid: 0 === errors.length,
|
|
19937
|
-
errors: errors,
|
|
19938
|
-
warnings: warnings
|
|
19939
|
-
};
|
|
19940
|
-
}(finalConfig)), config = {
|
|
19941
|
-
...finalConfig,
|
|
19942
|
-
validated: validate,
|
|
19943
|
-
errors: validationResult?.errors,
|
|
19944
|
-
warnings: validationResult?.warnings
|
|
19945
|
-
};
|
|
19946
|
-
} catch (error) {
|
|
19947
|
-
// Fallback: return default config structure
|
|
19948
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
19949
|
-
logger.warn(`Failed to load theme config from ${configPath}`, {
|
|
19950
|
-
configPath: configPath,
|
|
19951
|
-
error: errorMessage
|
|
19952
|
-
}), config = {
|
|
19953
|
-
themes: {},
|
|
19954
|
-
build: {
|
|
19955
|
-
output: {
|
|
19956
|
-
directory: "themes",
|
|
19957
|
-
formats: {
|
|
19958
|
-
expanded: ".css",
|
|
19959
|
-
compressed: ".min.css"
|
|
19960
|
-
}
|
|
19961
|
-
},
|
|
19962
|
-
sass: {
|
|
19963
|
-
...DEFAULT_SASS_CONFIG,
|
|
19964
|
-
loadPaths: [ ...DEFAULT_SASS_CONFIG.loadPaths ]
|
|
19965
|
-
}
|
|
19966
|
-
},
|
|
19967
|
-
runtime: {
|
|
19968
|
-
basePath: "/themes",
|
|
19969
|
-
cdnPath: null,
|
|
19970
|
-
preload: [],
|
|
19971
|
-
lazy: !0,
|
|
19972
|
-
defaultTheme: "",
|
|
19973
|
-
// No default - use built-in styles (empty string instead of undefined)
|
|
19974
|
-
storageKey: "atomix-theme",
|
|
19975
|
-
dataAttribute: "data-theme",
|
|
19976
|
-
enablePersistence: !0,
|
|
19977
|
-
useMinified: "production" === env
|
|
19978
|
-
},
|
|
19979
|
-
integration: {
|
|
19980
|
-
cssVariables: DEFAULT_INTEGRATION_CSS_VARIABLES,
|
|
19981
|
-
classNames: DEFAULT_INTEGRATION_CLASS_NAMES
|
|
19982
|
-
},
|
|
19983
|
-
dependencies: {},
|
|
19984
|
-
validated: !1,
|
|
19985
|
-
errors: [ `Failed to load config: ${error instanceof Error ? error.message : String(error)}` ],
|
|
19986
|
-
warnings: [],
|
|
19987
|
-
__tokens: {},
|
|
19988
|
-
__extend: {}
|
|
19989
|
-
};
|
|
19990
|
-
}
|
|
19991
|
-
// Cache the loaded config
|
|
19992
|
-
return cachedConfig = config, config;
|
|
19993
|
-
}();
|
|
19994
|
-
} catch (error) {
|
|
19995
|
-
// In browser environments, config loading will fail
|
|
19996
|
-
// Use empty config as fallback
|
|
19997
|
-
this.config = {
|
|
19998
|
-
themes: {},
|
|
19999
|
-
build: {
|
|
20000
|
-
output: {
|
|
20001
|
-
directory: "themes",
|
|
20002
|
-
formats: {
|
|
20003
|
-
expanded: ".css",
|
|
20004
|
-
compressed: ".min.css"
|
|
20005
|
-
}
|
|
20006
|
-
},
|
|
20007
|
-
sass: {
|
|
20008
|
-
style: "expanded",
|
|
20009
|
-
sourceMap: !0,
|
|
20010
|
-
loadPaths: [ "src" ]
|
|
20011
|
-
}
|
|
20012
|
-
},
|
|
20013
|
-
runtime: {
|
|
20014
|
-
basePath: "",
|
|
20015
|
-
defaultTheme: void 0
|
|
20016
|
-
},
|
|
20017
|
-
integration: {
|
|
20018
|
-
cssVariables: {
|
|
20019
|
-
colorMode: "--color-mode"
|
|
20020
|
-
},
|
|
20021
|
-
classNames: {
|
|
20022
|
-
theme: "data-theme",
|
|
20023
|
-
colorMode: "data-color-mode"
|
|
20024
|
-
}
|
|
20025
|
-
},
|
|
20026
|
-
dependencies: {},
|
|
20027
|
-
validated: !1,
|
|
20028
|
-
errors: [],
|
|
20029
|
-
warnings: [],
|
|
20030
|
-
__tokens: {},
|
|
20031
|
-
__extend: {}
|
|
20032
|
-
};
|
|
20033
|
-
}
|
|
20034
|
-
// Register all themes from config
|
|
20035
|
-
for (const [themeId, definition] of Object.entries(this.config.themes)) this.register(themeId, definition);
|
|
20036
|
-
// Resolve dependencies
|
|
20037
|
-
this.resolveDependencies(), this.initialized = !0;
|
|
20038
|
-
}
|
|
20039
|
-
}
|
|
20040
|
-
/**
|
|
20041
|
-
* Register a theme
|
|
20042
|
-
*/ register(themeId, definition) {
|
|
20043
|
-
// Get dependencies from config or definition
|
|
20044
|
-
const entry = {
|
|
20045
|
-
id: themeId,
|
|
20046
|
-
definition: definition,
|
|
20047
|
-
loaded: !1,
|
|
20048
|
-
dependencies: [ ...this.config?.dependencies?.[themeId] || definition.dependencies || [] ],
|
|
20049
|
-
dependents: []
|
|
20050
|
-
};
|
|
20051
|
-
this.entries.set(themeId, entry);
|
|
20052
|
-
}
|
|
20053
|
-
/**
|
|
20054
|
-
* Get theme entry
|
|
20055
|
-
*/ get(themeId) {
|
|
20056
|
-
return this.entries.get(themeId);
|
|
20057
|
-
}
|
|
20058
|
-
/**
|
|
20059
|
-
* Check if theme exists
|
|
20060
|
-
*/ has(themeId) {
|
|
20061
|
-
return this.entries.has(themeId);
|
|
20062
|
-
}
|
|
20063
|
-
/**
|
|
20064
|
-
* Get all theme IDs
|
|
20065
|
-
*/ getAllIds() {
|
|
20066
|
-
return Array.from(this.entries.keys());
|
|
20067
|
-
}
|
|
20068
|
-
/**
|
|
20069
|
-
* Get all theme metadata
|
|
20070
|
-
*/ getAllMetadata() {
|
|
20071
|
-
return Array.from(this.entries.values()).map((entry => ({
|
|
20072
|
-
id: entry.id,
|
|
20073
|
-
name: entry.definition.name,
|
|
20074
|
-
type: entry.definition.type,
|
|
20075
|
-
class: entry.definition.class,
|
|
20076
|
-
description: entry.definition.description,
|
|
20077
|
-
author: entry.definition.author,
|
|
20078
|
-
version: entry.definition.version,
|
|
20079
|
-
tags: entry.definition.tags,
|
|
20080
|
-
supportsDarkMode: entry.definition.supportsDarkMode,
|
|
20081
|
-
status: entry.definition.status,
|
|
20082
|
-
a11y: entry.definition.a11y,
|
|
20083
|
-
color: entry.definition.color,
|
|
20084
|
-
features: entry.definition.features,
|
|
20085
|
-
dependencies: entry.dependencies
|
|
20086
|
-
})));
|
|
20087
|
-
}
|
|
20088
|
-
/**
|
|
20089
|
-
* Get theme definition
|
|
20090
|
-
*/ getDefinition(themeId) {
|
|
20091
|
-
return this.entries.get(themeId)?.definition;
|
|
20092
|
-
}
|
|
20093
|
-
/**
|
|
20094
|
-
* Check if a theme is loaded
|
|
20095
|
-
*/ isThemeLoaded(themeId) {
|
|
20096
|
-
const entry = this.entries.get(themeId);
|
|
20097
|
-
return !!entry && entry.loaded;
|
|
20098
|
-
}
|
|
20099
|
-
/**
|
|
20100
|
-
* Mark a theme as loaded
|
|
20101
|
-
*/ markLoaded(themeId, theme) {
|
|
20102
|
-
const entry = this.entries.get(themeId);
|
|
20103
|
-
entry && (entry.loaded = !0, theme && (entry.theme = theme));
|
|
20104
|
-
}
|
|
20105
|
-
/**
|
|
20106
|
-
* Get theme object (for JS themes)
|
|
20107
|
-
*/ getTheme(themeId) {
|
|
20108
|
-
const entry = this.entries.get(themeId);
|
|
20109
|
-
return entry?.loaded ? entry.theme : void 0;
|
|
20110
|
-
}
|
|
20111
|
-
/**
|
|
20112
|
-
* Get dependencies for a theme
|
|
20113
|
-
*/ getDependencies(themeId) {
|
|
20114
|
-
return this.entries.get(themeId)?.dependencies || [];
|
|
20115
|
-
}
|
|
20116
|
-
/**
|
|
20117
|
-
* Get dependents for a theme (themes that depend on this one)
|
|
20118
|
-
*/ getDependents(themeId) {
|
|
20119
|
-
return this.entries.get(themeId)?.dependents || [];
|
|
20120
|
-
}
|
|
20121
|
-
/**
|
|
20122
|
-
* Resolve all dependencies in correct order
|
|
20123
|
-
*/ resolveDependencyOrder(themeId) {
|
|
20124
|
-
const resolved = [], visited = new Set, visiting = new Set, visit = id => {
|
|
20125
|
-
if (visiting.has(id)) throw new Error(`Circular dependency detected involving theme: ${id}`);
|
|
20126
|
-
if (visited.has(id)) return;
|
|
20127
|
-
visiting.add(id);
|
|
20128
|
-
const entry = this.entries.get(id);
|
|
20129
|
-
if (entry) for (const dep of entry.dependencies) {
|
|
20130
|
-
if (!this.has(dep)) throw new Error(`Theme "${id}" depends on non-existent theme: ${dep}`);
|
|
20131
|
-
visit(dep);
|
|
20132
|
-
}
|
|
20133
|
-
visiting.delete(id), visited.add(id), resolved.push(id);
|
|
20134
|
-
};
|
|
20135
|
-
return visit(themeId), resolved;
|
|
20136
|
-
}
|
|
20137
|
-
/**
|
|
20138
|
-
* Resolve dependencies and build dependency graph
|
|
20139
|
-
*/ resolveDependencies() {
|
|
20140
|
-
// Build dependents map
|
|
20141
|
-
for (const entry of this.entries.values()) for (const dep of entry.dependencies) {
|
|
20142
|
-
const depEntry = this.entries.get(dep);
|
|
20143
|
-
var _context;
|
|
20144
|
-
depEntry && (_includesInstanceProperty(_context = depEntry.dependents).call(_context, entry.id) || depEntry.dependents.push(entry.id));
|
|
20145
|
-
}
|
|
20146
|
-
}
|
|
20147
|
-
/**
|
|
20148
|
-
* Validate all themes
|
|
20149
|
-
*/ validate() {
|
|
20150
|
-
const errors = [];
|
|
20151
|
-
// Check for circular dependencies
|
|
20152
|
-
for (const themeId of this.entries.keys()) try {
|
|
20153
|
-
this.resolveDependencyOrder(themeId);
|
|
20154
|
-
} catch (error) {
|
|
20155
|
-
errors.push(error instanceof Error ? error.message : String(error));
|
|
20156
|
-
}
|
|
20157
|
-
// Check for missing dependencies
|
|
20158
|
-
for (const [themeId, entry] of this.entries.entries()) for (const dep of entry.dependencies) this.has(dep) || errors.push(`Theme "${themeId}" depends on non-existent theme: ${dep}`);
|
|
20159
|
-
return {
|
|
20160
|
-
valid: 0 === errors.length,
|
|
20161
|
-
errors: errors
|
|
20162
|
-
};
|
|
20163
|
-
}
|
|
20164
|
-
/**
|
|
20165
|
-
* Clear registry
|
|
20166
|
-
*/ clear() {
|
|
20167
|
-
this.entries.clear(), this.config = null, this.initialized = !1;
|
|
20168
|
-
}
|
|
19268
|
+
* Get the number of registered themes
|
|
19269
|
+
* @param registry - Theme registry object
|
|
19270
|
+
*/ function getThemeCount(registry) {
|
|
19271
|
+
return Object.keys(registry).length;
|
|
20169
19272
|
}
|
|
20170
19273
|
|
|
20171
19274
|
/**
|
|
@@ -20250,71 +19353,18 @@ class ThemeRegistry {
|
|
|
20250
19353
|
* const css = ':root { --atomix-color-primary: #7AFFD7; }';
|
|
20251
19354
|
* await saveCSSFile(css, './themes/custom.css');
|
|
20252
19355
|
* ```
|
|
20253
|
-
*/
|
|
20254
|
-
// Check if in browser environment
|
|
20255
|
-
if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
|
|
20256
|
-
// Dynamic import to avoid bundling Node.js modules in browser builds
|
|
20257
|
-
const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
|
|
20258
|
-
await fs.mkdir(dir, {
|
|
20259
|
-
recursive: !0
|
|
20260
|
-
}),
|
|
20261
|
-
// Write file
|
|
20262
|
-
await fs.writeFile(filePath, css, "utf8");
|
|
20263
|
-
}
|
|
20264
|
-
|
|
20265
|
-
/**
|
|
20266
|
-
* Save CSS to file (synchronous version)
|
|
20267
|
-
*
|
|
20268
|
-
* Synchronous version of saveCSSFile. Only works in Node.js environment.
|
|
20269
|
-
*
|
|
20270
|
-
* @param css - CSS string to save
|
|
20271
|
-
* @param filePath - Output file path
|
|
20272
|
-
* @throws Error if called in browser environment
|
|
20273
|
-
*/ function saveCSSFileSync(css, filePath) {
|
|
20274
|
-
// Check if in browser environment
|
|
20275
|
-
if ("undefined" != typeof window) throw new Error("saveCSSFileSync can only be used in Node.js environment. Use injectCSS() for browser environments.");
|
|
20276
|
-
// Use require for synchronous file operations
|
|
20277
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
20278
|
-
const fs = require("fs"), dir = require("path").dirname(filePath);
|
|
20279
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
20280
|
-
fs.existsSync(dir) || fs.mkdirSync(dir, {
|
|
20281
|
-
recursive: !0
|
|
20282
|
-
}),
|
|
20283
|
-
// Write file
|
|
20284
|
-
fs.writeFileSync(filePath, css, "utf8");
|
|
20285
|
-
}
|
|
19356
|
+
*/ "undefined" != typeof process && process.env;
|
|
20286
19357
|
|
|
20287
19358
|
/**
|
|
20288
19359
|
* Check if code is running in a browser environment
|
|
20289
|
-
*/
|
|
19360
|
+
*/
|
|
19361
|
+
const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
|
|
20290
19362
|
// Validate theme name to prevent path injection
|
|
20291
19363
|
if (!isValidThemeName(themeName)) throw new Error(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens.`);
|
|
20292
19364
|
const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
|
|
20293
19365
|
return cdnPath ? `${cdnPath.replace(/[<>"']/g, "")}/${fileName}` : `${basePath.replace(/\/$/, "").replace(/[<>"']/g, "")}/${fileName.replace(/^\//, "")}`;
|
|
20294
19366
|
// Ensure basePath doesn't end with slash and fileName doesn't start with slash
|
|
20295
19367
|
// Also sanitize basePath to prevent path injection
|
|
20296
|
-
}, loadThemeCSS = (fullPath, linkId) => isServer() ? Promise.resolve() : new Promise(((resolve, reject) => {
|
|
20297
|
-
if (document.getElementById(linkId)) return void resolve();
|
|
20298
|
-
// Create link element
|
|
20299
|
-
const link = document.createElement("link");
|
|
20300
|
-
link.id = linkId, link.rel = "stylesheet", link.type = "text/css", link.href = fullPath,
|
|
20301
|
-
// Add data attribute for tracking
|
|
20302
|
-
link.setAttribute("data-atomix-theme", "true"),
|
|
20303
|
-
// Handle load success
|
|
20304
|
-
link.onload = () => {
|
|
20305
|
-
resolve();
|
|
20306
|
-
},
|
|
20307
|
-
// Handle load error
|
|
20308
|
-
link.onerror = () => {
|
|
20309
|
-
// Remove failed link element
|
|
20310
|
-
link.remove(), reject(new Error(`Failed to load theme CSS: ${fullPath}`));
|
|
20311
|
-
},
|
|
20312
|
-
// Append to head
|
|
20313
|
-
document.head.appendChild(link);
|
|
20314
|
-
})), isThemeLoaded = themeName => {
|
|
20315
|
-
if (isServer()) return !1;
|
|
20316
|
-
const linkId = getThemeLinkId(themeName);
|
|
20317
|
-
return null !== document.getElementById(linkId);
|
|
20318
19368
|
}, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName);
|
|
20319
19369
|
|
|
20320
19370
|
/**
|
|
@@ -20787,211 +19837,198 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
20787
19837
|
styleElement.textContent = css;
|
|
20788
19838
|
}
|
|
20789
19839
|
/**
|
|
20790
|
-
*
|
|
19840
|
+
* Naming Utilities
|
|
20791
19841
|
*
|
|
20792
|
-
*
|
|
19842
|
+
* Provides consistent naming conventions across the theme system
|
|
20793
19843
|
*/
|
|
20794
19844
|
/**
|
|
20795
|
-
*
|
|
19845
|
+
* Generate consistent CSS class names following BEM methodology
|
|
20796
19846
|
*/ (css, styleId), css;
|
|
20797
19847
|
}
|
|
20798
19848
|
|
|
20799
|
-
|
|
19849
|
+
function generateClassName(block, element, modifiers) {
|
|
19850
|
+
let className = block;
|
|
19851
|
+
return element && (className += `__${element}`), modifiers && Object.entries(modifiers).forEach((([key, value]) => {
|
|
19852
|
+
value && (className += `--${key}`, "string" == typeof value && value !== key && (className += `-${value}`));
|
|
19853
|
+
})), className;
|
|
19854
|
+
}
|
|
20800
19855
|
|
|
20801
|
-
|
|
19856
|
+
/**
|
|
19857
|
+
* Generate consistent CSS variable names
|
|
19858
|
+
*/ function generateCSSVariableName(property, options = {}) {
|
|
19859
|
+
const {prefix: prefix = "atomix", component: component, variant: variant, state: state} = options, parts = [ prefix ];
|
|
19860
|
+
return component && parts.push(component), variant && parts.push(variant), state && parts.push(state),
|
|
19861
|
+
parts.push(property), `--${parts.join("-")}`;
|
|
19862
|
+
}
|
|
20802
19863
|
|
|
20803
19864
|
/**
|
|
20804
|
-
*
|
|
20805
|
-
|
|
20806
|
-
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
19865
|
+
* Normalize theme tokens to consistent naming convention
|
|
19866
|
+
*/ function normalizeThemeTokens(tokens) {
|
|
19867
|
+
const normalized = {};
|
|
19868
|
+
for (const [key, value] of Object.entries(tokens))
|
|
19869
|
+
// Recursively normalize nested objects
|
|
19870
|
+
normalized[key] = "object" == typeof value && null !== value ? normalizeThemeTokens(value) : value;
|
|
19871
|
+
return normalized;
|
|
19872
|
+
}
|
|
19873
|
+
|
|
20811
19874
|
/**
|
|
20812
|
-
*
|
|
19875
|
+
* Convert camelCase to kebab-case for CSS custom properties
|
|
19876
|
+
*/ function camelToKebab(str) {
|
|
19877
|
+
return str.replace(/[A-Z]/g, (match => `-${match.toLowerCase()}`));
|
|
19878
|
+
}
|
|
19879
|
+
|
|
19880
|
+
/**
|
|
19881
|
+
* Convert theme property to CSS variable name
|
|
19882
|
+
*/ function themePropertyToCSSVar(propertyPath, prefix = "atomix") {
|
|
19883
|
+
return `--${prefix}-${propertyPath.split(".").map((part => camelToKebab(part))).join("-")}`;
|
|
19884
|
+
}
|
|
19885
|
+
|
|
19886
|
+
/**
|
|
19887
|
+
* Component Theming Utilities
|
|
20813
19888
|
*
|
|
20814
|
-
*
|
|
19889
|
+
* Provides consistent patterns for applying theme values to components
|
|
20815
19890
|
*/
|
|
20816
|
-
|
|
20817
|
-
|
|
20818
|
-
|
|
20819
|
-
|
|
20820
|
-
|
|
20821
|
-
|
|
20822
|
-
|
|
20823
|
-
|
|
20824
|
-
|
|
20825
|
-
*/ applyTheme(theme) {
|
|
20826
|
-
// Clear previously applied variables
|
|
20827
|
-
this.clearAppliedVars(),
|
|
20828
|
-
// Check if it's DesignTokens
|
|
20829
|
-
this.isDesignTokens(theme) ?
|
|
20830
|
-
// Direct DesignTokens - use unified theme system (with config support)
|
|
20831
|
-
this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
|
|
20832
|
-
selector: ":root",
|
|
20833
|
-
prefix: "atomix"
|
|
20834
|
-
}), this.styleId),
|
|
20835
|
-
// Apply component overrides (only for Theme objects)
|
|
20836
|
-
!this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
|
|
20837
|
-
}
|
|
20838
|
-
/**
|
|
20839
|
-
* Apply DesignTokens using unified theme system
|
|
20840
|
-
*
|
|
20841
|
-
* Uses createTheme() which automatically loads from atomix.config.ts
|
|
20842
|
-
* if no tokens are provided, ensuring config is always respected.
|
|
20843
|
-
*/ applyDesignTokens(tokens) {
|
|
20844
|
-
// Inject CSS into DOM
|
|
20845
|
-
injectCSS$1(createTheme(tokens, {
|
|
20846
|
-
selector: ":root",
|
|
20847
|
-
prefix: "atomix"
|
|
20848
|
-
}), this.styleId);
|
|
20849
|
-
}
|
|
20850
|
-
/**
|
|
20851
|
-
* Check if object is DesignTokens
|
|
20852
|
-
*/ isDesignTokens(obj) {
|
|
20853
|
-
// DesignTokens is a flat object with string keys, no nested structures
|
|
20854
|
-
return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
|
|
20855
|
-
}
|
|
20856
|
-
/**
|
|
20857
|
-
* Apply global CSS variables (for component overrides)
|
|
20858
|
-
*/ applyGlobalCSSVars(vars) {
|
|
20859
|
-
Object.entries(vars).forEach((([key, value]) => {
|
|
20860
|
-
this.root.style.setProperty(key, String(value));
|
|
20861
|
-
}));
|
|
20862
|
-
}
|
|
20863
|
-
/**
|
|
20864
|
-
* Apply component-level overrides
|
|
20865
|
-
*/ applyComponentOverrides(overrides) {
|
|
20866
|
-
Object.entries(overrides).forEach((([componentName, override]) => {
|
|
20867
|
-
override && this.applyComponentOverride(componentName, override);
|
|
20868
|
-
}));
|
|
20869
|
-
}
|
|
20870
|
-
/**
|
|
20871
|
-
* Apply override for a specific component
|
|
20872
|
-
*/ applyComponentOverride(componentName, override) {
|
|
20873
|
-
const vars = {}, componentKey = componentName.toLowerCase();
|
|
20874
|
-
// Apply component-level CSS variables
|
|
20875
|
-
override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
|
|
20876
|
-
// If key doesn't start with --, add component prefix
|
|
20877
|
-
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
|
|
20878
|
-
vars[varKey] = value;
|
|
20879
|
-
})),
|
|
20880
|
-
// Apply part-specific CSS variables
|
|
20881
|
-
override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
|
|
20882
|
-
partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
|
|
20883
|
-
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
|
|
20884
|
-
vars[varKey] = value;
|
|
20885
|
-
}));
|
|
20886
|
-
})),
|
|
20887
|
-
// Apply variant-specific CSS variables
|
|
20888
|
-
override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
|
|
20889
|
-
variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
|
|
20890
|
-
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
|
|
20891
|
-
vars[varKey] = value;
|
|
20892
|
-
}));
|
|
20893
|
-
})), this.applyGlobalCSSVars(vars);
|
|
20894
|
-
}
|
|
20895
|
-
/**
|
|
20896
|
-
* Clear all applied CSS variables
|
|
20897
|
-
*/ clearAppliedVars() {
|
|
20898
|
-
removeCSS(this.styleId);
|
|
20899
|
-
}
|
|
20900
|
-
/**
|
|
20901
|
-
* Remove theme application
|
|
20902
|
-
*/ removeTheme() {
|
|
20903
|
-
this.clearAppliedVars(), removeCSS(this.styleId);
|
|
20904
|
-
}
|
|
20905
|
-
/**
|
|
20906
|
-
* Update specific CSS variables without clearing all
|
|
20907
|
-
*/ updateCSSVars(vars) {
|
|
20908
|
-
this.applyGlobalCSSVars(vars);
|
|
20909
|
-
}
|
|
19891
|
+
/**
|
|
19892
|
+
* Get a theme value for a specific component using CSS variables
|
|
19893
|
+
* This ensures all components access theme values consistently
|
|
19894
|
+
*/ function getComponentThemeValue(component, property, variant, size) {
|
|
19895
|
+
// Build CSS variable name following consistent pattern
|
|
19896
|
+
const parts = [ "atomix", component ];
|
|
19897
|
+
// Return CSS variable reference with fallback
|
|
19898
|
+
return variant && parts.push(variant), size && parts.push(size), parts.push(property),
|
|
19899
|
+
`var(--${parts.join("-")}, var(--atomix-${property}, initial))`;
|
|
20910
19900
|
}
|
|
20911
19901
|
|
|
20912
19902
|
/**
|
|
20913
|
-
*
|
|
20914
|
-
*/
|
|
19903
|
+
* Generate component-specific CSS variables from theme
|
|
19904
|
+
*/ function generateComponentCSSVars(component, theme, variant, size) {
|
|
19905
|
+
const vars = {}, prefixParts = [ "atomix", component ];
|
|
19906
|
+
// This is a simplified implementation - in a real system you'd have more
|
|
19907
|
+
// sophisticated logic to extract component-specific values from the theme
|
|
19908
|
+
variant && prefixParts.push(variant), size && prefixParts.push(size);
|
|
19909
|
+
const prefix = prefixParts.join("-");
|
|
19910
|
+
// Add common component properties
|
|
19911
|
+
if (theme.palette && (vars[`--${prefix}-color`] = theme.palette.primary?.main || "#7c3aed",
|
|
19912
|
+
vars[`--${prefix}-color-hover`] = theme.palette.primary?.dark || "#5b21b6", vars[`--${prefix}-color-active`] = theme.palette.primary?.main || "#7c3aed",
|
|
19913
|
+
vars[`--${prefix}-color-disabled`] = theme.palette.text?.disabled || "#9ca3af"),
|
|
19914
|
+
theme.typography && (vars[`--${prefix}-font-family`] = theme.typography.fontFamily || "Inter, sans-serif",
|
|
19915
|
+
vars[`--${prefix}-font-size`] = theme.typography.fontSize ? `${theme.typography.fontSize}px` : "16px"),
|
|
19916
|
+
theme.spacing) {
|
|
19917
|
+
const spacing = "function" == typeof theme.spacing ? theme.spacing : val => 8 * val;
|
|
19918
|
+
vars[`--${prefix}-spacing-unit`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-sm`] = `${spacing(.5)}px`,
|
|
19919
|
+
vars[`--${prefix}-spacing-md`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-lg`] = `${spacing(2)}px`;
|
|
19920
|
+
}
|
|
19921
|
+
return vars;
|
|
19922
|
+
}
|
|
20915
19923
|
|
|
20916
19924
|
/**
|
|
20917
|
-
*
|
|
20918
|
-
*/ function
|
|
20919
|
-
|
|
19925
|
+
* Apply consistent theme to component style object
|
|
19926
|
+
*/ function applyComponentTheme(component, style = {}, variant, size, theme) {
|
|
19927
|
+
// If no theme provided, return original style
|
|
19928
|
+
return theme ? {
|
|
19929
|
+
...generateComponentCSSVars(component, theme, variant, size),
|
|
19930
|
+
...style
|
|
19931
|
+
} : style;
|
|
19932
|
+
// Generate component-specific CSS variables
|
|
20920
19933
|
}
|
|
20921
19934
|
|
|
20922
19935
|
/**
|
|
20923
|
-
*
|
|
20924
|
-
*/ function
|
|
20925
|
-
|
|
19936
|
+
* Create a hook for consistent component theming
|
|
19937
|
+
*/ function useComponentTheme(component, variant, size, theme) {
|
|
19938
|
+
return property => getComponentThemeValue(component, property, variant, size);
|
|
20926
19939
|
}
|
|
20927
19940
|
|
|
20928
19941
|
/**
|
|
20929
|
-
*
|
|
20930
|
-
*
|
|
20931
|
-
* Provides theme context to child components and manages theme state.
|
|
19942
|
+
* Theme Configuration Loader
|
|
20932
19943
|
*
|
|
20933
|
-
*
|
|
20934
|
-
*
|
|
19944
|
+
* Provides functions to load theme configurations from atomix.config.ts
|
|
19945
|
+
* Includes both sync and async versions, with automatic fallbacks
|
|
19946
|
+
*/
|
|
19947
|
+
/**
|
|
19948
|
+
* Load theme from config file (synchronous, Node.js only)
|
|
19949
|
+
* @param configPath - Path to config file (default: atomix.config.ts)
|
|
19950
|
+
* @returns DesignTokens from theme configuration
|
|
19951
|
+
* @throws Error if config loading is not available in browser environment
|
|
19952
|
+
*/ function loadThemeFromConfigSync(options) {
|
|
19953
|
+
// Check if we're in a browser environment
|
|
19954
|
+
if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
19955
|
+
// Use dynamic import to load the config loader
|
|
19956
|
+
// This allows bundlers to handle external dependencies properly
|
|
19957
|
+
let loadAtomixConfig;
|
|
19958
|
+
try {
|
|
19959
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19960
|
+
const {loadAtomixConfig: loader} = require("../../config/loader");
|
|
19961
|
+
loadAtomixConfig = loader;
|
|
19962
|
+
} catch (error) {
|
|
19963
|
+
if (!1 !== options?.required) throw new Error("Config loader module not available");
|
|
19964
|
+
// Return empty tokens if config is not required
|
|
19965
|
+
return createTokens({});
|
|
19966
|
+
}
|
|
19967
|
+
const config = loadAtomixConfig({
|
|
19968
|
+
configPath: options?.configPath || "atomix.config.ts",
|
|
19969
|
+
required: !1 !== options?.required
|
|
19970
|
+
});
|
|
19971
|
+
return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
|
|
19972
|
+
}
|
|
19973
|
+
|
|
19974
|
+
/**
|
|
19975
|
+
* Load theme from config file (asynchronous)
|
|
19976
|
+
* @param configPath - Path to config file (default: atomix.config.ts)
|
|
19977
|
+
* @returns Promise resolving to DesignTokens from theme configuration
|
|
19978
|
+
*/ async function loadThemeFromConfig(options) {
|
|
19979
|
+
// Check if we're in a browser environment
|
|
19980
|
+
if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
19981
|
+
// Dynamic import for config loader
|
|
19982
|
+
const {loadAtomixConfig: loadAtomixConfig} = await import("./lib/config/loader"), config = await loadAtomixConfig({
|
|
19983
|
+
configPath: options?.configPath || "atomix.config.ts",
|
|
19984
|
+
required: !1 !== options?.required
|
|
19985
|
+
});
|
|
19986
|
+
return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
|
|
19987
|
+
}
|
|
19988
|
+
|
|
19989
|
+
/**
|
|
19990
|
+
* Check if the provided object is a Theme object
|
|
19991
|
+
* @param theme - Object to check
|
|
19992
|
+
* @returns True if the object is a Theme object, false otherwise
|
|
19993
|
+
*/ function isThemeObject$1(theme) {
|
|
19994
|
+
return "object" == typeof theme && null !== theme;
|
|
19995
|
+
}
|
|
19996
|
+
|
|
19997
|
+
/**
|
|
19998
|
+
* Theme Context
|
|
20935
19999
|
*
|
|
20936
|
-
*
|
|
20937
|
-
|
|
20938
|
-
|
|
20000
|
+
* React context for theme management
|
|
20001
|
+
*/
|
|
20002
|
+
/**
|
|
20003
|
+
* Theme context with default values
|
|
20004
|
+
*/ const ThemeContext = createContext(null);
|
|
20005
|
+
|
|
20006
|
+
ThemeContext.displayName = "ThemeContext";
|
|
20007
|
+
|
|
20008
|
+
/**
|
|
20009
|
+
* Theme Provider
|
|
20939
20010
|
*
|
|
20940
|
-
*
|
|
20941
|
-
*
|
|
20942
|
-
*
|
|
20943
|
-
*
|
|
20944
|
-
*
|
|
20945
|
-
* </ThemeProvider>
|
|
20946
|
-
* );
|
|
20947
|
-
* }
|
|
20011
|
+
* React context provider for theme management with separated concerns.
|
|
20012
|
+
* Simplified version focusing on core functionality:
|
|
20013
|
+
* - String-based themes (CSS files)
|
|
20014
|
+
* - JS Theme objects
|
|
20015
|
+
* - Persistence via localStorage
|
|
20948
20016
|
*
|
|
20949
|
-
*
|
|
20950
|
-
|
|
20951
|
-
|
|
20952
|
-
* <ThemeProvider defaultTheme="dark">
|
|
20953
|
-
* <YourApp />
|
|
20954
|
-
* </ThemeProvider>
|
|
20955
|
-
* );
|
|
20956
|
-
* }
|
|
20957
|
-
* ```
|
|
20958
|
-
*/ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes: themes = {}, basePath: basePath = "/themes", cdnPath: cdnPath = null, preload: preload = [], lazy: lazy = !0, storageKey: storageKey = "atomix-theme", dataAttribute: dataAttribute = "data-theme", enablePersistence: enablePersistence = !0, useMinified: useMinified = !1, onThemeChange: onThemeChange, onError: onError}) => {
|
|
20017
|
+
* Falls back to 'default' theme if no configuration is found.
|
|
20018
|
+
*/
|
|
20019
|
+
const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes: themes = {}, basePath: basePath = "/themes", cdnPath: cdnPath = null, useMinified: useMinified = !1, storageKey: storageKey = "atomix-theme", dataAttribute: dataAttribute = "data-theme", enablePersistence: enablePersistence = !0, onThemeChange: onThemeChange, onError: onError}) => {
|
|
20959
20020
|
// Store callbacks in refs to avoid recreating when they change
|
|
20960
20021
|
const onThemeChangeRef = useRef(onThemeChange), onErrorRef = useRef(onError);
|
|
20961
|
-
// Update
|
|
20022
|
+
// Update ref when callback changes
|
|
20962
20023
|
useEffect((() => {
|
|
20963
20024
|
onThemeChangeRef.current = onThemeChange, onErrorRef.current = onError;
|
|
20964
20025
|
}), [ onThemeChange, onError ]);
|
|
20965
|
-
// Create stable wrapper functions that read from
|
|
20026
|
+
// Create stable wrapper functions that read from ref
|
|
20966
20027
|
const handleThemeChange = useCallback((theme => {
|
|
20967
20028
|
onThemeChangeRef.current?.(theme);
|
|
20968
20029
|
}), []), handleError = useCallback(((error, themeName) => {
|
|
20969
20030
|
onErrorRef.current?.(error, themeName);
|
|
20970
|
-
}), []),
|
|
20971
|
-
// Only update if themes object actually changed (shallow comparison)
|
|
20972
|
-
const currentKeys = Object.keys(themes), prevKeys = Object.keys(themesRef.current);
|
|
20973
|
-
return currentKeys.length !== prevKeys.length || currentKeys.some((key => themes[key] !== themesRef.current[key])) ? (themesRef.current = themes,
|
|
20974
|
-
themes) : themesRef.current;
|
|
20975
|
-
}), [ themes ]), logger = useMemo((() => getLogger()), []), registry = useMemo((() => {
|
|
20976
|
-
const reg = new ThemeRegistry;
|
|
20977
|
-
// Register themes from props
|
|
20978
|
-
if (themesStable && Object.keys(themesStable).length > 0) for (const [themeId, metadata] of Object.entries(themesStable)) reg.has(themeId) || reg.register(themeId, {
|
|
20979
|
-
type: "css",
|
|
20980
|
-
name: metadata.name,
|
|
20981
|
-
class: metadata.class || themeId,
|
|
20982
|
-
description: metadata.description,
|
|
20983
|
-
author: metadata.author,
|
|
20984
|
-
version: metadata.version,
|
|
20985
|
-
tags: metadata.tags,
|
|
20986
|
-
supportsDarkMode: metadata.supportsDarkMode,
|
|
20987
|
-
status: metadata.status,
|
|
20988
|
-
a11y: metadata.a11y,
|
|
20989
|
-
color: metadata.color,
|
|
20990
|
-
features: metadata.features,
|
|
20991
|
-
dependencies: metadata.dependencies
|
|
20992
|
-
});
|
|
20993
|
-
return reg;
|
|
20994
|
-
}), [ themesStable ]), storageAdapter = useMemo((() => ({
|
|
20031
|
+
}), []), storageAdapter = useMemo((() => ({
|
|
20995
20032
|
getItem: key => {
|
|
20996
20033
|
if (isServer()) return null;
|
|
20997
20034
|
try {
|
|
@@ -21023,7 +20060,7 @@ class ThemeApplicator {
|
|
|
21023
20060
|
return !1;
|
|
21024
20061
|
}
|
|
21025
20062
|
}
|
|
21026
|
-
})), []),
|
|
20063
|
+
})), []), initialDefaultTheme = useMemo((() => {
|
|
21027
20064
|
// Check storage first
|
|
21028
20065
|
if (enablePersistence && storageAdapter.isAvailable()) {
|
|
21029
20066
|
const stored = storageAdapter.getItem(storageKey);
|
|
@@ -21031,236 +20068,368 @@ class ThemeApplicator {
|
|
|
21031
20068
|
}
|
|
21032
20069
|
// If defaultTheme is provided, use it
|
|
21033
20070
|
if (null != defaultTheme) return defaultTheme;
|
|
21034
|
-
//
|
|
21035
|
-
|
|
21036
|
-
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
|
|
21042
|
-
|
|
21043
|
-
|
|
21044
|
-
version: meta.version,
|
|
21045
|
-
tags: meta.tags,
|
|
21046
|
-
supportsDarkMode: meta.supportsDarkMode,
|
|
21047
|
-
status: meta.status,
|
|
21048
|
-
a11y: meta.a11y,
|
|
21049
|
-
color: meta.color,
|
|
21050
|
-
features: meta.features,
|
|
21051
|
-
dependencies: meta.dependencies
|
|
21052
|
-
}))))), [isLoading, setIsLoading] = useState(!1), [error, setError] = useState(null), loadedThemesRef = useRef(new Set), previousThemeRef = useRef(null);
|
|
21053
|
-
// Get default theme (with automatic config loading)
|
|
21054
|
-
useCallback((() => {
|
|
21055
|
-
// Check storage first
|
|
21056
|
-
if (enablePersistence && storageAdapter.isAvailable()) {
|
|
21057
|
-
const stored = storageAdapter.getItem(storageKey);
|
|
21058
|
-
if (stored) return stored;
|
|
20071
|
+
// Try to load from atomix.config.ts as fallback, but only in Node.js/SSR environments
|
|
20072
|
+
if ("undefined" == typeof window) try {
|
|
20073
|
+
// Dynamically import the config loader to avoid bundling issues in browser
|
|
20074
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20075
|
+
const {loadThemeFromConfigSync: loadThemeFromConfigSync} = require("../config/configLoader"), configTokens = loadThemeFromConfigSync();
|
|
20076
|
+
if (configTokens && Object.keys(configTokens).length > 0)
|
|
20077
|
+
// For simplicity, we'll treat config tokens as a special theme name
|
|
20078
|
+
return "config-theme";
|
|
20079
|
+
} catch (error) {
|
|
20080
|
+
console.warn("Failed to load theme from config, using default");
|
|
21059
20081
|
}
|
|
21060
|
-
//
|
|
21061
|
-
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
|
|
21075
|
-
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
// Use ThemeApplicator for Theme objects
|
|
21080
|
-
themeApplicator?.applyTheme(theme) : injectCSS$1(createTheme(theme), "atomix-theme"));
|
|
21081
|
-
}), [ activeTheme, themeApplicator ]), setTheme = useCallback((async (theme, options) => {
|
|
21082
|
-
const {removePrevious: removePrevious = !0, fallbackOnError: fallbackOnError = !0, customPath: customPath} = options || {};
|
|
20082
|
+
// Default fallback
|
|
20083
|
+
return "default";
|
|
20084
|
+
}), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = useState((() => initialDefaultTheme)), [activeTheme, setActiveTheme] = useState(null), [isLoading, setIsLoading] = useState(!1), [error, setError] = useState(null), loadedThemesRef = useRef(new Set), themePromisesRef = useRef({});
|
|
20085
|
+
// Apply initial theme attributes to document element
|
|
20086
|
+
useEffect((() => {
|
|
20087
|
+
isServer() || ((dataAttribute, themeName) => {
|
|
20088
|
+
isServer() || (
|
|
20089
|
+
// Set data attribute on body
|
|
20090
|
+
document.body.setAttribute(dataAttribute, themeName),
|
|
20091
|
+
// Also set on documentElement for broader compatibility
|
|
20092
|
+
document.documentElement.setAttribute(dataAttribute, themeName));
|
|
20093
|
+
})(String(currentTheme), dataAttribute);
|
|
20094
|
+
}), [ currentTheme, dataAttribute ]),
|
|
20095
|
+
// Handle theme persistence
|
|
20096
|
+
useEffect((() => {
|
|
20097
|
+
enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
|
|
20098
|
+
}), [ currentTheme, storageKey, enablePersistence ]);
|
|
20099
|
+
// Function to set theme with proper type handling
|
|
20100
|
+
const setTheme = useCallback((async (theme, options) => {
|
|
21083
20101
|
setIsLoading(!0), setError(null);
|
|
21084
20102
|
try {
|
|
21085
|
-
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21089
|
-
|
|
21090
|
-
|
|
21091
|
-
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
if (
|
|
21098
|
-
|
|
21099
|
-
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
|
|
21103
|
-
|
|
21104
|
-
|
|
21105
|
-
|
|
21106
|
-
|
|
21107
|
-
|
|
21108
|
-
|
|
21109
|
-
|
|
21110
|
-
|
|
21111
|
-
|
|
21112
|
-
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
// Try as link ID first, then as theme name
|
|
21124
|
-
let link = document.getElementById(themeNameOrLinkId);
|
|
21125
|
-
if (!link) {
|
|
21126
|
-
const linkId = getThemeLinkId(themeNameOrLinkId);
|
|
21127
|
-
link = document.getElementById(linkId);
|
|
21128
|
-
}
|
|
21129
|
-
link && link.remove();
|
|
21130
|
-
})(previousThemeRef.current),
|
|
21131
|
-
// Load CSS if not already loaded
|
|
21132
|
-
isThemeLoaded(theme) || (await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(theme)),
|
|
21133
|
-
// Apply theme attributes
|
|
21134
|
-
((dataAttribute, themeName) => {
|
|
21135
|
-
isServer() || (
|
|
21136
|
-
// Set data attribute on body
|
|
21137
|
-
document.body.setAttribute(dataAttribute, themeName),
|
|
21138
|
-
// Also set on documentElement for broader compatibility
|
|
21139
|
-
document.documentElement.setAttribute(dataAttribute, themeName));
|
|
21140
|
-
})(dataAttribute, theme),
|
|
21141
|
-
// Update state
|
|
21142
|
-
previousThemeRef.current = currentTheme, setCurrentTheme(theme), setActiveTheme(null),
|
|
21143
|
-
previousThemeRef.current, Date.now(), handleThemeChange(theme),
|
|
21144
|
-
// Persist to storage
|
|
21145
|
-
enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, theme),
|
|
21146
|
-
setIsLoading(!1);
|
|
20103
|
+
let themeName, themeObj = null;
|
|
20104
|
+
// If it's a string theme name, load the associated CSS
|
|
20105
|
+
if ("string" == typeof theme ? themeName = theme :
|
|
20106
|
+
// If it's a Theme object or DesignTokens, we need to process it
|
|
20107
|
+
function(theme) {
|
|
20108
|
+
return "object" == typeof theme && null !== theme && "__isJSTheme" in theme && !0 === theme.__isJSTheme;
|
|
20109
|
+
}(theme) ? (themeObj = theme,
|
|
20110
|
+
// For JS themes, we use a generic name
|
|
20111
|
+
themeName = "js-theme", setActiveTheme(themeObj)) :
|
|
20112
|
+
// For DesignTokens, we might create a theme from tokens
|
|
20113
|
+
themeName = "tokens-theme", "string" == typeof theme && themes[theme]) {
|
|
20114
|
+
// Check if theme is already loading
|
|
20115
|
+
if (themePromisesRef.current[theme]) return await themePromisesRef.current[theme],
|
|
20116
|
+
setCurrentTheme(theme), setActiveTheme(null), void handleThemeChange(theme);
|
|
20117
|
+
// Load CSS theme
|
|
20118
|
+
const themeLoadPromise = new Promise((async (resolve, reject) => {
|
|
20119
|
+
try {
|
|
20120
|
+
if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
|
|
20121
|
+
{
|
|
20122
|
+
// Build CSS path using utility function
|
|
20123
|
+
const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
|
|
20124
|
+
// Remove any previously loaded theme CSS
|
|
20125
|
+
removeCSS(`theme-${String(currentTheme)}`),
|
|
20126
|
+
// Inject new theme CSS
|
|
20127
|
+
await injectCSS$1(cssPath, `theme-${theme}`), loadedThemesRef.current.add(theme),
|
|
20128
|
+
setCurrentTheme(theme), setActiveTheme(null), handleThemeChange(theme), resolve();
|
|
20129
|
+
}
|
|
20130
|
+
} catch (err) {
|
|
20131
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
20132
|
+
setError(error), handleError(error, String(theme)), reject(error);
|
|
20133
|
+
}
|
|
20134
|
+
}));
|
|
20135
|
+
themePromisesRef.current[theme] = themeLoadPromise, await themeLoadPromise;
|
|
20136
|
+
} else themeObj ? (
|
|
20137
|
+
// For JS themes, set them directly
|
|
20138
|
+
setCurrentTheme(themeName), setActiveTheme(themeObj), handleThemeChange(themeObj)) : (
|
|
20139
|
+
// For string theme that isn't in our themes record, just set the name
|
|
20140
|
+
setCurrentTheme(themeName), setActiveTheme(null), handleThemeChange(themeName));
|
|
21147
20141
|
} catch (err) {
|
|
21148
20142
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
21149
|
-
|
|
21150
|
-
|
|
20143
|
+
setError(error), handleError(error, String(theme));
|
|
20144
|
+
} finally {
|
|
20145
|
+
setIsLoading(!1);
|
|
21151
20146
|
}
|
|
21152
|
-
}), [
|
|
21153
|
-
if (
|
|
20147
|
+
}), [ themes, currentTheme, handleThemeChange, handleError, basePath, useMinified, cdnPath ]), isThemeLoaded = useCallback((themeName => loadedThemesRef.current.has(themeName)), []), preloadTheme = useCallback((async themeName => {
|
|
20148
|
+
if (themes[themeName] && !isThemeLoaded(themeName)) {
|
|
21154
20149
|
setIsLoading(!0);
|
|
21155
20150
|
try {
|
|
21156
|
-
|
|
21157
|
-
const
|
|
21158
|
-
|
|
20151
|
+
// Build CSS path using utility function
|
|
20152
|
+
const cssPath = buildThemePath(themeName, basePath, useMinified, cdnPath);
|
|
20153
|
+
// Preload CSS by fetching it
|
|
20154
|
+
await fetch(cssPath), loadedThemesRef.current.add(themeName);
|
|
21159
20155
|
} catch (err) {
|
|
21160
20156
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
21161
|
-
|
|
20157
|
+
setError(error), handleError(error, themeName);
|
|
21162
20158
|
} finally {
|
|
21163
20159
|
setIsLoading(!1);
|
|
21164
20160
|
}
|
|
21165
20161
|
}
|
|
21166
|
-
}), [
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
|
|
21181
|
-
|
|
21182
|
-
|
|
21183
|
-
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
|
|
21188
|
-
|
|
21189
|
-
|
|
21190
|
-
|
|
20162
|
+
}), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = useMemo((() => ({})), []), contextValue = useMemo((() => ({
|
|
20163
|
+
theme: "string" == typeof currentTheme ? currentTheme : "js-theme",
|
|
20164
|
+
activeTheme: activeTheme,
|
|
20165
|
+
setTheme: setTheme,
|
|
20166
|
+
availableThemes: Object.entries(themes).map((([name, metadata]) => ({
|
|
20167
|
+
...metadata
|
|
20168
|
+
}))),
|
|
20169
|
+
isLoading: isLoading,
|
|
20170
|
+
error: error,
|
|
20171
|
+
isThemeLoaded: isThemeLoaded,
|
|
20172
|
+
preloadTheme: preloadTheme,
|
|
20173
|
+
themeManager: themeManager
|
|
20174
|
+
})), [ currentTheme, activeTheme, setTheme, themes, isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
|
|
20175
|
+
// Check if theme is loaded
|
|
20176
|
+
return jsx(ThemeContext.Provider, {
|
|
20177
|
+
value: contextValue,
|
|
20178
|
+
children: children
|
|
20179
|
+
});
|
|
20180
|
+
};
|
|
20181
|
+
|
|
20182
|
+
/**
|
|
20183
|
+
* useTheme Hook
|
|
20184
|
+
*
|
|
20185
|
+
* React hook for accessing theme context
|
|
20186
|
+
*/
|
|
20187
|
+
/**
|
|
20188
|
+
* useTheme hook
|
|
20189
|
+
*
|
|
20190
|
+
* Access theme context and theme management functions
|
|
20191
|
+
*
|
|
20192
|
+
* @example
|
|
20193
|
+
* ```tsx
|
|
20194
|
+
* function MyComponent() {
|
|
20195
|
+
* const { theme, setTheme, availableThemes } = useTheme();
|
|
20196
|
+
*
|
|
20197
|
+
* return (
|
|
20198
|
+
* <div>
|
|
20199
|
+
* <p>Current theme: {theme}</p>
|
|
20200
|
+
* <button onClick={() => setTheme('dark-theme')}>
|
|
20201
|
+
* Switch to Dark
|
|
20202
|
+
* </button>
|
|
20203
|
+
* </div>
|
|
20204
|
+
* );
|
|
20205
|
+
* }
|
|
20206
|
+
* ```
|
|
20207
|
+
*/ function useTheme() {
|
|
20208
|
+
const context = useContext(ThemeContext);
|
|
20209
|
+
if (!context) throw new Error("useTheme must be used within a ThemeProvider");
|
|
20210
|
+
return {
|
|
20211
|
+
theme: context.theme,
|
|
20212
|
+
activeTheme: context.activeTheme,
|
|
20213
|
+
setTheme: context.setTheme,
|
|
20214
|
+
availableThemes: context.availableThemes,
|
|
20215
|
+
isLoading: context.isLoading,
|
|
20216
|
+
error: context.error,
|
|
20217
|
+
isThemeLoaded: context.isThemeLoaded,
|
|
20218
|
+
preloadTheme: context.preloadTheme
|
|
20219
|
+
};
|
|
20220
|
+
}
|
|
20221
|
+
|
|
20222
|
+
function useThemeTokens() {
|
|
20223
|
+
const {theme: theme, activeTheme: activeTheme} = useTheme(), getToken = useCallback(((tokenName, fallback) => {
|
|
20224
|
+
if ("undefined" == typeof window) return fallback || "";
|
|
20225
|
+
const cssVarName = `--atomix-${tokenName}`;
|
|
20226
|
+
return getComputedStyle(document.documentElement).getPropertyValue(cssVarName).trim() || fallback || "";
|
|
20227
|
+
}), []), getThemeValue = useCallback(((path, fallback) => {
|
|
20228
|
+
var _context;
|
|
20229
|
+
return activeTheme && _reduceInstanceProperty(_context = path.split(".")).call(_context, ((obj, key) => obj?.[key]), activeTheme) || fallback;
|
|
20230
|
+
// Navigate through nested theme object using dot notation
|
|
20231
|
+
}), [ activeTheme ]);
|
|
20232
|
+
// Helper function to get CSS variable value
|
|
20233
|
+
// Return unified API for accessing theme values
|
|
20234
|
+
return {
|
|
20235
|
+
theme: theme,
|
|
20236
|
+
activeTheme: activeTheme,
|
|
20237
|
+
getToken: getToken,
|
|
20238
|
+
getThemeValue: getThemeValue,
|
|
20239
|
+
// Commonly used tokens with fallbacks
|
|
20240
|
+
colors: {
|
|
20241
|
+
primary: getToken("primary", "#3b82f6"),
|
|
20242
|
+
secondary: getToken("secondary", "#10b981"),
|
|
20243
|
+
error: getToken("error", "#ef4444"),
|
|
20244
|
+
success: getToken("success", "#22c55e"),
|
|
20245
|
+
warning: getToken("warning", "#eab308"),
|
|
20246
|
+
info: getToken("info", "#3b82f6"),
|
|
20247
|
+
light: getToken("light", "#f9fafb"),
|
|
20248
|
+
dark: getToken("dark", "#111827")
|
|
20249
|
+
},
|
|
20250
|
+
spacing: {
|
|
20251
|
+
1: getToken("spacing-1", "0.25rem"),
|
|
20252
|
+
2: getToken("spacing-2", "0.5rem"),
|
|
20253
|
+
3: getToken("spacing-3", "0.75rem"),
|
|
20254
|
+
4: getToken("spacing-4", "1rem"),
|
|
20255
|
+
5: getToken("spacing-5", "1.25rem"),
|
|
20256
|
+
6: getToken("spacing-6", "1.5rem"),
|
|
20257
|
+
8: getToken("spacing-8", "2rem"),
|
|
20258
|
+
10: getToken("spacing-10", "2.5rem"),
|
|
20259
|
+
12: getToken("spacing-12", "3rem"),
|
|
20260
|
+
16: getToken("spacing-16", "4rem"),
|
|
20261
|
+
20: getToken("spacing-20", "5rem")
|
|
20262
|
+
},
|
|
20263
|
+
borderRadius: {
|
|
20264
|
+
sm: getToken("border-radius-sm", "0.25rem"),
|
|
20265
|
+
md: getToken("border-radius-md", "0.5rem"),
|
|
20266
|
+
lg: getToken("border-radius-lg", "0.75rem"),
|
|
20267
|
+
xl: getToken("border-radius-xl", "1rem"),
|
|
20268
|
+
full: getToken("border-radius-full", "9999px")
|
|
20269
|
+
},
|
|
20270
|
+
typography: {
|
|
20271
|
+
fontFamily: {
|
|
20272
|
+
sans: getToken("font-sans-serif", "Inter, system-ui, sans-serif"),
|
|
20273
|
+
serif: getToken("font-serif", "Georgia, serif"),
|
|
20274
|
+
mono: getToken("font-monospace", "Fira Code, monospace")
|
|
20275
|
+
},
|
|
20276
|
+
fontSize: {
|
|
20277
|
+
xs: getToken("font-size-xs", "0.75rem"),
|
|
20278
|
+
sm: getToken("font-size-sm", "0.875rem"),
|
|
20279
|
+
md: getToken("font-size-md", "1rem"),
|
|
20280
|
+
lg: getToken("font-size-lg", "1.125rem"),
|
|
20281
|
+
xl: getToken("font-size-xl", "1.25rem"),
|
|
20282
|
+
"2xl": getToken("font-size-2xl", "1.5rem"),
|
|
20283
|
+
"3xl": getToken("font-size-3xl", "1.875rem"),
|
|
20284
|
+
"4xl": getToken("font-size-4xl", "2.25rem")
|
|
20285
|
+
},
|
|
20286
|
+
fontWeight: {
|
|
20287
|
+
light: getToken("font-weight-light", "300"),
|
|
20288
|
+
normal: getToken("font-weight-normal", "400"),
|
|
20289
|
+
medium: getToken("font-weight-medium", "500"),
|
|
20290
|
+
semibold: getToken("font-weight-semibold", "600"),
|
|
20291
|
+
bold: getToken("font-weight-bold", "700")
|
|
21191
20292
|
}
|
|
21192
|
-
}
|
|
20293
|
+
},
|
|
20294
|
+
shadows: {
|
|
20295
|
+
sm: getToken("box-shadow-sm", "0 1px 2px 0 rgba(0, 0, 0, 0.05)"),
|
|
20296
|
+
md: getToken("box-shadow-md", "0 4px 6px -1px rgba(0, 0, 0, 0.1)"),
|
|
20297
|
+
lg: getToken("box-shadow-lg", "0 10px 15px -3px rgba(0, 0, 0, 0.1)"),
|
|
20298
|
+
xl: getToken("box-shadow-xl", "0 20px 25px -5px rgba(0, 0, 0, 0.1)"),
|
|
20299
|
+
inset: getToken("box-shadow-inset", "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)")
|
|
20300
|
+
},
|
|
20301
|
+
transitions: {
|
|
20302
|
+
fast: getToken("transition-fast", "150ms"),
|
|
20303
|
+
base: getToken("transition-base", "200ms"),
|
|
20304
|
+
slow: getToken("transition-slow", "300ms")
|
|
20305
|
+
}
|
|
20306
|
+
};
|
|
20307
|
+
}
|
|
20308
|
+
|
|
20309
|
+
/**
|
|
20310
|
+
* Theme System Error Handling
|
|
20311
|
+
*
|
|
20312
|
+
* Centralized error handling for the Atomix theme system.
|
|
20313
|
+
* Provides custom error classes and logging utilities.
|
|
20314
|
+
*/
|
|
20315
|
+
/**
|
|
20316
|
+
* Theme error codes
|
|
20317
|
+
*/ var ThemeErrorCode, LogLevel;
|
|
20318
|
+
|
|
20319
|
+
!function(ThemeErrorCode) {
|
|
20320
|
+
/** Theme not found in registry */
|
|
20321
|
+
ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
|
|
20322
|
+
/** Theme failed to load */
|
|
20323
|
+
ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
|
|
20324
|
+
/** Theme validation failed */
|
|
20325
|
+
ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
|
|
20326
|
+
/** Configuration loading failed */
|
|
20327
|
+
ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
|
|
20328
|
+
/** Configuration validation failed */
|
|
20329
|
+
ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
|
|
20330
|
+
/** Circular dependency detected */
|
|
20331
|
+
ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
|
|
20332
|
+
/** Missing dependency */
|
|
20333
|
+
ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
|
|
20334
|
+
/** Storage operation failed */
|
|
20335
|
+
ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
|
|
20336
|
+
/** Invalid theme name */
|
|
20337
|
+
ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
|
|
20338
|
+
/** CSS injection failed */
|
|
20339
|
+
ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
|
|
20340
|
+
/** Unknown error */
|
|
20341
|
+
ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
|
20342
|
+
}(ThemeErrorCode || (ThemeErrorCode = {}));
|
|
20343
|
+
|
|
20344
|
+
/**
|
|
20345
|
+
* Custom error class for theme-related errors
|
|
20346
|
+
*/
|
|
20347
|
+
class ThemeError extends Error {
|
|
20348
|
+
constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
|
|
20349
|
+
super(message), this.name = "ThemeError", this.code = code, this.context = context,
|
|
20350
|
+
this.timestamp = Date.now(),
|
|
20351
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
20352
|
+
Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
|
|
20353
|
+
}
|
|
20354
|
+
/**
|
|
20355
|
+
* Convert error to JSON for logging
|
|
20356
|
+
*/ toJSON() {
|
|
20357
|
+
return {
|
|
20358
|
+
name: this.name,
|
|
20359
|
+
message: this.message,
|
|
20360
|
+
code: this.code,
|
|
20361
|
+
context: this.context,
|
|
20362
|
+
timestamp: this.timestamp,
|
|
20363
|
+
stack: this.stack
|
|
20364
|
+
};
|
|
21193
20365
|
}
|
|
21194
|
-
|
|
21195
|
-
), []), // Only run once on mount - initialDefaultTheme is stable
|
|
21196
|
-
// Preload themes
|
|
21197
|
-
useEffect((() => {
|
|
21198
|
-
!isServer() && preload && 0 !== preload.length && (async () => {
|
|
21199
|
-
for (const themeName of preload) if (!isThemeLoaded(themeName)) try {
|
|
21200
|
-
await preloadTheme(themeName);
|
|
21201
|
-
} catch (err) {
|
|
21202
|
-
// Silently fail for preload
|
|
21203
|
-
logger.warn(`Failed to preload theme "${themeName}"`, {
|
|
21204
|
-
error: err instanceof Error ? err.message : String(err)
|
|
21205
|
-
});
|
|
21206
|
-
}
|
|
21207
|
-
})();
|
|
21208
|
-
}), [ preload, preloadTheme, logger ]);
|
|
21209
|
-
// Context value
|
|
21210
|
-
const contextValue = useMemo((() => ({
|
|
21211
|
-
theme: currentTheme,
|
|
21212
|
-
activeTheme: activeTheme,
|
|
21213
|
-
setTheme: setTheme,
|
|
21214
|
-
availableThemes: availableThemes,
|
|
21215
|
-
isLoading: isLoading,
|
|
21216
|
-
error: error,
|
|
21217
|
-
isThemeLoaded: isThemeLoaded$1,
|
|
21218
|
-
preloadTheme: preloadTheme
|
|
21219
|
-
})), [ currentTheme, activeTheme, setTheme, availableThemes, isLoading, error, isThemeLoaded$1, preloadTheme ]);
|
|
21220
|
-
return jsx(ThemeContext.Provider, {
|
|
21221
|
-
value: contextValue,
|
|
21222
|
-
children: children
|
|
21223
|
-
});
|
|
21224
|
-
};
|
|
20366
|
+
}
|
|
21225
20367
|
|
|
21226
20368
|
/**
|
|
21227
|
-
*
|
|
20369
|
+
* Log level
|
|
20370
|
+
*/ !function(LogLevel) {
|
|
20371
|
+
LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
|
|
20372
|
+
LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
|
|
20373
|
+
}(LogLevel || (LogLevel = {}));
|
|
20374
|
+
|
|
20375
|
+
/**
|
|
20376
|
+
* Theme Logger
|
|
21228
20377
|
*
|
|
21229
|
-
*
|
|
20378
|
+
* Centralized logging for the theme system.
|
|
20379
|
+
* Replaces console statements with structured logging.
|
|
21230
20380
|
*/
|
|
20381
|
+
class ThemeLogger {
|
|
20382
|
+
constructor(config = {}) {
|
|
20383
|
+
this.config = {
|
|
20384
|
+
level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
|
|
20385
|
+
enableConsole: config.enableConsole ?? !0,
|
|
20386
|
+
onError: config.onError,
|
|
20387
|
+
onWarn: config.onWarn,
|
|
20388
|
+
onInfo: config.onInfo,
|
|
20389
|
+
onDebug: config.onDebug
|
|
20390
|
+
};
|
|
20391
|
+
}
|
|
20392
|
+
/**
|
|
20393
|
+
* Log an error
|
|
20394
|
+
*/ error(message, error, context) {
|
|
20395
|
+
if (this.config.level < LogLevel.ERROR) return;
|
|
20396
|
+
const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
|
|
20397
|
+
this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
|
|
20398
|
+
error: errorObj,
|
|
20399
|
+
context: {
|
|
20400
|
+
...context,
|
|
20401
|
+
...themeError.context
|
|
20402
|
+
},
|
|
20403
|
+
code: themeError.code
|
|
20404
|
+
}), this.config.onError?.(themeError, context);
|
|
20405
|
+
}
|
|
20406
|
+
/**
|
|
20407
|
+
* Log a warning
|
|
20408
|
+
*/ warn(message, context) {
|
|
20409
|
+
this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
|
|
20410
|
+
this.config.onWarn?.(message, context));
|
|
20411
|
+
}
|
|
20412
|
+
/**
|
|
20413
|
+
* Log an info message
|
|
20414
|
+
*/ info(message, context) {
|
|
20415
|
+
this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
|
|
20416
|
+
this.config.onInfo?.(message, context));
|
|
20417
|
+
}
|
|
20418
|
+
/**
|
|
20419
|
+
* Log a debug message
|
|
20420
|
+
*/ debug(message, context) {
|
|
20421
|
+
this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
|
|
20422
|
+
}
|
|
20423
|
+
}
|
|
20424
|
+
|
|
21231
20425
|
/**
|
|
21232
|
-
*
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
*
|
|
21237
|
-
|
|
21238
|
-
|
|
21239
|
-
* const { theme, setTheme, availableThemes } = useTheme();
|
|
21240
|
-
*
|
|
21241
|
-
* return (
|
|
21242
|
-
* <div>
|
|
21243
|
-
* <p>Current theme: {theme}</p>
|
|
21244
|
-
* <button onClick={() => setTheme('dark-theme')}>
|
|
21245
|
-
* Switch to Dark
|
|
21246
|
-
* </button>
|
|
21247
|
-
* </div>
|
|
21248
|
-
* );
|
|
21249
|
-
* }
|
|
21250
|
-
* ```
|
|
21251
|
-
*/ function useTheme() {
|
|
21252
|
-
const context = useContext(ThemeContext);
|
|
21253
|
-
if (!context) throw new Error("useTheme must be used within a ThemeProvider");
|
|
21254
|
-
return {
|
|
21255
|
-
theme: context.theme,
|
|
21256
|
-
activeTheme: context.activeTheme,
|
|
21257
|
-
setTheme: context.setTheme,
|
|
21258
|
-
availableThemes: context.availableThemes,
|
|
21259
|
-
isLoading: context.isLoading,
|
|
21260
|
-
error: context.error,
|
|
21261
|
-
isThemeLoaded: context.isThemeLoaded,
|
|
21262
|
-
preloadTheme: context.preloadTheme
|
|
21263
|
-
};
|
|
20426
|
+
* Default logger instance
|
|
20427
|
+
*/ let defaultLogger = null;
|
|
20428
|
+
|
|
20429
|
+
/**
|
|
20430
|
+
* Get or create default logger
|
|
20431
|
+
*/ function getLogger() {
|
|
20432
|
+
return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
|
|
21264
20433
|
}
|
|
21265
20434
|
|
|
21266
20435
|
/**
|
|
@@ -21311,7 +20480,7 @@ class ThemeApplicator {
|
|
|
21311
20480
|
},
|
|
21312
20481
|
children: JSON.stringify(context, null, 2)
|
|
21313
20482
|
}) ]
|
|
21314
|
-
}), "development" === process.env
|
|
20483
|
+
}), ("undefined" == typeof process || "development" === process.env?.NODE_ENV) && errorInfo && jsxs("details", {
|
|
21315
20484
|
style: {
|
|
21316
20485
|
marginTop: "1rem"
|
|
21317
20486
|
},
|
|
@@ -21407,6 +20576,130 @@ class ThemeApplicator {
|
|
|
21407
20576
|
}
|
|
21408
20577
|
}
|
|
21409
20578
|
|
|
20579
|
+
/**
|
|
20580
|
+
* Theme Applicator
|
|
20581
|
+
*
|
|
20582
|
+
* Applies theme configurations to the DOM, including CSS variables,
|
|
20583
|
+
* component overrides, typography, spacing, and color palettes.
|
|
20584
|
+
*
|
|
20585
|
+
* Uses the unified theme system for CSS generation and injection.
|
|
20586
|
+
*/
|
|
20587
|
+
/**
|
|
20588
|
+
* Theme applicator class for runtime theme application
|
|
20589
|
+
*
|
|
20590
|
+
* Uses the unified theme system for efficient CSS variable generation and injection.
|
|
20591
|
+
*/ class ThemeApplicator {
|
|
20592
|
+
constructor(root = document.documentElement) {
|
|
20593
|
+
this.styleId = "atomix-theme-applicator", this.root = root;
|
|
20594
|
+
}
|
|
20595
|
+
/**
|
|
20596
|
+
* Apply a complete theme configuration
|
|
20597
|
+
*
|
|
20598
|
+
* Uses the unified theme system to convert Theme to DesignTokens and inject CSS.
|
|
20599
|
+
* Automatically respects atomix.config.ts when using DesignTokens.
|
|
20600
|
+
*/ applyTheme(theme) {
|
|
20601
|
+
// Clear previously applied variables
|
|
20602
|
+
this.clearAppliedVars(),
|
|
20603
|
+
// Check if it's DesignTokens
|
|
20604
|
+
this.isDesignTokens(theme) ?
|
|
20605
|
+
// Direct DesignTokens - use unified theme system (with config support)
|
|
20606
|
+
this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
|
|
20607
|
+
selector: ":root",
|
|
20608
|
+
prefix: "atomix"
|
|
20609
|
+
}), this.styleId),
|
|
20610
|
+
// Apply component overrides (only for Theme objects)
|
|
20611
|
+
!this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
|
|
20612
|
+
}
|
|
20613
|
+
/**
|
|
20614
|
+
* Apply DesignTokens using unified theme system
|
|
20615
|
+
*
|
|
20616
|
+
* Uses createTheme() which automatically loads from atomix.config.ts
|
|
20617
|
+
* if no tokens are provided, ensuring config is always respected.
|
|
20618
|
+
*/ applyDesignTokens(tokens) {
|
|
20619
|
+
// Inject CSS into DOM
|
|
20620
|
+
injectCSS$1(createTheme(tokens, {
|
|
20621
|
+
selector: ":root",
|
|
20622
|
+
prefix: "atomix"
|
|
20623
|
+
}), this.styleId);
|
|
20624
|
+
}
|
|
20625
|
+
/**
|
|
20626
|
+
* Check if object is DesignTokens
|
|
20627
|
+
*/ isDesignTokens(obj) {
|
|
20628
|
+
// DesignTokens is a flat object with string keys, no nested structures
|
|
20629
|
+
return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
|
|
20630
|
+
}
|
|
20631
|
+
/**
|
|
20632
|
+
* Apply global CSS variables (for component overrides)
|
|
20633
|
+
*/ applyGlobalCSSVars(vars) {
|
|
20634
|
+
Object.entries(vars).forEach((([key, value]) => {
|
|
20635
|
+
this.root.style.setProperty(key, String(value));
|
|
20636
|
+
}));
|
|
20637
|
+
}
|
|
20638
|
+
/**
|
|
20639
|
+
* Apply component-level overrides
|
|
20640
|
+
*/ applyComponentOverrides(overrides) {
|
|
20641
|
+
Object.entries(overrides).forEach((([componentName, override]) => {
|
|
20642
|
+
override && this.applyComponentOverride(componentName, override);
|
|
20643
|
+
}));
|
|
20644
|
+
}
|
|
20645
|
+
/**
|
|
20646
|
+
* Apply override for a specific component
|
|
20647
|
+
*/ applyComponentOverride(componentName, override) {
|
|
20648
|
+
const vars = {}, componentKey = componentName.toLowerCase();
|
|
20649
|
+
// Apply component-level CSS variables
|
|
20650
|
+
override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
|
|
20651
|
+
// If key doesn't start with --, add component prefix
|
|
20652
|
+
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
|
|
20653
|
+
vars[varKey] = value;
|
|
20654
|
+
})),
|
|
20655
|
+
// Apply part-specific CSS variables
|
|
20656
|
+
override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
|
|
20657
|
+
partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
|
|
20658
|
+
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
|
|
20659
|
+
vars[varKey] = value;
|
|
20660
|
+
}));
|
|
20661
|
+
})),
|
|
20662
|
+
// Apply variant-specific CSS variables
|
|
20663
|
+
override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
|
|
20664
|
+
variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
|
|
20665
|
+
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
|
|
20666
|
+
vars[varKey] = value;
|
|
20667
|
+
}));
|
|
20668
|
+
})), this.applyGlobalCSSVars(vars);
|
|
20669
|
+
}
|
|
20670
|
+
/**
|
|
20671
|
+
* Clear all applied CSS variables
|
|
20672
|
+
*/ clearAppliedVars() {
|
|
20673
|
+
removeCSS(this.styleId);
|
|
20674
|
+
}
|
|
20675
|
+
/**
|
|
20676
|
+
* Remove theme application
|
|
20677
|
+
*/ removeTheme() {
|
|
20678
|
+
this.clearAppliedVars(), removeCSS(this.styleId);
|
|
20679
|
+
}
|
|
20680
|
+
/**
|
|
20681
|
+
* Update specific CSS variables without clearing all
|
|
20682
|
+
*/ updateCSSVars(vars) {
|
|
20683
|
+
this.applyGlobalCSSVars(vars);
|
|
20684
|
+
}
|
|
20685
|
+
}
|
|
20686
|
+
|
|
20687
|
+
/**
|
|
20688
|
+
* Global theme applicator instance
|
|
20689
|
+
*/ let globalApplicator = null;
|
|
20690
|
+
|
|
20691
|
+
/**
|
|
20692
|
+
* Get or create global theme applicator
|
|
20693
|
+
*/ function getThemeApplicator() {
|
|
20694
|
+
return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
|
|
20695
|
+
}
|
|
20696
|
+
|
|
20697
|
+
/**
|
|
20698
|
+
* Apply theme using global applicator
|
|
20699
|
+
*/ function applyTheme(theme) {
|
|
20700
|
+
getThemeApplicator().applyTheme(theme);
|
|
20701
|
+
}
|
|
20702
|
+
|
|
21410
20703
|
const VIEWPORT_PRESETS = {
|
|
21411
20704
|
mobile: {
|
|
21412
20705
|
width: 375,
|
|
@@ -23633,7 +22926,25 @@ class RTLManager {
|
|
|
23633
22926
|
/**
|
|
23634
22927
|
* Save theme to CSS file
|
|
23635
22928
|
*/ async function saveTheme(css, filePath) {
|
|
23636
|
-
await
|
|
22929
|
+
await async function(css, filePath) {
|
|
22930
|
+
// Check if in browser environment
|
|
22931
|
+
if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
|
|
22932
|
+
// Dynamic import to avoid bundling Node.js modules in browser builds
|
|
22933
|
+
const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
|
|
22934
|
+
await fs.mkdir(dir, {
|
|
22935
|
+
recursive: !0
|
|
22936
|
+
}),
|
|
22937
|
+
// Write file
|
|
22938
|
+
await fs.writeFile(filePath, css, "utf8");
|
|
22939
|
+
}
|
|
22940
|
+
/**
|
|
22941
|
+
* Theme System Constants
|
|
22942
|
+
*
|
|
22943
|
+
* Centralized constants for the theme system to avoid magic numbers and strings.
|
|
22944
|
+
*/
|
|
22945
|
+
/**
|
|
22946
|
+
* Default storage key for theme persistence
|
|
22947
|
+
*/ (css, filePath);
|
|
23637
22948
|
}
|
|
23638
22949
|
|
|
23639
22950
|
const themeImport = Object.freeze( Object.defineProperty({
|
|
@@ -23647,13 +22958,16 @@ const themeImport = Object.freeze( Object.defineProperty({
|
|
|
23647
22958
|
ThemeLiveEditor: ThemeLiveEditor,
|
|
23648
22959
|
ThemePreview: ThemePreview,
|
|
23649
22960
|
ThemeProvider: ThemeProvider,
|
|
23650
|
-
ThemeRegistry: ThemeRegistry,
|
|
23651
22961
|
ThemeValidator: ThemeValidator,
|
|
23652
22962
|
applyCSSVariables: applyCSSVariables,
|
|
22963
|
+
applyComponentTheme: applyComponentTheme,
|
|
23653
22964
|
applyTheme: applyTheme,
|
|
22965
|
+
camelToKebab: camelToKebab,
|
|
22966
|
+
clearThemes: clearThemes,
|
|
23654
22967
|
createDesignTokensFromTheme: createDesignTokensFromTheme,
|
|
23655
22968
|
createTheme: createTheme,
|
|
23656
22969
|
createThemeObject: createThemeObject,
|
|
22970
|
+
createThemeRegistry: createThemeRegistry,
|
|
23657
22971
|
createTokens: createTokens,
|
|
23658
22972
|
cssVarsToStyle: cssVarsToStyle,
|
|
23659
22973
|
deepMerge: deepMerge,
|
|
@@ -23665,10 +22979,17 @@ const themeImport = Object.freeze( Object.defineProperty({
|
|
|
23665
22979
|
generateCSSVariableName: generateCSSVariableName,
|
|
23666
22980
|
generateCSSVariables: generateCSSVariables$1,
|
|
23667
22981
|
generateCSSVariablesForSelector: generateCSSVariablesForSelector,
|
|
22982
|
+
generateClassName: generateClassName,
|
|
23668
22983
|
generateComponentCSSVars: generateComponentCSSVars,
|
|
22984
|
+
getAllThemes: getAllThemes,
|
|
23669
22985
|
getCSSVariable: getCSSVariable,
|
|
22986
|
+
getComponentThemeValue: getComponentThemeValue,
|
|
23670
22987
|
getDesignTokensFromTheme: getDesignTokensFromTheme,
|
|
22988
|
+
getTheme: getTheme,
|
|
23671
22989
|
getThemeApplicator: getThemeApplicator,
|
|
22990
|
+
getThemeCount: getThemeCount,
|
|
22991
|
+
getThemeIds: getThemeIds,
|
|
22992
|
+
hasTheme: hasTheme,
|
|
23672
22993
|
injectCSS: injectCSS$1,
|
|
23673
22994
|
injectTheme: injectTheme,
|
|
23674
22995
|
isCSSInjected: isCSSInjected,
|
|
@@ -23680,15 +23001,19 @@ const themeImport = Object.freeze( Object.defineProperty({
|
|
|
23680
23001
|
mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
|
|
23681
23002
|
mergeCSSVars: mergeCSSVars,
|
|
23682
23003
|
mergeTheme: mergeTheme,
|
|
23004
|
+
normalizeThemeTokens: normalizeThemeTokens,
|
|
23005
|
+
registerTheme: registerTheme,
|
|
23683
23006
|
removeCSS: removeCSS,
|
|
23684
23007
|
removeCSSVariables: removeCSSVariables,
|
|
23685
23008
|
removeTheme: removeTheme,
|
|
23686
|
-
saveCSSFile: saveCSSFile,
|
|
23687
|
-
saveCSSFileSync: saveCSSFileSync,
|
|
23688
23009
|
saveTheme: saveTheme,
|
|
23010
|
+
themePropertyToCSSVar: themePropertyToCSSVar,
|
|
23689
23011
|
themeToDesignTokens: themeToDesignTokens,
|
|
23012
|
+
unregisterTheme: unregisterTheme,
|
|
23013
|
+
useComponentTheme: useComponentTheme,
|
|
23690
23014
|
useHistory: useHistory,
|
|
23691
|
-
useTheme: useTheme
|
|
23015
|
+
useTheme: useTheme,
|
|
23016
|
+
useThemeTokens: useThemeTokens
|
|
23692
23017
|
}, Symbol.toStringTag, {
|
|
23693
23018
|
value: "Module"
|
|
23694
23019
|
})), BUTTON_CSS_VARS = {
|
|
@@ -24173,7 +23498,7 @@ function getComponentCSSVars(component) {
|
|
|
24173
23498
|
// Default config
|
|
24174
23499
|
// In browser environments, config loading is not supported
|
|
24175
23500
|
if ("undefined" != typeof window) {
|
|
24176
|
-
if (required) throw new Error("
|
|
23501
|
+
if (required) throw new Error("loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
24177
23502
|
return defaultConfig;
|
|
24178
23503
|
}
|
|
24179
23504
|
// Try to load config file
|
|
@@ -24237,14 +23562,6 @@ function getComponentCSSVars(component) {
|
|
|
24237
23562
|
return null;
|
|
24238
23563
|
}
|
|
24239
23564
|
|
|
24240
|
-
const loader = Object.freeze( Object.defineProperty({
|
|
24241
|
-
__proto__: null,
|
|
24242
|
-
loadAtomixConfig: loadAtomixConfig,
|
|
24243
|
-
resolveConfigPath: resolveConfigPath
|
|
24244
|
-
}, Symbol.toStringTag, {
|
|
24245
|
-
value: "Module"
|
|
24246
|
-
}));
|
|
24247
|
-
|
|
24248
23565
|
/**
|
|
24249
23566
|
* Atomix Configuration System
|
|
24250
23567
|
*
|
|
@@ -24414,5 +23731,5 @@ const atomix = {
|
|
|
24414
23731
|
types: types
|
|
24415
23732
|
};
|
|
24416
23733
|
|
|
24417
|
-
export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AnimatedChart, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DOTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GLASS_CONTAINER, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PhotoViewer, PieChart, Popover, ProductReview, Progress, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider,
|
|
23734
|
+
export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AnimatedChart, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DOTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GLASS_CONTAINER, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PhotoViewer, PieChart, Popover, ProductReview, Progress, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, THEME_NAMING, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeValidator, Todo, Toggle, Tooltip, TreemapChart, UPLOAD, Upload, VIDEO_PLAYER, VideoPlayer, WaterfallChart, applyCSSVariables, applyCSSVarsToStyle, applyComponentTheme, applyPartStyles, applyTheme, camelToKebab, clearThemes, composables, constants, createCSSVarStyle, createDarkVariant, createDebugAttrs, createDesignTokensFromTheme, createFontPreloadLink, createPartProps, createSlotComponent, createSlotProps, createTheme, createThemeObject, createThemeRegistry, createTokens, cssVarsToStyle, deepMerge, atomix as default, defaultTokens, defineConfig, designTokensToCSSVars, designTokensToTheme, exportTheme, extendTheme, extractComponentName, extractYouTubeId, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateClassName, generateComponentCSSVars, generateFontPreloadTags, generateUUID, getAllThemes, getCSSVariable, getComponentCSSVars, getComponentThemeValue, getDesignTokensFromTheme, getPartStyles, getTheme, getThemeApplicator, getThemeCount, getThemeIds, getThemeMetadata, hasCustomization, hasTheme, importTheme, injectCSS$1 as injectCSS, injectTheme, isCSSInjected, isDesignTokens, isSlot, isThemeObject, isValidCSSVariableName, isYouTubeUrl, loadAtomixConfig, loadThemeFromConfig, loadThemeFromConfigSync, mapSCSSTokensToCSSVars, mergeCSSVars, mergeClassNames, mergeComponentProps, mergePartStyles, mergeSlots, mergeTheme, normalizeThemeTokens, preloadFonts, quickTheme, registerTheme, removeCSS, removeCSSVariables, removeTheme, renderSlot, resolveConfigPath, saveTheme, sliderConstants, supportsDarkMode, theme, themePropertyToCSSVar, themeToCSS, themeToDesignTokens, types, unregisterTheme, useAccordion, useAtomixGlass, useBadge, useBarChart, useBlock, useBreadcrumb, useButton, useCard, useChartData, useChartInteraction, useChartScale, useCheckbox, useComponentCustomization, useComponentDefaultProps, useComponentTheme, useDataTable, useEdgePanel, useForm, useFormGroup, useGlassContainer, useHero, useHistory, useInput, useLineChart, useMergedProps, useModal$1 as useModal, useNav, useNavDropdown, useNavItem, useNavbar, usePagination, usePieChart, useRadio, useRiver, useSelect, useSideMenu, useSideMenuItem, useSlider, useSlot, useSpinner, useTextarea, useTheme, useThemeTokens, useTodo, utils, validateTheme };
|
|
24418
23735
|
//# sourceMappingURL=index.esm.js.map
|