@shohojdhara/atomix 0.5.2 → 0.5.5
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/atomix.config.ts +33 -33
- package/dist/atomix.css +3213 -159
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +5 -5
- package/dist/atomix.min.css.map +1 -1
- package/dist/config.d.ts +187 -112
- package/dist/config.js +2 -47
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1958 -900
- package/dist/index.esm.js +2279 -382
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2332 -413
- 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 +1390 -276
- package/dist/theme.js +2125 -621
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/scripts/cli/internal/config-loader.js +30 -20
- package/src/lib/config/index.ts +38 -362
- package/src/lib/config/loader.ts +422 -0
- package/src/lib/config/public-api.ts +43 -0
- package/src/lib/config/types.ts +389 -0
- package/src/lib/config/validator.ts +305 -0
- package/src/lib/theme/adapters/index.ts +1 -1
- package/src/lib/theme/adapters/themeAdapter.ts +358 -229
- package/src/lib/theme/components/ThemeToggle.tsx +276 -0
- package/src/lib/theme/config/configLoader.ts +351 -0
- package/src/lib/theme/config/loader.ts +221 -0
- package/src/lib/theme/core/createTheme.ts +126 -50
- package/src/lib/theme/core/createThemeObject.ts +7 -4
- package/src/lib/theme/hooks/useThemeSwitcher.ts +164 -0
- package/src/lib/theme/index.ts +322 -38
- package/src/lib/theme/runtime/ThemeProvider.tsx +44 -10
- package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +44 -393
- package/src/lib/theme/runtime/useTheme.ts +1 -0
- package/src/lib/theme/tokens/tokens.ts +101 -1
- package/src/lib/theme/types.ts +91 -0
- package/src/lib/theme/utils/performanceMonitor.ts +315 -0
- package/src/lib/theme/utils/responsive.ts +280 -0
- package/src/lib/theme/utils/themeUtils.ts +531 -117
- package/src/styles/01-settings/_settings.background.scss +34 -5
- package/src/styles/02-tools/_tools.background.scss +330 -52
- package/src/styles/05-objects/_objects.masonry-grid.scss +3 -3
- package/src/styles/06-components/_components.accordion.scss +2 -2
- package/src/styles/06-components/_components.badge.scss +1 -1
- package/src/styles/06-components/_components.button.scss +2 -2
- package/src/styles/06-components/_components.callout.scss +2 -2
- package/src/styles/06-components/_components.card.scss +1 -1
- package/src/styles/06-components/_components.dropdown.scss +1 -1
- package/src/styles/06-components/_components.dynamic-background.scss +69 -0
- package/src/styles/06-components/_components.edge-panel.scss +2 -2
- package/src/styles/06-components/_components.input.scss +3 -3
- package/src/styles/06-components/_components.messages.scss +6 -6
- package/src/styles/06-components/_components.modal.scss +1 -1
- package/src/styles/06-components/_components.navbar.scss +1 -1
- package/src/styles/06-components/_components.popover.scss +1 -1
- package/src/styles/06-components/_components.toggle.scss +1 -1
- package/src/styles/06-components/_components.tooltip.scss +3 -3
- package/src/styles/06-components/_index.scss +1 -0
package/dist/index.js
CHANGED
|
@@ -3587,7 +3587,7 @@ function useResponsiveGlass({baseParams: baseParams, breakpoints: breakpoints =
|
|
|
3587
3587
|
* @param config Monitor configuration
|
|
3588
3588
|
* @returns Performance metrics and controls
|
|
3589
3589
|
*/
|
|
3590
|
-
function usePerformanceMonitor(config = {}) {
|
|
3590
|
+
function usePerformanceMonitor$1(config = {}) {
|
|
3591
3591
|
const {enabled: enabled = !0, targetFps: targetFps = 60, minFps: minFps = 45, scaleUpThreshold: scaleUpThreshold = 58, lowFpsFrames: lowFpsFrames = 3, highFpsFrames: highFpsFrames = 10, debug: debug = !1, showOverlay: showOverlay = !1} = config, [metrics, setMetrics] = React.useState({
|
|
3592
3592
|
fps: 0,
|
|
3593
3593
|
frameTime: 0,
|
|
@@ -4143,7 +4143,7 @@ function getDevicePreset(presetName) {
|
|
|
4143
4143
|
debug: !1
|
|
4144
4144
|
});
|
|
4145
4145
|
// Performance monitoring - tracks FPS, frame time, memory usage
|
|
4146
|
-
const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor({
|
|
4146
|
+
const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor$1({
|
|
4147
4147
|
enabled: debugPerformance,
|
|
4148
4148
|
// Enable when debugPerformance is true
|
|
4149
4149
|
debug: !1,
|
|
@@ -5144,7 +5144,7 @@ const BreadcrumbItem = React.forwardRef((({children: children, href: href, acti
|
|
|
5144
5144
|
|
|
5145
5145
|
BreadcrumbItem.displayName = "BreadcrumbItem";
|
|
5146
5146
|
|
|
5147
|
-
const
|
|
5147
|
+
const BreadcrumbComponent = React.memo((function({items: items, divider: divider, className: className = "", "aria-label": ariaLabel = "Breadcrumb", linkComponent: linkComponent, style: style, children: children}) {
|
|
5148
5148
|
const breadcrumbClasses = [ BREADCRUMB.CLASSES.BASE, className ].filter(Boolean).join(" ");
|
|
5149
5149
|
let content;
|
|
5150
5150
|
if (items && items.length > 0)
|
|
@@ -5184,7 +5184,7 @@ const Breadcrumb = React.memo((function({items: items, divider: divider, classN
|
|
|
5184
5184
|
children: content
|
|
5185
5185
|
})
|
|
5186
5186
|
});
|
|
5187
|
-
}));
|
|
5187
|
+
})), Breadcrumb = BreadcrumbComponent;
|
|
5188
5188
|
|
|
5189
5189
|
/**
|
|
5190
5190
|
* Spinner state and functionality
|
|
@@ -13506,21 +13506,21 @@ const DEFAULT_ATOMIX_FONTS = [ {
|
|
|
13506
13506
|
const [interaction, setInteraction] = React.useState({
|
|
13507
13507
|
hoveredIndex: null,
|
|
13508
13508
|
selectedIndex: null
|
|
13509
|
-
})
|
|
13509
|
+
}), handlePointHover = React.useCallback((index => {
|
|
13510
|
+
setInteraction((prev => ({
|
|
13511
|
+
...prev,
|
|
13512
|
+
hoveredIndex: index
|
|
13513
|
+
})));
|
|
13514
|
+
}), []), handlePointClick = React.useCallback((index => {
|
|
13515
|
+
setInteraction((prev => ({
|
|
13516
|
+
...prev,
|
|
13517
|
+
selectedIndex: prev.selectedIndex === index ? null : index
|
|
13518
|
+
})));
|
|
13519
|
+
}), []);
|
|
13510
13520
|
return {
|
|
13511
13521
|
interaction: interaction,
|
|
13512
|
-
handlePointHover:
|
|
13513
|
-
|
|
13514
|
-
...prev,
|
|
13515
|
-
hoveredIndex: index
|
|
13516
|
-
})));
|
|
13517
|
-
}), []),
|
|
13518
|
-
handlePointClick: React.useCallback((index => {
|
|
13519
|
-
setInteraction((prev => ({
|
|
13520
|
-
...prev,
|
|
13521
|
-
selectedIndex: prev.selectedIndex === index ? null : index
|
|
13522
|
-
})));
|
|
13523
|
-
}), []),
|
|
13522
|
+
handlePointHover: handlePointHover,
|
|
13523
|
+
handlePointClick: handlePointClick,
|
|
13524
13524
|
clearInteraction: React.useCallback((() => {
|
|
13525
13525
|
setInteraction({
|
|
13526
13526
|
hoveredIndex: null,
|
|
@@ -13563,7 +13563,7 @@ var composablesImport = Object.freeze({
|
|
|
13563
13563
|
useNavDropdown: useNavDropdown,
|
|
13564
13564
|
useNavItem: useNavItem,
|
|
13565
13565
|
useNavbar: useNavbar,
|
|
13566
|
-
usePerformanceMonitor: usePerformanceMonitor,
|
|
13566
|
+
usePerformanceMonitor: usePerformanceMonitor$1,
|
|
13567
13567
|
usePieChart: usePieChart,
|
|
13568
13568
|
useRadio: useRadio,
|
|
13569
13569
|
useResponsiveGlass: useResponsiveGlass,
|
|
@@ -20901,7 +20901,51 @@ const defaultTokens = {
|
|
|
20901
20901
|
"breakpoint-md": "768px",
|
|
20902
20902
|
"breakpoint-lg": "992px",
|
|
20903
20903
|
"breakpoint-xl": "1200px",
|
|
20904
|
-
"breakpoint-xxl": "1440px"
|
|
20904
|
+
"breakpoint-xxl": "1440px",
|
|
20905
|
+
// Advanced Features - Interactive Effects (Phase 2)
|
|
20906
|
+
"interactive-vortex-enabled": "false",
|
|
20907
|
+
"interactive-vortex-strength": "0.5",
|
|
20908
|
+
"interactive-vortex-radius": "100",
|
|
20909
|
+
"interactive-vortex-decay": "0.8",
|
|
20910
|
+
"interactive-chromatic-enabled": "false",
|
|
20911
|
+
"interactive-chromatic-mode": "lateral",
|
|
20912
|
+
"interactive-chromatic-red-shift": "0.02",
|
|
20913
|
+
"interactive-chromatic-green-shift": "0",
|
|
20914
|
+
"interactive-chromatic-blue-shift": "-0.02",
|
|
20915
|
+
"interactive-chromatic-edge-only": "false",
|
|
20916
|
+
"interactive-chromatic-edge-threshold": "0.5",
|
|
20917
|
+
"interactive-mouse-sensitivity": "1.0",
|
|
20918
|
+
"interactive-mouse-trail-effect": "false",
|
|
20919
|
+
"interactive-animation-speed-base": "1.0",
|
|
20920
|
+
"interactive-animation-speed-multiplier": "1.0",
|
|
20921
|
+
// Advanced Features - Optimization (Phase 3)
|
|
20922
|
+
"optimization-breakpoint-mobile": "0px",
|
|
20923
|
+
"optimization-breakpoint-tablet": "768px",
|
|
20924
|
+
"optimization-breakpoint-desktop": "1024px",
|
|
20925
|
+
"optimization-breakpoint-wide": "1440px",
|
|
20926
|
+
"optimization-device-scaling-mobile": "0.5",
|
|
20927
|
+
"optimization-device-scaling-tablet": "0.75",
|
|
20928
|
+
"optimization-device-scaling-desktop": "1.0",
|
|
20929
|
+
"optimization-performance-fps-target": "60",
|
|
20930
|
+
"optimization-auto-scaling-enabled": "false",
|
|
20931
|
+
"optimization-auto-scaling-low-end": "0.5",
|
|
20932
|
+
"optimization-auto-scaling-mid-range": "0.75",
|
|
20933
|
+
"optimization-auto-scaling-high-end": "1.0",
|
|
20934
|
+
// Advanced Features - Visual Polish (Phase 4)
|
|
20935
|
+
"visual-polish-border-iridescent-glow": "false",
|
|
20936
|
+
"visual-polish-border-shimmer-effect": "false",
|
|
20937
|
+
"visual-polish-border-beveled-edges": "false",
|
|
20938
|
+
"visual-polish-border-pulsing-glow": "false",
|
|
20939
|
+
"visual-polish-content-aware-blur-enabled": "false",
|
|
20940
|
+
"visual-polish-content-aware-depth-detection": "false",
|
|
20941
|
+
"visual-polish-content-aware-edge-preservation": "false",
|
|
20942
|
+
"visual-polish-content-aware-variable-radius": "false",
|
|
20943
|
+
"visual-polish-holographic-enabled": "false",
|
|
20944
|
+
"visual-polish-holographic-rainbow-diffraction": "false",
|
|
20945
|
+
"visual-polish-holographic-scanline-animation": "false",
|
|
20946
|
+
"visual-polish-holographic-grid-overlay": "false",
|
|
20947
|
+
"visual-polish-holographic-data-stream": "false",
|
|
20948
|
+
"visual-polish-holographic-pulse-rings": "false"
|
|
20905
20949
|
};
|
|
20906
20950
|
|
|
20907
20951
|
/**
|
|
@@ -20981,158 +21025,485 @@ const defaultTokens = {
|
|
|
20981
21025
|
}
|
|
20982
21026
|
|
|
20983
21027
|
/**
|
|
20984
|
-
* Theme
|
|
21028
|
+
* Theme Adapter
|
|
20985
21029
|
*
|
|
20986
|
-
*
|
|
20987
|
-
* Provides custom error classes and logging utilities.
|
|
21030
|
+
* Converts between Theme objects and DesignTokens
|
|
20988
21031
|
*/
|
|
20989
21032
|
/**
|
|
20990
|
-
* Theme
|
|
20991
|
-
*/
|
|
20992
|
-
|
|
20993
|
-
|
|
20994
|
-
|
|
20995
|
-
|
|
20996
|
-
|
|
20997
|
-
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21001
|
-
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
|
|
21013
|
-
|
|
21014
|
-
|
|
21015
|
-
|
|
21016
|
-
|
|
21017
|
-
|
|
21018
|
-
|
|
21019
|
-
|
|
21020
|
-
|
|
21021
|
-
|
|
21022
|
-
|
|
21023
|
-
|
|
21024
|
-
|
|
21033
|
+
* Convert a Theme object to DesignTokens
|
|
21034
|
+
*/ function themeToDesignTokens(theme) {
|
|
21035
|
+
const tokens = {};
|
|
21036
|
+
// Convert colors
|
|
21037
|
+
if (theme.palette) {
|
|
21038
|
+
// Primary color
|
|
21039
|
+
if (theme.palette.primary) {
|
|
21040
|
+
const primaryMain = theme.palette.primary.main;
|
|
21041
|
+
tokens.primary = primaryMain;
|
|
21042
|
+
const rgb = hexToRgb$2(primaryMain);
|
|
21043
|
+
rgb && (tokens["primary-rgb"] = rgb);
|
|
21044
|
+
}
|
|
21045
|
+
// Secondary color
|
|
21046
|
+
if (theme.palette.secondary) {
|
|
21047
|
+
const secondaryMain = theme.palette.secondary.main;
|
|
21048
|
+
tokens.secondary = secondaryMain;
|
|
21049
|
+
const rgb = hexToRgb$2(secondaryMain);
|
|
21050
|
+
rgb && (tokens["secondary-rgb"] = rgb);
|
|
21051
|
+
}
|
|
21052
|
+
// Other colors
|
|
21053
|
+
const colorKeys = [ "error", "warning", "info", "success" ];
|
|
21054
|
+
for (const key of colorKeys) if (theme.palette[key]) {
|
|
21055
|
+
const colorMain = theme.palette[key].main;
|
|
21056
|
+
tokens[key] = colorMain;
|
|
21057
|
+
const rgb = hexToRgb$2(colorMain);
|
|
21058
|
+
rgb && (tokens[`${key}-rgb`] = rgb);
|
|
21059
|
+
}
|
|
21060
|
+
// Background colors
|
|
21061
|
+
theme.palette.background && (tokens["body-bg"] = theme.palette.background.default),
|
|
21062
|
+
// Text colors
|
|
21063
|
+
theme.palette.text && (tokens["body-color"] = theme.palette.text.primary);
|
|
21064
|
+
}
|
|
21065
|
+
// Convert typography
|
|
21066
|
+
// Convert border radius
|
|
21067
|
+
if (theme.typography && (tokens["body-font-family"] = theme.typography.fontFamily,
|
|
21068
|
+
tokens["body-font-size"] = `${theme.typography.fontSize}px`, tokens["font-weight-normal"] = `${theme.typography.fontWeightRegular}`,
|
|
21069
|
+
tokens["font-weight-bold"] = `${theme.typography.fontWeightBold}`),
|
|
21070
|
+
// Convert spacing
|
|
21071
|
+
"function" == typeof theme.spacing && (
|
|
21072
|
+
// If spacing is a function, call it with some values to get results
|
|
21073
|
+
tokens["spacing-1"] = theme.spacing(1), tokens["spacing-2"] = theme.spacing(2),
|
|
21074
|
+
tokens["spacing-4"] = theme.spacing(4)),
|
|
21075
|
+
// Convert breakpoints
|
|
21076
|
+
theme.breakpoints?.values && (tokens["breakpoint-xs"] = `${theme.breakpoints.values.xs}px`,
|
|
21077
|
+
tokens["breakpoint-sm"] = `${theme.breakpoints.values.sm}px`, tokens["breakpoint-md"] = `${theme.breakpoints.values.md}px`,
|
|
21078
|
+
tokens["breakpoint-lg"] = `${theme.breakpoints.values.lg}px`, tokens["breakpoint-xl"] = `${theme.breakpoints.values.xl}px`),
|
|
21079
|
+
// Convert shadows
|
|
21080
|
+
theme.shadows && (tokens["box-shadow"] = theme.shadows[2], // Use a moderate shadow
|
|
21081
|
+
tokens["box-shadow-sm"] = theme.shadows[1], tokens["box-shadow-lg"] = theme.shadows[3]),
|
|
21082
|
+
// Convert transitions
|
|
21083
|
+
theme.transitions && (tokens["transition-duration-base"] = `${theme.transitions.duration.standard}ms`),
|
|
21084
|
+
// Convert z-index
|
|
21085
|
+
theme.zIndex && (tokens["z-modal"] = `${theme.zIndex.modal}`, tokens["z-popover"] = `${theme.zIndex.popover}`,
|
|
21086
|
+
tokens["z-tooltip"] = `${theme.zIndex.tooltip}`), theme.borderRadius) {
|
|
21087
|
+
const baseRadius = theme.borderRadius.base;
|
|
21088
|
+
tokens["border-radius"] = "number" == typeof baseRadius ? `${baseRadius}px` : baseRadius;
|
|
21089
|
+
}
|
|
21090
|
+
// Add advanced feature tokens if available in theme
|
|
21091
|
+
if (theme.custom) {
|
|
21092
|
+
// Interactive Effects (Phase 2)
|
|
21093
|
+
if (theme.custom.interactiveEffects) {
|
|
21094
|
+
const ie = theme.custom.interactiveEffects;
|
|
21095
|
+
// Vortex effects
|
|
21096
|
+
ie.vortex && (tokens["interactive-vortex-enabled"] = String(ie.vortex.enabled ?? !1),
|
|
21097
|
+
tokens["interactive-vortex-strength"] = String(ie.vortex.strength ?? .5), tokens["interactive-vortex-radius"] = String(ie.vortex.radius ?? 100),
|
|
21098
|
+
tokens["interactive-vortex-decay"] = String(ie.vortex.decay ?? .8)),
|
|
21099
|
+
// Chromatic aberration
|
|
21100
|
+
ie.chromaticAberration && (tokens["interactive-chromatic-enabled"] = String(ie.chromaticAberration.enabled ?? !1),
|
|
21101
|
+
tokens["interactive-chromatic-mode"] = ie.chromaticAberration.mode ?? "lateral",
|
|
21102
|
+
tokens["interactive-chromatic-red-shift"] = String(ie.chromaticAberration.redShift ?? .02),
|
|
21103
|
+
tokens["interactive-chromatic-green-shift"] = String(ie.chromaticAberration.greenShift ?? 0),
|
|
21104
|
+
tokens["interactive-chromatic-blue-shift"] = String(ie.chromaticAberration.blueShift ?? -.02),
|
|
21105
|
+
tokens["interactive-chromatic-edge-only"] = String(ie.chromaticAberration.edgeOnly ?? !1),
|
|
21106
|
+
tokens["interactive-chromatic-edge-threshold"] = String(ie.chromaticAberration.edgeThreshold ?? .5)),
|
|
21107
|
+
// Mouse interaction
|
|
21108
|
+
ie.mouseInteraction && (tokens["interactive-mouse-sensitivity"] = String(ie.mouseInteraction.sensitivity ?? 1),
|
|
21109
|
+
tokens["interactive-mouse-trail-effect"] = String(ie.mouseInteraction.trailEffect ?? !1)),
|
|
21110
|
+
// Animation speed
|
|
21111
|
+
ie.animationSpeed && (tokens["interactive-animation-speed-base"] = String(ie.animationSpeed.base ?? 1),
|
|
21112
|
+
tokens["interactive-animation-speed-multiplier"] = String(ie.animationSpeed.timeMultiplier ?? 1));
|
|
21113
|
+
}
|
|
21114
|
+
// Optimization (Phase 3)
|
|
21115
|
+
if (theme.custom.optimization) {
|
|
21116
|
+
const opt = theme.custom.optimization;
|
|
21117
|
+
// Responsive breakpoints
|
|
21118
|
+
opt.responsive && (opt.responsive.breakpoints && (tokens["optimization-breakpoint-mobile"] = opt.responsive.breakpoints.mobile ?? "0px",
|
|
21119
|
+
tokens["optimization-breakpoint-tablet"] = opt.responsive.breakpoints.tablet ?? "768px",
|
|
21120
|
+
tokens["optimization-breakpoint-desktop"] = opt.responsive.breakpoints.desktop ?? "1024px",
|
|
21121
|
+
tokens["optimization-breakpoint-wide"] = opt.responsive.breakpoints.wide ?? "1440px"),
|
|
21122
|
+
opt.responsive.deviceScaling && (tokens["optimization-device-scaling-mobile"] = String(opt.responsive.deviceScaling.mobile ?? .5),
|
|
21123
|
+
tokens["optimization-device-scaling-tablet"] = String(opt.responsive.deviceScaling.tablet ?? .75),
|
|
21124
|
+
tokens["optimization-device-scaling-desktop"] = String(opt.responsive.deviceScaling.desktop ?? 1))),
|
|
21125
|
+
// Performance settings
|
|
21126
|
+
opt.performance && (tokens["optimization-performance-fps-target"] = String(opt.performance.fpsTarget ?? 60),
|
|
21127
|
+
tokens["optimization-auto-scaling-enabled"] = String(opt.performance.autoScaling ?? !1)),
|
|
21128
|
+
// Auto-scaling settings
|
|
21129
|
+
opt.autoScaling && (tokens["optimization-auto-scaling-enabled"] = String(opt.autoScaling.enabled ?? !1),
|
|
21130
|
+
tokens["optimization-auto-scaling-low-end"] = String(opt.autoScaling.qualityThresholds?.lowEnd ?? .5),
|
|
21131
|
+
tokens["optimization-auto-scaling-mid-range"] = String(opt.autoScaling.qualityThresholds?.midRange ?? .75),
|
|
21132
|
+
tokens["optimization-auto-scaling-high-end"] = String(opt.autoScaling.qualityThresholds?.highEnd ?? 1));
|
|
21133
|
+
}
|
|
21134
|
+
// Visual Polish (Phase 4)
|
|
21135
|
+
if (theme.custom.visualPolish) {
|
|
21136
|
+
const vp = theme.custom.visualPolish;
|
|
21137
|
+
vp.borders && (tokens["visual-polish-border-iridescent-glow"] = String(vp.borders.iridescentGlow ?? !1),
|
|
21138
|
+
tokens["visual-polish-border-shimmer-effect"] = String(vp.borders.shimmerEffect ?? !1),
|
|
21139
|
+
tokens["visual-polish-border-beveled-edges"] = String(vp.borders.beveledEdges ?? !1),
|
|
21140
|
+
tokens["visual-polish-border-pulsing-glow"] = String(vp.borders.pulsingGlow ?? !1)),
|
|
21141
|
+
vp.contentAwareBlur && (tokens["visual-polish-content-aware-blur-enabled"] = String(vp.contentAwareBlur.enabled ?? !1),
|
|
21142
|
+
tokens["visual-polish-content-aware-depth-detection"] = String(vp.contentAwareBlur.depthDetection ?? !1),
|
|
21143
|
+
tokens["visual-polish-content-aware-edge-preservation"] = String(vp.contentAwareBlur.edgePreservation ?? !1),
|
|
21144
|
+
tokens["visual-polish-content-aware-variable-radius"] = String(vp.contentAwareBlur.variableRadius ?? !1)),
|
|
21145
|
+
vp.holographicEffects && (tokens["visual-polish-holographic-enabled"] = String(vp.holographicEffects.enabled ?? !1),
|
|
21146
|
+
tokens["visual-polish-holographic-rainbow-diffraction"] = String(vp.holographicEffects.rainbowDiffraction ?? !1),
|
|
21147
|
+
tokens["visual-polish-holographic-scanline-animation"] = String(vp.holographicEffects.scanlineAnimation ?? !1),
|
|
21148
|
+
tokens["visual-polish-holographic-grid-overlay"] = String(vp.holographicEffects.gridOverlay ?? !1),
|
|
21149
|
+
tokens["visual-polish-holographic-data-stream"] = String(vp.holographicEffects.dataStream ?? !1),
|
|
21150
|
+
tokens["visual-polish-holographic-pulse-rings"] = String(vp.holographicEffects.pulseRings ?? !1));
|
|
21151
|
+
}
|
|
21152
|
+
}
|
|
21153
|
+
// Create full tokens object with defaults
|
|
21154
|
+
return createTokens(tokens);
|
|
21155
|
+
}
|
|
21025
21156
|
|
|
21026
21157
|
/**
|
|
21027
|
-
*
|
|
21028
|
-
|
|
21029
|
-
|
|
21030
|
-
|
|
21031
|
-
|
|
21032
|
-
|
|
21033
|
-
|
|
21034
|
-
|
|
21035
|
-
|
|
21036
|
-
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
|
|
21042
|
-
|
|
21043
|
-
|
|
21044
|
-
|
|
21045
|
-
|
|
21046
|
-
|
|
21158
|
+
* Converts an AtomixConfig to DesignTokens
|
|
21159
|
+
*
|
|
21160
|
+
* This function maps the configuration from the user-facing format
|
|
21161
|
+
* to the internal DesignTokens format used by the theme system.
|
|
21162
|
+
*
|
|
21163
|
+
* @param config - The configuration object to convert
|
|
21164
|
+
* @returns DesignTokens object ready for theme generation
|
|
21165
|
+
*
|
|
21166
|
+
* @example
|
|
21167
|
+
* ```typescript
|
|
21168
|
+
* import { configToTokens } from '@shohojdhara/atomix/theme';
|
|
21169
|
+
*
|
|
21170
|
+
* const config = {
|
|
21171
|
+
* prefix: 'myapp',
|
|
21172
|
+
* theme: { extend: { colors: { primary: { main: '#7AFFD7' } } } }
|
|
21173
|
+
* };
|
|
21174
|
+
* const tokens = configToTokens(config);
|
|
21175
|
+
* ```
|
|
21176
|
+
*/ function configToTokens(config) {
|
|
21177
|
+
const prefix = config.prefix || "atomix", theme = config.theme || {};
|
|
21178
|
+
// Start with default tokens
|
|
21179
|
+
let tokens = {
|
|
21180
|
+
...defaultTokens
|
|
21181
|
+
};
|
|
21182
|
+
// Apply theme extensions
|
|
21183
|
+
// Apply advanced features if available in config
|
|
21184
|
+
if (theme.extend &&
|
|
21185
|
+
// Apply extensions to tokens
|
|
21186
|
+
Object.entries(theme.extend).forEach((([category, values]) => {
|
|
21187
|
+
"object" == typeof values && null !== values && Object.entries(values).forEach((([key, value]) => {
|
|
21188
|
+
// Map theme categories to token names
|
|
21189
|
+
const tokenName = `${category}-${key}`;
|
|
21190
|
+
"string" == typeof value || "number" == typeof value ? tokens[tokenName] = String(value) : "object" == typeof value && null !== value &&
|
|
21191
|
+
// Handle nested objects like color scales
|
|
21192
|
+
Object.entries(value).forEach((([nestedKey, nestedValue]) => {
|
|
21193
|
+
"string" != typeof nestedValue && "number" != typeof nestedValue || (tokens[`${tokenName}-${nestedKey}`] = String(nestedValue));
|
|
21194
|
+
}));
|
|
21195
|
+
}));
|
|
21196
|
+
})),
|
|
21197
|
+
// Apply theme tokens if provided (completely replacing defaults)
|
|
21198
|
+
theme.tokens && (tokens = {
|
|
21199
|
+
...tokens,
|
|
21200
|
+
...theme.tokens
|
|
21201
|
+
}), config) {
|
|
21202
|
+
// Interactive Effects (Phase 2)
|
|
21203
|
+
if (config.interactiveEffects) {
|
|
21204
|
+
const ie = config.interactiveEffects;
|
|
21205
|
+
// Vortex effects
|
|
21206
|
+
ie.vortex && (tokens["interactive-vortex-enabled"] = String(ie.vortex.enabled ?? !1),
|
|
21207
|
+
tokens["interactive-vortex-strength"] = String(ie.vortex.strength ?? .5), tokens["interactive-vortex-radius"] = String(ie.vortex.radius ?? 100),
|
|
21208
|
+
tokens["interactive-vortex-decay"] = String(ie.vortex.decay ?? .8), tokens["interactive-vortex-curl-noise"] = String(ie.vortex.curlNoise ?? !1),
|
|
21209
|
+
tokens["interactive-vortex-velocity-tracking"] = String(ie.vortex.velocityTracking ?? !1)),
|
|
21210
|
+
// Chromatic aberration
|
|
21211
|
+
ie.chromaticAberration && (tokens["interactive-chromatic-enabled"] = String(ie.chromaticAberration.enabled ?? !1),
|
|
21212
|
+
tokens["interactive-chromatic-mode"] = ie.chromaticAberration.mode ?? "lateral",
|
|
21213
|
+
tokens["interactive-chromatic-red-shift"] = String(ie.chromaticAberration.redShift ?? .02),
|
|
21214
|
+
tokens["interactive-chromatic-green-shift"] = String(ie.chromaticAberration.greenShift ?? 0),
|
|
21215
|
+
tokens["interactive-chromatic-blue-shift"] = String(ie.chromaticAberration.blueShift ?? -.02),
|
|
21216
|
+
tokens["interactive-chromatic-edge-only"] = String(ie.chromaticAberration.edgeOnly ?? !1),
|
|
21217
|
+
tokens["interactive-chromatic-edge-threshold"] = String(ie.chromaticAberration.edgeThreshold ?? .5)),
|
|
21218
|
+
// Mouse interaction
|
|
21219
|
+
ie.mouseInteraction && (tokens["interactive-mouse-sensitivity"] = String(ie.mouseInteraction.sensitivity ?? 1),
|
|
21220
|
+
tokens["interactive-mouse-trail-effect"] = String(ie.mouseInteraction.trailEffect ?? !1),
|
|
21221
|
+
tokens["interactive-mouse-pressure-sensitivity"] = String(ie.mouseInteraction.pressureSensitivity ?? !1)),
|
|
21222
|
+
// Animation speed
|
|
21223
|
+
ie.animationSpeed && (tokens["interactive-animation-speed-base"] = String(ie.animationSpeed.base ?? 1),
|
|
21224
|
+
tokens["interactive-animation-speed-multiplier"] = String(ie.animationSpeed.timeMultiplier ?? 1));
|
|
21225
|
+
}
|
|
21226
|
+
// Optimization (Phase 3)
|
|
21227
|
+
if (config.optimization) {
|
|
21228
|
+
const opt = config.optimization;
|
|
21229
|
+
// Responsive breakpoints
|
|
21230
|
+
opt.responsive && (opt.responsive.breakpoints && (tokens["optimization-breakpoint-mobile"] = opt.responsive.breakpoints.mobile ?? "0px",
|
|
21231
|
+
tokens["optimization-breakpoint-tablet"] = opt.responsive.breakpoints.tablet ?? "768px",
|
|
21232
|
+
tokens["optimization-breakpoint-desktop"] = opt.responsive.breakpoints.desktop ?? "1024px",
|
|
21233
|
+
tokens["optimization-breakpoint-wide"] = opt.responsive.breakpoints.wide ?? "1440px"),
|
|
21234
|
+
opt.responsive.deviceScaling && (tokens["optimization-device-scaling-mobile"] = String(opt.responsive.deviceScaling.mobile ?? .5),
|
|
21235
|
+
tokens["optimization-device-scaling-tablet"] = String(opt.responsive.deviceScaling.tablet ?? .75),
|
|
21236
|
+
tokens["optimization-device-scaling-desktop"] = String(opt.responsive.deviceScaling.desktop ?? 1))),
|
|
21237
|
+
// Performance settings
|
|
21238
|
+
opt.performance && (tokens["optimization-performance-fps-target"] = String(opt.performance.fpsTarget ?? 60),
|
|
21239
|
+
tokens["optimization-auto-scaling-enabled"] = String(opt.performance.autoScaling ?? !1),
|
|
21240
|
+
tokens["optimization-monitor-dashboard-enabled"] = String(opt.performance.monitorDashboard ?? !1)),
|
|
21241
|
+
// Auto-scaling settings
|
|
21242
|
+
opt.autoScaling && (tokens["optimization-auto-scaling-enabled"] = String(opt.autoScaling.enabled ?? !1),
|
|
21243
|
+
tokens["optimization-auto-scaling-low-end"] = String(opt.autoScaling.qualityThresholds?.lowEnd ?? .5),
|
|
21244
|
+
tokens["optimization-auto-scaling-mid-range"] = String(opt.autoScaling.qualityThresholds?.midRange ?? .75),
|
|
21245
|
+
tokens["optimization-auto-scaling-high-end"] = String(opt.autoScaling.qualityThresholds?.highEnd ?? 1));
|
|
21246
|
+
}
|
|
21247
|
+
// Visual Polish (Phase 4)
|
|
21248
|
+
if (config.visualPolish) {
|
|
21249
|
+
const vp = config.visualPolish;
|
|
21250
|
+
vp.borders && (tokens["visual-polish-border-iridescent-glow"] = String(vp.borders.iridescentGlow ?? !1),
|
|
21251
|
+
tokens["visual-polish-border-shimmer-effect"] = String(vp.borders.shimmerEffect ?? !1),
|
|
21252
|
+
tokens["visual-polish-border-beveled-edges"] = String(vp.borders.beveledEdges ?? !1),
|
|
21253
|
+
tokens["visual-polish-border-pulsing-glow"] = String(vp.borders.pulsingGlow ?? !1)),
|
|
21254
|
+
vp.contentAwareBlur && (tokens["visual-polish-content-aware-blur-enabled"] = String(vp.contentAwareBlur.enabled ?? !1),
|
|
21255
|
+
tokens["visual-polish-content-aware-depth-detection"] = String(vp.contentAwareBlur.depthDetection ?? !1),
|
|
21256
|
+
tokens["visual-polish-content-aware-edge-preservation"] = String(vp.contentAwareBlur.edgePreservation ?? !1),
|
|
21257
|
+
tokens["visual-polish-content-aware-variable-radius"] = String(vp.contentAwareBlur.variableRadius ?? !1)),
|
|
21258
|
+
vp.holographicEffects && (tokens["visual-polish-holographic-enabled"] = String(vp.holographicEffects.enabled ?? !1),
|
|
21259
|
+
tokens["visual-polish-holographic-rainbow-diffraction"] = String(vp.holographicEffects.rainbowDiffraction ?? !1),
|
|
21260
|
+
tokens["visual-polish-holographic-scanline-animation"] = String(vp.holographicEffects.scanlineAnimation ?? !1),
|
|
21261
|
+
tokens["visual-polish-holographic-grid-overlay"] = String(vp.holographicEffects.gridOverlay ?? !1),
|
|
21262
|
+
tokens["visual-polish-holographic-data-stream"] = String(vp.holographicEffects.dataStream ?? !1),
|
|
21263
|
+
tokens["visual-polish-holographic-pulse-rings"] = String(vp.holographicEffects.pulseRings ?? !1));
|
|
21264
|
+
}
|
|
21047
21265
|
}
|
|
21266
|
+
// Apply prefix to all tokens
|
|
21267
|
+
const prefixedTokens = {};
|
|
21268
|
+
return Object.entries(tokens).forEach((([key, value]) => {
|
|
21269
|
+
// If the token key already starts with the prefix, use as-is
|
|
21270
|
+
// Otherwise, add the prefix
|
|
21271
|
+
const prefixedKey = key.startsWith(prefix) ? key : `${prefix}-${key}`;
|
|
21272
|
+
prefixedTokens[prefixedKey] = value;
|
|
21273
|
+
})), prefixedTokens;
|
|
21048
21274
|
}
|
|
21049
21275
|
|
|
21050
21276
|
/**
|
|
21051
|
-
*
|
|
21052
|
-
*/
|
|
21053
|
-
|
|
21054
|
-
|
|
21055
|
-
|
|
21277
|
+
* Convert hex color to RGB
|
|
21278
|
+
*/ function hexToRgb$2(hex) {
|
|
21279
|
+
hex = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, ((m, r, g, b) => r + r + g + g + b + b));
|
|
21280
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
21281
|
+
return result && result[1] && result[2] && result[3] ? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}` : "0, 0, 0";
|
|
21282
|
+
}
|
|
21056
21283
|
|
|
21057
21284
|
/**
|
|
21058
|
-
*
|
|
21285
|
+
* Converts DesignTokens to CSS variables
|
|
21059
21286
|
*
|
|
21060
|
-
*
|
|
21061
|
-
*
|
|
21287
|
+
* @param tokens - The tokens to convert
|
|
21288
|
+
* @returns A record of CSS variable names and values
|
|
21289
|
+
*/ function designTokensToCSSVars(tokens) {
|
|
21290
|
+
const cssVars = {};
|
|
21291
|
+
return Object.entries(tokens).forEach((([key, value]) => {
|
|
21292
|
+
void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
|
|
21293
|
+
})), cssVars;
|
|
21294
|
+
}
|
|
21295
|
+
|
|
21296
|
+
/**
|
|
21297
|
+
* Load theme from config file (synchronous, Node.js only)
|
|
21298
|
+
* @param configPath - Path to config file (default: atomix.config.ts)
|
|
21299
|
+
* @returns DesignTokens from theme configuration
|
|
21300
|
+
* @throws Error if config loading is not available in browser environment
|
|
21062
21301
|
*/
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
|
|
21075
|
-
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
|
|
21083
|
-
|
|
21084
|
-
|
|
21085
|
-
|
|
21086
|
-
|
|
21302
|
+
/**
|
|
21303
|
+
* Atomix Config Loader
|
|
21304
|
+
*
|
|
21305
|
+
* Helper functions to load atomix.config.ts from external projects.
|
|
21306
|
+
* Now also supports atomix.config.js and atomix.config.json
|
|
21307
|
+
*/
|
|
21308
|
+
/**
|
|
21309
|
+
* Validate Atomix configuration structure
|
|
21310
|
+
*
|
|
21311
|
+
* Performs basic validation to catch common configuration errors early.
|
|
21312
|
+
* Returns warnings for potential issues.
|
|
21313
|
+
*
|
|
21314
|
+
* @param config - Configuration object to validate
|
|
21315
|
+
* @returns Array of validation warnings (empty if valid)
|
|
21316
|
+
*
|
|
21317
|
+
* @example
|
|
21318
|
+
* ```typescript
|
|
21319
|
+
* import { loadAtomixConfig, validateConfig } from '@shohojdhara/atomix/config';
|
|
21320
|
+
*
|
|
21321
|
+
* const config = loadAtomixConfig();
|
|
21322
|
+
* const warnings = validateConfig(config);
|
|
21323
|
+
* warnings.forEach(w => console.warn(w));
|
|
21324
|
+
* ```
|
|
21325
|
+
*/
|
|
21326
|
+
function validateConfig$1(config) {
|
|
21327
|
+
const warnings = [];
|
|
21328
|
+
// Check prefix format
|
|
21329
|
+
// Check theme structure
|
|
21330
|
+
if (config.prefix && (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(config.prefix) || warnings.push(`Invalid prefix "${config.prefix}". Prefix should start with a letter and contain only letters, numbers, and hyphens.\nExample: "myapp", "brand-ui", "enterprise"`),
|
|
21331
|
+
config.prefix.length < 2 && warnings.push(`Prefix "${config.prefix}" is too short. Use at least 2 characters for clarity.\nExample: "app" instead of "a"`)),
|
|
21332
|
+
config.theme && (
|
|
21333
|
+
// Warn if both extend and tokens are provided
|
|
21334
|
+
config.theme.extend && config.theme.tokens && warnings.push("Both theme.extend and theme.tokens are defined. theme.tokens will take precedence and completely replace the default token system.\nIf you want to extend defaults, remove theme.tokens and use only theme.extend."),
|
|
21335
|
+
config.theme.extend)) {
|
|
21336
|
+
const extend = config.theme.extend, validThemeKeys = [ "colors", "typography", "spacing", "borderRadius", "shadows", "zIndex", "transitions", "breakpoints" ];
|
|
21337
|
+
// Check for common typos in theme properties
|
|
21338
|
+
Object.keys(extend).forEach((key => {
|
|
21339
|
+
_includesInstanceProperty(validThemeKeys).call(validThemeKeys, key) || warnings.push(`Unknown theme property: "${key}"\nValid properties: ${validThemeKeys.join(", ")}\nDid you mean one of these? Check for typos.`);
|
|
21340
|
+
}));
|
|
21087
21341
|
}
|
|
21088
|
-
|
|
21089
|
-
|
|
21090
|
-
|
|
21091
|
-
|
|
21092
|
-
|
|
21342
|
+
// Validate advanced features
|
|
21343
|
+
if (config.interactiveEffects) {
|
|
21344
|
+
const ie = config.interactiveEffects;
|
|
21345
|
+
// Validate vortex settings
|
|
21346
|
+
ie.vortex && (ie.vortex.strength && (ie.vortex.strength < 0 || ie.vortex.strength > 10) && warnings.push("Vortex strength should be between 0 and 10 for optimal performance"),
|
|
21347
|
+
ie.vortex.radius && ie.vortex.radius < 0 && warnings.push("Vortex radius should be a positive number"),
|
|
21348
|
+
ie.vortex.decay && (ie.vortex.decay <= 0 || ie.vortex.decay > 1) && warnings.push("Vortex decay should be between 0 and 1")),
|
|
21349
|
+
// Validate chromatic aberration settings
|
|
21350
|
+
ie.chromaticAberration && (ie.chromaticAberration.redShift && Math.abs(ie.chromaticAberration.redShift) > .1 && warnings.push("Chromatic red shift value seems unusually high (>0.1), verify this is intended"),
|
|
21351
|
+
ie.chromaticAberration.blueShift && Math.abs(ie.chromaticAberration.blueShift) > .1 && warnings.push("Chromatic blue shift value seems unusually high (>0.1), verify this is intended"),
|
|
21352
|
+
ie.chromaticAberration.edgeThreshold && (ie.chromaticAberration.edgeThreshold < 0 || ie.chromaticAberration.edgeThreshold > 1) && warnings.push("Chromatic edge threshold should be between 0 and 1")),
|
|
21353
|
+
// Validate mouse interaction settings
|
|
21354
|
+
ie.mouseInteraction && ie.mouseInteraction.sensitivity && ie.mouseInteraction.sensitivity < 0 && warnings.push("Mouse sensitivity should be a positive number"),
|
|
21355
|
+
// Validate animation speed settings
|
|
21356
|
+
ie.animationSpeed && (ie.animationSpeed.base && ie.animationSpeed.base <= 0 && warnings.push("Animation base speed should be greater than 0"),
|
|
21357
|
+
ie.animationSpeed.timeMultiplier && ie.animationSpeed.timeMultiplier <= 0 && warnings.push("Animation time multiplier should be greater than 0"));
|
|
21093
21358
|
}
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
|
|
21098
|
-
|
|
21359
|
+
// Validate optimization settings
|
|
21360
|
+
if (config.optimization) {
|
|
21361
|
+
const opt = config.optimization;
|
|
21362
|
+
// Validate responsive breakpoints
|
|
21363
|
+
if (opt.responsive && opt.responsive.breakpoints) {
|
|
21364
|
+
const breakpoints = opt.responsive.breakpoints;
|
|
21365
|
+
breakpoints.mobile && !isValidCSSLength(breakpoints.mobile) && warnings.push("Mobile breakpoint value is not a valid CSS length"),
|
|
21366
|
+
breakpoints.tablet && !isValidCSSLength(breakpoints.tablet) && warnings.push("Tablet breakpoint value is not a valid CSS length"),
|
|
21367
|
+
breakpoints.desktop && !isValidCSSLength(breakpoints.desktop) && warnings.push("Desktop breakpoint value is not a valid CSS length"),
|
|
21368
|
+
breakpoints.wide && !isValidCSSLength(breakpoints.wide) && warnings.push("Wide breakpoint value is not a valid CSS length");
|
|
21369
|
+
}
|
|
21370
|
+
// Validate device scaling
|
|
21371
|
+
if (opt.responsive && opt.responsive.deviceScaling) {
|
|
21372
|
+
const scaling = opt.responsive.deviceScaling;
|
|
21373
|
+
scaling.mobile && (scaling.mobile <= 0 || scaling.mobile > 1) && warnings.push("Mobile device scaling should be between 0 and 1"),
|
|
21374
|
+
scaling.tablet && (scaling.tablet <= 0 || scaling.tablet > 1) && warnings.push("Tablet device scaling should be between 0 and 1"),
|
|
21375
|
+
scaling.desktop && (scaling.desktop <= 0 || scaling.desktop > 1) && warnings.push("Desktop device scaling should be between 0 and 1");
|
|
21376
|
+
}
|
|
21377
|
+
// Validate performance settings
|
|
21378
|
+
// Validate auto-scaling thresholds
|
|
21379
|
+
if (opt.performance && opt.performance.fpsTarget && (opt.performance.fpsTarget <= 0 || opt.performance.fpsTarget > 240) && warnings.push("FPS target should be a reasonable value (typically 30-120)"),
|
|
21380
|
+
opt.autoScaling && opt.autoScaling.qualityThresholds) {
|
|
21381
|
+
const thresholds = opt.autoScaling.qualityThresholds;
|
|
21382
|
+
thresholds.lowEnd && (thresholds.lowEnd < 0 || thresholds.lowEnd > 1) && warnings.push("Auto-scaling low-end threshold should be between 0 and 1"),
|
|
21383
|
+
thresholds.midRange && (thresholds.midRange < 0 || thresholds.midRange > 1) && warnings.push("Auto-scaling mid-range threshold should be between 0 and 1"),
|
|
21384
|
+
thresholds.highEnd && (thresholds.highEnd < 0 || thresholds.highEnd > 1) && warnings.push("Auto-scaling high-end threshold should be between 0 and 1");
|
|
21385
|
+
}
|
|
21099
21386
|
}
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
|
|
21103
|
-
|
|
21387
|
+
// Validate visual polish settings
|
|
21388
|
+
if (config.visualPolish) {
|
|
21389
|
+
const vp = config.visualPolish;
|
|
21390
|
+
// Validate content aware blur settings
|
|
21391
|
+
vp.contentAwareBlur && (void 0 !== vp.contentAwareBlur.edgePreservation && "boolean" != typeof vp.contentAwareBlur.edgePreservation && warnings.push("Content-aware blur edge preservation should be a boolean value"),
|
|
21392
|
+
void 0 !== vp.contentAwareBlur.depthDetection && "boolean" != typeof vp.contentAwareBlur.depthDetection && warnings.push("Content-aware blur depth detection should be a boolean value")),
|
|
21393
|
+
// Validate holographic effects settings
|
|
21394
|
+
vp.holographicEffects && (void 0 !== vp.holographicEffects.enabled && "boolean" != typeof vp.holographicEffects.enabled && warnings.push("Holographic effects enabled should be a boolean value"),
|
|
21395
|
+
void 0 !== vp.holographicEffects.rainbowDiffraction && "boolean" != typeof vp.holographicEffects.rainbowDiffraction && warnings.push("Holographic rainbow diffraction should be a boolean value"));
|
|
21104
21396
|
}
|
|
21397
|
+
// Validate AI settings
|
|
21398
|
+
var _context;
|
|
21399
|
+
return config.ai && (config.ai.provider && !_includesInstanceProperty(_context = [ "openai", "anthropic" ]).call(_context, config.ai.provider) && warnings.push(`Unknown AI provider: "${config.ai.provider}". Supported: openai, anthropic`),
|
|
21400
|
+
config.ai.temperature && (config.ai.temperature < 0 || config.ai.temperature > 1) && warnings.push("AI temperature should be between 0 and 1"),
|
|
21401
|
+
config.ai.maxTokens && config.ai.maxTokens < 100 && warnings.push("AI maxTokens should typically be 100 or more"),
|
|
21402
|
+
config.ai.rateLimit && (config.ai.rateLimit.requests <= 0 && warnings.push("AI rate limit requests should be greater than 0"),
|
|
21403
|
+
config.ai.rateLimit.windowMs <= 0 && warnings.push("AI rate limit window should be greater than 0"))),
|
|
21404
|
+
// Validate telemetry settings
|
|
21405
|
+
config.telemetry && config.telemetry.path && !config.telemetry.path.endsWith(".json") && warnings.push("Telemetry path should typically end with .json"),
|
|
21406
|
+
warnings;
|
|
21105
21407
|
}
|
|
21106
21408
|
|
|
21107
21409
|
/**
|
|
21108
|
-
*
|
|
21109
|
-
*/
|
|
21410
|
+
* Helper function to validate CSS length values
|
|
21411
|
+
*/ function isValidCSSLength(value) {
|
|
21412
|
+
return /^(\d+(\.\d+)?)(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ex|ch)?$/.test(value);
|
|
21413
|
+
}
|
|
21110
21414
|
|
|
21111
21415
|
/**
|
|
21112
|
-
*
|
|
21113
|
-
|
|
21114
|
-
|
|
21416
|
+
* Load Atomix configuration from project root
|
|
21417
|
+
*
|
|
21418
|
+
* Attempts to load atomix.config.ts, atomix.config.js, or atomix.config.json from the current working directory.
|
|
21419
|
+
* Falls back to default config if file doesn't exist.
|
|
21420
|
+
*
|
|
21421
|
+
* @param options - Loader options
|
|
21422
|
+
* @returns Loaded configuration or default
|
|
21423
|
+
*
|
|
21424
|
+
* @example
|
|
21425
|
+
* ```typescript
|
|
21426
|
+
* import { loadAtomixConfig } from '@shohojdhara/atomix/config';
|
|
21427
|
+
* import { createTheme } from '@shohojdhara/atomix/theme';
|
|
21428
|
+
*
|
|
21429
|
+
* const config = loadAtomixConfig();
|
|
21430
|
+
* const theme = createTheme(config.theme?.tokens || {});
|
|
21431
|
+
* ```
|
|
21432
|
+
*/ function loadAtomixConfig(options = {}) {
|
|
21433
|
+
const {configPath: configPath, required: required = !1} = options, defaultConfig = {
|
|
21434
|
+
prefix: "atomix",
|
|
21435
|
+
theme: {
|
|
21436
|
+
extend: {}
|
|
21437
|
+
}
|
|
21438
|
+
};
|
|
21439
|
+
// Default config
|
|
21440
|
+
// In browser environments, config loading is not supported
|
|
21441
|
+
if ("undefined" != typeof window) {
|
|
21442
|
+
if (required) throw new Error('Config loading requires Node.js file system access.\n\nSolutions:\n1. Provide tokens explicitly to createTheme():\n const css = createTheme({ "--brand-primary": "#6366f1" });\n\n2. Use SSR framework (Next.js, Remix, Astro)\n\n3. Load config on server and pass to client\n\nSee examples/config-examples/browser-only.config.ts');
|
|
21443
|
+
return defaultConfig;
|
|
21444
|
+
}
|
|
21445
|
+
// If a specific config path is provided, try to load it directly
|
|
21446
|
+
if (configPath) return loadConfigAtPath(configPath, required, defaultConfig);
|
|
21447
|
+
// Otherwise, try standard locations in order of preference
|
|
21448
|
+
const possiblePaths = [ "atomix.config.ts", "atomix.config.js", "atomix.config.json" ];
|
|
21449
|
+
for (const path of possiblePaths) {
|
|
21450
|
+
const config = loadConfigAtPath(path, !1, defaultConfig);
|
|
21451
|
+
// If we found a valid config, return it
|
|
21452
|
+
if (JSON.stringify(config) !== JSON.stringify(defaultConfig)) return config;
|
|
21453
|
+
}
|
|
21454
|
+
// If no config file was found or all contained only defaults, return default config
|
|
21455
|
+
if (required) throw new Error('No Atomix configuration file found in project root.\n\nExpected one of:\n - atomix.config.ts (recommended)\n - atomix.config.js\n - atomix.config.json\n\nQuick Fix:\n1. Create a config file in your project root:\n touch atomix.config.ts\n\n2. Add basic configuration:\n import { defineConfig } from "@shohojdhara/atomix/config";\n export default defineConfig({ prefix: "myapp" });\n\n3. Or copy an example:\n cp node_modules/@shohojdhara/atomix/examples/config-examples/standard.config.ts ./atomix.config.ts');
|
|
21456
|
+
return defaultConfig;
|
|
21457
|
+
}
|
|
21458
|
+
|
|
21459
|
+
/**
|
|
21460
|
+
* Helper function to load config from a specific path
|
|
21461
|
+
*/ function loadConfigAtPath(path, required, defaultConfig) {
|
|
21462
|
+
try {
|
|
21463
|
+
// Use dynamic import for ESM compatibility
|
|
21464
|
+
const configModule = require(path), config = configModule.default || configModule;
|
|
21465
|
+
// Validate it's an AtomixConfig
|
|
21466
|
+
if (config && "object" == typeof config) return config;
|
|
21467
|
+
throw new Error("Invalid config format");
|
|
21468
|
+
} catch (error) {
|
|
21469
|
+
if (required) throw new Error(`Failed to load config from ${path}: ${error.message}`);
|
|
21470
|
+
// Return default config if not required
|
|
21471
|
+
return defaultConfig;
|
|
21472
|
+
}
|
|
21115
21473
|
}
|
|
21116
21474
|
|
|
21475
|
+
/**
|
|
21476
|
+
* Resolve config path
|
|
21477
|
+
*
|
|
21478
|
+
* Finds atomix.config.ts in the project, checking common locations.
|
|
21479
|
+
* Returns null in browser environments where file system access is not available.
|
|
21480
|
+
*
|
|
21481
|
+
* This function is designed to help tools identify if a config exists without loading it.
|
|
21482
|
+
*
|
|
21483
|
+
* @param configPath - Optional custom path to check
|
|
21484
|
+
* @returns Absolute path to config file or null if not found
|
|
21485
|
+
*/
|
|
21117
21486
|
/**
|
|
21118
21487
|
* Core Theme Functions
|
|
21119
21488
|
*
|
|
21120
|
-
*
|
|
21489
|
+
* Unified theme system that handles both DesignTokens and Theme objects.
|
|
21121
21490
|
* Config-first approach: loads from atomix.config.ts when no input is provided.
|
|
21491
|
+
* Config-first approach: loads advanced features from config when available.
|
|
21122
21492
|
*/
|
|
21123
21493
|
/**
|
|
21124
|
-
* Create theme CSS from
|
|
21494
|
+
* Create theme CSS from tokens or Theme object
|
|
21125
21495
|
*
|
|
21126
21496
|
* **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
|
|
21497
|
+
* Config file is required for automatic loading.
|
|
21127
21498
|
*
|
|
21128
|
-
* @param input - DesignTokens (partial) or undefined (loads from config)
|
|
21499
|
+
* @param input - DesignTokens (partial), Theme object, or undefined (loads from config)
|
|
21129
21500
|
* @param options - CSS generation options (prefix is automatically read from config if not provided)
|
|
21130
21501
|
* @returns CSS string with custom properties
|
|
21131
21502
|
* @throws Error if config loading fails when no input is provided
|
|
21132
21503
|
*
|
|
21133
21504
|
* @example
|
|
21134
21505
|
* ```typescript
|
|
21135
|
-
* // Loads from atomix.config.ts
|
|
21506
|
+
* // Loads from atomix.config.ts (config file required)
|
|
21136
21507
|
* const css = createTheme();
|
|
21137
21508
|
*
|
|
21138
21509
|
* // Using DesignTokens
|
|
@@ -21141,42 +21512,151 @@ class ThemeLogger {
|
|
|
21141
21512
|
* 'spacing-4': '1rem',
|
|
21142
21513
|
* });
|
|
21143
21514
|
*
|
|
21515
|
+
* // Using Theme object
|
|
21516
|
+
* const theme = createThemeObject({ palette: { primary: { main: '#7c3aed' } } });
|
|
21517
|
+
* const css = createTheme(theme);
|
|
21518
|
+
*
|
|
21144
21519
|
* // With custom options
|
|
21145
21520
|
* const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
|
|
21146
21521
|
* ```
|
|
21147
|
-
*/
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
21153
|
-
|
|
21154
|
-
|
|
21155
|
-
|
|
21156
|
-
|
|
21157
|
-
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21164
|
-
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21522
|
+
*/
|
|
21523
|
+
function createTheme(input, options) {
|
|
21524
|
+
let tokens, configPrefix;
|
|
21525
|
+
// If no input provided, load from config (required)
|
|
21526
|
+
if (input)
|
|
21527
|
+
// Convert Theme object to DesignTokens
|
|
21528
|
+
tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
|
|
21529
|
+
const configTokens = function() {
|
|
21530
|
+
// Check if we're in a browser environment
|
|
21531
|
+
if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
21532
|
+
// Use dynamic import to load the config loader
|
|
21533
|
+
// This allows bundlers to handle external dependencies properly
|
|
21534
|
+
let loadAtomixConfig;
|
|
21535
|
+
try {
|
|
21536
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
21537
|
+
const {loadAtomixConfig: loader} = require("../../config/loader");
|
|
21538
|
+
loadAtomixConfig = loader;
|
|
21539
|
+
} catch (error) {
|
|
21540
|
+
throw new Error("Config loader module not available");
|
|
21541
|
+
}
|
|
21542
|
+
const config = loadAtomixConfig({
|
|
21543
|
+
configPath: undefined,
|
|
21544
|
+
required: !0
|
|
21545
|
+
});
|
|
21546
|
+
if (!config?.theme) return createTokens({});
|
|
21547
|
+
if ((obj = config.theme) && "object" == typeof obj && (obj.palette || obj.typography || obj.spacing || obj.breakpoints || obj.colors)) return themeToDesignTokens(config.theme);
|
|
21548
|
+
// Handle the config.theme object which has extend/tokens/themes properties
|
|
21549
|
+
// Extract the actual tokens from the theme configuration
|
|
21550
|
+
// Helper type guard function
|
|
21551
|
+
var obj;
|
|
21552
|
+
const themeConfig = config.theme;
|
|
21553
|
+
let tokensToApply = {};
|
|
21554
|
+
return themeConfig.tokens ?
|
|
21555
|
+
// If tokens is provided, use it as the base
|
|
21556
|
+
tokensToApply = themeConfig.tokens : themeConfig.extend && (
|
|
21557
|
+
// If only extend is provided, use it as overrides
|
|
21558
|
+
tokensToApply = themeConfig.extend),
|
|
21559
|
+
// Apply advanced feature configurations as tokens
|
|
21560
|
+
config.interactiveEffects && (
|
|
21561
|
+
// Vortex effects
|
|
21562
|
+
config.interactiveEffects.vortex && (tokensToApply = {
|
|
21563
|
+
...tokensToApply,
|
|
21564
|
+
"interactive-vortex-enabled": String(config.interactiveEffects.vortex.enabled ?? !1),
|
|
21565
|
+
"interactive-vortex-strength": String(config.interactiveEffects.vortex.strength ?? .5),
|
|
21566
|
+
"interactive-vortex-radius": String(config.interactiveEffects.vortex.radius ?? 100),
|
|
21567
|
+
"interactive-vortex-decay": String(config.interactiveEffects.vortex.decay ?? .8)
|
|
21568
|
+
}),
|
|
21569
|
+
// Chromatic aberration
|
|
21570
|
+
config.interactiveEffects.chromaticAberration && (tokensToApply = {
|
|
21571
|
+
...tokensToApply,
|
|
21572
|
+
"interactive-chromatic-enabled": String(config.interactiveEffects.chromaticAberration.enabled ?? !1),
|
|
21573
|
+
"interactive-chromatic-mode": config.interactiveEffects.chromaticAberration.mode ?? "lateral",
|
|
21574
|
+
"interactive-chromatic-red-shift": String(config.interactiveEffects.chromaticAberration.redShift ?? .02),
|
|
21575
|
+
"interactive-chromatic-green-shift": String(config.interactiveEffects.chromaticAberration.greenShift ?? 0),
|
|
21576
|
+
"interactive-chromatic-blue-shift": String(config.interactiveEffects.chromaticAberration.blueShift ?? -.02),
|
|
21577
|
+
"interactive-chromatic-edge-only": String(config.interactiveEffects.chromaticAberration.edgeOnly ?? !1),
|
|
21578
|
+
"interactive-chromatic-edge-threshold": String(config.interactiveEffects.chromaticAberration.edgeThreshold ?? .5)
|
|
21579
|
+
}),
|
|
21580
|
+
// Mouse interaction
|
|
21581
|
+
config.interactiveEffects.mouseInteraction && (tokensToApply = {
|
|
21582
|
+
...tokensToApply,
|
|
21583
|
+
"interactive-mouse-sensitivity": String(config.interactiveEffects.mouseInteraction.sensitivity ?? 1),
|
|
21584
|
+
"interactive-mouse-trail-effect": String(config.interactiveEffects.mouseInteraction.trailEffect ?? !1)
|
|
21585
|
+
}),
|
|
21586
|
+
// Animation speed
|
|
21587
|
+
config.interactiveEffects.animationSpeed && (tokensToApply = {
|
|
21588
|
+
...tokensToApply,
|
|
21589
|
+
"interactive-animation-speed-base": String(config.interactiveEffects.animationSpeed.base ?? 1),
|
|
21590
|
+
"interactive-animation-speed-multiplier": String(config.interactiveEffects.animationSpeed.timeMultiplier ?? 1)
|
|
21591
|
+
})),
|
|
21592
|
+
// Apply optimization configurations as tokens
|
|
21593
|
+
config.optimization && (
|
|
21594
|
+
// Responsive breakpoints
|
|
21595
|
+
config.optimization.responsive && (config.optimization.responsive.breakpoints && (tokensToApply = {
|
|
21596
|
+
...tokensToApply,
|
|
21597
|
+
"optimization-breakpoint-mobile": config.optimization.responsive.breakpoints.mobile ?? "0px",
|
|
21598
|
+
"optimization-breakpoint-tablet": config.optimization.responsive.breakpoints.tablet ?? "768px",
|
|
21599
|
+
"optimization-breakpoint-desktop": config.optimization.responsive.breakpoints.desktop ?? "1024px",
|
|
21600
|
+
"optimization-breakpoint-wide": config.optimization.responsive.breakpoints.wide ?? "1440px"
|
|
21601
|
+
}), config.optimization.responsive.deviceScaling && (tokensToApply = {
|
|
21602
|
+
...tokensToApply,
|
|
21603
|
+
"optimization-device-scaling-mobile": String(config.optimization.responsive.deviceScaling.mobile ?? .5),
|
|
21604
|
+
"optimization-device-scaling-tablet": String(config.optimization.responsive.deviceScaling.tablet ?? .75),
|
|
21605
|
+
"optimization-device-scaling-desktop": String(config.optimization.responsive.deviceScaling.desktop ?? 1)
|
|
21606
|
+
})),
|
|
21607
|
+
// Performance settings
|
|
21608
|
+
config.optimization.performance && (tokensToApply = {
|
|
21609
|
+
...tokensToApply,
|
|
21610
|
+
"optimization-performance-fps-target": String(config.optimization.performance.fpsTarget ?? 60),
|
|
21611
|
+
"optimization-auto-scaling-enabled": String(config.optimization.performance.autoScaling ?? !1)
|
|
21612
|
+
}),
|
|
21613
|
+
// Auto-scaling settings
|
|
21614
|
+
config.optimization.autoScaling && (tokensToApply = {
|
|
21615
|
+
...tokensToApply,
|
|
21616
|
+
"optimization-auto-scaling-enabled": String(config.optimization.autoScaling.enabled ?? !1),
|
|
21617
|
+
"optimization-auto-scaling-low-end": String(config.optimization.autoScaling.qualityThresholds?.lowEnd ?? .5),
|
|
21618
|
+
"optimization-auto-scaling-mid-range": String(config.optimization.autoScaling.qualityThresholds?.midRange ?? .75),
|
|
21619
|
+
"optimization-auto-scaling-high-end": String(config.optimization.autoScaling.qualityThresholds?.highEnd ?? 1)
|
|
21620
|
+
})),
|
|
21621
|
+
// Apply visual polish configurations as tokens
|
|
21622
|
+
config.visualPolish && (config.visualPolish.borders && (tokensToApply = {
|
|
21623
|
+
...tokensToApply,
|
|
21624
|
+
"visual-polish-border-iridescent-glow": String(config.visualPolish.borders.iridescentGlow ?? !1),
|
|
21625
|
+
"visual-polish-border-shimmer-effect": String(config.visualPolish.borders.shimmerEffect ?? !1),
|
|
21626
|
+
"visual-polish-border-beveled-edges": String(config.visualPolish.borders.beveledEdges ?? !1),
|
|
21627
|
+
"visual-polish-border-pulsing-glow": String(config.visualPolish.borders.pulsingGlow ?? !1)
|
|
21628
|
+
}), config.visualPolish.contentAwareBlur && (tokensToApply = {
|
|
21629
|
+
...tokensToApply,
|
|
21630
|
+
"visual-polish-content-aware-blur-enabled": String(config.visualPolish.contentAwareBlur.enabled ?? !1),
|
|
21631
|
+
"visual-polish-content-aware-depth-detection": String(config.visualPolish.contentAwareBlur.depthDetection ?? !1),
|
|
21632
|
+
"visual-polish-content-aware-edge-preservation": String(config.visualPolish.contentAwareBlur.edgePreservation ?? !1),
|
|
21633
|
+
"visual-polish-content-aware-variable-radius": String(config.visualPolish.contentAwareBlur.variableRadius ?? !1)
|
|
21634
|
+
}), config.visualPolish.holographicEffects && (tokensToApply = {
|
|
21635
|
+
...tokensToApply,
|
|
21636
|
+
"visual-polish-holographic-enabled": String(config.visualPolish.holographicEffects.enabled ?? !1),
|
|
21637
|
+
"visual-polish-holographic-rainbow-diffraction": String(config.visualPolish.holographicEffects.rainbowDiffraction ?? !1),
|
|
21638
|
+
"visual-polish-holographic-scanline-animation": String(config.visualPolish.holographicEffects.scanlineAnimation ?? !1),
|
|
21639
|
+
"visual-polish-holographic-grid-overlay": String(config.visualPolish.holographicEffects.gridOverlay ?? !1),
|
|
21640
|
+
"visual-polish-holographic-data-stream": String(config.visualPolish.holographicEffects.dataStream ?? !1),
|
|
21641
|
+
"visual-polish-holographic-pulse-rings": String(config.visualPolish.holographicEffects.pulseRings ?? !1)
|
|
21642
|
+
})), createTokens(tokensToApply);
|
|
21643
|
+
}();
|
|
21644
|
+
// Get prefix from config
|
|
21645
|
+
try {
|
|
21646
|
+
// Use the imported function directly instead of require to avoid bundling issues
|
|
21647
|
+
const config = loadAtomixConfig({
|
|
21648
|
+
configPath: "atomix.config.ts",
|
|
21649
|
+
required: !0
|
|
21650
|
+
});
|
|
21651
|
+
configPrefix = config?.prefix;
|
|
21652
|
+
} catch (error) {
|
|
21653
|
+
// Prefix loading failed, but tokens were loaded, so continue
|
|
21654
|
+
}
|
|
21655
|
+
tokens = configTokens;
|
|
21169
21656
|
}
|
|
21170
21657
|
// Merge with defaults and generate CSS
|
|
21171
|
-
|
|
21172
|
-
//
|
|
21173
|
-
// If no input is provided, we return an empty theme (using defaults only) or user must provide tokens.
|
|
21174
|
-
// This allows createTheme to be isomorphic.
|
|
21175
|
-
// Warn in development if no input provided
|
|
21176
|
-
"production" !== process.env.NODE_ENV && "undefined" != typeof window && console.warn("Atomix: createTheme() called without tokens. Using default tokens only."),
|
|
21177
|
-
tokens = {};
|
|
21178
|
-
const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
|
|
21179
|
-
// Get prefix from options or use default
|
|
21658
|
+
const allTokens = createTokens(tokens), prefix = options?.prefix ?? configPrefix ?? "atomix";
|
|
21659
|
+
// Get prefix from options, config, or use default
|
|
21180
21660
|
return generateCSSVariables$1(allTokens, {
|
|
21181
21661
|
...options,
|
|
21182
21662
|
prefix: prefix
|
|
@@ -21390,43 +21870,176 @@ class ThemeLogger {
|
|
|
21390
21870
|
*/
|
|
21391
21871
|
/**
|
|
21392
21872
|
* Default storage key for theme persistence
|
|
21393
|
-
*/
|
|
21394
|
-
|
|
21873
|
+
*/
|
|
21395
21874
|
/**
|
|
21396
|
-
*
|
|
21875
|
+
* Theme System Error Handling
|
|
21876
|
+
*
|
|
21877
|
+
* Centralized error handling for the Atomix theme system.
|
|
21878
|
+
* Provides custom error classes and logging utilities.
|
|
21397
21879
|
*/
|
|
21398
|
-
|
|
21399
|
-
|
|
21400
|
-
|
|
21401
|
-
|
|
21402
|
-
|
|
21403
|
-
|
|
21404
|
-
|
|
21405
|
-
|
|
21406
|
-
|
|
21407
|
-
|
|
21408
|
-
|
|
21409
|
-
|
|
21410
|
-
|
|
21411
|
-
|
|
21412
|
-
|
|
21413
|
-
|
|
21414
|
-
|
|
21415
|
-
|
|
21416
|
-
|
|
21417
|
-
|
|
21418
|
-
|
|
21419
|
-
|
|
21420
|
-
|
|
21421
|
-
|
|
21422
|
-
|
|
21423
|
-
|
|
21424
|
-
|
|
21425
|
-
|
|
21426
|
-
|
|
21427
|
-
|
|
21428
|
-
|
|
21429
|
-
|
|
21880
|
+
/**
|
|
21881
|
+
* Theme error codes
|
|
21882
|
+
*/
|
|
21883
|
+
var ThemeErrorCode, LogLevel;
|
|
21884
|
+
|
|
21885
|
+
"undefined" != typeof process && process.env, function(ThemeErrorCode) {
|
|
21886
|
+
/** Theme not found in registry */
|
|
21887
|
+
ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
|
|
21888
|
+
/** Theme failed to load */
|
|
21889
|
+
ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
|
|
21890
|
+
/** Theme validation failed */
|
|
21891
|
+
ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
|
|
21892
|
+
/** Configuration loading failed */
|
|
21893
|
+
ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
|
|
21894
|
+
/** Configuration validation failed */
|
|
21895
|
+
ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
|
|
21896
|
+
/** Circular dependency detected */
|
|
21897
|
+
ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
|
|
21898
|
+
/** Missing dependency */
|
|
21899
|
+
ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
|
|
21900
|
+
/** Storage operation failed */
|
|
21901
|
+
ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
|
|
21902
|
+
/** Invalid theme name */
|
|
21903
|
+
ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
|
|
21904
|
+
/** CSS injection failed */
|
|
21905
|
+
ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
|
|
21906
|
+
/** Invalid color format */
|
|
21907
|
+
ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
|
|
21908
|
+
/** Missing required token */
|
|
21909
|
+
ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
|
|
21910
|
+
/** Accessibility contrast violation */
|
|
21911
|
+
ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
|
|
21912
|
+
/** Invalid token type */
|
|
21913
|
+
ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
|
|
21914
|
+
/** Unknown error */
|
|
21915
|
+
ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
|
21916
|
+
}(ThemeErrorCode || (ThemeErrorCode = {}));
|
|
21917
|
+
|
|
21918
|
+
/**
|
|
21919
|
+
* Custom error class for theme-related errors
|
|
21920
|
+
*/
|
|
21921
|
+
class ThemeError extends Error {
|
|
21922
|
+
constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
|
|
21923
|
+
super(message), this.name = "ThemeError", this.code = code, this.context = context,
|
|
21924
|
+
this.timestamp = Date.now(),
|
|
21925
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
21926
|
+
Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
|
|
21927
|
+
}
|
|
21928
|
+
/**
|
|
21929
|
+
* Convert error to JSON for logging
|
|
21930
|
+
*/ toJSON() {
|
|
21931
|
+
return {
|
|
21932
|
+
name: this.name,
|
|
21933
|
+
message: this.message,
|
|
21934
|
+
code: this.code,
|
|
21935
|
+
context: this.context,
|
|
21936
|
+
timestamp: this.timestamp,
|
|
21937
|
+
stack: this.stack
|
|
21938
|
+
};
|
|
21939
|
+
}
|
|
21940
|
+
}
|
|
21941
|
+
|
|
21942
|
+
/**
|
|
21943
|
+
* Log level
|
|
21944
|
+
*/ !function(LogLevel) {
|
|
21945
|
+
LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
|
|
21946
|
+
LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
|
|
21947
|
+
}(LogLevel || (LogLevel = {}));
|
|
21948
|
+
|
|
21949
|
+
/**
|
|
21950
|
+
* Theme Logger
|
|
21951
|
+
*
|
|
21952
|
+
* Centralized logging for the theme system.
|
|
21953
|
+
* Replaces console statements with structured logging.
|
|
21954
|
+
*/
|
|
21955
|
+
class ThemeLogger {
|
|
21956
|
+
constructor(config = {}) {
|
|
21957
|
+
this.config = {
|
|
21958
|
+
level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
|
|
21959
|
+
enableConsole: config.enableConsole ?? !0,
|
|
21960
|
+
onError: config.onError,
|
|
21961
|
+
onWarn: config.onWarn,
|
|
21962
|
+
onInfo: config.onInfo,
|
|
21963
|
+
onDebug: config.onDebug
|
|
21964
|
+
};
|
|
21965
|
+
}
|
|
21966
|
+
/**
|
|
21967
|
+
* Log an error
|
|
21968
|
+
*/ error(message, error, context) {
|
|
21969
|
+
if (this.config.level < LogLevel.ERROR) return;
|
|
21970
|
+
const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
|
|
21971
|
+
this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
|
|
21972
|
+
error: errorObj,
|
|
21973
|
+
context: {
|
|
21974
|
+
...context,
|
|
21975
|
+
...themeError.context
|
|
21976
|
+
},
|
|
21977
|
+
code: themeError.code
|
|
21978
|
+
}), this.config.onError?.(themeError, context);
|
|
21979
|
+
}
|
|
21980
|
+
/**
|
|
21981
|
+
* Log a warning
|
|
21982
|
+
*/ warn(message, context) {
|
|
21983
|
+
this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
|
|
21984
|
+
this.config.onWarn?.(message, context));
|
|
21985
|
+
}
|
|
21986
|
+
/**
|
|
21987
|
+
* Log an info message
|
|
21988
|
+
*/ info(message, context) {
|
|
21989
|
+
this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
|
|
21990
|
+
this.config.onInfo?.(message, context));
|
|
21991
|
+
}
|
|
21992
|
+
/**
|
|
21993
|
+
* Log a debug message
|
|
21994
|
+
*/ debug(message, context) {
|
|
21995
|
+
this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
|
|
21996
|
+
}
|
|
21997
|
+
}
|
|
21998
|
+
|
|
21999
|
+
/**
|
|
22000
|
+
* Default logger instance
|
|
22001
|
+
*/ let defaultLogger = null;
|
|
22002
|
+
|
|
22003
|
+
/**
|
|
22004
|
+
* Get or create default logger
|
|
22005
|
+
*/ function getLogger() {
|
|
22006
|
+
return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
|
|
22007
|
+
}
|
|
22008
|
+
|
|
22009
|
+
/**
|
|
22010
|
+
* Check if code is running in a browser environment
|
|
22011
|
+
*/ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), sanitizePath = path => path.replace(/[<>"']/g, "").replace(/\.\./g, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "") // Trim leading/trailing slashes
|
|
22012
|
+
, buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
|
|
22013
|
+
// Validate theme name to prevent path injection
|
|
22014
|
+
if (!isValidThemeName(themeName)) throw new ThemeError(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens (e.g., "my-theme").`, ThemeErrorCode.INVALID_THEME_NAME, {
|
|
22015
|
+
themeName: themeName,
|
|
22016
|
+
pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/
|
|
22017
|
+
});
|
|
22018
|
+
const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
|
|
22019
|
+
return cdnPath ? `${sanitizePath(cdnPath)}/${fileName}` : `${sanitizePath(basePath)}/${fileName.replace(/^\//, "")}`;
|
|
22020
|
+
// Sanitize basePath to prevent path injection
|
|
22021
|
+
}, applyThemeAttributes = (dataAttribute, themeName) => {
|
|
22022
|
+
isServer() || (
|
|
22023
|
+
// Set data attribute on body (with null check)
|
|
22024
|
+
document.body && document.body.setAttribute(dataAttribute, themeName),
|
|
22025
|
+
// Also set on documentElement for broader compatibility
|
|
22026
|
+
document.documentElement.setAttribute(dataAttribute, themeName));
|
|
22027
|
+
}, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName), createLocalStorageAdapter = () => ({
|
|
22028
|
+
getItem: key => {
|
|
22029
|
+
if (isServer()) return null;
|
|
22030
|
+
try {
|
|
22031
|
+
return localStorage.getItem(key);
|
|
22032
|
+
} catch {
|
|
22033
|
+
return null;
|
|
22034
|
+
}
|
|
22035
|
+
},
|
|
22036
|
+
setItem: (key, value) => {
|
|
22037
|
+
if (!isServer()) try {
|
|
22038
|
+
localStorage.setItem(key, value);
|
|
22039
|
+
} catch {
|
|
22040
|
+
// Silently fail if localStorage is not available
|
|
22041
|
+
}
|
|
22042
|
+
},
|
|
21430
22043
|
removeItem: key => {
|
|
21431
22044
|
if (!isServer()) try {
|
|
21432
22045
|
localStorage.removeItem(key);
|
|
@@ -21479,105 +22092,427 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
21479
22092
|
}))
|
|
21480
22093
|
});
|
|
21481
22094
|
|
|
22095
|
+
// ============================================================================
|
|
22096
|
+
// Theme Mode Switching
|
|
22097
|
+
// ============================================================================
|
|
21482
22098
|
/**
|
|
21483
|
-
*
|
|
22099
|
+
* Switch between light and dark themes
|
|
21484
22100
|
*
|
|
21485
|
-
*
|
|
21486
|
-
*
|
|
21487
|
-
|
|
22101
|
+
* Automatically toggles a class on the root element and persists the choice.
|
|
22102
|
+
*
|
|
22103
|
+
* @param mode - Theme mode ('light', 'dark', or 'system')
|
|
22104
|
+
* @param options - Configuration options
|
|
22105
|
+
*
|
|
22106
|
+
* @example
|
|
22107
|
+
* ```typescript
|
|
22108
|
+
* import { switchTheme } from '@shohojdhara/atomix/theme/utils';
|
|
22109
|
+
*
|
|
22110
|
+
* // Switch to dark mode
|
|
22111
|
+
* switchTheme('dark');
|
|
22112
|
+
*
|
|
22113
|
+
* // Toggle between light/dark
|
|
22114
|
+
* const current = getCurrentTheme();
|
|
22115
|
+
* switchTheme(current === 'dark' ? 'light' : 'dark');
|
|
22116
|
+
* ```
|
|
22117
|
+
*/ function switchTheme(mode, options = {}) {
|
|
22118
|
+
const {selector: selector = ":root", storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, resolvedMode = "system" === mode ? getSystemTheme() : mode, root = ":root" === selector ? document.documentElement : document.querySelector(selector);
|
|
22119
|
+
// Determine actual mode (resolve 'system')
|
|
22120
|
+
if (root) {
|
|
22121
|
+
// Add transition class if enabled
|
|
22122
|
+
if (enableTransition) {
|
|
22123
|
+
const htmlRoot = root;
|
|
22124
|
+
htmlRoot.style.transition = `all ${transitionDuration}ms ease-in-out`,
|
|
22125
|
+
// Remove transition after it completes
|
|
22126
|
+
setTimeout((() => {
|
|
22127
|
+
htmlRoot.style.transition = "";
|
|
22128
|
+
}), transitionDuration);
|
|
22129
|
+
}
|
|
22130
|
+
// Apply theme class
|
|
22131
|
+
root.classList.remove("atomix-theme-light", "atomix-theme-dark"), root.classList.add(`atomix-theme-${resolvedMode}`),
|
|
22132
|
+
// Set data attribute for CSS selectors
|
|
22133
|
+
root.setAttribute("data-theme", resolvedMode),
|
|
22134
|
+
// Persist choice
|
|
22135
|
+
persistTheme(resolvedMode, {
|
|
22136
|
+
storageKey: storageKey
|
|
22137
|
+
}),
|
|
22138
|
+
// Dispatch custom event for listeners
|
|
22139
|
+
window.dispatchEvent(new CustomEvent("atomix-theme-change", {
|
|
22140
|
+
detail: {
|
|
22141
|
+
mode: resolvedMode
|
|
22142
|
+
}
|
|
22143
|
+
}));
|
|
22144
|
+
}
|
|
22145
|
+
}
|
|
22146
|
+
|
|
22147
|
+
/**
|
|
22148
|
+
* Toggle between light and dark themes
|
|
22149
|
+
*
|
|
22150
|
+
* @param options - Configuration options
|
|
22151
|
+
* @returns The new theme mode
|
|
22152
|
+
*
|
|
22153
|
+
* @example
|
|
22154
|
+
* ```typescript
|
|
22155
|
+
* const newMode = toggleTheme();
|
|
22156
|
+
* console.log('Switched to:', newMode);
|
|
22157
|
+
* ```
|
|
22158
|
+
*/ function toggleTheme(options = {}) {
|
|
22159
|
+
const next = "dark" === getCurrentTheme(options.storageKey) ? "light" : "dark";
|
|
22160
|
+
return switchTheme(next, options), next;
|
|
22161
|
+
}
|
|
22162
|
+
|
|
22163
|
+
/**
|
|
22164
|
+
* Get current theme mode
|
|
22165
|
+
*
|
|
22166
|
+
* @param storageKey - Storage key (default: 'atomix-theme')
|
|
22167
|
+
* @returns Current theme mode or 'light' if not set
|
|
22168
|
+
*/ function getCurrentTheme(storageKey = "atomix-theme") {
|
|
22169
|
+
return "undefined" == typeof window ? "light" : localStorage.getItem(storageKey) || "light";
|
|
22170
|
+
}
|
|
22171
|
+
|
|
22172
|
+
/**
|
|
22173
|
+
* Get system theme preference
|
|
22174
|
+
*
|
|
22175
|
+
* @returns 'dark' if system prefers dark mode, 'light' otherwise
|
|
22176
|
+
*/ function getSystemTheme() {
|
|
22177
|
+
return "undefined" == typeof window ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
22178
|
+
}
|
|
22179
|
+
|
|
22180
|
+
/**
|
|
22181
|
+
* Initialize theme based on saved preference or system preference
|
|
22182
|
+
*
|
|
22183
|
+
* Call this once at app startup.
|
|
22184
|
+
*
|
|
22185
|
+
* @param options - Configuration options
|
|
22186
|
+
* @returns The initialized theme mode
|
|
22187
|
+
*
|
|
22188
|
+
* @example
|
|
22189
|
+
* ```typescript
|
|
22190
|
+
* // In your app entry point
|
|
22191
|
+
* import { initializeTheme } from '@shohojdhara/atomix/theme/utils';
|
|
22192
|
+
*
|
|
22193
|
+
* const theme = initializeTheme();
|
|
22194
|
+
* console.log('Theme initialized:', theme);
|
|
22195
|
+
* ```
|
|
22196
|
+
*/ function initializeTheme(options = {}) {
|
|
22197
|
+
const saved = getCurrentTheme(options.storageKey);
|
|
22198
|
+
// If no saved preference, use system preference
|
|
22199
|
+
if (!saved || "system" === saved) {
|
|
22200
|
+
const system = getSystemTheme();
|
|
22201
|
+
return switchTheme(system, options), system;
|
|
22202
|
+
}
|
|
22203
|
+
// Use saved preference
|
|
22204
|
+
return switchTheme(saved, options), saved;
|
|
22205
|
+
}
|
|
22206
|
+
|
|
22207
|
+
/**
|
|
22208
|
+
* Listen for system theme changes
|
|
22209
|
+
*
|
|
22210
|
+
* @param callback - Function to call when system theme changes
|
|
22211
|
+
* @returns Cleanup function to stop listening
|
|
22212
|
+
*
|
|
22213
|
+
* @example
|
|
22214
|
+
* ```typescript
|
|
22215
|
+
* const cleanup = listenToSystemTheme((mode) => {
|
|
22216
|
+
* console.log('System theme changed to:', mode);
|
|
22217
|
+
* switchTheme(mode);
|
|
22218
|
+
* });
|
|
22219
|
+
*
|
|
22220
|
+
* // Later, when component unmounts
|
|
22221
|
+
* cleanup();
|
|
22222
|
+
* ```
|
|
22223
|
+
*/ function listenToSystemTheme(callback) {
|
|
22224
|
+
if ("undefined" == typeof window) return () => {};
|
|
22225
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"), handler = e => {
|
|
22226
|
+
callback(e.matches ? "dark" : "light");
|
|
22227
|
+
};
|
|
22228
|
+
// Modern browsers
|
|
22229
|
+
return mediaQuery.addEventListener ? (mediaQuery.addEventListener("change", handler),
|
|
22230
|
+
() => mediaQuery.removeEventListener("change", handler)) : (
|
|
22231
|
+
// Fallback for older browsers
|
|
22232
|
+
mediaQuery.addListener(handler), () => mediaQuery.removeListener(handler));
|
|
22233
|
+
}
|
|
22234
|
+
|
|
21488
22235
|
// ============================================================================
|
|
21489
|
-
//
|
|
22236
|
+
// Theme Persistence
|
|
21490
22237
|
// ============================================================================
|
|
21491
22238
|
/**
|
|
21492
|
-
*
|
|
22239
|
+
* Save theme preference to storage
|
|
22240
|
+
*
|
|
22241
|
+
* @param mode - Theme mode to save
|
|
22242
|
+
* @param options - Persistence options
|
|
22243
|
+
*/ function persistTheme(mode, options = {}) {
|
|
22244
|
+
if ("undefined" == typeof window) return;
|
|
22245
|
+
const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
|
|
22246
|
+
("localStorage" === storageType ? localStorage : sessionStorage).setItem(storageKey, mode);
|
|
22247
|
+
}
|
|
22248
|
+
|
|
22249
|
+
/**
|
|
22250
|
+
* Clear saved theme preference
|
|
22251
|
+
*
|
|
22252
|
+
* @param options - Persistence options
|
|
22253
|
+
*/ function clearThemePreference(options = {}) {
|
|
22254
|
+
if ("undefined" == typeof window) return;
|
|
22255
|
+
const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
|
|
22256
|
+
("localStorage" === storageType ? localStorage : sessionStorage).removeItem(storageKey);
|
|
22257
|
+
}
|
|
22258
|
+
|
|
22259
|
+
// ============================================================================
|
|
22260
|
+
// Theme Tokens Manipulation
|
|
22261
|
+
// ============================================================================
|
|
22262
|
+
/**
|
|
22263
|
+
* Merge multiple token sets
|
|
22264
|
+
*
|
|
22265
|
+
* Deep merges token objects, with later tokens overriding earlier ones.
|
|
22266
|
+
*
|
|
22267
|
+
* @param tokens - Token objects to merge
|
|
22268
|
+
* @returns Merged tokens
|
|
22269
|
+
*
|
|
22270
|
+
* @example
|
|
22271
|
+
* ```typescript
|
|
22272
|
+
* const merged = mergeTokens(
|
|
22273
|
+
* baseTokens,
|
|
22274
|
+
* { colors: { primary: { main: '#custom' } } }
|
|
22275
|
+
* );
|
|
22276
|
+
* ```
|
|
22277
|
+
*/ function mergeTokens(...tokens) {
|
|
22278
|
+
return _reduceInstanceProperty(tokens).call(tokens, ((acc, current) => deepMerge(acc, current)), {});
|
|
22279
|
+
}
|
|
22280
|
+
|
|
22281
|
+
/**
|
|
22282
|
+
* Override specific tokens
|
|
22283
|
+
*
|
|
22284
|
+
* Creates a new token object with specific overrides.
|
|
22285
|
+
*
|
|
22286
|
+
* @param base - Base tokens
|
|
22287
|
+
* @param overrides - Tokens to override
|
|
22288
|
+
* @returns New tokens with overrides applied
|
|
22289
|
+
*
|
|
22290
|
+
* @example
|
|
22291
|
+
* ```typescript
|
|
22292
|
+
* const customized = overrideTokens(defaultTokens, {
|
|
22293
|
+
* colors: {
|
|
22294
|
+
* primary: { main: '#ff0000' }
|
|
22295
|
+
* }
|
|
22296
|
+
* });
|
|
22297
|
+
* ```
|
|
22298
|
+
*/ function overrideTokens(base, overrides) {
|
|
22299
|
+
return deepMerge({
|
|
22300
|
+
...base
|
|
22301
|
+
}, overrides);
|
|
22302
|
+
}
|
|
22303
|
+
|
|
22304
|
+
/**
|
|
22305
|
+
* Pick specific token categories
|
|
22306
|
+
*
|
|
22307
|
+
* Extracts only the specified categories from tokens.
|
|
22308
|
+
*
|
|
22309
|
+
* @param tokens - Source tokens
|
|
22310
|
+
* @param categories - Categories to pick
|
|
22311
|
+
* @returns Tokens with only selected categories
|
|
22312
|
+
*
|
|
22313
|
+
* @example
|
|
22314
|
+
* ```typescript
|
|
22315
|
+
* const colorTokens = pickTokens(allTokens, ['colors']);
|
|
22316
|
+
* ```
|
|
22317
|
+
*/ function pickTokens(tokens, categories) {
|
|
22318
|
+
const result = {};
|
|
22319
|
+
return categories.forEach((category => {
|
|
22320
|
+
tokens[category] && (result[category] = tokens[category]);
|
|
22321
|
+
})), result;
|
|
22322
|
+
}
|
|
22323
|
+
|
|
22324
|
+
/**
|
|
22325
|
+
* Omit specific token categories
|
|
22326
|
+
*
|
|
22327
|
+
* Removes specified categories from tokens.
|
|
22328
|
+
*
|
|
22329
|
+
* @param tokens - Source tokens
|
|
22330
|
+
* @param categories - Categories to omit
|
|
22331
|
+
* @returns Tokens without omitted categories
|
|
22332
|
+
*
|
|
22333
|
+
* @example
|
|
22334
|
+
* ```typescript
|
|
22335
|
+
* const withoutColors = omitTokens(allTokens, ['colors']);
|
|
22336
|
+
* ```
|
|
22337
|
+
*/ function omitTokens(tokens, categories) {
|
|
22338
|
+
const result = {
|
|
22339
|
+
...tokens
|
|
22340
|
+
};
|
|
22341
|
+
return categories.forEach((category => {
|
|
22342
|
+
delete result[category];
|
|
22343
|
+
})), result;
|
|
22344
|
+
}
|
|
22345
|
+
|
|
22346
|
+
// ============================================================================
|
|
22347
|
+
// Color Utilities
|
|
22348
|
+
// ============================================================================
|
|
22349
|
+
/**
|
|
22350
|
+
* Convert hex color to RGB
|
|
22351
|
+
*
|
|
22352
|
+
* @param hex - Hex color (with or without #)
|
|
22353
|
+
* @returns RGB object { r, g, b }
|
|
21493
22354
|
*/ function hexToRgb$1(hex) {
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
22355
|
+
// Validate
|
|
22356
|
+
if (
|
|
22357
|
+
// Remove # if present
|
|
22358
|
+
// Handle shorthand hex
|
|
22359
|
+
3 === (hex = hex.replace(/^#/, "")).length && (hex = hex.split("").map((c => c + c)).join("")),
|
|
22360
|
+
6 !== hex.length) return null;
|
|
22361
|
+
const num = parseInt(hex, 16);
|
|
22362
|
+
return {
|
|
22363
|
+
r: num >> 16 & 255,
|
|
22364
|
+
g: num >> 8 & 255,
|
|
22365
|
+
b: 255 & num
|
|
22366
|
+
};
|
|
21500
22367
|
}
|
|
21501
22368
|
|
|
21502
22369
|
/**
|
|
21503
|
-
* Convert RGB to hex
|
|
22370
|
+
* Convert RGB to hex
|
|
22371
|
+
*
|
|
22372
|
+
* @param r - Red (0-255)
|
|
22373
|
+
* @param g - Green (0-255)
|
|
22374
|
+
* @param b - Blue (0-255)
|
|
22375
|
+
* @returns Hex color with #
|
|
21504
22376
|
*/ function rgbToHex(r, g, b) {
|
|
21505
|
-
|
|
21506
|
-
|
|
22377
|
+
return "#" + [ r, g, b ].map((x => {
|
|
22378
|
+
const hex = x.toString(16);
|
|
22379
|
+
return 1 === hex.length ? "0" + hex : hex;
|
|
22380
|
+
})).join("");
|
|
21507
22381
|
}
|
|
21508
22382
|
|
|
21509
22383
|
/**
|
|
21510
|
-
* Calculate
|
|
21511
|
-
*
|
|
21512
|
-
|
|
21513
|
-
|
|
22384
|
+
* Calculate luminance of a color
|
|
22385
|
+
*
|
|
22386
|
+
* Used for determining contrast ratios.
|
|
22387
|
+
*
|
|
22388
|
+
* @param hex - Hex color
|
|
22389
|
+
* @returns Luminance value (0-1)
|
|
22390
|
+
*/ function getLuminance(hex) {
|
|
22391
|
+
const rgb = hexToRgb$1(hex);
|
|
21514
22392
|
if (!rgb) return 0;
|
|
21515
|
-
const
|
|
21516
|
-
|
|
21517
|
-
return val <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
|
|
21518
|
-
}));
|
|
21519
|
-
return .2126 * (rs ?? 0) + .7152 * (gs ?? 0) + .0722 * (bs ?? 0);
|
|
22393
|
+
const [r, g, b] = [ rgb.r, rgb.g, rgb.b ].map((v => (v /= 255) <= .03928 ? v / 12.92 : Math.pow((v + .055) / 1.055, 2.4)));
|
|
22394
|
+
return .2126 * (r ?? 0) + .7152 * (g ?? 0) + .0722 * (b ?? 0);
|
|
21520
22395
|
}
|
|
21521
22396
|
|
|
21522
22397
|
/**
|
|
21523
22398
|
* Calculate contrast ratio between two colors
|
|
21524
|
-
|
|
21525
|
-
|
|
21526
|
-
|
|
22399
|
+
*
|
|
22400
|
+
* @param hex1 - First hex color
|
|
22401
|
+
* @param hex2 - Second hex color
|
|
22402
|
+
* @returns Contrast ratio (1-21)
|
|
22403
|
+
*/ function getContrastRatio(hex1, hex2) {
|
|
22404
|
+
const lum1 = getLuminance(hex1), lum2 = getLuminance(hex2);
|
|
22405
|
+
return (Math.max(lum1, lum2) + .05) / (Math.min(lum1, lum2) + .05);
|
|
21527
22406
|
}
|
|
21528
22407
|
|
|
21529
22408
|
/**
|
|
21530
|
-
*
|
|
21531
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
22409
|
+
* Check if text color passes WCAG AA standard
|
|
22410
|
+
*
|
|
22411
|
+
* @param textColor - Text color hex
|
|
22412
|
+
* @param backgroundColor - Background color hex
|
|
22413
|
+
* @param size - Font size ('small' or 'large')
|
|
22414
|
+
* @returns true if passes WCAG AA
|
|
22415
|
+
*/ function isAccessible(textColor, backgroundColor, size = "small") {
|
|
22416
|
+
return getContrastRatio(textColor, backgroundColor) >= ("large" === size ? 3 : 4.5);
|
|
21534
22417
|
}
|
|
21535
22418
|
|
|
21536
22419
|
/**
|
|
21537
|
-
*
|
|
22420
|
+
* Get appropriate text color (black or white) for a background
|
|
21538
22421
|
*
|
|
21539
|
-
* @param
|
|
21540
|
-
* @param
|
|
22422
|
+
* @param backgroundColor - Background hex color
|
|
22423
|
+
* @param threshold - Contrast threshold (default: 3)
|
|
22424
|
+
* @returns '#000000' or '#FFFFFF'
|
|
22425
|
+
*/ function getContrastText(backgroundColor, threshold = 3) {
|
|
22426
|
+
return getContrastRatio(backgroundColor, "#FFFFFF") >= threshold ? "#FFFFFF" : "#000000";
|
|
22427
|
+
}
|
|
22428
|
+
|
|
22429
|
+
/**
|
|
22430
|
+
* Lighten a color
|
|
22431
|
+
*
|
|
22432
|
+
* @param hex - Base hex color
|
|
22433
|
+
* @param amount - Amount to lighten (0-1)
|
|
21541
22434
|
* @returns Lightened hex color
|
|
21542
|
-
*/ function lighten(
|
|
21543
|
-
const rgb = hexToRgb$1(
|
|
21544
|
-
if (!rgb) return
|
|
21545
|
-
|
|
21546
|
-
|
|
22435
|
+
*/ function lighten(hex, amount = 0) {
|
|
22436
|
+
const rgb = hexToRgb$1(hex);
|
|
22437
|
+
if (!rgb) return hex;
|
|
22438
|
+
// Use amount directly as factor (0-1)
|
|
22439
|
+
const factor = Math.max(0, Math.min(1, amount)), r = Math.round(rgb.r + (255 - rgb.r) * factor), g = Math.round(rgb.g + (255 - rgb.g) * factor), b = Math.round(rgb.b + (255 - rgb.b) * factor);
|
|
22440
|
+
return rgbToHex(Math.min(255, r), Math.min(255, g), Math.min(255, b));
|
|
21547
22441
|
}
|
|
21548
22442
|
|
|
21549
22443
|
/**
|
|
21550
|
-
* Darken a color
|
|
22444
|
+
* Darken a color
|
|
21551
22445
|
*
|
|
21552
|
-
* @param
|
|
21553
|
-
* @param amount - Amount to darken (0-1)
|
|
22446
|
+
* @param hex - Base hex color
|
|
22447
|
+
* @param amount - Amount to darken (0-1)
|
|
21554
22448
|
* @returns Darkened hex color
|
|
21555
|
-
*/ function darken(
|
|
21556
|
-
const rgb = hexToRgb$1(
|
|
21557
|
-
if (!rgb) return
|
|
21558
|
-
|
|
21559
|
-
|
|
22449
|
+
*/ function darken(hex, amount = 0) {
|
|
22450
|
+
const rgb = hexToRgb$1(hex);
|
|
22451
|
+
if (!rgb) return hex;
|
|
22452
|
+
// Use amount directly as factor (0-1)
|
|
22453
|
+
const factor = Math.max(0, Math.min(1, amount)), r = Math.round(rgb.r * (1 - factor)), g = Math.round(rgb.g * (1 - factor)), b = Math.round(rgb.b * (1 - factor));
|
|
22454
|
+
return rgbToHex(Math.max(0, r), Math.max(0, g), Math.max(0, b));
|
|
21560
22455
|
}
|
|
21561
22456
|
|
|
21562
22457
|
/**
|
|
21563
|
-
* Add alpha
|
|
22458
|
+
* Add alpha to a color
|
|
21564
22459
|
*
|
|
21565
|
-
* @param
|
|
22460
|
+
* @param hex - Hex color
|
|
21566
22461
|
* @param opacity - Opacity value (0-1)
|
|
21567
22462
|
* @returns RGBA color string
|
|
21568
|
-
*/ function alpha(
|
|
21569
|
-
const rgb = hexToRgb$1(
|
|
21570
|
-
if (!rgb) return
|
|
21571
|
-
const
|
|
21572
|
-
return `rgba(${r}, ${g}, ${b}, ${
|
|
22463
|
+
*/ function alpha(hex, opacity) {
|
|
22464
|
+
const rgb = hexToRgb$1(hex);
|
|
22465
|
+
if (!rgb) return hex;
|
|
22466
|
+
const validOpacity = Math.max(0, Math.min(1, opacity));
|
|
22467
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${validOpacity})`;
|
|
21573
22468
|
}
|
|
21574
22469
|
|
|
21575
22470
|
/**
|
|
21576
22471
|
* Emphasize a color (lighten if dark, darken if light)
|
|
21577
22472
|
*
|
|
21578
|
-
* @param
|
|
21579
|
-
* @param
|
|
22473
|
+
* @param hex - Hex color
|
|
22474
|
+
* @param amount - Amount to emphasize (0-1)
|
|
21580
22475
|
* @returns Emphasized hex color
|
|
22476
|
+
*/ function emphasize(hex, amount = .15) {
|
|
22477
|
+
return getLuminance(hex) > .5 ? darken(hex, amount) : lighten(hex, amount);
|
|
22478
|
+
}
|
|
22479
|
+
|
|
22480
|
+
/**
|
|
22481
|
+
* Create a spacing utility
|
|
22482
|
+
*
|
|
22483
|
+
* @param spacingInput - Spacing configuration
|
|
22484
|
+
* @returns Spacing function
|
|
22485
|
+
*/ function createSpacing(spacingInput = 4) {
|
|
22486
|
+
return (...values) => 0 === values.length ? "0px" : "function" == typeof spacingInput ? spacingInput(...values) : values.map((value => {
|
|
22487
|
+
if ("number" == typeof spacingInput) return value * spacingInput + "px";
|
|
22488
|
+
if (Array.isArray(spacingInput)) {
|
|
22489
|
+
const scaled = spacingInput[value];
|
|
22490
|
+
return "number" == typeof scaled ? `${scaled}px` : `${value}px`;
|
|
22491
|
+
}
|
|
22492
|
+
return `${value}px`;
|
|
22493
|
+
})).join(" ");
|
|
22494
|
+
}
|
|
22495
|
+
|
|
22496
|
+
/**
|
|
22497
|
+
* CSS Variable Generator
|
|
22498
|
+
*
|
|
22499
|
+
* Generates CSS custom properties from theme objects and injects them into the DOM.
|
|
22500
|
+
*
|
|
22501
|
+
* **Token Naming Alignment:**
|
|
22502
|
+
* This generator produces CSS variables that match the SCSS token naming pattern exactly:
|
|
22503
|
+
* - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
|
|
22504
|
+
* - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
|
|
22505
|
+
* - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
|
|
22506
|
+
* - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
|
|
22507
|
+
*
|
|
22508
|
+
* All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
|
|
22509
|
+
* This ensures compatibility between SCSS themes and JavaScript themes.
|
|
22510
|
+
*
|
|
22511
|
+
* @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
|
|
22512
|
+
*/
|
|
22513
|
+
/**
|
|
22514
|
+
* Convert a nested object to flat CSS variable declarations
|
|
22515
|
+
* Uses iterative approach for better performance with large objects
|
|
21581
22516
|
*/
|
|
21582
22517
|
/**
|
|
21583
22518
|
* Generate a color scale from a base color (1-10 steps)
|
|
@@ -21645,18 +22580,7 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
21645
22580
|
color.dark && (vars[`${prefix}-${key}-hover`] = color.dark),
|
|
21646
22581
|
// Generate semantic color variants (matches SCSS patterns)
|
|
21647
22582
|
// Text emphasis: emphasized version of the color for text (--atomix-primary-text-emphasis)
|
|
21648
|
-
vars[`${prefix}-${key}-text-emphasis`] =
|
|
21649
|
-
return getLuminance(color) > .5 ? darken(color, coefficient) : lighten(color, coefficient);
|
|
21650
|
-
}
|
|
21651
|
-
// ============================================================================
|
|
21652
|
-
// Spacing Utilities
|
|
21653
|
-
// ============================================================================
|
|
21654
|
-
/**
|
|
21655
|
-
* Create a spacing function from various input types
|
|
21656
|
-
*
|
|
21657
|
-
* @param spacingInput - Spacing configuration (number, array, or function), default 4
|
|
21658
|
-
* @returns Spacing function
|
|
21659
|
-
*/ (color.main, .15),
|
|
22583
|
+
vars[`${prefix}-${key}-text-emphasis`] = emphasize(color.main, .15),
|
|
21660
22584
|
// Background subtle: very light version for backgrounds (--atomix-primary-bg-subtle)
|
|
21661
22585
|
vars[`${prefix}-${key}-bg-subtle`] = alpha(color.main, .1),
|
|
21662
22586
|
// Border subtle: light version for borders (--atomix-primary-border-subtle)
|
|
@@ -22001,29 +22925,7 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
22001
22925
|
return vars[`${prefix}-focus-ring-width`] = "3px", vars[`${prefix}-focus-ring-offset`] = "2px",
|
|
22002
22926
|
vars[`${prefix}-focus-ring-opacity`] = "0.25", vars;
|
|
22003
22927
|
}(theme.palette, prefix)), theme.custom && Object.keys(theme.custom).length > 0) {
|
|
22004
|
-
const customVars =
|
|
22005
|
-
/**
|
|
22006
|
-
* CSS Variable Generator
|
|
22007
|
-
*
|
|
22008
|
-
* Generates CSS custom properties from theme objects and injects them into the DOM.
|
|
22009
|
-
*
|
|
22010
|
-
* **Token Naming Alignment:**
|
|
22011
|
-
* This generator produces CSS variables that match the SCSS token naming pattern exactly:
|
|
22012
|
-
* - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
|
|
22013
|
-
* - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
|
|
22014
|
-
* - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
|
|
22015
|
-
* - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
|
|
22016
|
-
*
|
|
22017
|
-
* All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
|
|
22018
|
-
* This ensures compatibility between SCSS themes and JavaScript themes.
|
|
22019
|
-
*
|
|
22020
|
-
* @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
|
|
22021
|
-
*/
|
|
22022
|
-
/**
|
|
22023
|
-
* Convert a nested object to flat CSS variable declarations
|
|
22024
|
-
* Uses iterative approach for better performance with large objects
|
|
22025
|
-
*/
|
|
22026
|
-
function(obj, prefix = "", result = {}) {
|
|
22928
|
+
const customVars = function(obj, prefix = "", result = {}) {
|
|
22027
22929
|
// Use iterative approach with stack to avoid deep recursion
|
|
22028
22930
|
const stack = [ {
|
|
22029
22931
|
obj: obj,
|
|
@@ -22477,19 +23379,29 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
|
|
|
22477
23379
|
// Check storage first
|
|
22478
23380
|
if (enablePersistence && storageAdapter.isAvailable()) {
|
|
22479
23381
|
const stored = storageAdapter.getItem(storageKey);
|
|
22480
|
-
if (stored)
|
|
23382
|
+
if (stored) {
|
|
23383
|
+
// If it looks like a JSON object, parse it
|
|
23384
|
+
if (stored.trim().startsWith("{")) try {
|
|
23385
|
+
return JSON.parse(stored);
|
|
23386
|
+
} catch (e) {
|
|
23387
|
+
return logger.error("Failed to parse stored theme tokens", e), stored;
|
|
23388
|
+
}
|
|
23389
|
+
return stored;
|
|
23390
|
+
}
|
|
22481
23391
|
}
|
|
22482
23392
|
// If defaultTheme is provided, use it
|
|
22483
23393
|
return null != defaultTheme ? defaultTheme : "default";
|
|
22484
23394
|
// Default fallback
|
|
22485
23395
|
}), [ defaultTheme, enablePersistence, storageKey, storageAdapter ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
|
|
22486
|
-
//
|
|
22487
|
-
if (
|
|
23396
|
+
// 1. Check if initialDefaultTheme (from storage) is an object
|
|
23397
|
+
if (initialDefaultTheme && "string" != typeof initialDefaultTheme) {
|
|
23398
|
+
const {tokens: tokens, validation: validation} = validateAndMergeTokens(initialDefaultTheme);
|
|
23399
|
+
if (validation.valid) return tokens;
|
|
23400
|
+
}
|
|
23401
|
+
// 2. Check if defaultTheme prop is an object
|
|
23402
|
+
if (defaultTheme && "string" != typeof defaultTheme) {
|
|
22488
23403
|
const {tokens: tokens, validation: validation} = validateAndMergeTokens(defaultTheme);
|
|
22489
|
-
|
|
22490
|
-
errors: validation.errors,
|
|
22491
|
-
warnings: validation.warnings
|
|
22492
|
-
}), createTokens({}));
|
|
23404
|
+
if (validation.valid) return tokens;
|
|
22493
23405
|
}
|
|
22494
23406
|
return null;
|
|
22495
23407
|
})), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
|
|
@@ -22501,10 +23413,14 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
|
|
|
22501
23413
|
React.useEffect((() => {
|
|
22502
23414
|
isServer() || applyThemeAttributes(String(currentTheme), dataAttribute);
|
|
22503
23415
|
}), [ currentTheme, dataAttribute ]),
|
|
22504
|
-
// Handle
|
|
23416
|
+
// Handle persistence
|
|
22505
23417
|
React.useEffect((() => {
|
|
22506
|
-
enablePersistence && storageAdapter.isAvailable() &&
|
|
22507
|
-
|
|
23418
|
+
enablePersistence && storageAdapter.isAvailable() && ("tokens-theme" === currentTheme ?
|
|
23419
|
+
// Only persist if we have actual tokens to store
|
|
23420
|
+
activeTokens && storageAdapter.setItem(storageKey, JSON.stringify(activeTokens)) :
|
|
23421
|
+
// Persist named theme string
|
|
23422
|
+
storageAdapter.setItem(storageKey, String(currentTheme)));
|
|
23423
|
+
}), [ currentTheme, activeTokens, enablePersistence, storageKey, storageAdapter ]),
|
|
22508
23424
|
// Cleanup: Remove completed promises and abort controllers on unmount
|
|
22509
23425
|
React.useEffect((() => () => {
|
|
22510
23426
|
// Cancel any in-flight theme loads
|
|
@@ -22645,20 +23561,21 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
|
|
|
22645
23561
|
setIsLoading(!1);
|
|
22646
23562
|
}
|
|
22647
23563
|
}
|
|
22648
|
-
}), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = React.useMemo((() => ({})), []), availableThemes = React.useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
|
|
23564
|
+
}), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), updateTheme = React.useCallback((async (sectionOrTokens, values) => setTheme("string" == typeof sectionOrTokens && values ? values : sectionOrTokens)), [ setTheme ]), themeManager = React.useMemo((() => ({})), []), availableThemes = React.useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
|
|
22649
23565
|
...metadata,
|
|
22650
23566
|
name: name
|
|
22651
23567
|
})))), [ themes ]), contextValue = React.useMemo((() => ({
|
|
22652
23568
|
theme: currentTheme,
|
|
22653
23569
|
activeTokens: activeTokens,
|
|
22654
23570
|
setTheme: setTheme,
|
|
23571
|
+
updateTheme: updateTheme,
|
|
22655
23572
|
availableThemes: availableThemes,
|
|
22656
23573
|
isLoading: isLoading,
|
|
22657
23574
|
error: error,
|
|
22658
23575
|
isThemeLoaded: isThemeLoaded,
|
|
22659
23576
|
preloadTheme: preloadTheme,
|
|
22660
23577
|
themeManager: themeManager
|
|
22661
|
-
})), [ currentTheme, activeTokens, setTheme, availableThemes,
|
|
23578
|
+
})), [ currentTheme, activeTokens, setTheme, updateTheme, availableThemes,
|
|
22662
23579
|
// Use memoized value
|
|
22663
23580
|
isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
|
|
22664
23581
|
// Check if theme is loaded
|
|
@@ -22712,6 +23629,7 @@ function useTheme() {
|
|
|
22712
23629
|
theme: context.theme,
|
|
22713
23630
|
activeTokens: context.activeTokens,
|
|
22714
23631
|
setTheme: context.setTheme,
|
|
23632
|
+
updateTheme: context.updateTheme,
|
|
22715
23633
|
availableThemes: context.availableThemes,
|
|
22716
23634
|
isLoading: context.isLoading,
|
|
22717
23635
|
error: context.error,
|
|
@@ -22947,6 +23865,389 @@ function useThemeTokens() {
|
|
|
22947
23865
|
}
|
|
22948
23866
|
}
|
|
22949
23867
|
|
|
23868
|
+
/**
|
|
23869
|
+
* useThemeSwitcher Hook
|
|
23870
|
+
*
|
|
23871
|
+
* React hook for managing theme switching with persistence and system preference detection.
|
|
23872
|
+
* Provides an easy-to-use API for dark/light mode toggling.
|
|
23873
|
+
*
|
|
23874
|
+
* @example
|
|
23875
|
+
* ```tsx
|
|
23876
|
+
* import { useThemeSwitcher } from '@shohojdhara/atomix/theme';
|
|
23877
|
+
*
|
|
23878
|
+
* function ThemeToggle() {
|
|
23879
|
+
* const { mode, toggle, setMode, isDark } = useThemeSwitcher();
|
|
23880
|
+
*
|
|
23881
|
+
* return (
|
|
23882
|
+
* <button onClick={toggle}>
|
|
23883
|
+
* {isDark ? '☀️ Light' : '🌙 Dark'}
|
|
23884
|
+
* </button>
|
|
23885
|
+
* );
|
|
23886
|
+
* }
|
|
23887
|
+
* ```
|
|
23888
|
+
*/
|
|
23889
|
+
/**
|
|
23890
|
+
* Hook for managing theme switching
|
|
23891
|
+
*
|
|
23892
|
+
* @param options - Configuration options
|
|
23893
|
+
* @returns Theme switcher controls
|
|
23894
|
+
*/ function useThemeSwitcher(options = {}) {
|
|
23895
|
+
const {initialMode: initialMode = "system", syncWithSystem: syncWithSystem = !1, storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, [mode, setModeState] = React.useState((() => {
|
|
23896
|
+
if ("undefined" == typeof window) return initialMode;
|
|
23897
|
+
// Check for saved preference first
|
|
23898
|
+
const saved = getCurrentTheme(storageKey);
|
|
23899
|
+
return saved && "system" !== saved ? saved : "system" === initialMode ? getSystemTheme() : initialMode;
|
|
23900
|
+
// Fall back to initial mode or system
|
|
23901
|
+
}));
|
|
23902
|
+
// State for current mode
|
|
23903
|
+
// Initialize theme on mount
|
|
23904
|
+
return React.useEffect((() => {
|
|
23905
|
+
"undefined" != typeof window && (
|
|
23906
|
+
// Initialize with proper theme application
|
|
23907
|
+
initializeTheme({
|
|
23908
|
+
storageKey: storageKey,
|
|
23909
|
+
enableTransition: enableTransition,
|
|
23910
|
+
transitionDuration: transitionDuration
|
|
23911
|
+
}),
|
|
23912
|
+
// Update state to match initialized theme
|
|
23913
|
+
setModeState(getCurrentTheme(storageKey)));
|
|
23914
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23915
|
+
// Listen for system theme changes if enabled
|
|
23916
|
+
React.useEffect((() => {
|
|
23917
|
+
if (syncWithSystem) return listenToSystemTheme((newMode => {
|
|
23918
|
+
setModeState(newMode), switchTheme(newMode, {
|
|
23919
|
+
storageKey: storageKey,
|
|
23920
|
+
enableTransition: enableTransition,
|
|
23921
|
+
transitionDuration: transitionDuration
|
|
23922
|
+
});
|
|
23923
|
+
}));
|
|
23924
|
+
}), [ syncWithSystem, storageKey, enableTransition, transitionDuration ]), {
|
|
23925
|
+
mode: mode,
|
|
23926
|
+
isDark: "dark" === mode,
|
|
23927
|
+
isLight: "light" === mode,
|
|
23928
|
+
toggle: React.useCallback((() => {
|
|
23929
|
+
const newMode = toggleTheme({
|
|
23930
|
+
storageKey: storageKey,
|
|
23931
|
+
enableTransition: enableTransition,
|
|
23932
|
+
transitionDuration: transitionDuration
|
|
23933
|
+
});
|
|
23934
|
+
return setModeState(newMode), newMode;
|
|
23935
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23936
|
+
setMode: React.useCallback((newMode => {
|
|
23937
|
+
switchTheme(newMode, {
|
|
23938
|
+
storageKey: storageKey,
|
|
23939
|
+
enableTransition: enableTransition,
|
|
23940
|
+
transitionDuration: transitionDuration
|
|
23941
|
+
}), setModeState(newMode);
|
|
23942
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23943
|
+
resetToSystem: React.useCallback((() => {
|
|
23944
|
+
const systemMode = getSystemTheme();
|
|
23945
|
+
switchTheme(systemMode, {
|
|
23946
|
+
storageKey: storageKey,
|
|
23947
|
+
enableTransition: enableTransition,
|
|
23948
|
+
transitionDuration: transitionDuration
|
|
23949
|
+
}), setModeState(systemMode);
|
|
23950
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23951
|
+
clearPreference: React.useCallback((() => {
|
|
23952
|
+
"undefined" != typeof window && localStorage.removeItem(storageKey);
|
|
23953
|
+
}), [ storageKey ])
|
|
23954
|
+
};
|
|
23955
|
+
}
|
|
23956
|
+
|
|
23957
|
+
/**
|
|
23958
|
+
* ThemeToggle component with multiple variants
|
|
23959
|
+
*/ const ThemeToggle = ({className: className = "", showLabel: showLabel = !1, lightLabel: lightLabel = "Light", darkLabel: darkLabel = "Dark", iconSize: iconSize = 20, variant: variant = "icon", render: render, ariaLabel: ariaLabel = "Toggle theme", ...hookOptions}) => {
|
|
23960
|
+
const {mode: mode, isDark: isDark, toggle: toggle} = useThemeSwitcher(hookOptions);
|
|
23961
|
+
// Custom render
|
|
23962
|
+
return render ? jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
23963
|
+
children: render({
|
|
23964
|
+
isDark: isDark,
|
|
23965
|
+
toggle: toggle,
|
|
23966
|
+
mode: mode
|
|
23967
|
+
})
|
|
23968
|
+
}) :
|
|
23969
|
+
// Icon-only variant (default)
|
|
23970
|
+
"icon" === variant ? jsxRuntime.jsx("button", {
|
|
23971
|
+
onClick: toggle,
|
|
23972
|
+
className: `theme-toggle theme-toggle-icon ${className}`,
|
|
23973
|
+
"aria-label": ariaLabel,
|
|
23974
|
+
title: isDark ? darkLabel : lightLabel,
|
|
23975
|
+
style: {
|
|
23976
|
+
background: "none",
|
|
23977
|
+
border: "none",
|
|
23978
|
+
cursor: "pointer",
|
|
23979
|
+
padding: "8px",
|
|
23980
|
+
borderRadius: "50%",
|
|
23981
|
+
display: "flex",
|
|
23982
|
+
alignItems: "center",
|
|
23983
|
+
justifyContent: "center",
|
|
23984
|
+
transition: "all 0.3s ease-in-out"
|
|
23985
|
+
},
|
|
23986
|
+
children: isDark ? jsxRuntime.jsxs("svg", {
|
|
23987
|
+
width: iconSize,
|
|
23988
|
+
height: iconSize,
|
|
23989
|
+
viewBox: "0 0 24 24",
|
|
23990
|
+
fill: "none",
|
|
23991
|
+
stroke: "currentColor",
|
|
23992
|
+
strokeWidth: "2",
|
|
23993
|
+
strokeLinecap: "round",
|
|
23994
|
+
strokeLinejoin: "round",
|
|
23995
|
+
children: [ jsxRuntime.jsx("circle", {
|
|
23996
|
+
cx: "12",
|
|
23997
|
+
cy: "12",
|
|
23998
|
+
r: "5"
|
|
23999
|
+
}), jsxRuntime.jsx("line", {
|
|
24000
|
+
x1: "12",
|
|
24001
|
+
y1: "1",
|
|
24002
|
+
x2: "12",
|
|
24003
|
+
y2: "3"
|
|
24004
|
+
}), jsxRuntime.jsx("line", {
|
|
24005
|
+
x1: "12",
|
|
24006
|
+
y1: "21",
|
|
24007
|
+
x2: "12",
|
|
24008
|
+
y2: "23"
|
|
24009
|
+
}), jsxRuntime.jsx("line", {
|
|
24010
|
+
x1: "4.22",
|
|
24011
|
+
y1: "4.22",
|
|
24012
|
+
x2: "5.64",
|
|
24013
|
+
y2: "5.64"
|
|
24014
|
+
}), jsxRuntime.jsx("line", {
|
|
24015
|
+
x1: "18.36",
|
|
24016
|
+
y1: "18.36",
|
|
24017
|
+
x2: "19.78",
|
|
24018
|
+
y2: "19.78"
|
|
24019
|
+
}), jsxRuntime.jsx("line", {
|
|
24020
|
+
x1: "1",
|
|
24021
|
+
y1: "12",
|
|
24022
|
+
x2: "3",
|
|
24023
|
+
y2: "12"
|
|
24024
|
+
}), jsxRuntime.jsx("line", {
|
|
24025
|
+
x1: "21",
|
|
24026
|
+
y1: "12",
|
|
24027
|
+
x2: "23",
|
|
24028
|
+
y2: "12"
|
|
24029
|
+
}), jsxRuntime.jsx("line", {
|
|
24030
|
+
x1: "4.22",
|
|
24031
|
+
y1: "19.78",
|
|
24032
|
+
x2: "5.64",
|
|
24033
|
+
y2: "18.36"
|
|
24034
|
+
}), jsxRuntime.jsx("line", {
|
|
24035
|
+
x1: "18.36",
|
|
24036
|
+
y1: "5.64",
|
|
24037
|
+
x2: "19.78",
|
|
24038
|
+
y2: "4.22"
|
|
24039
|
+
}) ]
|
|
24040
|
+
}) : jsxRuntime.jsx("svg", {
|
|
24041
|
+
width: iconSize,
|
|
24042
|
+
height: iconSize,
|
|
24043
|
+
viewBox: "0 0 24 24",
|
|
24044
|
+
fill: "none",
|
|
24045
|
+
stroke: "currentColor",
|
|
24046
|
+
strokeWidth: "2",
|
|
24047
|
+
strokeLinecap: "round",
|
|
24048
|
+
strokeLinejoin: "round",
|
|
24049
|
+
children: jsxRuntime.jsx("path", {
|
|
24050
|
+
d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
|
|
24051
|
+
})
|
|
24052
|
+
})
|
|
24053
|
+
}) :
|
|
24054
|
+
// Button variant with text
|
|
24055
|
+
"button" === variant ? jsxRuntime.jsxs("button", {
|
|
24056
|
+
onClick: toggle,
|
|
24057
|
+
className: `theme-toggle theme-toggle-button ${className}`,
|
|
24058
|
+
"aria-label": ariaLabel,
|
|
24059
|
+
style: {
|
|
24060
|
+
display: "flex",
|
|
24061
|
+
alignItems: "center",
|
|
24062
|
+
gap: "8px",
|
|
24063
|
+
padding: "8px 16px",
|
|
24064
|
+
borderRadius: "8px",
|
|
24065
|
+
border: "1px solid currentColor",
|
|
24066
|
+
background: "transparent",
|
|
24067
|
+
color: "inherit",
|
|
24068
|
+
cursor: "pointer",
|
|
24069
|
+
fontSize: "14px",
|
|
24070
|
+
fontWeight: "500",
|
|
24071
|
+
transition: "all 0.3s ease-in-out"
|
|
24072
|
+
},
|
|
24073
|
+
children: [ isDark ? jsxRuntime.jsxs("svg", {
|
|
24074
|
+
width: iconSize,
|
|
24075
|
+
height: iconSize,
|
|
24076
|
+
viewBox: "0 0 24 24",
|
|
24077
|
+
fill: "none",
|
|
24078
|
+
stroke: "currentColor",
|
|
24079
|
+
strokeWidth: "2",
|
|
24080
|
+
strokeLinecap: "round",
|
|
24081
|
+
strokeLinejoin: "round",
|
|
24082
|
+
children: [ jsxRuntime.jsx("circle", {
|
|
24083
|
+
cx: "12",
|
|
24084
|
+
cy: "12",
|
|
24085
|
+
r: "5"
|
|
24086
|
+
}), jsxRuntime.jsx("line", {
|
|
24087
|
+
x1: "12",
|
|
24088
|
+
y1: "1",
|
|
24089
|
+
x2: "12",
|
|
24090
|
+
y2: "3"
|
|
24091
|
+
}), jsxRuntime.jsx("line", {
|
|
24092
|
+
x1: "12",
|
|
24093
|
+
y1: "21",
|
|
24094
|
+
x2: "12",
|
|
24095
|
+
y2: "23"
|
|
24096
|
+
}), jsxRuntime.jsx("line", {
|
|
24097
|
+
x1: "4.22",
|
|
24098
|
+
y1: "4.22",
|
|
24099
|
+
x2: "5.64",
|
|
24100
|
+
y2: "5.64"
|
|
24101
|
+
}), jsxRuntime.jsx("line", {
|
|
24102
|
+
x1: "18.36",
|
|
24103
|
+
y1: "18.36",
|
|
24104
|
+
x2: "19.78",
|
|
24105
|
+
y2: "19.78"
|
|
24106
|
+
}), jsxRuntime.jsx("line", {
|
|
24107
|
+
x1: "1",
|
|
24108
|
+
y1: "12",
|
|
24109
|
+
x2: "3",
|
|
24110
|
+
y2: "12"
|
|
24111
|
+
}), jsxRuntime.jsx("line", {
|
|
24112
|
+
x1: "21",
|
|
24113
|
+
y1: "12",
|
|
24114
|
+
x2: "23",
|
|
24115
|
+
y2: "12"
|
|
24116
|
+
}), jsxRuntime.jsx("line", {
|
|
24117
|
+
x1: "4.22",
|
|
24118
|
+
y1: "19.78",
|
|
24119
|
+
x2: "5.64",
|
|
24120
|
+
y2: "18.36"
|
|
24121
|
+
}), jsxRuntime.jsx("line", {
|
|
24122
|
+
x1: "18.36",
|
|
24123
|
+
y1: "5.64",
|
|
24124
|
+
x2: "19.78",
|
|
24125
|
+
y2: "4.22"
|
|
24126
|
+
}) ]
|
|
24127
|
+
}) : jsxRuntime.jsx("svg", {
|
|
24128
|
+
width: iconSize,
|
|
24129
|
+
height: iconSize,
|
|
24130
|
+
viewBox: "0 0 24 24",
|
|
24131
|
+
fill: "none",
|
|
24132
|
+
stroke: "currentColor",
|
|
24133
|
+
strokeWidth: "2",
|
|
24134
|
+
strokeLinecap: "round",
|
|
24135
|
+
strokeLinejoin: "round",
|
|
24136
|
+
children: jsxRuntime.jsx("path", {
|
|
24137
|
+
d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
|
|
24138
|
+
})
|
|
24139
|
+
}), showLabel && jsxRuntime.jsx("span", {
|
|
24140
|
+
children: isDark ? darkLabel : lightLabel
|
|
24141
|
+
}) ]
|
|
24142
|
+
}) :
|
|
24143
|
+
// Switch/toggle variant
|
|
24144
|
+
"switch" === variant ? jsxRuntime.jsx("div", {
|
|
24145
|
+
className: `theme-toggle theme-toggle-switch ${className}`,
|
|
24146
|
+
role: "button",
|
|
24147
|
+
tabIndex: 0,
|
|
24148
|
+
onClick: toggle,
|
|
24149
|
+
onKeyDown: e => "Enter" === e.key && toggle(),
|
|
24150
|
+
"aria-label": ariaLabel,
|
|
24151
|
+
style: {
|
|
24152
|
+
position: "relative",
|
|
24153
|
+
width: "56px",
|
|
24154
|
+
height: "28px",
|
|
24155
|
+
borderRadius: "14px",
|
|
24156
|
+
background: isDark ? "#4b5563" : "#d1d5db",
|
|
24157
|
+
cursor: "pointer",
|
|
24158
|
+
transition: "background 0.3s ease-in-out",
|
|
24159
|
+
display: "flex",
|
|
24160
|
+
alignItems: "center",
|
|
24161
|
+
padding: "2px"
|
|
24162
|
+
},
|
|
24163
|
+
children: jsxRuntime.jsx("div", {
|
|
24164
|
+
style: {
|
|
24165
|
+
position: "absolute",
|
|
24166
|
+
left: isDark ? "auto" : "2px",
|
|
24167
|
+
right: isDark ? "2px" : "auto",
|
|
24168
|
+
width: "24px",
|
|
24169
|
+
height: "24px",
|
|
24170
|
+
borderRadius: "50%",
|
|
24171
|
+
background: "white",
|
|
24172
|
+
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
|
|
24173
|
+
transition: "all 0.3s ease-in-out",
|
|
24174
|
+
display: "flex",
|
|
24175
|
+
alignItems: "center",
|
|
24176
|
+
justifyContent: "center"
|
|
24177
|
+
},
|
|
24178
|
+
children: isDark ? jsxRuntime.jsx("svg", {
|
|
24179
|
+
width: "14",
|
|
24180
|
+
height: "14",
|
|
24181
|
+
viewBox: "0 0 24 24",
|
|
24182
|
+
fill: "none",
|
|
24183
|
+
stroke: "#4b5563",
|
|
24184
|
+
strokeWidth: "2",
|
|
24185
|
+
strokeLinecap: "round",
|
|
24186
|
+
strokeLinejoin: "round",
|
|
24187
|
+
children: jsxRuntime.jsx("path", {
|
|
24188
|
+
d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
|
|
24189
|
+
})
|
|
24190
|
+
}) : jsxRuntime.jsxs("svg", {
|
|
24191
|
+
width: "14",
|
|
24192
|
+
height: "14",
|
|
24193
|
+
viewBox: "0 0 24 24",
|
|
24194
|
+
fill: "none",
|
|
24195
|
+
stroke: "#f59e0b",
|
|
24196
|
+
strokeWidth: "2",
|
|
24197
|
+
strokeLinecap: "round",
|
|
24198
|
+
strokeLinejoin: "round",
|
|
24199
|
+
children: [ jsxRuntime.jsx("circle", {
|
|
24200
|
+
cx: "12",
|
|
24201
|
+
cy: "12",
|
|
24202
|
+
r: "5"
|
|
24203
|
+
}), jsxRuntime.jsx("line", {
|
|
24204
|
+
x1: "12",
|
|
24205
|
+
y1: "1",
|
|
24206
|
+
x2: "12",
|
|
24207
|
+
y2: "3"
|
|
24208
|
+
}), jsxRuntime.jsx("line", {
|
|
24209
|
+
x1: "12",
|
|
24210
|
+
y1: "21",
|
|
24211
|
+
x2: "12",
|
|
24212
|
+
y2: "23"
|
|
24213
|
+
}), jsxRuntime.jsx("line", {
|
|
24214
|
+
x1: "4.22",
|
|
24215
|
+
y1: "4.22",
|
|
24216
|
+
x2: "5.64",
|
|
24217
|
+
y2: "5.64"
|
|
24218
|
+
}), jsxRuntime.jsx("line", {
|
|
24219
|
+
x1: "18.36",
|
|
24220
|
+
y1: "18.36",
|
|
24221
|
+
x2: "19.78",
|
|
24222
|
+
y2: "19.78"
|
|
24223
|
+
}), jsxRuntime.jsx("line", {
|
|
24224
|
+
x1: "1",
|
|
24225
|
+
y1: "12",
|
|
24226
|
+
x2: "3",
|
|
24227
|
+
y2: "12"
|
|
24228
|
+
}), jsxRuntime.jsx("line", {
|
|
24229
|
+
x1: "21",
|
|
24230
|
+
y1: "12",
|
|
24231
|
+
x2: "23",
|
|
24232
|
+
y2: "12"
|
|
24233
|
+
}), jsxRuntime.jsx("line", {
|
|
24234
|
+
x1: "4.22",
|
|
24235
|
+
y1: "19.78",
|
|
24236
|
+
x2: "5.64",
|
|
24237
|
+
y2: "18.36"
|
|
24238
|
+
}), jsxRuntime.jsx("line", {
|
|
24239
|
+
x1: "18.36",
|
|
24240
|
+
y1: "5.64",
|
|
24241
|
+
x2: "19.78",
|
|
24242
|
+
y2: "4.22"
|
|
24243
|
+
}) ]
|
|
24244
|
+
})
|
|
24245
|
+
})
|
|
24246
|
+
}) : null;
|
|
24247
|
+
};
|
|
24248
|
+
|
|
24249
|
+
ThemeToggle.displayName = "ThemeToggle";
|
|
24250
|
+
|
|
22950
24251
|
/**
|
|
22951
24252
|
* Theme Applicator
|
|
22952
24253
|
*
|
|
@@ -22959,7 +24260,8 @@ function useThemeTokens() {
|
|
|
22959
24260
|
* Theme applicator class for runtime theme application
|
|
22960
24261
|
*
|
|
22961
24262
|
* Uses the unified theme system for efficient CSS variable generation and injection.
|
|
22962
|
-
*/
|
|
24263
|
+
*/
|
|
24264
|
+
class ThemeApplicator {
|
|
22963
24265
|
constructor(root = document.documentElement) {
|
|
22964
24266
|
this.styleId = "atomix-theme-applicator", this.root = root;
|
|
22965
24267
|
}
|
|
@@ -24698,13 +26000,13 @@ class ThemeValidator {
|
|
|
24698
26000
|
function createPaletteColor(color) {
|
|
24699
26001
|
return "string" == typeof color ? {
|
|
24700
26002
|
main: color,
|
|
24701
|
-
light: lighten(color),
|
|
24702
|
-
dark: darken(color),
|
|
26003
|
+
light: lighten(color, .15),
|
|
26004
|
+
dark: darken(color, .15),
|
|
24703
26005
|
contrastText: getContrastText(color)
|
|
24704
26006
|
} : {
|
|
24705
26007
|
main: color.main || "#000000",
|
|
24706
|
-
light: color.light || lighten(color.main || "#000000"),
|
|
24707
|
-
dark: color.dark || darken(color.main || "#000000"),
|
|
26008
|
+
light: color.light || lighten(color.main || "#000000", .15),
|
|
26009
|
+
dark: color.dark || darken(color.main || "#000000", .15),
|
|
24708
26010
|
contrastText: color.contrastText || getContrastText(color.main || "#000000")
|
|
24709
26011
|
};
|
|
24710
26012
|
}
|
|
@@ -24739,23 +26041,19 @@ function createThemeObject(...options) {
|
|
|
24739
26041
|
},
|
|
24740
26042
|
background: {
|
|
24741
26043
|
default: mergedOptions.palette?.background?.default || DEFAULT_PALETTE.background.default,
|
|
26044
|
+
paper: mergedOptions.palette?.background?.paper || DEFAULT_PALETTE.background.paper,
|
|
24742
26045
|
subtle: mergedOptions.palette?.background?.subtle || DEFAULT_PALETTE.background.subtle
|
|
24743
26046
|
},
|
|
24744
26047
|
text: {
|
|
24745
26048
|
primary: mergedOptions.palette?.text?.primary || DEFAULT_PALETTE.text.primary,
|
|
24746
26049
|
secondary: mergedOptions.palette?.text?.secondary || DEFAULT_PALETTE.text.secondary,
|
|
24747
26050
|
disabled: mergedOptions.palette?.text?.disabled || DEFAULT_PALETTE.text.disabled
|
|
24748
|
-
}
|
|
26051
|
+
},
|
|
26052
|
+
// Spread other palette properties
|
|
26053
|
+
...mergedOptions.palette
|
|
24749
26054
|
}, typography = deepMerge({
|
|
24750
26055
|
...DEFAULT_TYPOGRAPHY
|
|
24751
|
-
}, mergedOptions.typography || {}), spacing =
|
|
24752
|
-
// If it's already a function, return it
|
|
24753
|
-
return "function" == typeof spacingInput ? spacingInput :
|
|
24754
|
-
// If it's a number, create a function that multiplies by that number
|
|
24755
|
-
"number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
|
|
24756
|
-
// If it's an array, use it as a scale
|
|
24757
|
-
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(" ");
|
|
24758
|
-
}(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
|
|
26056
|
+
}, mergedOptions.typography || {}), spacing = createSpacing(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
|
|
24759
26057
|
const values = {
|
|
24760
26058
|
xs: 0,
|
|
24761
26059
|
sm: 576,
|
|
@@ -25577,25 +26875,7 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
|
|
|
25577
26875
|
|
|
25578
26876
|
/**
|
|
25579
26877
|
* Design Tokens Customizer Component
|
|
25580
|
-
*/
|
|
25581
|
-
/**
|
|
25582
|
-
* Theme Adapter
|
|
25583
|
-
*
|
|
25584
|
-
* Converts between Theme objects and DesignTokens.
|
|
25585
|
-
*/
|
|
25586
|
-
/**
|
|
25587
|
-
* Convert DesignTokens to Theme-compatible CSS variables
|
|
25588
|
-
*
|
|
25589
|
-
* @param tokens - DesignTokens object
|
|
25590
|
-
* @returns CSS variables object compatible with Theme.cssVars
|
|
25591
|
-
*/
|
|
25592
|
-
function designTokensToCSSVars(tokens) {
|
|
25593
|
-
const cssVars = {};
|
|
25594
|
-
return Object.entries(tokens).forEach((([key, value]) => {
|
|
25595
|
-
void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
|
|
25596
|
-
})), cssVars;
|
|
25597
|
-
}
|
|
25598
|
-
|
|
26878
|
+
*/
|
|
25599
26879
|
/**
|
|
25600
26880
|
* Theme Helper Functions
|
|
25601
26881
|
*
|
|
@@ -25608,7 +26888,8 @@ function designTokensToCSSVars(tokens) {
|
|
|
25608
26888
|
*
|
|
25609
26889
|
* @param value - Value to check
|
|
25610
26890
|
* @returns True if value is DesignTokens
|
|
25611
|
-
*/
|
|
26891
|
+
*/
|
|
26892
|
+
function isDesignTokens(value) {
|
|
25612
26893
|
if (!value || "object" != typeof value) return !1;
|
|
25613
26894
|
// DesignTokens is a flat object with string keys, no nested structures
|
|
25614
26895
|
const obj = value;
|
|
@@ -25620,6 +26901,335 @@ function designTokensToCSSVars(tokens) {
|
|
|
25620
26901
|
// Check if keys look like DesignTokens (kebab-case, no nesting)
|
|
25621
26902
|
}
|
|
25622
26903
|
|
|
26904
|
+
/**
|
|
26905
|
+
* Performance monitor class
|
|
26906
|
+
*/ class PerformanceMonitor {
|
|
26907
|
+
/**
|
|
26908
|
+
* Create a new performance monitor
|
|
26909
|
+
*
|
|
26910
|
+
* @param config Configuration options
|
|
26911
|
+
*/
|
|
26912
|
+
constructor(config) {
|
|
26913
|
+
this.frameCount = 0, this.lastSampleTime = 0, this.lastFpsUpdate = 0, this.frameTimes = [],
|
|
26914
|
+
this.animationFrameId = null, this.isActive = !1, this.startTime = 0, this.config = {
|
|
26915
|
+
fpsTarget: config?.fpsTarget ?? 60,
|
|
26916
|
+
sampleInterval: config?.sampleInterval ?? 500,
|
|
26917
|
+
onUpdate: config?.onUpdate ?? (() => {}),
|
|
26918
|
+
onDegraded: config?.onDegraded ?? (() => {}),
|
|
26919
|
+
enableMemoryMonitoring: config?.enableMemoryMonitoring ?? ("undefined" != typeof window && window.performance && window.performance.memory)
|
|
26920
|
+
};
|
|
26921
|
+
}
|
|
26922
|
+
/**
|
|
26923
|
+
* Start monitoring performance
|
|
26924
|
+
*/ start() {
|
|
26925
|
+
this.isActive || (this.isActive = !0, this.frameCount = 0, this.lastSampleTime = performance.now(),
|
|
26926
|
+
this.lastFpsUpdate = this.lastSampleTime, this.frameTimes = [], this.startTime = this.lastSampleTime,
|
|
26927
|
+
this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this)));
|
|
26928
|
+
}
|
|
26929
|
+
/**
|
|
26930
|
+
* Stop monitoring performance
|
|
26931
|
+
*/ stop() {
|
|
26932
|
+
this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null),
|
|
26933
|
+
this.isActive = !1;
|
|
26934
|
+
}
|
|
26935
|
+
/**
|
|
26936
|
+
* Get current performance metrics
|
|
26937
|
+
*/ getMetrics() {
|
|
26938
|
+
var _context;
|
|
26939
|
+
const now = performance.now(), elapsed = now - this.lastFpsUpdate, fps = elapsed > 0 ? Math.round(this.frameCount / elapsed * 1e3) : 0, avgFrameTime = this.frameTimes.length > 0 ? _reduceInstanceProperty(_context = this.frameTimes).call(_context, ((a, b) => a + b), 0) / this.frameTimes.length : 0, peakFrameTime = this.frameTimes.length > 0 ? Math.max(...this.frameTimes) : 0;
|
|
26940
|
+
// Get memory stats if available
|
|
26941
|
+
let memory;
|
|
26942
|
+
if (this.config.enableMemoryMonitoring) {
|
|
26943
|
+
const perf = window.performance;
|
|
26944
|
+
perf && perf.memory && (memory = {
|
|
26945
|
+
usedJSHeapSize: perf.memory.usedJSHeapSize,
|
|
26946
|
+
totalJSHeapSize: perf.memory.totalJSHeapSize,
|
|
26947
|
+
jsHeapSizeLimit: perf.memory.jsHeapSizeLimit
|
|
26948
|
+
});
|
|
26949
|
+
}
|
|
26950
|
+
return {
|
|
26951
|
+
fps: fps,
|
|
26952
|
+
frameTime: avgFrameTime,
|
|
26953
|
+
peakFrameTime: peakFrameTime,
|
|
26954
|
+
memory: memory,
|
|
26955
|
+
timestamp: now,
|
|
26956
|
+
isDegraded: fps < .7 * this.config.fpsTarget
|
|
26957
|
+
};
|
|
26958
|
+
}
|
|
26959
|
+
/**
|
|
26960
|
+
* Get the current FPS
|
|
26961
|
+
*/ getFps() {
|
|
26962
|
+
return this.getMetrics().fps;
|
|
26963
|
+
}
|
|
26964
|
+
/**
|
|
26965
|
+
* Check if performance is degraded
|
|
26966
|
+
*/ isPerformanceDegraded() {
|
|
26967
|
+
return this.getMetrics().isDegraded;
|
|
26968
|
+
}
|
|
26969
|
+
/**
|
|
26970
|
+
* Private method called on each animation frame
|
|
26971
|
+
*/ onFrame(timestamp) {
|
|
26972
|
+
if (!this.isActive) return;
|
|
26973
|
+
// Calculate frame time
|
|
26974
|
+
const frameTime = timestamp - this.lastSampleTime;
|
|
26975
|
+
// Check if we need to update metrics
|
|
26976
|
+
if (this.frameTimes.push(frameTime),
|
|
26977
|
+
// Keep only the last 60 frame times for averaging
|
|
26978
|
+
this.frameTimes.length > 60 && this.frameTimes.shift(), this.frameCount++, this.lastSampleTime = timestamp,
|
|
26979
|
+
timestamp - this.lastFpsUpdate >= this.config.sampleInterval) {
|
|
26980
|
+
const metrics = this.getMetrics();
|
|
26981
|
+
// Call update callback
|
|
26982
|
+
this.config.onUpdate(metrics),
|
|
26983
|
+
// Check for degradation
|
|
26984
|
+
metrics.isDegraded && this.config.onDegraded(metrics),
|
|
26985
|
+
// Reset counters
|
|
26986
|
+
this.frameCount = 0, this.lastFpsUpdate = timestamp;
|
|
26987
|
+
}
|
|
26988
|
+
this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this));
|
|
26989
|
+
}
|
|
26990
|
+
/**
|
|
26991
|
+
* Run a performance test for a specific function
|
|
26992
|
+
*
|
|
26993
|
+
* @param fn Function to test
|
|
26994
|
+
* @param iterations Number of iterations (default: 100)
|
|
26995
|
+
* @returns Average execution time in ms
|
|
26996
|
+
*/ async testFunctionPerformance(fn, iterations = 100) {
|
|
26997
|
+
const times = [];
|
|
26998
|
+
for (let i = 0; i < iterations; i++) {
|
|
26999
|
+
const start = performance.now();
|
|
27000
|
+
fn();
|
|
27001
|
+
const end = performance.now();
|
|
27002
|
+
times.push(end - start);
|
|
27003
|
+
}
|
|
27004
|
+
return _reduceInstanceProperty(times).call(times, ((a, b) => a + b), 0) / times.length;
|
|
27005
|
+
}
|
|
27006
|
+
}
|
|
27007
|
+
|
|
27008
|
+
/**
|
|
27009
|
+
* Create a performance monitor instance
|
|
27010
|
+
*
|
|
27011
|
+
* @param config Configuration options
|
|
27012
|
+
* @returns PerformanceMonitor instance
|
|
27013
|
+
*
|
|
27014
|
+
* @example
|
|
27015
|
+
* ```typescript
|
|
27016
|
+
* import { createPerformanceMonitor } from '@shohojdhara/atomix/theme';
|
|
27017
|
+
*
|
|
27018
|
+
* const monitor = createPerformanceMonitor({
|
|
27019
|
+
* fpsTarget: 60,
|
|
27020
|
+
* onUpdate: (metrics) => console.log('FPS:', metrics.fps),
|
|
27021
|
+
* onDegraded: (metrics) => console.warn('Performance degraded!', metrics),
|
|
27022
|
+
* });
|
|
27023
|
+
*
|
|
27024
|
+
* monitor.start();
|
|
27025
|
+
*
|
|
27026
|
+
* // Later...
|
|
27027
|
+
* monitor.stop();
|
|
27028
|
+
* ```
|
|
27029
|
+
*/ function createPerformanceMonitor(config) {
|
|
27030
|
+
return new PerformanceMonitor(config);
|
|
27031
|
+
}
|
|
27032
|
+
|
|
27033
|
+
/**
|
|
27034
|
+
* Hook for React components to monitor performance
|
|
27035
|
+
*
|
|
27036
|
+
* @param config Configuration options
|
|
27037
|
+
* @returns Performance metrics and monitor controls
|
|
27038
|
+
*
|
|
27039
|
+
* @example
|
|
27040
|
+
* ```typescript
|
|
27041
|
+
* import { usePerformanceMonitor } from '@shohojdhara/atomix/theme';
|
|
27042
|
+
*
|
|
27043
|
+
* function MyComponent() {
|
|
27044
|
+
* const { metrics, start, stop } = usePerformanceMonitor({ fpsTarget: 60 });
|
|
27045
|
+
*
|
|
27046
|
+
* useEffect(() => {
|
|
27047
|
+
* start();
|
|
27048
|
+
* return () => stop();
|
|
27049
|
+
* }, []);
|
|
27050
|
+
*
|
|
27051
|
+
* return <div>FPS: {metrics.fps}</div>;
|
|
27052
|
+
* }
|
|
27053
|
+
* ```
|
|
27054
|
+
*/ function usePerformanceMonitor(config) {
|
|
27055
|
+
const [monitor] = React__default.default.useState((() => createPerformanceMonitor(config))), [metrics, setMetrics] = React__default.default.useState((() => "undefined" != typeof window ? monitor.getMetrics() : {
|
|
27056
|
+
fps: 0,
|
|
27057
|
+
frameTime: 0,
|
|
27058
|
+
peakFrameTime: 0,
|
|
27059
|
+
timestamp: 0,
|
|
27060
|
+
isDegraded: !1
|
|
27061
|
+
})), start = React__default.default.useCallback((() => {
|
|
27062
|
+
"undefined" != typeof window && monitor.start();
|
|
27063
|
+
}), [ monitor ]), stop = React__default.default.useCallback((() => {
|
|
27064
|
+
"undefined" != typeof window && monitor.stop();
|
|
27065
|
+
}), [ monitor ]);
|
|
27066
|
+
return React__default.default.useEffect((() => {
|
|
27067
|
+
if ("undefined" == typeof window) return;
|
|
27068
|
+
// Update metrics when monitor callbacks fire
|
|
27069
|
+
const originalOnUpdate = config?.onUpdate;
|
|
27070
|
+
return monitor.config.onUpdate = newMetrics => {
|
|
27071
|
+
setMetrics(newMetrics), originalOnUpdate?.(newMetrics);
|
|
27072
|
+
}, () => {
|
|
27073
|
+
monitor.stop();
|
|
27074
|
+
};
|
|
27075
|
+
}), [ monitor, config?.onUpdate ]), {
|
|
27076
|
+
metrics: metrics,
|
|
27077
|
+
start: start,
|
|
27078
|
+
stop: stop
|
|
27079
|
+
};
|
|
27080
|
+
}
|
|
27081
|
+
|
|
27082
|
+
/**
|
|
27083
|
+
* Responsive Utility for Atomix Theme System
|
|
27084
|
+
*
|
|
27085
|
+
* Provides responsive breakpoint detection and device-aware parameter scaling
|
|
27086
|
+
* based on configuration from the advanced optimization features.
|
|
27087
|
+
*/
|
|
27088
|
+
/**
|
|
27089
|
+
* Responsive utility class
|
|
27090
|
+
*/ class ResponsiveUtil {
|
|
27091
|
+
constructor(config) {
|
|
27092
|
+
this.currentDevice = "desktop", // Default
|
|
27093
|
+
this.resizeHandler = null, this.observer = null, this.config = config, this.currentDevice = this.getCurrentDeviceType(),
|
|
27094
|
+
// Set up resize listener
|
|
27095
|
+
this.setupResizeListener();
|
|
27096
|
+
}
|
|
27097
|
+
/**
|
|
27098
|
+
* Get the current device type based on viewport width
|
|
27099
|
+
*/ getCurrentDeviceType() {
|
|
27100
|
+
if ("undefined" == typeof window) return "desktop";
|
|
27101
|
+
// SSR fallback
|
|
27102
|
+
const width = window.innerWidth;
|
|
27103
|
+
// Parse breakpoint values to numbers
|
|
27104
|
+
this.parsePxValue(this.config.breakpoints.mobile);
|
|
27105
|
+
const tabletWidth = this.parsePxValue(this.config.breakpoints.tablet), desktopWidth = this.parsePxValue(this.config.breakpoints.desktop), wideWidth = this.parsePxValue(this.config.breakpoints.wide);
|
|
27106
|
+
return width < tabletWidth ? "mobile" : width < desktopWidth ? "tablet" : width < wideWidth ? "desktop" : "wide";
|
|
27107
|
+
}
|
|
27108
|
+
/**
|
|
27109
|
+
* Get the scaling factor for the current device
|
|
27110
|
+
*/ getCurrentScalingFactor() {
|
|
27111
|
+
// 'wide' devices use the same scaling as 'desktop'
|
|
27112
|
+
const scalingKey = "wide" === this.currentDevice ? "desktop" : this.currentDevice;
|
|
27113
|
+
return this.config.deviceScaling[scalingKey] || 1;
|
|
27114
|
+
}
|
|
27115
|
+
/**
|
|
27116
|
+
* Scale a value based on the current device's scaling factor
|
|
27117
|
+
*/ scaleValue(value) {
|
|
27118
|
+
return value * this.getCurrentScalingFactor();
|
|
27119
|
+
}
|
|
27120
|
+
/**
|
|
27121
|
+
* Check if the current device matches a specific type
|
|
27122
|
+
*/ isDevice(device) {
|
|
27123
|
+
return this.currentDevice === device;
|
|
27124
|
+
}
|
|
27125
|
+
/**
|
|
27126
|
+
* Check if the current device is mobile or smaller
|
|
27127
|
+
*/ isMobileOrSmaller() {
|
|
27128
|
+
return "mobile" === this.currentDevice;
|
|
27129
|
+
}
|
|
27130
|
+
/**
|
|
27131
|
+
* Check if the current device is tablet or smaller
|
|
27132
|
+
*/ isTabletOrSmaller() {
|
|
27133
|
+
return "mobile" === this.currentDevice || "tablet" === this.currentDevice;
|
|
27134
|
+
}
|
|
27135
|
+
/**
|
|
27136
|
+
* Check if the current device is desktop or larger
|
|
27137
|
+
*/ isDesktopOrLarger() {
|
|
27138
|
+
return "desktop" === this.currentDevice || "wide" === this.currentDevice;
|
|
27139
|
+
}
|
|
27140
|
+
/**
|
|
27141
|
+
* Update the responsive configuration
|
|
27142
|
+
*/ updateConfig(config) {
|
|
27143
|
+
this.config = config, this.currentDevice = this.getCurrentDeviceType();
|
|
27144
|
+
}
|
|
27145
|
+
/**
|
|
27146
|
+
* Destroy the responsive utility and clean up listeners
|
|
27147
|
+
*/ destroy() {
|
|
27148
|
+
this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler),
|
|
27149
|
+
this.resizeHandler = null), this.observer && (this.observer.disconnect(), this.observer = null);
|
|
27150
|
+
}
|
|
27151
|
+
/**
|
|
27152
|
+
* Parse a CSS value to pixels
|
|
27153
|
+
*/ parsePxValue(value) {
|
|
27154
|
+
return value.endsWith("px") ? parseFloat(value.slice(0, -2)) :
|
|
27155
|
+
// For other units, we'll use a rough conversion assuming 16px base
|
|
27156
|
+
value.endsWith("rem") ? 16 * parseFloat(value.slice(0, -3)) : value.endsWith("em") ? 16 * parseFloat(value.slice(0, -2)) : parseFloat(value) || 0;
|
|
27157
|
+
}
|
|
27158
|
+
/**
|
|
27159
|
+
* Set up the resize listener
|
|
27160
|
+
*/ setupResizeListener() {
|
|
27161
|
+
if ("undefined" == typeof window) return;
|
|
27162
|
+
// Throttled resize handler
|
|
27163
|
+
let resizeTimeout = null;
|
|
27164
|
+
const handleResize = () => {
|
|
27165
|
+
resizeTimeout && window.clearTimeout(resizeTimeout), resizeTimeout = window.setTimeout((() => {
|
|
27166
|
+
const newDeviceType = this.getCurrentDeviceType();
|
|
27167
|
+
newDeviceType !== this.currentDevice && (this.currentDevice = newDeviceType);
|
|
27168
|
+
}), 150);
|
|
27169
|
+
} // Throttle to 150ms
|
|
27170
|
+
;
|
|
27171
|
+
this.resizeHandler = handleResize, window.addEventListener("resize", handleResize),
|
|
27172
|
+
// Also observe the document body for size changes
|
|
27173
|
+
"undefined" != typeof ResizeObserver && (this.observer = new ResizeObserver(handleResize),
|
|
27174
|
+
this.observer.observe(document.body));
|
|
27175
|
+
}
|
|
27176
|
+
}
|
|
27177
|
+
|
|
27178
|
+
/**
|
|
27179
|
+
* Create a responsive utility instance
|
|
27180
|
+
*
|
|
27181
|
+
* @param config Responsive configuration
|
|
27182
|
+
* @returns ResponsiveUtil instance
|
|
27183
|
+
*/ function createResponsiveUtil(config) {
|
|
27184
|
+
return new ResponsiveUtil(config);
|
|
27185
|
+
}
|
|
27186
|
+
|
|
27187
|
+
/**
|
|
27188
|
+
* Hook for React components to use responsive features
|
|
27189
|
+
*
|
|
27190
|
+
* @param config Responsive configuration
|
|
27191
|
+
* @returns Current device type and utility functions
|
|
27192
|
+
*/ function useResponsive(config) {
|
|
27193
|
+
const [util] = React__default.default.useState((() => createResponsiveUtil(config))), [deviceType, setDeviceType] = React__default.default.useState((() => "undefined" != typeof window ? util.getCurrentDeviceType() : "desktop"));
|
|
27194
|
+
return React__default.default.useEffect((() => {
|
|
27195
|
+
if ("undefined" == typeof window) return;
|
|
27196
|
+
const handleResize = () => {
|
|
27197
|
+
const newDeviceType = util.getCurrentDeviceType();
|
|
27198
|
+
newDeviceType !== deviceType && setDeviceType(newDeviceType);
|
|
27199
|
+
};
|
|
27200
|
+
// Update device type on mount
|
|
27201
|
+
return setDeviceType(util.getCurrentDeviceType()),
|
|
27202
|
+
// Listen for resize events
|
|
27203
|
+
window.addEventListener("resize", handleResize), () => {
|
|
27204
|
+
window.removeEventListener("resize", handleResize), util.destroy();
|
|
27205
|
+
};
|
|
27206
|
+
}), [ util, deviceType ]), "undefined" == typeof window ? {
|
|
27207
|
+
deviceType: "desktop",
|
|
27208
|
+
isMobile: !1,
|
|
27209
|
+
isTablet: !1,
|
|
27210
|
+
isDesktop: !0,
|
|
27211
|
+
isWide: !1,
|
|
27212
|
+
scaleValue: value => value,
|
|
27213
|
+
getCurrentDeviceType: () => "desktop",
|
|
27214
|
+
getCurrentScalingFactor: () => 1,
|
|
27215
|
+
isMobileOrSmaller: () => !1,
|
|
27216
|
+
isTabletOrSmaller: () => !0,
|
|
27217
|
+
isDesktopOrLarger: () => !0
|
|
27218
|
+
} : {
|
|
27219
|
+
deviceType: deviceType,
|
|
27220
|
+
isMobile: "mobile" === deviceType,
|
|
27221
|
+
isTablet: "tablet" === deviceType,
|
|
27222
|
+
isDesktop: "desktop" === deviceType,
|
|
27223
|
+
isWide: "wide" === deviceType,
|
|
27224
|
+
scaleValue: value => util.scaleValue(value),
|
|
27225
|
+
getCurrentDeviceType: () => util.getCurrentDeviceType(),
|
|
27226
|
+
getCurrentScalingFactor: () => util.getCurrentScalingFactor(),
|
|
27227
|
+
isMobileOrSmaller: () => util.isMobileOrSmaller(),
|
|
27228
|
+
isTabletOrSmaller: () => util.isTabletOrSmaller(),
|
|
27229
|
+
isDesktopOrLarger: () => util.isDesktopOrLarger()
|
|
27230
|
+
};
|
|
27231
|
+
}
|
|
27232
|
+
|
|
25623
27233
|
/**
|
|
25624
27234
|
* RTL (Right-to-Left) Support Utilities
|
|
25625
27235
|
*
|
|
@@ -25805,6 +27415,32 @@ class RTLManager {
|
|
|
25805
27415
|
}
|
|
25806
27416
|
}
|
|
25807
27417
|
|
|
27418
|
+
/**
|
|
27419
|
+
* Create RTL manager instance
|
|
27420
|
+
*/ function createRTLManager(config) {
|
|
27421
|
+
return new RTLManager(config);
|
|
27422
|
+
}
|
|
27423
|
+
|
|
27424
|
+
/**
|
|
27425
|
+
* Check if locale is RTL
|
|
27426
|
+
*/ function isRTLLocale(locale) {
|
|
27427
|
+
return RTL_LOCALES.has(locale.toLowerCase());
|
|
27428
|
+
}
|
|
27429
|
+
|
|
27430
|
+
/**
|
|
27431
|
+
* Get direction from locale
|
|
27432
|
+
*/ function getDirectionFromLocale(locale) {
|
|
27433
|
+
return isRTLLocale(locale) ? "rtl" : "ltr";
|
|
27434
|
+
}
|
|
27435
|
+
|
|
27436
|
+
/**
|
|
27437
|
+
* RTL-aware CSS helper
|
|
27438
|
+
*
|
|
27439
|
+
* Returns appropriate CSS based on direction
|
|
27440
|
+
*/ function rtlCSS(ltrCSS, rtlCSS, direction = "ltr") {
|
|
27441
|
+
return "rtl" === direction ? rtlCSS : ltrCSS;
|
|
27442
|
+
}
|
|
27443
|
+
|
|
25808
27444
|
/**
|
|
25809
27445
|
* Theme System Exports
|
|
25810
27446
|
*
|
|
@@ -25827,8 +27463,6 @@ class RTLManager {
|
|
|
25827
27463
|
// ============================================================================
|
|
25828
27464
|
// Core Theme Functions
|
|
25829
27465
|
// ============================================================================
|
|
25830
|
-
// Create theme CSS from DesignTokens
|
|
25831
|
-
// File saving utilities removed to prevent bundling Node.js modules in browser
|
|
25832
27466
|
/**
|
|
25833
27467
|
* Inject theme CSS into DOM
|
|
25834
27468
|
*/ function injectTheme(css, id = "atomix-theme") {
|
|
@@ -25841,6 +27475,115 @@ class RTLManager {
|
|
|
25841
27475
|
removeCSS(id);
|
|
25842
27476
|
}
|
|
25843
27477
|
|
|
27478
|
+
/**
|
|
27479
|
+
* Main theme module interface
|
|
27480
|
+
*/ var index = {
|
|
27481
|
+
// Core
|
|
27482
|
+
createTheme: createTheme,
|
|
27483
|
+
injectTheme: injectTheme,
|
|
27484
|
+
removeTheme: removeTheme,
|
|
27485
|
+
// Context and Provider
|
|
27486
|
+
ThemeProvider: ThemeProvider,
|
|
27487
|
+
useTheme: useTheme,
|
|
27488
|
+
useThemeTokens: useThemeTokens,
|
|
27489
|
+
ThemeContext: ThemeContext,
|
|
27490
|
+
ThemeErrorBoundary: ThemeErrorBoundary,
|
|
27491
|
+
// Adapters
|
|
27492
|
+
configToTokens: configToTokens,
|
|
27493
|
+
designTokensToCSSVars: designTokensToCSSVars,
|
|
27494
|
+
// Theme Utils
|
|
27495
|
+
switchTheme: switchTheme,
|
|
27496
|
+
toggleTheme: toggleTheme,
|
|
27497
|
+
getCurrentTheme: getCurrentTheme,
|
|
27498
|
+
getSystemTheme: getSystemTheme,
|
|
27499
|
+
initializeTheme: initializeTheme,
|
|
27500
|
+
listenToSystemTheme: listenToSystemTheme,
|
|
27501
|
+
persistTheme: persistTheme,
|
|
27502
|
+
clearThemePreference: clearThemePreference,
|
|
27503
|
+
// Token Manipulation
|
|
27504
|
+
mergeTokens: mergeTokens,
|
|
27505
|
+
overrideTokens: overrideTokens,
|
|
27506
|
+
pickTokens: pickTokens,
|
|
27507
|
+
omitTokens: omitTokens,
|
|
27508
|
+
// Color Utilities
|
|
27509
|
+
hexToRgb: hexToRgb$1,
|
|
27510
|
+
rgbToHex: rgbToHex,
|
|
27511
|
+
getLuminance: getLuminance,
|
|
27512
|
+
getContrastRatio: getContrastRatio,
|
|
27513
|
+
isAccessible: isAccessible,
|
|
27514
|
+
getContrastText: getContrastText,
|
|
27515
|
+
lighten: lighten,
|
|
27516
|
+
darken: darken,
|
|
27517
|
+
alpha: alpha,
|
|
27518
|
+
emphasize: emphasize,
|
|
27519
|
+
createSpacing: createSpacing,
|
|
27520
|
+
// Performance utilities
|
|
27521
|
+
createPerformanceMonitor: createPerformanceMonitor,
|
|
27522
|
+
usePerformanceMonitor: usePerformanceMonitor,
|
|
27523
|
+
// Responsive utilities
|
|
27524
|
+
createResponsiveUtil: createResponsiveUtil,
|
|
27525
|
+
useResponsive: useResponsive,
|
|
27526
|
+
// Components
|
|
27527
|
+
ThemeToggle: ThemeToggle,
|
|
27528
|
+
ThemeApplicator: ThemeApplicator,
|
|
27529
|
+
applyTheme: applyTheme,
|
|
27530
|
+
getThemeApplicator: getThemeApplicator,
|
|
27531
|
+
// Registry
|
|
27532
|
+
createThemeRegistry: createThemeRegistry,
|
|
27533
|
+
registerTheme: registerTheme,
|
|
27534
|
+
unregisterTheme: unregisterTheme,
|
|
27535
|
+
hasTheme: hasTheme,
|
|
27536
|
+
getTheme: getTheme,
|
|
27537
|
+
getAllThemes: getAllThemes,
|
|
27538
|
+
getThemeIds: getThemeIds,
|
|
27539
|
+
clearThemes: clearThemes,
|
|
27540
|
+
getThemeCount: getThemeCount,
|
|
27541
|
+
// Composition
|
|
27542
|
+
deepMerge: deepMerge,
|
|
27543
|
+
mergeTheme: mergeTheme,
|
|
27544
|
+
extendTheme: extendTheme,
|
|
27545
|
+
// Tokens
|
|
27546
|
+
createTokens: createTokens,
|
|
27547
|
+
defaultTokens: defaultTokens,
|
|
27548
|
+
// Generators
|
|
27549
|
+
generateCSSVariables: generateCSSVariables$1,
|
|
27550
|
+
generateCSSVariablesForSelector: generateCSSVariablesForSelector,
|
|
27551
|
+
// Naming
|
|
27552
|
+
generateClassName: generateClassName,
|
|
27553
|
+
generateCSSVariableName: generateCSSVariableName,
|
|
27554
|
+
normalizeThemeTokens: normalizeThemeTokens,
|
|
27555
|
+
camelToKebab: camelToKebab,
|
|
27556
|
+
themePropertyToCSSVar: themePropertyToCSSVar,
|
|
27557
|
+
// Component Theming
|
|
27558
|
+
getComponentThemeValue: getComponentThemeValue,
|
|
27559
|
+
generateComponentCSSVars: generateComponentCSSVars,
|
|
27560
|
+
applyComponentTheme: applyComponentTheme,
|
|
27561
|
+
useComponentTheme: useComponentTheme,
|
|
27562
|
+
// Hooks
|
|
27563
|
+
useThemeSwitcher: useThemeSwitcher,
|
|
27564
|
+
// Helpers
|
|
27565
|
+
isDesignTokens: isDesignTokens,
|
|
27566
|
+
// CSS Variable Mapper
|
|
27567
|
+
mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
|
|
27568
|
+
applyCSSVariables: applyCSSVariables,
|
|
27569
|
+
removeCSSVariables: removeCSSVariables,
|
|
27570
|
+
getCSSVariable: getCSSVariable,
|
|
27571
|
+
cssVarsToStyle: cssVarsToStyle,
|
|
27572
|
+
mergeCSSVars: mergeCSSVars,
|
|
27573
|
+
isValidCSSVariableName: isValidCSSVariableName,
|
|
27574
|
+
extractComponentName: extractComponentName,
|
|
27575
|
+
// Injection Utils
|
|
27576
|
+
injectCSS: injectCSS$1,
|
|
27577
|
+
removeCSS: removeCSS,
|
|
27578
|
+
isCSSInjected: isCSSInjected,
|
|
27579
|
+
// I18n
|
|
27580
|
+
RTLManager: RTLManager,
|
|
27581
|
+
createRTLManager: createRTLManager,
|
|
27582
|
+
isRTLLocale: isRTLLocale,
|
|
27583
|
+
getDirectionFromLocale: getDirectionFromLocale,
|
|
27584
|
+
rtlCSS: rtlCSS
|
|
27585
|
+
};
|
|
27586
|
+
|
|
25844
27587
|
/**
|
|
25845
27588
|
* CSS Variables Constants
|
|
25846
27589
|
*
|
|
@@ -26147,6 +27890,122 @@ function mergePartStyles(base, override) {
|
|
|
26147
27890
|
* );
|
|
26148
27891
|
* }
|
|
26149
27892
|
*/
|
|
27893
|
+
/**
|
|
27894
|
+
* Configuration Validator
|
|
27895
|
+
*
|
|
27896
|
+
* Provides detailed validation and feedback for Atomix configurations,
|
|
27897
|
+
* especially for advanced features (Phases 2, 3, and 4).
|
|
27898
|
+
*/
|
|
27899
|
+
/**
|
|
27900
|
+
* Validate an Atomix configuration with detailed feedback
|
|
27901
|
+
*
|
|
27902
|
+
* @param config - The configuration to validate
|
|
27903
|
+
* @param options - Validation options
|
|
27904
|
+
* @returns Detailed validation result
|
|
27905
|
+
*
|
|
27906
|
+
* @example
|
|
27907
|
+
* ```typescript
|
|
27908
|
+
* import { validateConfiguration } from '@shohojdhara/atomix/config';
|
|
27909
|
+
*
|
|
27910
|
+
* const config = { /* your config *\/ };
|
|
27911
|
+
* const result = validateConfiguration(config);
|
|
27912
|
+
*
|
|
27913
|
+
* if (!result.isValid) {
|
|
27914
|
+
* console.warn('Warnings:', result.warnings);
|
|
27915
|
+
* console.info('Suggestions:', result.suggestions);
|
|
27916
|
+
* }
|
|
27917
|
+
* ```
|
|
27918
|
+
*/
|
|
27919
|
+
function validateConfiguration(config, options) {
|
|
27920
|
+
const {performanceAnalysis: performanceAnalysis = !0, compatibilityReport: compatibilityReport = !0} = options || {}, warnings = [], suggestions = [];
|
|
27921
|
+
let performanceImpact = "low";
|
|
27922
|
+
// Use the existing validation
|
|
27923
|
+
const baseWarnings = validateConfig$1(config);
|
|
27924
|
+
warnings.push(...baseWarnings),
|
|
27925
|
+
// Analyze advanced features for performance impact
|
|
27926
|
+
performanceAnalysis && (performanceImpact =
|
|
27927
|
+
/**
|
|
27928
|
+
* Analyze the performance impact of a configuration
|
|
27929
|
+
*/
|
|
27930
|
+
function(config) {
|
|
27931
|
+
let impactScore = 0;
|
|
27932
|
+
// Analyze interactive effects
|
|
27933
|
+
if (config.interactiveEffects) {
|
|
27934
|
+
const ie = config.interactiveEffects;
|
|
27935
|
+
ie.vortex?.enabled && (impactScore += 2), ie.chromaticAberration?.enabled && (impactScore += 1),
|
|
27936
|
+
ie.mouseInteraction?.trailEffect && (impactScore += 1), ie.mouseInteraction?.pressureSensitivity && (impactScore += 1);
|
|
27937
|
+
}
|
|
27938
|
+
// Analyze visual polish effects
|
|
27939
|
+
if (config.visualPolish) {
|
|
27940
|
+
const vp = config.visualPolish;
|
|
27941
|
+
vp.borders?.iridescentGlow && (impactScore += 1), vp.borders?.shimmerEffect && (impactScore += 1),
|
|
27942
|
+
vp.contentAwareBlur?.enabled && (impactScore += 2), vp.holographicEffects?.enabled && (impactScore += 2),
|
|
27943
|
+
vp.holographicEffects?.scanlineAnimation && (impactScore += 1), vp.holographicEffects?.dataStream && (impactScore += 1),
|
|
27944
|
+
vp.holographicEffects?.pulseRings && (impactScore += 1);
|
|
27945
|
+
}
|
|
27946
|
+
// Analyze optimization settings
|
|
27947
|
+
return config.optimization?.autoScaling?.enabled && (impactScore -= 1),
|
|
27948
|
+
impactScore >= 6 ? "high" : impactScore >= 3 ? "medium" : "low";
|
|
27949
|
+
}
|
|
27950
|
+
/**
|
|
27951
|
+
* Generate suggestions based on the configuration
|
|
27952
|
+
*/ (config)),
|
|
27953
|
+
// Generate suggestions based on configuration
|
|
27954
|
+
function(config, suggestions) {
|
|
27955
|
+
// Suggest enabling performance optimizations if heavy effects are used
|
|
27956
|
+
(config.interactiveEffects || config.visualPolish?.holographicEffects?.enabled) && (config.optimization?.autoScaling?.enabled || suggestions.push("Consider enabling auto-scaling in optimization settings to adjust effects based on device performance: optimization.autoScaling.enabled = true"),
|
|
27957
|
+
config.optimization?.performance?.fpsTarget || suggestions.push("Set a target FPS in optimization.performance.fpsTarget to ensure smooth performance when using interactive effects")),
|
|
27958
|
+
// Suggest responsive breakpoints if optimization is partially configured
|
|
27959
|
+
config.optimization && !config.optimization.responsive && suggestions.push("Consider adding responsive breakpoints in optimization.responsive.breakpoints to adapt advanced effects based on device type"),
|
|
27960
|
+
// Suggest disabling heavy effects on lower-end devices
|
|
27961
|
+
config.visualPolish?.holographicEffects?.enabled && suggestions.push("For better performance on lower-end devices, consider conditionally disabling holographic effects based on device capabilities"),
|
|
27962
|
+
// Suggest using content-aware blur with performance considerations
|
|
27963
|
+
config.visualPolish?.contentAwareBlur?.enabled && suggestions.push("Content-aware blur can be expensive; consider setting a maximum blur radius or using simpler blur techniques for mobile devices"),
|
|
27964
|
+
// Suggest using chromatic aberration适度
|
|
27965
|
+
config.interactiveEffects?.chromaticAberration?.enabled && (config.interactiveEffects.chromaticAberration.redShift && Math.abs(config.interactiveEffects.chromaticAberration.redShift) > .05 && suggestions.push("High chromatic aberration red shift values (>0.05) may cause discomfort for some users; consider reducing to improve accessibility"),
|
|
27966
|
+
config.interactiveEffects.chromaticAberration.blueShift && Math.abs(config.interactiveEffects.chromaticAberration.blueShift) > .05 && suggestions.push("High chromatic aberration blue shift values (>0.05) may cause discomfort for some users; consider reducing to improve accessibility"));
|
|
27967
|
+
}
|
|
27968
|
+
/**
|
|
27969
|
+
* Generate a compatibility report for the configuration
|
|
27970
|
+
*/ (config, suggestions);
|
|
27971
|
+
// Determine overall validity
|
|
27972
|
+
const isValid = 0 === warnings.length, compatibility = compatibilityReport ? function(config) {
|
|
27973
|
+
return {
|
|
27974
|
+
browsers: !(config.visualPolish?.holographicEffects?.enabled || config.visualPolish?.contentAwareBlur?.enabled || config.interactiveEffects?.vortex?.enabled || config.interactiveEffects?.chromaticAberration?.enabled),
|
|
27975
|
+
// May have issues on older browsers
|
|
27976
|
+
ssr: !0,
|
|
27977
|
+
// Works fine with SSR
|
|
27978
|
+
frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
|
|
27979
|
+
};
|
|
27980
|
+
}
|
|
27981
|
+
/**
|
|
27982
|
+
* Print a detailed configuration report to the console
|
|
27983
|
+
*
|
|
27984
|
+
* @param config - The configuration to analyze
|
|
27985
|
+
* @param title - Optional title for the report
|
|
27986
|
+
*
|
|
27987
|
+
* @example
|
|
27988
|
+
* ```typescript
|
|
27989
|
+
* import { printConfigReport } from '@shohojdhara/atomix/config';
|
|
27990
|
+
*
|
|
27991
|
+
* const config = { /* your config *\/ };
|
|
27992
|
+
* printConfigReport(config, 'My Application Config');
|
|
27993
|
+
* ```
|
|
27994
|
+
*/ (config) : {
|
|
27995
|
+
browsers: !0,
|
|
27996
|
+
ssr: !0,
|
|
27997
|
+
frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
|
|
27998
|
+
};
|
|
27999
|
+
// Generate compatibility report
|
|
28000
|
+
return {
|
|
28001
|
+
isValid: isValid,
|
|
28002
|
+
warnings: warnings,
|
|
28003
|
+
suggestions: suggestions,
|
|
28004
|
+
performanceImpact: performanceImpact,
|
|
28005
|
+
compatibility: compatibility
|
|
28006
|
+
};
|
|
28007
|
+
}
|
|
28008
|
+
|
|
26150
28009
|
// Import and re-export as namespaces with proper typing
|
|
26151
28010
|
// Export as namespaces with explicit typing
|
|
26152
28011
|
const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
|
|
@@ -26161,19 +28020,30 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
|
|
|
26161
28020
|
ThemeLiveEditor: ThemeLiveEditor,
|
|
26162
28021
|
ThemePreview: ThemePreview,
|
|
26163
28022
|
ThemeProvider: ThemeProvider,
|
|
28023
|
+
ThemeToggle: ThemeToggle,
|
|
26164
28024
|
ThemeValidator: ThemeValidator,
|
|
28025
|
+
alpha: alpha,
|
|
26165
28026
|
applyCSSVariables: applyCSSVariables,
|
|
26166
28027
|
applyComponentTheme: applyComponentTheme,
|
|
26167
28028
|
applyTheme: applyTheme,
|
|
26168
28029
|
camelToKebab: camelToKebab,
|
|
28030
|
+
clearThemePreference: clearThemePreference,
|
|
26169
28031
|
clearThemes: clearThemes,
|
|
28032
|
+
configToTokens: configToTokens,
|
|
28033
|
+
createPerformanceMonitor: createPerformanceMonitor,
|
|
28034
|
+
createRTLManager: createRTLManager,
|
|
28035
|
+
createResponsiveUtil: createResponsiveUtil,
|
|
28036
|
+
createSpacing: createSpacing,
|
|
26170
28037
|
createTheme: createTheme,
|
|
26171
28038
|
createThemeRegistry: createThemeRegistry,
|
|
26172
28039
|
createTokens: createTokens,
|
|
26173
28040
|
cssVarsToStyle: cssVarsToStyle,
|
|
28041
|
+
darken: darken,
|
|
26174
28042
|
deepMerge: deepMerge,
|
|
28043
|
+
default: index,
|
|
26175
28044
|
defaultTokens: defaultTokens,
|
|
26176
28045
|
designTokensToCSSVars: designTokensToCSSVars,
|
|
28046
|
+
emphasize: emphasize,
|
|
26177
28047
|
extendTheme: extendTheme,
|
|
26178
28048
|
extractComponentName: extractComponentName,
|
|
26179
28049
|
generateCSSVariableName: generateCSSVariableName,
|
|
@@ -26184,29 +28054,53 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
|
|
|
26184
28054
|
getAllThemes: getAllThemes,
|
|
26185
28055
|
getCSSVariable: getCSSVariable,
|
|
26186
28056
|
getComponentThemeValue: getComponentThemeValue,
|
|
28057
|
+
getContrastRatio: getContrastRatio,
|
|
28058
|
+
getContrastText: getContrastText,
|
|
28059
|
+
getCurrentTheme: getCurrentTheme,
|
|
28060
|
+
getDirectionFromLocale: getDirectionFromLocale,
|
|
28061
|
+
getLuminance: getLuminance,
|
|
28062
|
+
getSystemTheme: getSystemTheme,
|
|
26187
28063
|
getTheme: getTheme,
|
|
26188
28064
|
getThemeApplicator: getThemeApplicator,
|
|
26189
28065
|
getThemeCount: getThemeCount,
|
|
26190
28066
|
getThemeIds: getThemeIds,
|
|
26191
28067
|
hasTheme: hasTheme,
|
|
28068
|
+
hexToRgb: hexToRgb$1,
|
|
28069
|
+
initializeTheme: initializeTheme,
|
|
26192
28070
|
injectCSS: injectCSS$1,
|
|
26193
28071
|
injectTheme: injectTheme,
|
|
28072
|
+
isAccessible: isAccessible,
|
|
26194
28073
|
isCSSInjected: isCSSInjected,
|
|
26195
28074
|
isDesignTokens: isDesignTokens,
|
|
28075
|
+
isRTLLocale: isRTLLocale,
|
|
26196
28076
|
isValidCSSVariableName: isValidCSSVariableName,
|
|
28077
|
+
lighten: lighten,
|
|
28078
|
+
listenToSystemTheme: listenToSystemTheme,
|
|
26197
28079
|
mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
|
|
26198
28080
|
mergeCSSVars: mergeCSSVars,
|
|
26199
28081
|
mergeTheme: mergeTheme,
|
|
28082
|
+
mergeTokens: mergeTokens,
|
|
26200
28083
|
normalizeThemeTokens: normalizeThemeTokens,
|
|
28084
|
+
omitTokens: omitTokens,
|
|
28085
|
+
overrideTokens: overrideTokens,
|
|
28086
|
+
persistTheme: persistTheme,
|
|
28087
|
+
pickTokens: pickTokens,
|
|
26201
28088
|
registerTheme: registerTheme,
|
|
26202
28089
|
removeCSS: removeCSS,
|
|
26203
28090
|
removeCSSVariables: removeCSSVariables,
|
|
26204
28091
|
removeTheme: removeTheme,
|
|
28092
|
+
rgbToHex: rgbToHex,
|
|
28093
|
+
rtlCSS: rtlCSS,
|
|
28094
|
+
switchTheme: switchTheme,
|
|
26205
28095
|
themePropertyToCSSVar: themePropertyToCSSVar,
|
|
28096
|
+
toggleTheme: toggleTheme,
|
|
26206
28097
|
unregisterTheme: unregisterTheme,
|
|
26207
28098
|
useComponentTheme: useComponentTheme,
|
|
26208
28099
|
useHistory: useHistory,
|
|
28100
|
+
usePerformanceMonitor: usePerformanceMonitor,
|
|
28101
|
+
useResponsive: useResponsive,
|
|
26209
28102
|
useTheme: useTheme,
|
|
28103
|
+
useThemeSwitcher: useThemeSwitcher,
|
|
26210
28104
|
useThemeTokens: useThemeTokens
|
|
26211
28105
|
}), atomix = {
|
|
26212
28106
|
// Re-export all components and utilities
|
|
@@ -26274,10 +28168,11 @@ exports.TYPEDBUTTON = TYPEDBUTTON, exports.Tabs = Tabs, exports.Testimonial = Te
|
|
|
26274
28168
|
exports.Textarea = Textarea, exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
|
|
26275
28169
|
exports.ThemeContext = ThemeContext, exports.ThemeErrorBoundary = ThemeErrorBoundary,
|
|
26276
28170
|
exports.ThemeInspector = ThemeInspector, exports.ThemeLiveEditor = ThemeLiveEditor,
|
|
26277
|
-
exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.
|
|
26278
|
-
exports.
|
|
26279
|
-
exports.
|
|
26280
|
-
exports.
|
|
28171
|
+
exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeToggle = ThemeToggle,
|
|
28172
|
+
exports.ThemeValidator = ThemeValidator, exports.Todo = Todo, exports.Toggle = Toggle,
|
|
28173
|
+
exports.Tooltip = Tooltip, exports.TreemapChart = TreemapChart, exports.UPLOAD = UPLOAD,
|
|
28174
|
+
exports.Upload = Upload, exports.VIDEO_PLAYER = VIDEO_PLAYER, exports.VideoPlayer = VideoPlayer,
|
|
28175
|
+
exports.WaterfallChart = WaterfallChart, exports.alpha = alpha, exports.applyCSSVariables = applyCSSVariables,
|
|
26281
28176
|
exports.applyCSSVarsToStyle =
|
|
26282
28177
|
/**
|
|
26283
28178
|
* Utility to apply CSS variables to style object
|
|
@@ -26291,60 +28186,16 @@ function(cssVars, baseStyle) {
|
|
|
26291
28186
|
};
|
|
26292
28187
|
}
|
|
26293
28188
|
/**
|
|
26294
|
-
*
|
|
26295
|
-
*
|
|
26296
|
-
* Tailwind-like configuration for customizing the Atomix Design System.
|
|
26297
|
-
*
|
|
26298
|
-
* External developers can create `atomix.config.ts` in their project root
|
|
26299
|
-
* to customize design tokens, similar to Tailwind's tailwind.config.js
|
|
26300
|
-
*
|
|
26301
|
-
* @example
|
|
26302
|
-
* ```typescript
|
|
26303
|
-
* // atomix.config.ts (in your project)
|
|
26304
|
-
* import { defineConfig } from '@shohojdhara/atomix/config';
|
|
26305
|
-
*
|
|
26306
|
-
* export default defineConfig({
|
|
26307
|
-
* theme: {
|
|
26308
|
-
* extend: {
|
|
26309
|
-
* colors: {
|
|
26310
|
-
* primary: { main: '#7AFFD7' },
|
|
26311
|
-
* },
|
|
26312
|
-
* },
|
|
26313
|
-
* },
|
|
26314
|
-
* });
|
|
26315
|
-
* ```
|
|
26316
|
-
*/
|
|
26317
|
-
/**
|
|
26318
|
-
* Helper function to define Atomix configuration with type safety
|
|
28189
|
+
* Configuration Types
|
|
26319
28190
|
*
|
|
26320
|
-
*
|
|
26321
|
-
* @returns The configuration object
|
|
28191
|
+
* Type definitions for the Atomix configuration system.
|
|
26322
28192
|
*/
|
|
26323
28193
|
/**
|
|
26324
28194
|
* Helper function to define Atomix configuration with type safety
|
|
26325
|
-
*
|
|
26326
|
-
* Similar to Tailwind's defineConfig, provides autocomplete and type checking.
|
|
26327
|
-
*
|
|
26328
|
-
* @param config - Atomix configuration object
|
|
26329
|
-
* @returns The configuration object
|
|
26330
|
-
*
|
|
26331
|
-
* @example
|
|
26332
|
-
* ```typescript
|
|
26333
|
-
* import { defineConfig } from '@shohojdhara/atomix/config';
|
|
26334
|
-
*
|
|
26335
|
-
* export default defineConfig({
|
|
26336
|
-
* theme: {
|
|
26337
|
-
* extend: {
|
|
26338
|
-
* colors: {
|
|
26339
|
-
* primary: { main: '#7AFFD7' },
|
|
26340
|
-
* },
|
|
26341
|
-
* },
|
|
26342
|
-
* },
|
|
26343
|
-
* });
|
|
26344
|
-
* ```
|
|
26345
28195
|
*/ , exports.applyComponentTheme = applyComponentTheme, exports.applyPartStyles = applyPartStyles,
|
|
26346
|
-
exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.
|
|
26347
|
-
exports.
|
|
28196
|
+
exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemePreference = clearThemePreference,
|
|
28197
|
+
exports.clearThemes = clearThemes, exports.composables = composables, exports.configToTokens = configToTokens,
|
|
28198
|
+
exports.constants = constants, exports.createBreakpoints = createBreakpoints$1,
|
|
26348
28199
|
exports.createCSSVarStyle = createCSSVarStyle, exports.createDarkVariant =
|
|
26349
28200
|
/**
|
|
26350
28201
|
* Create a dark theme variant from a light theme
|
|
@@ -26401,7 +28252,9 @@ function(lightTheme) {
|
|
|
26401
28252
|
/**
|
|
26402
28253
|
* Validate theme structure
|
|
26403
28254
|
*/ , exports.createDebugAttrs = createDebugAttrs, exports.createFontPreloadLink = createFontPreloadLink,
|
|
26404
|
-
exports.createPartProps = createPartProps, exports.
|
|
28255
|
+
exports.createPartProps = createPartProps, exports.createPerformanceMonitor = createPerformanceMonitor,
|
|
28256
|
+
exports.createRTLManager = createRTLManager, exports.createResponsiveUtil = createResponsiveUtil,
|
|
28257
|
+
exports.createSlotComponent =
|
|
26405
28258
|
/**
|
|
26406
28259
|
* Create a slot wrapper component
|
|
26407
28260
|
*
|
|
@@ -26439,11 +28292,13 @@ function(defaultElement = "div") {
|
|
|
26439
28292
|
}
|
|
26440
28293
|
/**
|
|
26441
28294
|
* Hook to manage slot rendering
|
|
26442
|
-
*/ , exports.
|
|
26443
|
-
exports.
|
|
28295
|
+
*/ , exports.createSpacing = createSpacing, exports.createTheme = createTheme,
|
|
28296
|
+
exports.createThemeRegistry = createThemeRegistry, exports.createTokens = createTokens,
|
|
28297
|
+
exports.cssVarsToStyle = cssVarsToStyle, exports.darken = darken, exports.deepMerge = deepMerge,
|
|
26444
28298
|
exports.default = atomix, exports.defaultTokens = defaultTokens, exports.defineConfig = function(config) {
|
|
26445
28299
|
return config;
|
|
26446
|
-
}, exports.designTokensToCSSVars = designTokensToCSSVars, exports.
|
|
28300
|
+
}, exports.designTokensToCSSVars = designTokensToCSSVars, exports.emphasize = emphasize,
|
|
28301
|
+
exports.exportTheme =
|
|
26447
28302
|
/**
|
|
26448
28303
|
* Export theme as JSON
|
|
26449
28304
|
*/
|
|
@@ -26463,9 +28318,12 @@ exports.getAllThemes = getAllThemes, exports.getCSSVariable = getCSSVariable, ex
|
|
|
26463
28318
|
*/
|
|
26464
28319
|
function(component) {
|
|
26465
28320
|
return COMPONENT_CSS_VARS[component];
|
|
26466
|
-
}, exports.getComponentThemeValue = getComponentThemeValue, exports.
|
|
26467
|
-
exports.
|
|
26468
|
-
exports.
|
|
28321
|
+
}, exports.getComponentThemeValue = getComponentThemeValue, exports.getContrastRatio = getContrastRatio,
|
|
28322
|
+
exports.getContrastText = getContrastText, exports.getCurrentTheme = getCurrentTheme,
|
|
28323
|
+
exports.getDefaultBreakpoints = getDefaultBreakpoints, exports.getDevicePreset = getDevicePreset,
|
|
28324
|
+
exports.getDirectionFromLocale = getDirectionFromLocale, exports.getLuminance = getLuminance,
|
|
28325
|
+
exports.getMobileOptimizedParams = getMobileOptimizedParams, exports.getPartStyles = getPartStyles,
|
|
28326
|
+
exports.getQualityMultipliers = getQualityMultipliers, exports.getSystemTheme = getSystemTheme,
|
|
26469
28327
|
exports.getTheme = getTheme, exports.getThemeApplicator = getThemeApplicator, exports.getThemeCount = getThemeCount,
|
|
26470
28328
|
exports.getThemeIds = getThemeIds, exports.getThemeMetadata =
|
|
26471
28329
|
/**
|
|
@@ -26486,7 +28344,7 @@ function(theme) {
|
|
|
26486
28344
|
/**
|
|
26487
28345
|
* Check if theme supports dark mode
|
|
26488
28346
|
*/ , exports.hasCustomization = hasCustomization, exports.hasTheme = hasTheme,
|
|
26489
|
-
exports.importTheme = function(json) {
|
|
28347
|
+
exports.hexToRgb = hexToRgb$1, exports.importTheme = function(json) {
|
|
26490
28348
|
try {
|
|
26491
28349
|
return JSON.parse(json);
|
|
26492
28350
|
} catch (error) {
|
|
@@ -26497,15 +28355,49 @@ exports.importTheme = function(json) {
|
|
|
26497
28355
|
// are already exported from './theme' module. Import them directly from there.
|
|
26498
28356
|
// This file only exports theme-tools specific utilities.
|
|
26499
28357
|
// Export all components individually for better tree-shaking
|
|
26500
|
-
, exports.
|
|
26501
|
-
exports.
|
|
28358
|
+
, exports.initializeTheme = initializeTheme, exports.injectCSS = injectCSS$1, exports.injectTheme = injectTheme,
|
|
28359
|
+
exports.isAccessible = isAccessible, exports.isCSSInjected = isCSSInjected, exports.isDesignTokens = isDesignTokens,
|
|
28360
|
+
exports.isRTLLocale = isRTLLocale, exports.isSlot = function(value) {
|
|
26502
28361
|
return "object" == typeof value && null !== value && ("render" in value || "component" in value || "children" in value);
|
|
26503
28362
|
}
|
|
26504
28363
|
/**
|
|
26505
28364
|
* Merge multiple slot configurations
|
|
26506
28365
|
* Later slots override earlier ones
|
|
26507
28366
|
*/ , exports.isValidCSSVariableName = isValidCSSVariableName, exports.isYouTubeUrl = isYouTubeUrl,
|
|
26508
|
-
exports.
|
|
28367
|
+
exports.lighten = lighten, exports.listenToSystemTheme = listenToSystemTheme, exports.loadAtomixConfig = loadAtomixConfig,
|
|
28368
|
+
exports.loadConfig =
|
|
28369
|
+
/**
|
|
28370
|
+
* Public API for loading and managing Atomix configuration
|
|
28371
|
+
*
|
|
28372
|
+
* This module provides the public-facing API for configuration loading
|
|
28373
|
+
* in external projects.
|
|
28374
|
+
*/
|
|
28375
|
+
/**
|
|
28376
|
+
* Load Atomix configuration from an external project.
|
|
28377
|
+
*
|
|
28378
|
+
* @param options - Loading options
|
|
28379
|
+
* @returns The loaded configuration
|
|
28380
|
+
*
|
|
28381
|
+
* @example
|
|
28382
|
+
* ```typescript
|
|
28383
|
+
* import { loadConfig } from '@shohojdhara/atomix/config';
|
|
28384
|
+
*
|
|
28385
|
+
* const config = loadConfig();
|
|
28386
|
+
* console.log(config.prefix); // 'atomix' or user's custom prefix
|
|
28387
|
+
* ```
|
|
28388
|
+
*/
|
|
28389
|
+
function(options) {
|
|
28390
|
+
return loadAtomixConfig({
|
|
28391
|
+
configPath: options?.configPath,
|
|
28392
|
+
required: options?.required ?? !1
|
|
28393
|
+
});
|
|
28394
|
+
}
|
|
28395
|
+
/**
|
|
28396
|
+
* Validate Atomix configuration structure.
|
|
28397
|
+
*
|
|
28398
|
+
* @param config - Configuration object to validate
|
|
28399
|
+
* @returns Array of validation warnings (empty if valid)
|
|
28400
|
+
*/ , exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
|
|
26509
28401
|
exports.mergeClassNames = mergeClassNames, exports.mergeComponentProps = mergeComponentProps,
|
|
26510
28402
|
exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slots) {
|
|
26511
28403
|
const filtered = slots.filter((s => void 0 !== s));
|
|
@@ -26513,8 +28405,17 @@ exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slot
|
|
|
26513
28405
|
...acc,
|
|
26514
28406
|
...slot
|
|
26515
28407
|
})));
|
|
26516
|
-
}, exports.mergeTheme = mergeTheme, exports.normalizeThemeTokens = normalizeThemeTokens,
|
|
26517
|
-
exports.
|
|
28408
|
+
}, exports.mergeTheme = mergeTheme, exports.mergeTokens = mergeTokens, exports.normalizeThemeTokens = normalizeThemeTokens,
|
|
28409
|
+
exports.omitTokens = omitTokens, exports.overrideTokens = overrideTokens, exports.persistTheme = persistTheme,
|
|
28410
|
+
exports.pickTokens = pickTokens, exports.preloadFonts = preloadFonts, exports.printConfigReport = function(config, title) {
|
|
28411
|
+
const result = validateConfiguration(config);
|
|
28412
|
+
result.warnings.length > 0 && result.warnings.forEach((warning => {})), result.suggestions.length > 0 && result.suggestions.forEach((suggestion => {}));
|
|
28413
|
+
const featuresDetected = [];
|
|
28414
|
+
config.interactiveEffects && featuresDetected.push("Interactive Effects"), config.optimization && featuresDetected.push("Optimization"),
|
|
28415
|
+
config.visualPolish && featuresDetected.push("Visual Polish"), config.ai && featuresDetected.push("AI Integration"),
|
|
28416
|
+
config.tokenEngine && featuresDetected.push("Token Engine"), config.generator && featuresDetected.push("Component Generator"),
|
|
28417
|
+
featuresDetected.length > 0 && featuresDetected.forEach((feature => {}));
|
|
28418
|
+
}, exports.quickTheme =
|
|
26518
28419
|
/**
|
|
26519
28420
|
* Quick theme creator with sensible defaults
|
|
26520
28421
|
*/
|
|
@@ -26531,11 +28432,26 @@ function(name, primaryColor, secondaryColor) {
|
|
|
26531
28432
|
}
|
|
26532
28433
|
});
|
|
26533
28434
|
}, exports.registerTheme = registerTheme, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
|
|
26534
|
-
exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.
|
|
28435
|
+
exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = function(configPath) {
|
|
28436
|
+
// In browser environments, config resolution is not possible
|
|
28437
|
+
if ("undefined" != typeof window) return null;
|
|
28438
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
28439
|
+
const {existsSync: existsSync} = require("fs"), {join: join} = require("path");
|
|
28440
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
28441
|
+
// If a specific config path is provided, check if it exists
|
|
28442
|
+
if (configPath) {
|
|
28443
|
+
const absPath = join(process.cwd(), configPath);
|
|
28444
|
+
return existsSync(absPath) ? absPath : null;
|
|
28445
|
+
}
|
|
28446
|
+
// Otherwise, check standard locations
|
|
28447
|
+
const possiblePaths = [ join(process.cwd(), "atomix.config.ts"), join(process.cwd(), "atomix.config.js"), join(process.cwd(), "atomix.config.json") ];
|
|
28448
|
+
for (const path of possiblePaths) if (existsSync(path)) return path;
|
|
28449
|
+
return null;
|
|
28450
|
+
}, exports.rgbToHex = rgbToHex, exports.rtlCSS = rtlCSS, exports.sliderConstants = sliderConstants,
|
|
26535
28451
|
exports.supportsDarkMode = function(theme) {
|
|
26536
28452
|
var _context;
|
|
26537
28453
|
return "dark" === theme.palette?.mode || !0 === theme.supportsDarkMode || Boolean((null == (_context = theme.a11y?.modes) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("dark"));
|
|
26538
|
-
}, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
|
|
28454
|
+
}, exports.switchTheme = switchTheme, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
|
|
26539
28455
|
exports.themeToCSS =
|
|
26540
28456
|
/**
|
|
26541
28457
|
* Generate CSS string from theme
|
|
@@ -26545,10 +28461,11 @@ function(theme, selector = ":root") {
|
|
|
26545
28461
|
selector: selector,
|
|
26546
28462
|
prefix: "atomix"
|
|
26547
28463
|
});
|
|
26548
|
-
}, exports.
|
|
26549
|
-
exports.
|
|
26550
|
-
exports.
|
|
26551
|
-
exports.
|
|
28464
|
+
}, exports.toggleTheme = toggleTheme, exports.types = types, exports.unregisterTheme = unregisterTheme,
|
|
28465
|
+
exports.useAccordion = useAccordion, exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge,
|
|
28466
|
+
exports.useBarChart = useBarChart, exports.useBlock = useBlock, exports.useChartData = useChartData,
|
|
28467
|
+
exports.useChartInteraction = useChartInteraction, exports.useChartScale = useChartScale,
|
|
28468
|
+
exports.useComponentCustomization = function(component, props) {
|
|
26552
28469
|
const {theme: theme} = useTheme(), cssVars = React.useMemo((() => mergeCSSVars(theme?.components?.[component]?.cssVars || {}, props.cssVars || {})), [ theme, component, props.cssVars ]), parts = React.useMemo((() => {
|
|
26553
28470
|
const themeParts = theme?.components?.[component]?.parts || {}, propParts = props.parts || {}, merged = {};
|
|
26554
28471
|
return new Set([ ...Object.keys(themeParts), ...Object.keys(propParts) ]).forEach((partName => {
|
|
@@ -26587,14 +28504,16 @@ exports.useMergedProps = function(defaultProps, props) {
|
|
|
26587
28504
|
...props
|
|
26588
28505
|
})), [ defaultProps, props ]);
|
|
26589
28506
|
}, exports.useNav = useNav, exports.useNavDropdown = useNavDropdown, exports.useNavItem = useNavItem,
|
|
26590
|
-
exports.useNavbar = useNavbar, exports.
|
|
26591
|
-
exports.
|
|
28507
|
+
exports.useNavbar = useNavbar, exports.usePieChart = usePieChart, exports.useRadio = useRadio,
|
|
28508
|
+
exports.useResponsive = useResponsive, exports.useResponsiveGlass = useResponsiveGlass,
|
|
26592
28509
|
exports.useRiver = useRiver, exports.useSelect = useSelect, exports.useSideMenu = useSideMenu,
|
|
26593
28510
|
exports.useSideMenuItem = useSideMenuItem, exports.useSlot = function(slot, props, fallback) {
|
|
26594
28511
|
return React__default.default.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
|
|
26595
28512
|
}, exports.useSpinner = useSpinner, exports.useTextarea = useTextarea, exports.useTheme = useTheme,
|
|
26596
|
-
exports.
|
|
26597
|
-
exports.
|
|
28513
|
+
exports.useThemeSwitcher = useThemeSwitcher, exports.useThemeTokens = useThemeTokens,
|
|
28514
|
+
exports.useTodo = useTodo, exports.utils = utils, exports.validateConfig = function(config) {
|
|
28515
|
+
return validateConfig$1(config);
|
|
28516
|
+
}, exports.validateConfiguration = validateConfiguration, exports.validateTheme = function(theme) {
|
|
26598
28517
|
const errors = [];
|
|
26599
28518
|
return theme.name || errors.push("Theme must have a name"), theme.palette || errors.push("Theme must have a palette"),
|
|
26600
28519
|
theme.palette && !theme.palette.primary && errors.push("Theme palette must have a primary color"),
|