@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.js
CHANGED
|
@@ -38,6 +38,11 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
38
38
|
UTILITY: "u-",
|
|
39
39
|
LAYOUT: "l-",
|
|
40
40
|
OBJECT: "o-"
|
|
41
|
+
}, THEME_NAMING = {
|
|
42
|
+
BUTTON_PREFIX: "btn",
|
|
43
|
+
ICON_ELEMENT: "icon",
|
|
44
|
+
LABEL_ELEMENT: "label",
|
|
45
|
+
SPINNER_ELEMENT: "spinner"
|
|
41
46
|
}, BUTTON = {
|
|
42
47
|
BASE_CLASS: "c-btn",
|
|
43
48
|
ICON_CLASS: "c-btn__icon",
|
|
@@ -1910,7 +1915,7 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
|
|
|
1910
1915
|
timestamp: Date.now()
|
|
1911
1916
|
}),
|
|
1912
1917
|
// Development mode: log cache size
|
|
1913
|
-
"production"
|
|
1918
|
+
"undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
|
|
1914
1919
|
})(cacheKey, url), setShaderMapUrl(url);
|
|
1915
1920
|
};
|
|
1916
1921
|
"undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
|
|
@@ -2223,9 +2228,9 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2223
2228
|
childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS && (extractedRadius = childRadius,
|
|
2224
2229
|
extractionSource = "React children");
|
|
2225
2230
|
}
|
|
2226
|
-
null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : process.env
|
|
2231
|
+
null !== extractedRadius && extractedRadius > 0 ? setDynamicCornerRadius(extractedRadius) : "undefined" == typeof process || process.env;
|
|
2227
2232
|
} catch (error) {
|
|
2228
|
-
"production"
|
|
2233
|
+
"undefined" != typeof process && "production" === process.env?.NODE_ENV || !debugCornerRadius || console.error("[AtomixGlass] Error extracting corner radius:", error);
|
|
2229
2234
|
}
|
|
2230
2235
|
};
|
|
2231
2236
|
extractRadius();
|
|
@@ -2300,7 +2305,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2300
2305
|
// For image backgrounds, assume medium luminance
|
|
2301
2306
|
totalLuminance += .5, validSamples++, hasValidBackground = !0);
|
|
2302
2307
|
} catch (styleError) {
|
|
2303
|
-
process.env
|
|
2308
|
+
"undefined" == typeof process || process.env;
|
|
2304
2309
|
}
|
|
2305
2310
|
// Move to parent element for next iteration
|
|
2306
2311
|
if (!currentElement) break;
|
|
@@ -2339,7 +2344,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2339
2344
|
}
|
|
2340
2345
|
} catch (error) {
|
|
2341
2346
|
// Enhanced error logging with context
|
|
2342
|
-
"development"
|
|
2347
|
+
"undefined" != typeof process && "development" !== process.env?.NODE_ENV || console.warn("AtomixGlass: Error detecting background brightness:", error);
|
|
2343
2348
|
const result = !1;
|
|
2344
2349
|
if (element && element.parentElement) {
|
|
2345
2350
|
const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
|
|
@@ -2396,7 +2401,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2396
2401
|
};
|
|
2397
2402
|
// Calculate offset relative to this container
|
|
2398
2403
|
// React 18 automatically batches these updates
|
|
2399
|
-
setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "production"
|
|
2404
|
+
setInternalMouseOffset(newOffset), setInternalGlobalMousePosition(globalPos), "undefined" != typeof process && "production" === process.env?.NODE_ENV || !enablePerformanceMonitoring || performance.now();
|
|
2400
2405
|
}), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveDisableEffects, enablePerformanceMonitoring ]);
|
|
2401
2406
|
// Subscribe to shared mouse tracker
|
|
2402
2407
|
React.useEffect((() => {
|
|
@@ -2536,10 +2541,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2536
2541
|
saturationBoost: validatedSaturationBoost + .4 * mouseInfluence
|
|
2537
2542
|
};
|
|
2538
2543
|
// Validate and apply object config values with proper clamping
|
|
2539
|
-
return process.env
|
|
2544
|
+
return "undefined" == typeof process || process.env, finalConfig;
|
|
2540
2545
|
}
|
|
2541
2546
|
// Debug logging for non-object configs
|
|
2542
|
-
return process.env
|
|
2547
|
+
return "undefined" == typeof process || process.env, baseConfig;
|
|
2543
2548
|
}), [ overLight, getEffectiveOverLight, mouseOffset, isHovered, isActive, validateConfigValue, debugOverLight ]), handleMouseEnter = React.useCallback((() => setIsHovered(!0)), []), handleMouseLeave = React.useCallback((() => setIsHovered(!1)), []), handleMouseDown = React.useCallback((() => setIsActive(!0)), []), handleMouseUp = React.useCallback((() => setIsActive(!1)), []), handleKeyDown = React.useCallback((e => {
|
|
2544
2549
|
!onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
|
|
2545
2550
|
}), [ onClick ]), handleMouseMove = React.useCallback((_e => {}), []);
|
|
@@ -2650,7 +2655,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2650
2655
|
* <div>Content with debug logging enabled</div>
|
|
2651
2656
|
* </AtomixGlass>
|
|
2652
2657
|
*/ 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}) {
|
|
2653
|
-
const glassRef = React.useRef(null), contentRef = React.useRef(null),
|
|
2658
|
+
const glassRef = React.useRef(null), contentRef = React.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({
|
|
2654
2659
|
glassRef: glassRef,
|
|
2655
2660
|
contentRef: contentRef,
|
|
2656
2661
|
cornerRadius: cornerRadius,
|
|
@@ -2667,143 +2672,51 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2667
2672
|
debugOverLight: debugOverLight,
|
|
2668
2673
|
enablePerformanceMonitoring: enablePerformanceMonitoring,
|
|
2669
2674
|
children: children
|
|
2670
|
-
}), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight
|
|
2671
|
-
// Read CSS custom properties once on mount and cache them
|
|
2672
|
-
React.useEffect((() => {
|
|
2673
|
-
if ("undefined" != typeof window && glassRef.current) try {
|
|
2674
|
-
const computedStyle = window.getComputedStyle(glassRef.current);
|
|
2675
|
-
// Cache opacity values
|
|
2676
|
-
if (!opacityCacheRef.current) {
|
|
2677
|
-
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) => {
|
|
2678
|
-
if (!value) return defaultValue;
|
|
2679
|
-
const parsed = parseFloat(value);
|
|
2680
|
-
return isNaN(parsed) ? defaultValue : parsed;
|
|
2681
|
-
};
|
|
2682
|
-
opacityCacheRef.current = {
|
|
2683
|
-
opacity50: parseOpacity(opacity50Value, .5),
|
|
2684
|
-
opacity40: parseOpacity(opacity40Value, .4),
|
|
2685
|
-
opacity80: parseOpacity(opacity80Value, .8),
|
|
2686
|
-
opacity0: parseOpacity(opacity0Value, 0)
|
|
2687
|
-
};
|
|
2688
|
-
}
|
|
2689
|
-
// Cache RGB color values from design tokens
|
|
2690
|
-
if (!rgbCacheRef.current) {
|
|
2691
|
-
// Try to read from design tokens, fallback to defaults
|
|
2692
|
-
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() || "";
|
|
2693
|
-
rgbCacheRef.current = {
|
|
2694
|
-
whiteRgb: whiteRgbValue || "255, 255, 255",
|
|
2695
|
-
// Fallback to white RGB
|
|
2696
|
-
blackRgb: blackRgbValue || "0, 0, 0"
|
|
2697
|
-
};
|
|
2698
|
-
}
|
|
2699
|
-
} catch (error) {
|
|
2700
|
-
// Fallback to defaults if reading fails
|
|
2701
|
-
opacityCacheRef.current || (opacityCacheRef.current = {
|
|
2702
|
-
opacity50: .5,
|
|
2703
|
-
opacity40: .4,
|
|
2704
|
-
opacity80: .8,
|
|
2705
|
-
opacity0: 0
|
|
2706
|
-
}), rgbCacheRef.current || (rgbCacheRef.current = {
|
|
2707
|
-
whiteRgb: "255, 255, 255",
|
|
2708
|
-
blackRgb: "0, 0, 0"
|
|
2709
|
-
});
|
|
2710
|
-
}
|
|
2711
|
-
}), []);
|
|
2712
|
-
// Calculate base style with transforms (only dynamic values)
|
|
2713
|
-
const baseStyle = React.useMemo((() => ({
|
|
2675
|
+
}), isOverLight = overLightConfig.isOverLight, shouldRenderOverLightLayers = enableOverLightLayers && isOverLight, baseStyle = {
|
|
2714
2676
|
...style,
|
|
2715
2677
|
...0 !== elasticity && !effectiveDisableEffects && {
|
|
2716
2678
|
transform: transformStyle
|
|
2717
2679
|
}
|
|
2718
|
-
}
|
|
2719
|
-
position:
|
|
2720
|
-
top:
|
|
2721
|
-
left:
|
|
2722
|
-
}
|
|
2723
|
-
width: "fixed" !==
|
|
2724
|
-
height: "fixed" !==
|
|
2725
|
-
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
}), [ 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 = React.useMemo((() => {
|
|
2759
|
-
// RGB color values for rgba() functions
|
|
2760
|
-
// Note: CSS doesn't support rgba(var(--rgb), opacity) syntax - this is a CSS specification
|
|
2761
|
-
// limitation, not a browser support issue. We read RGB values from design tokens at mount
|
|
2762
|
-
// and cache them for performance. Falls back to defaults if tokens are not available.
|
|
2763
|
-
// Uses design tokens: --atomix-light-rgb / --atomix-white-rgb and --atomix-dark-rgb / --atomix-black-rgb
|
|
2764
|
-
const whiteColor = rgbCacheRef.current?.whiteRgb || "255, 255, 255", blackColor = rgbCacheRef.current?.blackRgb || "0, 0, 0";
|
|
2765
|
-
return {
|
|
2766
|
-
// Standard CSS custom properties for dynamic values
|
|
2767
|
-
"--atomix-glass-radius": `${effectiveCornerRadius}px`,
|
|
2768
|
-
"--atomix-glass-transform": baseStyleTransform || "none",
|
|
2769
|
-
"--atomix-glass-position": positionStylesPosition,
|
|
2770
|
-
"--atomix-glass-top": "fixed" !== positionStylesTop ? `${positionStylesTop}px` : "0",
|
|
2771
|
-
"--atomix-glass-left": "fixed" !== positionStylesLeft ? `${positionStylesLeft}px` : "0",
|
|
2772
|
-
"--atomix-glass-width": "fixed" !== baseStylePosition ? adjustedSizeWidth : `${adjustedSizeWidth}px`,
|
|
2773
|
-
"--atomix-glass-height": "fixed" !== baseStylePosition ? adjustedSizeHeight : `${adjustedSizeHeight}px`,
|
|
2774
|
-
// Border width: Use spacing token for consistency
|
|
2775
|
-
"--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
|
|
2776
|
-
"--atomix-glass-blend-mode": gradientIsOverLight ? "multiply" : "overlay",
|
|
2777
|
-
// Dynamic gradients and backgrounds
|
|
2778
|
-
// Note: RGB values use design token-aligned constants (white: 255,255,255; black: 0,0,0)
|
|
2779
|
-
"--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%)`,
|
|
2780
|
-
"--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%)`,
|
|
2781
|
-
"--atomix-glass-hover-1-opacity": opacityValuesHover1,
|
|
2782
|
-
"--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}%)`,
|
|
2783
|
-
"--atomix-glass-hover-2-opacity": opacityValuesHover2,
|
|
2784
|
-
"--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}%)`,
|
|
2785
|
-
"--atomix-glass-hover-3-opacity": opacityValuesHover3,
|
|
2786
|
-
"--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}%)`,
|
|
2787
|
-
"--atomix-glass-base-opacity": opacityValuesBase,
|
|
2788
|
-
"--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})`,
|
|
2789
|
-
"--atomix-glass-overlay-opacity": opacityValuesOver,
|
|
2790
|
-
"--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})`
|
|
2791
|
-
};
|
|
2792
|
-
}), [
|
|
2793
|
-
// Position styles - only specific properties
|
|
2794
|
-
positionStylesPosition, positionStylesTop, positionStylesLeft,
|
|
2795
|
-
// Adjusted size - only specific properties
|
|
2796
|
-
adjustedSizeWidth, adjustedSizeHeight,
|
|
2797
|
-
// Base style - only transform property
|
|
2798
|
-
baseStyleTransform, baseStylePosition,
|
|
2799
|
-
// Other values
|
|
2800
|
-
effectiveCornerRadius, effectiveReducedMotion,
|
|
2801
|
-
// Gradient calculations - extracted properties
|
|
2802
|
-
gradientIsOverLight, gradientMx, gradientMy, gradientBorderGradientAngle, gradientBorderStop1, gradientBorderStop2, gradientBorderOpacity1, gradientBorderOpacity2, gradientBorderOpacity3, gradientBorderOpacity4, gradientHover1X, gradientHover1Y, gradientHover2X, gradientHover2Y, gradientHover3X, gradientHover3Y, gradientBaseX, gradientBaseY,
|
|
2803
|
-
// Opacity values - extracted properties
|
|
2804
|
-
opacityValuesHover1, opacityValuesHover2, opacityValuesHover3, opacityValuesBase, opacityValuesOver ]);
|
|
2805
|
-
// Build className with state modifiers
|
|
2806
|
-
return jsxRuntime.jsxs("div", {
|
|
2680
|
+
}, 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 = {
|
|
2681
|
+
position: style.position || "absolute",
|
|
2682
|
+
top: style.top || 0,
|
|
2683
|
+
left: style.left || 0
|
|
2684
|
+
}, adjustedSize = {
|
|
2685
|
+
width: "fixed" !== style.position ? "100%" : style.width ? style.width : Math.max(glassSize.width, 0),
|
|
2686
|
+
height: "fixed" !== style.position ? "100%" : style.height ? style.height : Math.max(glassSize.height, 0)
|
|
2687
|
+
}, 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 = {
|
|
2688
|
+
hover1: isHovered || isActive ? .5 : 0,
|
|
2689
|
+
hover2: isActive ? .5 : 0,
|
|
2690
|
+
hover3: isHovered ? .4 : isActive ? .8 : 0,
|
|
2691
|
+
base: isOverLight ? overLightOpacity || .4 : 0,
|
|
2692
|
+
over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
|
|
2693
|
+
}, whiteColor = "255, 255, 255", glassVars = {
|
|
2694
|
+
// Standard CSS custom properties for dynamic values
|
|
2695
|
+
"--atomix-glass-radius": `${effectiveCornerRadius}px`,
|
|
2696
|
+
"--atomix-glass-transform": transformStyle || "none",
|
|
2697
|
+
"--atomix-glass-position": positionStyles.position,
|
|
2698
|
+
"--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
|
|
2699
|
+
"--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
|
|
2700
|
+
"--atomix-glass-width": "fixed" !== style.position ? adjustedSize.width : `${adjustedSize.width}px`,
|
|
2701
|
+
"--atomix-glass-height": "fixed" !== style.position ? adjustedSize.height : `${adjustedSize.height}px`,
|
|
2702
|
+
// Border width: Use spacing token for consistency
|
|
2703
|
+
"--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
|
|
2704
|
+
"--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
|
|
2705
|
+
// Dynamic gradients and backgrounds
|
|
2706
|
+
"--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%)`,
|
|
2707
|
+
"--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%)`,
|
|
2708
|
+
"--atomix-glass-hover-1-opacity": opacityValues.hover1,
|
|
2709
|
+
"--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}%)`,
|
|
2710
|
+
"--atomix-glass-hover-2-opacity": opacityValues.hover2,
|
|
2711
|
+
"--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}%)`,
|
|
2712
|
+
"--atomix-glass-hover-3-opacity": opacityValues.hover3,
|
|
2713
|
+
"--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}%)`,
|
|
2714
|
+
"--atomix-glass-base-opacity": opacityValues.base,
|
|
2715
|
+
"--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})`,
|
|
2716
|
+
"--atomix-glass-overlay-opacity": opacityValues.over,
|
|
2717
|
+
"--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})`
|
|
2718
|
+
};
|
|
2719
|
+
return jsxRuntime.jsxs("div", {
|
|
2807
2720
|
className: componentClassName,
|
|
2808
2721
|
style: glassVars,
|
|
2809
2722
|
role: role || (onClick ? "button" : void 0),
|
|
@@ -3681,11 +3594,103 @@ const Spinner = React.memo((({size: size = "md", variant: variant = "primary",
|
|
|
3681
3594
|
|
|
3682
3595
|
Spinner.displayName = "Spinner";
|
|
3683
3596
|
|
|
3597
|
+
/**
|
|
3598
|
+
* Theme Naming Utility
|
|
3599
|
+
*
|
|
3600
|
+
* Provides consistent naming conventions for CSS classes, CSS variables,
|
|
3601
|
+
* and JavaScript properties throughout the theme system.
|
|
3602
|
+
*/
|
|
3603
|
+
class ThemeNaming {
|
|
3604
|
+
/**
|
|
3605
|
+
* Set the global prefix for all theme tokens
|
|
3606
|
+
* @param newPrefix - New prefix to use
|
|
3607
|
+
*/
|
|
3608
|
+
static setPrefix(newPrefix) {
|
|
3609
|
+
this.prefix = newPrefix;
|
|
3610
|
+
}
|
|
3611
|
+
/**
|
|
3612
|
+
* Get the current prefix
|
|
3613
|
+
*/ static getPrefix() {
|
|
3614
|
+
return this.prefix;
|
|
3615
|
+
}
|
|
3616
|
+
/**
|
|
3617
|
+
* Convert camelCase to kebab-case for CSS variables
|
|
3618
|
+
* @param str - String to convert
|
|
3619
|
+
*/ static camelToKebab(str) {
|
|
3620
|
+
return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
|
|
3621
|
+
}
|
|
3622
|
+
/**
|
|
3623
|
+
* Convert kebab-case to camelCase for JavaScript properties
|
|
3624
|
+
* @param str - String to convert
|
|
3625
|
+
*/ static kebabToCamel(str) {
|
|
3626
|
+
return str.replace(/-([a-z])/g, (g => g[1].toUpperCase()));
|
|
3627
|
+
}
|
|
3628
|
+
/**
|
|
3629
|
+
* Create a CSS variable name
|
|
3630
|
+
* @param token - Token name in camelCase
|
|
3631
|
+
*/ static cssVar(token) {
|
|
3632
|
+
return `--${this.prefix}-${this.camelToKebab(token)}`;
|
|
3633
|
+
}
|
|
3634
|
+
/**
|
|
3635
|
+
* Create a BEM CSS class name
|
|
3636
|
+
* @param block - Block name
|
|
3637
|
+
* @param element - Element name (optional)
|
|
3638
|
+
* @param modifier - Modifier name (optional)
|
|
3639
|
+
*/ static bemClass(block, element, modifier) {
|
|
3640
|
+
let className = `c-${block}`;
|
|
3641
|
+
return element && (className += `__${element}`), modifier && (className += `--${modifier}`),
|
|
3642
|
+
className;
|
|
3643
|
+
}
|
|
3644
|
+
/**
|
|
3645
|
+
* Create a variant class name
|
|
3646
|
+
* @param component - Component name
|
|
3647
|
+
* @param variant - Variant name
|
|
3648
|
+
*/ static variantClass(component, variant) {
|
|
3649
|
+
return `c-${component}--${variant}`;
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* Create a size class name
|
|
3653
|
+
* @param component - Component name
|
|
3654
|
+
* @param size - Size name
|
|
3655
|
+
*/ static sizeClass(component, size) {
|
|
3656
|
+
return `c-${component}--${size}`;
|
|
3657
|
+
}
|
|
3658
|
+
/**
|
|
3659
|
+
* Create a state class name
|
|
3660
|
+
* @param component - Component name
|
|
3661
|
+
* @param state - State name
|
|
3662
|
+
*/ static stateClass(component, state) {
|
|
3663
|
+
return `c-${component}--${state}`;
|
|
3664
|
+
}
|
|
3665
|
+
/**
|
|
3666
|
+
* Create a utility class name
|
|
3667
|
+
* @param utility - Utility name
|
|
3668
|
+
*/ static utilityClass(utility) {
|
|
3669
|
+
return `u-${utility}`;
|
|
3670
|
+
}
|
|
3671
|
+
/**
|
|
3672
|
+
* Create a layout class name
|
|
3673
|
+
* @param layout - Layout name
|
|
3674
|
+
*/ static layoutClass(layout) {
|
|
3675
|
+
return `l-${layout}`;
|
|
3676
|
+
}
|
|
3677
|
+
/**
|
|
3678
|
+
* Create an object class name
|
|
3679
|
+
* @param object - Object name
|
|
3680
|
+
*/ static objectClass(object) {
|
|
3681
|
+
return `o-${object}`;
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
ThemeNaming.prefix = "atomix";
|
|
3686
|
+
|
|
3684
3687
|
const Button = React__default.default.memo( React.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) => {
|
|
3685
|
-
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement =
|
|
3688
|
+
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsxRuntime.jsx(Icon, {
|
|
3686
3689
|
name: iconName,
|
|
3687
3690
|
size: iconSize
|
|
3688
|
-
}) : icon
|
|
3691
|
+
}) : icon;
|
|
3692
|
+
// Determine if we should render as a link
|
|
3693
|
+
useButton({
|
|
3689
3694
|
variant: variant,
|
|
3690
3695
|
size: size,
|
|
3691
3696
|
disabled: isDisabled,
|
|
@@ -3696,20 +3701,8 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
3696
3701
|
block: block,
|
|
3697
3702
|
active: active,
|
|
3698
3703
|
selected: selected
|
|
3699
|
-
})
|
|
3700
|
-
|
|
3701
|
-
size: size,
|
|
3702
|
-
disabled: isDisabled,
|
|
3703
|
-
rounded: rounded,
|
|
3704
|
-
iconOnly: iconOnly,
|
|
3705
|
-
glass: glass,
|
|
3706
|
-
loading: loading,
|
|
3707
|
-
fullWidth: fullWidth,
|
|
3708
|
-
block: block,
|
|
3709
|
-
active: active,
|
|
3710
|
-
selected: selected,
|
|
3711
|
-
className: className
|
|
3712
|
-
})), [ variant, size, isDisabled, rounded, iconOnly, glass, loading, fullWidth, block, active, selected, className, generateButtonClass ]), handleClickEvent = React.useCallback((event => {
|
|
3704
|
+
});
|
|
3705
|
+
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 = React.useCallback((event => {
|
|
3713
3706
|
isDisabled ? event.preventDefault() : onClick?.(event);
|
|
3714
3707
|
}), [ isDisabled, onClick ]), handleMouseEnter = React.useCallback((event => {
|
|
3715
3708
|
isDisabled || onHover?.(event);
|
|
@@ -3717,28 +3710,23 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
3717
3710
|
isDisabled || onFocus?.(event);
|
|
3718
3711
|
}), [ isDisabled, onFocus ]), handleBlurEvent = React.useCallback((event => {
|
|
3719
3712
|
isDisabled || onBlur?.(event);
|
|
3720
|
-
}), [ isDisabled, onBlur ]), buttonText =
|
|
3721
|
-
|
|
3722
|
-
className:
|
|
3723
|
-
"aria-hidden": "true",
|
|
3724
|
-
children: iconElement
|
|
3725
|
-
}), spinnerElement = loading && jsxRuntime.jsx("span", {
|
|
3726
|
-
className: BUTTON.SPINNER_CLASS,
|
|
3713
|
+
}), [ isDisabled, onBlur ]), buttonText = loading && loadingText ? loadingText : label || children, spinnerSize = "sm" === size ? "sm" : "lg" === size ? "md" : "sm", buttonContent = jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
3714
|
+
children: [ loading && jsxRuntime.jsx("span", {
|
|
3715
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
|
|
3727
3716
|
"aria-hidden": "true",
|
|
3728
3717
|
children: jsxRuntime.jsx(Spinner, {
|
|
3729
3718
|
size: spinnerSize,
|
|
3730
3719
|
variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
|
|
3731
3720
|
})
|
|
3732
|
-
}),
|
|
3733
|
-
className:
|
|
3721
|
+
}), iconElement && !loading && jsxRuntime.jsx("span", {
|
|
3722
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
|
|
3723
|
+
"aria-hidden": "true",
|
|
3724
|
+
children: iconElement
|
|
3725
|
+
}), !iconOnly && buttonText && jsxRuntime.jsx("span", {
|
|
3726
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
|
|
3734
3727
|
children: buttonText
|
|
3735
|
-
})
|
|
3736
|
-
|
|
3737
|
-
children: [ labelElement, spinnerElement, iconSpan ]
|
|
3738
|
-
}) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
3739
|
-
children: [ spinnerElement, iconSpan, labelElement ]
|
|
3740
|
-
});
|
|
3741
|
-
}), [ iconElement, iconPosition, iconOnly, buttonText, loading, spinnerSize, variant ]), buttonProps = React.useMemo((() => ({
|
|
3728
|
+
}) ]
|
|
3729
|
+
}), buttonProps = {
|
|
3742
3730
|
ref: ref,
|
|
3743
3731
|
className: buttonClass,
|
|
3744
3732
|
type: "button" !== Component || shouldRenderAsLink ? void 0 : type,
|
|
@@ -3756,8 +3744,16 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
3756
3744
|
tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
|
|
3757
3745
|
style: style,
|
|
3758
3746
|
...props
|
|
3759
|
-
}
|
|
3760
|
-
|
|
3747
|
+
}, defaultGlassProps = {
|
|
3748
|
+
displacementScale: 20,
|
|
3749
|
+
blurAmount: 0,
|
|
3750
|
+
saturation: 200,
|
|
3751
|
+
elasticity: 0
|
|
3752
|
+
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3753
|
+
...defaultGlassProps,
|
|
3754
|
+
...glass
|
|
3755
|
+
};
|
|
3756
|
+
// Handle click with loading check
|
|
3761
3757
|
// Render as anchor if href is provided
|
|
3762
3758
|
if (shouldRenderAsLink) {
|
|
3763
3759
|
const {ref: _, ...buttonPropsWithoutRef} = buttonProps, anchorButtonProps = {
|
|
@@ -3777,22 +3773,10 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
3777
3773
|
...linkProps,
|
|
3778
3774
|
children: buttonContent
|
|
3779
3775
|
});
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
saturation: 200,
|
|
3785
|
-
elasticity: 0
|
|
3786
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3787
|
-
...defaultGlassProps,
|
|
3788
|
-
...glass
|
|
3789
|
-
};
|
|
3790
|
-
return jsxRuntime.jsx(AtomixGlass, {
|
|
3791
|
-
...glassProps,
|
|
3792
|
-
children: linkElement
|
|
3793
|
-
});
|
|
3794
|
-
}
|
|
3795
|
-
return linkElement;
|
|
3776
|
+
return glass ? jsxRuntime.jsx(AtomixGlass, {
|
|
3777
|
+
...glassProps,
|
|
3778
|
+
children: linkElement
|
|
3779
|
+
}) : linkElement;
|
|
3796
3780
|
}
|
|
3797
3781
|
// Fallback to regular anchor tag
|
|
3798
3782
|
const anchorElement = jsxRuntime.jsx("a", {
|
|
@@ -3803,46 +3787,20 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
3803
3787
|
rel: "_blank" === target ? "noopener noreferrer" : void 0,
|
|
3804
3788
|
children: buttonContent
|
|
3805
3789
|
});
|
|
3806
|
-
|
|
3807
|
-
const defaultGlassProps = {
|
|
3808
|
-
displacementScale: 20,
|
|
3809
|
-
blurAmount: 0,
|
|
3810
|
-
saturation: 200,
|
|
3811
|
-
elasticity: 0
|
|
3812
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3813
|
-
...defaultGlassProps,
|
|
3814
|
-
...glass
|
|
3815
|
-
};
|
|
3816
|
-
return jsxRuntime.jsx(AtomixGlass, {
|
|
3817
|
-
...glassProps,
|
|
3818
|
-
children: anchorElement
|
|
3819
|
-
});
|
|
3820
|
-
}
|
|
3821
|
-
return anchorElement;
|
|
3822
|
-
}
|
|
3823
|
-
// Default button rendering
|
|
3824
|
-
if (glass) {
|
|
3825
|
-
const defaultGlassProps = {
|
|
3826
|
-
displacementScale: 20,
|
|
3827
|
-
blurAmount: 0,
|
|
3828
|
-
saturation: 200,
|
|
3829
|
-
elasticity: 0
|
|
3830
|
-
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3831
|
-
...defaultGlassProps,
|
|
3832
|
-
...glass
|
|
3833
|
-
};
|
|
3834
|
-
return jsxRuntime.jsx(AtomixGlass, {
|
|
3790
|
+
return glass ? jsxRuntime.jsx(AtomixGlass, {
|
|
3835
3791
|
...glassProps,
|
|
3836
|
-
children:
|
|
3837
|
-
|
|
3838
|
-
children: buttonContent
|
|
3839
|
-
})
|
|
3840
|
-
});
|
|
3792
|
+
children: anchorElement
|
|
3793
|
+
}) : anchorElement;
|
|
3841
3794
|
}
|
|
3842
|
-
|
|
3795
|
+
// Default button rendering
|
|
3796
|
+
const buttonElement = jsxRuntime.jsx(Component, {
|
|
3843
3797
|
...buttonProps,
|
|
3844
3798
|
children: buttonContent
|
|
3845
3799
|
});
|
|
3800
|
+
return glass ? jsxRuntime.jsx(AtomixGlass, {
|
|
3801
|
+
...glassProps,
|
|
3802
|
+
children: buttonElement
|
|
3803
|
+
}) : buttonElement;
|
|
3846
3804
|
})));
|
|
3847
3805
|
|
|
3848
3806
|
Button.displayName = "Button";
|
|
@@ -11163,62 +11121,6 @@ function useHero(initialProps) {
|
|
|
11163
11121
|
};
|
|
11164
11122
|
}
|
|
11165
11123
|
|
|
11166
|
-
/**
|
|
11167
|
-
* CSS Variable Mapper
|
|
11168
|
-
*
|
|
11169
|
-
* Utilities for generating and managing CSS custom properties from SCSS tokens
|
|
11170
|
-
* and component configurations.
|
|
11171
|
-
*/
|
|
11172
|
-
/**
|
|
11173
|
-
* Generate CSS variable name from parts
|
|
11174
|
-
*
|
|
11175
|
-
* @example
|
|
11176
|
-
* generateCSSVariableName('button', 'bg', { prefix: 'atomix' })
|
|
11177
|
-
* // Returns: '--atomix-button-bg'
|
|
11178
|
-
*/ function generateCSSVariableName(component, property, options = {}) {
|
|
11179
|
-
const {prefix: prefix = "atomix", separator: separator = "-", includeComponent: includeComponent = !0} = options, parts = [ prefix ];
|
|
11180
|
-
return includeComponent && parts.push(component), parts.push(property), `--${parts.join(separator)}`;
|
|
11181
|
-
}
|
|
11182
|
-
|
|
11183
|
-
/**
|
|
11184
|
-
* Generate CSS variables object from configuration
|
|
11185
|
-
*
|
|
11186
|
-
* @example
|
|
11187
|
-
* const vars = generateComponentCSSVars({
|
|
11188
|
-
* component: 'button',
|
|
11189
|
-
* properties: { bg: '#000', color: '#fff' }
|
|
11190
|
-
* })
|
|
11191
|
-
* // Returns: { '--atomix-button-bg': '#000', '--atomix-button-color': '#fff' }
|
|
11192
|
-
*/ function generateComponentCSSVars(config, options = {}) {
|
|
11193
|
-
const vars = {}, {component: component, properties: properties, parts: parts, states: states, variants: variants} = config;
|
|
11194
|
-
// Base properties
|
|
11195
|
-
return Object.entries(properties).forEach((([key, value]) => {
|
|
11196
|
-
const varName = generateCSSVariableName(component, key, options);
|
|
11197
|
-
vars[varName] = String(value);
|
|
11198
|
-
})),
|
|
11199
|
-
// Part properties
|
|
11200
|
-
parts && Object.entries(parts).forEach((([partName, partProps]) => {
|
|
11201
|
-
Object.entries(partProps).forEach((([key, value]) => {
|
|
11202
|
-
const varName = generateCSSVariableName(component, `${partName}-${key}`, options);
|
|
11203
|
-
vars[varName] = String(value);
|
|
11204
|
-
}));
|
|
11205
|
-
})),
|
|
11206
|
-
// State properties
|
|
11207
|
-
states && Object.entries(states).forEach((([stateName, stateProps]) => {
|
|
11208
|
-
Object.entries(stateProps).forEach((([key, value]) => {
|
|
11209
|
-
const varName = generateCSSVariableName(component, `${stateName}-${key}`, options);
|
|
11210
|
-
vars[varName] = String(value);
|
|
11211
|
-
}));
|
|
11212
|
-
})),
|
|
11213
|
-
// Variant properties
|
|
11214
|
-
variants && Object.entries(variants).forEach((([variantName, variantProps]) => {
|
|
11215
|
-
Object.entries(variantProps).forEach((([key, value]) => {
|
|
11216
|
-
const varName = generateCSSVariableName(component, `${variantName}-${key}`, options);
|
|
11217
|
-
vars[varName] = String(value);
|
|
11218
|
-
}));
|
|
11219
|
-
})), vars;
|
|
11220
|
-
}
|
|
11221
|
-
|
|
11222
11124
|
/**
|
|
11223
11125
|
* Map SCSS tokens to CSS custom properties
|
|
11224
11126
|
*
|
|
@@ -11381,7 +11283,7 @@ function mergeComponentProps(baseProps, customization) {
|
|
|
11381
11283
|
/**
|
|
11382
11284
|
* Create data attributes for debugging
|
|
11383
11285
|
*/ function createDebugAttrs(componentName, variant) {
|
|
11384
|
-
return "development" !== process.env
|
|
11286
|
+
return "undefined" == typeof process || "development" !== process.env?.NODE_ENV ? {} : {
|
|
11385
11287
|
"data-component": componentName,
|
|
11386
11288
|
...variant && {
|
|
11387
11289
|
"data-variant": variant
|
|
@@ -18251,6 +18153,7 @@ var components = Object.freeze({
|
|
|
18251
18153
|
TESTIMONIAL: TESTIMONIAL,
|
|
18252
18154
|
TEXTAREA: TEXTAREA,
|
|
18253
18155
|
THEME_COLORS: THEME_COLORS,
|
|
18156
|
+
THEME_NAMING: THEME_NAMING,
|
|
18254
18157
|
TODO: TODO,
|
|
18255
18158
|
TOGGLE: TOGGLE,
|
|
18256
18159
|
TOOLTIP: TOOLTIP,
|
|
@@ -18734,13 +18637,6 @@ const defaultTokens = {
|
|
|
18734
18637
|
* @param coefficient - Amount to emphasize (0-1), default 0.15
|
|
18735
18638
|
* @returns Emphasized hex color
|
|
18736
18639
|
*/
|
|
18737
|
-
/**
|
|
18738
|
-
* Check if a theme is a JS theme (created with createTheme)
|
|
18739
|
-
*/
|
|
18740
|
-
function isJSTheme(theme) {
|
|
18741
|
-
return theme && "object" == typeof theme && !0 === theme.__isJSTheme;
|
|
18742
|
-
}
|
|
18743
|
-
|
|
18744
18640
|
/**
|
|
18745
18641
|
* Theme Adapter
|
|
18746
18642
|
*
|
|
@@ -18760,7 +18656,8 @@ function isJSTheme(theme) {
|
|
|
18760
18656
|
* const tokens = themeToDesignTokens(theme);
|
|
18761
18657
|
* // Returns: { 'primary': '#7c3aed', ... }
|
|
18762
18658
|
* ```
|
|
18763
|
-
*/
|
|
18659
|
+
*/
|
|
18660
|
+
function themeToDesignTokens(theme) {
|
|
18764
18661
|
const tokens = {};
|
|
18765
18662
|
// Convert palette colors
|
|
18766
18663
|
if (theme.palette) {
|
|
@@ -18900,160 +18797,10 @@ function isJSTheme(theme) {
|
|
|
18900
18797
|
};
|
|
18901
18798
|
}
|
|
18902
18799
|
|
|
18903
|
-
/**
|
|
18904
|
-
* Config Loader
|
|
18905
|
-
*
|
|
18906
|
-
* Load design tokens from atomix.config.ts and convert to flat token format.
|
|
18907
|
-
*/
|
|
18908
|
-
/**
|
|
18909
|
-
* Convert nested config tokens to flat DesignTokens format
|
|
18910
|
-
*
|
|
18911
|
-
* Handles conversion from atomix.config.ts structure to flat tokens.
|
|
18912
|
-
* Maps config structure to actual DesignTokens key names.
|
|
18913
|
-
*/ function flattenConfigTokens(tokens, prefix = "atomix") {
|
|
18914
|
-
const flat = {};
|
|
18915
|
-
// Colors
|
|
18916
|
-
return tokens.colors && Object.entries(tokens.colors).forEach((([key, value]) => {
|
|
18917
|
-
var _context;
|
|
18918
|
-
// Simple color: 'primary': '#7AFFD7'
|
|
18919
|
-
// Map directly to DesignTokens keys (e.g., 'primary', 'secondary', 'error')
|
|
18920
|
-
// Only map if it's a valid semantic color key
|
|
18921
|
-
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)
|
|
18922
|
-
// Color scale or palette
|
|
18923
|
-
if ("main" in value) {
|
|
18924
|
-
var _context2;
|
|
18925
|
-
// PaletteColorOptions: { main: '#7AFFD7', light?: '#...', dark?: '#...' }
|
|
18926
|
-
const palette = value, baseKey = key;
|
|
18927
|
-
// Map main to base color (e.g., primary, secondary, error)
|
|
18928
|
-
_includesInstanceProperty(_context2 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context2, key) && (flat[baseKey] = palette.main,
|
|
18929
|
-
// Map light/dark to appropriate scale values
|
|
18930
|
-
// light typically maps to step 3, dark to step 9
|
|
18931
|
-
palette.light && (flat[`${key}-3`] = palette.light), palette.dark && (flat[`${key}-9`] = palette.dark));
|
|
18932
|
-
} else
|
|
18933
|
-
// Color scale: { 1: '#fff', 2: '#eee', ..., 6: '#main', ... }
|
|
18934
|
-
// Or full scale: { 1: '#...', 2: '#...', ..., 10: '#...' }
|
|
18935
|
-
Object.entries(value).forEach((([scaleKey, scaleValue]) => {
|
|
18936
|
-
if ("string" == typeof scaleValue)
|
|
18937
|
-
// Map scale keys to DesignTokens format
|
|
18938
|
-
if ("main" === scaleKey || "6" === scaleKey) {
|
|
18939
|
-
var _context3, _context4;
|
|
18940
|
-
// Main color maps to base key (e.g., 'primary')
|
|
18941
|
-
_includesInstanceProperty(_context3 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context3, key) && (flat[key] = scaleValue),
|
|
18942
|
-
// Also map to step 6 if it's a scale color
|
|
18943
|
-
_includesInstanceProperty(_context4 = [ "primary", "red", "green", "blue", "yellow", "gray" ]).call(_context4, key) && (flat[`${key}-6`] = scaleValue);
|
|
18944
|
-
} else {
|
|
18945
|
-
// Map scale numbers (1-10) to DesignTokens format
|
|
18946
|
-
const scaleNum = parseInt(scaleKey, 10);
|
|
18947
|
-
!isNaN(scaleNum) && scaleNum >= 1 && scaleNum <= 10 && (flat[`${key}-${scaleKey}`] = scaleValue);
|
|
18948
|
-
}
|
|
18949
|
-
}));
|
|
18950
|
-
})),
|
|
18951
|
-
// Spacing
|
|
18952
|
-
tokens.spacing && Object.entries(tokens.spacing).forEach((([key, value]) => {
|
|
18953
|
-
flat[`spacing-${key}`] = String(value);
|
|
18954
|
-
})),
|
|
18955
|
-
// Border Radius
|
|
18956
|
-
tokens.borderRadius && Object.entries(tokens.borderRadius).forEach((([key, value]) => {
|
|
18957
|
-
// Map to DesignTokens format
|
|
18958
|
-
"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);
|
|
18959
|
-
})),
|
|
18960
|
-
// Typography
|
|
18961
|
-
tokens.typography && (
|
|
18962
|
-
// Font Families
|
|
18963
|
-
tokens.typography.fontFamilies && Object.entries(tokens.typography.fontFamilies).forEach((([key, value]) => {
|
|
18964
|
-
// Map to DesignTokens format
|
|
18965
|
-
"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);
|
|
18966
|
-
})),
|
|
18967
|
-
// Font Sizes
|
|
18968
|
-
tokens.typography.fontSizes && Object.entries(tokens.typography.fontSizes).forEach((([key, value]) => {
|
|
18969
|
-
flat[`font-size-${key}`] = String(value);
|
|
18970
|
-
})),
|
|
18971
|
-
// Font Weights
|
|
18972
|
-
tokens.typography.fontWeights && Object.entries(tokens.typography.fontWeights).forEach((([key, value]) => {
|
|
18973
|
-
flat[`font-weight-${key}`] = String(value);
|
|
18974
|
-
})),
|
|
18975
|
-
// Line Heights
|
|
18976
|
-
tokens.typography.lineHeights && Object.entries(tokens.typography.lineHeights).forEach((([key, value]) => {
|
|
18977
|
-
"base" === key || "default" === key ? flat["line-height-base"] = String(value) : flat[`line-height-${key}`] = String(value);
|
|
18978
|
-
}))),
|
|
18979
|
-
// Shadows
|
|
18980
|
-
tokens.shadows && Object.entries(tokens.shadows).forEach((([key, value]) => {
|
|
18981
|
-
flat[`shadow-${key}`] = String(value);
|
|
18982
|
-
})),
|
|
18983
|
-
// Z-Index
|
|
18984
|
-
tokens.zIndex && Object.entries(tokens.zIndex).forEach((([key, value]) => {
|
|
18985
|
-
flat[`z-index-${key}`] = String(value);
|
|
18986
|
-
})),
|
|
18987
|
-
// Transitions
|
|
18988
|
-
tokens.transitions && tokens.transitions.durations && Object.entries(tokens.transitions.durations).forEach((([key, value]) => {
|
|
18989
|
-
flat[`transition-${key}`] = String(value);
|
|
18990
|
-
})), flat;
|
|
18991
|
-
}
|
|
18992
|
-
|
|
18993
|
-
/**
|
|
18994
|
-
* Load theme tokens from atomix.config.ts
|
|
18995
|
-
*
|
|
18996
|
-
* Loads atomix.config.ts and extracts theme tokens.
|
|
18997
|
-
* Config file is required - throws error if not found.
|
|
18998
|
-
*
|
|
18999
|
-
* @param configPath - Optional custom config path (default: 'atomix.config.ts')
|
|
19000
|
-
* @returns Partial DesignTokens from config
|
|
19001
|
-
* @throws Error if config file is not found or cannot be loaded
|
|
19002
|
-
*
|
|
19003
|
-
* @example
|
|
19004
|
-
* ```typescript
|
|
19005
|
-
* const tokens = await loadThemeFromConfig();
|
|
19006
|
-
* const css = createTheme(tokens);
|
|
19007
|
-
* injectTheme(css);
|
|
19008
|
-
* ```
|
|
19009
|
-
*/ async function loadThemeFromConfig(configPath = "atomix.config.ts") {
|
|
19010
|
-
// In browser environments, config loading is not supported
|
|
19011
|
-
if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
19012
|
-
// Load config using the existing loader (required)
|
|
19013
|
-
const {loadAtomixConfig: loadAtomixConfig} = await Promise.resolve().then((function() {
|
|
19014
|
-
return loader;
|
|
19015
|
-
})), config = loadAtomixConfig({
|
|
19016
|
-
configPath: configPath,
|
|
19017
|
-
required: !0
|
|
19018
|
-
});
|
|
19019
|
-
if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
|
|
19020
|
-
// Extract tokens from config
|
|
19021
|
-
const tokens = config.theme.tokens || config.theme.extend || {};
|
|
19022
|
-
if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
|
|
19023
|
-
// Convert nested structure to flat tokens
|
|
19024
|
-
return flattenConfigTokens(tokens, config.prefix || "atomix");
|
|
19025
|
-
}
|
|
19026
|
-
|
|
19027
|
-
/**
|
|
19028
|
-
* Load theme tokens from atomix.config.ts (synchronous version)
|
|
19029
|
-
*
|
|
19030
|
-
* Synchronous version that uses require() instead of dynamic import.
|
|
19031
|
-
* Only works in Node.js environment.
|
|
19032
|
-
* Config file is required - throws error if not found.
|
|
19033
|
-
*
|
|
19034
|
-
* @param configPath - Optional custom config path
|
|
19035
|
-
* @returns Partial DesignTokens from config
|
|
19036
|
-
* @throws Error if config file is not found or cannot be loaded
|
|
19037
|
-
*/ function loadThemeFromConfigSync(configPath = "atomix.config.ts") {
|
|
19038
|
-
// In browser environments, config loading is not supported
|
|
19039
|
-
if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
19040
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
19041
|
-
const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
|
|
19042
|
-
configPath: configPath,
|
|
19043
|
-
required: !0
|
|
19044
|
-
});
|
|
19045
|
-
if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
|
|
19046
|
-
// Extract tokens from config
|
|
19047
|
-
const tokens = config.theme.tokens || config.theme.extend || {};
|
|
19048
|
-
if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
|
|
19049
|
-
// Convert nested structure to flat tokens
|
|
19050
|
-
return flattenConfigTokens(tokens, config.prefix || "atomix");
|
|
19051
|
-
}
|
|
19052
|
-
|
|
19053
18800
|
/**
|
|
19054
18801
|
* Core Theme Functions
|
|
19055
18802
|
*
|
|
19056
|
-
*
|
|
18803
|
+
* Simplified theme system that handles both DesignTokens and Theme objects.
|
|
19057
18804
|
* Config-first approach: loads from atomix.config.ts when no input is provided.
|
|
19058
18805
|
* Config file is required for automatic loading.
|
|
19059
18806
|
*/
|
|
@@ -19087,43 +18834,68 @@ function isJSTheme(theme) {
|
|
|
19087
18834
|
* const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
|
|
19088
18835
|
* ```
|
|
19089
18836
|
*/ function createTheme(input, options) {
|
|
19090
|
-
|
|
19091
|
-
|
|
18837
|
+
// Determine tokens based on input
|
|
18838
|
+
let tokens;
|
|
19092
18839
|
if (input)
|
|
19093
|
-
//
|
|
19094
|
-
tokens =
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
|
|
19098
|
-
|
|
19099
|
-
|
|
19100
|
-
|
|
19101
|
-
|
|
19102
|
-
|
|
19103
|
-
|
|
18840
|
+
// Use DesignTokens directly
|
|
18841
|
+
tokens =
|
|
18842
|
+
// Helper functions to simplify main function
|
|
18843
|
+
function(input) {
|
|
18844
|
+
return !0 === input?.__isJSTheme || input?.palette && input?.typography;
|
|
18845
|
+
}
|
|
18846
|
+
/**
|
|
18847
|
+
* Theme Composition Utilities
|
|
18848
|
+
*
|
|
18849
|
+
* Simplified utilities for composing, merging, and extending themes.
|
|
18850
|
+
*/
|
|
18851
|
+
// ============================================================================
|
|
18852
|
+
// Deep Merge Utility
|
|
18853
|
+
// ============================================================================
|
|
18854
|
+
/**
|
|
18855
|
+
* Check if value is an object
|
|
18856
|
+
*/ (input) ? themeToDesignTokens(input) : input;
|
|
18857
|
+
// Merge with defaults and generate CSS
|
|
18858
|
+
else {
|
|
18859
|
+
// Check if we're in a browser environment
|
|
18860
|
+
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.");
|
|
18861
|
+
// Load from config when no input provided
|
|
18862
|
+
// Using dynamic import in a way that's more compatible with bundlers
|
|
18863
|
+
let loadThemeFromConfigSync, loadAtomixConfig;
|
|
18864
|
+
try {
|
|
18865
|
+
// Use dynamic require but only in Node.js environments
|
|
18866
|
+
// This approach allows bundlers to properly handle external dependencies
|
|
18867
|
+
const configLoaderModule = require("../config/configLoader"), loaderModule = require("../../config/loader");
|
|
18868
|
+
// Get prefix from config if needed
|
|
18869
|
+
if (loadThemeFromConfigSync = configLoaderModule.loadThemeFromConfigSync, loadAtomixConfig = loaderModule.loadAtomixConfig,
|
|
18870
|
+
tokens = loadThemeFromConfigSync(), !options?.prefix) try {
|
|
18871
|
+
const config = loadAtomixConfig({
|
|
18872
|
+
configPath: "atomix.config.ts",
|
|
18873
|
+
required: !1
|
|
18874
|
+
});
|
|
18875
|
+
options = {
|
|
18876
|
+
...options,
|
|
18877
|
+
prefix: config?.prefix || "atomix"
|
|
18878
|
+
};
|
|
18879
|
+
} catch (error) {
|
|
18880
|
+
// If config loading fails, use default prefix
|
|
18881
|
+
options = {
|
|
18882
|
+
...options,
|
|
18883
|
+
prefix: "atomix"
|
|
18884
|
+
};
|
|
18885
|
+
}
|
|
19104
18886
|
} catch (error) {
|
|
19105
|
-
|
|
18887
|
+
throw new Error("createTheme: No input provided and config loading is not available in this environment. Please provide tokens explicitly.");
|
|
19106
18888
|
}
|
|
19107
|
-
tokens = configTokens;
|
|
19108
18889
|
}
|
|
19109
|
-
|
|
19110
|
-
|
|
18890
|
+
const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
|
|
18891
|
+
// Get prefix from options or use default
|
|
18892
|
+
return generateCSSVariables$1(allTokens, {
|
|
19111
18893
|
...options,
|
|
19112
|
-
prefix:
|
|
18894
|
+
prefix: prefix
|
|
19113
18895
|
});
|
|
19114
18896
|
}
|
|
19115
18897
|
|
|
19116
|
-
|
|
19117
|
-
* Theme Composition Utilities
|
|
19118
|
-
*
|
|
19119
|
-
* Utilities for composing, merging, and extending themes.
|
|
19120
|
-
*/
|
|
19121
|
-
// ============================================================================
|
|
19122
|
-
// Deep Merge Utility
|
|
19123
|
-
// ============================================================================
|
|
19124
|
-
/**
|
|
19125
|
-
* Check if value is an object
|
|
19126
|
-
*/ function isObject(item) {
|
|
18898
|
+
function isObject(item) {
|
|
19127
18899
|
return item && "object" == typeof item && !Array.isArray(item) && "function" != typeof item;
|
|
19128
18900
|
}
|
|
19129
18901
|
|
|
@@ -19182,65 +18954,14 @@ function isJSTheme(theme) {
|
|
|
19182
18954
|
* });
|
|
19183
18955
|
* ```
|
|
19184
18956
|
*/ function extendTheme(baseTheme, extension) {
|
|
19185
|
-
|
|
19186
|
-
|
|
19187
|
-
|
|
19188
|
-
* Extract theme options from a complete Theme object
|
|
19189
|
-
*/
|
|
19190
|
-
function(theme) {
|
|
19191
|
-
return {
|
|
19192
|
-
name: theme.name,
|
|
19193
|
-
class: theme.class,
|
|
19194
|
-
description: theme.description,
|
|
19195
|
-
author: theme.author,
|
|
19196
|
-
version: theme.version,
|
|
19197
|
-
tags: theme.tags,
|
|
19198
|
-
supportsDarkMode: theme.supportsDarkMode,
|
|
19199
|
-
status: theme.status,
|
|
19200
|
-
a11y: theme.a11y,
|
|
19201
|
-
color: theme.color,
|
|
19202
|
-
features: theme.features,
|
|
19203
|
-
dependencies: theme.dependencies,
|
|
19204
|
-
palette: {
|
|
19205
|
-
primary: theme.palette.primary,
|
|
19206
|
-
secondary: theme.palette.secondary,
|
|
19207
|
-
error: theme.palette.error,
|
|
19208
|
-
warning: theme.palette.warning,
|
|
19209
|
-
info: theme.palette.info,
|
|
19210
|
-
success: theme.palette.success,
|
|
19211
|
-
background: theme.palette.background,
|
|
19212
|
-
text: theme.palette.text
|
|
19213
|
-
},
|
|
19214
|
-
typography: {
|
|
19215
|
-
fontFamily: theme.typography.fontFamily,
|
|
19216
|
-
fontSize: theme.typography.fontSize,
|
|
19217
|
-
fontWeightLight: theme.typography.fontWeightLight,
|
|
19218
|
-
fontWeightRegular: theme.typography.fontWeightRegular,
|
|
19219
|
-
fontWeightMedium: theme.typography.fontWeightMedium,
|
|
19220
|
-
fontWeightSemiBold: theme.typography.fontWeightSemiBold,
|
|
19221
|
-
fontWeightBold: theme.typography.fontWeightBold,
|
|
19222
|
-
h1: theme.typography.h1,
|
|
19223
|
-
h2: theme.typography.h2,
|
|
19224
|
-
h3: theme.typography.h3,
|
|
19225
|
-
h4: theme.typography.h4,
|
|
19226
|
-
h5: theme.typography.h5,
|
|
19227
|
-
h6: theme.typography.h6,
|
|
19228
|
-
body1: theme.typography.body1,
|
|
19229
|
-
body2: theme.typography.body2
|
|
19230
|
-
},
|
|
19231
|
-
shadows: theme.shadows,
|
|
19232
|
-
transitions: theme.transitions,
|
|
19233
|
-
zIndex: theme.zIndex,
|
|
19234
|
-
custom: theme.custom
|
|
19235
|
-
};
|
|
19236
|
-
}
|
|
19237
|
-
// ============================================================================
|
|
19238
|
-
// Default Theme Values
|
|
19239
|
-
// ============================================================================
|
|
19240
|
-
(baseTheme) : baseTheme;
|
|
19241
|
-
return createThemeObject(mergeTheme(baseOptions, extension));
|
|
18957
|
+
return createThemeObject(mergeTheme(baseTheme.__isJSTheme ? {
|
|
18958
|
+
...baseTheme
|
|
18959
|
+
} : baseTheme, extension));
|
|
19242
18960
|
}
|
|
19243
18961
|
|
|
18962
|
+
// ============================================================================
|
|
18963
|
+
// Default Theme Values
|
|
18964
|
+
// ============================================================================
|
|
19244
18965
|
const DEFAULT_PALETTE = {
|
|
19245
18966
|
primary: {
|
|
19246
18967
|
main: "#7c3aed",
|
|
@@ -19502,7 +19223,10 @@ function createThemeObject(...options) {
|
|
|
19502
19223
|
"number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
|
|
19503
19224
|
// If it's an array, use it as a scale
|
|
19504
19225
|
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(" ");
|
|
19505
|
-
}
|
|
19226
|
+
}
|
|
19227
|
+
/**
|
|
19228
|
+
* Check if a theme is a JS theme (created with createTheme)
|
|
19229
|
+
*/ (mergedOptions.spacing), breakpoints = function(breakpointsInput) {
|
|
19506
19230
|
const values = {
|
|
19507
19231
|
xs: 0,
|
|
19508
19232
|
sm: 576,
|
|
@@ -19562,694 +19286,71 @@ function createThemeObject(...options) {
|
|
|
19562
19286
|
}
|
|
19563
19287
|
|
|
19564
19288
|
/**
|
|
19565
|
-
*
|
|
19566
|
-
|
|
19567
|
-
|
|
19568
|
-
|
|
19289
|
+
* Create a new theme registry
|
|
19290
|
+
*/ function createThemeRegistry() {
|
|
19291
|
+
return {};
|
|
19292
|
+
}
|
|
19293
|
+
|
|
19569
19294
|
/**
|
|
19570
|
-
*
|
|
19571
|
-
*
|
|
19572
|
-
* @param
|
|
19573
|
-
* @
|
|
19574
|
-
*/
|
|
19295
|
+
* Register a theme
|
|
19296
|
+
* @param registry - Theme registry object
|
|
19297
|
+
* @param id - Theme identifier
|
|
19298
|
+
* @param metadata - Theme metadata
|
|
19299
|
+
*/ function registerTheme(registry, id, metadata) {
|
|
19300
|
+
registry[id] = metadata;
|
|
19301
|
+
}
|
|
19302
|
+
|
|
19575
19303
|
/**
|
|
19576
|
-
*
|
|
19577
|
-
|
|
19578
|
-
|
|
19579
|
-
|
|
19580
|
-
|
|
19581
|
-
|
|
19582
|
-
return {
|
|
19583
|
-
valid: 0 === errors.length,
|
|
19584
|
-
errors: errors,
|
|
19585
|
-
warnings: []
|
|
19586
|
-
};
|
|
19304
|
+
* Unregister a theme
|
|
19305
|
+
* @param registry - Theme registry object
|
|
19306
|
+
* @param id - Theme identifier
|
|
19307
|
+
*/ function unregisterTheme(registry, id) {
|
|
19308
|
+
const exists = id in registry;
|
|
19309
|
+
return delete registry[id], exists;
|
|
19587
19310
|
}
|
|
19588
19311
|
|
|
19589
19312
|
/**
|
|
19590
|
-
*
|
|
19591
|
-
|
|
19592
|
-
|
|
19593
|
-
|
|
19594
|
-
return
|
|
19595
|
-
{
|
|
19596
|
-
valid: 0 === errors.length,
|
|
19597
|
-
errors: errors,
|
|
19598
|
-
warnings: []
|
|
19599
|
-
};
|
|
19313
|
+
* Check if a theme is registered
|
|
19314
|
+
* @param registry - Theme registry object
|
|
19315
|
+
* @param id - Theme identifier
|
|
19316
|
+
*/ function hasTheme(registry, id) {
|
|
19317
|
+
return id in registry;
|
|
19600
19318
|
}
|
|
19601
19319
|
|
|
19602
19320
|
/**
|
|
19603
|
-
*
|
|
19604
|
-
|
|
19321
|
+
* Get theme metadata
|
|
19322
|
+
* @param registry - Theme registry object
|
|
19323
|
+
* @param id - Theme identifier
|
|
19324
|
+
*/ function getTheme(registry, id) {
|
|
19325
|
+
return registry[id];
|
|
19326
|
+
}
|
|
19327
|
+
|
|
19605
19328
|
/**
|
|
19606
|
-
*
|
|
19607
|
-
*
|
|
19608
|
-
|
|
19609
|
-
|
|
19610
|
-
*/
|
|
19611
|
-
/**
|
|
19612
|
-
* Theme error codes
|
|
19613
|
-
*/
|
|
19614
|
-
var ThemeErrorCode, LogLevel;
|
|
19615
|
-
|
|
19616
|
-
!function(ThemeErrorCode) {
|
|
19617
|
-
/** Theme not found in registry */
|
|
19618
|
-
ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
|
|
19619
|
-
/** Theme failed to load */
|
|
19620
|
-
ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
|
|
19621
|
-
/** Theme validation failed */
|
|
19622
|
-
ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
|
|
19623
|
-
/** Configuration loading failed */
|
|
19624
|
-
ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
|
|
19625
|
-
/** Configuration validation failed */
|
|
19626
|
-
ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
|
|
19627
|
-
/** Circular dependency detected */
|
|
19628
|
-
ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
|
|
19629
|
-
/** Missing dependency */
|
|
19630
|
-
ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
|
|
19631
|
-
/** Storage operation failed */
|
|
19632
|
-
ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
|
|
19633
|
-
/** Invalid theme name */
|
|
19634
|
-
ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
|
|
19635
|
-
/** CSS injection failed */
|
|
19636
|
-
ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
|
|
19637
|
-
/** Unknown error */
|
|
19638
|
-
ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
|
19639
|
-
}(ThemeErrorCode || (ThemeErrorCode = {}));
|
|
19640
|
-
|
|
19641
|
-
/**
|
|
19642
|
-
* Custom error class for theme-related errors
|
|
19643
|
-
*/
|
|
19644
|
-
class ThemeError extends Error {
|
|
19645
|
-
constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
|
|
19646
|
-
super(message), this.name = "ThemeError", this.code = code, this.context = context,
|
|
19647
|
-
this.timestamp = Date.now(),
|
|
19648
|
-
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
19649
|
-
Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
|
|
19650
|
-
}
|
|
19651
|
-
/**
|
|
19652
|
-
* Convert error to JSON for logging
|
|
19653
|
-
*/ toJSON() {
|
|
19654
|
-
return {
|
|
19655
|
-
name: this.name,
|
|
19656
|
-
message: this.message,
|
|
19657
|
-
code: this.code,
|
|
19658
|
-
context: this.context,
|
|
19659
|
-
timestamp: this.timestamp,
|
|
19660
|
-
stack: this.stack
|
|
19661
|
-
};
|
|
19662
|
-
}
|
|
19329
|
+
* Get all registered theme metadata
|
|
19330
|
+
* @param registry - Theme registry object
|
|
19331
|
+
*/ function getAllThemes(registry) {
|
|
19332
|
+
return Object.values(registry);
|
|
19663
19333
|
}
|
|
19664
19334
|
|
|
19665
19335
|
/**
|
|
19666
|
-
*
|
|
19667
|
-
|
|
19668
|
-
|
|
19669
|
-
|
|
19670
|
-
}(LogLevel || (LogLevel = {}));
|
|
19671
|
-
|
|
19672
|
-
/**
|
|
19673
|
-
* Theme Logger
|
|
19674
|
-
*
|
|
19675
|
-
* Centralized logging for the theme system.
|
|
19676
|
-
* Replaces console statements with structured logging.
|
|
19677
|
-
*/
|
|
19678
|
-
class ThemeLogger {
|
|
19679
|
-
constructor(config = {}) {
|
|
19680
|
-
this.config = {
|
|
19681
|
-
level: config.level ?? ("production" === process.env.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
|
|
19682
|
-
enableConsole: config.enableConsole ?? !0,
|
|
19683
|
-
onError: config.onError,
|
|
19684
|
-
onWarn: config.onWarn,
|
|
19685
|
-
onInfo: config.onInfo,
|
|
19686
|
-
onDebug: config.onDebug
|
|
19687
|
-
};
|
|
19688
|
-
}
|
|
19689
|
-
/**
|
|
19690
|
-
* Log an error
|
|
19691
|
-
*/ error(message, error, context) {
|
|
19692
|
-
if (this.config.level < LogLevel.ERROR) return;
|
|
19693
|
-
const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
|
|
19694
|
-
this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
|
|
19695
|
-
error: errorObj,
|
|
19696
|
-
context: {
|
|
19697
|
-
...context,
|
|
19698
|
-
...themeError.context
|
|
19699
|
-
},
|
|
19700
|
-
code: themeError.code
|
|
19701
|
-
}), this.config.onError?.(themeError, context);
|
|
19702
|
-
}
|
|
19703
|
-
/**
|
|
19704
|
-
* Log a warning
|
|
19705
|
-
*/ warn(message, context) {
|
|
19706
|
-
this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
|
|
19707
|
-
this.config.onWarn?.(message, context));
|
|
19708
|
-
}
|
|
19709
|
-
/**
|
|
19710
|
-
* Log an info message
|
|
19711
|
-
*/ info(message, context) {
|
|
19712
|
-
this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
|
|
19713
|
-
this.config.onInfo?.(message, context));
|
|
19714
|
-
}
|
|
19715
|
-
/**
|
|
19716
|
-
* Log a debug message
|
|
19717
|
-
*/ debug(message, context) {
|
|
19718
|
-
this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
|
|
19719
|
-
}
|
|
19336
|
+
* Get all registered theme IDs
|
|
19337
|
+
* @param registry - Theme registry object
|
|
19338
|
+
*/ function getThemeIds(registry) {
|
|
19339
|
+
return Object.keys(registry);
|
|
19720
19340
|
}
|
|
19721
19341
|
|
|
19722
19342
|
/**
|
|
19723
|
-
*
|
|
19724
|
-
|
|
19725
|
-
|
|
19726
|
-
|
|
19727
|
-
* Get or create default logger
|
|
19728
|
-
*/ function getLogger() {
|
|
19729
|
-
return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
|
|
19343
|
+
* Clear all registered themes
|
|
19344
|
+
* @param registry - Theme registry object
|
|
19345
|
+
*/ function clearThemes(registry) {
|
|
19346
|
+
Object.keys(registry).forEach((key => delete registry[key]));
|
|
19730
19347
|
}
|
|
19731
19348
|
|
|
19732
19349
|
/**
|
|
19733
|
-
*
|
|
19734
|
-
*
|
|
19735
|
-
|
|
19736
|
-
|
|
19737
|
-
/**
|
|
19738
|
-
* Default storage key for theme persistence
|
|
19739
|
-
*/ const DEFAULT_ATOMIX_CONFIG_PATH = "atomix.config.ts";
|
|
19740
|
-
|
|
19741
|
-
/**
|
|
19742
|
-
* Default data attribute name for theme
|
|
19743
|
-
*/ process.env.NODE_ENV;
|
|
19744
|
-
|
|
19745
|
-
/**
|
|
19746
|
-
* Integration default class names
|
|
19747
|
-
*/
|
|
19748
|
-
const DEFAULT_INTEGRATION_CLASS_NAMES = {
|
|
19749
|
-
theme: "data-theme",
|
|
19750
|
-
colorMode: "data-atomix-color-mode"
|
|
19751
|
-
}, DEFAULT_INTEGRATION_CSS_VARIABLES = {
|
|
19752
|
-
colorMode: "--storybook-color-mode"
|
|
19753
|
-
}, DEFAULT_SASS_CONFIG = {
|
|
19754
|
-
style: "expanded",
|
|
19755
|
-
sourceMap: !0,
|
|
19756
|
-
loadPaths: [ "src" ]
|
|
19757
|
-
};
|
|
19758
|
-
|
|
19759
|
-
/**
|
|
19760
|
-
* Integration default CSS variables
|
|
19761
|
-
*/
|
|
19762
|
-
/**
|
|
19763
|
-
* Theme Configuration Loader
|
|
19764
|
-
*
|
|
19765
|
-
* Loads and validates the theme configuration from atomix.config.ts
|
|
19766
|
-
*/
|
|
19767
|
-
/**
|
|
19768
|
-
* Cache for loaded configuration
|
|
19769
|
-
*/
|
|
19770
|
-
let cachedConfig = null;
|
|
19771
|
-
|
|
19772
|
-
/**
|
|
19773
|
-
* Logger instance
|
|
19774
|
-
*/ const logger = getLogger();
|
|
19775
|
-
|
|
19776
|
-
/**
|
|
19777
|
-
* Load theme configuration from atomix.config.ts
|
|
19778
|
-
*
|
|
19779
|
-
* @param options - Loader options
|
|
19780
|
-
* @returns Loaded and validated theme configuration
|
|
19781
|
-
*
|
|
19782
|
-
* @example
|
|
19783
|
-
* ```typescript
|
|
19784
|
-
* import { loadThemeConfig } from '@shohojdhara/atomix/theme/config';
|
|
19785
|
-
* const config = loadThemeConfig();
|
|
19786
|
-
* ```
|
|
19787
|
-
*/
|
|
19788
|
-
/**
|
|
19789
|
-
* Theme Registry
|
|
19790
|
-
*
|
|
19791
|
-
* Manages theme registration, discovery, and dependency resolution
|
|
19792
|
-
*/
|
|
19793
|
-
class ThemeRegistry {
|
|
19794
|
-
constructor() {
|
|
19795
|
-
this.entries = new Map, this.config = null, this.initialized = !1;
|
|
19796
|
-
}
|
|
19797
|
-
/**
|
|
19798
|
-
* Initialize registry from config
|
|
19799
|
-
*/ async initialize(config) {
|
|
19800
|
-
if (!this.initialized) {
|
|
19801
|
-
// Load config if not provided
|
|
19802
|
-
if (config) this.config = config; else try {
|
|
19803
|
-
this.config = function(options = {}) {
|
|
19804
|
-
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;
|
|
19805
|
-
// Return cached config if available
|
|
19806
|
-
if (cachedConfig) return cachedConfig;
|
|
19807
|
-
// Try to load config dynamically
|
|
19808
|
-
let config;
|
|
19809
|
-
try {
|
|
19810
|
-
// In browser/Vite environment, we can't load config dynamically
|
|
19811
|
-
if ("undefined" != typeof window) throw new Error("Theme config loading not supported in browser environment");
|
|
19812
|
-
// In ESM environments, require might be undefined.
|
|
19813
|
-
let nodeRequire, configModule;
|
|
19814
|
-
try {
|
|
19815
|
-
nodeRequire = require;
|
|
19816
|
-
} catch {
|
|
19817
|
-
// require is not defined
|
|
19818
|
-
}
|
|
19819
|
-
if (!nodeRequire) throw new Error("Theme config loading not supported in this environment (require is undefined)");
|
|
19820
|
-
// Try require (Node.js/CommonJS)
|
|
19821
|
-
try {
|
|
19822
|
-
// Try relative path first
|
|
19823
|
-
try {
|
|
19824
|
-
configModule = nodeRequire("../../../../atomix.config");
|
|
19825
|
-
} catch {
|
|
19826
|
-
// If relative path fails, try to resolve from process.cwd()
|
|
19827
|
-
const path = nodeRequire("path"), fs = nodeRequire("fs");
|
|
19828
|
-
let configFilePath = path.resolve(process.cwd(), configPath);
|
|
19829
|
-
// If atomix.config.ts not found at the root, use the default path
|
|
19830
|
-
if (fs.existsSync(configFilePath) || configPath !== DEFAULT_ATOMIX_CONFIG_PATH || (configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH)),
|
|
19831
|
-
!fs.existsSync(configFilePath)) throw new Error(`Config file not found: ${configFilePath}`);
|
|
19832
|
-
{
|
|
19833
|
-
const resolvedPath = nodeRequire.resolve(configFilePath);
|
|
19834
|
-
nodeRequire.cache && nodeRequire.cache[resolvedPath] && delete nodeRequire.cache[resolvedPath],
|
|
19835
|
-
configModule = nodeRequire(configFilePath);
|
|
19836
|
-
}
|
|
19837
|
-
}
|
|
19838
|
-
} catch (requireError) {
|
|
19839
|
-
const errorMessage = requireError instanceof Error ? requireError.message : String(requireError);
|
|
19840
|
-
throw new ThemeError(`Cannot load config: ${errorMessage}`, ThemeErrorCode.CONFIG_LOAD_FAILED, {
|
|
19841
|
-
configPath: configPath,
|
|
19842
|
-
error: errorMessage
|
|
19843
|
-
});
|
|
19844
|
-
}
|
|
19845
|
-
const rawConfig = configModule.default || configModule, finalConfig =
|
|
19846
|
-
/**
|
|
19847
|
-
* Apply environment-specific overrides to configuration
|
|
19848
|
-
*
|
|
19849
|
-
* @param config - Base configuration
|
|
19850
|
-
* @param env - Environment name
|
|
19851
|
-
* @returns Configuration with environment overrides applied
|
|
19852
|
-
*/
|
|
19853
|
-
function(config, env) {
|
|
19854
|
-
const overridden = {
|
|
19855
|
-
...config
|
|
19856
|
-
};
|
|
19857
|
-
// Production overrides
|
|
19858
|
-
return "production" === env && overridden.runtime && (overridden.runtime = {
|
|
19859
|
-
...overridden.runtime,
|
|
19860
|
-
useMinified: !0,
|
|
19861
|
-
lazy: !0
|
|
19862
|
-
}),
|
|
19863
|
-
// Development overrides
|
|
19864
|
-
"development" === env && (overridden.runtime && (overridden.runtime = {
|
|
19865
|
-
...overridden.runtime,
|
|
19866
|
-
useMinified: !1,
|
|
19867
|
-
lazy: !1
|
|
19868
|
-
}), overridden.build && (overridden.build = {
|
|
19869
|
-
...overridden.build,
|
|
19870
|
-
sass: {
|
|
19871
|
-
...overridden.build.sass,
|
|
19872
|
-
sourceMap: !0
|
|
19873
|
-
}
|
|
19874
|
-
})),
|
|
19875
|
-
// Test overrides
|
|
19876
|
-
"test" === env && overridden.runtime && (overridden.runtime = {
|
|
19877
|
-
...overridden.runtime,
|
|
19878
|
-
enablePersistence: !1,
|
|
19879
|
-
preload: []
|
|
19880
|
-
}), overridden;
|
|
19881
|
-
}({
|
|
19882
|
-
themes: rawConfig.theme?.themes || {},
|
|
19883
|
-
build: rawConfig.build || {},
|
|
19884
|
-
runtime: rawConfig.runtime || {},
|
|
19885
|
-
integration: rawConfig.integration || {},
|
|
19886
|
-
dependencies: rawConfig.dependencies || {},
|
|
19887
|
-
validated: !1,
|
|
19888
|
-
// Will be set after validation
|
|
19889
|
-
// Store tokens for generator
|
|
19890
|
-
__tokens: rawConfig.theme?.tokens,
|
|
19891
|
-
__extend: rawConfig.theme?.extend
|
|
19892
|
-
}, env);
|
|
19893
|
-
// Process the AtomixConfig structure
|
|
19894
|
-
// Validate if requested
|
|
19895
|
-
let validationResult = null;
|
|
19896
|
-
validate && (validationResult = function(config) {
|
|
19897
|
-
const errors = [], warnings = [];
|
|
19898
|
-
// Validate top-level structure
|
|
19899
|
-
if (!config || "object" != typeof config) return errors.push("Configuration must be an object"),
|
|
19900
|
-
{
|
|
19901
|
-
valid: !1,
|
|
19902
|
-
errors: errors,
|
|
19903
|
-
warnings: warnings
|
|
19904
|
-
};
|
|
19905
|
-
// Validate themes
|
|
19906
|
-
if (config.themes && "object" == typeof config.themes) {
|
|
19907
|
-
const themeErrors =
|
|
19908
|
-
/**
|
|
19909
|
-
* Validate themes object
|
|
19910
|
-
*/
|
|
19911
|
-
function(themes) {
|
|
19912
|
-
const errors = [], warnings = [];
|
|
19913
|
-
0 === Object.keys(themes).length && warnings.push("No themes defined in configuration");
|
|
19914
|
-
for (const [themeId, theme] of Object.entries(themes))
|
|
19915
|
-
// Validate theme ID
|
|
19916
|
-
if (themeId && "string" == typeof themeId)
|
|
19917
|
-
// Validate theme object
|
|
19918
|
-
if (theme && "object" == typeof theme)
|
|
19919
|
-
// Validate theme type
|
|
19920
|
-
if (!theme.type || "css" !== theme.type && "js" !== theme.type) errors.push(`Theme "${themeId}" must have type "css" or "js"`); else {
|
|
19921
|
-
// Validate CSS theme
|
|
19922
|
-
if (
|
|
19923
|
-
// Validate required fields
|
|
19924
|
-
theme.name && "string" == typeof theme.name || errors.push(`Theme "${themeId}" must have a "name" string`),
|
|
19925
|
-
"css" === theme.type) {
|
|
19926
|
-
const cssErrors = validateCSSTheme();
|
|
19927
|
-
errors.push(...cssErrors.errors), warnings.push(...cssErrors.warnings);
|
|
19928
|
-
}
|
|
19929
|
-
// Validate JS theme
|
|
19930
|
-
if ("js" === theme.type) {
|
|
19931
|
-
const jsErrors = validateJSTheme(themeId, theme);
|
|
19932
|
-
errors.push(...jsErrors.errors), warnings.push(...jsErrors.warnings);
|
|
19933
|
-
}
|
|
19934
|
-
// Validate accessibility (only critical checks)
|
|
19935
|
-
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}`);
|
|
19936
|
-
} else errors.push(`Theme "${themeId}" must be an object`); else errors.push(`Invalid theme ID: ${themeId}`);
|
|
19937
|
-
return {
|
|
19938
|
-
valid: 0 === errors.length,
|
|
19939
|
-
errors: errors,
|
|
19940
|
-
warnings: warnings
|
|
19941
|
-
};
|
|
19942
|
-
}(config.themes);
|
|
19943
|
-
errors.push(...themeErrors.errors), warnings.push(...themeErrors.warnings);
|
|
19944
|
-
}
|
|
19945
|
-
// Validate build config (only if provided)
|
|
19946
|
-
else errors.push('Configuration must have a "themes" object');
|
|
19947
|
-
if (config.build) {
|
|
19948
|
-
const buildErrors = function(build) {
|
|
19949
|
-
const errors = [];
|
|
19950
|
-
// Only validate structure if provided
|
|
19951
|
-
return build.output && "object" != typeof build.output && errors.push("Build output must be an object"),
|
|
19952
|
-
build.sass && "object" != typeof build.sass && errors.push("Build sass config must be an object"),
|
|
19953
|
-
{
|
|
19954
|
-
valid: 0 === errors.length,
|
|
19955
|
-
errors: errors,
|
|
19956
|
-
warnings: []
|
|
19957
|
-
};
|
|
19958
|
-
}
|
|
19959
|
-
/**
|
|
19960
|
-
* Validate runtime configuration
|
|
19961
|
-
*/ (config.build);
|
|
19962
|
-
errors.push(...buildErrors.errors), warnings.push(...buildErrors.warnings);
|
|
19963
|
-
}
|
|
19964
|
-
// Validate runtime config (only if provided)
|
|
19965
|
-
if (config.runtime) {
|
|
19966
|
-
const runtimeErrors = function(runtime) {
|
|
19967
|
-
const errors = [];
|
|
19968
|
-
return runtime.basePath && "string" != typeof runtime.basePath && errors.push("Runtime basePath must be a string"),
|
|
19969
|
-
runtime.defaultTheme && "string" != typeof runtime.defaultTheme && errors.push("Runtime defaultTheme must be a string"),
|
|
19970
|
-
runtime.preload && !Array.isArray(runtime.preload) && errors.push("Runtime preload must be an array"),
|
|
19971
|
-
runtime.storageKey && "string" != typeof runtime.storageKey && errors.push("Runtime storageKey must be a string"),
|
|
19972
|
-
{
|
|
19973
|
-
valid: 0 === errors.length,
|
|
19974
|
-
errors: errors,
|
|
19975
|
-
warnings: []
|
|
19976
|
-
};
|
|
19977
|
-
}
|
|
19978
|
-
/**
|
|
19979
|
-
* Validate integration configuration
|
|
19980
|
-
*/ (config.runtime);
|
|
19981
|
-
errors.push(...runtimeErrors.errors), warnings.push(...runtimeErrors.warnings);
|
|
19982
|
-
}
|
|
19983
|
-
// Validate integration config (only if provided)
|
|
19984
|
-
if (config.integration) {
|
|
19985
|
-
const integrationErrors = function(integration) {
|
|
19986
|
-
const errors = [];
|
|
19987
|
-
// Only validate structure if provided
|
|
19988
|
-
return integration.classNames && "object" != typeof integration.classNames && errors.push("Integration classNames must be an object"),
|
|
19989
|
-
{
|
|
19990
|
-
valid: 0 === errors.length,
|
|
19991
|
-
errors: errors,
|
|
19992
|
-
warnings: []
|
|
19993
|
-
};
|
|
19994
|
-
}
|
|
19995
|
-
/**
|
|
19996
|
-
* Validate dependencies
|
|
19997
|
-
*/ (config.integration);
|
|
19998
|
-
errors.push(...integrationErrors.errors), warnings.push(...integrationErrors.warnings);
|
|
19999
|
-
}
|
|
20000
|
-
// Validate dependencies
|
|
20001
|
-
if (config.dependencies) {
|
|
20002
|
-
const depErrors = function(dependencies, themes) {
|
|
20003
|
-
const errors = [], warnings = [];
|
|
20004
|
-
for (const [themeId, deps] of Object.entries(dependencies))
|
|
20005
|
-
// Check if theme exists
|
|
20006
|
-
if (themes[themeId])
|
|
20007
|
-
// Validate dependencies array
|
|
20008
|
-
if (Array.isArray(deps))
|
|
20009
|
-
// Check if all dependencies exist
|
|
20010
|
-
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}`);
|
|
20011
|
-
return {
|
|
20012
|
-
valid: 0 === errors.length,
|
|
20013
|
-
errors: errors,
|
|
20014
|
-
warnings: warnings
|
|
20015
|
-
};
|
|
20016
|
-
}(config.dependencies, config.themes || {});
|
|
20017
|
-
errors.push(...depErrors.errors), warnings.push(...depErrors.warnings);
|
|
20018
|
-
}
|
|
20019
|
-
return {
|
|
20020
|
-
valid: 0 === errors.length,
|
|
20021
|
-
errors: errors,
|
|
20022
|
-
warnings: warnings
|
|
20023
|
-
};
|
|
20024
|
-
}(finalConfig)), config = {
|
|
20025
|
-
...finalConfig,
|
|
20026
|
-
validated: validate,
|
|
20027
|
-
errors: validationResult?.errors,
|
|
20028
|
-
warnings: validationResult?.warnings
|
|
20029
|
-
};
|
|
20030
|
-
} catch (error) {
|
|
20031
|
-
// Fallback: return default config structure
|
|
20032
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
20033
|
-
logger.warn(`Failed to load theme config from ${configPath}`, {
|
|
20034
|
-
configPath: configPath,
|
|
20035
|
-
error: errorMessage
|
|
20036
|
-
}), config = {
|
|
20037
|
-
themes: {},
|
|
20038
|
-
build: {
|
|
20039
|
-
output: {
|
|
20040
|
-
directory: "themes",
|
|
20041
|
-
formats: {
|
|
20042
|
-
expanded: ".css",
|
|
20043
|
-
compressed: ".min.css"
|
|
20044
|
-
}
|
|
20045
|
-
},
|
|
20046
|
-
sass: {
|
|
20047
|
-
...DEFAULT_SASS_CONFIG,
|
|
20048
|
-
loadPaths: [ ...DEFAULT_SASS_CONFIG.loadPaths ]
|
|
20049
|
-
}
|
|
20050
|
-
},
|
|
20051
|
-
runtime: {
|
|
20052
|
-
basePath: "/themes",
|
|
20053
|
-
cdnPath: null,
|
|
20054
|
-
preload: [],
|
|
20055
|
-
lazy: !0,
|
|
20056
|
-
defaultTheme: "",
|
|
20057
|
-
// No default - use built-in styles (empty string instead of undefined)
|
|
20058
|
-
storageKey: "atomix-theme",
|
|
20059
|
-
dataAttribute: "data-theme",
|
|
20060
|
-
enablePersistence: !0,
|
|
20061
|
-
useMinified: "production" === env
|
|
20062
|
-
},
|
|
20063
|
-
integration: {
|
|
20064
|
-
cssVariables: DEFAULT_INTEGRATION_CSS_VARIABLES,
|
|
20065
|
-
classNames: DEFAULT_INTEGRATION_CLASS_NAMES
|
|
20066
|
-
},
|
|
20067
|
-
dependencies: {},
|
|
20068
|
-
validated: !1,
|
|
20069
|
-
errors: [ `Failed to load config: ${error instanceof Error ? error.message : String(error)}` ],
|
|
20070
|
-
warnings: [],
|
|
20071
|
-
__tokens: {},
|
|
20072
|
-
__extend: {}
|
|
20073
|
-
};
|
|
20074
|
-
}
|
|
20075
|
-
// Cache the loaded config
|
|
20076
|
-
return cachedConfig = config, config;
|
|
20077
|
-
}();
|
|
20078
|
-
} catch (error) {
|
|
20079
|
-
// In browser environments, config loading will fail
|
|
20080
|
-
// Use empty config as fallback
|
|
20081
|
-
this.config = {
|
|
20082
|
-
themes: {},
|
|
20083
|
-
build: {
|
|
20084
|
-
output: {
|
|
20085
|
-
directory: "themes",
|
|
20086
|
-
formats: {
|
|
20087
|
-
expanded: ".css",
|
|
20088
|
-
compressed: ".min.css"
|
|
20089
|
-
}
|
|
20090
|
-
},
|
|
20091
|
-
sass: {
|
|
20092
|
-
style: "expanded",
|
|
20093
|
-
sourceMap: !0,
|
|
20094
|
-
loadPaths: [ "src" ]
|
|
20095
|
-
}
|
|
20096
|
-
},
|
|
20097
|
-
runtime: {
|
|
20098
|
-
basePath: "",
|
|
20099
|
-
defaultTheme: void 0
|
|
20100
|
-
},
|
|
20101
|
-
integration: {
|
|
20102
|
-
cssVariables: {
|
|
20103
|
-
colorMode: "--color-mode"
|
|
20104
|
-
},
|
|
20105
|
-
classNames: {
|
|
20106
|
-
theme: "data-theme",
|
|
20107
|
-
colorMode: "data-color-mode"
|
|
20108
|
-
}
|
|
20109
|
-
},
|
|
20110
|
-
dependencies: {},
|
|
20111
|
-
validated: !1,
|
|
20112
|
-
errors: [],
|
|
20113
|
-
warnings: [],
|
|
20114
|
-
__tokens: {},
|
|
20115
|
-
__extend: {}
|
|
20116
|
-
};
|
|
20117
|
-
}
|
|
20118
|
-
// Register all themes from config
|
|
20119
|
-
for (const [themeId, definition] of Object.entries(this.config.themes)) this.register(themeId, definition);
|
|
20120
|
-
// Resolve dependencies
|
|
20121
|
-
this.resolveDependencies(), this.initialized = !0;
|
|
20122
|
-
}
|
|
20123
|
-
}
|
|
20124
|
-
/**
|
|
20125
|
-
* Register a theme
|
|
20126
|
-
*/ register(themeId, definition) {
|
|
20127
|
-
// Get dependencies from config or definition
|
|
20128
|
-
const entry = {
|
|
20129
|
-
id: themeId,
|
|
20130
|
-
definition: definition,
|
|
20131
|
-
loaded: !1,
|
|
20132
|
-
dependencies: [ ...this.config?.dependencies?.[themeId] || definition.dependencies || [] ],
|
|
20133
|
-
dependents: []
|
|
20134
|
-
};
|
|
20135
|
-
this.entries.set(themeId, entry);
|
|
20136
|
-
}
|
|
20137
|
-
/**
|
|
20138
|
-
* Get theme entry
|
|
20139
|
-
*/ get(themeId) {
|
|
20140
|
-
return this.entries.get(themeId);
|
|
20141
|
-
}
|
|
20142
|
-
/**
|
|
20143
|
-
* Check if theme exists
|
|
20144
|
-
*/ has(themeId) {
|
|
20145
|
-
return this.entries.has(themeId);
|
|
20146
|
-
}
|
|
20147
|
-
/**
|
|
20148
|
-
* Get all theme IDs
|
|
20149
|
-
*/ getAllIds() {
|
|
20150
|
-
return Array.from(this.entries.keys());
|
|
20151
|
-
}
|
|
20152
|
-
/**
|
|
20153
|
-
* Get all theme metadata
|
|
20154
|
-
*/ getAllMetadata() {
|
|
20155
|
-
return Array.from(this.entries.values()).map((entry => ({
|
|
20156
|
-
id: entry.id,
|
|
20157
|
-
name: entry.definition.name,
|
|
20158
|
-
type: entry.definition.type,
|
|
20159
|
-
class: entry.definition.class,
|
|
20160
|
-
description: entry.definition.description,
|
|
20161
|
-
author: entry.definition.author,
|
|
20162
|
-
version: entry.definition.version,
|
|
20163
|
-
tags: entry.definition.tags,
|
|
20164
|
-
supportsDarkMode: entry.definition.supportsDarkMode,
|
|
20165
|
-
status: entry.definition.status,
|
|
20166
|
-
a11y: entry.definition.a11y,
|
|
20167
|
-
color: entry.definition.color,
|
|
20168
|
-
features: entry.definition.features,
|
|
20169
|
-
dependencies: entry.dependencies
|
|
20170
|
-
})));
|
|
20171
|
-
}
|
|
20172
|
-
/**
|
|
20173
|
-
* Get theme definition
|
|
20174
|
-
*/ getDefinition(themeId) {
|
|
20175
|
-
return this.entries.get(themeId)?.definition;
|
|
20176
|
-
}
|
|
20177
|
-
/**
|
|
20178
|
-
* Check if a theme is loaded
|
|
20179
|
-
*/ isThemeLoaded(themeId) {
|
|
20180
|
-
const entry = this.entries.get(themeId);
|
|
20181
|
-
return !!entry && entry.loaded;
|
|
20182
|
-
}
|
|
20183
|
-
/**
|
|
20184
|
-
* Mark a theme as loaded
|
|
20185
|
-
*/ markLoaded(themeId, theme) {
|
|
20186
|
-
const entry = this.entries.get(themeId);
|
|
20187
|
-
entry && (entry.loaded = !0, theme && (entry.theme = theme));
|
|
20188
|
-
}
|
|
20189
|
-
/**
|
|
20190
|
-
* Get theme object (for JS themes)
|
|
20191
|
-
*/ getTheme(themeId) {
|
|
20192
|
-
const entry = this.entries.get(themeId);
|
|
20193
|
-
return entry?.loaded ? entry.theme : void 0;
|
|
20194
|
-
}
|
|
20195
|
-
/**
|
|
20196
|
-
* Get dependencies for a theme
|
|
20197
|
-
*/ getDependencies(themeId) {
|
|
20198
|
-
return this.entries.get(themeId)?.dependencies || [];
|
|
20199
|
-
}
|
|
20200
|
-
/**
|
|
20201
|
-
* Get dependents for a theme (themes that depend on this one)
|
|
20202
|
-
*/ getDependents(themeId) {
|
|
20203
|
-
return this.entries.get(themeId)?.dependents || [];
|
|
20204
|
-
}
|
|
20205
|
-
/**
|
|
20206
|
-
* Resolve all dependencies in correct order
|
|
20207
|
-
*/ resolveDependencyOrder(themeId) {
|
|
20208
|
-
const resolved = [], visited = new Set, visiting = new Set, visit = id => {
|
|
20209
|
-
if (visiting.has(id)) throw new Error(`Circular dependency detected involving theme: ${id}`);
|
|
20210
|
-
if (visited.has(id)) return;
|
|
20211
|
-
visiting.add(id);
|
|
20212
|
-
const entry = this.entries.get(id);
|
|
20213
|
-
if (entry) for (const dep of entry.dependencies) {
|
|
20214
|
-
if (!this.has(dep)) throw new Error(`Theme "${id}" depends on non-existent theme: ${dep}`);
|
|
20215
|
-
visit(dep);
|
|
20216
|
-
}
|
|
20217
|
-
visiting.delete(id), visited.add(id), resolved.push(id);
|
|
20218
|
-
};
|
|
20219
|
-
return visit(themeId), resolved;
|
|
20220
|
-
}
|
|
20221
|
-
/**
|
|
20222
|
-
* Resolve dependencies and build dependency graph
|
|
20223
|
-
*/ resolveDependencies() {
|
|
20224
|
-
// Build dependents map
|
|
20225
|
-
for (const entry of this.entries.values()) for (const dep of entry.dependencies) {
|
|
20226
|
-
const depEntry = this.entries.get(dep);
|
|
20227
|
-
var _context;
|
|
20228
|
-
depEntry && (_includesInstanceProperty(_context = depEntry.dependents).call(_context, entry.id) || depEntry.dependents.push(entry.id));
|
|
20229
|
-
}
|
|
20230
|
-
}
|
|
20231
|
-
/**
|
|
20232
|
-
* Validate all themes
|
|
20233
|
-
*/ validate() {
|
|
20234
|
-
const errors = [];
|
|
20235
|
-
// Check for circular dependencies
|
|
20236
|
-
for (const themeId of this.entries.keys()) try {
|
|
20237
|
-
this.resolveDependencyOrder(themeId);
|
|
20238
|
-
} catch (error) {
|
|
20239
|
-
errors.push(error instanceof Error ? error.message : String(error));
|
|
20240
|
-
}
|
|
20241
|
-
// Check for missing dependencies
|
|
20242
|
-
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}`);
|
|
20243
|
-
return {
|
|
20244
|
-
valid: 0 === errors.length,
|
|
20245
|
-
errors: errors
|
|
20246
|
-
};
|
|
20247
|
-
}
|
|
20248
|
-
/**
|
|
20249
|
-
* Clear registry
|
|
20250
|
-
*/ clear() {
|
|
20251
|
-
this.entries.clear(), this.config = null, this.initialized = !1;
|
|
20252
|
-
}
|
|
19350
|
+
* Get the number of registered themes
|
|
19351
|
+
* @param registry - Theme registry object
|
|
19352
|
+
*/ function getThemeCount(registry) {
|
|
19353
|
+
return Object.keys(registry).length;
|
|
20253
19354
|
}
|
|
20254
19355
|
|
|
20255
19356
|
/**
|
|
@@ -20334,71 +19435,18 @@ class ThemeRegistry {
|
|
|
20334
19435
|
* const css = ':root { --atomix-color-primary: #7AFFD7; }';
|
|
20335
19436
|
* await saveCSSFile(css, './themes/custom.css');
|
|
20336
19437
|
* ```
|
|
20337
|
-
*/
|
|
20338
|
-
// Check if in browser environment
|
|
20339
|
-
if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
|
|
20340
|
-
// Dynamic import to avoid bundling Node.js modules in browser builds
|
|
20341
|
-
const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
|
|
20342
|
-
await fs.mkdir(dir, {
|
|
20343
|
-
recursive: !0
|
|
20344
|
-
}),
|
|
20345
|
-
// Write file
|
|
20346
|
-
await fs.writeFile(filePath, css, "utf8");
|
|
20347
|
-
}
|
|
20348
|
-
|
|
20349
|
-
/**
|
|
20350
|
-
* Save CSS to file (synchronous version)
|
|
20351
|
-
*
|
|
20352
|
-
* Synchronous version of saveCSSFile. Only works in Node.js environment.
|
|
20353
|
-
*
|
|
20354
|
-
* @param css - CSS string to save
|
|
20355
|
-
* @param filePath - Output file path
|
|
20356
|
-
* @throws Error if called in browser environment
|
|
20357
|
-
*/ function saveCSSFileSync(css, filePath) {
|
|
20358
|
-
// Check if in browser environment
|
|
20359
|
-
if ("undefined" != typeof window) throw new Error("saveCSSFileSync can only be used in Node.js environment. Use injectCSS() for browser environments.");
|
|
20360
|
-
// Use require for synchronous file operations
|
|
20361
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
20362
|
-
const fs = require("fs"), dir = require("path").dirname(filePath);
|
|
20363
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
20364
|
-
fs.existsSync(dir) || fs.mkdirSync(dir, {
|
|
20365
|
-
recursive: !0
|
|
20366
|
-
}),
|
|
20367
|
-
// Write file
|
|
20368
|
-
fs.writeFileSync(filePath, css, "utf8");
|
|
20369
|
-
}
|
|
19438
|
+
*/ "undefined" != typeof process && process.env;
|
|
20370
19439
|
|
|
20371
19440
|
/**
|
|
20372
19441
|
* Check if code is running in a browser environment
|
|
20373
|
-
*/
|
|
19442
|
+
*/
|
|
19443
|
+
const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
|
|
20374
19444
|
// Validate theme name to prevent path injection
|
|
20375
19445
|
if (!isValidThemeName(themeName)) throw new Error(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens.`);
|
|
20376
19446
|
const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
|
|
20377
19447
|
return cdnPath ? `${cdnPath.replace(/[<>"']/g, "")}/${fileName}` : `${basePath.replace(/\/$/, "").replace(/[<>"']/g, "")}/${fileName.replace(/^\//, "")}`;
|
|
20378
19448
|
// Ensure basePath doesn't end with slash and fileName doesn't start with slash
|
|
20379
19449
|
// Also sanitize basePath to prevent path injection
|
|
20380
|
-
}, loadThemeCSS = (fullPath, linkId) => isServer() ? Promise.resolve() : new Promise(((resolve, reject) => {
|
|
20381
|
-
if (document.getElementById(linkId)) return void resolve();
|
|
20382
|
-
// Create link element
|
|
20383
|
-
const link = document.createElement("link");
|
|
20384
|
-
link.id = linkId, link.rel = "stylesheet", link.type = "text/css", link.href = fullPath,
|
|
20385
|
-
// Add data attribute for tracking
|
|
20386
|
-
link.setAttribute("data-atomix-theme", "true"),
|
|
20387
|
-
// Handle load success
|
|
20388
|
-
link.onload = () => {
|
|
20389
|
-
resolve();
|
|
20390
|
-
},
|
|
20391
|
-
// Handle load error
|
|
20392
|
-
link.onerror = () => {
|
|
20393
|
-
// Remove failed link element
|
|
20394
|
-
link.remove(), reject(new Error(`Failed to load theme CSS: ${fullPath}`));
|
|
20395
|
-
},
|
|
20396
|
-
// Append to head
|
|
20397
|
-
document.head.appendChild(link);
|
|
20398
|
-
})), isThemeLoaded = themeName => {
|
|
20399
|
-
if (isServer()) return !1;
|
|
20400
|
-
const linkId = getThemeLinkId(themeName);
|
|
20401
|
-
return null !== document.getElementById(linkId);
|
|
20402
19450
|
}, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName);
|
|
20403
19451
|
|
|
20404
19452
|
/**
|
|
@@ -20871,211 +19919,198 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
20871
19919
|
styleElement.textContent = css;
|
|
20872
19920
|
}
|
|
20873
19921
|
/**
|
|
20874
|
-
*
|
|
19922
|
+
* Naming Utilities
|
|
20875
19923
|
*
|
|
20876
|
-
*
|
|
19924
|
+
* Provides consistent naming conventions across the theme system
|
|
20877
19925
|
*/
|
|
20878
19926
|
/**
|
|
20879
|
-
*
|
|
19927
|
+
* Generate consistent CSS class names following BEM methodology
|
|
20880
19928
|
*/ (css, styleId), css;
|
|
20881
19929
|
}
|
|
20882
19930
|
|
|
20883
|
-
|
|
19931
|
+
function generateClassName(block, element, modifiers) {
|
|
19932
|
+
let className = block;
|
|
19933
|
+
return element && (className += `__${element}`), modifiers && Object.entries(modifiers).forEach((([key, value]) => {
|
|
19934
|
+
value && (className += `--${key}`, "string" == typeof value && value !== key && (className += `-${value}`));
|
|
19935
|
+
})), className;
|
|
19936
|
+
}
|
|
20884
19937
|
|
|
20885
|
-
|
|
19938
|
+
/**
|
|
19939
|
+
* Generate consistent CSS variable names
|
|
19940
|
+
*/ function generateCSSVariableName(property, options = {}) {
|
|
19941
|
+
const {prefix: prefix = "atomix", component: component, variant: variant, state: state} = options, parts = [ prefix ];
|
|
19942
|
+
return component && parts.push(component), variant && parts.push(variant), state && parts.push(state),
|
|
19943
|
+
parts.push(property), `--${parts.join("-")}`;
|
|
19944
|
+
}
|
|
20886
19945
|
|
|
20887
19946
|
/**
|
|
20888
|
-
*
|
|
20889
|
-
|
|
20890
|
-
|
|
20891
|
-
|
|
20892
|
-
|
|
20893
|
-
|
|
20894
|
-
|
|
19947
|
+
* Normalize theme tokens to consistent naming convention
|
|
19948
|
+
*/ function normalizeThemeTokens(tokens) {
|
|
19949
|
+
const normalized = {};
|
|
19950
|
+
for (const [key, value] of Object.entries(tokens))
|
|
19951
|
+
// Recursively normalize nested objects
|
|
19952
|
+
normalized[key] = "object" == typeof value && null !== value ? normalizeThemeTokens(value) : value;
|
|
19953
|
+
return normalized;
|
|
19954
|
+
}
|
|
19955
|
+
|
|
20895
19956
|
/**
|
|
20896
|
-
*
|
|
19957
|
+
* Convert camelCase to kebab-case for CSS custom properties
|
|
19958
|
+
*/ function camelToKebab(str) {
|
|
19959
|
+
return str.replace(/[A-Z]/g, (match => `-${match.toLowerCase()}`));
|
|
19960
|
+
}
|
|
19961
|
+
|
|
19962
|
+
/**
|
|
19963
|
+
* Convert theme property to CSS variable name
|
|
19964
|
+
*/ function themePropertyToCSSVar(propertyPath, prefix = "atomix") {
|
|
19965
|
+
return `--${prefix}-${propertyPath.split(".").map((part => camelToKebab(part))).join("-")}`;
|
|
19966
|
+
}
|
|
19967
|
+
|
|
19968
|
+
/**
|
|
19969
|
+
* Component Theming Utilities
|
|
20897
19970
|
*
|
|
20898
|
-
*
|
|
19971
|
+
* Provides consistent patterns for applying theme values to components
|
|
20899
19972
|
*/
|
|
20900
|
-
|
|
20901
|
-
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
*/ applyTheme(theme) {
|
|
20910
|
-
// Clear previously applied variables
|
|
20911
|
-
this.clearAppliedVars(),
|
|
20912
|
-
// Check if it's DesignTokens
|
|
20913
|
-
this.isDesignTokens(theme) ?
|
|
20914
|
-
// Direct DesignTokens - use unified theme system (with config support)
|
|
20915
|
-
this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
|
|
20916
|
-
selector: ":root",
|
|
20917
|
-
prefix: "atomix"
|
|
20918
|
-
}), this.styleId),
|
|
20919
|
-
// Apply component overrides (only for Theme objects)
|
|
20920
|
-
!this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
|
|
20921
|
-
}
|
|
20922
|
-
/**
|
|
20923
|
-
* Apply DesignTokens using unified theme system
|
|
20924
|
-
*
|
|
20925
|
-
* Uses createTheme() which automatically loads from atomix.config.ts
|
|
20926
|
-
* if no tokens are provided, ensuring config is always respected.
|
|
20927
|
-
*/ applyDesignTokens(tokens) {
|
|
20928
|
-
// Inject CSS into DOM
|
|
20929
|
-
injectCSS$1(createTheme(tokens, {
|
|
20930
|
-
selector: ":root",
|
|
20931
|
-
prefix: "atomix"
|
|
20932
|
-
}), this.styleId);
|
|
20933
|
-
}
|
|
20934
|
-
/**
|
|
20935
|
-
* Check if object is DesignTokens
|
|
20936
|
-
*/ isDesignTokens(obj) {
|
|
20937
|
-
// DesignTokens is a flat object with string keys, no nested structures
|
|
20938
|
-
return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
|
|
20939
|
-
}
|
|
20940
|
-
/**
|
|
20941
|
-
* Apply global CSS variables (for component overrides)
|
|
20942
|
-
*/ applyGlobalCSSVars(vars) {
|
|
20943
|
-
Object.entries(vars).forEach((([key, value]) => {
|
|
20944
|
-
this.root.style.setProperty(key, String(value));
|
|
20945
|
-
}));
|
|
20946
|
-
}
|
|
20947
|
-
/**
|
|
20948
|
-
* Apply component-level overrides
|
|
20949
|
-
*/ applyComponentOverrides(overrides) {
|
|
20950
|
-
Object.entries(overrides).forEach((([componentName, override]) => {
|
|
20951
|
-
override && this.applyComponentOverride(componentName, override);
|
|
20952
|
-
}));
|
|
20953
|
-
}
|
|
20954
|
-
/**
|
|
20955
|
-
* Apply override for a specific component
|
|
20956
|
-
*/ applyComponentOverride(componentName, override) {
|
|
20957
|
-
const vars = {}, componentKey = componentName.toLowerCase();
|
|
20958
|
-
// Apply component-level CSS variables
|
|
20959
|
-
override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
|
|
20960
|
-
// If key doesn't start with --, add component prefix
|
|
20961
|
-
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
|
|
20962
|
-
vars[varKey] = value;
|
|
20963
|
-
})),
|
|
20964
|
-
// Apply part-specific CSS variables
|
|
20965
|
-
override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
|
|
20966
|
-
partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
|
|
20967
|
-
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
|
|
20968
|
-
vars[varKey] = value;
|
|
20969
|
-
}));
|
|
20970
|
-
})),
|
|
20971
|
-
// Apply variant-specific CSS variables
|
|
20972
|
-
override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
|
|
20973
|
-
variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
|
|
20974
|
-
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
|
|
20975
|
-
vars[varKey] = value;
|
|
20976
|
-
}));
|
|
20977
|
-
})), this.applyGlobalCSSVars(vars);
|
|
20978
|
-
}
|
|
20979
|
-
/**
|
|
20980
|
-
* Clear all applied CSS variables
|
|
20981
|
-
*/ clearAppliedVars() {
|
|
20982
|
-
removeCSS(this.styleId);
|
|
20983
|
-
}
|
|
20984
|
-
/**
|
|
20985
|
-
* Remove theme application
|
|
20986
|
-
*/ removeTheme() {
|
|
20987
|
-
this.clearAppliedVars(), removeCSS(this.styleId);
|
|
20988
|
-
}
|
|
20989
|
-
/**
|
|
20990
|
-
* Update specific CSS variables without clearing all
|
|
20991
|
-
*/ updateCSSVars(vars) {
|
|
20992
|
-
this.applyGlobalCSSVars(vars);
|
|
20993
|
-
}
|
|
19973
|
+
/**
|
|
19974
|
+
* Get a theme value for a specific component using CSS variables
|
|
19975
|
+
* This ensures all components access theme values consistently
|
|
19976
|
+
*/ function getComponentThemeValue(component, property, variant, size) {
|
|
19977
|
+
// Build CSS variable name following consistent pattern
|
|
19978
|
+
const parts = [ "atomix", component ];
|
|
19979
|
+
// Return CSS variable reference with fallback
|
|
19980
|
+
return variant && parts.push(variant), size && parts.push(size), parts.push(property),
|
|
19981
|
+
`var(--${parts.join("-")}, var(--atomix-${property}, initial))`;
|
|
20994
19982
|
}
|
|
20995
19983
|
|
|
20996
19984
|
/**
|
|
20997
|
-
*
|
|
20998
|
-
*/
|
|
19985
|
+
* Generate component-specific CSS variables from theme
|
|
19986
|
+
*/ function generateComponentCSSVars(component, theme, variant, size) {
|
|
19987
|
+
const vars = {}, prefixParts = [ "atomix", component ];
|
|
19988
|
+
// This is a simplified implementation - in a real system you'd have more
|
|
19989
|
+
// sophisticated logic to extract component-specific values from the theme
|
|
19990
|
+
variant && prefixParts.push(variant), size && prefixParts.push(size);
|
|
19991
|
+
const prefix = prefixParts.join("-");
|
|
19992
|
+
// Add common component properties
|
|
19993
|
+
if (theme.palette && (vars[`--${prefix}-color`] = theme.palette.primary?.main || "#7c3aed",
|
|
19994
|
+
vars[`--${prefix}-color-hover`] = theme.palette.primary?.dark || "#5b21b6", vars[`--${prefix}-color-active`] = theme.palette.primary?.main || "#7c3aed",
|
|
19995
|
+
vars[`--${prefix}-color-disabled`] = theme.palette.text?.disabled || "#9ca3af"),
|
|
19996
|
+
theme.typography && (vars[`--${prefix}-font-family`] = theme.typography.fontFamily || "Inter, sans-serif",
|
|
19997
|
+
vars[`--${prefix}-font-size`] = theme.typography.fontSize ? `${theme.typography.fontSize}px` : "16px"),
|
|
19998
|
+
theme.spacing) {
|
|
19999
|
+
const spacing = "function" == typeof theme.spacing ? theme.spacing : val => 8 * val;
|
|
20000
|
+
vars[`--${prefix}-spacing-unit`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-sm`] = `${spacing(.5)}px`,
|
|
20001
|
+
vars[`--${prefix}-spacing-md`] = `${spacing(1)}px`, vars[`--${prefix}-spacing-lg`] = `${spacing(2)}px`;
|
|
20002
|
+
}
|
|
20003
|
+
return vars;
|
|
20004
|
+
}
|
|
20999
20005
|
|
|
21000
20006
|
/**
|
|
21001
|
-
*
|
|
21002
|
-
*/ function
|
|
21003
|
-
|
|
20007
|
+
* Apply consistent theme to component style object
|
|
20008
|
+
*/ function applyComponentTheme(component, style = {}, variant, size, theme) {
|
|
20009
|
+
// If no theme provided, return original style
|
|
20010
|
+
return theme ? {
|
|
20011
|
+
...generateComponentCSSVars(component, theme, variant, size),
|
|
20012
|
+
...style
|
|
20013
|
+
} : style;
|
|
20014
|
+
// Generate component-specific CSS variables
|
|
21004
20015
|
}
|
|
21005
20016
|
|
|
21006
20017
|
/**
|
|
21007
|
-
*
|
|
21008
|
-
*/ function
|
|
21009
|
-
|
|
20018
|
+
* Create a hook for consistent component theming
|
|
20019
|
+
*/ function useComponentTheme(component, variant, size, theme) {
|
|
20020
|
+
return property => getComponentThemeValue(component, property, variant, size);
|
|
21010
20021
|
}
|
|
21011
20022
|
|
|
21012
20023
|
/**
|
|
21013
|
-
*
|
|
21014
|
-
*
|
|
21015
|
-
* Provides theme context to child components and manages theme state.
|
|
20024
|
+
* Theme Configuration Loader
|
|
21016
20025
|
*
|
|
21017
|
-
*
|
|
21018
|
-
*
|
|
20026
|
+
* Provides functions to load theme configurations from atomix.config.ts
|
|
20027
|
+
* Includes both sync and async versions, with automatic fallbacks
|
|
20028
|
+
*/
|
|
20029
|
+
/**
|
|
20030
|
+
* Load theme from config file (synchronous, Node.js only)
|
|
20031
|
+
* @param configPath - Path to config file (default: atomix.config.ts)
|
|
20032
|
+
* @returns DesignTokens from theme configuration
|
|
20033
|
+
* @throws Error if config loading is not available in browser environment
|
|
20034
|
+
*/ function loadThemeFromConfigSync(options) {
|
|
20035
|
+
// Check if we're in a browser environment
|
|
20036
|
+
if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
20037
|
+
// Use dynamic import to load the config loader
|
|
20038
|
+
// This allows bundlers to handle external dependencies properly
|
|
20039
|
+
let loadAtomixConfig;
|
|
20040
|
+
try {
|
|
20041
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20042
|
+
const {loadAtomixConfig: loader} = require("../../config/loader");
|
|
20043
|
+
loadAtomixConfig = loader;
|
|
20044
|
+
} catch (error) {
|
|
20045
|
+
if (!1 !== options?.required) throw new Error("Config loader module not available");
|
|
20046
|
+
// Return empty tokens if config is not required
|
|
20047
|
+
return createTokens({});
|
|
20048
|
+
}
|
|
20049
|
+
const config = loadAtomixConfig({
|
|
20050
|
+
configPath: options?.configPath || "atomix.config.ts",
|
|
20051
|
+
required: !1 !== options?.required
|
|
20052
|
+
});
|
|
20053
|
+
return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
|
|
20054
|
+
}
|
|
20055
|
+
|
|
20056
|
+
/**
|
|
20057
|
+
* Load theme from config file (asynchronous)
|
|
20058
|
+
* @param configPath - Path to config file (default: atomix.config.ts)
|
|
20059
|
+
* @returns Promise resolving to DesignTokens from theme configuration
|
|
20060
|
+
*/ async function loadThemeFromConfig(options) {
|
|
20061
|
+
// Check if we're in a browser environment
|
|
20062
|
+
if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
20063
|
+
// Dynamic import for config loader
|
|
20064
|
+
const {loadAtomixConfig: loadAtomixConfig} = await import("./lib/config/loader"), config = await loadAtomixConfig({
|
|
20065
|
+
configPath: options?.configPath || "atomix.config.ts",
|
|
20066
|
+
required: !1 !== options?.required
|
|
20067
|
+
});
|
|
20068
|
+
return config?.theme ? isThemeObject$1(config.theme) ? createDesignTokensFromTheme(config.theme) : createTokens(config.theme) : createTokens({});
|
|
20069
|
+
}
|
|
20070
|
+
|
|
20071
|
+
/**
|
|
20072
|
+
* Check if the provided object is a Theme object
|
|
20073
|
+
* @param theme - Object to check
|
|
20074
|
+
* @returns True if the object is a Theme object, false otherwise
|
|
20075
|
+
*/ function isThemeObject$1(theme) {
|
|
20076
|
+
return "object" == typeof theme && null !== theme;
|
|
20077
|
+
}
|
|
20078
|
+
|
|
20079
|
+
/**
|
|
20080
|
+
* Theme Context
|
|
21019
20081
|
*
|
|
21020
|
-
*
|
|
21021
|
-
|
|
21022
|
-
|
|
20082
|
+
* React context for theme management
|
|
20083
|
+
*/
|
|
20084
|
+
/**
|
|
20085
|
+
* Theme context with default values
|
|
20086
|
+
*/ const ThemeContext = React.createContext(null);
|
|
20087
|
+
|
|
20088
|
+
ThemeContext.displayName = "ThemeContext";
|
|
20089
|
+
|
|
20090
|
+
/**
|
|
20091
|
+
* Theme Provider
|
|
21023
20092
|
*
|
|
21024
|
-
*
|
|
21025
|
-
*
|
|
21026
|
-
*
|
|
21027
|
-
*
|
|
21028
|
-
*
|
|
21029
|
-
* </ThemeProvider>
|
|
21030
|
-
* );
|
|
21031
|
-
* }
|
|
20093
|
+
* React context provider for theme management with separated concerns.
|
|
20094
|
+
* Simplified version focusing on core functionality:
|
|
20095
|
+
* - String-based themes (CSS files)
|
|
20096
|
+
* - JS Theme objects
|
|
20097
|
+
* - Persistence via localStorage
|
|
21032
20098
|
*
|
|
21033
|
-
*
|
|
21034
|
-
|
|
21035
|
-
|
|
21036
|
-
* <ThemeProvider defaultTheme="dark">
|
|
21037
|
-
* <YourApp />
|
|
21038
|
-
* </ThemeProvider>
|
|
21039
|
-
* );
|
|
21040
|
-
* }
|
|
21041
|
-
* ```
|
|
21042
|
-
*/ 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}) => {
|
|
20099
|
+
* Falls back to 'default' theme if no configuration is found.
|
|
20100
|
+
*/
|
|
20101
|
+
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}) => {
|
|
21043
20102
|
// Store callbacks in refs to avoid recreating when they change
|
|
21044
20103
|
const onThemeChangeRef = React.useRef(onThemeChange), onErrorRef = React.useRef(onError);
|
|
21045
|
-
// Update
|
|
20104
|
+
// Update ref when callback changes
|
|
21046
20105
|
React.useEffect((() => {
|
|
21047
20106
|
onThemeChangeRef.current = onThemeChange, onErrorRef.current = onError;
|
|
21048
20107
|
}), [ onThemeChange, onError ]);
|
|
21049
|
-
// Create stable wrapper functions that read from
|
|
20108
|
+
// Create stable wrapper functions that read from ref
|
|
21050
20109
|
const handleThemeChange = React.useCallback((theme => {
|
|
21051
20110
|
onThemeChangeRef.current?.(theme);
|
|
21052
20111
|
}), []), handleError = React.useCallback(((error, themeName) => {
|
|
21053
20112
|
onErrorRef.current?.(error, themeName);
|
|
21054
|
-
}), []),
|
|
21055
|
-
// Only update if themes object actually changed (shallow comparison)
|
|
21056
|
-
const currentKeys = Object.keys(themes), prevKeys = Object.keys(themesRef.current);
|
|
21057
|
-
return currentKeys.length !== prevKeys.length || currentKeys.some((key => themes[key] !== themesRef.current[key])) ? (themesRef.current = themes,
|
|
21058
|
-
themes) : themesRef.current;
|
|
21059
|
-
}), [ themes ]), logger = React.useMemo((() => getLogger()), []), registry = React.useMemo((() => {
|
|
21060
|
-
const reg = new ThemeRegistry;
|
|
21061
|
-
// Register themes from props
|
|
21062
|
-
if (themesStable && Object.keys(themesStable).length > 0) for (const [themeId, metadata] of Object.entries(themesStable)) reg.has(themeId) || reg.register(themeId, {
|
|
21063
|
-
type: "css",
|
|
21064
|
-
name: metadata.name,
|
|
21065
|
-
class: metadata.class || themeId,
|
|
21066
|
-
description: metadata.description,
|
|
21067
|
-
author: metadata.author,
|
|
21068
|
-
version: metadata.version,
|
|
21069
|
-
tags: metadata.tags,
|
|
21070
|
-
supportsDarkMode: metadata.supportsDarkMode,
|
|
21071
|
-
status: metadata.status,
|
|
21072
|
-
a11y: metadata.a11y,
|
|
21073
|
-
color: metadata.color,
|
|
21074
|
-
features: metadata.features,
|
|
21075
|
-
dependencies: metadata.dependencies
|
|
21076
|
-
});
|
|
21077
|
-
return reg;
|
|
21078
|
-
}), [ themesStable ]), storageAdapter = React.useMemo((() => ({
|
|
20113
|
+
}), []), storageAdapter = React.useMemo((() => ({
|
|
21079
20114
|
getItem: key => {
|
|
21080
20115
|
if (isServer()) return null;
|
|
21081
20116
|
try {
|
|
@@ -21107,7 +20142,7 @@ class ThemeApplicator {
|
|
|
21107
20142
|
return !1;
|
|
21108
20143
|
}
|
|
21109
20144
|
}
|
|
21110
|
-
})), []),
|
|
20145
|
+
})), []), initialDefaultTheme = React.useMemo((() => {
|
|
21111
20146
|
// Check storage first
|
|
21112
20147
|
if (enablePersistence && storageAdapter.isAvailable()) {
|
|
21113
20148
|
const stored = storageAdapter.getItem(storageKey);
|
|
@@ -21115,193 +20150,112 @@ class ThemeApplicator {
|
|
|
21115
20150
|
}
|
|
21116
20151
|
// If defaultTheme is provided, use it
|
|
21117
20152
|
if (null != defaultTheme) return defaultTheme;
|
|
21118
|
-
//
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
version: meta.version,
|
|
21129
|
-
tags: meta.tags,
|
|
21130
|
-
supportsDarkMode: meta.supportsDarkMode,
|
|
21131
|
-
status: meta.status,
|
|
21132
|
-
a11y: meta.a11y,
|
|
21133
|
-
color: meta.color,
|
|
21134
|
-
features: meta.features,
|
|
21135
|
-
dependencies: meta.dependencies
|
|
21136
|
-
}))))), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), previousThemeRef = React.useRef(null);
|
|
21137
|
-
// Get default theme (with automatic config loading)
|
|
21138
|
-
React.useCallback((() => {
|
|
21139
|
-
// Check storage first
|
|
21140
|
-
if (enablePersistence && storageAdapter.isAvailable()) {
|
|
21141
|
-
const stored = storageAdapter.getItem(storageKey);
|
|
21142
|
-
if (stored) return stored;
|
|
20153
|
+
// Try to load from atomix.config.ts as fallback, but only in Node.js/SSR environments
|
|
20154
|
+
if ("undefined" == typeof window) try {
|
|
20155
|
+
// Dynamically import the config loader to avoid bundling issues in browser
|
|
20156
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20157
|
+
const {loadThemeFromConfigSync: loadThemeFromConfigSync} = require("../config/configLoader"), configTokens = loadThemeFromConfigSync();
|
|
20158
|
+
if (configTokens && Object.keys(configTokens).length > 0)
|
|
20159
|
+
// For simplicity, we'll treat config tokens as a special theme name
|
|
20160
|
+
return "config-theme";
|
|
20161
|
+
} catch (error) {
|
|
20162
|
+
console.warn("Failed to load theme from config, using default");
|
|
21143
20163
|
}
|
|
21144
|
-
//
|
|
21145
|
-
|
|
21146
|
-
|
|
21147
|
-
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
21153
|
-
|
|
21154
|
-
|
|
21155
|
-
|
|
21156
|
-
|
|
21157
|
-
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
// Use ThemeApplicator for Theme objects
|
|
21164
|
-
themeApplicator?.applyTheme(theme) : injectCSS$1(createTheme(theme), "atomix-theme"));
|
|
21165
|
-
}), [ activeTheme, themeApplicator ]), setTheme = React.useCallback((async (theme, options) => {
|
|
21166
|
-
const {removePrevious: removePrevious = !0, fallbackOnError: fallbackOnError = !0, customPath: customPath} = options || {};
|
|
20164
|
+
// Default fallback
|
|
20165
|
+
return "default";
|
|
20166
|
+
}), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => initialDefaultTheme)), [activeTheme, setActiveTheme] = React.useState(null), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({});
|
|
20167
|
+
// Apply initial theme attributes to document element
|
|
20168
|
+
React.useEffect((() => {
|
|
20169
|
+
isServer() || ((dataAttribute, themeName) => {
|
|
20170
|
+
isServer() || (
|
|
20171
|
+
// Set data attribute on body
|
|
20172
|
+
document.body.setAttribute(dataAttribute, themeName),
|
|
20173
|
+
// Also set on documentElement for broader compatibility
|
|
20174
|
+
document.documentElement.setAttribute(dataAttribute, themeName));
|
|
20175
|
+
})(String(currentTheme), dataAttribute);
|
|
20176
|
+
}), [ currentTheme, dataAttribute ]),
|
|
20177
|
+
// Handle theme persistence
|
|
20178
|
+
React.useEffect((() => {
|
|
20179
|
+
enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
|
|
20180
|
+
}), [ currentTheme, storageKey, enablePersistence ]);
|
|
20181
|
+
// Function to set theme with proper type handling
|
|
20182
|
+
const setTheme = React.useCallback((async (theme, options) => {
|
|
21167
20183
|
setIsLoading(!0), setError(null);
|
|
21168
20184
|
try {
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
|
|
21181
|
-
if (
|
|
21182
|
-
|
|
21183
|
-
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
|
|
21188
|
-
|
|
21189
|
-
|
|
21190
|
-
|
|
21191
|
-
|
|
21192
|
-
|
|
21193
|
-
|
|
21194
|
-
|
|
21195
|
-
|
|
21196
|
-
|
|
21197
|
-
|
|
21198
|
-
|
|
21199
|
-
|
|
21200
|
-
|
|
21201
|
-
|
|
21202
|
-
|
|
21203
|
-
|
|
21204
|
-
|
|
21205
|
-
|
|
21206
|
-
|
|
21207
|
-
// Try as link ID first, then as theme name
|
|
21208
|
-
let link = document.getElementById(themeNameOrLinkId);
|
|
21209
|
-
if (!link) {
|
|
21210
|
-
const linkId = getThemeLinkId(themeNameOrLinkId);
|
|
21211
|
-
link = document.getElementById(linkId);
|
|
21212
|
-
}
|
|
21213
|
-
link && link.remove();
|
|
21214
|
-
})(previousThemeRef.current),
|
|
21215
|
-
// Load CSS if not already loaded
|
|
21216
|
-
isThemeLoaded(theme) || (await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(theme)),
|
|
21217
|
-
// Apply theme attributes
|
|
21218
|
-
((dataAttribute, themeName) => {
|
|
21219
|
-
isServer() || (
|
|
21220
|
-
// Set data attribute on body
|
|
21221
|
-
document.body.setAttribute(dataAttribute, themeName),
|
|
21222
|
-
// Also set on documentElement for broader compatibility
|
|
21223
|
-
document.documentElement.setAttribute(dataAttribute, themeName));
|
|
21224
|
-
})(dataAttribute, theme),
|
|
21225
|
-
// Update state
|
|
21226
|
-
previousThemeRef.current = currentTheme, setCurrentTheme(theme), setActiveTheme(null),
|
|
21227
|
-
previousThemeRef.current, Date.now(), handleThemeChange(theme),
|
|
21228
|
-
// Persist to storage
|
|
21229
|
-
enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, theme),
|
|
21230
|
-
setIsLoading(!1);
|
|
20185
|
+
let themeName, themeObj = null;
|
|
20186
|
+
// If it's a string theme name, load the associated CSS
|
|
20187
|
+
if ("string" == typeof theme ? themeName = theme :
|
|
20188
|
+
// If it's a Theme object or DesignTokens, we need to process it
|
|
20189
|
+
function(theme) {
|
|
20190
|
+
return "object" == typeof theme && null !== theme && "__isJSTheme" in theme && !0 === theme.__isJSTheme;
|
|
20191
|
+
}(theme) ? (themeObj = theme,
|
|
20192
|
+
// For JS themes, we use a generic name
|
|
20193
|
+
themeName = "js-theme", setActiveTheme(themeObj)) :
|
|
20194
|
+
// For DesignTokens, we might create a theme from tokens
|
|
20195
|
+
themeName = "tokens-theme", "string" == typeof theme && themes[theme]) {
|
|
20196
|
+
// Check if theme is already loading
|
|
20197
|
+
if (themePromisesRef.current[theme]) return await themePromisesRef.current[theme],
|
|
20198
|
+
setCurrentTheme(theme), setActiveTheme(null), void handleThemeChange(theme);
|
|
20199
|
+
// Load CSS theme
|
|
20200
|
+
const themeLoadPromise = new Promise((async (resolve, reject) => {
|
|
20201
|
+
try {
|
|
20202
|
+
if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
|
|
20203
|
+
{
|
|
20204
|
+
// Build CSS path using utility function
|
|
20205
|
+
const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
|
|
20206
|
+
// Remove any previously loaded theme CSS
|
|
20207
|
+
removeCSS(`theme-${String(currentTheme)}`),
|
|
20208
|
+
// Inject new theme CSS
|
|
20209
|
+
await injectCSS$1(cssPath, `theme-${theme}`), loadedThemesRef.current.add(theme),
|
|
20210
|
+
setCurrentTheme(theme), setActiveTheme(null), handleThemeChange(theme), resolve();
|
|
20211
|
+
}
|
|
20212
|
+
} catch (err) {
|
|
20213
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
20214
|
+
setError(error), handleError(error, String(theme)), reject(error);
|
|
20215
|
+
}
|
|
20216
|
+
}));
|
|
20217
|
+
themePromisesRef.current[theme] = themeLoadPromise, await themeLoadPromise;
|
|
20218
|
+
} else themeObj ? (
|
|
20219
|
+
// For JS themes, set them directly
|
|
20220
|
+
setCurrentTheme(themeName), setActiveTheme(themeObj), handleThemeChange(themeObj)) : (
|
|
20221
|
+
// For string theme that isn't in our themes record, just set the name
|
|
20222
|
+
setCurrentTheme(themeName), setActiveTheme(null), handleThemeChange(themeName));
|
|
21231
20223
|
} catch (err) {
|
|
21232
20224
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
21233
|
-
|
|
21234
|
-
|
|
20225
|
+
setError(error), handleError(error, String(theme));
|
|
20226
|
+
} finally {
|
|
20227
|
+
setIsLoading(!1);
|
|
21235
20228
|
}
|
|
21236
|
-
}), [
|
|
21237
|
-
if (
|
|
20229
|
+
}), [ themes, currentTheme, handleThemeChange, handleError, basePath, useMinified, cdnPath ]), isThemeLoaded = React.useCallback((themeName => loadedThemesRef.current.has(themeName)), []), preloadTheme = React.useCallback((async themeName => {
|
|
20230
|
+
if (themes[themeName] && !isThemeLoaded(themeName)) {
|
|
21238
20231
|
setIsLoading(!0);
|
|
21239
20232
|
try {
|
|
21240
|
-
|
|
21241
|
-
const
|
|
21242
|
-
|
|
20233
|
+
// Build CSS path using utility function
|
|
20234
|
+
const cssPath = buildThemePath(themeName, basePath, useMinified, cdnPath);
|
|
20235
|
+
// Preload CSS by fetching it
|
|
20236
|
+
await fetch(cssPath), loadedThemesRef.current.add(themeName);
|
|
21243
20237
|
} catch (err) {
|
|
21244
20238
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
21245
|
-
|
|
20239
|
+
setError(error), handleError(error, themeName);
|
|
21246
20240
|
} finally {
|
|
21247
20241
|
setIsLoading(!1);
|
|
21248
20242
|
}
|
|
21249
20243
|
}
|
|
21250
|
-
}), [
|
|
21251
|
-
|
|
21252
|
-
// Initialize default theme on mount
|
|
21253
|
-
React.useEffect((() => {
|
|
21254
|
-
isServer() || (async () => {
|
|
21255
|
-
// Use the initial default theme we computed
|
|
21256
|
-
const defaultThemeValue = initialDefaultTheme;
|
|
21257
|
-
if (defaultThemeValue) try {
|
|
21258
|
-
null === defaultThemeValue || "object" != typeof defaultThemeValue || "palette" in defaultThemeValue || "typography" in defaultThemeValue || "__isJSTheme" in defaultThemeValue || "string" == typeof defaultThemeValue ?
|
|
21259
|
-
// Handle string or Theme object
|
|
21260
|
-
await setTheme(defaultThemeValue, {
|
|
21261
|
-
removePrevious: !1,
|
|
21262
|
-
fallbackOnError: !0
|
|
21263
|
-
}) : (
|
|
21264
|
-
// Apply config tokens directly
|
|
21265
|
-
await applyJSTheme(defaultThemeValue, !1),
|
|
21266
|
-
// Update state and emit events
|
|
21267
|
-
setCurrentTheme("config-theme"), setActiveTheme(null), Date.now(), handleThemeChange("config-theme"),
|
|
21268
|
-
// Persist to storage
|
|
21269
|
-
enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, "config-theme"));
|
|
21270
|
-
} catch (err) {
|
|
21271
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
21272
|
-
throw logger.error("Failed to load theme from config", error, {
|
|
21273
|
-
theme: defaultThemeValue
|
|
21274
|
-
}), handleError(error, "config-theme"), setError(error), error;
|
|
21275
|
-
}
|
|
21276
|
-
})();
|
|
21277
|
-
}
|
|
21278
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21279
|
-
), []), // Only run once on mount - initialDefaultTheme is stable
|
|
21280
|
-
// Preload themes
|
|
21281
|
-
React.useEffect((() => {
|
|
21282
|
-
!isServer() && preload && 0 !== preload.length && (async () => {
|
|
21283
|
-
for (const themeName of preload) if (!isThemeLoaded(themeName)) try {
|
|
21284
|
-
await preloadTheme(themeName);
|
|
21285
|
-
} catch (err) {
|
|
21286
|
-
// Silently fail for preload
|
|
21287
|
-
logger.warn(`Failed to preload theme "${themeName}"`, {
|
|
21288
|
-
error: err instanceof Error ? err.message : String(err)
|
|
21289
|
-
});
|
|
21290
|
-
}
|
|
21291
|
-
})();
|
|
21292
|
-
}), [ preload, preloadTheme, logger ]);
|
|
21293
|
-
// Context value
|
|
21294
|
-
const contextValue = React.useMemo((() => ({
|
|
21295
|
-
theme: currentTheme,
|
|
20244
|
+
}), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = React.useMemo((() => ({})), []), contextValue = React.useMemo((() => ({
|
|
20245
|
+
theme: "string" == typeof currentTheme ? currentTheme : "js-theme",
|
|
21296
20246
|
activeTheme: activeTheme,
|
|
21297
20247
|
setTheme: setTheme,
|
|
21298
|
-
availableThemes:
|
|
20248
|
+
availableThemes: Object.entries(themes).map((([name, metadata]) => ({
|
|
20249
|
+
...metadata
|
|
20250
|
+
}))),
|
|
21299
20251
|
isLoading: isLoading,
|
|
21300
20252
|
error: error,
|
|
21301
|
-
isThemeLoaded: isThemeLoaded
|
|
21302
|
-
preloadTheme: preloadTheme
|
|
21303
|
-
|
|
21304
|
-
|
|
20253
|
+
isThemeLoaded: isThemeLoaded,
|
|
20254
|
+
preloadTheme: preloadTheme,
|
|
20255
|
+
themeManager: themeManager
|
|
20256
|
+
})), [ currentTheme, activeTheme, setTheme, themes, isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
|
|
20257
|
+
// Check if theme is loaded
|
|
20258
|
+
return jsxRuntime.jsx(ThemeContext.Provider, {
|
|
21305
20259
|
value: contextValue,
|
|
21306
20260
|
children: children
|
|
21307
20261
|
});
|
|
@@ -21347,6 +20301,219 @@ class ThemeApplicator {
|
|
|
21347
20301
|
};
|
|
21348
20302
|
}
|
|
21349
20303
|
|
|
20304
|
+
function useThemeTokens() {
|
|
20305
|
+
const {theme: theme, activeTheme: activeTheme} = useTheme(), getToken = React.useCallback(((tokenName, fallback) => {
|
|
20306
|
+
if ("undefined" == typeof window) return fallback || "";
|
|
20307
|
+
const cssVarName = `--atomix-${tokenName}`;
|
|
20308
|
+
return getComputedStyle(document.documentElement).getPropertyValue(cssVarName).trim() || fallback || "";
|
|
20309
|
+
}), []), getThemeValue = React.useCallback(((path, fallback) => {
|
|
20310
|
+
var _context;
|
|
20311
|
+
return activeTheme && _reduceInstanceProperty(_context = path.split(".")).call(_context, ((obj, key) => obj?.[key]), activeTheme) || fallback;
|
|
20312
|
+
// Navigate through nested theme object using dot notation
|
|
20313
|
+
}), [ activeTheme ]);
|
|
20314
|
+
// Helper function to get CSS variable value
|
|
20315
|
+
// Return unified API for accessing theme values
|
|
20316
|
+
return {
|
|
20317
|
+
theme: theme,
|
|
20318
|
+
activeTheme: activeTheme,
|
|
20319
|
+
getToken: getToken,
|
|
20320
|
+
getThemeValue: getThemeValue,
|
|
20321
|
+
// Commonly used tokens with fallbacks
|
|
20322
|
+
colors: {
|
|
20323
|
+
primary: getToken("primary", "#3b82f6"),
|
|
20324
|
+
secondary: getToken("secondary", "#10b981"),
|
|
20325
|
+
error: getToken("error", "#ef4444"),
|
|
20326
|
+
success: getToken("success", "#22c55e"),
|
|
20327
|
+
warning: getToken("warning", "#eab308"),
|
|
20328
|
+
info: getToken("info", "#3b82f6"),
|
|
20329
|
+
light: getToken("light", "#f9fafb"),
|
|
20330
|
+
dark: getToken("dark", "#111827")
|
|
20331
|
+
},
|
|
20332
|
+
spacing: {
|
|
20333
|
+
1: getToken("spacing-1", "0.25rem"),
|
|
20334
|
+
2: getToken("spacing-2", "0.5rem"),
|
|
20335
|
+
3: getToken("spacing-3", "0.75rem"),
|
|
20336
|
+
4: getToken("spacing-4", "1rem"),
|
|
20337
|
+
5: getToken("spacing-5", "1.25rem"),
|
|
20338
|
+
6: getToken("spacing-6", "1.5rem"),
|
|
20339
|
+
8: getToken("spacing-8", "2rem"),
|
|
20340
|
+
10: getToken("spacing-10", "2.5rem"),
|
|
20341
|
+
12: getToken("spacing-12", "3rem"),
|
|
20342
|
+
16: getToken("spacing-16", "4rem"),
|
|
20343
|
+
20: getToken("spacing-20", "5rem")
|
|
20344
|
+
},
|
|
20345
|
+
borderRadius: {
|
|
20346
|
+
sm: getToken("border-radius-sm", "0.25rem"),
|
|
20347
|
+
md: getToken("border-radius-md", "0.5rem"),
|
|
20348
|
+
lg: getToken("border-radius-lg", "0.75rem"),
|
|
20349
|
+
xl: getToken("border-radius-xl", "1rem"),
|
|
20350
|
+
full: getToken("border-radius-full", "9999px")
|
|
20351
|
+
},
|
|
20352
|
+
typography: {
|
|
20353
|
+
fontFamily: {
|
|
20354
|
+
sans: getToken("font-sans-serif", "Inter, system-ui, sans-serif"),
|
|
20355
|
+
serif: getToken("font-serif", "Georgia, serif"),
|
|
20356
|
+
mono: getToken("font-monospace", "Fira Code, monospace")
|
|
20357
|
+
},
|
|
20358
|
+
fontSize: {
|
|
20359
|
+
xs: getToken("font-size-xs", "0.75rem"),
|
|
20360
|
+
sm: getToken("font-size-sm", "0.875rem"),
|
|
20361
|
+
md: getToken("font-size-md", "1rem"),
|
|
20362
|
+
lg: getToken("font-size-lg", "1.125rem"),
|
|
20363
|
+
xl: getToken("font-size-xl", "1.25rem"),
|
|
20364
|
+
"2xl": getToken("font-size-2xl", "1.5rem"),
|
|
20365
|
+
"3xl": getToken("font-size-3xl", "1.875rem"),
|
|
20366
|
+
"4xl": getToken("font-size-4xl", "2.25rem")
|
|
20367
|
+
},
|
|
20368
|
+
fontWeight: {
|
|
20369
|
+
light: getToken("font-weight-light", "300"),
|
|
20370
|
+
normal: getToken("font-weight-normal", "400"),
|
|
20371
|
+
medium: getToken("font-weight-medium", "500"),
|
|
20372
|
+
semibold: getToken("font-weight-semibold", "600"),
|
|
20373
|
+
bold: getToken("font-weight-bold", "700")
|
|
20374
|
+
}
|
|
20375
|
+
},
|
|
20376
|
+
shadows: {
|
|
20377
|
+
sm: getToken("box-shadow-sm", "0 1px 2px 0 rgba(0, 0, 0, 0.05)"),
|
|
20378
|
+
md: getToken("box-shadow-md", "0 4px 6px -1px rgba(0, 0, 0, 0.1)"),
|
|
20379
|
+
lg: getToken("box-shadow-lg", "0 10px 15px -3px rgba(0, 0, 0, 0.1)"),
|
|
20380
|
+
xl: getToken("box-shadow-xl", "0 20px 25px -5px rgba(0, 0, 0, 0.1)"),
|
|
20381
|
+
inset: getToken("box-shadow-inset", "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)")
|
|
20382
|
+
},
|
|
20383
|
+
transitions: {
|
|
20384
|
+
fast: getToken("transition-fast", "150ms"),
|
|
20385
|
+
base: getToken("transition-base", "200ms"),
|
|
20386
|
+
slow: getToken("transition-slow", "300ms")
|
|
20387
|
+
}
|
|
20388
|
+
};
|
|
20389
|
+
}
|
|
20390
|
+
|
|
20391
|
+
/**
|
|
20392
|
+
* Theme System Error Handling
|
|
20393
|
+
*
|
|
20394
|
+
* Centralized error handling for the Atomix theme system.
|
|
20395
|
+
* Provides custom error classes and logging utilities.
|
|
20396
|
+
*/
|
|
20397
|
+
/**
|
|
20398
|
+
* Theme error codes
|
|
20399
|
+
*/ var ThemeErrorCode, LogLevel;
|
|
20400
|
+
|
|
20401
|
+
!function(ThemeErrorCode) {
|
|
20402
|
+
/** Theme not found in registry */
|
|
20403
|
+
ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
|
|
20404
|
+
/** Theme failed to load */
|
|
20405
|
+
ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
|
|
20406
|
+
/** Theme validation failed */
|
|
20407
|
+
ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
|
|
20408
|
+
/** Configuration loading failed */
|
|
20409
|
+
ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
|
|
20410
|
+
/** Configuration validation failed */
|
|
20411
|
+
ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
|
|
20412
|
+
/** Circular dependency detected */
|
|
20413
|
+
ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
|
|
20414
|
+
/** Missing dependency */
|
|
20415
|
+
ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
|
|
20416
|
+
/** Storage operation failed */
|
|
20417
|
+
ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
|
|
20418
|
+
/** Invalid theme name */
|
|
20419
|
+
ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
|
|
20420
|
+
/** CSS injection failed */
|
|
20421
|
+
ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
|
|
20422
|
+
/** Unknown error */
|
|
20423
|
+
ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
|
20424
|
+
}(ThemeErrorCode || (ThemeErrorCode = {}));
|
|
20425
|
+
|
|
20426
|
+
/**
|
|
20427
|
+
* Custom error class for theme-related errors
|
|
20428
|
+
*/
|
|
20429
|
+
class ThemeError extends Error {
|
|
20430
|
+
constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
|
|
20431
|
+
super(message), this.name = "ThemeError", this.code = code, this.context = context,
|
|
20432
|
+
this.timestamp = Date.now(),
|
|
20433
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
20434
|
+
Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
|
|
20435
|
+
}
|
|
20436
|
+
/**
|
|
20437
|
+
* Convert error to JSON for logging
|
|
20438
|
+
*/ toJSON() {
|
|
20439
|
+
return {
|
|
20440
|
+
name: this.name,
|
|
20441
|
+
message: this.message,
|
|
20442
|
+
code: this.code,
|
|
20443
|
+
context: this.context,
|
|
20444
|
+
timestamp: this.timestamp,
|
|
20445
|
+
stack: this.stack
|
|
20446
|
+
};
|
|
20447
|
+
}
|
|
20448
|
+
}
|
|
20449
|
+
|
|
20450
|
+
/**
|
|
20451
|
+
* Log level
|
|
20452
|
+
*/ !function(LogLevel) {
|
|
20453
|
+
LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
|
|
20454
|
+
LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
|
|
20455
|
+
}(LogLevel || (LogLevel = {}));
|
|
20456
|
+
|
|
20457
|
+
/**
|
|
20458
|
+
* Theme Logger
|
|
20459
|
+
*
|
|
20460
|
+
* Centralized logging for the theme system.
|
|
20461
|
+
* Replaces console statements with structured logging.
|
|
20462
|
+
*/
|
|
20463
|
+
class ThemeLogger {
|
|
20464
|
+
constructor(config = {}) {
|
|
20465
|
+
this.config = {
|
|
20466
|
+
level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
|
|
20467
|
+
enableConsole: config.enableConsole ?? !0,
|
|
20468
|
+
onError: config.onError,
|
|
20469
|
+
onWarn: config.onWarn,
|
|
20470
|
+
onInfo: config.onInfo,
|
|
20471
|
+
onDebug: config.onDebug
|
|
20472
|
+
};
|
|
20473
|
+
}
|
|
20474
|
+
/**
|
|
20475
|
+
* Log an error
|
|
20476
|
+
*/ error(message, error, context) {
|
|
20477
|
+
if (this.config.level < LogLevel.ERROR) return;
|
|
20478
|
+
const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
|
|
20479
|
+
this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
|
|
20480
|
+
error: errorObj,
|
|
20481
|
+
context: {
|
|
20482
|
+
...context,
|
|
20483
|
+
...themeError.context
|
|
20484
|
+
},
|
|
20485
|
+
code: themeError.code
|
|
20486
|
+
}), this.config.onError?.(themeError, context);
|
|
20487
|
+
}
|
|
20488
|
+
/**
|
|
20489
|
+
* Log a warning
|
|
20490
|
+
*/ warn(message, context) {
|
|
20491
|
+
this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
|
|
20492
|
+
this.config.onWarn?.(message, context));
|
|
20493
|
+
}
|
|
20494
|
+
/**
|
|
20495
|
+
* Log an info message
|
|
20496
|
+
*/ info(message, context) {
|
|
20497
|
+
this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
|
|
20498
|
+
this.config.onInfo?.(message, context));
|
|
20499
|
+
}
|
|
20500
|
+
/**
|
|
20501
|
+
* Log a debug message
|
|
20502
|
+
*/ debug(message, context) {
|
|
20503
|
+
this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
|
|
20504
|
+
}
|
|
20505
|
+
}
|
|
20506
|
+
|
|
20507
|
+
/**
|
|
20508
|
+
* Default logger instance
|
|
20509
|
+
*/ let defaultLogger = null;
|
|
20510
|
+
|
|
20511
|
+
/**
|
|
20512
|
+
* Get or create default logger
|
|
20513
|
+
*/ function getLogger() {
|
|
20514
|
+
return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
|
|
20515
|
+
}
|
|
20516
|
+
|
|
21350
20517
|
/**
|
|
21351
20518
|
* Default fallback UI
|
|
21352
20519
|
*/ const DefaultFallback = ({error: error, errorInfo: errorInfo}) => {
|
|
@@ -21395,7 +20562,7 @@ class ThemeApplicator {
|
|
|
21395
20562
|
},
|
|
21396
20563
|
children: JSON.stringify(context, null, 2)
|
|
21397
20564
|
}) ]
|
|
21398
|
-
}), "development" === process.env
|
|
20565
|
+
}), ("undefined" == typeof process || "development" === process.env?.NODE_ENV) && errorInfo && jsxRuntime.jsxs("details", {
|
|
21399
20566
|
style: {
|
|
21400
20567
|
marginTop: "1rem"
|
|
21401
20568
|
},
|
|
@@ -21491,6 +20658,130 @@ class ThemeApplicator {
|
|
|
21491
20658
|
}
|
|
21492
20659
|
}
|
|
21493
20660
|
|
|
20661
|
+
/**
|
|
20662
|
+
* Theme Applicator
|
|
20663
|
+
*
|
|
20664
|
+
* Applies theme configurations to the DOM, including CSS variables,
|
|
20665
|
+
* component overrides, typography, spacing, and color palettes.
|
|
20666
|
+
*
|
|
20667
|
+
* Uses the unified theme system for CSS generation and injection.
|
|
20668
|
+
*/
|
|
20669
|
+
/**
|
|
20670
|
+
* Theme applicator class for runtime theme application
|
|
20671
|
+
*
|
|
20672
|
+
* Uses the unified theme system for efficient CSS variable generation and injection.
|
|
20673
|
+
*/ class ThemeApplicator {
|
|
20674
|
+
constructor(root = document.documentElement) {
|
|
20675
|
+
this.styleId = "atomix-theme-applicator", this.root = root;
|
|
20676
|
+
}
|
|
20677
|
+
/**
|
|
20678
|
+
* Apply a complete theme configuration
|
|
20679
|
+
*
|
|
20680
|
+
* Uses the unified theme system to convert Theme to DesignTokens and inject CSS.
|
|
20681
|
+
* Automatically respects atomix.config.ts when using DesignTokens.
|
|
20682
|
+
*/ applyTheme(theme) {
|
|
20683
|
+
// Clear previously applied variables
|
|
20684
|
+
this.clearAppliedVars(),
|
|
20685
|
+
// Check if it's DesignTokens
|
|
20686
|
+
this.isDesignTokens(theme) ?
|
|
20687
|
+
// Direct DesignTokens - use unified theme system (with config support)
|
|
20688
|
+
this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
|
|
20689
|
+
selector: ":root",
|
|
20690
|
+
prefix: "atomix"
|
|
20691
|
+
}), this.styleId),
|
|
20692
|
+
// Apply component overrides (only for Theme objects)
|
|
20693
|
+
!this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
|
|
20694
|
+
}
|
|
20695
|
+
/**
|
|
20696
|
+
* Apply DesignTokens using unified theme system
|
|
20697
|
+
*
|
|
20698
|
+
* Uses createTheme() which automatically loads from atomix.config.ts
|
|
20699
|
+
* if no tokens are provided, ensuring config is always respected.
|
|
20700
|
+
*/ applyDesignTokens(tokens) {
|
|
20701
|
+
// Inject CSS into DOM
|
|
20702
|
+
injectCSS$1(createTheme(tokens, {
|
|
20703
|
+
selector: ":root",
|
|
20704
|
+
prefix: "atomix"
|
|
20705
|
+
}), this.styleId);
|
|
20706
|
+
}
|
|
20707
|
+
/**
|
|
20708
|
+
* Check if object is DesignTokens
|
|
20709
|
+
*/ isDesignTokens(obj) {
|
|
20710
|
+
// DesignTokens is a flat object with string keys, no nested structures
|
|
20711
|
+
return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
|
|
20712
|
+
}
|
|
20713
|
+
/**
|
|
20714
|
+
* Apply global CSS variables (for component overrides)
|
|
20715
|
+
*/ applyGlobalCSSVars(vars) {
|
|
20716
|
+
Object.entries(vars).forEach((([key, value]) => {
|
|
20717
|
+
this.root.style.setProperty(key, String(value));
|
|
20718
|
+
}));
|
|
20719
|
+
}
|
|
20720
|
+
/**
|
|
20721
|
+
* Apply component-level overrides
|
|
20722
|
+
*/ applyComponentOverrides(overrides) {
|
|
20723
|
+
Object.entries(overrides).forEach((([componentName, override]) => {
|
|
20724
|
+
override && this.applyComponentOverride(componentName, override);
|
|
20725
|
+
}));
|
|
20726
|
+
}
|
|
20727
|
+
/**
|
|
20728
|
+
* Apply override for a specific component
|
|
20729
|
+
*/ applyComponentOverride(componentName, override) {
|
|
20730
|
+
const vars = {}, componentKey = componentName.toLowerCase();
|
|
20731
|
+
// Apply component-level CSS variables
|
|
20732
|
+
override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
|
|
20733
|
+
// If key doesn't start with --, add component prefix
|
|
20734
|
+
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
|
|
20735
|
+
vars[varKey] = value;
|
|
20736
|
+
})),
|
|
20737
|
+
// Apply part-specific CSS variables
|
|
20738
|
+
override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
|
|
20739
|
+
partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
|
|
20740
|
+
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
|
|
20741
|
+
vars[varKey] = value;
|
|
20742
|
+
}));
|
|
20743
|
+
})),
|
|
20744
|
+
// Apply variant-specific CSS variables
|
|
20745
|
+
override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
|
|
20746
|
+
variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
|
|
20747
|
+
const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
|
|
20748
|
+
vars[varKey] = value;
|
|
20749
|
+
}));
|
|
20750
|
+
})), this.applyGlobalCSSVars(vars);
|
|
20751
|
+
}
|
|
20752
|
+
/**
|
|
20753
|
+
* Clear all applied CSS variables
|
|
20754
|
+
*/ clearAppliedVars() {
|
|
20755
|
+
removeCSS(this.styleId);
|
|
20756
|
+
}
|
|
20757
|
+
/**
|
|
20758
|
+
* Remove theme application
|
|
20759
|
+
*/ removeTheme() {
|
|
20760
|
+
this.clearAppliedVars(), removeCSS(this.styleId);
|
|
20761
|
+
}
|
|
20762
|
+
/**
|
|
20763
|
+
* Update specific CSS variables without clearing all
|
|
20764
|
+
*/ updateCSSVars(vars) {
|
|
20765
|
+
this.applyGlobalCSSVars(vars);
|
|
20766
|
+
}
|
|
20767
|
+
}
|
|
20768
|
+
|
|
20769
|
+
/**
|
|
20770
|
+
* Global theme applicator instance
|
|
20771
|
+
*/ let globalApplicator = null;
|
|
20772
|
+
|
|
20773
|
+
/**
|
|
20774
|
+
* Get or create global theme applicator
|
|
20775
|
+
*/ function getThemeApplicator() {
|
|
20776
|
+
return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
|
|
20777
|
+
}
|
|
20778
|
+
|
|
20779
|
+
/**
|
|
20780
|
+
* Apply theme using global applicator
|
|
20781
|
+
*/ function applyTheme(theme) {
|
|
20782
|
+
getThemeApplicator().applyTheme(theme);
|
|
20783
|
+
}
|
|
20784
|
+
|
|
21494
20785
|
const VIEWPORT_PRESETS = {
|
|
21495
20786
|
mobile: {
|
|
21496
20787
|
width: 375,
|
|
@@ -23717,64 +23008,27 @@ class RTLManager {
|
|
|
23717
23008
|
/**
|
|
23718
23009
|
* Save theme to CSS file
|
|
23719
23010
|
*/ async function saveTheme(css, filePath) {
|
|
23720
|
-
await
|
|
23011
|
+
await async function(css, filePath) {
|
|
23012
|
+
// Check if in browser environment
|
|
23013
|
+
if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
|
|
23014
|
+
// Dynamic import to avoid bundling Node.js modules in browser builds
|
|
23015
|
+
const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
|
|
23016
|
+
await fs.mkdir(dir, {
|
|
23017
|
+
recursive: !0
|
|
23018
|
+
}),
|
|
23019
|
+
// Write file
|
|
23020
|
+
await fs.writeFile(filePath, css, "utf8");
|
|
23021
|
+
}
|
|
23022
|
+
/**
|
|
23023
|
+
* Theme System Constants
|
|
23024
|
+
*
|
|
23025
|
+
* Centralized constants for the theme system to avoid magic numbers and strings.
|
|
23026
|
+
*/
|
|
23027
|
+
/**
|
|
23028
|
+
* Default storage key for theme persistence
|
|
23029
|
+
*/ (css, filePath);
|
|
23721
23030
|
}
|
|
23722
23031
|
|
|
23723
|
-
var themeImport = Object.freeze({
|
|
23724
|
-
__proto__: null,
|
|
23725
|
-
RTLManager: RTLManager,
|
|
23726
|
-
ThemeApplicator: ThemeApplicator,
|
|
23727
|
-
ThemeComparator: ThemeComparator,
|
|
23728
|
-
ThemeContext: ThemeContext,
|
|
23729
|
-
ThemeErrorBoundary: ThemeErrorBoundary,
|
|
23730
|
-
ThemeInspector: ThemeInspector,
|
|
23731
|
-
ThemeLiveEditor: ThemeLiveEditor,
|
|
23732
|
-
ThemePreview: ThemePreview,
|
|
23733
|
-
ThemeProvider: ThemeProvider,
|
|
23734
|
-
ThemeRegistry: ThemeRegistry,
|
|
23735
|
-
ThemeValidator: ThemeValidator,
|
|
23736
|
-
applyCSSVariables: applyCSSVariables,
|
|
23737
|
-
applyTheme: applyTheme,
|
|
23738
|
-
createDesignTokensFromTheme: createDesignTokensFromTheme,
|
|
23739
|
-
createTheme: createTheme,
|
|
23740
|
-
createThemeObject: createThemeObject,
|
|
23741
|
-
createTokens: createTokens,
|
|
23742
|
-
cssVarsToStyle: cssVarsToStyle,
|
|
23743
|
-
deepMerge: deepMerge,
|
|
23744
|
-
defaultTokens: defaultTokens,
|
|
23745
|
-
designTokensToCSSVars: designTokensToCSSVars,
|
|
23746
|
-
designTokensToTheme: designTokensToTheme,
|
|
23747
|
-
extendTheme: extendTheme,
|
|
23748
|
-
extractComponentName: extractComponentName,
|
|
23749
|
-
generateCSSVariableName: generateCSSVariableName,
|
|
23750
|
-
generateCSSVariables: generateCSSVariables$1,
|
|
23751
|
-
generateCSSVariablesForSelector: generateCSSVariablesForSelector,
|
|
23752
|
-
generateComponentCSSVars: generateComponentCSSVars,
|
|
23753
|
-
getCSSVariable: getCSSVariable,
|
|
23754
|
-
getDesignTokensFromTheme: getDesignTokensFromTheme,
|
|
23755
|
-
getThemeApplicator: getThemeApplicator,
|
|
23756
|
-
injectCSS: injectCSS$1,
|
|
23757
|
-
injectTheme: injectTheme,
|
|
23758
|
-
isCSSInjected: isCSSInjected,
|
|
23759
|
-
isDesignTokens: isDesignTokens,
|
|
23760
|
-
isThemeObject: isThemeObject,
|
|
23761
|
-
isValidCSSVariableName: isValidCSSVariableName,
|
|
23762
|
-
loadThemeFromConfig: loadThemeFromConfig,
|
|
23763
|
-
loadThemeFromConfigSync: loadThemeFromConfigSync,
|
|
23764
|
-
mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
|
|
23765
|
-
mergeCSSVars: mergeCSSVars,
|
|
23766
|
-
mergeTheme: mergeTheme,
|
|
23767
|
-
removeCSS: removeCSS,
|
|
23768
|
-
removeCSSVariables: removeCSSVariables,
|
|
23769
|
-
removeTheme: removeTheme,
|
|
23770
|
-
saveCSSFile: saveCSSFile,
|
|
23771
|
-
saveCSSFileSync: saveCSSFileSync,
|
|
23772
|
-
saveTheme: saveTheme,
|
|
23773
|
-
themeToDesignTokens: themeToDesignTokens,
|
|
23774
|
-
useHistory: useHistory,
|
|
23775
|
-
useTheme: useTheme
|
|
23776
|
-
});
|
|
23777
|
-
|
|
23778
23032
|
/**
|
|
23779
23033
|
* CSS Variables Constants
|
|
23780
23034
|
*
|
|
@@ -23783,7 +23037,8 @@ var themeImport = Object.freeze({
|
|
|
23783
23037
|
*/
|
|
23784
23038
|
/**
|
|
23785
23039
|
* Button CSS Variables
|
|
23786
|
-
*/
|
|
23040
|
+
*/
|
|
23041
|
+
const BUTTON_CSS_VARS = {
|
|
23787
23042
|
// Base properties
|
|
23788
23043
|
"--atomix-button-bg": "background-color",
|
|
23789
23044
|
"--atomix-button-color": "text color",
|
|
@@ -24054,216 +23309,126 @@ var themeImport = Object.freeze({
|
|
|
24054
23309
|
* Utility function to merge part styles
|
|
24055
23310
|
*/
|
|
24056
23311
|
function mergePartStyles(base, override) {
|
|
24057
|
-
if (base || override) return base ? override ? {
|
|
24058
|
-
className: [ base.className, override.className ].filter(Boolean).join(" "),
|
|
24059
|
-
style: {
|
|
24060
|
-
...base.style,
|
|
24061
|
-
...override.style
|
|
24062
|
-
}
|
|
24063
|
-
} : base : override;
|
|
24064
|
-
}
|
|
24065
|
-
|
|
24066
|
-
/**
|
|
24067
|
-
* Render a slot with the given props
|
|
24068
|
-
*
|
|
24069
|
-
* Priority order:
|
|
24070
|
-
* 1. render function
|
|
24071
|
-
* 2. component
|
|
24072
|
-
* 3. children
|
|
24073
|
-
* 4. fallback
|
|
24074
|
-
*
|
|
24075
|
-
* @example
|
|
24076
|
-
* renderSlot(
|
|
24077
|
-
* { render: (props) => <CustomButton {...props} /> },
|
|
24078
|
-
* { onClick: handleClick, children: 'Click me' }
|
|
24079
|
-
* )
|
|
24080
|
-
*/ function renderSlot(slot, props, fallback) {
|
|
24081
|
-
// No slot provided, use fallback
|
|
24082
|
-
if (!slot) return fallback;
|
|
24083
|
-
// Slot is a plain React node
|
|
24084
|
-
if ( React__default.default.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
|
|
24085
|
-
// Slot is an object with rendering options
|
|
24086
|
-
if ("object" == typeof slot && null !== slot) {
|
|
24087
|
-
const slotObj = slot;
|
|
24088
|
-
// Priority 1: render function
|
|
24089
|
-
if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
|
|
24090
|
-
// Priority 2: component
|
|
24091
|
-
if (slotObj.component) {
|
|
24092
|
-
const Component = slotObj.component;
|
|
24093
|
-
return jsxRuntime.jsx(Component, {
|
|
24094
|
-
...props
|
|
24095
|
-
});
|
|
24096
|
-
}
|
|
24097
|
-
// Priority 3: children
|
|
24098
|
-
if (void 0 !== slotObj.children) return slotObj.children;
|
|
24099
|
-
}
|
|
24100
|
-
// Fallback
|
|
24101
|
-
return fallback;
|
|
24102
|
-
}
|
|
24103
|
-
|
|
24104
|
-
/**
|
|
24105
|
-
* Check if a value is a slot configuration
|
|
24106
|
-
*/
|
|
24107
|
-
/**
|
|
24108
|
-
* Atomix Config Loader
|
|
24109
|
-
*
|
|
24110
|
-
* Helper functions to load atomix.config.ts from external projects.
|
|
24111
|
-
* Similar to how Tailwind loads tailwind.config.js
|
|
24112
|
-
*/
|
|
24113
|
-
/**
|
|
24114
|
-
* Load Atomix configuration from project root
|
|
24115
|
-
*
|
|
24116
|
-
* Attempts to load atomix.config.ts from the current working directory.
|
|
24117
|
-
* Falls back to default config if file doesn't exist.
|
|
24118
|
-
*
|
|
24119
|
-
* @param options - Loader options
|
|
24120
|
-
* @returns Loaded configuration or default
|
|
24121
|
-
*
|
|
24122
|
-
* @example
|
|
24123
|
-
* ```typescript
|
|
24124
|
-
* import { loadAtomixConfig } from '@shohojdhara/atomix/config';
|
|
24125
|
-
* import { createTheme } from '@shohojdhara/atomix/theme';
|
|
24126
|
-
*
|
|
24127
|
-
* const config = loadAtomixConfig();
|
|
24128
|
-
* const theme = createTheme(config.theme?.tokens || {});
|
|
24129
|
-
* ```
|
|
24130
|
-
*/
|
|
24131
|
-
function loadAtomixConfig(options = {}) {
|
|
24132
|
-
const {configPath: configPath = "atomix.config.ts", required: required = !1} = options, defaultConfig = {
|
|
24133
|
-
prefix: "atomix",
|
|
24134
|
-
theme: {
|
|
24135
|
-
extend: {}
|
|
24136
|
-
}
|
|
24137
|
-
};
|
|
24138
|
-
// Default config
|
|
24139
|
-
// In browser environments, config loading is not supported
|
|
24140
|
-
if ("undefined" != typeof window) {
|
|
24141
|
-
if (required) throw new Error("Config loading not supported in browser environment");
|
|
24142
|
-
return defaultConfig;
|
|
24143
|
-
}
|
|
24144
|
-
// Try to load config file
|
|
24145
|
-
try {
|
|
24146
|
-
// Use dynamic import for ESM compatibility
|
|
24147
|
-
const configModule = require(configPath), config = configModule.default || configModule;
|
|
24148
|
-
// Validate it's an AtomixConfig
|
|
24149
|
-
if (config && "object" == typeof config) return config;
|
|
24150
|
-
throw new Error("Invalid config format");
|
|
24151
|
-
} catch (error) {
|
|
24152
|
-
if (required) throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
|
|
24153
|
-
// Return default config if not required
|
|
24154
|
-
return defaultConfig;
|
|
24155
|
-
}
|
|
24156
|
-
}
|
|
24157
|
-
|
|
24158
|
-
/**
|
|
24159
|
-
* Resolve config path
|
|
24160
|
-
*
|
|
24161
|
-
* Finds atomix.config.ts in the project, checking common locations.
|
|
24162
|
-
* Returns null in browser environments where file system access is not available.
|
|
24163
|
-
*
|
|
24164
|
-
* This function is designed to work in Node.js environments only.
|
|
24165
|
-
* In browser builds, it will always return null without attempting to access Node.js modules.
|
|
24166
|
-
*
|
|
24167
|
-
* @internal This function uses Node.js modules and should not be called in browser environments.
|
|
24168
|
-
*/ function resolveConfigPath() {
|
|
24169
|
-
// Early return for browser environments - prevents any Node.js module access
|
|
24170
|
-
// This check happens before any require() calls, preventing bundlers from analyzing them
|
|
24171
|
-
if ("undefined" != typeof window || "undefined" == typeof process || !process.cwd) return null;
|
|
24172
|
-
// Only attempt to load Node.js modules in Node.js runtime
|
|
24173
|
-
// Use a lazy-loading pattern that prevents static analysis by bundlers
|
|
24174
|
-
try {
|
|
24175
|
-
// Create a function that only executes in Node.js runtime
|
|
24176
|
-
// Use string-based module names to prevent static analysis by bundlers
|
|
24177
|
-
const modules = (() => {
|
|
24178
|
-
// These requires are only executed at runtime in Node.js environments
|
|
24179
|
-
// They are marked as external in Rollup config and should not be bundled
|
|
24180
|
-
// Using string concatenation and computed property access to prevent static analysis
|
|
24181
|
-
if ("undefined" == typeof require) return null;
|
|
24182
|
-
// Use a try-catch wrapper to safely access require
|
|
24183
|
-
try {
|
|
24184
|
-
// Build module names dynamically to prevent static analysis
|
|
24185
|
-
const moduleNames = [ "fs", "path" ];
|
|
24186
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
24187
|
-
return {
|
|
24188
|
-
fs: require(moduleNames[0]),
|
|
24189
|
-
path: require(moduleNames[1])
|
|
24190
|
-
};
|
|
24191
|
-
} catch {
|
|
24192
|
-
return null;
|
|
24193
|
-
}
|
|
24194
|
-
})();
|
|
24195
|
-
if (!modules) return null;
|
|
24196
|
-
const {fs: fs, path: path} = modules, cwd = process.cwd(), possiblePaths = [ path.join(cwd, "atomix.config.ts"), path.join(cwd, "atomix.config.js"), path.join(cwd, "atomix.config.mjs") ];
|
|
24197
|
-
for (const configPath of possiblePaths) if (fs.existsSync(configPath)) return configPath;
|
|
24198
|
-
} catch (error) {
|
|
24199
|
-
// Silently fail in browser environments or when modules are unavailable
|
|
24200
|
-
return null;
|
|
24201
|
-
}
|
|
24202
|
-
return null;
|
|
24203
|
-
}
|
|
24204
|
-
|
|
24205
|
-
var loader = Object.freeze({
|
|
24206
|
-
__proto__: null,
|
|
24207
|
-
loadAtomixConfig: loadAtomixConfig,
|
|
24208
|
-
resolveConfigPath: resolveConfigPath
|
|
24209
|
-
});
|
|
24210
|
-
|
|
24211
|
-
/**
|
|
24212
|
-
* Atomix Configuration System
|
|
24213
|
-
*
|
|
24214
|
-
* Tailwind-like configuration for customizing the Atomix Design System.
|
|
24215
|
-
*
|
|
24216
|
-
* External developers can create `atomix.config.ts` in their project root
|
|
24217
|
-
* to customize design tokens, similar to Tailwind's tailwind.config.js
|
|
24218
|
-
*
|
|
24219
|
-
* @example
|
|
24220
|
-
* ```typescript
|
|
24221
|
-
* // atomix.config.ts (in your project)
|
|
24222
|
-
* import { defineConfig } from '@shohojdhara/atomix/config';
|
|
24223
|
-
*
|
|
24224
|
-
* export default defineConfig({
|
|
24225
|
-
* theme: {
|
|
24226
|
-
* extend: {
|
|
24227
|
-
* colors: {
|
|
24228
|
-
* primary: { main: '#7AFFD7' },
|
|
24229
|
-
* },
|
|
24230
|
-
* },
|
|
24231
|
-
* },
|
|
24232
|
-
* });
|
|
24233
|
-
* ```
|
|
24234
|
-
*/
|
|
24235
|
-
/**
|
|
24236
|
-
* Helper function to define Atomix configuration with type safety
|
|
24237
|
-
*
|
|
24238
|
-
* @param config - Atomix configuration object
|
|
24239
|
-
* @returns The configuration object
|
|
24240
|
-
*/
|
|
23312
|
+
if (base || override) return base ? override ? {
|
|
23313
|
+
className: [ base.className, override.className ].filter(Boolean).join(" "),
|
|
23314
|
+
style: {
|
|
23315
|
+
...base.style,
|
|
23316
|
+
...override.style
|
|
23317
|
+
}
|
|
23318
|
+
} : base : override;
|
|
23319
|
+
}
|
|
23320
|
+
|
|
24241
23321
|
/**
|
|
24242
|
-
*
|
|
24243
|
-
*
|
|
24244
|
-
* Similar to Tailwind's defineConfig, provides autocomplete and type checking.
|
|
23322
|
+
* Render a slot with the given props
|
|
24245
23323
|
*
|
|
24246
|
-
*
|
|
24247
|
-
*
|
|
23324
|
+
* Priority order:
|
|
23325
|
+
* 1. render function
|
|
23326
|
+
* 2. component
|
|
23327
|
+
* 3. children
|
|
23328
|
+
* 4. fallback
|
|
24248
23329
|
*
|
|
24249
23330
|
* @example
|
|
24250
|
-
*
|
|
24251
|
-
*
|
|
24252
|
-
*
|
|
24253
|
-
*
|
|
24254
|
-
|
|
24255
|
-
|
|
24256
|
-
|
|
24257
|
-
|
|
24258
|
-
|
|
24259
|
-
|
|
24260
|
-
|
|
24261
|
-
|
|
24262
|
-
|
|
23331
|
+
* renderSlot(
|
|
23332
|
+
* { render: (props) => <CustomButton {...props} /> },
|
|
23333
|
+
* { onClick: handleClick, children: 'Click me' }
|
|
23334
|
+
* )
|
|
23335
|
+
*/ function renderSlot(slot, props, fallback) {
|
|
23336
|
+
// No slot provided, use fallback
|
|
23337
|
+
if (!slot) return fallback;
|
|
23338
|
+
// Slot is a plain React node
|
|
23339
|
+
if ( React__default.default.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
|
|
23340
|
+
// Slot is an object with rendering options
|
|
23341
|
+
if ("object" == typeof slot && null !== slot) {
|
|
23342
|
+
const slotObj = slot;
|
|
23343
|
+
// Priority 1: render function
|
|
23344
|
+
if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
|
|
23345
|
+
// Priority 2: component
|
|
23346
|
+
if (slotObj.component) {
|
|
23347
|
+
const Component = slotObj.component;
|
|
23348
|
+
return jsxRuntime.jsx(Component, {
|
|
23349
|
+
...props
|
|
23350
|
+
});
|
|
23351
|
+
}
|
|
23352
|
+
// Priority 3: children
|
|
23353
|
+
if (void 0 !== slotObj.children) return slotObj.children;
|
|
23354
|
+
}
|
|
23355
|
+
// Fallback
|
|
23356
|
+
return fallback;
|
|
23357
|
+
}
|
|
23358
|
+
|
|
23359
|
+
/**
|
|
23360
|
+
* Check if a value is a slot configuration
|
|
24263
23361
|
*/
|
|
24264
23362
|
// Import and re-export as namespaces with proper typing
|
|
24265
23363
|
// Export as namespaces with explicit typing
|
|
24266
|
-
const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme =
|
|
23364
|
+
const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
|
|
23365
|
+
__proto__: null,
|
|
23366
|
+
RTLManager: RTLManager,
|
|
23367
|
+
ThemeApplicator: ThemeApplicator,
|
|
23368
|
+
ThemeComparator: ThemeComparator,
|
|
23369
|
+
ThemeContext: ThemeContext,
|
|
23370
|
+
ThemeErrorBoundary: ThemeErrorBoundary,
|
|
23371
|
+
ThemeInspector: ThemeInspector,
|
|
23372
|
+
ThemeLiveEditor: ThemeLiveEditor,
|
|
23373
|
+
ThemePreview: ThemePreview,
|
|
23374
|
+
ThemeProvider: ThemeProvider,
|
|
23375
|
+
ThemeValidator: ThemeValidator,
|
|
23376
|
+
applyCSSVariables: applyCSSVariables,
|
|
23377
|
+
applyComponentTheme: applyComponentTheme,
|
|
23378
|
+
applyTheme: applyTheme,
|
|
23379
|
+
camelToKebab: camelToKebab,
|
|
23380
|
+
clearThemes: clearThemes,
|
|
23381
|
+
createDesignTokensFromTheme: createDesignTokensFromTheme,
|
|
23382
|
+
createTheme: createTheme,
|
|
23383
|
+
createThemeObject: createThemeObject,
|
|
23384
|
+
createThemeRegistry: createThemeRegistry,
|
|
23385
|
+
createTokens: createTokens,
|
|
23386
|
+
cssVarsToStyle: cssVarsToStyle,
|
|
23387
|
+
deepMerge: deepMerge,
|
|
23388
|
+
defaultTokens: defaultTokens,
|
|
23389
|
+
designTokensToCSSVars: designTokensToCSSVars,
|
|
23390
|
+
designTokensToTheme: designTokensToTheme,
|
|
23391
|
+
extendTheme: extendTheme,
|
|
23392
|
+
extractComponentName: extractComponentName,
|
|
23393
|
+
generateCSSVariableName: generateCSSVariableName,
|
|
23394
|
+
generateCSSVariables: generateCSSVariables$1,
|
|
23395
|
+
generateCSSVariablesForSelector: generateCSSVariablesForSelector,
|
|
23396
|
+
generateClassName: generateClassName,
|
|
23397
|
+
generateComponentCSSVars: generateComponentCSSVars,
|
|
23398
|
+
getAllThemes: getAllThemes,
|
|
23399
|
+
getCSSVariable: getCSSVariable,
|
|
23400
|
+
getComponentThemeValue: getComponentThemeValue,
|
|
23401
|
+
getDesignTokensFromTheme: getDesignTokensFromTheme,
|
|
23402
|
+
getTheme: getTheme,
|
|
23403
|
+
getThemeApplicator: getThemeApplicator,
|
|
23404
|
+
getThemeCount: getThemeCount,
|
|
23405
|
+
getThemeIds: getThemeIds,
|
|
23406
|
+
hasTheme: hasTheme,
|
|
23407
|
+
injectCSS: injectCSS$1,
|
|
23408
|
+
injectTheme: injectTheme,
|
|
23409
|
+
isCSSInjected: isCSSInjected,
|
|
23410
|
+
isDesignTokens: isDesignTokens,
|
|
23411
|
+
isThemeObject: isThemeObject,
|
|
23412
|
+
isValidCSSVariableName: isValidCSSVariableName,
|
|
23413
|
+
loadThemeFromConfig: loadThemeFromConfig,
|
|
23414
|
+
loadThemeFromConfigSync: loadThemeFromConfigSync,
|
|
23415
|
+
mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
|
|
23416
|
+
mergeCSSVars: mergeCSSVars,
|
|
23417
|
+
mergeTheme: mergeTheme,
|
|
23418
|
+
normalizeThemeTokens: normalizeThemeTokens,
|
|
23419
|
+
registerTheme: registerTheme,
|
|
23420
|
+
removeCSS: removeCSS,
|
|
23421
|
+
removeCSSVariables: removeCSSVariables,
|
|
23422
|
+
removeTheme: removeTheme,
|
|
23423
|
+
saveTheme: saveTheme,
|
|
23424
|
+
themePropertyToCSSVar: themePropertyToCSSVar,
|
|
23425
|
+
themeToDesignTokens: themeToDesignTokens,
|
|
23426
|
+
unregisterTheme: unregisterTheme,
|
|
23427
|
+
useComponentTheme: useComponentTheme,
|
|
23428
|
+
useHistory: useHistory,
|
|
23429
|
+
useTheme: useTheme,
|
|
23430
|
+
useThemeTokens: useThemeTokens
|
|
23431
|
+
}), atomix = {
|
|
24267
23432
|
// Re-export all components and utilities
|
|
24268
23433
|
...components,
|
|
24269
23434
|
...layouts,
|
|
@@ -24320,13 +23485,13 @@ exports.ScatterChart = ScatterChart, exports.SectionIntro = SectionIntro, export
|
|
|
24320
23485
|
exports.SideMenu = SideMenu, exports.SideMenuItem = SideMenuItem, exports.SideMenuList = SideMenuList,
|
|
24321
23486
|
exports.Slider = Slider, exports.Spinner = Spinner, exports.Steps = Steps, exports.TAB = TAB,
|
|
24322
23487
|
exports.TABS_CSS_VARS = TABS_CSS_VARS, exports.TESTIMONIAL = TESTIMONIAL, exports.TEXTAREA = TEXTAREA,
|
|
24323
|
-
exports.THEME_COLORS = THEME_COLORS, exports.
|
|
24324
|
-
exports.
|
|
24325
|
-
exports.
|
|
24326
|
-
exports.
|
|
24327
|
-
exports.
|
|
24328
|
-
exports.
|
|
24329
|
-
exports.
|
|
23488
|
+
exports.THEME_COLORS = THEME_COLORS, exports.THEME_NAMING = THEME_NAMING, exports.TODO = TODO,
|
|
23489
|
+
exports.TOGGLE = TOGGLE, exports.TOOLTIP = TOOLTIP, exports.TOOLTIP_CSS_VARS = TOOLTIP_CSS_VARS,
|
|
23490
|
+
exports.Tabs = Tabs, exports.Testimonial = Testimonial, exports.Textarea = Textarea,
|
|
23491
|
+
exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
|
|
23492
|
+
exports.ThemeContext = ThemeContext, exports.ThemeErrorBoundary = ThemeErrorBoundary,
|
|
23493
|
+
exports.ThemeInspector = ThemeInspector, exports.ThemeLiveEditor = ThemeLiveEditor,
|
|
23494
|
+
exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeValidator = ThemeValidator,
|
|
24330
23495
|
exports.Todo = Todo, exports.Toggle = Toggle, exports.Tooltip = Tooltip, exports.TreemapChart = TreemapChart,
|
|
24331
23496
|
exports.UPLOAD = UPLOAD, exports.Upload = Upload, exports.VIDEO_PLAYER = VIDEO_PLAYER,
|
|
24332
23497
|
exports.VideoPlayer = VideoPlayer, exports.WaterfallChart = WaterfallChart, exports.applyCSSVariables = applyCSSVariables,
|
|
@@ -24341,8 +23506,34 @@ function(cssVars, baseStyle) {
|
|
|
24341
23506
|
acc)), {}),
|
|
24342
23507
|
...baseStyle
|
|
24343
23508
|
};
|
|
24344
|
-
}
|
|
24345
|
-
|
|
23509
|
+
}
|
|
23510
|
+
/**
|
|
23511
|
+
* Atomix Config Loader
|
|
23512
|
+
*
|
|
23513
|
+
* Helper functions to load atomix.config.ts from external projects.
|
|
23514
|
+
* Similar to how Tailwind loads tailwind.config.js
|
|
23515
|
+
*/
|
|
23516
|
+
/**
|
|
23517
|
+
* Load Atomix configuration from project root
|
|
23518
|
+
*
|
|
23519
|
+
* Attempts to load atomix.config.ts from the current working directory.
|
|
23520
|
+
* Falls back to default config if file doesn't exist.
|
|
23521
|
+
*
|
|
23522
|
+
* @param options - Loader options
|
|
23523
|
+
* @returns Loaded configuration or default
|
|
23524
|
+
*
|
|
23525
|
+
* @example
|
|
23526
|
+
* ```typescript
|
|
23527
|
+
* import { loadAtomixConfig } from '@shohojdhara/atomix/config';
|
|
23528
|
+
* import { createTheme } from '@shohojdhara/atomix/theme';
|
|
23529
|
+
*
|
|
23530
|
+
* const config = loadAtomixConfig();
|
|
23531
|
+
* const theme = createTheme(config.theme?.tokens || {});
|
|
23532
|
+
* ```
|
|
23533
|
+
*/ , exports.applyComponentTheme = applyComponentTheme, exports.applyPartStyles = applyPartStyles,
|
|
23534
|
+
exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemes = clearThemes,
|
|
23535
|
+
exports.composables = composables, exports.constants = constants, exports.createCSSVarStyle = createCSSVarStyle,
|
|
23536
|
+
exports.createDarkVariant =
|
|
24346
23537
|
/**
|
|
24347
23538
|
* Create a dark theme variant from a light theme
|
|
24348
23539
|
*/
|
|
@@ -24405,8 +23596,63 @@ function(defaultElement = "div") {
|
|
|
24405
23596
|
/**
|
|
24406
23597
|
* Hook to manage slot rendering
|
|
24407
23598
|
*/ , exports.createTheme = createTheme, exports.createThemeObject = createThemeObject,
|
|
24408
|
-
exports.
|
|
24409
|
-
exports.
|
|
23599
|
+
exports.createThemeRegistry = createThemeRegistry, exports.createTokens = createTokens,
|
|
23600
|
+
exports.cssVarsToStyle = cssVarsToStyle, exports.deepMerge = deepMerge, exports.default = atomix,
|
|
23601
|
+
exports.defaultTokens = defaultTokens, exports.defineConfig =
|
|
23602
|
+
/**
|
|
23603
|
+
* Atomix Configuration System
|
|
23604
|
+
*
|
|
23605
|
+
* Tailwind-like configuration for customizing the Atomix Design System.
|
|
23606
|
+
*
|
|
23607
|
+
* External developers can create `atomix.config.ts` in their project root
|
|
23608
|
+
* to customize design tokens, similar to Tailwind's tailwind.config.js
|
|
23609
|
+
*
|
|
23610
|
+
* @example
|
|
23611
|
+
* ```typescript
|
|
23612
|
+
* // atomix.config.ts (in your project)
|
|
23613
|
+
* import { defineConfig } from '@shohojdhara/atomix/config';
|
|
23614
|
+
*
|
|
23615
|
+
* export default defineConfig({
|
|
23616
|
+
* theme: {
|
|
23617
|
+
* extend: {
|
|
23618
|
+
* colors: {
|
|
23619
|
+
* primary: { main: '#7AFFD7' },
|
|
23620
|
+
* },
|
|
23621
|
+
* },
|
|
23622
|
+
* },
|
|
23623
|
+
* });
|
|
23624
|
+
* ```
|
|
23625
|
+
*/
|
|
23626
|
+
/**
|
|
23627
|
+
* Helper function to define Atomix configuration with type safety
|
|
23628
|
+
*
|
|
23629
|
+
* @param config - Atomix configuration object
|
|
23630
|
+
* @returns The configuration object
|
|
23631
|
+
*/
|
|
23632
|
+
/**
|
|
23633
|
+
* Helper function to define Atomix configuration with type safety
|
|
23634
|
+
*
|
|
23635
|
+
* Similar to Tailwind's defineConfig, provides autocomplete and type checking.
|
|
23636
|
+
*
|
|
23637
|
+
* @param config - Atomix configuration object
|
|
23638
|
+
* @returns The configuration object
|
|
23639
|
+
*
|
|
23640
|
+
* @example
|
|
23641
|
+
* ```typescript
|
|
23642
|
+
* import { defineConfig } from '@shohojdhara/atomix/config';
|
|
23643
|
+
*
|
|
23644
|
+
* export default defineConfig({
|
|
23645
|
+
* theme: {
|
|
23646
|
+
* extend: {
|
|
23647
|
+
* colors: {
|
|
23648
|
+
* primary: { main: '#7AFFD7' },
|
|
23649
|
+
* },
|
|
23650
|
+
* },
|
|
23651
|
+
* },
|
|
23652
|
+
* });
|
|
23653
|
+
* ```
|
|
23654
|
+
*/
|
|
23655
|
+
function(config) {
|
|
24410
23656
|
return config;
|
|
24411
23657
|
}, exports.designTokensToCSSVars = designTokensToCSSVars, exports.designTokensToTheme = designTokensToTheme,
|
|
24412
23658
|
exports.exportTheme =
|
|
@@ -24421,15 +23667,17 @@ function(theme) {
|
|
|
24421
23667
|
*/ , exports.extendTheme = extendTheme, exports.extractComponentName = extractComponentName,
|
|
24422
23668
|
exports.extractYouTubeId = extractYouTubeId, exports.generateCSSVariableName = generateCSSVariableName,
|
|
24423
23669
|
exports.generateCSSVariables = generateCSSVariables$1, exports.generateCSSVariablesForSelector = generateCSSVariablesForSelector,
|
|
24424
|
-
exports.
|
|
24425
|
-
exports.
|
|
23670
|
+
exports.generateClassName = generateClassName, exports.generateComponentCSSVars = generateComponentCSSVars,
|
|
23671
|
+
exports.generateFontPreloadTags = generateFontPreloadTags, exports.generateUUID = generateUUID,
|
|
23672
|
+
exports.getAllThemes = getAllThemes, exports.getCSSVariable = getCSSVariable, exports.getComponentCSSVars =
|
|
24426
23673
|
/**
|
|
24427
23674
|
* Get CSS variables for a component
|
|
24428
23675
|
*/
|
|
24429
23676
|
function(component) {
|
|
24430
23677
|
return COMPONENT_CSS_VARS[component];
|
|
24431
|
-
}, exports.
|
|
24432
|
-
exports.
|
|
23678
|
+
}, exports.getComponentThemeValue = getComponentThemeValue, exports.getDesignTokensFromTheme = getDesignTokensFromTheme,
|
|
23679
|
+
exports.getPartStyles = getPartStyles, exports.getTheme = getTheme, exports.getThemeApplicator = getThemeApplicator,
|
|
23680
|
+
exports.getThemeCount = getThemeCount, exports.getThemeIds = getThemeIds, exports.getThemeMetadata =
|
|
24433
23681
|
/**
|
|
24434
23682
|
* Get theme metadata
|
|
24435
23683
|
*/
|
|
@@ -24447,7 +23695,8 @@ function(theme) {
|
|
|
24447
23695
|
}
|
|
24448
23696
|
/**
|
|
24449
23697
|
* Check if theme supports dark mode
|
|
24450
|
-
*/ , exports.hasCustomization = hasCustomization, exports.
|
|
23698
|
+
*/ , exports.hasCustomization = hasCustomization, exports.hasTheme = hasTheme,
|
|
23699
|
+
exports.importTheme = function(json) {
|
|
24451
23700
|
try {
|
|
24452
23701
|
return JSON.parse(json);
|
|
24453
23702
|
} catch (error) {
|
|
@@ -24466,8 +23715,43 @@ exports.isDesignTokens = isDesignTokens, exports.isSlot = function(value) {
|
|
|
24466
23715
|
* Merge multiple slot configurations
|
|
24467
23716
|
* Later slots override earlier ones
|
|
24468
23717
|
*/ , exports.isThemeObject = isThemeObject, exports.isValidCSSVariableName = isValidCSSVariableName,
|
|
24469
|
-
exports.isYouTubeUrl = isYouTubeUrl, exports.loadAtomixConfig =
|
|
24470
|
-
|
|
23718
|
+
exports.isYouTubeUrl = isYouTubeUrl, exports.loadAtomixConfig = function(options = {}) {
|
|
23719
|
+
const {configPath: configPath = "atomix.config.ts", required: required = !1} = options, defaultConfig = {
|
|
23720
|
+
prefix: "atomix",
|
|
23721
|
+
theme: {
|
|
23722
|
+
extend: {}
|
|
23723
|
+
}
|
|
23724
|
+
};
|
|
23725
|
+
// Default config
|
|
23726
|
+
// In browser environments, config loading is not supported
|
|
23727
|
+
if ("undefined" != typeof window) {
|
|
23728
|
+
if (required) throw new Error("loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
23729
|
+
return defaultConfig;
|
|
23730
|
+
}
|
|
23731
|
+
// Try to load config file
|
|
23732
|
+
try {
|
|
23733
|
+
// Use dynamic import for ESM compatibility
|
|
23734
|
+
const configModule = require(configPath), config = configModule.default || configModule;
|
|
23735
|
+
// Validate it's an AtomixConfig
|
|
23736
|
+
if (config && "object" == typeof config) return config;
|
|
23737
|
+
throw new Error("Invalid config format");
|
|
23738
|
+
} catch (error) {
|
|
23739
|
+
if (required) throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
|
|
23740
|
+
// Return default config if not required
|
|
23741
|
+
return defaultConfig;
|
|
23742
|
+
}
|
|
23743
|
+
}
|
|
23744
|
+
/**
|
|
23745
|
+
* Resolve config path
|
|
23746
|
+
*
|
|
23747
|
+
* Finds atomix.config.ts in the project, checking common locations.
|
|
23748
|
+
* Returns null in browser environments where file system access is not available.
|
|
23749
|
+
*
|
|
23750
|
+
* This function is designed to work in Node.js environments only.
|
|
23751
|
+
* In browser builds, it will always return null without attempting to access Node.js modules.
|
|
23752
|
+
*
|
|
23753
|
+
* @internal This function uses Node.js modules and should not be called in browser environments.
|
|
23754
|
+
*/ , exports.loadThemeFromConfig = loadThemeFromConfig, exports.loadThemeFromConfigSync = loadThemeFromConfigSync,
|
|
24471
23755
|
exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
|
|
24472
23756
|
exports.mergeClassNames = mergeClassNames, exports.mergeComponentProps = mergeComponentProps,
|
|
24473
23757
|
exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slots) {
|
|
@@ -24476,7 +23760,8 @@ exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slot
|
|
|
24476
23760
|
...acc,
|
|
24477
23761
|
...slot
|
|
24478
23762
|
})));
|
|
24479
|
-
}, exports.mergeTheme = mergeTheme, exports.
|
|
23763
|
+
}, exports.mergeTheme = mergeTheme, exports.normalizeThemeTokens = normalizeThemeTokens,
|
|
23764
|
+
exports.preloadFonts = preloadFonts, exports.quickTheme =
|
|
24480
23765
|
/**
|
|
24481
23766
|
* Quick theme creator with sensible defaults
|
|
24482
23767
|
*/
|
|
@@ -24492,13 +23777,47 @@ function(name, primaryColor, secondaryColor) {
|
|
|
24492
23777
|
} : void 0
|
|
24493
23778
|
}
|
|
24494
23779
|
});
|
|
24495
|
-
}, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
|
|
24496
|
-
exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath =
|
|
24497
|
-
|
|
24498
|
-
|
|
23780
|
+
}, exports.registerTheme = registerTheme, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
|
|
23781
|
+
exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = function() {
|
|
23782
|
+
// Early return for browser environments - prevents any Node.js module access
|
|
23783
|
+
// This check happens before any require() calls, preventing bundlers from analyzing them
|
|
23784
|
+
if ("undefined" != typeof window || "undefined" == typeof process || !process.cwd) return null;
|
|
23785
|
+
// Only attempt to load Node.js modules in Node.js runtime
|
|
23786
|
+
// Use a lazy-loading pattern that prevents static analysis by bundlers
|
|
23787
|
+
try {
|
|
23788
|
+
// Create a function that only executes in Node.js runtime
|
|
23789
|
+
// Use string-based module names to prevent static analysis by bundlers
|
|
23790
|
+
const modules = (() => {
|
|
23791
|
+
// These requires are only executed at runtime in Node.js environments
|
|
23792
|
+
// They are marked as external in Rollup config and should not be bundled
|
|
23793
|
+
// Using string concatenation and computed property access to prevent static analysis
|
|
23794
|
+
if ("undefined" == typeof require) return null;
|
|
23795
|
+
// Use a try-catch wrapper to safely access require
|
|
23796
|
+
try {
|
|
23797
|
+
// Build module names dynamically to prevent static analysis
|
|
23798
|
+
const moduleNames = [ "fs", "path" ];
|
|
23799
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
23800
|
+
return {
|
|
23801
|
+
fs: require(moduleNames[0]),
|
|
23802
|
+
path: require(moduleNames[1])
|
|
23803
|
+
};
|
|
23804
|
+
} catch {
|
|
23805
|
+
return null;
|
|
23806
|
+
}
|
|
23807
|
+
})();
|
|
23808
|
+
if (!modules) return null;
|
|
23809
|
+
const {fs: fs, path: path} = modules, cwd = process.cwd(), possiblePaths = [ path.join(cwd, "atomix.config.ts"), path.join(cwd, "atomix.config.js"), path.join(cwd, "atomix.config.mjs") ];
|
|
23810
|
+
for (const configPath of possiblePaths) if (fs.existsSync(configPath)) return configPath;
|
|
23811
|
+
} catch (error) {
|
|
23812
|
+
// Silently fail in browser environments or when modules are unavailable
|
|
23813
|
+
return null;
|
|
23814
|
+
}
|
|
23815
|
+
return null;
|
|
23816
|
+
}, exports.saveTheme = saveTheme, exports.sliderConstants = sliderConstants, exports.supportsDarkMode = function(theme) {
|
|
24499
23817
|
var _context;
|
|
24500
23818
|
return "dark" === theme.palette?.mode || !0 === theme.supportsDarkMode || Boolean((null == (_context = theme.a11y?.modes) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("dark"));
|
|
24501
|
-
}, exports.theme = theme, exports.
|
|
23819
|
+
}, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
|
|
23820
|
+
exports.themeToCSS =
|
|
24502
23821
|
/**
|
|
24503
23822
|
* Generate CSS string from theme
|
|
24504
23823
|
*/
|
|
@@ -24507,11 +23826,12 @@ function(theme, selector = ":root") {
|
|
|
24507
23826
|
selector: selector,
|
|
24508
23827
|
prefix: "atomix"
|
|
24509
23828
|
});
|
|
24510
|
-
}, exports.themeToDesignTokens = themeToDesignTokens, exports.types = types, exports.
|
|
24511
|
-
exports.
|
|
24512
|
-
exports.
|
|
24513
|
-
exports.
|
|
24514
|
-
exports.
|
|
23829
|
+
}, exports.themeToDesignTokens = themeToDesignTokens, exports.types = types, exports.unregisterTheme = unregisterTheme,
|
|
23830
|
+
exports.useAccordion = useAccordion, exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge,
|
|
23831
|
+
exports.useBarChart = useBarChart, exports.useBlock = useBlock, exports.useBreadcrumb = useBreadcrumb,
|
|
23832
|
+
exports.useButton = useButton, exports.useCard = useCard, exports.useChartData = useChartData,
|
|
23833
|
+
exports.useChartInteraction = useChartInteraction, exports.useChartScale = useChartScale,
|
|
23834
|
+
exports.useCheckbox = useCheckbox, exports.useComponentCustomization =
|
|
24515
23835
|
/**
|
|
24516
23836
|
* Hook to merge theme overrides with component props
|
|
24517
23837
|
*
|
|
@@ -24559,10 +23879,10 @@ function(component, props) {
|
|
|
24559
23879
|
}
|
|
24560
23880
|
/**
|
|
24561
23881
|
* Hook to merge default props with provided props
|
|
24562
|
-
*/ , exports.
|
|
24563
|
-
exports.
|
|
24564
|
-
exports.
|
|
24565
|
-
exports.useLineChart = useLineChart, exports.useMergedProps = function(defaultProps, props) {
|
|
23882
|
+
*/ , exports.useComponentTheme = useComponentTheme, exports.useDataTable = useDataTable,
|
|
23883
|
+
exports.useEdgePanel = useEdgePanel, exports.useForm = useForm, exports.useFormGroup = useFormGroup,
|
|
23884
|
+
exports.useGlassContainer = useGlassContainer, exports.useHero = useHero, exports.useHistory = useHistory,
|
|
23885
|
+
exports.useInput = useInput, exports.useLineChart = useLineChart, exports.useMergedProps = function(defaultProps, props) {
|
|
24566
23886
|
return React.useMemo((() => ({
|
|
24567
23887
|
...defaultProps,
|
|
24568
23888
|
...props
|
|
@@ -24574,7 +23894,8 @@ exports.useSelect = useSelect, exports.useSideMenu = useSideMenu, exports.useSid
|
|
|
24574
23894
|
exports.useSlider = useSlider, exports.useSlot = function(slot, props, fallback) {
|
|
24575
23895
|
return React__default.default.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
|
|
24576
23896
|
}, exports.useSpinner = useSpinner, exports.useTextarea = useTextarea, exports.useTheme = useTheme,
|
|
24577
|
-
exports.
|
|
23897
|
+
exports.useThemeTokens = useThemeTokens, exports.useTodo = useTodo, exports.utils = utils,
|
|
23898
|
+
exports.validateTheme = function(theme) {
|
|
24578
23899
|
const errors = [];
|
|
24579
23900
|
return theme.name || errors.push("Theme must have a name"), theme.palette || errors.push("Theme must have a palette"),
|
|
24580
23901
|
theme.palette && !theme.palette.primary && errors.push("Theme palette must have a primary color"),
|