@shohojdhara/atomix 0.5.1 → 0.5.4
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 +45 -33
- package/build-tools/webpack-loader.js +5 -4
- package/dist/atomix.css +138 -17
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/build-tools/webpack-loader.js +5 -4
- package/dist/charts.d.ts +23 -23
- package/dist/charts.js +40 -37
- package/dist/charts.js.map +1 -1
- package/dist/config.d.ts +699 -0
- package/dist/config.js +17 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +2 -2
- package/dist/core.js +111 -50
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +3 -6
- package/dist/forms.js +2 -2
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +1 -1
- package/dist/heavy.js +173 -111
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +1881 -790
- package/dist/index.esm.js +2713 -816
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2693 -780
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/layout.js +59 -60
- package/dist/layout.js.map +1 -1
- package/dist/theme.d.ts +1390 -276
- package/dist/theme.js +2133 -625
- package/dist/theme.js.map +1 -1
- package/package.json +14 -9
- package/scripts/atomix-cli.js +15 -1
- package/scripts/cli/__tests__/complexity-utils.test.js +24 -0
- package/scripts/cli/__tests__/detector.test.js +50 -0
- package/scripts/cli/__tests__/template-engine.test.js +23 -0
- package/scripts/cli/__tests__/test-setup.js +3 -0
- package/scripts/cli/commands/doctor.js +15 -3
- package/scripts/cli/commands/generate.js +113 -51
- package/scripts/cli/internal/ai-engine.js +30 -10
- package/scripts/cli/internal/complexity-utils.js +60 -0
- package/scripts/cli/internal/component-validator.js +49 -16
- package/scripts/cli/internal/config-loader.js +30 -20
- package/scripts/cli/internal/generator.js +89 -36
- package/scripts/cli/internal/hook-generator.js +5 -2
- package/scripts/cli/internal/itcss-generator.js +16 -12
- package/scripts/cli/templates/next-templates.js +81 -30
- package/scripts/cli/templates/storybook-templates.js +12 -2
- package/scripts/cli/utils/detector.js +45 -7
- package/scripts/cli/utils/diagnostics.js +78 -0
- package/scripts/cli/utils/telemetry.js +13 -0
- package/src/components/Accordion/Accordion.stories.tsx +4 -0
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +219 -0
- package/src/components/AtomixGlass/glass-utils.ts +1 -1
- package/src/components/Button/Button.tsx +114 -57
- package/src/components/Callout/Callout.tsx +4 -4
- package/src/components/Chart/ChartRenderer.tsx +1 -1
- package/src/components/Chart/DonutChart.tsx +11 -8
- package/src/components/EdgePanel/EdgePanel.tsx +119 -115
- package/src/components/Form/Select.tsx +4 -4
- package/src/components/List/List.tsx +4 -4
- package/src/components/Navigation/SideMenu/SideMenu.tsx +6 -6
- package/src/components/PhotoViewer/PhotoViewerImage.tsx +1 -1
- package/src/components/ProductReview/ProductReview.tsx +4 -2
- package/src/components/Rating/Rating.tsx +4 -2
- package/src/components/SectionIntro/SectionIntro.tsx +4 -2
- package/src/components/Steps/Steps.tsx +1 -1
- package/src/components/Tabs/Tabs.tsx +5 -5
- package/src/components/Testimonial/Testimonial.tsx +4 -2
- package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
- package/src/layouts/CssGrid/CssGrid.stories.tsx +464 -0
- package/src/layouts/CssGrid/CssGrid.tsx +215 -0
- package/src/layouts/CssGrid/index.ts +8 -0
- package/src/layouts/CssGrid/scripts/CssGrid.js +284 -0
- package/src/layouts/CssGrid/scripts/index.js +43 -0
- package/src/layouts/Grid/scripts/Container.js +139 -0
- package/src/layouts/Grid/scripts/Grid.js +184 -0
- package/src/layouts/Grid/scripts/GridCol.js +273 -0
- package/src/layouts/Grid/scripts/Row.js +154 -0
- package/src/layouts/Grid/scripts/index.js +48 -0
- package/src/layouts/MasonryGrid/MasonryGrid.tsx +71 -59
- package/src/lib/composables/atomix-glass/useGlassSize.ts +1 -1
- package/src/lib/composables/useAccordion.ts +5 -5
- package/src/lib/composables/useAtomixGlass.ts +3 -3
- package/src/lib/composables/useBarChart.ts +2 -2
- package/src/lib/composables/useChart.ts +3 -2
- package/src/lib/composables/useChartToolbar.ts +48 -66
- package/src/lib/composables/useDataTable.ts +1 -1
- package/src/lib/composables/useDatePicker.ts +2 -2
- package/src/lib/composables/useEdgePanel.ts +45 -54
- package/src/lib/composables/useHeroBackgroundSlider.ts +5 -5
- package/src/lib/composables/usePhotoViewer.ts +2 -3
- package/src/lib/composables/usePieChart.ts +1 -1
- package/src/lib/composables/usePopover.ts +151 -139
- package/src/lib/composables/useSideMenu.ts +28 -41
- package/src/lib/composables/useSlider.ts +2 -6
- package/src/lib/composables/useTooltip.ts +2 -2
- package/src/lib/config/index.ts +38 -323
- package/src/lib/config/loader.ts +419 -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/devtools/Comparator.tsx +1 -1
- package/src/lib/theme/devtools/Inspector.tsx +1 -1
- package/src/lib/theme/devtools/LiveEditor.tsx +1 -1
- package/src/lib/theme/hooks/useThemeSwitcher.ts +164 -0
- package/src/lib/theme/index.ts +322 -38
- package/src/lib/theme/runtime/ThemeProvider.tsx +45 -11
- 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/_index.scss +1 -0
- package/src/styles/01-settings/_settings.atomix-glass.scss +174 -0
- package/src/styles/01-settings/_settings.masonry-grid.scss +42 -6
- package/src/styles/02-tools/_tools.glass.scss +6 -0
- package/src/styles/05-objects/_objects.masonry-grid.scss +162 -24
- package/src/styles/06-components/_components.atomix-glass.scss +4 -4
- package/src/lib/composables/useBreadcrumb.ts +0 -81
- package/src/lib/composables/useChartInteractions.ts +0 -123
- package/src/lib/composables/useChartPerformance.ts +0 -347
- package/src/lib/composables/useDropdown.ts +0 -338
- package/src/lib/composables/useModal.ts +0 -110
- package/src/lib/hooks/usePerformanceMonitor.ts +0 -148
- package/src/lib/utils/displacement-generator.ts +0 -92
- package/src/lib/utils/memoryMonitor.ts +0 -191
- package/src/styles/01-settings/_settings.testtypecheck.scss +0 -53
- package/src/styles/01-settings/_settings.typedbutton.scss +0 -53
- package/src/styles/06-components/_components.testbutton.scss +0 -212
- package/src/styles/06-components/_components.testtypecheck.scss +0 -212
- package/src/styles/06-components/_components.typedbutton.scss +0 -212
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: !0
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
-
var jsxRuntime = require("react/jsx-runtime"), React = require("react"), PhosphorIcons = require("@phosphor-icons/react"), reactDom = require("react-dom");
|
|
7
|
+
var jsxRuntime = require("react/jsx-runtime"), React = require("react"), PhosphorIcons = require("@phosphor-icons/react"), reactDom = require("react-dom"), fs = require("fs"), path$4 = require("path");
|
|
8
8
|
|
|
9
9
|
function _interopDefaultCompat(e) {
|
|
10
10
|
return e && "object" == typeof e && "default" in e ? e : {
|
|
@@ -1988,19 +1988,19 @@ function useAccordion(initialProps) {
|
|
|
1988
1988
|
disabled: !1,
|
|
1989
1989
|
iconPosition: "right",
|
|
1990
1990
|
...initialProps
|
|
1991
|
-
}, isControlled = "boolean" == typeof defaultProps.isOpen, [internalOpen, setInternalOpen] = React.useState(defaultProps.defaultOpen || !1), isOpen = isControlled ? defaultProps.isOpen : internalOpen, [panelHeight, setPanelHeight] = React.useState(isOpen ? "auto" : "0px"), panelRef = React.useRef(null), contentRef = React.useRef(null), updatePanelHeight = () => {
|
|
1991
|
+
}, isControlled = "boolean" == typeof defaultProps.isOpen, [internalOpen, setInternalOpen] = React.useState(defaultProps.defaultOpen || !1), isOpen = isControlled ? defaultProps.isOpen : internalOpen, [panelHeight, setPanelHeight] = React.useState(isOpen ? "auto" : "0px"), panelRef = React.useRef(null), contentRef = React.useRef(null), updatePanelHeight = React.useCallback((() => {
|
|
1992
1992
|
if (contentRef.current && panelRef.current) {
|
|
1993
1993
|
const height = isOpen ? `${contentRef.current.clientHeight}px` : "0px";
|
|
1994
1994
|
panelRef.current.style.setProperty(ACCORDION.CSS_VARS.PANEL_HEIGHT, height), setPanelHeight(height);
|
|
1995
1995
|
}
|
|
1996
|
-
};
|
|
1996
|
+
}), [ isOpen ]);
|
|
1997
1997
|
// Controlled/uncontrolled open state
|
|
1998
1998
|
/**
|
|
1999
1999
|
* Effect to update panel height when open state changes
|
|
2000
2000
|
*/
|
|
2001
2001
|
return React.useEffect((() => {
|
|
2002
2002
|
updatePanelHeight();
|
|
2003
|
-
}), [ isOpen ]),
|
|
2003
|
+
}), [ isOpen, updatePanelHeight ]),
|
|
2004
2004
|
/**
|
|
2005
2005
|
* Effect to handle window resize and update panel height
|
|
2006
2006
|
*/
|
|
@@ -2009,7 +2009,7 @@ function useAccordion(initialProps) {
|
|
|
2009
2009
|
isOpen && updatePanelHeight();
|
|
2010
2010
|
};
|
|
2011
2011
|
return window.addEventListener("resize", handleResize), () => window.removeEventListener("resize", handleResize);
|
|
2012
|
-
}), [ isOpen ]), {
|
|
2012
|
+
}), [ isOpen, updatePanelHeight ]), {
|
|
2013
2013
|
state: {
|
|
2014
2014
|
isOpen: isOpen,
|
|
2015
2015
|
panelHeight: panelHeight
|
|
@@ -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
|
|
@@ -5344,7 +5344,100 @@ class ThemeNaming {
|
|
|
5344
5344
|
|
|
5345
5345
|
ThemeNaming.prefix = "atomix";
|
|
5346
5346
|
|
|
5347
|
-
|
|
5347
|
+
var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
|
|
5348
|
+
return function(that, callbackfn, argumentsLength, memo) {
|
|
5349
|
+
var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
|
|
5350
|
+
if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
|
|
5351
|
+
var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
|
|
5352
|
+
if (argumentsLength < 2) for (;;) {
|
|
5353
|
+
if (index in self) {
|
|
5354
|
+
memo = self[index], index += i;
|
|
5355
|
+
break;
|
|
5356
|
+
}
|
|
5357
|
+
if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
|
|
5358
|
+
}
|
|
5359
|
+
for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
|
|
5360
|
+
return memo;
|
|
5361
|
+
};
|
|
5362
|
+
}, arrayReduce = {
|
|
5363
|
+
// `Array.prototype.reduce` method
|
|
5364
|
+
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
5365
|
+
left: createMethod(!1),
|
|
5366
|
+
// `Array.prototype.reduceRight` method
|
|
5367
|
+
// https://tc39.es/ecma262/#sec-array.prototype.reduceright
|
|
5368
|
+
right: createMethod(!0)
|
|
5369
|
+
}, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
|
|
5370
|
+
return userAgent.slice(0, string.length) === string;
|
|
5371
|
+
}, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
|
|
5372
|
+
|
|
5373
|
+
// `Array.prototype.reduce` method
|
|
5374
|
+
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
5375
|
+
_export({
|
|
5376
|
+
target: "Array",
|
|
5377
|
+
proto: !0,
|
|
5378
|
+
forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
|
|
5379
|
+
var method = [][METHOD_NAME];
|
|
5380
|
+
return !!method && fails((function() {
|
|
5381
|
+
// eslint-disable-next-line no-useless-call -- required for testing
|
|
5382
|
+
method.call(null, argument || function() {
|
|
5383
|
+
return 1;
|
|
5384
|
+
}, 1);
|
|
5385
|
+
}));
|
|
5386
|
+
}("reduce")
|
|
5387
|
+
}, {
|
|
5388
|
+
reduce: function(callbackfn /* , initialValue */) {
|
|
5389
|
+
var length = arguments.length;
|
|
5390
|
+
return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
|
|
5391
|
+
}
|
|
5392
|
+
});
|
|
5393
|
+
|
|
5394
|
+
var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype, _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
5395
|
+
var own = it.reduce;
|
|
5396
|
+
return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
|
|
5397
|
+
}));
|
|
5398
|
+
|
|
5399
|
+
/**
|
|
5400
|
+
* Render a slot with the given props
|
|
5401
|
+
*
|
|
5402
|
+
* Priority order:
|
|
5403
|
+
* 1. render function
|
|
5404
|
+
* 2. component
|
|
5405
|
+
* 3. children
|
|
5406
|
+
* 4. fallback
|
|
5407
|
+
*
|
|
5408
|
+
* @example
|
|
5409
|
+
* renderSlot(
|
|
5410
|
+
* { render: (props) => <CustomButton {...props} /> },
|
|
5411
|
+
* { onClick: handleClick, children: 'Click me' }
|
|
5412
|
+
* )
|
|
5413
|
+
*/
|
|
5414
|
+
function renderSlot(slot, props, fallback) {
|
|
5415
|
+
// No slot provided, use fallback
|
|
5416
|
+
if (!slot) return fallback;
|
|
5417
|
+
// Slot is a plain React node
|
|
5418
|
+
if ( React__default.default.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
|
|
5419
|
+
// Slot is an object with rendering options
|
|
5420
|
+
if ("object" == typeof slot && null !== slot) {
|
|
5421
|
+
const slotObj = slot;
|
|
5422
|
+
// Priority 1: render function
|
|
5423
|
+
if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
|
|
5424
|
+
// Priority 2: component
|
|
5425
|
+
if (slotObj.component) {
|
|
5426
|
+
const Component = slotObj.component;
|
|
5427
|
+
return jsxRuntime.jsx(Component, {
|
|
5428
|
+
...props
|
|
5429
|
+
});
|
|
5430
|
+
}
|
|
5431
|
+
// Priority 3: children
|
|
5432
|
+
if (void 0 !== slotObj.children) return slotObj.children;
|
|
5433
|
+
}
|
|
5434
|
+
// Fallback
|
|
5435
|
+
return fallback;
|
|
5436
|
+
}
|
|
5437
|
+
|
|
5438
|
+
/**
|
|
5439
|
+
* Check if a value is a slot configuration
|
|
5440
|
+
*/ const Button = React__default.default.memo( React.forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-expanded": ariaExpanded, "aria-controls": ariaControls, tabIndex: tabIndex, style: style, linkComponent: linkComponent, slots: slots, ...props}, ref) => {
|
|
5348
5441
|
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsxRuntime.jsx(Icon, {
|
|
5349
5442
|
name: iconName,
|
|
5350
5443
|
size: iconSize
|
|
@@ -5360,17 +5453,28 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
5360
5453
|
children: [ loading && jsxRuntime.jsx("span", {
|
|
5361
5454
|
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
|
|
5362
5455
|
"aria-hidden": "true",
|
|
5363
|
-
children:
|
|
5456
|
+
children: renderSlot(slots?.spinner, {
|
|
5457
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
|
|
5364
5458
|
size: spinnerSize,
|
|
5365
5459
|
variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
|
|
5366
|
-
}
|
|
5460
|
+
}, jsxRuntime.jsx(Spinner, {
|
|
5461
|
+
size: spinnerSize,
|
|
5462
|
+
variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
|
|
5463
|
+
}))
|
|
5367
5464
|
}), iconElement && !loading && jsxRuntime.jsx("span", {
|
|
5368
5465
|
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
|
|
5369
5466
|
"aria-hidden": "true",
|
|
5370
|
-
children:
|
|
5467
|
+
children: renderSlot(slots?.icon, {
|
|
5468
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
|
|
5469
|
+
children: iconElement,
|
|
5470
|
+
size: iconSize
|
|
5471
|
+
}, iconElement)
|
|
5371
5472
|
}), !iconOnly && buttonText && jsxRuntime.jsx("span", {
|
|
5372
5473
|
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
|
|
5373
|
-
children:
|
|
5474
|
+
children: renderSlot(slots?.label, {
|
|
5475
|
+
className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
|
|
5476
|
+
children: buttonText
|
|
5477
|
+
}, buttonText)
|
|
5374
5478
|
}) ]
|
|
5375
5479
|
}), buttonProps = {
|
|
5376
5480
|
className: buttonClass,
|
|
@@ -5387,48 +5491,59 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
5387
5491
|
tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
|
|
5388
5492
|
style: style,
|
|
5389
5493
|
...props
|
|
5390
|
-
}
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5494
|
+
}, buttonChildren = renderSlot(slots?.root, {
|
|
5495
|
+
className: buttonClass,
|
|
5496
|
+
children: buttonContent,
|
|
5497
|
+
disabled: isDisabled,
|
|
5498
|
+
loading: loading,
|
|
5499
|
+
onClick: handleClickEvent,
|
|
5500
|
+
type: type,
|
|
5501
|
+
"aria-label": safeAriaLabel,
|
|
5502
|
+
"aria-disabled": isDisabled,
|
|
5503
|
+
"aria-busy": loading
|
|
5504
|
+
}, (() => {
|
|
5505
|
+
// Render as anchor if href is provided
|
|
5506
|
+
if (shouldRenderAsLink) {
|
|
5507
|
+
// Use custom linkComponent if provided (e.g., Next.js Link)
|
|
5508
|
+
if (linkComponent) {
|
|
5509
|
+
const LinkComp = linkComponent, linkProps = {
|
|
5510
|
+
...buttonProps,
|
|
5511
|
+
ref: ref,
|
|
5512
|
+
// linkComponent usually forwards ref to anchor
|
|
5513
|
+
href: isDisabled ? void 0 : href,
|
|
5514
|
+
to: isDisabled ? void 0 : href,
|
|
5515
|
+
target: target,
|
|
5516
|
+
rel: "_blank" === target ? "noopener noreferrer" : void 0
|
|
5517
|
+
};
|
|
5518
|
+
return jsxRuntime.jsx(LinkComp, {
|
|
5519
|
+
...linkProps,
|
|
5520
|
+
children: buttonContent
|
|
5521
|
+
});
|
|
5522
|
+
}
|
|
5523
|
+
// Fallback to regular anchor tag
|
|
5524
|
+
return jsxRuntime.jsx("a", {
|
|
5525
|
+
...buttonProps,
|
|
5526
|
+
ref: ref,
|
|
5527
|
+
href: isDisabled ? void 0 : href,
|
|
5528
|
+
target: target,
|
|
5529
|
+
rel: "_blank" === target ? "noopener noreferrer" : void 0,
|
|
5530
|
+
children: buttonContent
|
|
5531
|
+
});
|
|
5532
|
+
}
|
|
5533
|
+
// Default button rendering
|
|
5534
|
+
return jsxRuntime.jsx(Component, {
|
|
5401
5535
|
...buttonProps,
|
|
5402
5536
|
ref: ref,
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
to: isDisabled ? void 0 : href,
|
|
5406
|
-
target: target,
|
|
5407
|
-
rel: "_blank" === target ? "noopener noreferrer" : void 0
|
|
5408
|
-
};
|
|
5409
|
-
content = jsxRuntime.jsx(LinkComp, {
|
|
5410
|
-
...linkProps,
|
|
5537
|
+
type: "button" === Component ? type : void 0,
|
|
5538
|
+
disabled: isDisabled,
|
|
5411
5539
|
children: buttonContent
|
|
5412
5540
|
});
|
|
5413
|
-
}
|
|
5414
|
-
//
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
target: target,
|
|
5420
|
-
rel: "_blank" === target ? "noopener noreferrer" : void 0,
|
|
5421
|
-
children: buttonContent
|
|
5422
|
-
}); else
|
|
5423
|
-
// Default button rendering
|
|
5424
|
-
content = jsxRuntime.jsx(Component, {
|
|
5425
|
-
...buttonProps,
|
|
5426
|
-
ref: ref,
|
|
5427
|
-
type: "button" === Component ? type : void 0,
|
|
5428
|
-
disabled: isDisabled,
|
|
5429
|
-
children: buttonContent
|
|
5430
|
-
});
|
|
5431
|
-
if (glass) {
|
|
5541
|
+
})());
|
|
5542
|
+
// Determine if we should render as a link
|
|
5543
|
+
// If disabled, we still check href, but we might want to render as button or anchor with aria-disabled
|
|
5544
|
+
// The previous logic was Boolean(href && !isDisabled). This meant if disabled, it renders as <button>.
|
|
5545
|
+
// This is a safe fallback for disabled links.
|
|
5546
|
+
if (glass) {
|
|
5432
5547
|
// Default glass props
|
|
5433
5548
|
const defaultGlassProps = {
|
|
5434
5549
|
displacementScale: 20,
|
|
@@ -5441,10 +5556,10 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
|
|
|
5441
5556
|
};
|
|
5442
5557
|
return jsxRuntime.jsx(AtomixGlass, {
|
|
5443
5558
|
...glassProps,
|
|
5444
|
-
children:
|
|
5559
|
+
children: buttonChildren
|
|
5445
5560
|
});
|
|
5446
5561
|
}
|
|
5447
|
-
return
|
|
5562
|
+
return buttonChildren;
|
|
5448
5563
|
})));
|
|
5449
5564
|
|
|
5450
5565
|
Button.displayName = "Button";
|
|
@@ -5552,7 +5667,7 @@ const CalloutContent = React.forwardRef((({children: children, className: class
|
|
|
5552
5667
|
|
|
5553
5668
|
CalloutContent.displayName = "CalloutContent";
|
|
5554
5669
|
|
|
5555
|
-
const
|
|
5670
|
+
const CalloutComponentBase = ({title: title, children: children, icon: icon, variant: variant = "primary", onClose: onClose, actions: actions, compact: compact = !1, isToast: isToast = !1, glass: glass, className: className, style: style, ...props}) => {
|
|
5556
5671
|
const {generateCalloutClass: generateCalloutClass, handleClose: handleClose} =
|
|
5557
5672
|
/**
|
|
5558
5673
|
* Callout state and functionality
|
|
@@ -5678,7 +5793,7 @@ const Callout = React.memo((({title: title, children: children, icon: icon, var
|
|
|
5678
5793
|
style: style,
|
|
5679
5794
|
children: calloutContent
|
|
5680
5795
|
});
|
|
5681
|
-
})
|
|
5796
|
+
}, Callout = React.memo(CalloutComponentBase);
|
|
5682
5797
|
|
|
5683
5798
|
Callout.displayName = "Callout",
|
|
5684
5799
|
// Attach subcomponents
|
|
@@ -5968,60 +6083,6 @@ const ElevationCard = ({elevationClass: elevationClass = "is-elevated", classNam
|
|
|
5968
6083
|
});
|
|
5969
6084
|
};
|
|
5970
6085
|
|
|
5971
|
-
ElevationCard.displayName = "ElevationCard";
|
|
5972
|
-
|
|
5973
|
-
var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
|
|
5974
|
-
return function(that, callbackfn, argumentsLength, memo) {
|
|
5975
|
-
var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
|
|
5976
|
-
if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
|
|
5977
|
-
var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
|
|
5978
|
-
if (argumentsLength < 2) for (;;) {
|
|
5979
|
-
if (index in self) {
|
|
5980
|
-
memo = self[index], index += i;
|
|
5981
|
-
break;
|
|
5982
|
-
}
|
|
5983
|
-
if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
|
|
5984
|
-
}
|
|
5985
|
-
for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
|
|
5986
|
-
return memo;
|
|
5987
|
-
};
|
|
5988
|
-
}, arrayReduce = {
|
|
5989
|
-
// `Array.prototype.reduce` method
|
|
5990
|
-
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
5991
|
-
left: createMethod(!1),
|
|
5992
|
-
// `Array.prototype.reduceRight` method
|
|
5993
|
-
// https://tc39.es/ecma262/#sec-array.prototype.reduceright
|
|
5994
|
-
right: createMethod(!0)
|
|
5995
|
-
}, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
|
|
5996
|
-
return userAgent.slice(0, string.length) === string;
|
|
5997
|
-
}, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
|
|
5998
|
-
|
|
5999
|
-
// `Array.prototype.reduce` method
|
|
6000
|
-
// https://tc39.es/ecma262/#sec-array.prototype.reduce
|
|
6001
|
-
_export({
|
|
6002
|
-
target: "Array",
|
|
6003
|
-
proto: !0,
|
|
6004
|
-
forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
|
|
6005
|
-
var method = [][METHOD_NAME];
|
|
6006
|
-
return !!method && fails((function() {
|
|
6007
|
-
// eslint-disable-next-line no-useless-call -- required for testing
|
|
6008
|
-
method.call(null, argument || function() {
|
|
6009
|
-
return 1;
|
|
6010
|
-
}, 1);
|
|
6011
|
-
}));
|
|
6012
|
-
}("reduce")
|
|
6013
|
-
}, {
|
|
6014
|
-
reduce: function(callbackfn /* , initialValue */) {
|
|
6015
|
-
var length = arguments.length;
|
|
6016
|
-
return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
|
|
6017
|
-
}
|
|
6018
|
-
});
|
|
6019
|
-
|
|
6020
|
-
var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype, _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
|
|
6021
|
-
var own = it.reduce;
|
|
6022
|
-
return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
|
|
6023
|
-
}));
|
|
6024
|
-
|
|
6025
6086
|
/**
|
|
6026
6087
|
* Comprehensive chart hook with shared functionality
|
|
6027
6088
|
* @param initialProps - Initial chart properties
|
|
@@ -6059,8 +6120,11 @@ function useChart(initialProps) {
|
|
|
6059
6120
|
}), animationFrameRef = React.useRef(null);
|
|
6060
6121
|
// Default chart properties
|
|
6061
6122
|
// Cleanup animation frame on unmount
|
|
6062
|
-
React.useEffect((() =>
|
|
6063
|
-
|
|
6123
|
+
React.useEffect((() => {
|
|
6124
|
+
const currentRef = animationFrameRef.current;
|
|
6125
|
+
return () => {
|
|
6126
|
+
currentRef && cancelAnimationFrame(currentRef);
|
|
6127
|
+
};
|
|
6064
6128
|
}), []);
|
|
6065
6129
|
/**
|
|
6066
6130
|
* Point interaction handlers
|
|
@@ -6451,7 +6515,9 @@ function getDatasetBounds(data) {
|
|
|
6451
6515
|
|
|
6452
6516
|
/**
|
|
6453
6517
|
* Hook for managing chart toolbar state and generating chart-specific configurations
|
|
6454
|
-
*/
|
|
6518
|
+
*/ ElevationCard.displayName = "ElevationCard";
|
|
6519
|
+
|
|
6520
|
+
const ChartToolbar = React.memo( React.forwardRef((({chartType: chartType = "line", groups: groups = [], enableDefaults: enableDefaults = !0, defaults: defaults = {
|
|
6455
6521
|
refresh: !0,
|
|
6456
6522
|
export: !0,
|
|
6457
6523
|
fullscreen: !0,
|
|
@@ -6941,8 +7007,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
|
|
|
6941
7007
|
}), [ chartType ]), finalDefaults = React.useMemo((() => ({
|
|
6942
7008
|
...getChartDefaults(),
|
|
6943
7009
|
...defaults
|
|
6944
|
-
})), [ getChartDefaults, defaults ]), enhancedHandlers = {
|
|
6945
|
-
onRefresh:
|
|
7010
|
+
})), [ getChartDefaults, defaults ]), enhancedHandlers = React.useMemo((() => ({
|
|
7011
|
+
onRefresh: () => {
|
|
6946
7012
|
setState((prev => ({
|
|
6947
7013
|
...prev,
|
|
6948
7014
|
isRefreshing: !0
|
|
@@ -6952,8 +7018,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
|
|
|
6952
7018
|
isRefreshing: !1
|
|
6953
7019
|
})));
|
|
6954
7020
|
}), 1e3);
|
|
6955
|
-
}
|
|
6956
|
-
onExport:
|
|
7021
|
+
},
|
|
7022
|
+
onExport: async format => {
|
|
6957
7023
|
setState((prev => ({
|
|
6958
7024
|
...prev,
|
|
6959
7025
|
isExporting: !0
|
|
@@ -6966,70 +7032,70 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
|
|
|
6966
7032
|
isExporting: !1
|
|
6967
7033
|
})));
|
|
6968
7034
|
}
|
|
6969
|
-
}
|
|
6970
|
-
onFullscreen:
|
|
7035
|
+
},
|
|
7036
|
+
onFullscreen: isFullscreen => {
|
|
6971
7037
|
setState((prev => ({
|
|
6972
7038
|
...prev,
|
|
6973
7039
|
isFullscreen: isFullscreen
|
|
6974
7040
|
}))), handlers.onFullscreen?.(isFullscreen);
|
|
6975
|
-
}
|
|
6976
|
-
onZoomIn:
|
|
7041
|
+
},
|
|
7042
|
+
onZoomIn: () => {
|
|
6977
7043
|
setState((prev => ({
|
|
6978
7044
|
...prev,
|
|
6979
7045
|
zoomLevel: Math.min(1.2 * prev.zoomLevel, 5)
|
|
6980
7046
|
}))), handlers.onZoomIn?.();
|
|
6981
|
-
}
|
|
6982
|
-
onZoomOut:
|
|
7047
|
+
},
|
|
7048
|
+
onZoomOut: () => {
|
|
6983
7049
|
setState((prev => ({
|
|
6984
7050
|
...prev,
|
|
6985
7051
|
zoomLevel: Math.max(prev.zoomLevel / 1.2, .2)
|
|
6986
7052
|
}))), handlers.onZoomOut?.();
|
|
6987
|
-
}
|
|
6988
|
-
onZoomReset:
|
|
7053
|
+
},
|
|
7054
|
+
onZoomReset: () => {
|
|
6989
7055
|
setState((prev => ({
|
|
6990
7056
|
...prev,
|
|
6991
7057
|
zoomLevel: 1
|
|
6992
7058
|
}))), handlers.onZoomReset?.();
|
|
6993
|
-
}
|
|
6994
|
-
onPanToggle:
|
|
7059
|
+
},
|
|
7060
|
+
onPanToggle: enabled => {
|
|
6995
7061
|
setState((prev => ({
|
|
6996
7062
|
...prev,
|
|
6997
7063
|
panEnabled: enabled
|
|
6998
7064
|
}))), handlers.onPanToggle?.(enabled);
|
|
6999
|
-
}
|
|
7000
|
-
onReset:
|
|
7065
|
+
},
|
|
7066
|
+
onReset: () => {
|
|
7001
7067
|
setState((prev => ({
|
|
7002
7068
|
...prev,
|
|
7003
7069
|
zoomLevel: 1,
|
|
7004
7070
|
panEnabled: !1
|
|
7005
7071
|
}))), handlers.onReset?.();
|
|
7006
|
-
}
|
|
7007
|
-
onGridToggle:
|
|
7072
|
+
},
|
|
7073
|
+
onGridToggle: show => {
|
|
7008
7074
|
setState((prev => ({
|
|
7009
7075
|
...prev,
|
|
7010
7076
|
showGrid: show
|
|
7011
7077
|
}))), handlers.onGridToggle?.(show);
|
|
7012
|
-
}
|
|
7013
|
-
onLegendToggle:
|
|
7078
|
+
},
|
|
7079
|
+
onLegendToggle: show => {
|
|
7014
7080
|
setState((prev => ({
|
|
7015
7081
|
...prev,
|
|
7016
7082
|
showLegend: show
|
|
7017
7083
|
}))), handlers.onLegendToggle?.(show);
|
|
7018
|
-
}
|
|
7019
|
-
onTooltipsToggle:
|
|
7084
|
+
},
|
|
7085
|
+
onTooltipsToggle: show => {
|
|
7020
7086
|
setState((prev => ({
|
|
7021
7087
|
...prev,
|
|
7022
7088
|
showTooltips: show
|
|
7023
7089
|
}))), handlers.onTooltipsToggle?.(show);
|
|
7024
|
-
}
|
|
7025
|
-
onAnimationsToggle:
|
|
7090
|
+
},
|
|
7091
|
+
onAnimationsToggle: enabled => {
|
|
7026
7092
|
setState((prev => ({
|
|
7027
7093
|
...prev,
|
|
7028
7094
|
animationsEnabled: enabled
|
|
7029
7095
|
}))), handlers.onAnimationsToggle?.(enabled);
|
|
7030
|
-
}
|
|
7031
|
-
onSettings:
|
|
7032
|
-
}, generateToolbarGroups = React.useCallback((() => {
|
|
7096
|
+
},
|
|
7097
|
+
onSettings: () => {}
|
|
7098
|
+
})), [ handlers ]), generateToolbarGroups = React.useCallback((() => {
|
|
7033
7099
|
const groups = [], dataActions = [];
|
|
7034
7100
|
// Data actions group
|
|
7035
7101
|
finalDefaults.refresh && dataActions.push({
|
|
@@ -7154,7 +7220,7 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
|
|
|
7154
7220
|
actions: customActions
|
|
7155
7221
|
});
|
|
7156
7222
|
return groups;
|
|
7157
|
-
}), [
|
|
7223
|
+
}), [ finalDefaults, state, enhancedHandlers, customActions, customGroups ]);
|
|
7158
7224
|
// Keyboard shortcuts
|
|
7159
7225
|
return React.useEffect((() => {
|
|
7160
7226
|
const handleKeyDown = event => {
|
|
@@ -7746,7 +7812,7 @@ const ChartRenderer = React.memo( React.forwardRef((({datasets: datasets = [],
|
|
|
7746
7812
|
announcement: announcement,
|
|
7747
7813
|
focusedPoint: focusedPoint,
|
|
7748
7814
|
getAccessibleDescription: () => "Chart description"
|
|
7749
|
-
})), [ announcement, focusedPoint ]), transform = React.useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext
|
|
7815
|
+
})), [ announcement, focusedPoint ]), transform = React.useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext ]), chartData = React.useMemo((() => {
|
|
7750
7816
|
// Return null if dimensions not ready to prevent calculation with invalid dimensions
|
|
7751
7817
|
if (!isInitialized || 0 === dimensions.width || 0 === dimensions.height) return null;
|
|
7752
7818
|
const scales = calculateScales(processedData, dimensions.width, dimensions.height, void 0, config);
|
|
@@ -8159,7 +8225,7 @@ function useBarChart(datasets, options = {}) {
|
|
|
8159
8225
|
opacity: .4
|
|
8160
8226
|
} ]
|
|
8161
8227
|
};
|
|
8162
|
-
})) : []), [ options.useGradients ]), formatValue = React.useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options
|
|
8228
|
+
})) : []), [ options.useGradients ]), formatValue = React.useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options ]);
|
|
8163
8229
|
return {
|
|
8164
8230
|
// State
|
|
8165
8231
|
hoveredBar: hoveredBar,
|
|
@@ -8185,7 +8251,7 @@ function useBarChart(datasets, options = {}) {
|
|
|
8185
8251
|
y: horizontal ? y + height / 2 : y - 5
|
|
8186
8252
|
};
|
|
8187
8253
|
}
|
|
8188
|
-
}), [ options
|
|
8254
|
+
}), [ options ]),
|
|
8189
8255
|
// Handlers
|
|
8190
8256
|
handleBarHover: handleBarHover,
|
|
8191
8257
|
handleBarLeave: handleBarLeave,
|
|
@@ -8495,13 +8561,13 @@ const DonutChart = React.memo( React.forwardRef((({datasets: datasets = [], con
|
|
|
8495
8561
|
roundedCorners: !0
|
|
8496
8562
|
}, onDataPointClick: onDataPointClick, ...props}, ref) => {
|
|
8497
8563
|
// Use the first dataset for donut chart
|
|
8498
|
-
const dataset = datasets.length > 0 ? datasets[0] : {
|
|
8564
|
+
const dataset = React.useMemo((() => datasets.length > 0 ? datasets[0] : {
|
|
8499
8565
|
label: "",
|
|
8500
8566
|
data: []
|
|
8501
|
-
}, chartData = React.useMemo((() => {
|
|
8567
|
+
}), [ datasets ]), chartData = React.useMemo((() => {
|
|
8502
8568
|
if (!dataset?.data?.length) return null;
|
|
8503
8569
|
// Filter out invalid data points
|
|
8504
|
-
const validDataPoints = dataset?.data
|
|
8570
|
+
const validDataPoints = (dataset?.data || []).filter((point => "number" == typeof point.value && !isNaN(point.value) && isFinite(point.value) && point.value > 0));
|
|
8505
8571
|
return validDataPoints.length ? {
|
|
8506
8572
|
validDataPoints: validDataPoints
|
|
8507
8573
|
} : null;
|
|
@@ -9460,7 +9526,7 @@ function usePieChart(data, options = {}) {
|
|
|
9460
9526
|
const parts = [];
|
|
9461
9527
|
return !1 !== options.showLabels && parts.push(slice.label), options.showPercentages && parts.push(`${Math.round(slice.percentage)}%`),
|
|
9462
9528
|
options.showValues && parts.push(slice.value.toString()), parts.join(" - ");
|
|
9463
|
-
}), [ options
|
|
9529
|
+
}), [ options ]), getSliceTransform = React.useCallback(((slice, isHovered) => isHovered && options.enableHoverEffects && options.hoverOffset ? `translate(${Math.cos(slice.midAngle) * options.hoverOffset}, ${Math.sin(slice.midAngle) * options.hoverOffset})` : ""), [ options.enableHoverEffects, options.hoverOffset ]), isSliceSelected = React.useCallback((index => selectedSlices.has(index)), [ selectedSlices ]);
|
|
9464
9530
|
return {
|
|
9465
9531
|
// Data
|
|
9466
9532
|
processedData: processedData,
|
|
@@ -10896,7 +10962,7 @@ const DataTable = React.memo((({data: data, columns: columns, className: classN
|
|
|
10896
10962
|
const newOrder = columns.map((col => col.key)), currentOrderSet = new Set(columnOrder), newOrderSet = new Set(newOrder);
|
|
10897
10963
|
// Only update if there are actual differences
|
|
10898
10964
|
newOrder.length === columnOrder.length && newOrder.every((key => currentOrderSet.has(key))) && columnOrder.every((key => newOrderSet.has(key))) || setColumnOrder(newOrder);
|
|
10899
|
-
}), [ columns ]),
|
|
10965
|
+
}), [ columns, columnOrder ]),
|
|
10900
10966
|
// Update column visibility when columns prop changes
|
|
10901
10967
|
React.useEffect((() => {
|
|
10902
10968
|
setColumnVisibility((prev => {
|
|
@@ -11441,7 +11507,7 @@ function formatDate(date, format) {
|
|
|
11441
11507
|
/**
|
|
11442
11508
|
* Check if a date is within a min and max range
|
|
11443
11509
|
*/ function useDatePicker({value: value, onChange: onChange, selectionMode: selectionMode = "single", startDate: startDate, endDate: endDate, onRangeChange: onRangeChange, format: format = "MM/dd/yyyy", minDate: minDate, maxDate: maxDate, inline: inline = !1} = {}) {
|
|
11444
|
-
const [isOpen, setIsOpen] = React.useState(inline), [inputValue, setInputValue] = React.useState(value ? formatDate(value, format) : ""), [rangeInputValue, setRangeInputValue] = React.useState(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""), [viewDate, setViewDate] = React.useState(value || startDate || new Date), [viewMode, setViewMode] = React.useState("days"), [rangeSelectionState, setRangeSelectionState] = React.useState(!startDate || startDate && endDate ? "start" : "end"), datePickerRef = React.useRef(null), inputRef = React.useRef(null), today = new Date, currentMonth = viewDate.getMonth(), currentYear = viewDate.getFullYear(), daysInMonth = getDaysInMonth(currentYear, currentMonth), firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
|
|
11510
|
+
const [isOpen, setIsOpen] = React.useState(inline), [inputValue, setInputValue] = React.useState(value ? formatDate(value, format) : ""), [rangeInputValue, setRangeInputValue] = React.useState(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""), [viewDate, setViewDate] = React.useState(value || startDate || new Date), [viewMode, setViewMode] = React.useState("days"), [rangeSelectionState, setRangeSelectionState] = React.useState(!startDate || startDate && endDate ? "start" : "end"), datePickerRef = React.useRef(null), inputRef = React.useRef(null), today = React.useMemo((() => new Date), []), currentMonth = viewDate.getMonth(), currentYear = viewDate.getFullYear(), daysInMonth = getDaysInMonth(currentYear, currentMonth), firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
|
|
11445
11511
|
// Update input value when value or range dates change externally
|
|
11446
11512
|
React.useEffect((() => {
|
|
11447
11513
|
"single" === selectionMode ? setInputValue(value ? formatDate(value, format) : "") : (setRangeInputValue(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""),
|
|
@@ -11964,21 +12030,11 @@ const DatePicker = React.forwardRef((({value: value, onChange: onChange, select
|
|
|
11964
12030
|
* @returns EdgePanel state and methods
|
|
11965
12031
|
*/
|
|
11966
12032
|
function useEdgePanel(initialProps) {
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
position
|
|
11970
|
-
mode: "slide",
|
|
11971
|
-
isOpen: !1,
|
|
11972
|
-
backdrop: !0,
|
|
11973
|
-
closeOnBackdropClick: !0,
|
|
11974
|
-
closeOnEscape: !0,
|
|
11975
|
-
glass: void 0,
|
|
11976
|
-
...initialProps
|
|
11977
|
-
}, [isOpen, setIsOpen] = React.useState(defaultProps.isOpen || !1), containerRef = React.useRef(null), backdropRef = React.useRef(null), adjustBodyPadding = React.useCallback((() => {
|
|
11978
|
-
if (!containerRef.current || "push" !== defaultProps.mode) return;
|
|
11979
|
-
const {position: position} = defaultProps, size = "top" === position || "bottom" === position ? containerRef.current.clientHeight : containerRef.current.clientWidth;
|
|
12033
|
+
const {position: position = "start", mode: mode = "slide", isOpen: propIsOpen = !1, backdrop: backdrop = !0, closeOnBackdropClick: closeOnBackdropClick = !0, closeOnEscape: closeOnEscape = !0, glass: glass, onOpenChange: onOpenChange, className: className = ""} = initialProps || {}, [isOpen, setIsOpen] = React.useState(propIsOpen || !1), containerRef = React.useRef(null), backdropRef = React.useRef(null), adjustBodyPadding = React.useCallback((() => {
|
|
12034
|
+
if (!containerRef.current || "push" !== mode) return;
|
|
12035
|
+
const size = "top" === position || "bottom" === position ? containerRef.current.clientHeight : containerRef.current.clientWidth;
|
|
11980
12036
|
// Map position to CSS padding property
|
|
11981
|
-
|
|
12037
|
+
let paddingProperty;
|
|
11982
12038
|
switch (position) {
|
|
11983
12039
|
case "start":
|
|
11984
12040
|
paddingProperty = "paddingLeft";
|
|
@@ -11993,9 +12049,8 @@ function useEdgePanel(initialProps) {
|
|
|
11993
12049
|
paddingProperty = `padding${position.charAt(0).toUpperCase() + position.slice(1)}`;
|
|
11994
12050
|
}
|
|
11995
12051
|
document.body.style[paddingProperty] = `${size}px`, document.body.classList.add("is-pushed");
|
|
11996
|
-
}), [
|
|
11997
|
-
if ("push" !==
|
|
11998
|
-
const {position: position} = defaultProps;
|
|
12052
|
+
}), [ mode, position ]), resetBodyPadding = React.useCallback((() => {
|
|
12053
|
+
if ("push" !== mode) return;
|
|
11999
12054
|
// Map position to CSS padding property
|
|
12000
12055
|
let paddingProperty;
|
|
12001
12056
|
switch (position) {
|
|
@@ -12012,11 +12067,10 @@ function useEdgePanel(initialProps) {
|
|
|
12012
12067
|
paddingProperty = `padding${position.charAt(0).toUpperCase() + position.slice(1)}`;
|
|
12013
12068
|
}
|
|
12014
12069
|
document.body.style[paddingProperty] = "", document.body.classList.remove("is-pushed");
|
|
12015
|
-
}), [
|
|
12070
|
+
}), [ mode, position ]), openPanel = React.useCallback(((useFadeAnimation = !1) => {
|
|
12016
12071
|
if (setIsOpen(!0), document.body.classList.add("is-edgepanel-open"), containerRef.current) {
|
|
12017
|
-
const {mode: mode} = defaultProps;
|
|
12018
12072
|
// Only add animation if not in 'none' mode
|
|
12019
|
-
|
|
12073
|
+
if ("none" !== mode) if (useFadeAnimation) {
|
|
12020
12074
|
// Add fade animation class
|
|
12021
12075
|
containerRef.current.classList.add("is-fade-animating"), containerRef.current.offsetHeight;
|
|
12022
12076
|
// Remove animation class after animation completes
|
|
@@ -12036,14 +12090,13 @@ function useEdgePanel(initialProps) {
|
|
|
12036
12090
|
// Set transform or opacity based on animation type
|
|
12037
12091
|
useFadeAnimation ? (containerRef.current.style.opacity = "1", containerRef.current.style.transform = "") : containerRef.current.style.transform = "translate(0)",
|
|
12038
12092
|
// If push mode, adjust body padding
|
|
12039
|
-
"push" ===
|
|
12093
|
+
"push" === mode && adjustBodyPadding();
|
|
12040
12094
|
}
|
|
12041
|
-
|
|
12042
|
-
}), [
|
|
12095
|
+
onOpenChange && onOpenChange(!0);
|
|
12096
|
+
}), [ mode, adjustBodyPadding, onOpenChange ]), closePanel = React.useCallback(((useFadeAnimation = !1) => {
|
|
12043
12097
|
if (containerRef.current) {
|
|
12044
|
-
const {position: position, mode: mode} = defaultProps;
|
|
12045
12098
|
// Only add animation if not in 'none' mode
|
|
12046
|
-
|
|
12099
|
+
if ("none" !== mode) if (useFadeAnimation) {
|
|
12047
12100
|
// Add fade out animation class
|
|
12048
12101
|
containerRef.current.classList.add("is-fade-animating-out");
|
|
12049
12102
|
// Capture container for setTimeout
|
|
@@ -12065,46 +12118,42 @@ function useEdgePanel(initialProps) {
|
|
|
12065
12118
|
// Then set transform
|
|
12066
12119
|
containerRef.current.style.transform = position ? EDGE_PANEL.TRANSFORM_VALUES[position] : "",
|
|
12067
12120
|
// Reset body padding if push mode
|
|
12068
|
-
"push" ===
|
|
12069
|
-
setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"),
|
|
12121
|
+
"push" === mode && resetBodyPadding(), setTimeout((() => {
|
|
12122
|
+
setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), onOpenChange && onOpenChange(!1);
|
|
12070
12123
|
}), "none" === mode ? 0 : EDGE_PANEL.ANIMATION_DURATION);
|
|
12071
|
-
} else setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"),
|
|
12072
|
-
}), [
|
|
12073
|
-
|
|
12074
|
-
}), [ closePanel,
|
|
12075
|
-
|
|
12076
|
-
}), [ closePanel,
|
|
12124
|
+
} else setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), onOpenChange && onOpenChange(!1);
|
|
12125
|
+
}), [ mode, position, onOpenChange, resetBodyPadding ]), handleEscapeKey = React.useCallback((event => {
|
|
12126
|
+
closeOnEscape && "Escape" === event.key && isOpen && closePanel();
|
|
12127
|
+
}), [ closePanel, closeOnEscape, isOpen ]), handleBackdropClick = React.useCallback((event => {
|
|
12128
|
+
closeOnBackdropClick && event.target === event.currentTarget && closePanel();
|
|
12129
|
+
}), [ closePanel, closeOnBackdropClick ]);
|
|
12077
12130
|
/**
|
|
12078
12131
|
* Set up event listeners for keyboard events
|
|
12079
12132
|
*/
|
|
12080
|
-
return React.useEffect((() => (isOpen &&
|
|
12133
|
+
return React.useEffect((() => (isOpen && closeOnEscape && document.addEventListener("keydown", handleEscapeKey),
|
|
12081
12134
|
() => {
|
|
12082
12135
|
document.removeEventListener("keydown", handleEscapeKey);
|
|
12083
|
-
})), [ isOpen, handleEscapeKey,
|
|
12136
|
+
})), [ isOpen, handleEscapeKey, closeOnEscape ]),
|
|
12084
12137
|
/**
|
|
12085
12138
|
* Set initial transform values
|
|
12086
12139
|
*/
|
|
12087
12140
|
React.useEffect((() => {
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
defaultProps.glass && (containerRef.current.style.opacity = "0"));
|
|
12093
|
-
}
|
|
12094
|
-
}), [ defaultProps.mode, defaultProps.position, defaultProps.glass, isOpen ]),
|
|
12141
|
+
containerRef.current && (isOpen || "slide" !== mode && "push" !== mode || !position || (containerRef.current.style.transform = EDGE_PANEL.TRANSFORM_VALUES[position],
|
|
12142
|
+
// Set initial opacity for fade animations
|
|
12143
|
+
glass && (containerRef.current.style.opacity = "0")));
|
|
12144
|
+
}), [ mode, position, glass, isOpen ]),
|
|
12095
12145
|
/**
|
|
12096
12146
|
* Sync with prop changes
|
|
12097
12147
|
*/
|
|
12098
12148
|
React.useEffect((() => {
|
|
12099
|
-
void 0 !==
|
|
12100
|
-
}), [
|
|
12101
|
-
{
|
|
12149
|
+
void 0 !== propIsOpen && propIsOpen !== isOpen && (propIsOpen ? openPanel(!!glass) : closePanel(!!glass));
|
|
12150
|
+
}), [ propIsOpen, closePanel, isOpen, openPanel, glass ]), {
|
|
12102
12151
|
isOpen: isOpen,
|
|
12103
12152
|
containerRef: containerRef,
|
|
12104
12153
|
backdropRef: backdropRef,
|
|
12105
12154
|
generateEdgePanelClass: props => {
|
|
12106
|
-
const {position:
|
|
12107
|
-
return `${baseClass} ${
|
|
12155
|
+
const {position: propPosition = position, className: propClassName = className, isOpen: argIsOpen} = props, baseClass = EDGE_PANEL.CLASSES.BASE;
|
|
12156
|
+
return `${baseClass} ${propPosition ? `${baseClass}--${propPosition}` : ""} ${argIsOpen ?? isOpen ? EDGE_PANEL.CLASSES.IS_OPEN : ""} ${propClassName}`.trim();
|
|
12108
12157
|
},
|
|
12109
12158
|
openPanel: openPanel,
|
|
12110
12159
|
closePanel: closePanel,
|
|
@@ -12155,7 +12204,7 @@ const EdgePanelCloseButton = React.forwardRef((({className: className = "", onC
|
|
|
12155
12204
|
|
|
12156
12205
|
EdgePanelCloseButton.displayName = "EdgePanelCloseButton";
|
|
12157
12206
|
|
|
12158
|
-
const
|
|
12207
|
+
const EdgePanelComponentBase = ({title: title, children: children, position: position = "start", mode: mode = "slide", isOpen: isOpen = !1, onOpenChange: onOpenChange, backdrop: backdrop = !0, closeOnBackdropClick: closeOnBackdropClick = !0, closeOnEscape: closeOnEscape = !0, className: className = "", style: style, glass: glass}) => {
|
|
12159
12208
|
const {isOpen: isOpenState, containerRef: containerRef, backdropRef: backdropRef, generateEdgePanelClass: generateEdgePanelClass, closePanel: closePanel, handleBackdropClick: handleBackdropClick} = useEdgePanel({
|
|
12160
12209
|
position: position,
|
|
12161
12210
|
mode: mode,
|
|
@@ -12231,7 +12280,7 @@ const EdgePanel = React.memo((({title: title, children: children, position: pos
|
|
|
12231
12280
|
}) : panelContent
|
|
12232
12281
|
}) ]
|
|
12233
12282
|
});
|
|
12234
|
-
})
|
|
12283
|
+
}, EdgePanel = React.memo(EdgePanelComponentBase);
|
|
12235
12284
|
|
|
12236
12285
|
/**
|
|
12237
12286
|
* Form state and functionality
|
|
@@ -12486,7 +12535,7 @@ function useHero(initialProps) {
|
|
|
12486
12535
|
* @returns Slider state and methods
|
|
12487
12536
|
*/
|
|
12488
12537
|
function(config) {
|
|
12489
|
-
const {slides: slides, autoplay: autoplay, loop: loop = !0, transition: transition = "fade", transitionDuration: transitionDuration = 1e3} = config, [currentIndex, setCurrentIndex] = React.useState(0), [isTransitioning, setIsTransitioning] = React.useState(!1), autoplayRef = React.useRef(null), isPausedRef = React.useRef(!1), callbackRef = React.useRef(), slideRefs = React.useMemo((() => slides.map((() => React__default.default.createRef()))), [ slides
|
|
12538
|
+
const {slides: slides, autoplay: autoplay, loop: loop = !0, transition: transition = "fade", transitionDuration: transitionDuration = 1e3} = config, [currentIndex, setCurrentIndex] = React.useState(0), [isTransitioning, setIsTransitioning] = React.useState(!1), autoplayRef = React.useRef(null), isPausedRef = React.useRef(!1), callbackRef = React.useRef(void 0), slideRefs = React.useMemo((() => slides.map((() => React__default.default.createRef()))), [ slides ]), videoRefs = React.useMemo((() => slides.map((() => React__default.default.createRef()))), [ slides ]), handleSlideTransition = React.useCallback((nextIndex => {
|
|
12490
12539
|
if (nextIndex === currentIndex || isTransitioning) return;
|
|
12491
12540
|
if (nextIndex < 0 || nextIndex >= slides.length) return;
|
|
12492
12541
|
setIsTransitioning(!0),
|
|
@@ -12805,22 +12854,15 @@ function useHero(initialProps) {
|
|
|
12805
12854
|
* @param initialProps - Initial side menu properties
|
|
12806
12855
|
* @returns SideMenu state and methods
|
|
12807
12856
|
*/ function useSideMenu(initialProps) {
|
|
12808
|
-
|
|
12809
|
-
const defaultProps = {
|
|
12810
|
-
collapsible: !0,
|
|
12811
|
-
collapsibleDesktop: !1,
|
|
12812
|
-
defaultCollapsedDesktop: !1,
|
|
12813
|
-
isOpen: !1,
|
|
12814
|
-
...initialProps
|
|
12815
|
-
}, [isOpenState, setIsOpenState] = React.useState(void 0 !== defaultProps.defaultCollapsedDesktop ? !defaultProps.defaultCollapsedDesktop : defaultProps.isOpen || !1), wrapperRef = React.useRef(null), innerRef = React.useRef(null), sideMenuRef = React.useRef(null);
|
|
12857
|
+
const {collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, isOpen: isOpen, onToggle: onToggle, disabled: disabled = !1} = initialProps || {}, [isOpenState, setIsOpenState] = React.useState(void 0 !== defaultCollapsedDesktop ? !defaultCollapsedDesktop : isOpen || !1), wrapperRef = React.useRef(null), innerRef = React.useRef(null), sideMenuRef = React.useRef(null);
|
|
12816
12858
|
// Local open state for when not controlled externally
|
|
12817
12859
|
// Update local state when external state changes
|
|
12818
12860
|
React.useEffect((() => {
|
|
12819
|
-
void 0 !==
|
|
12820
|
-
}), [
|
|
12861
|
+
void 0 !== isOpen ? setIsOpenState(isOpen) : void 0 !== defaultCollapsedDesktop && setIsOpenState(!defaultCollapsedDesktop);
|
|
12862
|
+
}), [ isOpen, defaultCollapsedDesktop ]),
|
|
12821
12863
|
// Set initial height on mount
|
|
12822
12864
|
React.useEffect((() => {
|
|
12823
|
-
const shouldCollapse = window.innerWidth < 768 ?
|
|
12865
|
+
const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop, currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
12824
12866
|
if (shouldCollapse && wrapperRef.current && innerRef.current) {
|
|
12825
12867
|
// Use setTimeout to ensure DOM is fully rendered
|
|
12826
12868
|
const timeoutId = setTimeout((() => {
|
|
@@ -12829,14 +12871,14 @@ function useHero(initialProps) {
|
|
|
12829
12871
|
return () => clearTimeout(timeoutId);
|
|
12830
12872
|
}
|
|
12831
12873
|
!shouldCollapse && wrapperRef.current && (wrapperRef.current.style.height = "auto");
|
|
12832
|
-
}), [
|
|
12874
|
+
}), [ collapsible, collapsibleDesktop, isOpen, isOpenState ]),
|
|
12833
12875
|
// Handle responsive behavior - vertical collapse for both mobile and desktop
|
|
12834
12876
|
React.useEffect((() => {
|
|
12835
12877
|
const handleResize = () => {
|
|
12836
|
-
if (window.innerWidth < 768 ?
|
|
12878
|
+
if (window.innerWidth < 768 ? collapsible : collapsibleDesktop) {
|
|
12837
12879
|
if (wrapperRef.current && innerRef.current) {
|
|
12838
12880
|
// Set proper height for vertical animation (both mobile and desktop)
|
|
12839
|
-
const currentOpen = void 0 !==
|
|
12881
|
+
const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
12840
12882
|
// Use requestAnimationFrame to ensure DOM is ready
|
|
12841
12883
|
requestAnimationFrame((() => {
|
|
12842
12884
|
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
@@ -12850,12 +12892,12 @@ function useHero(initialProps) {
|
|
|
12850
12892
|
return window.addEventListener("resize", handleResize), () => {
|
|
12851
12893
|
clearTimeout(timeoutId), window.removeEventListener("resize", handleResize);
|
|
12852
12894
|
};
|
|
12853
|
-
}), [
|
|
12895
|
+
}), [ collapsible, collapsibleDesktop, isOpen, onToggle, isOpenState ]),
|
|
12854
12896
|
// Update wrapper height when open state changes (both mobile and desktop)
|
|
12855
12897
|
React.useEffect((() => {
|
|
12856
|
-
const shouldCollapse = window.innerWidth < 768 ?
|
|
12898
|
+
const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop;
|
|
12857
12899
|
if (shouldCollapse && wrapperRef.current && innerRef.current) {
|
|
12858
|
-
const currentOpen = void 0 !==
|
|
12900
|
+
const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
|
|
12859
12901
|
// Use requestAnimationFrame to ensure DOM is ready
|
|
12860
12902
|
requestAnimationFrame((() => {
|
|
12861
12903
|
wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
|
|
@@ -12863,26 +12905,25 @@ function useHero(initialProps) {
|
|
|
12863
12905
|
} else !shouldCollapse && wrapperRef.current && (
|
|
12864
12906
|
// Not collapsible - always show content
|
|
12865
12907
|
wrapperRef.current.style.height = "auto");
|
|
12866
|
-
}), [
|
|
12908
|
+
}), [ isOpen, isOpenState, collapsible, collapsibleDesktop ]);
|
|
12867
12909
|
/**
|
|
12868
12910
|
* Generate side menu class based on properties
|
|
12869
12911
|
* @param props - Side menu properties
|
|
12870
12912
|
* @returns Class string
|
|
12871
12913
|
*/
|
|
12872
12914
|
const handleToggle = () => {
|
|
12873
|
-
if (
|
|
12874
|
-
const newState = void 0 !==
|
|
12875
|
-
"function" == typeof
|
|
12915
|
+
if (disabled) return;
|
|
12916
|
+
const newState = void 0 !== isOpen ? !isOpen : !isOpenState;
|
|
12917
|
+
"function" == typeof onToggle ?
|
|
12876
12918
|
// Controlled component
|
|
12877
|
-
|
|
12919
|
+
onToggle(newState) :
|
|
12878
12920
|
// Uncontrolled component
|
|
12879
12921
|
setIsOpenState(newState);
|
|
12880
|
-
}, getCurrentOpenState = () => void 0 !==
|
|
12922
|
+
}, getCurrentOpenState = () => void 0 !== isOpen ? isOpen : isOpenState;
|
|
12881
12923
|
/**
|
|
12882
12924
|
* Generate wrapper class
|
|
12883
12925
|
* @returns Class string
|
|
12884
12926
|
*/ return {
|
|
12885
|
-
defaultProps: defaultProps,
|
|
12886
12927
|
isOpenState: getCurrentOpenState(),
|
|
12887
12928
|
wrapperRef: wrapperRef,
|
|
12888
12929
|
innerRef: innerRef,
|
|
@@ -13465,21 +13506,21 @@ const DEFAULT_ATOMIX_FONTS = [ {
|
|
|
13465
13506
|
const [interaction, setInteraction] = React.useState({
|
|
13466
13507
|
hoveredIndex: null,
|
|
13467
13508
|
selectedIndex: null
|
|
13468
|
-
})
|
|
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
|
+
}), []);
|
|
13469
13520
|
return {
|
|
13470
13521
|
interaction: interaction,
|
|
13471
|
-
handlePointHover:
|
|
13472
|
-
|
|
13473
|
-
...prev,
|
|
13474
|
-
hoveredIndex: index
|
|
13475
|
-
})));
|
|
13476
|
-
}), []),
|
|
13477
|
-
handlePointClick: React.useCallback((index => {
|
|
13478
|
-
setInteraction((prev => ({
|
|
13479
|
-
...prev,
|
|
13480
|
-
selectedIndex: prev.selectedIndex === index ? null : index
|
|
13481
|
-
})));
|
|
13482
|
-
}), []),
|
|
13522
|
+
handlePointHover: handlePointHover,
|
|
13523
|
+
handlePointClick: handlePointClick,
|
|
13483
13524
|
clearInteraction: React.useCallback((() => {
|
|
13484
13525
|
setInteraction({
|
|
13485
13526
|
hoveredIndex: null,
|
|
@@ -13522,7 +13563,7 @@ var composablesImport = Object.freeze({
|
|
|
13522
13563
|
useNavDropdown: useNavDropdown,
|
|
13523
13564
|
useNavItem: useNavItem,
|
|
13524
13565
|
useNavbar: useNavbar,
|
|
13525
|
-
usePerformanceMonitor: usePerformanceMonitor,
|
|
13566
|
+
usePerformanceMonitor: usePerformanceMonitor$1,
|
|
13526
13567
|
usePieChart: usePieChart,
|
|
13527
13568
|
useRadio: useRadio,
|
|
13528
13569
|
useResponsiveGlass: useResponsiveGlass,
|
|
@@ -13585,7 +13626,7 @@ SelectOption.displayName = "SelectOption";
|
|
|
13585
13626
|
/**
|
|
13586
13627
|
* Select - A component for dropdown selection
|
|
13587
13628
|
*/
|
|
13588
|
-
const
|
|
13629
|
+
const SelectComponentBase = ({options: options, value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder = "Select an option", className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, size: size = "md", invalid: invalid = !1, valid: valid = !1, multiple: multiple = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass, children: children}) => {
|
|
13589
13630
|
const {generateSelectClass: generateSelectClass} = useSelect({
|
|
13590
13631
|
size: size,
|
|
13591
13632
|
disabled: disabled,
|
|
@@ -13776,7 +13817,7 @@ const Select = React.memo((({options: options, value: value, onChange: onChange
|
|
|
13776
13817
|
});
|
|
13777
13818
|
}
|
|
13778
13819
|
return selectContent;
|
|
13779
|
-
})
|
|
13820
|
+
}, Select = React.memo(SelectComponentBase);
|
|
13780
13821
|
|
|
13781
13822
|
Select.displayName = "Select", Select.Option = SelectOption;
|
|
13782
13823
|
|
|
@@ -14343,7 +14384,7 @@ Footer.displayName = "Footer";
|
|
|
14343
14384
|
*/
|
|
14344
14385
|
const MasonryGrid = React.forwardRef((({children: children, className: className = "", xs: xs = 1, sm: sm, md: md, lg: lg, xl: xl, xxl: xxl, gap: gap = 16, animate: animate = !0, imagesLoaded: imagesLoaded = !0, onLayoutComplete: onLayoutComplete, onImageLoad: onImageLoad, ...props}, ref) => {
|
|
14345
14386
|
// === REFS & STATE ===
|
|
14346
|
-
const [columns, setColumns] = React.useState(xs), [positions, setPositions] = React.useState([]), [
|
|
14387
|
+
const [columns, setColumns] = React.useState(xs), [positions, setPositions] = React.useState([]), [, setLayoutComplete] = React.useState(!1), [loadingImages, setLoadingImages] = React.useState(!1), containerRef = React.useRef(null), columnHeights = React.useRef([]), imagesLoadedCount = React.useRef(0), totalImagesCount = React.useRef(0), imageElements = React.useRef(new Map);
|
|
14347
14388
|
React.useEffect((() => {
|
|
14348
14389
|
setLoadingImages(!!imagesLoaded);
|
|
14349
14390
|
}), [ columns, imagesLoaded ]),
|
|
@@ -14372,34 +14413,45 @@ const MasonryGrid = React.forwardRef((({children: children, className: classNam
|
|
|
14372
14413
|
});
|
|
14373
14414
|
})), setItems(newItems);
|
|
14374
14415
|
}), [ children ]);
|
|
14375
|
-
// ===
|
|
14376
|
-
const
|
|
14377
|
-
if (!
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
|
|
14381
|
-
|
|
14382
|
-
|
|
14416
|
+
// === MANAGE ITEM LAYOUT ===
|
|
14417
|
+
const calculateLayout = React.useCallback((() => {
|
|
14418
|
+
if (!containerRef.current || 0 === items.length) return;
|
|
14419
|
+
const colWidth = (containerRef.current.offsetWidth - gap * (columns - 1)) / columns;
|
|
14420
|
+
columnHeights.current = Array(columns).fill(0);
|
|
14421
|
+
const newPositions = [];
|
|
14422
|
+
items.forEach(((item, index) => {
|
|
14423
|
+
if (item.ref.current) {
|
|
14424
|
+
// Find the shortest column
|
|
14425
|
+
const shortestCol = columnHeights.current.indexOf(Math.min(...columnHeights.current)), left = shortestCol * (colWidth + gap), top = columnHeights.current[shortestCol] ?? 0, height = item.ref.current.offsetHeight;
|
|
14426
|
+
columnHeights.current[shortestCol] = top + height + gap, newPositions[index] = {
|
|
14427
|
+
left: left,
|
|
14428
|
+
top: top,
|
|
14429
|
+
width: colWidth,
|
|
14430
|
+
height: height
|
|
14431
|
+
};
|
|
14383
14432
|
}
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
setLoadingImages(!1), // This ensures the loading class is removed *immediately* after images load
|
|
14393
|
-
// Force a double requestAnimationFrame for final layout calculation after all images are loaded (guarantees DOM paint)
|
|
14394
|
-
requestAnimationFrame((() => {
|
|
14395
|
-
requestAnimationFrame((() => {
|
|
14396
|
-
calculateLayout(),
|
|
14397
|
-
// As a failsafe, if still present for some render lag, force another setLoadingImages(false)
|
|
14398
|
-
setLoadingImages(!1);
|
|
14399
|
-
}));
|
|
14400
|
-
})), onLayoutComplete?.());
|
|
14433
|
+
})), setPositions(newPositions);
|
|
14434
|
+
}), [ items, columns, gap ]), handleImageLoad = React.useCallback((img => {
|
|
14435
|
+
if (imageElements.current.get(img)) return;
|
|
14436
|
+
// Add loaded class for animation
|
|
14437
|
+
if (imageElements.current.set(img, !0), imagesLoadedCount.current += 1, containerRef.current && imagesLoaded) {
|
|
14438
|
+
const itemElement = img.closest(".o-masonry-grid > div");
|
|
14439
|
+
itemElement && (itemElement.offsetHeight, itemElement.classList.add("o-masonry-grid__item-loaded"),
|
|
14440
|
+
itemElement.classList.remove("o-masonry-grid__item-loading"));
|
|
14401
14441
|
}
|
|
14402
|
-
|
|
14442
|
+
// Schedule layout recalculation after next paint to prevent overlap
|
|
14443
|
+
const scheduleLayoutUpdate = () => {
|
|
14444
|
+
const frameId = requestAnimationFrame((() => {
|
|
14445
|
+
onImageLoad?.(imagesLoadedCount.current, totalImagesCount.current), calculateLayout();
|
|
14446
|
+
}));
|
|
14447
|
+
return () => cancelAnimationFrame(frameId);
|
|
14448
|
+
}, cleanup = scheduleLayoutUpdate();
|
|
14449
|
+
// Clean up previous scheduled updates
|
|
14450
|
+
// If all images have loaded, update loading state and complete layout
|
|
14451
|
+
imagesLoadedCount.current >= totalImagesCount.current && totalImagesCount.current > 0 && (setLayoutComplete(!0),
|
|
14452
|
+
setLoadingImages(!1), setTimeout((() => cleanup()), 0), // Clean up after current execution
|
|
14453
|
+
scheduleLayoutUpdate(), onLayoutComplete?.());
|
|
14454
|
+
}), [ onImageLoad, onLayoutComplete, imagesLoaded, calculateLayout ]), trackImages = React.useCallback((() => {
|
|
14403
14455
|
if (!imagesLoaded || !containerRef.current) return;
|
|
14404
14456
|
imageElements.current.clear(), imagesLoadedCount.current = 0;
|
|
14405
14457
|
const images = containerRef.current.querySelectorAll("img");
|
|
@@ -14418,30 +14470,21 @@ const MasonryGrid = React.forwardRef((({children: children, className: classNam
|
|
|
14418
14470
|
img.removeEventListener("error", masonryImg._masonryLoadHandler), delete masonryImg._masonryLoadHandler);
|
|
14419
14471
|
}));
|
|
14420
14472
|
});
|
|
14421
|
-
}), [ imagesLoaded, handleImageLoad, onLayoutComplete ])
|
|
14422
|
-
|
|
14423
|
-
|
|
14424
|
-
columnHeights.current = Array(columns).fill(0);
|
|
14425
|
-
const newPositions = [];
|
|
14426
|
-
items.forEach(((item, index) => {
|
|
14427
|
-
if (item.ref.current) {
|
|
14428
|
-
// Find the shortest column
|
|
14429
|
-
const shortestCol = columnHeights.current.indexOf(Math.min(...columnHeights.current)), left = shortestCol * (colWidth + gap), top = columnHeights.current[shortestCol] ?? 0, height = item.ref.current.offsetHeight;
|
|
14430
|
-
columnHeights.current[shortestCol] = top + height + gap, newPositions[index] = {
|
|
14431
|
-
left: left,
|
|
14432
|
-
top: top,
|
|
14433
|
-
width: colWidth,
|
|
14434
|
-
height: height
|
|
14435
|
-
};
|
|
14436
|
-
}
|
|
14437
|
-
})), setPositions(newPositions);
|
|
14438
|
-
}), [ items, columns, gap ]);
|
|
14439
|
-
// === OBSERVE CONTAINER RESIZE ===
|
|
14473
|
+
}), [ imagesLoaded, handleImageLoad, onLayoutComplete ]);
|
|
14474
|
+
// === TRACK & MANAGE IMAGES ===
|
|
14475
|
+
// === OBSERVE CONTAINER RESIZE ===
|
|
14440
14476
|
React.useEffect((() => {
|
|
14441
14477
|
if (!containerRef.current) return;
|
|
14442
|
-
let animationFrame = null;
|
|
14443
|
-
const observer = new ResizeObserver((
|
|
14444
|
-
|
|
14478
|
+
let animationFrame = null, lastWidth = 0;
|
|
14479
|
+
const observer = new ResizeObserver((entries => {
|
|
14480
|
+
const entry = entries[0];
|
|
14481
|
+
if (!entry) return;
|
|
14482
|
+
const currentWidth = entry.contentRect.width;
|
|
14483
|
+
// Only recalculate if width actually changed (prevents excessive calculations)
|
|
14484
|
+
Math.abs(currentWidth - lastWidth) > 1 && (animationFrame && cancelAnimationFrame(animationFrame),
|
|
14485
|
+
animationFrame = requestAnimationFrame((() => {
|
|
14486
|
+
calculateLayout(), lastWidth = currentWidth;
|
|
14487
|
+
})));
|
|
14445
14488
|
}));
|
|
14446
14489
|
return observer.observe(containerRef.current), () => {
|
|
14447
14490
|
observer.disconnect(), animationFrame && cancelAnimationFrame(animationFrame);
|
|
@@ -14452,24 +14495,21 @@ const MasonryGrid = React.forwardRef((({children: children, className: classNam
|
|
|
14452
14495
|
setLayoutComplete(!0), void setLoadingImages(!1))
|
|
14453
14496
|
// Only reset layoutComplete when items or columns change
|
|
14454
14497
|
), [ items, columns, calculateLayout, imagesLoaded, trackImages ]),
|
|
14455
|
-
// ===
|
|
14498
|
+
// === ADD RESIZEOBSERVERS TO GRID ITEMS FOR DYNAMIC CONTENT MEASUREMENT ===
|
|
14456
14499
|
React__default.default.useEffect((() => {
|
|
14457
|
-
// Clean up old observers if items ever change
|
|
14458
14500
|
const observers = [];
|
|
14501
|
+
let animationFrame = null;
|
|
14502
|
+
// Debounced layout calculation for item resize events
|
|
14503
|
+
const debouncedCalculateLayout = () => {
|
|
14504
|
+
animationFrame && cancelAnimationFrame(animationFrame), animationFrame = requestAnimationFrame(calculateLayout);
|
|
14505
|
+
};
|
|
14459
14506
|
return items.forEach((item => {
|
|
14460
14507
|
if (item.ref.current) {
|
|
14461
|
-
const obs = new ResizeObserver(
|
|
14462
|
-
// Double rAF: ensures layout only runs after DOM/paint/async renders
|
|
14463
|
-
requestAnimationFrame((() => {
|
|
14464
|
-
requestAnimationFrame((() => {
|
|
14465
|
-
calculateLayout();
|
|
14466
|
-
}));
|
|
14467
|
-
}));
|
|
14468
|
-
}));
|
|
14508
|
+
const obs = new ResizeObserver(debouncedCalculateLayout);
|
|
14469
14509
|
obs.observe(item.ref.current), observers.push(obs);
|
|
14470
14510
|
}
|
|
14471
14511
|
})), () => {
|
|
14472
|
-
observers.forEach((obs => obs.disconnect()));
|
|
14512
|
+
observers.forEach((obs => obs.disconnect())), animationFrame && cancelAnimationFrame(animationFrame);
|
|
14473
14513
|
};
|
|
14474
14514
|
}), [ items, calculateLayout ]);
|
|
14475
14515
|
// Ensure loadingImages state resets when items/columns/imagesLoaded change
|
|
@@ -14954,7 +14994,7 @@ const ListItem = React.forwardRef((({children: children, className: className =
|
|
|
14954
14994
|
|
|
14955
14995
|
ListItem.displayName = "ListItem";
|
|
14956
14996
|
|
|
14957
|
-
const
|
|
14997
|
+
const ListComponentBase = ({children: children, variant: variant = "default", className: className = "", style: style, ...props}) => {
|
|
14958
14998
|
var _context;
|
|
14959
14999
|
// Generate CSS classes
|
|
14960
15000
|
const listClasses = [ LIST.BASE_CLASS, "default" !== variant && `c-list--${variant}`, className ].filter(Boolean).join(" "), ListElement = _includesInstanceProperty(_context = [ "number", "text" ]).call(_context, variant) ? "ol" : "ul";
|
|
@@ -14968,7 +15008,7 @@ const List = React.memo((({children: children, variant: variant = "default", cl
|
|
|
14968
15008
|
children: child
|
|
14969
15009
|
})))
|
|
14970
15010
|
});
|
|
14971
|
-
})
|
|
15011
|
+
}, List = React.memo(ListComponentBase);
|
|
14972
15012
|
|
|
14973
15013
|
List.displayName = "List", List.Item = ListItem;
|
|
14974
15014
|
|
|
@@ -15919,12 +15959,12 @@ const SideMenu = React.forwardRef((({title: title, children: children, menuItem
|
|
|
15919
15959
|
const index = Number(key);
|
|
15920
15960
|
index >= currentLength && (delete nestedWrapperRefs.current[index], delete nestedInnerRefs.current[index]);
|
|
15921
15961
|
})));
|
|
15922
|
-
}), [ menuItems
|
|
15962
|
+
}), [ menuItems ]);
|
|
15923
15963
|
// Helper function to update nested wrapper height
|
|
15924
|
-
const updateNestedHeight = (index, isOpen) => {
|
|
15964
|
+
const updateNestedHeight = React.useCallback(((index, isOpen) => {
|
|
15925
15965
|
const wrapper = nestedWrapperRefs.current[index], inner = nestedInnerRefs.current[index];
|
|
15926
15966
|
wrapper && inner && (wrapper.style.height = isOpen ? `${inner.scrollHeight}px` : "0px");
|
|
15927
|
-
};
|
|
15967
|
+
}), []);
|
|
15928
15968
|
// Set initial heights for nested wrappers on mount and when menuItems change
|
|
15929
15969
|
React.useEffect((() => {
|
|
15930
15970
|
if (!menuItems?.length) return;
|
|
@@ -15938,7 +15978,7 @@ const SideMenu = React.forwardRef((({title: title, children: children, menuItem
|
|
|
15938
15978
|
// Only run when menuItems change, nestedItemStates is read but not in deps to avoid loops
|
|
15939
15979
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
15940
15980
|
;
|
|
15941
|
-
}), [ menuItems
|
|
15981
|
+
}), [ menuItems, updateNestedHeight ]),
|
|
15942
15982
|
// Update nested wrapper heights when state changes
|
|
15943
15983
|
React.useEffect((() => {
|
|
15944
15984
|
if (!menuItems?.length) return;
|
|
@@ -15951,7 +15991,7 @@ const SideMenu = React.forwardRef((({title: title, children: children, menuItem
|
|
|
15951
15991
|
})), () => {
|
|
15952
15992
|
frameIds.forEach((id => cancelAnimationFrame(id)));
|
|
15953
15993
|
};
|
|
15954
|
-
}), [ nestedItemStates, menuItems
|
|
15994
|
+
}), [ nestedItemStates, menuItems, updateNestedHeight ]);
|
|
15955
15995
|
// Combine refs using utility
|
|
15956
15996
|
const combinedRef = useForkRef(sideMenuRef, ref), sideMenuClass = generateSideMenuClass({
|
|
15957
15997
|
className: className,
|
|
@@ -16854,7 +16894,7 @@ React.useEffect((() => {
|
|
|
16854
16894
|
}
|
|
16855
16895
|
};
|
|
16856
16896
|
}));
|
|
16857
|
-
}), [
|
|
16897
|
+
}), [ currentIndex, calculateBounds, constrainPosition ]), setImagePosition = React.useCallback((position => {
|
|
16858
16898
|
setImageStates((prev => {
|
|
16859
16899
|
const currentState = prev[currentIndex] || {
|
|
16860
16900
|
zoomLevel: 1,
|
|
@@ -16904,7 +16944,7 @@ React.useEffect((() => {
|
|
|
16904
16944
|
}
|
|
16905
16945
|
};
|
|
16906
16946
|
}));
|
|
16907
|
-
}), [
|
|
16947
|
+
}), [ currentIndex, calculateBounds, constrainPosition ]), handleWheel = React.useCallback((event => {
|
|
16908
16948
|
var _context;
|
|
16909
16949
|
if (!isMounted || !event || !event.currentTarget) return;
|
|
16910
16950
|
// Additional safety check for the target element
|
|
@@ -17261,7 +17301,7 @@ React.useEffect((() => {
|
|
|
17261
17301
|
}
|
|
17262
17302
|
return prev;
|
|
17263
17303
|
}));
|
|
17264
|
-
}), [
|
|
17304
|
+
}), [ enableGestures, isDragging, startDragPosition, currentIndex, constrainPosition, calculateBounds ]), handleTouchEnd = React.useCallback((() => {
|
|
17265
17305
|
setIsDragging(!1), lastDistanceRef.current = null, lastMidpointRef.current = null;
|
|
17266
17306
|
}), []), currentState = imageStates[currentIndex] || {
|
|
17267
17307
|
zoomLevel: 1,
|
|
@@ -17465,9 +17505,9 @@ const PopoverContext = React.createContext({
|
|
|
17465
17505
|
triggerType: "click"
|
|
17466
17506
|
}), Popover = ({content: content, position: position = "top", trigger: trigger = "click", className: className = "", style: style, delay: delay = 0, offset: offset = 12, defaultOpen: defaultOpen = !1, isOpen: controlledIsOpen, onOpenChange: onOpenChange, closeOnClickOutside: closeOnClickOutside = !0, closeOnEscape: closeOnEscape = !0, id: id, children: children, glass: glass}) => {
|
|
17467
17507
|
const {isOpen: isOpen, setIsOpen: setIsOpen, triggerRef: triggerRef, popoverRef: popoverRef, arrowRef: arrowRef, popoverId: popoverId, currentPosition: currentPosition, updatePosition: updatePosition} = (({position: position = "top", trigger: trigger = "click", offset: offset = 12, delay: delay = 0, defaultOpen: defaultOpen = !1, isOpen: controlledIsOpen, onOpenChange: onOpenChange, closeOnClickOutside: closeOnClickOutside = !0, closeOnEscape: closeOnEscape = !0, id: id}) => {
|
|
17468
|
-
const [isOpen, setIsOpenState] = React.useState(defaultOpen), [currentPosition, setCurrentPosition] = React.useState("auto" === position ? "top" : position), triggerRef = React.useRef(null), popoverRef = React.useRef(null), arrowRef = React.useRef(null), timeoutRef = React.useRef(null), popoverId = id || `popover-${Math.random().toString(36).slice(2, 11)}`, isControlled = void 0 !== controlledIsOpen, isOpenState = isControlled ? controlledIsOpen : isOpen, setIsOpen = newIsOpen => {
|
|
17508
|
+
const [isOpen, setIsOpenState] = React.useState(defaultOpen), [currentPosition, setCurrentPosition] = React.useState("auto" === position ? "top" : position), triggerRef = React.useRef(null), popoverRef = React.useRef(null), arrowRef = React.useRef(null), timeoutRef = React.useRef(null), popoverId = id || `popover-${Math.random().toString(36).slice(2, 11)}`, isControlled = void 0 !== controlledIsOpen, isOpenState = isControlled ? controlledIsOpen : isOpen, setIsOpen = React.useCallback((newIsOpen => {
|
|
17469
17509
|
isControlled || setIsOpenState(newIsOpen), onOpenChange && onOpenChange(newIsOpen);
|
|
17470
|
-
};
|
|
17510
|
+
}), [ isControlled, onOpenChange ]);
|
|
17471
17511
|
// Handle hover events if trigger is hover
|
|
17472
17512
|
React.useEffect((() => {
|
|
17473
17513
|
if ("hover" !== trigger || !triggerRef.current || !popoverRef.current) return;
|
|
@@ -17487,17 +17527,16 @@ const PopoverContext = React.createContext({
|
|
|
17487
17527
|
setIsOpen(!1);
|
|
17488
17528
|
};
|
|
17489
17529
|
// Add hover event listeners
|
|
17490
|
-
|
|
17491
|
-
|
|
17492
|
-
|
|
17493
|
-
|
|
17494
|
-
|
|
17495
|
-
|
|
17496
|
-
|
|
17497
|
-
null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
|
|
17530
|
+
triggerRef.current.addEventListener("mouseenter", handleTriggerMouseEnter), triggerRef.current.addEventListener("mouseleave", handleTriggerMouseLeave),
|
|
17531
|
+
popoverRef.current.addEventListener("mouseenter", handlePopoverMouseEnter), popoverRef.current.addEventListener("mouseleave", handlePopoverMouseLeave);
|
|
17532
|
+
const currentTrigger = triggerRef.current, currentPopover = popoverRef.current;
|
|
17533
|
+
return () => {
|
|
17534
|
+
currentTrigger && (currentTrigger.removeEventListener("mouseenter", handleTriggerMouseEnter),
|
|
17535
|
+
currentTrigger.removeEventListener("mouseleave", handleTriggerMouseLeave)), currentPopover && (currentPopover.removeEventListener("mouseenter", handlePopoverMouseEnter),
|
|
17536
|
+
currentPopover.removeEventListener("mouseleave", handlePopoverMouseLeave)), null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
|
|
17498
17537
|
};
|
|
17499
|
-
}), [ trigger, delay, isOpenState ]);
|
|
17500
|
-
const updatePosition = event => {
|
|
17538
|
+
}), [ trigger, delay, isOpenState, setIsOpen ]);
|
|
17539
|
+
const updatePosition = React.useCallback((event => {
|
|
17501
17540
|
if (!triggerRef.current || !popoverRef.current) return;
|
|
17502
17541
|
const triggerRect = triggerRef.current.getBoundingClientRect(), popoverRect = popoverRef.current.getBoundingClientRect(), viewportWidth = window.innerWidth, viewportHeight = window.innerHeight, isNearViewportEdge = triggerRect.top < 50 || triggerRect.bottom > viewportHeight - 50 || triggerRect.left < 50 || triggerRect.right > viewportWidth - 50;
|
|
17503
17542
|
// If this is a scroll update and trigger isn't near edges, skip repositioning
|
|
@@ -17558,9 +17597,9 @@ const PopoverContext = React.createContext({
|
|
|
17558
17597
|
// Add scroll position to convert viewport coordinates to absolute position
|
|
17559
17598
|
const absoluteTop = top + window.scrollY, absoluteLeft = left + window.scrollX;
|
|
17560
17599
|
// Apply position using absolute positioning to follow when scrolling
|
|
17561
|
-
popoverRef.current.style.position = "absolute", popoverRef.current.style.top = `${absoluteTop}px`,
|
|
17562
|
-
popoverRef.current.style.left = `${absoluteLeft}px
|
|
17563
|
-
};
|
|
17600
|
+
popoverRef.current && (popoverRef.current.style.position = "absolute", popoverRef.current.style.top = `${absoluteTop}px`,
|
|
17601
|
+
popoverRef.current.style.left = `${absoluteLeft}px`);
|
|
17602
|
+
}), [ position, offset ]);
|
|
17564
17603
|
// Position the popover
|
|
17565
17604
|
return React.useEffect((() => {
|
|
17566
17605
|
if (!isOpenState || !triggerRef.current || !popoverRef.current) return;
|
|
@@ -17586,7 +17625,7 @@ const PopoverContext = React.createContext({
|
|
|
17586
17625
|
window.removeEventListener("resize", updatePosition), window.removeEventListener("scroll", handleScroll),
|
|
17587
17626
|
scrollTimeout && clearTimeout(scrollTimeout), clearInterval(intervalId);
|
|
17588
17627
|
};
|
|
17589
|
-
}), [ isOpenState,
|
|
17628
|
+
}), [ isOpenState, updatePosition ]),
|
|
17590
17629
|
// Handle click outside to close popover
|
|
17591
17630
|
React.useEffect((() => {
|
|
17592
17631
|
if (!isOpenState || !closeOnClickOutside) return;
|
|
@@ -17596,7 +17635,7 @@ const PopoverContext = React.createContext({
|
|
|
17596
17635
|
return document.addEventListener("mousedown", handleClickOutside), () => {
|
|
17597
17636
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
17598
17637
|
};
|
|
17599
|
-
}), [ isOpenState, closeOnClickOutside ]),
|
|
17638
|
+
}), [ isOpenState, closeOnClickOutside, setIsOpen ]),
|
|
17600
17639
|
// Handle escape key to close popover
|
|
17601
17640
|
React.useEffect((() => {
|
|
17602
17641
|
if (!isOpenState || !closeOnEscape) return;
|
|
@@ -17606,7 +17645,7 @@ const PopoverContext = React.createContext({
|
|
|
17606
17645
|
return document.addEventListener("keydown", handleEscapeKey), () => {
|
|
17607
17646
|
document.removeEventListener("keydown", handleEscapeKey);
|
|
17608
17647
|
};
|
|
17609
|
-
}), [ isOpenState, closeOnEscape ]),
|
|
17648
|
+
}), [ isOpenState, closeOnEscape, setIsOpen ]),
|
|
17610
17649
|
// Clean up on unmount
|
|
17611
17650
|
React.useEffect((() => () => {
|
|
17612
17651
|
null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
|
|
@@ -17787,10 +17826,11 @@ const calculateStarValue = (e, starValue, allowHalf) => {
|
|
|
17787
17826
|
}), [ readOnly, onChange, allowHalf ]);
|
|
17788
17827
|
// Use vanilla JS implementation if specified
|
|
17789
17828
|
React.useEffect((() => {
|
|
17790
|
-
if (useVanillaJS
|
|
17829
|
+
if (!useVanillaJS || "undefined" == typeof window || !internalRef.current) return;
|
|
17830
|
+
const currentInstance = ratingInstance.current;
|
|
17791
17831
|
// Cleanup on unmount
|
|
17792
|
-
|
|
17793
|
-
|
|
17832
|
+
return () => {
|
|
17833
|
+
currentInstance && currentInstance.destroy();
|
|
17794
17834
|
};
|
|
17795
17835
|
}), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, variant, onChange ]),
|
|
17796
17836
|
// Update vanilla JS implementation when props change
|
|
@@ -17911,10 +17951,11 @@ const ProductReview = ({productName: productName, productImage: productImage, in
|
|
|
17911
17951
|
const [rating, setRating] = React.useState(initialRating), [comment, setComment] = React.useState(""), [submitted, setSubmitted] = React.useState(!1), reviewRef = React.useRef(null), reviewInstance = React.useRef(null);
|
|
17912
17952
|
React.useEffect((() => {
|
|
17913
17953
|
// Only run on client-side
|
|
17914
|
-
if ("undefined"
|
|
17954
|
+
if ("undefined" == typeof window || !reviewRef.current) return;
|
|
17955
|
+
const currentInstance = reviewInstance.current;
|
|
17915
17956
|
// Cleanup on unmount
|
|
17916
|
-
|
|
17917
|
-
|
|
17957
|
+
return () => {
|
|
17958
|
+
currentInstance && currentInstance.destroy();
|
|
17918
17959
|
};
|
|
17919
17960
|
}), [ productName, productImage, initialRating, maxRating, allowHalf, ratingColor, onSubmit ]);
|
|
17920
17961
|
const handleSubmit = e => {
|
|
@@ -18159,10 +18200,11 @@ const SectionIntro = ({title: title, label: label, text: text, actions: actions,
|
|
|
18159
18200
|
const sectionIntroRef = React.useRef(null), sectionIntroInstance = React.useRef(null);
|
|
18160
18201
|
React.useEffect((() => {
|
|
18161
18202
|
// Only run on client-side
|
|
18162
|
-
if ("undefined"
|
|
18203
|
+
if ("undefined" == typeof window || !sectionIntroRef.current) return;
|
|
18204
|
+
const currentInstance = sectionIntroInstance.current;
|
|
18163
18205
|
// Cleanup on unmount
|
|
18164
|
-
|
|
18165
|
-
|
|
18206
|
+
return () => {
|
|
18207
|
+
currentInstance && currentInstance.destroy();
|
|
18166
18208
|
};
|
|
18167
18209
|
}), [ alignment, backgroundImageSrc, showOverlay, size, skeleton ]);
|
|
18168
18210
|
// Determine CSS classes
|
|
@@ -18246,7 +18288,7 @@ SectionIntro.displayName = "SectionIntro";
|
|
|
18246
18288
|
|
|
18247
18289
|
const Slider = React.forwardRef(((props, ref) => {
|
|
18248
18290
|
const {slides: slides = [], height: height = 300, width: width = "100%", slidesToShow: slidesToShow = 1, spaceBetween: spaceBetween = 0, loop: loop = !1, initialSlide: initialSlide = 0, direction: direction = "horizontal", speed: speed = 300, allowTouchMove: allowTouchMove = !0, threshold: threshold = 50, grabCursor: grabCursor = !0, autoplay: autoplay, navigation: navigation, pagination: pagination, className: className, style: style, onSlideChange: onSlideChange, ...rest} = props, validSlides = Array.isArray(slides) ? slides : [], slider = function(options) {
|
|
18249
|
-
const {slides: rawSlides, slidesToShow: slidesToShow = 1, spaceBetween: spaceBetween = 0, loop: loop = !1, initialSlide: initialSlide = 0, direction: direction = "horizontal", speed: speed = 300, allowTouchMove: allowTouchMove = !0, threshold: threshold = 50, autoplay: autoplay, onSlideChange: onSlideChange} = options, slides = Array.isArray(rawSlides) ? rawSlides : [], containerRef = React.useRef(null), wrapperRef = React.useRef(null), repositioningRef = React.useRef(!1), autoplayRef = React.useRef(null), [autoplayRunning, setAutoplayRunning] = React.useState(!1), sliderStateRef = React.useRef({
|
|
18291
|
+
const {slides: rawSlides, slidesToShow: slidesToShow = 1, spaceBetween: spaceBetween = 0, loop: loop = !1, initialSlide: initialSlide = 0, direction: direction = "horizontal", speed: speed = 300, allowTouchMove: allowTouchMove = !0, threshold: threshold = 50, autoplay: autoplay, onSlideChange: onSlideChange} = options, slides = React.useMemo((() => Array.isArray(rawSlides) ? rawSlides : []), [ rawSlides ]), containerRef = React.useRef(null), wrapperRef = React.useRef(null), repositioningRef = React.useRef(!1), autoplayRef = React.useRef(null), [autoplayRunning, setAutoplayRunning] = React.useState(!1), sliderStateRef = React.useRef({
|
|
18250
18292
|
isTransitioning: !1,
|
|
18251
18293
|
loop: loop,
|
|
18252
18294
|
slides: slides,
|
|
@@ -18381,7 +18423,7 @@ const Slider = React.forwardRef(((props, ref) => {
|
|
|
18381
18423
|
setIsTransitioning(!1), onSlideChange?.(nextIndex);
|
|
18382
18424
|
}), speed);
|
|
18383
18425
|
}
|
|
18384
|
-
}), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange,
|
|
18426
|
+
}), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange, autoplay ]), slidePrev = React.useCallback((() => {
|
|
18385
18427
|
if (!isTransitioning) if (
|
|
18386
18428
|
// Stop autoplay on interaction if disableOnInteraction is true
|
|
18387
18429
|
autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
|
|
@@ -18403,7 +18445,7 @@ const Slider = React.forwardRef(((props, ref) => {
|
|
|
18403
18445
|
setIsTransitioning(!1), onSlideChange?.(prevIndex);
|
|
18404
18446
|
}), speed);
|
|
18405
18447
|
}
|
|
18406
|
-
}), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange,
|
|
18448
|
+
}), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange, autoplay ]), goToSlide = React.useCallback((index => {
|
|
18407
18449
|
isTransitioning || index === realIndex || (
|
|
18408
18450
|
// Stop autoplay on interaction if disableOnInteraction is true
|
|
18409
18451
|
autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
|
|
@@ -18411,7 +18453,7 @@ const Slider = React.forwardRef(((props, ref) => {
|
|
|
18411
18453
|
setRealIndex(index), setInternalIndex(loop ? slides.length + index : index), setTimeout((() => {
|
|
18412
18454
|
setIsTransitioning(!1), onSlideChange?.(index);
|
|
18413
18455
|
}), speed));
|
|
18414
|
-
}), [ realIndex, isTransitioning, speed, onSlideChange, loop,
|
|
18456
|
+
}), [ realIndex, isTransitioning, speed, onSlideChange, loop, slides.length, autoplay ]), handleTouchStart = React.useCallback((e => {
|
|
18415
18457
|
if (!allowTouchMove) return;
|
|
18416
18458
|
// Stop autoplay on interaction if disableOnInteraction is true
|
|
18417
18459
|
autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
|
|
@@ -18666,7 +18708,7 @@ const Steps = ({items: items, activeIndex: activeIndex = 0, vertical: vertical =
|
|
|
18666
18708
|
let content;
|
|
18667
18709
|
React.useEffect((() => {
|
|
18668
18710
|
currentStep !== activeIndex && setCurrentStep(activeIndex);
|
|
18669
|
-
}), [ activeIndex ]),
|
|
18711
|
+
}), [ activeIndex, currentStep ]),
|
|
18670
18712
|
// Legacy rendering
|
|
18671
18713
|
content = items && items.length > 0 ? items.map(((item, index) => jsxRuntime.jsx(StepsItem, {
|
|
18672
18714
|
index: index,
|
|
@@ -18810,7 +18852,7 @@ const TabsPanel = React.forwardRef((({children: children, className: className
|
|
|
18810
18852
|
|
|
18811
18853
|
TabsPanel.displayName = "TabsPanel";
|
|
18812
18854
|
|
|
18813
|
-
const
|
|
18855
|
+
const TabsComponentBase = ({items: items, activeIndex: activeIndex = TAB.DEFAULTS.ACTIVE_INDEX, onTabChange: onTabChange, className: className = "", style: style, glass: glass, children: children}) => {
|
|
18814
18856
|
const [currentTab, setCurrentTab] = React.useState(activeIndex), handleTabClick = index => {
|
|
18815
18857
|
setCurrentTab(index), onTabChange && onTabChange(index);
|
|
18816
18858
|
}, handleKeyDown = (event, totalTabs) => {
|
|
@@ -18926,7 +18968,7 @@ const Tabs = React.memo((({items: items, activeIndex: activeIndex = TAB.DEFAULT
|
|
|
18926
18968
|
});
|
|
18927
18969
|
}
|
|
18928
18970
|
return wrapper;
|
|
18929
|
-
})
|
|
18971
|
+
}, Tabs = React.memo(TabsComponentBase);
|
|
18930
18972
|
|
|
18931
18973
|
Tabs.displayName = "Tabs", Tabs.List = TabsList, Tabs.Trigger = TabsTrigger, Tabs.Panels = TabsPanels,
|
|
18932
18974
|
Tabs.Panel = TabsPanel;
|
|
@@ -18938,10 +18980,11 @@ const Testimonial = ({quote: quote, author: author, size: size = "", skeleton: s
|
|
|
18938
18980
|
const testimonialRef = React.useRef(null), testimonialInstance = React.useRef(null);
|
|
18939
18981
|
React.useEffect((() => {
|
|
18940
18982
|
// Only run on client-side
|
|
18941
|
-
if ("undefined"
|
|
18983
|
+
if ("undefined" == typeof window || !testimonialRef.current) return;
|
|
18984
|
+
const currentInstance = testimonialInstance.current;
|
|
18942
18985
|
// Cleanup on unmount
|
|
18943
|
-
|
|
18944
|
-
|
|
18986
|
+
return () => {
|
|
18987
|
+
currentInstance && currentInstance.destroy();
|
|
18945
18988
|
};
|
|
18946
18989
|
}), [ size, skeleton ]);
|
|
18947
18990
|
// Determine CSS classes
|
|
@@ -20082,11 +20125,13 @@ const VideoPlayer = React.forwardRef((({src: src, type: type = "video", youtube
|
|
|
20082
20125
|
detectBorderRadius();
|
|
20083
20126
|
// Create ResizeObserver to watch for style changes
|
|
20084
20127
|
let resizeObserver = null;
|
|
20085
|
-
|
|
20128
|
+
"undefined" != typeof ResizeObserver && containerRef.current && (resizeObserver = new ResizeObserver(detectBorderRadius),
|
|
20086
20129
|
resizeObserver.observe(containerRef.current)),
|
|
20087
20130
|
// Also listen for window resize (in case styles change)
|
|
20088
|
-
window.addEventListener("resize", detectBorderRadius)
|
|
20089
|
-
|
|
20131
|
+
window.addEventListener("resize", detectBorderRadius);
|
|
20132
|
+
const currentContainer = containerRef.current;
|
|
20133
|
+
return () => {
|
|
20134
|
+
window.removeEventListener("resize", detectBorderRadius), resizeObserver && currentContainer && (resizeObserver.unobserve(currentContainer),
|
|
20090
20135
|
resizeObserver.disconnect());
|
|
20091
20136
|
};
|
|
20092
20137
|
}), []);
|
|
@@ -20856,7 +20901,51 @@ const defaultTokens = {
|
|
|
20856
20901
|
"breakpoint-md": "768px",
|
|
20857
20902
|
"breakpoint-lg": "992px",
|
|
20858
20903
|
"breakpoint-xl": "1200px",
|
|
20859
|
-
"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"
|
|
20860
20949
|
};
|
|
20861
20950
|
|
|
20862
20951
|
/**
|
|
@@ -20936,158 +21025,479 @@ const defaultTokens = {
|
|
|
20936
21025
|
}
|
|
20937
21026
|
|
|
20938
21027
|
/**
|
|
20939
|
-
* Theme
|
|
21028
|
+
* Theme Adapter
|
|
20940
21029
|
*
|
|
20941
|
-
*
|
|
20942
|
-
* Provides custom error classes and logging utilities.
|
|
21030
|
+
* Converts between Theme objects and DesignTokens
|
|
20943
21031
|
*/
|
|
20944
21032
|
/**
|
|
20945
|
-
* Theme
|
|
20946
|
-
*/
|
|
20947
|
-
|
|
20948
|
-
|
|
20949
|
-
|
|
20950
|
-
|
|
20951
|
-
|
|
20952
|
-
|
|
20953
|
-
|
|
20954
|
-
|
|
20955
|
-
|
|
20956
|
-
|
|
20957
|
-
|
|
20958
|
-
|
|
20959
|
-
|
|
20960
|
-
|
|
20961
|
-
|
|
20962
|
-
|
|
20963
|
-
|
|
20964
|
-
|
|
20965
|
-
|
|
20966
|
-
|
|
20967
|
-
|
|
20968
|
-
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
|
|
20972
|
-
|
|
20973
|
-
|
|
20974
|
-
|
|
20975
|
-
|
|
20976
|
-
|
|
20977
|
-
|
|
20978
|
-
|
|
20979
|
-
|
|
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
|
+
}
|
|
20980
21156
|
|
|
20981
21157
|
/**
|
|
20982
|
-
*
|
|
20983
|
-
|
|
20984
|
-
|
|
20985
|
-
|
|
20986
|
-
|
|
20987
|
-
|
|
20988
|
-
|
|
20989
|
-
|
|
20990
|
-
|
|
20991
|
-
|
|
20992
|
-
|
|
20993
|
-
|
|
20994
|
-
|
|
20995
|
-
|
|
20996
|
-
|
|
20997
|
-
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21001
|
-
|
|
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
|
+
}
|
|
21002
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;
|
|
21003
21274
|
}
|
|
21004
21275
|
|
|
21005
21276
|
/**
|
|
21006
|
-
*
|
|
21007
|
-
*/
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
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
|
+
}
|
|
21011
21283
|
|
|
21012
21284
|
/**
|
|
21013
|
-
*
|
|
21285
|
+
* Converts DesignTokens to CSS variables
|
|
21014
21286
|
*
|
|
21015
|
-
*
|
|
21016
|
-
*
|
|
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
|
|
21017
21301
|
*/
|
|
21018
|
-
|
|
21019
|
-
|
|
21020
|
-
|
|
21021
|
-
|
|
21022
|
-
|
|
21023
|
-
|
|
21024
|
-
|
|
21025
|
-
|
|
21026
|
-
|
|
21027
|
-
|
|
21028
|
-
|
|
21029
|
-
|
|
21030
|
-
|
|
21031
|
-
|
|
21032
|
-
|
|
21033
|
-
|
|
21034
|
-
|
|
21035
|
-
|
|
21036
|
-
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
|
|
21302
|
+
/**
|
|
21303
|
+
* Validate Atomix configuration structure
|
|
21304
|
+
*
|
|
21305
|
+
* Performs basic validation to catch common configuration errors early.
|
|
21306
|
+
* Returns warnings for potential issues.
|
|
21307
|
+
*
|
|
21308
|
+
* @param config - Configuration object to validate
|
|
21309
|
+
* @returns Array of validation warnings (empty if valid)
|
|
21310
|
+
*
|
|
21311
|
+
* @example
|
|
21312
|
+
* ```typescript
|
|
21313
|
+
* import { loadAtomixConfig, validateConfig } from '@shohojdhara/atomix/config';
|
|
21314
|
+
*
|
|
21315
|
+
* const config = loadAtomixConfig();
|
|
21316
|
+
* const warnings = validateConfig(config);
|
|
21317
|
+
* warnings.forEach(w => console.warn(w));
|
|
21318
|
+
* ```
|
|
21319
|
+
*/
|
|
21320
|
+
function validateConfig$1(config) {
|
|
21321
|
+
const warnings = [];
|
|
21322
|
+
// Check prefix format
|
|
21323
|
+
// Check theme structure
|
|
21324
|
+
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"`),
|
|
21325
|
+
config.prefix.length < 2 && warnings.push(`Prefix "${config.prefix}" is too short. Use at least 2 characters for clarity.\nExample: "app" instead of "a"`)),
|
|
21326
|
+
config.theme && (
|
|
21327
|
+
// Warn if both extend and tokens are provided
|
|
21328
|
+
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."),
|
|
21329
|
+
config.theme.extend)) {
|
|
21330
|
+
const extend = config.theme.extend, validThemeKeys = [ "colors", "typography", "spacing", "borderRadius", "shadows", "zIndex", "transitions", "breakpoints" ];
|
|
21331
|
+
// Check for common typos in theme properties
|
|
21332
|
+
Object.keys(extend).forEach((key => {
|
|
21333
|
+
_includesInstanceProperty(validThemeKeys).call(validThemeKeys, key) || warnings.push(`Unknown theme property: "${key}"\nValid properties: ${validThemeKeys.join(", ")}\nDid you mean one of these? Check for typos.`);
|
|
21334
|
+
}));
|
|
21042
21335
|
}
|
|
21043
|
-
|
|
21044
|
-
|
|
21045
|
-
|
|
21046
|
-
|
|
21047
|
-
|
|
21336
|
+
// Validate advanced features
|
|
21337
|
+
if (config.interactiveEffects) {
|
|
21338
|
+
const ie = config.interactiveEffects;
|
|
21339
|
+
// Validate vortex settings
|
|
21340
|
+
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"),
|
|
21341
|
+
ie.vortex.radius && ie.vortex.radius < 0 && warnings.push("Vortex radius should be a positive number"),
|
|
21342
|
+
ie.vortex.decay && (ie.vortex.decay <= 0 || ie.vortex.decay > 1) && warnings.push("Vortex decay should be between 0 and 1")),
|
|
21343
|
+
// Validate chromatic aberration settings
|
|
21344
|
+
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"),
|
|
21345
|
+
ie.chromaticAberration.blueShift && Math.abs(ie.chromaticAberration.blueShift) > .1 && warnings.push("Chromatic blue shift value seems unusually high (>0.1), verify this is intended"),
|
|
21346
|
+
ie.chromaticAberration.edgeThreshold && (ie.chromaticAberration.edgeThreshold < 0 || ie.chromaticAberration.edgeThreshold > 1) && warnings.push("Chromatic edge threshold should be between 0 and 1")),
|
|
21347
|
+
// Validate mouse interaction settings
|
|
21348
|
+
ie.mouseInteraction && ie.mouseInteraction.sensitivity && ie.mouseInteraction.sensitivity < 0 && warnings.push("Mouse sensitivity should be a positive number"),
|
|
21349
|
+
// Validate animation speed settings
|
|
21350
|
+
ie.animationSpeed && (ie.animationSpeed.base && ie.animationSpeed.base <= 0 && warnings.push("Animation base speed should be greater than 0"),
|
|
21351
|
+
ie.animationSpeed.timeMultiplier && ie.animationSpeed.timeMultiplier <= 0 && warnings.push("Animation time multiplier should be greater than 0"));
|
|
21048
21352
|
}
|
|
21049
|
-
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
|
|
21353
|
+
// Validate optimization settings
|
|
21354
|
+
if (config.optimization) {
|
|
21355
|
+
const opt = config.optimization;
|
|
21356
|
+
// Validate responsive breakpoints
|
|
21357
|
+
if (opt.responsive && opt.responsive.breakpoints) {
|
|
21358
|
+
const breakpoints = opt.responsive.breakpoints;
|
|
21359
|
+
breakpoints.mobile && !isValidCSSLength(breakpoints.mobile) && warnings.push("Mobile breakpoint value is not a valid CSS length"),
|
|
21360
|
+
breakpoints.tablet && !isValidCSSLength(breakpoints.tablet) && warnings.push("Tablet breakpoint value is not a valid CSS length"),
|
|
21361
|
+
breakpoints.desktop && !isValidCSSLength(breakpoints.desktop) && warnings.push("Desktop breakpoint value is not a valid CSS length"),
|
|
21362
|
+
breakpoints.wide && !isValidCSSLength(breakpoints.wide) && warnings.push("Wide breakpoint value is not a valid CSS length");
|
|
21363
|
+
}
|
|
21364
|
+
// Validate device scaling
|
|
21365
|
+
if (opt.responsive && opt.responsive.deviceScaling) {
|
|
21366
|
+
const scaling = opt.responsive.deviceScaling;
|
|
21367
|
+
scaling.mobile && (scaling.mobile <= 0 || scaling.mobile > 1) && warnings.push("Mobile device scaling should be between 0 and 1"),
|
|
21368
|
+
scaling.tablet && (scaling.tablet <= 0 || scaling.tablet > 1) && warnings.push("Tablet device scaling should be between 0 and 1"),
|
|
21369
|
+
scaling.desktop && (scaling.desktop <= 0 || scaling.desktop > 1) && warnings.push("Desktop device scaling should be between 0 and 1");
|
|
21370
|
+
}
|
|
21371
|
+
// Validate performance settings
|
|
21372
|
+
// Validate auto-scaling thresholds
|
|
21373
|
+
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)"),
|
|
21374
|
+
opt.autoScaling && opt.autoScaling.qualityThresholds) {
|
|
21375
|
+
const thresholds = opt.autoScaling.qualityThresholds;
|
|
21376
|
+
thresholds.lowEnd && (thresholds.lowEnd < 0 || thresholds.lowEnd > 1) && warnings.push("Auto-scaling low-end threshold should be between 0 and 1"),
|
|
21377
|
+
thresholds.midRange && (thresholds.midRange < 0 || thresholds.midRange > 1) && warnings.push("Auto-scaling mid-range threshold should be between 0 and 1"),
|
|
21378
|
+
thresholds.highEnd && (thresholds.highEnd < 0 || thresholds.highEnd > 1) && warnings.push("Auto-scaling high-end threshold should be between 0 and 1");
|
|
21379
|
+
}
|
|
21054
21380
|
}
|
|
21055
|
-
|
|
21056
|
-
|
|
21057
|
-
|
|
21058
|
-
|
|
21381
|
+
// Validate visual polish settings
|
|
21382
|
+
if (config.visualPolish) {
|
|
21383
|
+
const vp = config.visualPolish;
|
|
21384
|
+
// Validate content aware blur settings
|
|
21385
|
+
vp.contentAwareBlur && (void 0 !== vp.contentAwareBlur.edgePreservation && "boolean" != typeof vp.contentAwareBlur.edgePreservation && warnings.push("Content-aware blur edge preservation should be a boolean value"),
|
|
21386
|
+
void 0 !== vp.contentAwareBlur.depthDetection && "boolean" != typeof vp.contentAwareBlur.depthDetection && warnings.push("Content-aware blur depth detection should be a boolean value")),
|
|
21387
|
+
// Validate holographic effects settings
|
|
21388
|
+
vp.holographicEffects && (void 0 !== vp.holographicEffects.enabled && "boolean" != typeof vp.holographicEffects.enabled && warnings.push("Holographic effects enabled should be a boolean value"),
|
|
21389
|
+
void 0 !== vp.holographicEffects.rainbowDiffraction && "boolean" != typeof vp.holographicEffects.rainbowDiffraction && warnings.push("Holographic rainbow diffraction should be a boolean value"));
|
|
21059
21390
|
}
|
|
21391
|
+
// Validate AI settings
|
|
21392
|
+
var _context;
|
|
21393
|
+
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`),
|
|
21394
|
+
config.ai.temperature && (config.ai.temperature < 0 || config.ai.temperature > 1) && warnings.push("AI temperature should be between 0 and 1"),
|
|
21395
|
+
config.ai.maxTokens && config.ai.maxTokens < 100 && warnings.push("AI maxTokens should typically be 100 or more"),
|
|
21396
|
+
config.ai.rateLimit && (config.ai.rateLimit.requests <= 0 && warnings.push("AI rate limit requests should be greater than 0"),
|
|
21397
|
+
config.ai.rateLimit.windowMs <= 0 && warnings.push("AI rate limit window should be greater than 0"))),
|
|
21398
|
+
// Validate telemetry settings
|
|
21399
|
+
config.telemetry && config.telemetry.path && !config.telemetry.path.endsWith(".json") && warnings.push("Telemetry path should typically end with .json"),
|
|
21400
|
+
warnings;
|
|
21060
21401
|
}
|
|
21061
21402
|
|
|
21062
21403
|
/**
|
|
21063
|
-
*
|
|
21064
|
-
*/
|
|
21404
|
+
* Helper function to validate CSS length values
|
|
21405
|
+
*/ function isValidCSSLength(value) {
|
|
21406
|
+
return /^(\d+(\.\d+)?)(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ex|ch)?$/.test(value);
|
|
21407
|
+
}
|
|
21065
21408
|
|
|
21066
21409
|
/**
|
|
21067
|
-
*
|
|
21068
|
-
|
|
21069
|
-
|
|
21410
|
+
* Load Atomix configuration from project root
|
|
21411
|
+
*
|
|
21412
|
+
* Attempts to load atomix.config.ts, atomix.config.js, or atomix.config.json from the current working directory.
|
|
21413
|
+
* Falls back to default config if file doesn't exist.
|
|
21414
|
+
*
|
|
21415
|
+
* @param options - Loader options
|
|
21416
|
+
* @returns Loaded configuration or default
|
|
21417
|
+
*
|
|
21418
|
+
* @example
|
|
21419
|
+
* ```typescript
|
|
21420
|
+
* import { loadAtomixConfig } from '@shohojdhara/atomix/config';
|
|
21421
|
+
* import { createTheme } from '@shohojdhara/atomix/theme';
|
|
21422
|
+
*
|
|
21423
|
+
* const config = loadAtomixConfig();
|
|
21424
|
+
* const theme = createTheme(config.theme?.tokens || {});
|
|
21425
|
+
* ```
|
|
21426
|
+
*/ function loadAtomixConfig(options = {}) {
|
|
21427
|
+
const {configPath: configPath, required: required = !1} = options, defaultConfig = {
|
|
21428
|
+
prefix: "atomix",
|
|
21429
|
+
theme: {
|
|
21430
|
+
extend: {}
|
|
21431
|
+
}
|
|
21432
|
+
};
|
|
21433
|
+
// Default config
|
|
21434
|
+
// In browser environments, config loading is not supported
|
|
21435
|
+
if ("undefined" != typeof window) {
|
|
21436
|
+
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');
|
|
21437
|
+
return defaultConfig;
|
|
21438
|
+
}
|
|
21439
|
+
// If a specific config path is provided, try to load it directly
|
|
21440
|
+
if (configPath) return loadConfigAtPath(configPath, required, defaultConfig);
|
|
21441
|
+
// Otherwise, try standard locations in order of preference
|
|
21442
|
+
const possiblePaths = [ "atomix.config.ts", "atomix.config.js", "atomix.config.json" ];
|
|
21443
|
+
for (const path of possiblePaths) {
|
|
21444
|
+
const config = loadConfigAtPath(path, !1, defaultConfig);
|
|
21445
|
+
// If we found a valid config, return it
|
|
21446
|
+
if (JSON.stringify(config) !== JSON.stringify(defaultConfig)) return config;
|
|
21447
|
+
}
|
|
21448
|
+
// If no config file was found or all contained only defaults, return default config
|
|
21449
|
+
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');
|
|
21450
|
+
return defaultConfig;
|
|
21451
|
+
}
|
|
21452
|
+
|
|
21453
|
+
/**
|
|
21454
|
+
* Helper function to load config from a specific path
|
|
21455
|
+
*/ function loadConfigAtPath(path, required, defaultConfig) {
|
|
21456
|
+
try {
|
|
21457
|
+
// Use dynamic import for ESM compatibility
|
|
21458
|
+
const configModule = require(path), config = configModule.default || configModule;
|
|
21459
|
+
// Validate it's an AtomixConfig
|
|
21460
|
+
if (config && "object" == typeof config) return config;
|
|
21461
|
+
throw new Error("Invalid config format");
|
|
21462
|
+
} catch (error) {
|
|
21463
|
+
if (required) throw new Error(`Failed to load config from ${path}: ${error.message}`);
|
|
21464
|
+
// Return default config if not required
|
|
21465
|
+
return defaultConfig;
|
|
21466
|
+
}
|
|
21070
21467
|
}
|
|
21071
21468
|
|
|
21469
|
+
/**
|
|
21470
|
+
* Resolve config path
|
|
21471
|
+
*
|
|
21472
|
+
* Finds atomix.config.ts in the project, checking common locations.
|
|
21473
|
+
* Returns null in browser environments where file system access is not available.
|
|
21474
|
+
*
|
|
21475
|
+
* This function is designed to help tools identify if a config exists without loading it.
|
|
21476
|
+
*
|
|
21477
|
+
* @param configPath - Optional custom path to check
|
|
21478
|
+
* @returns Absolute path to config file or null if not found
|
|
21479
|
+
*/
|
|
21072
21480
|
/**
|
|
21073
21481
|
* Core Theme Functions
|
|
21074
21482
|
*
|
|
21075
|
-
*
|
|
21483
|
+
* Unified theme system that handles both DesignTokens and Theme objects.
|
|
21076
21484
|
* Config-first approach: loads from atomix.config.ts when no input is provided.
|
|
21485
|
+
* Config-first approach: loads advanced features from config when available.
|
|
21077
21486
|
*/
|
|
21078
21487
|
/**
|
|
21079
|
-
* Create theme CSS from
|
|
21488
|
+
* Create theme CSS from tokens or Theme object
|
|
21080
21489
|
*
|
|
21081
21490
|
* **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
|
|
21491
|
+
* Config file is required for automatic loading.
|
|
21082
21492
|
*
|
|
21083
|
-
* @param input - DesignTokens (partial) or undefined (loads from config)
|
|
21493
|
+
* @param input - DesignTokens (partial), Theme object, or undefined (loads from config)
|
|
21084
21494
|
* @param options - CSS generation options (prefix is automatically read from config if not provided)
|
|
21085
21495
|
* @returns CSS string with custom properties
|
|
21086
21496
|
* @throws Error if config loading fails when no input is provided
|
|
21087
21497
|
*
|
|
21088
21498
|
* @example
|
|
21089
21499
|
* ```typescript
|
|
21090
|
-
* // Loads from atomix.config.ts
|
|
21500
|
+
* // Loads from atomix.config.ts (config file required)
|
|
21091
21501
|
* const css = createTheme();
|
|
21092
21502
|
*
|
|
21093
21503
|
* // Using DesignTokens
|
|
@@ -21096,42 +21506,151 @@ class ThemeLogger {
|
|
|
21096
21506
|
* 'spacing-4': '1rem',
|
|
21097
21507
|
* });
|
|
21098
21508
|
*
|
|
21509
|
+
* // Using Theme object
|
|
21510
|
+
* const theme = createThemeObject({ palette: { primary: { main: '#7c3aed' } } });
|
|
21511
|
+
* const css = createTheme(theme);
|
|
21512
|
+
*
|
|
21099
21513
|
* // With custom options
|
|
21100
21514
|
* const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
|
|
21101
21515
|
* ```
|
|
21102
|
-
*/
|
|
21103
|
-
|
|
21104
|
-
|
|
21105
|
-
|
|
21106
|
-
|
|
21107
|
-
|
|
21108
|
-
|
|
21109
|
-
|
|
21110
|
-
|
|
21111
|
-
|
|
21112
|
-
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21516
|
+
*/
|
|
21517
|
+
function createTheme(input, options) {
|
|
21518
|
+
let tokens, configPrefix;
|
|
21519
|
+
// If no input provided, load from config (required)
|
|
21520
|
+
if (input)
|
|
21521
|
+
// Convert Theme object to DesignTokens
|
|
21522
|
+
tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
|
|
21523
|
+
const configTokens = function() {
|
|
21524
|
+
// Check if we're in a browser environment
|
|
21525
|
+
if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
|
|
21526
|
+
// Use dynamic import to load the config loader
|
|
21527
|
+
// This allows bundlers to handle external dependencies properly
|
|
21528
|
+
let loadAtomixConfig;
|
|
21529
|
+
try {
|
|
21530
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
21531
|
+
const {loadAtomixConfig: loader} = require("../../config/loader");
|
|
21532
|
+
loadAtomixConfig = loader;
|
|
21533
|
+
} catch (error) {
|
|
21534
|
+
throw new Error("Config loader module not available");
|
|
21535
|
+
}
|
|
21536
|
+
const config = loadAtomixConfig({
|
|
21537
|
+
configPath: undefined,
|
|
21538
|
+
required: !0
|
|
21539
|
+
});
|
|
21540
|
+
if (!config?.theme) return createTokens({});
|
|
21541
|
+
if ((obj = config.theme) && "object" == typeof obj && (obj.palette || obj.typography || obj.spacing || obj.breakpoints || obj.colors)) return themeToDesignTokens(config.theme);
|
|
21542
|
+
// Handle the config.theme object which has extend/tokens/themes properties
|
|
21543
|
+
// Extract the actual tokens from the theme configuration
|
|
21544
|
+
// Helper type guard function
|
|
21545
|
+
var obj;
|
|
21546
|
+
const themeConfig = config.theme;
|
|
21547
|
+
let tokensToApply = {};
|
|
21548
|
+
return themeConfig.tokens ?
|
|
21549
|
+
// If tokens is provided, use it as the base
|
|
21550
|
+
tokensToApply = themeConfig.tokens : themeConfig.extend && (
|
|
21551
|
+
// If only extend is provided, use it as overrides
|
|
21552
|
+
tokensToApply = themeConfig.extend),
|
|
21553
|
+
// Apply advanced feature configurations as tokens
|
|
21554
|
+
config.interactiveEffects && (
|
|
21555
|
+
// Vortex effects
|
|
21556
|
+
config.interactiveEffects.vortex && (tokensToApply = {
|
|
21557
|
+
...tokensToApply,
|
|
21558
|
+
"interactive-vortex-enabled": String(config.interactiveEffects.vortex.enabled ?? !1),
|
|
21559
|
+
"interactive-vortex-strength": String(config.interactiveEffects.vortex.strength ?? .5),
|
|
21560
|
+
"interactive-vortex-radius": String(config.interactiveEffects.vortex.radius ?? 100),
|
|
21561
|
+
"interactive-vortex-decay": String(config.interactiveEffects.vortex.decay ?? .8)
|
|
21562
|
+
}),
|
|
21563
|
+
// Chromatic aberration
|
|
21564
|
+
config.interactiveEffects.chromaticAberration && (tokensToApply = {
|
|
21565
|
+
...tokensToApply,
|
|
21566
|
+
"interactive-chromatic-enabled": String(config.interactiveEffects.chromaticAberration.enabled ?? !1),
|
|
21567
|
+
"interactive-chromatic-mode": config.interactiveEffects.chromaticAberration.mode ?? "lateral",
|
|
21568
|
+
"interactive-chromatic-red-shift": String(config.interactiveEffects.chromaticAberration.redShift ?? .02),
|
|
21569
|
+
"interactive-chromatic-green-shift": String(config.interactiveEffects.chromaticAberration.greenShift ?? 0),
|
|
21570
|
+
"interactive-chromatic-blue-shift": String(config.interactiveEffects.chromaticAberration.blueShift ?? -.02),
|
|
21571
|
+
"interactive-chromatic-edge-only": String(config.interactiveEffects.chromaticAberration.edgeOnly ?? !1),
|
|
21572
|
+
"interactive-chromatic-edge-threshold": String(config.interactiveEffects.chromaticAberration.edgeThreshold ?? .5)
|
|
21573
|
+
}),
|
|
21574
|
+
// Mouse interaction
|
|
21575
|
+
config.interactiveEffects.mouseInteraction && (tokensToApply = {
|
|
21576
|
+
...tokensToApply,
|
|
21577
|
+
"interactive-mouse-sensitivity": String(config.interactiveEffects.mouseInteraction.sensitivity ?? 1),
|
|
21578
|
+
"interactive-mouse-trail-effect": String(config.interactiveEffects.mouseInteraction.trailEffect ?? !1)
|
|
21579
|
+
}),
|
|
21580
|
+
// Animation speed
|
|
21581
|
+
config.interactiveEffects.animationSpeed && (tokensToApply = {
|
|
21582
|
+
...tokensToApply,
|
|
21583
|
+
"interactive-animation-speed-base": String(config.interactiveEffects.animationSpeed.base ?? 1),
|
|
21584
|
+
"interactive-animation-speed-multiplier": String(config.interactiveEffects.animationSpeed.timeMultiplier ?? 1)
|
|
21585
|
+
})),
|
|
21586
|
+
// Apply optimization configurations as tokens
|
|
21587
|
+
config.optimization && (
|
|
21588
|
+
// Responsive breakpoints
|
|
21589
|
+
config.optimization.responsive && (config.optimization.responsive.breakpoints && (tokensToApply = {
|
|
21590
|
+
...tokensToApply,
|
|
21591
|
+
"optimization-breakpoint-mobile": config.optimization.responsive.breakpoints.mobile ?? "0px",
|
|
21592
|
+
"optimization-breakpoint-tablet": config.optimization.responsive.breakpoints.tablet ?? "768px",
|
|
21593
|
+
"optimization-breakpoint-desktop": config.optimization.responsive.breakpoints.desktop ?? "1024px",
|
|
21594
|
+
"optimization-breakpoint-wide": config.optimization.responsive.breakpoints.wide ?? "1440px"
|
|
21595
|
+
}), config.optimization.responsive.deviceScaling && (tokensToApply = {
|
|
21596
|
+
...tokensToApply,
|
|
21597
|
+
"optimization-device-scaling-mobile": String(config.optimization.responsive.deviceScaling.mobile ?? .5),
|
|
21598
|
+
"optimization-device-scaling-tablet": String(config.optimization.responsive.deviceScaling.tablet ?? .75),
|
|
21599
|
+
"optimization-device-scaling-desktop": String(config.optimization.responsive.deviceScaling.desktop ?? 1)
|
|
21600
|
+
})),
|
|
21601
|
+
// Performance settings
|
|
21602
|
+
config.optimization.performance && (tokensToApply = {
|
|
21603
|
+
...tokensToApply,
|
|
21604
|
+
"optimization-performance-fps-target": String(config.optimization.performance.fpsTarget ?? 60),
|
|
21605
|
+
"optimization-auto-scaling-enabled": String(config.optimization.performance.autoScaling ?? !1)
|
|
21606
|
+
}),
|
|
21607
|
+
// Auto-scaling settings
|
|
21608
|
+
config.optimization.autoScaling && (tokensToApply = {
|
|
21609
|
+
...tokensToApply,
|
|
21610
|
+
"optimization-auto-scaling-enabled": String(config.optimization.autoScaling.enabled ?? !1),
|
|
21611
|
+
"optimization-auto-scaling-low-end": String(config.optimization.autoScaling.qualityThresholds?.lowEnd ?? .5),
|
|
21612
|
+
"optimization-auto-scaling-mid-range": String(config.optimization.autoScaling.qualityThresholds?.midRange ?? .75),
|
|
21613
|
+
"optimization-auto-scaling-high-end": String(config.optimization.autoScaling.qualityThresholds?.highEnd ?? 1)
|
|
21614
|
+
})),
|
|
21615
|
+
// Apply visual polish configurations as tokens
|
|
21616
|
+
config.visualPolish && (config.visualPolish.borders && (tokensToApply = {
|
|
21617
|
+
...tokensToApply,
|
|
21618
|
+
"visual-polish-border-iridescent-glow": String(config.visualPolish.borders.iridescentGlow ?? !1),
|
|
21619
|
+
"visual-polish-border-shimmer-effect": String(config.visualPolish.borders.shimmerEffect ?? !1),
|
|
21620
|
+
"visual-polish-border-beveled-edges": String(config.visualPolish.borders.beveledEdges ?? !1),
|
|
21621
|
+
"visual-polish-border-pulsing-glow": String(config.visualPolish.borders.pulsingGlow ?? !1)
|
|
21622
|
+
}), config.visualPolish.contentAwareBlur && (tokensToApply = {
|
|
21623
|
+
...tokensToApply,
|
|
21624
|
+
"visual-polish-content-aware-blur-enabled": String(config.visualPolish.contentAwareBlur.enabled ?? !1),
|
|
21625
|
+
"visual-polish-content-aware-depth-detection": String(config.visualPolish.contentAwareBlur.depthDetection ?? !1),
|
|
21626
|
+
"visual-polish-content-aware-edge-preservation": String(config.visualPolish.contentAwareBlur.edgePreservation ?? !1),
|
|
21627
|
+
"visual-polish-content-aware-variable-radius": String(config.visualPolish.contentAwareBlur.variableRadius ?? !1)
|
|
21628
|
+
}), config.visualPolish.holographicEffects && (tokensToApply = {
|
|
21629
|
+
...tokensToApply,
|
|
21630
|
+
"visual-polish-holographic-enabled": String(config.visualPolish.holographicEffects.enabled ?? !1),
|
|
21631
|
+
"visual-polish-holographic-rainbow-diffraction": String(config.visualPolish.holographicEffects.rainbowDiffraction ?? !1),
|
|
21632
|
+
"visual-polish-holographic-scanline-animation": String(config.visualPolish.holographicEffects.scanlineAnimation ?? !1),
|
|
21633
|
+
"visual-polish-holographic-grid-overlay": String(config.visualPolish.holographicEffects.gridOverlay ?? !1),
|
|
21634
|
+
"visual-polish-holographic-data-stream": String(config.visualPolish.holographicEffects.dataStream ?? !1),
|
|
21635
|
+
"visual-polish-holographic-pulse-rings": String(config.visualPolish.holographicEffects.pulseRings ?? !1)
|
|
21636
|
+
})), createTokens(tokensToApply);
|
|
21637
|
+
}();
|
|
21638
|
+
// Get prefix from config
|
|
21639
|
+
try {
|
|
21640
|
+
// Use the imported function directly instead of require to avoid bundling issues
|
|
21641
|
+
const config = loadAtomixConfig({
|
|
21642
|
+
configPath: "atomix.config.ts",
|
|
21643
|
+
required: !0
|
|
21644
|
+
});
|
|
21645
|
+
configPrefix = config?.prefix;
|
|
21646
|
+
} catch (error) {
|
|
21647
|
+
// Prefix loading failed, but tokens were loaded, so continue
|
|
21648
|
+
}
|
|
21649
|
+
tokens = configTokens;
|
|
21124
21650
|
}
|
|
21125
21651
|
// Merge with defaults and generate CSS
|
|
21126
|
-
|
|
21127
|
-
//
|
|
21128
|
-
// If no input is provided, we return an empty theme (using defaults only) or user must provide tokens.
|
|
21129
|
-
// This allows createTheme to be isomorphic.
|
|
21130
|
-
// Warn in development if no input provided
|
|
21131
|
-
"production" !== process.env.NODE_ENV && "undefined" != typeof window && console.warn("Atomix: createTheme() called without tokens. Using default tokens only."),
|
|
21132
|
-
tokens = {};
|
|
21133
|
-
const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
|
|
21134
|
-
// Get prefix from options or use default
|
|
21652
|
+
const allTokens = createTokens(tokens), prefix = options?.prefix ?? configPrefix ?? "atomix";
|
|
21653
|
+
// Get prefix from options, config, or use default
|
|
21135
21654
|
return generateCSSVariables$1(allTokens, {
|
|
21136
21655
|
...options,
|
|
21137
21656
|
prefix: prefix
|
|
@@ -21345,17 +21864,150 @@ class ThemeLogger {
|
|
|
21345
21864
|
*/
|
|
21346
21865
|
/**
|
|
21347
21866
|
* Default storage key for theme persistence
|
|
21348
|
-
*/
|
|
21349
|
-
|
|
21867
|
+
*/
|
|
21350
21868
|
/**
|
|
21351
|
-
*
|
|
21869
|
+
* Theme System Error Handling
|
|
21870
|
+
*
|
|
21871
|
+
* Centralized error handling for the Atomix theme system.
|
|
21872
|
+
* Provides custom error classes and logging utilities.
|
|
21352
21873
|
*/
|
|
21353
|
-
|
|
21354
|
-
|
|
21355
|
-
|
|
21356
|
-
|
|
21357
|
-
|
|
21358
|
-
|
|
21874
|
+
/**
|
|
21875
|
+
* Theme error codes
|
|
21876
|
+
*/
|
|
21877
|
+
var ThemeErrorCode, LogLevel;
|
|
21878
|
+
|
|
21879
|
+
"undefined" != typeof process && process.env, function(ThemeErrorCode) {
|
|
21880
|
+
/** Theme not found in registry */
|
|
21881
|
+
ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
|
|
21882
|
+
/** Theme failed to load */
|
|
21883
|
+
ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
|
|
21884
|
+
/** Theme validation failed */
|
|
21885
|
+
ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
|
|
21886
|
+
/** Configuration loading failed */
|
|
21887
|
+
ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
|
|
21888
|
+
/** Configuration validation failed */
|
|
21889
|
+
ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
|
|
21890
|
+
/** Circular dependency detected */
|
|
21891
|
+
ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
|
|
21892
|
+
/** Missing dependency */
|
|
21893
|
+
ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
|
|
21894
|
+
/** Storage operation failed */
|
|
21895
|
+
ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
|
|
21896
|
+
/** Invalid theme name */
|
|
21897
|
+
ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
|
|
21898
|
+
/** CSS injection failed */
|
|
21899
|
+
ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
|
|
21900
|
+
/** Invalid color format */
|
|
21901
|
+
ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
|
|
21902
|
+
/** Missing required token */
|
|
21903
|
+
ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
|
|
21904
|
+
/** Accessibility contrast violation */
|
|
21905
|
+
ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
|
|
21906
|
+
/** Invalid token type */
|
|
21907
|
+
ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
|
|
21908
|
+
/** Unknown error */
|
|
21909
|
+
ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
|
21910
|
+
}(ThemeErrorCode || (ThemeErrorCode = {}));
|
|
21911
|
+
|
|
21912
|
+
/**
|
|
21913
|
+
* Custom error class for theme-related errors
|
|
21914
|
+
*/
|
|
21915
|
+
class ThemeError extends Error {
|
|
21916
|
+
constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
|
|
21917
|
+
super(message), this.name = "ThemeError", this.code = code, this.context = context,
|
|
21918
|
+
this.timestamp = Date.now(),
|
|
21919
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
21920
|
+
Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
|
|
21921
|
+
}
|
|
21922
|
+
/**
|
|
21923
|
+
* Convert error to JSON for logging
|
|
21924
|
+
*/ toJSON() {
|
|
21925
|
+
return {
|
|
21926
|
+
name: this.name,
|
|
21927
|
+
message: this.message,
|
|
21928
|
+
code: this.code,
|
|
21929
|
+
context: this.context,
|
|
21930
|
+
timestamp: this.timestamp,
|
|
21931
|
+
stack: this.stack
|
|
21932
|
+
};
|
|
21933
|
+
}
|
|
21934
|
+
}
|
|
21935
|
+
|
|
21936
|
+
/**
|
|
21937
|
+
* Log level
|
|
21938
|
+
*/ !function(LogLevel) {
|
|
21939
|
+
LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
|
|
21940
|
+
LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
|
|
21941
|
+
}(LogLevel || (LogLevel = {}));
|
|
21942
|
+
|
|
21943
|
+
/**
|
|
21944
|
+
* Theme Logger
|
|
21945
|
+
*
|
|
21946
|
+
* Centralized logging for the theme system.
|
|
21947
|
+
* Replaces console statements with structured logging.
|
|
21948
|
+
*/
|
|
21949
|
+
class ThemeLogger {
|
|
21950
|
+
constructor(config = {}) {
|
|
21951
|
+
this.config = {
|
|
21952
|
+
level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
|
|
21953
|
+
enableConsole: config.enableConsole ?? !0,
|
|
21954
|
+
onError: config.onError,
|
|
21955
|
+
onWarn: config.onWarn,
|
|
21956
|
+
onInfo: config.onInfo,
|
|
21957
|
+
onDebug: config.onDebug
|
|
21958
|
+
};
|
|
21959
|
+
}
|
|
21960
|
+
/**
|
|
21961
|
+
* Log an error
|
|
21962
|
+
*/ error(message, error, context) {
|
|
21963
|
+
if (this.config.level < LogLevel.ERROR) return;
|
|
21964
|
+
const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
|
|
21965
|
+
this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
|
|
21966
|
+
error: errorObj,
|
|
21967
|
+
context: {
|
|
21968
|
+
...context,
|
|
21969
|
+
...themeError.context
|
|
21970
|
+
},
|
|
21971
|
+
code: themeError.code
|
|
21972
|
+
}), this.config.onError?.(themeError, context);
|
|
21973
|
+
}
|
|
21974
|
+
/**
|
|
21975
|
+
* Log a warning
|
|
21976
|
+
*/ warn(message, context) {
|
|
21977
|
+
this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
|
|
21978
|
+
this.config.onWarn?.(message, context));
|
|
21979
|
+
}
|
|
21980
|
+
/**
|
|
21981
|
+
* Log an info message
|
|
21982
|
+
*/ info(message, context) {
|
|
21983
|
+
this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
|
|
21984
|
+
this.config.onInfo?.(message, context));
|
|
21985
|
+
}
|
|
21986
|
+
/**
|
|
21987
|
+
* Log a debug message
|
|
21988
|
+
*/ debug(message, context) {
|
|
21989
|
+
this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
|
|
21990
|
+
}
|
|
21991
|
+
}
|
|
21992
|
+
|
|
21993
|
+
/**
|
|
21994
|
+
* Default logger instance
|
|
21995
|
+
*/ let defaultLogger = null;
|
|
21996
|
+
|
|
21997
|
+
/**
|
|
21998
|
+
* Get or create default logger
|
|
21999
|
+
*/ function getLogger() {
|
|
22000
|
+
return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
|
|
22001
|
+
}
|
|
22002
|
+
|
|
22003
|
+
/**
|
|
22004
|
+
* Check if code is running in a browser environment
|
|
22005
|
+
*/ 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
|
|
22006
|
+
, buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
|
|
22007
|
+
// Validate theme name to prevent path injection
|
|
22008
|
+
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, {
|
|
22009
|
+
themeName: themeName,
|
|
22010
|
+
pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/
|
|
21359
22011
|
});
|
|
21360
22012
|
const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
|
|
21361
22013
|
return cdnPath ? `${sanitizePath(cdnPath)}/${fileName}` : `${sanitizePath(basePath)}/${fileName.replace(/^\//, "")}`;
|
|
@@ -21434,105 +22086,427 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
21434
22086
|
}))
|
|
21435
22087
|
});
|
|
21436
22088
|
|
|
22089
|
+
// ============================================================================
|
|
22090
|
+
// Theme Mode Switching
|
|
22091
|
+
// ============================================================================
|
|
21437
22092
|
/**
|
|
21438
|
-
*
|
|
22093
|
+
* Switch between light and dark themes
|
|
21439
22094
|
*
|
|
21440
|
-
*
|
|
21441
|
-
*
|
|
21442
|
-
|
|
22095
|
+
* Automatically toggles a class on the root element and persists the choice.
|
|
22096
|
+
*
|
|
22097
|
+
* @param mode - Theme mode ('light', 'dark', or 'system')
|
|
22098
|
+
* @param options - Configuration options
|
|
22099
|
+
*
|
|
22100
|
+
* @example
|
|
22101
|
+
* ```typescript
|
|
22102
|
+
* import { switchTheme } from '@shohojdhara/atomix/theme/utils';
|
|
22103
|
+
*
|
|
22104
|
+
* // Switch to dark mode
|
|
22105
|
+
* switchTheme('dark');
|
|
22106
|
+
*
|
|
22107
|
+
* // Toggle between light/dark
|
|
22108
|
+
* const current = getCurrentTheme();
|
|
22109
|
+
* switchTheme(current === 'dark' ? 'light' : 'dark');
|
|
22110
|
+
* ```
|
|
22111
|
+
*/ function switchTheme(mode, options = {}) {
|
|
22112
|
+
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);
|
|
22113
|
+
// Determine actual mode (resolve 'system')
|
|
22114
|
+
if (root) {
|
|
22115
|
+
// Add transition class if enabled
|
|
22116
|
+
if (enableTransition) {
|
|
22117
|
+
const htmlRoot = root;
|
|
22118
|
+
htmlRoot.style.transition = `all ${transitionDuration}ms ease-in-out`,
|
|
22119
|
+
// Remove transition after it completes
|
|
22120
|
+
setTimeout((() => {
|
|
22121
|
+
htmlRoot.style.transition = "";
|
|
22122
|
+
}), transitionDuration);
|
|
22123
|
+
}
|
|
22124
|
+
// Apply theme class
|
|
22125
|
+
root.classList.remove("atomix-theme-light", "atomix-theme-dark"), root.classList.add(`atomix-theme-${resolvedMode}`),
|
|
22126
|
+
// Set data attribute for CSS selectors
|
|
22127
|
+
root.setAttribute("data-theme", resolvedMode),
|
|
22128
|
+
// Persist choice
|
|
22129
|
+
persistTheme(resolvedMode, {
|
|
22130
|
+
storageKey: storageKey
|
|
22131
|
+
}),
|
|
22132
|
+
// Dispatch custom event for listeners
|
|
22133
|
+
window.dispatchEvent(new CustomEvent("atomix-theme-change", {
|
|
22134
|
+
detail: {
|
|
22135
|
+
mode: resolvedMode
|
|
22136
|
+
}
|
|
22137
|
+
}));
|
|
22138
|
+
}
|
|
22139
|
+
}
|
|
22140
|
+
|
|
22141
|
+
/**
|
|
22142
|
+
* Toggle between light and dark themes
|
|
22143
|
+
*
|
|
22144
|
+
* @param options - Configuration options
|
|
22145
|
+
* @returns The new theme mode
|
|
22146
|
+
*
|
|
22147
|
+
* @example
|
|
22148
|
+
* ```typescript
|
|
22149
|
+
* const newMode = toggleTheme();
|
|
22150
|
+
* console.log('Switched to:', newMode);
|
|
22151
|
+
* ```
|
|
22152
|
+
*/ function toggleTheme(options = {}) {
|
|
22153
|
+
const next = "dark" === getCurrentTheme(options.storageKey) ? "light" : "dark";
|
|
22154
|
+
return switchTheme(next, options), next;
|
|
22155
|
+
}
|
|
22156
|
+
|
|
22157
|
+
/**
|
|
22158
|
+
* Get current theme mode
|
|
22159
|
+
*
|
|
22160
|
+
* @param storageKey - Storage key (default: 'atomix-theme')
|
|
22161
|
+
* @returns Current theme mode or 'light' if not set
|
|
22162
|
+
*/ function getCurrentTheme(storageKey = "atomix-theme") {
|
|
22163
|
+
return "undefined" == typeof window ? "light" : localStorage.getItem(storageKey) || "light";
|
|
22164
|
+
}
|
|
22165
|
+
|
|
22166
|
+
/**
|
|
22167
|
+
* Get system theme preference
|
|
22168
|
+
*
|
|
22169
|
+
* @returns 'dark' if system prefers dark mode, 'light' otherwise
|
|
22170
|
+
*/ function getSystemTheme() {
|
|
22171
|
+
return "undefined" == typeof window ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
22172
|
+
}
|
|
22173
|
+
|
|
22174
|
+
/**
|
|
22175
|
+
* Initialize theme based on saved preference or system preference
|
|
22176
|
+
*
|
|
22177
|
+
* Call this once at app startup.
|
|
22178
|
+
*
|
|
22179
|
+
* @param options - Configuration options
|
|
22180
|
+
* @returns The initialized theme mode
|
|
22181
|
+
*
|
|
22182
|
+
* @example
|
|
22183
|
+
* ```typescript
|
|
22184
|
+
* // In your app entry point
|
|
22185
|
+
* import { initializeTheme } from '@shohojdhara/atomix/theme/utils';
|
|
22186
|
+
*
|
|
22187
|
+
* const theme = initializeTheme();
|
|
22188
|
+
* console.log('Theme initialized:', theme);
|
|
22189
|
+
* ```
|
|
22190
|
+
*/ function initializeTheme(options = {}) {
|
|
22191
|
+
const saved = getCurrentTheme(options.storageKey);
|
|
22192
|
+
// If no saved preference, use system preference
|
|
22193
|
+
if (!saved || "system" === saved) {
|
|
22194
|
+
const system = getSystemTheme();
|
|
22195
|
+
return switchTheme(system, options), system;
|
|
22196
|
+
}
|
|
22197
|
+
// Use saved preference
|
|
22198
|
+
return switchTheme(saved, options), saved;
|
|
22199
|
+
}
|
|
22200
|
+
|
|
22201
|
+
/**
|
|
22202
|
+
* Listen for system theme changes
|
|
22203
|
+
*
|
|
22204
|
+
* @param callback - Function to call when system theme changes
|
|
22205
|
+
* @returns Cleanup function to stop listening
|
|
22206
|
+
*
|
|
22207
|
+
* @example
|
|
22208
|
+
* ```typescript
|
|
22209
|
+
* const cleanup = listenToSystemTheme((mode) => {
|
|
22210
|
+
* console.log('System theme changed to:', mode);
|
|
22211
|
+
* switchTheme(mode);
|
|
22212
|
+
* });
|
|
22213
|
+
*
|
|
22214
|
+
* // Later, when component unmounts
|
|
22215
|
+
* cleanup();
|
|
22216
|
+
* ```
|
|
22217
|
+
*/ function listenToSystemTheme(callback) {
|
|
22218
|
+
if ("undefined" == typeof window) return () => {};
|
|
22219
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"), handler = e => {
|
|
22220
|
+
callback(e.matches ? "dark" : "light");
|
|
22221
|
+
};
|
|
22222
|
+
// Modern browsers
|
|
22223
|
+
return mediaQuery.addEventListener ? (mediaQuery.addEventListener("change", handler),
|
|
22224
|
+
() => mediaQuery.removeEventListener("change", handler)) : (
|
|
22225
|
+
// Fallback for older browsers
|
|
22226
|
+
mediaQuery.addListener(handler), () => mediaQuery.removeListener(handler));
|
|
22227
|
+
}
|
|
22228
|
+
|
|
22229
|
+
// ============================================================================
|
|
22230
|
+
// Theme Persistence
|
|
22231
|
+
// ============================================================================
|
|
22232
|
+
/**
|
|
22233
|
+
* Save theme preference to storage
|
|
22234
|
+
*
|
|
22235
|
+
* @param mode - Theme mode to save
|
|
22236
|
+
* @param options - Persistence options
|
|
22237
|
+
*/ function persistTheme(mode, options = {}) {
|
|
22238
|
+
if ("undefined" == typeof window) return;
|
|
22239
|
+
const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
|
|
22240
|
+
("localStorage" === storageType ? localStorage : sessionStorage).setItem(storageKey, mode);
|
|
22241
|
+
}
|
|
22242
|
+
|
|
22243
|
+
/**
|
|
22244
|
+
* Clear saved theme preference
|
|
22245
|
+
*
|
|
22246
|
+
* @param options - Persistence options
|
|
22247
|
+
*/ function clearThemePreference(options = {}) {
|
|
22248
|
+
if ("undefined" == typeof window) return;
|
|
22249
|
+
const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
|
|
22250
|
+
("localStorage" === storageType ? localStorage : sessionStorage).removeItem(storageKey);
|
|
22251
|
+
}
|
|
22252
|
+
|
|
21443
22253
|
// ============================================================================
|
|
21444
|
-
//
|
|
22254
|
+
// Theme Tokens Manipulation
|
|
21445
22255
|
// ============================================================================
|
|
21446
22256
|
/**
|
|
21447
|
-
*
|
|
22257
|
+
* Merge multiple token sets
|
|
22258
|
+
*
|
|
22259
|
+
* Deep merges token objects, with later tokens overriding earlier ones.
|
|
22260
|
+
*
|
|
22261
|
+
* @param tokens - Token objects to merge
|
|
22262
|
+
* @returns Merged tokens
|
|
22263
|
+
*
|
|
22264
|
+
* @example
|
|
22265
|
+
* ```typescript
|
|
22266
|
+
* const merged = mergeTokens(
|
|
22267
|
+
* baseTokens,
|
|
22268
|
+
* { colors: { primary: { main: '#custom' } } }
|
|
22269
|
+
* );
|
|
22270
|
+
* ```
|
|
22271
|
+
*/ function mergeTokens(...tokens) {
|
|
22272
|
+
return _reduceInstanceProperty(tokens).call(tokens, ((acc, current) => deepMerge(acc, current)), {});
|
|
22273
|
+
}
|
|
22274
|
+
|
|
22275
|
+
/**
|
|
22276
|
+
* Override specific tokens
|
|
22277
|
+
*
|
|
22278
|
+
* Creates a new token object with specific overrides.
|
|
22279
|
+
*
|
|
22280
|
+
* @param base - Base tokens
|
|
22281
|
+
* @param overrides - Tokens to override
|
|
22282
|
+
* @returns New tokens with overrides applied
|
|
22283
|
+
*
|
|
22284
|
+
* @example
|
|
22285
|
+
* ```typescript
|
|
22286
|
+
* const customized = overrideTokens(defaultTokens, {
|
|
22287
|
+
* colors: {
|
|
22288
|
+
* primary: { main: '#ff0000' }
|
|
22289
|
+
* }
|
|
22290
|
+
* });
|
|
22291
|
+
* ```
|
|
22292
|
+
*/ function overrideTokens(base, overrides) {
|
|
22293
|
+
return deepMerge({
|
|
22294
|
+
...base
|
|
22295
|
+
}, overrides);
|
|
22296
|
+
}
|
|
22297
|
+
|
|
22298
|
+
/**
|
|
22299
|
+
* Pick specific token categories
|
|
22300
|
+
*
|
|
22301
|
+
* Extracts only the specified categories from tokens.
|
|
22302
|
+
*
|
|
22303
|
+
* @param tokens - Source tokens
|
|
22304
|
+
* @param categories - Categories to pick
|
|
22305
|
+
* @returns Tokens with only selected categories
|
|
22306
|
+
*
|
|
22307
|
+
* @example
|
|
22308
|
+
* ```typescript
|
|
22309
|
+
* const colorTokens = pickTokens(allTokens, ['colors']);
|
|
22310
|
+
* ```
|
|
22311
|
+
*/ function pickTokens(tokens, categories) {
|
|
22312
|
+
const result = {};
|
|
22313
|
+
return categories.forEach((category => {
|
|
22314
|
+
tokens[category] && (result[category] = tokens[category]);
|
|
22315
|
+
})), result;
|
|
22316
|
+
}
|
|
22317
|
+
|
|
22318
|
+
/**
|
|
22319
|
+
* Omit specific token categories
|
|
22320
|
+
*
|
|
22321
|
+
* Removes specified categories from tokens.
|
|
22322
|
+
*
|
|
22323
|
+
* @param tokens - Source tokens
|
|
22324
|
+
* @param categories - Categories to omit
|
|
22325
|
+
* @returns Tokens without omitted categories
|
|
22326
|
+
*
|
|
22327
|
+
* @example
|
|
22328
|
+
* ```typescript
|
|
22329
|
+
* const withoutColors = omitTokens(allTokens, ['colors']);
|
|
22330
|
+
* ```
|
|
22331
|
+
*/ function omitTokens(tokens, categories) {
|
|
22332
|
+
const result = {
|
|
22333
|
+
...tokens
|
|
22334
|
+
};
|
|
22335
|
+
return categories.forEach((category => {
|
|
22336
|
+
delete result[category];
|
|
22337
|
+
})), result;
|
|
22338
|
+
}
|
|
22339
|
+
|
|
22340
|
+
// ============================================================================
|
|
22341
|
+
// Color Utilities
|
|
22342
|
+
// ============================================================================
|
|
22343
|
+
/**
|
|
22344
|
+
* Convert hex color to RGB
|
|
22345
|
+
*
|
|
22346
|
+
* @param hex - Hex color (with or without #)
|
|
22347
|
+
* @returns RGB object { r, g, b }
|
|
21448
22348
|
*/ function hexToRgb$1(hex) {
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21453
|
-
|
|
21454
|
-
|
|
22349
|
+
// Validate
|
|
22350
|
+
if (
|
|
22351
|
+
// Remove # if present
|
|
22352
|
+
// Handle shorthand hex
|
|
22353
|
+
3 === (hex = hex.replace(/^#/, "")).length && (hex = hex.split("").map((c => c + c)).join("")),
|
|
22354
|
+
6 !== hex.length) return null;
|
|
22355
|
+
const num = parseInt(hex, 16);
|
|
22356
|
+
return {
|
|
22357
|
+
r: num >> 16 & 255,
|
|
22358
|
+
g: num >> 8 & 255,
|
|
22359
|
+
b: 255 & num
|
|
22360
|
+
};
|
|
21455
22361
|
}
|
|
21456
22362
|
|
|
21457
22363
|
/**
|
|
21458
|
-
* Convert RGB to hex
|
|
22364
|
+
* Convert RGB to hex
|
|
22365
|
+
*
|
|
22366
|
+
* @param r - Red (0-255)
|
|
22367
|
+
* @param g - Green (0-255)
|
|
22368
|
+
* @param b - Blue (0-255)
|
|
22369
|
+
* @returns Hex color with #
|
|
21459
22370
|
*/ function rgbToHex(r, g, b) {
|
|
21460
|
-
|
|
21461
|
-
|
|
22371
|
+
return "#" + [ r, g, b ].map((x => {
|
|
22372
|
+
const hex = x.toString(16);
|
|
22373
|
+
return 1 === hex.length ? "0" + hex : hex;
|
|
22374
|
+
})).join("");
|
|
21462
22375
|
}
|
|
21463
22376
|
|
|
21464
22377
|
/**
|
|
21465
|
-
* Calculate
|
|
21466
|
-
*
|
|
21467
|
-
|
|
21468
|
-
|
|
22378
|
+
* Calculate luminance of a color
|
|
22379
|
+
*
|
|
22380
|
+
* Used for determining contrast ratios.
|
|
22381
|
+
*
|
|
22382
|
+
* @param hex - Hex color
|
|
22383
|
+
* @returns Luminance value (0-1)
|
|
22384
|
+
*/ function getLuminance(hex) {
|
|
22385
|
+
const rgb = hexToRgb$1(hex);
|
|
21469
22386
|
if (!rgb) return 0;
|
|
21470
|
-
const
|
|
21471
|
-
|
|
21472
|
-
return val <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
|
|
21473
|
-
}));
|
|
21474
|
-
return .2126 * (rs ?? 0) + .7152 * (gs ?? 0) + .0722 * (bs ?? 0);
|
|
22387
|
+
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)));
|
|
22388
|
+
return .2126 * (r ?? 0) + .7152 * (g ?? 0) + .0722 * (b ?? 0);
|
|
21475
22389
|
}
|
|
21476
22390
|
|
|
21477
22391
|
/**
|
|
21478
22392
|
* Calculate contrast ratio between two colors
|
|
21479
|
-
|
|
21480
|
-
|
|
21481
|
-
|
|
22393
|
+
*
|
|
22394
|
+
* @param hex1 - First hex color
|
|
22395
|
+
* @param hex2 - Second hex color
|
|
22396
|
+
* @returns Contrast ratio (1-21)
|
|
22397
|
+
*/ function getContrastRatio(hex1, hex2) {
|
|
22398
|
+
const lum1 = getLuminance(hex1), lum2 = getLuminance(hex2);
|
|
22399
|
+
return (Math.max(lum1, lum2) + .05) / (Math.min(lum1, lum2) + .05);
|
|
22400
|
+
}
|
|
22401
|
+
|
|
22402
|
+
/**
|
|
22403
|
+
* Check if text color passes WCAG AA standard
|
|
22404
|
+
*
|
|
22405
|
+
* @param textColor - Text color hex
|
|
22406
|
+
* @param backgroundColor - Background color hex
|
|
22407
|
+
* @param size - Font size ('small' or 'large')
|
|
22408
|
+
* @returns true if passes WCAG AA
|
|
22409
|
+
*/ function isAccessible(textColor, backgroundColor, size = "small") {
|
|
22410
|
+
return getContrastRatio(textColor, backgroundColor) >= ("large" === size ? 3 : 4.5);
|
|
21482
22411
|
}
|
|
21483
22412
|
|
|
21484
22413
|
/**
|
|
21485
|
-
* Get appropriate
|
|
21486
|
-
|
|
21487
|
-
|
|
21488
|
-
|
|
22414
|
+
* Get appropriate text color (black or white) for a background
|
|
22415
|
+
*
|
|
22416
|
+
* @param backgroundColor - Background hex color
|
|
22417
|
+
* @param threshold - Contrast threshold (default: 3)
|
|
22418
|
+
* @returns '#000000' or '#FFFFFF'
|
|
22419
|
+
*/ function getContrastText(backgroundColor, threshold = 3) {
|
|
22420
|
+
return getContrastRatio(backgroundColor, "#FFFFFF") >= threshold ? "#FFFFFF" : "#000000";
|
|
21489
22421
|
}
|
|
21490
22422
|
|
|
21491
22423
|
/**
|
|
21492
|
-
* Lighten a color
|
|
22424
|
+
* Lighten a color
|
|
21493
22425
|
*
|
|
21494
|
-
* @param
|
|
21495
|
-
* @param amount - Amount to lighten (0-1)
|
|
22426
|
+
* @param hex - Base hex color
|
|
22427
|
+
* @param amount - Amount to lighten (0-1)
|
|
21496
22428
|
* @returns Lightened hex color
|
|
21497
|
-
*/ function lighten(
|
|
21498
|
-
const rgb = hexToRgb$1(
|
|
21499
|
-
if (!rgb) return
|
|
21500
|
-
|
|
21501
|
-
|
|
22429
|
+
*/ function lighten(hex, amount = 0) {
|
|
22430
|
+
const rgb = hexToRgb$1(hex);
|
|
22431
|
+
if (!rgb) return hex;
|
|
22432
|
+
// Use amount directly as factor (0-1)
|
|
22433
|
+
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);
|
|
22434
|
+
return rgbToHex(Math.min(255, r), Math.min(255, g), Math.min(255, b));
|
|
21502
22435
|
}
|
|
21503
22436
|
|
|
21504
22437
|
/**
|
|
21505
|
-
* Darken a color
|
|
22438
|
+
* Darken a color
|
|
21506
22439
|
*
|
|
21507
|
-
* @param
|
|
21508
|
-
* @param amount - Amount to darken (0-1)
|
|
22440
|
+
* @param hex - Base hex color
|
|
22441
|
+
* @param amount - Amount to darken (0-1)
|
|
21509
22442
|
* @returns Darkened hex color
|
|
21510
|
-
*/ function darken(
|
|
21511
|
-
const rgb = hexToRgb$1(
|
|
21512
|
-
if (!rgb) return
|
|
21513
|
-
|
|
21514
|
-
|
|
22443
|
+
*/ function darken(hex, amount = 0) {
|
|
22444
|
+
const rgb = hexToRgb$1(hex);
|
|
22445
|
+
if (!rgb) return hex;
|
|
22446
|
+
// Use amount directly as factor (0-1)
|
|
22447
|
+
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));
|
|
22448
|
+
return rgbToHex(Math.max(0, r), Math.max(0, g), Math.max(0, b));
|
|
21515
22449
|
}
|
|
21516
22450
|
|
|
21517
22451
|
/**
|
|
21518
|
-
* Add alpha
|
|
22452
|
+
* Add alpha to a color
|
|
21519
22453
|
*
|
|
21520
|
-
* @param
|
|
22454
|
+
* @param hex - Hex color
|
|
21521
22455
|
* @param opacity - Opacity value (0-1)
|
|
21522
22456
|
* @returns RGBA color string
|
|
21523
|
-
*/ function alpha(
|
|
21524
|
-
const rgb = hexToRgb$1(
|
|
21525
|
-
if (!rgb) return
|
|
21526
|
-
const
|
|
21527
|
-
return `rgba(${r}, ${g}, ${b}, ${
|
|
22457
|
+
*/ function alpha(hex, opacity) {
|
|
22458
|
+
const rgb = hexToRgb$1(hex);
|
|
22459
|
+
if (!rgb) return hex;
|
|
22460
|
+
const validOpacity = Math.max(0, Math.min(1, opacity));
|
|
22461
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${validOpacity})`;
|
|
21528
22462
|
}
|
|
21529
22463
|
|
|
21530
22464
|
/**
|
|
21531
22465
|
* Emphasize a color (lighten if dark, darken if light)
|
|
21532
22466
|
*
|
|
21533
|
-
* @param
|
|
21534
|
-
* @param
|
|
22467
|
+
* @param hex - Hex color
|
|
22468
|
+
* @param amount - Amount to emphasize (0-1)
|
|
21535
22469
|
* @returns Emphasized hex color
|
|
22470
|
+
*/ function emphasize(hex, amount = .15) {
|
|
22471
|
+
return getLuminance(hex) > .5 ? darken(hex, amount) : lighten(hex, amount);
|
|
22472
|
+
}
|
|
22473
|
+
|
|
22474
|
+
/**
|
|
22475
|
+
* Create a spacing utility
|
|
22476
|
+
*
|
|
22477
|
+
* @param spacingInput - Spacing configuration
|
|
22478
|
+
* @returns Spacing function
|
|
22479
|
+
*/ function createSpacing(spacingInput = 4) {
|
|
22480
|
+
return (...values) => 0 === values.length ? "0px" : "function" == typeof spacingInput ? spacingInput(...values) : values.map((value => {
|
|
22481
|
+
if ("number" == typeof spacingInput) return value * spacingInput + "px";
|
|
22482
|
+
if (Array.isArray(spacingInput)) {
|
|
22483
|
+
const scaled = spacingInput[value];
|
|
22484
|
+
return "number" == typeof scaled ? `${scaled}px` : `${value}px`;
|
|
22485
|
+
}
|
|
22486
|
+
return `${value}px`;
|
|
22487
|
+
})).join(" ");
|
|
22488
|
+
}
|
|
22489
|
+
|
|
22490
|
+
/**
|
|
22491
|
+
* CSS Variable Generator
|
|
22492
|
+
*
|
|
22493
|
+
* Generates CSS custom properties from theme objects and injects them into the DOM.
|
|
22494
|
+
*
|
|
22495
|
+
* **Token Naming Alignment:**
|
|
22496
|
+
* This generator produces CSS variables that match the SCSS token naming pattern exactly:
|
|
22497
|
+
* - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
|
|
22498
|
+
* - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
|
|
22499
|
+
* - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
|
|
22500
|
+
* - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
|
|
22501
|
+
*
|
|
22502
|
+
* All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
|
|
22503
|
+
* This ensures compatibility between SCSS themes and JavaScript themes.
|
|
22504
|
+
*
|
|
22505
|
+
* @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
|
|
22506
|
+
*/
|
|
22507
|
+
/**
|
|
22508
|
+
* Convert a nested object to flat CSS variable declarations
|
|
22509
|
+
* Uses iterative approach for better performance with large objects
|
|
21536
22510
|
*/
|
|
21537
22511
|
/**
|
|
21538
22512
|
* Generate a color scale from a base color (1-10 steps)
|
|
@@ -21600,18 +22574,7 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
21600
22574
|
color.dark && (vars[`${prefix}-${key}-hover`] = color.dark),
|
|
21601
22575
|
// Generate semantic color variants (matches SCSS patterns)
|
|
21602
22576
|
// Text emphasis: emphasized version of the color for text (--atomix-primary-text-emphasis)
|
|
21603
|
-
vars[`${prefix}-${key}-text-emphasis`] =
|
|
21604
|
-
return getLuminance(color) > .5 ? darken(color, coefficient) : lighten(color, coefficient);
|
|
21605
|
-
}
|
|
21606
|
-
// ============================================================================
|
|
21607
|
-
// Spacing Utilities
|
|
21608
|
-
// ============================================================================
|
|
21609
|
-
/**
|
|
21610
|
-
* Create a spacing function from various input types
|
|
21611
|
-
*
|
|
21612
|
-
* @param spacingInput - Spacing configuration (number, array, or function), default 4
|
|
21613
|
-
* @returns Spacing function
|
|
21614
|
-
*/ (color.main, .15),
|
|
22577
|
+
vars[`${prefix}-${key}-text-emphasis`] = emphasize(color.main, .15),
|
|
21615
22578
|
// Background subtle: very light version for backgrounds (--atomix-primary-bg-subtle)
|
|
21616
22579
|
vars[`${prefix}-${key}-bg-subtle`] = alpha(color.main, .1),
|
|
21617
22580
|
// Border subtle: light version for borders (--atomix-primary-border-subtle)
|
|
@@ -21956,29 +22919,7 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
21956
22919
|
return vars[`${prefix}-focus-ring-width`] = "3px", vars[`${prefix}-focus-ring-offset`] = "2px",
|
|
21957
22920
|
vars[`${prefix}-focus-ring-opacity`] = "0.25", vars;
|
|
21958
22921
|
}(theme.palette, prefix)), theme.custom && Object.keys(theme.custom).length > 0) {
|
|
21959
|
-
const customVars =
|
|
21960
|
-
/**
|
|
21961
|
-
* CSS Variable Generator
|
|
21962
|
-
*
|
|
21963
|
-
* Generates CSS custom properties from theme objects and injects them into the DOM.
|
|
21964
|
-
*
|
|
21965
|
-
* **Token Naming Alignment:**
|
|
21966
|
-
* This generator produces CSS variables that match the SCSS token naming pattern exactly:
|
|
21967
|
-
* - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
|
|
21968
|
-
* - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
|
|
21969
|
-
* - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
|
|
21970
|
-
* - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
|
|
21971
|
-
*
|
|
21972
|
-
* All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
|
|
21973
|
-
* This ensures compatibility between SCSS themes and JavaScript themes.
|
|
21974
|
-
*
|
|
21975
|
-
* @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
|
|
21976
|
-
*/
|
|
21977
|
-
/**
|
|
21978
|
-
* Convert a nested object to flat CSS variable declarations
|
|
21979
|
-
* Uses iterative approach for better performance with large objects
|
|
21980
|
-
*/
|
|
21981
|
-
function(obj, prefix = "", result = {}) {
|
|
22922
|
+
const customVars = function(obj, prefix = "", result = {}) {
|
|
21982
22923
|
// Use iterative approach with stack to avoid deep recursion
|
|
21983
22924
|
const stack = [ {
|
|
21984
22925
|
obj: obj,
|
|
@@ -22432,19 +23373,29 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
|
|
|
22432
23373
|
// Check storage first
|
|
22433
23374
|
if (enablePersistence && storageAdapter.isAvailable()) {
|
|
22434
23375
|
const stored = storageAdapter.getItem(storageKey);
|
|
22435
|
-
if (stored)
|
|
23376
|
+
if (stored) {
|
|
23377
|
+
// If it looks like a JSON object, parse it
|
|
23378
|
+
if (stored.trim().startsWith("{")) try {
|
|
23379
|
+
return JSON.parse(stored);
|
|
23380
|
+
} catch (e) {
|
|
23381
|
+
return logger.error("Failed to parse stored theme tokens", e), stored;
|
|
23382
|
+
}
|
|
23383
|
+
return stored;
|
|
23384
|
+
}
|
|
22436
23385
|
}
|
|
22437
23386
|
// If defaultTheme is provided, use it
|
|
22438
23387
|
return null != defaultTheme ? defaultTheme : "default";
|
|
22439
23388
|
// Default fallback
|
|
22440
|
-
}), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
|
|
22441
|
-
//
|
|
22442
|
-
if (
|
|
23389
|
+
}), [ defaultTheme, enablePersistence, storageKey, storageAdapter ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
|
|
23390
|
+
// 1. Check if initialDefaultTheme (from storage) is an object
|
|
23391
|
+
if (initialDefaultTheme && "string" != typeof initialDefaultTheme) {
|
|
23392
|
+
const {tokens: tokens, validation: validation} = validateAndMergeTokens(initialDefaultTheme);
|
|
23393
|
+
if (validation.valid) return tokens;
|
|
23394
|
+
}
|
|
23395
|
+
// 2. Check if defaultTheme prop is an object
|
|
23396
|
+
if (defaultTheme && "string" != typeof defaultTheme) {
|
|
22443
23397
|
const {tokens: tokens, validation: validation} = validateAndMergeTokens(defaultTheme);
|
|
22444
|
-
|
|
22445
|
-
errors: validation.errors,
|
|
22446
|
-
warnings: validation.warnings
|
|
22447
|
-
}), createTokens({}));
|
|
23398
|
+
if (validation.valid) return tokens;
|
|
22448
23399
|
}
|
|
22449
23400
|
return null;
|
|
22450
23401
|
})), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
|
|
@@ -22456,10 +23407,14 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
|
|
|
22456
23407
|
React.useEffect((() => {
|
|
22457
23408
|
isServer() || applyThemeAttributes(String(currentTheme), dataAttribute);
|
|
22458
23409
|
}), [ currentTheme, dataAttribute ]),
|
|
22459
|
-
// Handle
|
|
23410
|
+
// Handle persistence
|
|
22460
23411
|
React.useEffect((() => {
|
|
22461
|
-
enablePersistence && storageAdapter.isAvailable() &&
|
|
22462
|
-
|
|
23412
|
+
enablePersistence && storageAdapter.isAvailable() && ("tokens-theme" === currentTheme ?
|
|
23413
|
+
// Only persist if we have actual tokens to store
|
|
23414
|
+
activeTokens && storageAdapter.setItem(storageKey, JSON.stringify(activeTokens)) :
|
|
23415
|
+
// Persist named theme string
|
|
23416
|
+
storageAdapter.setItem(storageKey, String(currentTheme)));
|
|
23417
|
+
}), [ currentTheme, activeTokens, enablePersistence, storageKey, storageAdapter ]),
|
|
22463
23418
|
// Cleanup: Remove completed promises and abort controllers on unmount
|
|
22464
23419
|
React.useEffect((() => () => {
|
|
22465
23420
|
// Cancel any in-flight theme loads
|
|
@@ -22600,20 +23555,21 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
|
|
|
22600
23555
|
setIsLoading(!1);
|
|
22601
23556
|
}
|
|
22602
23557
|
}
|
|
22603
|
-
}), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = React.useMemo((() => ({})), []), availableThemes = React.useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
|
|
23558
|
+
}), [ 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]) => ({
|
|
22604
23559
|
...metadata,
|
|
22605
23560
|
name: name
|
|
22606
23561
|
})))), [ themes ]), contextValue = React.useMemo((() => ({
|
|
22607
23562
|
theme: currentTheme,
|
|
22608
23563
|
activeTokens: activeTokens,
|
|
22609
23564
|
setTheme: setTheme,
|
|
23565
|
+
updateTheme: updateTheme,
|
|
22610
23566
|
availableThemes: availableThemes,
|
|
22611
23567
|
isLoading: isLoading,
|
|
22612
23568
|
error: error,
|
|
22613
23569
|
isThemeLoaded: isThemeLoaded,
|
|
22614
23570
|
preloadTheme: preloadTheme,
|
|
22615
23571
|
themeManager: themeManager
|
|
22616
|
-
})), [ currentTheme, activeTokens, setTheme, availableThemes,
|
|
23572
|
+
})), [ currentTheme, activeTokens, setTheme, updateTheme, availableThemes,
|
|
22617
23573
|
// Use memoized value
|
|
22618
23574
|
isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
|
|
22619
23575
|
// Check if theme is loaded
|
|
@@ -22667,6 +23623,7 @@ function useTheme() {
|
|
|
22667
23623
|
theme: context.theme,
|
|
22668
23624
|
activeTokens: context.activeTokens,
|
|
22669
23625
|
setTheme: context.setTheme,
|
|
23626
|
+
updateTheme: context.updateTheme,
|
|
22670
23627
|
availableThemes: context.availableThemes,
|
|
22671
23628
|
isLoading: context.isLoading,
|
|
22672
23629
|
error: context.error,
|
|
@@ -22902,6 +23859,389 @@ function useThemeTokens() {
|
|
|
22902
23859
|
}
|
|
22903
23860
|
}
|
|
22904
23861
|
|
|
23862
|
+
/**
|
|
23863
|
+
* useThemeSwitcher Hook
|
|
23864
|
+
*
|
|
23865
|
+
* React hook for managing theme switching with persistence and system preference detection.
|
|
23866
|
+
* Provides an easy-to-use API for dark/light mode toggling.
|
|
23867
|
+
*
|
|
23868
|
+
* @example
|
|
23869
|
+
* ```tsx
|
|
23870
|
+
* import { useThemeSwitcher } from '@shohojdhara/atomix/theme';
|
|
23871
|
+
*
|
|
23872
|
+
* function ThemeToggle() {
|
|
23873
|
+
* const { mode, toggle, setMode, isDark } = useThemeSwitcher();
|
|
23874
|
+
*
|
|
23875
|
+
* return (
|
|
23876
|
+
* <button onClick={toggle}>
|
|
23877
|
+
* {isDark ? '☀️ Light' : '🌙 Dark'}
|
|
23878
|
+
* </button>
|
|
23879
|
+
* );
|
|
23880
|
+
* }
|
|
23881
|
+
* ```
|
|
23882
|
+
*/
|
|
23883
|
+
/**
|
|
23884
|
+
* Hook for managing theme switching
|
|
23885
|
+
*
|
|
23886
|
+
* @param options - Configuration options
|
|
23887
|
+
* @returns Theme switcher controls
|
|
23888
|
+
*/ function useThemeSwitcher(options = {}) {
|
|
23889
|
+
const {initialMode: initialMode = "system", syncWithSystem: syncWithSystem = !1, storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, [mode, setModeState] = React.useState((() => {
|
|
23890
|
+
if ("undefined" == typeof window) return initialMode;
|
|
23891
|
+
// Check for saved preference first
|
|
23892
|
+
const saved = getCurrentTheme(storageKey);
|
|
23893
|
+
return saved && "system" !== saved ? saved : "system" === initialMode ? getSystemTheme() : initialMode;
|
|
23894
|
+
// Fall back to initial mode or system
|
|
23895
|
+
}));
|
|
23896
|
+
// State for current mode
|
|
23897
|
+
// Initialize theme on mount
|
|
23898
|
+
return React.useEffect((() => {
|
|
23899
|
+
"undefined" != typeof window && (
|
|
23900
|
+
// Initialize with proper theme application
|
|
23901
|
+
initializeTheme({
|
|
23902
|
+
storageKey: storageKey,
|
|
23903
|
+
enableTransition: enableTransition,
|
|
23904
|
+
transitionDuration: transitionDuration
|
|
23905
|
+
}),
|
|
23906
|
+
// Update state to match initialized theme
|
|
23907
|
+
setModeState(getCurrentTheme(storageKey)));
|
|
23908
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23909
|
+
// Listen for system theme changes if enabled
|
|
23910
|
+
React.useEffect((() => {
|
|
23911
|
+
if (syncWithSystem) return listenToSystemTheme((newMode => {
|
|
23912
|
+
setModeState(newMode), switchTheme(newMode, {
|
|
23913
|
+
storageKey: storageKey,
|
|
23914
|
+
enableTransition: enableTransition,
|
|
23915
|
+
transitionDuration: transitionDuration
|
|
23916
|
+
});
|
|
23917
|
+
}));
|
|
23918
|
+
}), [ syncWithSystem, storageKey, enableTransition, transitionDuration ]), {
|
|
23919
|
+
mode: mode,
|
|
23920
|
+
isDark: "dark" === mode,
|
|
23921
|
+
isLight: "light" === mode,
|
|
23922
|
+
toggle: React.useCallback((() => {
|
|
23923
|
+
const newMode = toggleTheme({
|
|
23924
|
+
storageKey: storageKey,
|
|
23925
|
+
enableTransition: enableTransition,
|
|
23926
|
+
transitionDuration: transitionDuration
|
|
23927
|
+
});
|
|
23928
|
+
return setModeState(newMode), newMode;
|
|
23929
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23930
|
+
setMode: React.useCallback((newMode => {
|
|
23931
|
+
switchTheme(newMode, {
|
|
23932
|
+
storageKey: storageKey,
|
|
23933
|
+
enableTransition: enableTransition,
|
|
23934
|
+
transitionDuration: transitionDuration
|
|
23935
|
+
}), setModeState(newMode);
|
|
23936
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23937
|
+
resetToSystem: React.useCallback((() => {
|
|
23938
|
+
const systemMode = getSystemTheme();
|
|
23939
|
+
switchTheme(systemMode, {
|
|
23940
|
+
storageKey: storageKey,
|
|
23941
|
+
enableTransition: enableTransition,
|
|
23942
|
+
transitionDuration: transitionDuration
|
|
23943
|
+
}), setModeState(systemMode);
|
|
23944
|
+
}), [ storageKey, enableTransition, transitionDuration ]),
|
|
23945
|
+
clearPreference: React.useCallback((() => {
|
|
23946
|
+
"undefined" != typeof window && localStorage.removeItem(storageKey);
|
|
23947
|
+
}), [ storageKey ])
|
|
23948
|
+
};
|
|
23949
|
+
}
|
|
23950
|
+
|
|
23951
|
+
/**
|
|
23952
|
+
* ThemeToggle component with multiple variants
|
|
23953
|
+
*/ 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}) => {
|
|
23954
|
+
const {mode: mode, isDark: isDark, toggle: toggle} = useThemeSwitcher(hookOptions);
|
|
23955
|
+
// Custom render
|
|
23956
|
+
return render ? jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
23957
|
+
children: render({
|
|
23958
|
+
isDark: isDark,
|
|
23959
|
+
toggle: toggle,
|
|
23960
|
+
mode: mode
|
|
23961
|
+
})
|
|
23962
|
+
}) :
|
|
23963
|
+
// Icon-only variant (default)
|
|
23964
|
+
"icon" === variant ? jsxRuntime.jsx("button", {
|
|
23965
|
+
onClick: toggle,
|
|
23966
|
+
className: `theme-toggle theme-toggle-icon ${className}`,
|
|
23967
|
+
"aria-label": ariaLabel,
|
|
23968
|
+
title: isDark ? darkLabel : lightLabel,
|
|
23969
|
+
style: {
|
|
23970
|
+
background: "none",
|
|
23971
|
+
border: "none",
|
|
23972
|
+
cursor: "pointer",
|
|
23973
|
+
padding: "8px",
|
|
23974
|
+
borderRadius: "50%",
|
|
23975
|
+
display: "flex",
|
|
23976
|
+
alignItems: "center",
|
|
23977
|
+
justifyContent: "center",
|
|
23978
|
+
transition: "all 0.3s ease-in-out"
|
|
23979
|
+
},
|
|
23980
|
+
children: isDark ? jsxRuntime.jsxs("svg", {
|
|
23981
|
+
width: iconSize,
|
|
23982
|
+
height: iconSize,
|
|
23983
|
+
viewBox: "0 0 24 24",
|
|
23984
|
+
fill: "none",
|
|
23985
|
+
stroke: "currentColor",
|
|
23986
|
+
strokeWidth: "2",
|
|
23987
|
+
strokeLinecap: "round",
|
|
23988
|
+
strokeLinejoin: "round",
|
|
23989
|
+
children: [ jsxRuntime.jsx("circle", {
|
|
23990
|
+
cx: "12",
|
|
23991
|
+
cy: "12",
|
|
23992
|
+
r: "5"
|
|
23993
|
+
}), jsxRuntime.jsx("line", {
|
|
23994
|
+
x1: "12",
|
|
23995
|
+
y1: "1",
|
|
23996
|
+
x2: "12",
|
|
23997
|
+
y2: "3"
|
|
23998
|
+
}), jsxRuntime.jsx("line", {
|
|
23999
|
+
x1: "12",
|
|
24000
|
+
y1: "21",
|
|
24001
|
+
x2: "12",
|
|
24002
|
+
y2: "23"
|
|
24003
|
+
}), jsxRuntime.jsx("line", {
|
|
24004
|
+
x1: "4.22",
|
|
24005
|
+
y1: "4.22",
|
|
24006
|
+
x2: "5.64",
|
|
24007
|
+
y2: "5.64"
|
|
24008
|
+
}), jsxRuntime.jsx("line", {
|
|
24009
|
+
x1: "18.36",
|
|
24010
|
+
y1: "18.36",
|
|
24011
|
+
x2: "19.78",
|
|
24012
|
+
y2: "19.78"
|
|
24013
|
+
}), jsxRuntime.jsx("line", {
|
|
24014
|
+
x1: "1",
|
|
24015
|
+
y1: "12",
|
|
24016
|
+
x2: "3",
|
|
24017
|
+
y2: "12"
|
|
24018
|
+
}), jsxRuntime.jsx("line", {
|
|
24019
|
+
x1: "21",
|
|
24020
|
+
y1: "12",
|
|
24021
|
+
x2: "23",
|
|
24022
|
+
y2: "12"
|
|
24023
|
+
}), jsxRuntime.jsx("line", {
|
|
24024
|
+
x1: "4.22",
|
|
24025
|
+
y1: "19.78",
|
|
24026
|
+
x2: "5.64",
|
|
24027
|
+
y2: "18.36"
|
|
24028
|
+
}), jsxRuntime.jsx("line", {
|
|
24029
|
+
x1: "18.36",
|
|
24030
|
+
y1: "5.64",
|
|
24031
|
+
x2: "19.78",
|
|
24032
|
+
y2: "4.22"
|
|
24033
|
+
}) ]
|
|
24034
|
+
}) : jsxRuntime.jsx("svg", {
|
|
24035
|
+
width: iconSize,
|
|
24036
|
+
height: iconSize,
|
|
24037
|
+
viewBox: "0 0 24 24",
|
|
24038
|
+
fill: "none",
|
|
24039
|
+
stroke: "currentColor",
|
|
24040
|
+
strokeWidth: "2",
|
|
24041
|
+
strokeLinecap: "round",
|
|
24042
|
+
strokeLinejoin: "round",
|
|
24043
|
+
children: jsxRuntime.jsx("path", {
|
|
24044
|
+
d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
|
|
24045
|
+
})
|
|
24046
|
+
})
|
|
24047
|
+
}) :
|
|
24048
|
+
// Button variant with text
|
|
24049
|
+
"button" === variant ? jsxRuntime.jsxs("button", {
|
|
24050
|
+
onClick: toggle,
|
|
24051
|
+
className: `theme-toggle theme-toggle-button ${className}`,
|
|
24052
|
+
"aria-label": ariaLabel,
|
|
24053
|
+
style: {
|
|
24054
|
+
display: "flex",
|
|
24055
|
+
alignItems: "center",
|
|
24056
|
+
gap: "8px",
|
|
24057
|
+
padding: "8px 16px",
|
|
24058
|
+
borderRadius: "8px",
|
|
24059
|
+
border: "1px solid currentColor",
|
|
24060
|
+
background: "transparent",
|
|
24061
|
+
color: "inherit",
|
|
24062
|
+
cursor: "pointer",
|
|
24063
|
+
fontSize: "14px",
|
|
24064
|
+
fontWeight: "500",
|
|
24065
|
+
transition: "all 0.3s ease-in-out"
|
|
24066
|
+
},
|
|
24067
|
+
children: [ isDark ? jsxRuntime.jsxs("svg", {
|
|
24068
|
+
width: iconSize,
|
|
24069
|
+
height: iconSize,
|
|
24070
|
+
viewBox: "0 0 24 24",
|
|
24071
|
+
fill: "none",
|
|
24072
|
+
stroke: "currentColor",
|
|
24073
|
+
strokeWidth: "2",
|
|
24074
|
+
strokeLinecap: "round",
|
|
24075
|
+
strokeLinejoin: "round",
|
|
24076
|
+
children: [ jsxRuntime.jsx("circle", {
|
|
24077
|
+
cx: "12",
|
|
24078
|
+
cy: "12",
|
|
24079
|
+
r: "5"
|
|
24080
|
+
}), jsxRuntime.jsx("line", {
|
|
24081
|
+
x1: "12",
|
|
24082
|
+
y1: "1",
|
|
24083
|
+
x2: "12",
|
|
24084
|
+
y2: "3"
|
|
24085
|
+
}), jsxRuntime.jsx("line", {
|
|
24086
|
+
x1: "12",
|
|
24087
|
+
y1: "21",
|
|
24088
|
+
x2: "12",
|
|
24089
|
+
y2: "23"
|
|
24090
|
+
}), jsxRuntime.jsx("line", {
|
|
24091
|
+
x1: "4.22",
|
|
24092
|
+
y1: "4.22",
|
|
24093
|
+
x2: "5.64",
|
|
24094
|
+
y2: "5.64"
|
|
24095
|
+
}), jsxRuntime.jsx("line", {
|
|
24096
|
+
x1: "18.36",
|
|
24097
|
+
y1: "18.36",
|
|
24098
|
+
x2: "19.78",
|
|
24099
|
+
y2: "19.78"
|
|
24100
|
+
}), jsxRuntime.jsx("line", {
|
|
24101
|
+
x1: "1",
|
|
24102
|
+
y1: "12",
|
|
24103
|
+
x2: "3",
|
|
24104
|
+
y2: "12"
|
|
24105
|
+
}), jsxRuntime.jsx("line", {
|
|
24106
|
+
x1: "21",
|
|
24107
|
+
y1: "12",
|
|
24108
|
+
x2: "23",
|
|
24109
|
+
y2: "12"
|
|
24110
|
+
}), jsxRuntime.jsx("line", {
|
|
24111
|
+
x1: "4.22",
|
|
24112
|
+
y1: "19.78",
|
|
24113
|
+
x2: "5.64",
|
|
24114
|
+
y2: "18.36"
|
|
24115
|
+
}), jsxRuntime.jsx("line", {
|
|
24116
|
+
x1: "18.36",
|
|
24117
|
+
y1: "5.64",
|
|
24118
|
+
x2: "19.78",
|
|
24119
|
+
y2: "4.22"
|
|
24120
|
+
}) ]
|
|
24121
|
+
}) : jsxRuntime.jsx("svg", {
|
|
24122
|
+
width: iconSize,
|
|
24123
|
+
height: iconSize,
|
|
24124
|
+
viewBox: "0 0 24 24",
|
|
24125
|
+
fill: "none",
|
|
24126
|
+
stroke: "currentColor",
|
|
24127
|
+
strokeWidth: "2",
|
|
24128
|
+
strokeLinecap: "round",
|
|
24129
|
+
strokeLinejoin: "round",
|
|
24130
|
+
children: jsxRuntime.jsx("path", {
|
|
24131
|
+
d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
|
|
24132
|
+
})
|
|
24133
|
+
}), showLabel && jsxRuntime.jsx("span", {
|
|
24134
|
+
children: isDark ? darkLabel : lightLabel
|
|
24135
|
+
}) ]
|
|
24136
|
+
}) :
|
|
24137
|
+
// Switch/toggle variant
|
|
24138
|
+
"switch" === variant ? jsxRuntime.jsx("div", {
|
|
24139
|
+
className: `theme-toggle theme-toggle-switch ${className}`,
|
|
24140
|
+
role: "button",
|
|
24141
|
+
tabIndex: 0,
|
|
24142
|
+
onClick: toggle,
|
|
24143
|
+
onKeyDown: e => "Enter" === e.key && toggle(),
|
|
24144
|
+
"aria-label": ariaLabel,
|
|
24145
|
+
style: {
|
|
24146
|
+
position: "relative",
|
|
24147
|
+
width: "56px",
|
|
24148
|
+
height: "28px",
|
|
24149
|
+
borderRadius: "14px",
|
|
24150
|
+
background: isDark ? "#4b5563" : "#d1d5db",
|
|
24151
|
+
cursor: "pointer",
|
|
24152
|
+
transition: "background 0.3s ease-in-out",
|
|
24153
|
+
display: "flex",
|
|
24154
|
+
alignItems: "center",
|
|
24155
|
+
padding: "2px"
|
|
24156
|
+
},
|
|
24157
|
+
children: jsxRuntime.jsx("div", {
|
|
24158
|
+
style: {
|
|
24159
|
+
position: "absolute",
|
|
24160
|
+
left: isDark ? "auto" : "2px",
|
|
24161
|
+
right: isDark ? "2px" : "auto",
|
|
24162
|
+
width: "24px",
|
|
24163
|
+
height: "24px",
|
|
24164
|
+
borderRadius: "50%",
|
|
24165
|
+
background: "white",
|
|
24166
|
+
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
|
|
24167
|
+
transition: "all 0.3s ease-in-out",
|
|
24168
|
+
display: "flex",
|
|
24169
|
+
alignItems: "center",
|
|
24170
|
+
justifyContent: "center"
|
|
24171
|
+
},
|
|
24172
|
+
children: isDark ? jsxRuntime.jsx("svg", {
|
|
24173
|
+
width: "14",
|
|
24174
|
+
height: "14",
|
|
24175
|
+
viewBox: "0 0 24 24",
|
|
24176
|
+
fill: "none",
|
|
24177
|
+
stroke: "#4b5563",
|
|
24178
|
+
strokeWidth: "2",
|
|
24179
|
+
strokeLinecap: "round",
|
|
24180
|
+
strokeLinejoin: "round",
|
|
24181
|
+
children: jsxRuntime.jsx("path", {
|
|
24182
|
+
d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
|
|
24183
|
+
})
|
|
24184
|
+
}) : jsxRuntime.jsxs("svg", {
|
|
24185
|
+
width: "14",
|
|
24186
|
+
height: "14",
|
|
24187
|
+
viewBox: "0 0 24 24",
|
|
24188
|
+
fill: "none",
|
|
24189
|
+
stroke: "#f59e0b",
|
|
24190
|
+
strokeWidth: "2",
|
|
24191
|
+
strokeLinecap: "round",
|
|
24192
|
+
strokeLinejoin: "round",
|
|
24193
|
+
children: [ jsxRuntime.jsx("circle", {
|
|
24194
|
+
cx: "12",
|
|
24195
|
+
cy: "12",
|
|
24196
|
+
r: "5"
|
|
24197
|
+
}), jsxRuntime.jsx("line", {
|
|
24198
|
+
x1: "12",
|
|
24199
|
+
y1: "1",
|
|
24200
|
+
x2: "12",
|
|
24201
|
+
y2: "3"
|
|
24202
|
+
}), jsxRuntime.jsx("line", {
|
|
24203
|
+
x1: "12",
|
|
24204
|
+
y1: "21",
|
|
24205
|
+
x2: "12",
|
|
24206
|
+
y2: "23"
|
|
24207
|
+
}), jsxRuntime.jsx("line", {
|
|
24208
|
+
x1: "4.22",
|
|
24209
|
+
y1: "4.22",
|
|
24210
|
+
x2: "5.64",
|
|
24211
|
+
y2: "5.64"
|
|
24212
|
+
}), jsxRuntime.jsx("line", {
|
|
24213
|
+
x1: "18.36",
|
|
24214
|
+
y1: "18.36",
|
|
24215
|
+
x2: "19.78",
|
|
24216
|
+
y2: "19.78"
|
|
24217
|
+
}), jsxRuntime.jsx("line", {
|
|
24218
|
+
x1: "1",
|
|
24219
|
+
y1: "12",
|
|
24220
|
+
x2: "3",
|
|
24221
|
+
y2: "12"
|
|
24222
|
+
}), jsxRuntime.jsx("line", {
|
|
24223
|
+
x1: "21",
|
|
24224
|
+
y1: "12",
|
|
24225
|
+
x2: "23",
|
|
24226
|
+
y2: "12"
|
|
24227
|
+
}), jsxRuntime.jsx("line", {
|
|
24228
|
+
x1: "4.22",
|
|
24229
|
+
y1: "19.78",
|
|
24230
|
+
x2: "5.64",
|
|
24231
|
+
y2: "18.36"
|
|
24232
|
+
}), jsxRuntime.jsx("line", {
|
|
24233
|
+
x1: "18.36",
|
|
24234
|
+
y1: "5.64",
|
|
24235
|
+
x2: "19.78",
|
|
24236
|
+
y2: "4.22"
|
|
24237
|
+
}) ]
|
|
24238
|
+
})
|
|
24239
|
+
})
|
|
24240
|
+
}) : null;
|
|
24241
|
+
};
|
|
24242
|
+
|
|
24243
|
+
ThemeToggle.displayName = "ThemeToggle";
|
|
24244
|
+
|
|
22905
24245
|
/**
|
|
22906
24246
|
* Theme Applicator
|
|
22907
24247
|
*
|
|
@@ -22914,7 +24254,8 @@ function useThemeTokens() {
|
|
|
22914
24254
|
* Theme applicator class for runtime theme application
|
|
22915
24255
|
*
|
|
22916
24256
|
* Uses the unified theme system for efficient CSS variable generation and injection.
|
|
22917
|
-
*/
|
|
24257
|
+
*/
|
|
24258
|
+
class ThemeApplicator {
|
|
22918
24259
|
constructor(root = document.documentElement) {
|
|
22919
24260
|
this.styleId = "atomix-theme-applicator", this.root = root;
|
|
22920
24261
|
}
|
|
@@ -23740,7 +25081,7 @@ class ThemeValidator {
|
|
|
23740
25081
|
*
|
|
23741
25082
|
* Provides detailed inspection and debugging information for themes
|
|
23742
25083
|
*/ const ThemeInspector = ({theme: theme, showValidation: showValidation = !0, showCSSVariables: showCSSVariables = !0, showStructure: showStructure = !0, className: className, style: style}) => {
|
|
23743
|
-
const [activeTab, setActiveTab] = React.useState("overview"), [expandedSections, setExpandedSections] = React.useState(new Set([ "palette" ])), [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [copiedPath, setCopiedPath] = React.useState(null), searchTimeoutRef = React.useRef();
|
|
25084
|
+
const [activeTab, setActiveTab] = React.useState("overview"), [expandedSections, setExpandedSections] = React.useState(new Set([ "palette" ])), [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [copiedPath, setCopiedPath] = React.useState(null), searchTimeoutRef = React.useRef(void 0);
|
|
23744
25085
|
// Debounce search query
|
|
23745
25086
|
React.useEffect((() => (searchTimeoutRef.current && clearTimeout(searchTimeoutRef.current),
|
|
23746
25087
|
searchTimeoutRef.current = setTimeout((() => {
|
|
@@ -24146,7 +25487,7 @@ class ThemeValidator {
|
|
|
24146
25487
|
}) ]
|
|
24147
25488
|
});
|
|
24148
25489
|
}, ThemeComparator = ({themeA: themeA, themeB: themeB, showOnlyDifferences: showOnlyDifferences = !1, className: className, style: style}) => {
|
|
24149
|
-
const [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [filterType, setFilterType] = React.useState("all"), [filterCategory, setFilterCategory] = React.useState("all"), searchTimeoutRef = React.useRef();
|
|
25490
|
+
const [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [filterType, setFilterType] = React.useState("all"), [filterCategory, setFilterCategory] = React.useState("all"), searchTimeoutRef = React.useRef(void 0);
|
|
24150
25491
|
// Debounce search query
|
|
24151
25492
|
React.useEffect((() => (searchTimeoutRef.current && clearTimeout(searchTimeoutRef.current),
|
|
24152
25493
|
searchTimeoutRef.current = setTimeout((() => {
|
|
@@ -24653,13 +25994,13 @@ class ThemeValidator {
|
|
|
24653
25994
|
function createPaletteColor(color) {
|
|
24654
25995
|
return "string" == typeof color ? {
|
|
24655
25996
|
main: color,
|
|
24656
|
-
light: lighten(color),
|
|
24657
|
-
dark: darken(color),
|
|
25997
|
+
light: lighten(color, .15),
|
|
25998
|
+
dark: darken(color, .15),
|
|
24658
25999
|
contrastText: getContrastText(color)
|
|
24659
26000
|
} : {
|
|
24660
26001
|
main: color.main || "#000000",
|
|
24661
|
-
light: color.light || lighten(color.main || "#000000"),
|
|
24662
|
-
dark: color.dark || darken(color.main || "#000000"),
|
|
26002
|
+
light: color.light || lighten(color.main || "#000000", .15),
|
|
26003
|
+
dark: color.dark || darken(color.main || "#000000", .15),
|
|
24663
26004
|
contrastText: color.contrastText || getContrastText(color.main || "#000000")
|
|
24664
26005
|
};
|
|
24665
26006
|
}
|
|
@@ -24694,23 +26035,19 @@ function createThemeObject(...options) {
|
|
|
24694
26035
|
},
|
|
24695
26036
|
background: {
|
|
24696
26037
|
default: mergedOptions.palette?.background?.default || DEFAULT_PALETTE.background.default,
|
|
26038
|
+
paper: mergedOptions.palette?.background?.paper || DEFAULT_PALETTE.background.paper,
|
|
24697
26039
|
subtle: mergedOptions.palette?.background?.subtle || DEFAULT_PALETTE.background.subtle
|
|
24698
26040
|
},
|
|
24699
26041
|
text: {
|
|
24700
26042
|
primary: mergedOptions.palette?.text?.primary || DEFAULT_PALETTE.text.primary,
|
|
24701
26043
|
secondary: mergedOptions.palette?.text?.secondary || DEFAULT_PALETTE.text.secondary,
|
|
24702
26044
|
disabled: mergedOptions.palette?.text?.disabled || DEFAULT_PALETTE.text.disabled
|
|
24703
|
-
}
|
|
26045
|
+
},
|
|
26046
|
+
// Spread other palette properties
|
|
26047
|
+
...mergedOptions.palette
|
|
24704
26048
|
}, typography = deepMerge({
|
|
24705
26049
|
...DEFAULT_TYPOGRAPHY
|
|
24706
|
-
}, mergedOptions.typography || {}), spacing =
|
|
24707
|
-
// If it's already a function, return it
|
|
24708
|
-
return "function" == typeof spacingInput ? spacingInput :
|
|
24709
|
-
// If it's a number, create a function that multiplies by that number
|
|
24710
|
-
"number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
|
|
24711
|
-
// If it's an array, use it as a scale
|
|
24712
|
-
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(" ");
|
|
24713
|
-
}(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
|
|
26050
|
+
}, mergedOptions.typography || {}), spacing = createSpacing(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
|
|
24714
26051
|
const values = {
|
|
24715
26052
|
xs: 0,
|
|
24716
26053
|
sm: 576,
|
|
@@ -24942,7 +26279,7 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
|
|
|
24942
26279
|
} catch (err) {
|
|
24943
26280
|
setError(err instanceof Error ? err.message : "Invalid JSON");
|
|
24944
26281
|
}
|
|
24945
|
-
}), [ updateTheme ]), jsonUpdateTimeoutRef = React.useRef();
|
|
26282
|
+
}), [ updateTheme ]), jsonUpdateTimeoutRef = React.useRef(void 0);
|
|
24946
26283
|
// Debounced JSON update to history
|
|
24947
26284
|
React.useEffect((() => {
|
|
24948
26285
|
if (!error) {
|
|
@@ -25534,45 +26871,357 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
|
|
|
25534
26871
|
* Design Tokens Customizer Component
|
|
25535
26872
|
*/
|
|
25536
26873
|
/**
|
|
25537
|
-
* Theme
|
|
26874
|
+
* Theme Helper Functions
|
|
25538
26875
|
*
|
|
25539
|
-
*
|
|
26876
|
+
* Utility functions for working with DesignTokens
|
|
25540
26877
|
*/
|
|
25541
26878
|
/**
|
|
25542
|
-
*
|
|
26879
|
+
* Check if a value is DesignTokens
|
|
26880
|
+
*
|
|
26881
|
+
* Type guard to check if an object is DesignTokens format.
|
|
25543
26882
|
*
|
|
25544
|
-
* @param
|
|
25545
|
-
* @returns
|
|
26883
|
+
* @param value - Value to check
|
|
26884
|
+
* @returns True if value is DesignTokens
|
|
25546
26885
|
*/
|
|
25547
|
-
function
|
|
25548
|
-
|
|
25549
|
-
|
|
25550
|
-
|
|
25551
|
-
|
|
26886
|
+
function isDesignTokens(value) {
|
|
26887
|
+
if (!value || "object" != typeof value) return !1;
|
|
26888
|
+
// DesignTokens is a flat object with string keys, no nested structures
|
|
26889
|
+
const obj = value;
|
|
26890
|
+
// Check for absence of Theme-specific properties
|
|
26891
|
+
if ("palette" in obj || "typography" in obj || "__isJSTheme" in obj) return !1;
|
|
26892
|
+
// Check if it has DesignTokens-like structure (flat string keys)
|
|
26893
|
+
const keys = Object.keys(obj);
|
|
26894
|
+
return 0 !== keys.length && keys.some((key => /^[a-z]+(-[a-z0-9]+)*$/.test(key) && "string" == typeof obj[key]));
|
|
26895
|
+
// Check if keys look like DesignTokens (kebab-case, no nesting)
|
|
26896
|
+
}
|
|
26897
|
+
|
|
26898
|
+
/**
|
|
26899
|
+
* Performance monitor class
|
|
26900
|
+
*/ class PerformanceMonitor {
|
|
26901
|
+
/**
|
|
26902
|
+
* Create a new performance monitor
|
|
26903
|
+
*
|
|
26904
|
+
* @param config Configuration options
|
|
26905
|
+
*/
|
|
26906
|
+
constructor(config) {
|
|
26907
|
+
this.frameCount = 0, this.lastSampleTime = 0, this.lastFpsUpdate = 0, this.frameTimes = [],
|
|
26908
|
+
this.animationFrameId = null, this.isActive = !1, this.startTime = 0, this.config = {
|
|
26909
|
+
fpsTarget: config?.fpsTarget ?? 60,
|
|
26910
|
+
sampleInterval: config?.sampleInterval ?? 500,
|
|
26911
|
+
onUpdate: config?.onUpdate ?? (() => {}),
|
|
26912
|
+
onDegraded: config?.onDegraded ?? (() => {}),
|
|
26913
|
+
enableMemoryMonitoring: config?.enableMemoryMonitoring ?? ("undefined" != typeof window && window.performance && window.performance.memory)
|
|
26914
|
+
};
|
|
26915
|
+
}
|
|
26916
|
+
/**
|
|
26917
|
+
* Start monitoring performance
|
|
26918
|
+
*/ start() {
|
|
26919
|
+
this.isActive || (this.isActive = !0, this.frameCount = 0, this.lastSampleTime = performance.now(),
|
|
26920
|
+
this.lastFpsUpdate = this.lastSampleTime, this.frameTimes = [], this.startTime = this.lastSampleTime,
|
|
26921
|
+
this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this)));
|
|
26922
|
+
}
|
|
26923
|
+
/**
|
|
26924
|
+
* Stop monitoring performance
|
|
26925
|
+
*/ stop() {
|
|
26926
|
+
this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null),
|
|
26927
|
+
this.isActive = !1;
|
|
26928
|
+
}
|
|
26929
|
+
/**
|
|
26930
|
+
* Get current performance metrics
|
|
26931
|
+
*/ getMetrics() {
|
|
26932
|
+
var _context;
|
|
26933
|
+
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;
|
|
26934
|
+
// Get memory stats if available
|
|
26935
|
+
let memory;
|
|
26936
|
+
if (this.config.enableMemoryMonitoring) {
|
|
26937
|
+
const perf = window.performance;
|
|
26938
|
+
perf && perf.memory && (memory = {
|
|
26939
|
+
usedJSHeapSize: perf.memory.usedJSHeapSize,
|
|
26940
|
+
totalJSHeapSize: perf.memory.totalJSHeapSize,
|
|
26941
|
+
jsHeapSizeLimit: perf.memory.jsHeapSizeLimit
|
|
26942
|
+
});
|
|
26943
|
+
}
|
|
26944
|
+
return {
|
|
26945
|
+
fps: fps,
|
|
26946
|
+
frameTime: avgFrameTime,
|
|
26947
|
+
peakFrameTime: peakFrameTime,
|
|
26948
|
+
memory: memory,
|
|
26949
|
+
timestamp: now,
|
|
26950
|
+
isDegraded: fps < .7 * this.config.fpsTarget
|
|
26951
|
+
};
|
|
26952
|
+
}
|
|
26953
|
+
/**
|
|
26954
|
+
* Get the current FPS
|
|
26955
|
+
*/ getFps() {
|
|
26956
|
+
return this.getMetrics().fps;
|
|
26957
|
+
}
|
|
26958
|
+
/**
|
|
26959
|
+
* Check if performance is degraded
|
|
26960
|
+
*/ isPerformanceDegraded() {
|
|
26961
|
+
return this.getMetrics().isDegraded;
|
|
26962
|
+
}
|
|
26963
|
+
/**
|
|
26964
|
+
* Private method called on each animation frame
|
|
26965
|
+
*/ onFrame(timestamp) {
|
|
26966
|
+
if (!this.isActive) return;
|
|
26967
|
+
// Calculate frame time
|
|
26968
|
+
const frameTime = timestamp - this.lastSampleTime;
|
|
26969
|
+
// Check if we need to update metrics
|
|
26970
|
+
if (this.frameTimes.push(frameTime),
|
|
26971
|
+
// Keep only the last 60 frame times for averaging
|
|
26972
|
+
this.frameTimes.length > 60 && this.frameTimes.shift(), this.frameCount++, this.lastSampleTime = timestamp,
|
|
26973
|
+
timestamp - this.lastFpsUpdate >= this.config.sampleInterval) {
|
|
26974
|
+
const metrics = this.getMetrics();
|
|
26975
|
+
// Call update callback
|
|
26976
|
+
this.config.onUpdate(metrics),
|
|
26977
|
+
// Check for degradation
|
|
26978
|
+
metrics.isDegraded && this.config.onDegraded(metrics),
|
|
26979
|
+
// Reset counters
|
|
26980
|
+
this.frameCount = 0, this.lastFpsUpdate = timestamp;
|
|
26981
|
+
}
|
|
26982
|
+
this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this));
|
|
26983
|
+
}
|
|
26984
|
+
/**
|
|
26985
|
+
* Run a performance test for a specific function
|
|
26986
|
+
*
|
|
26987
|
+
* @param fn Function to test
|
|
26988
|
+
* @param iterations Number of iterations (default: 100)
|
|
26989
|
+
* @returns Average execution time in ms
|
|
26990
|
+
*/ async testFunctionPerformance(fn, iterations = 100) {
|
|
26991
|
+
const times = [];
|
|
26992
|
+
for (let i = 0; i < iterations; i++) {
|
|
26993
|
+
const start = performance.now();
|
|
26994
|
+
fn();
|
|
26995
|
+
const end = performance.now();
|
|
26996
|
+
times.push(end - start);
|
|
26997
|
+
}
|
|
26998
|
+
return _reduceInstanceProperty(times).call(times, ((a, b) => a + b), 0) / times.length;
|
|
26999
|
+
}
|
|
27000
|
+
}
|
|
27001
|
+
|
|
27002
|
+
/**
|
|
27003
|
+
* Create a performance monitor instance
|
|
27004
|
+
*
|
|
27005
|
+
* @param config Configuration options
|
|
27006
|
+
* @returns PerformanceMonitor instance
|
|
27007
|
+
*
|
|
27008
|
+
* @example
|
|
27009
|
+
* ```typescript
|
|
27010
|
+
* import { createPerformanceMonitor } from '@shohojdhara/atomix/theme';
|
|
27011
|
+
*
|
|
27012
|
+
* const monitor = createPerformanceMonitor({
|
|
27013
|
+
* fpsTarget: 60,
|
|
27014
|
+
* onUpdate: (metrics) => console.log('FPS:', metrics.fps),
|
|
27015
|
+
* onDegraded: (metrics) => console.warn('Performance degraded!', metrics),
|
|
27016
|
+
* });
|
|
27017
|
+
*
|
|
27018
|
+
* monitor.start();
|
|
27019
|
+
*
|
|
27020
|
+
* // Later...
|
|
27021
|
+
* monitor.stop();
|
|
27022
|
+
* ```
|
|
27023
|
+
*/ function createPerformanceMonitor(config) {
|
|
27024
|
+
return new PerformanceMonitor(config);
|
|
27025
|
+
}
|
|
27026
|
+
|
|
27027
|
+
/**
|
|
27028
|
+
* Hook for React components to monitor performance
|
|
27029
|
+
*
|
|
27030
|
+
* @param config Configuration options
|
|
27031
|
+
* @returns Performance metrics and monitor controls
|
|
27032
|
+
*
|
|
27033
|
+
* @example
|
|
27034
|
+
* ```typescript
|
|
27035
|
+
* import { usePerformanceMonitor } from '@shohojdhara/atomix/theme';
|
|
27036
|
+
*
|
|
27037
|
+
* function MyComponent() {
|
|
27038
|
+
* const { metrics, start, stop } = usePerformanceMonitor({ fpsTarget: 60 });
|
|
27039
|
+
*
|
|
27040
|
+
* useEffect(() => {
|
|
27041
|
+
* start();
|
|
27042
|
+
* return () => stop();
|
|
27043
|
+
* }, []);
|
|
27044
|
+
*
|
|
27045
|
+
* return <div>FPS: {metrics.fps}</div>;
|
|
27046
|
+
* }
|
|
27047
|
+
* ```
|
|
27048
|
+
*/ function usePerformanceMonitor(config) {
|
|
27049
|
+
const [monitor] = React__default.default.useState((() => createPerformanceMonitor(config))), [metrics, setMetrics] = React__default.default.useState((() => "undefined" != typeof window ? monitor.getMetrics() : {
|
|
27050
|
+
fps: 0,
|
|
27051
|
+
frameTime: 0,
|
|
27052
|
+
peakFrameTime: 0,
|
|
27053
|
+
timestamp: 0,
|
|
27054
|
+
isDegraded: !1
|
|
27055
|
+
})), start = React__default.default.useCallback((() => {
|
|
27056
|
+
"undefined" != typeof window && monitor.start();
|
|
27057
|
+
}), [ monitor ]), stop = React__default.default.useCallback((() => {
|
|
27058
|
+
"undefined" != typeof window && monitor.stop();
|
|
27059
|
+
}), [ monitor ]);
|
|
27060
|
+
return React__default.default.useEffect((() => {
|
|
27061
|
+
if ("undefined" == typeof window) return;
|
|
27062
|
+
// Update metrics when monitor callbacks fire
|
|
27063
|
+
const originalOnUpdate = config?.onUpdate;
|
|
27064
|
+
return monitor.config.onUpdate = newMetrics => {
|
|
27065
|
+
setMetrics(newMetrics), originalOnUpdate?.(newMetrics);
|
|
27066
|
+
}, () => {
|
|
27067
|
+
monitor.stop();
|
|
27068
|
+
};
|
|
27069
|
+
}), [ monitor, config?.onUpdate ]), {
|
|
27070
|
+
metrics: metrics,
|
|
27071
|
+
start: start,
|
|
27072
|
+
stop: stop
|
|
27073
|
+
};
|
|
25552
27074
|
}
|
|
25553
27075
|
|
|
25554
27076
|
/**
|
|
25555
|
-
* Theme
|
|
27077
|
+
* Responsive Utility for Atomix Theme System
|
|
25556
27078
|
*
|
|
25557
|
-
*
|
|
27079
|
+
* Provides responsive breakpoint detection and device-aware parameter scaling
|
|
27080
|
+
* based on configuration from the advanced optimization features.
|
|
25558
27081
|
*/
|
|
25559
27082
|
/**
|
|
25560
|
-
*
|
|
27083
|
+
* Responsive utility class
|
|
27084
|
+
*/ class ResponsiveUtil {
|
|
27085
|
+
constructor(config) {
|
|
27086
|
+
this.currentDevice = "desktop", // Default
|
|
27087
|
+
this.resizeHandler = null, this.observer = null, this.config = config, this.currentDevice = this.getCurrentDeviceType(),
|
|
27088
|
+
// Set up resize listener
|
|
27089
|
+
this.setupResizeListener();
|
|
27090
|
+
}
|
|
27091
|
+
/**
|
|
27092
|
+
* Get the current device type based on viewport width
|
|
27093
|
+
*/ getCurrentDeviceType() {
|
|
27094
|
+
if ("undefined" == typeof window) return "desktop";
|
|
27095
|
+
// SSR fallback
|
|
27096
|
+
const width = window.innerWidth;
|
|
27097
|
+
// Parse breakpoint values to numbers
|
|
27098
|
+
this.parsePxValue(this.config.breakpoints.mobile);
|
|
27099
|
+
const tabletWidth = this.parsePxValue(this.config.breakpoints.tablet), desktopWidth = this.parsePxValue(this.config.breakpoints.desktop), wideWidth = this.parsePxValue(this.config.breakpoints.wide);
|
|
27100
|
+
return width < tabletWidth ? "mobile" : width < desktopWidth ? "tablet" : width < wideWidth ? "desktop" : "wide";
|
|
27101
|
+
}
|
|
27102
|
+
/**
|
|
27103
|
+
* Get the scaling factor for the current device
|
|
27104
|
+
*/ getCurrentScalingFactor() {
|
|
27105
|
+
// 'wide' devices use the same scaling as 'desktop'
|
|
27106
|
+
const scalingKey = "wide" === this.currentDevice ? "desktop" : this.currentDevice;
|
|
27107
|
+
return this.config.deviceScaling[scalingKey] || 1;
|
|
27108
|
+
}
|
|
27109
|
+
/**
|
|
27110
|
+
* Scale a value based on the current device's scaling factor
|
|
27111
|
+
*/ scaleValue(value) {
|
|
27112
|
+
return value * this.getCurrentScalingFactor();
|
|
27113
|
+
}
|
|
27114
|
+
/**
|
|
27115
|
+
* Check if the current device matches a specific type
|
|
27116
|
+
*/ isDevice(device) {
|
|
27117
|
+
return this.currentDevice === device;
|
|
27118
|
+
}
|
|
27119
|
+
/**
|
|
27120
|
+
* Check if the current device is mobile or smaller
|
|
27121
|
+
*/ isMobileOrSmaller() {
|
|
27122
|
+
return "mobile" === this.currentDevice;
|
|
27123
|
+
}
|
|
27124
|
+
/**
|
|
27125
|
+
* Check if the current device is tablet or smaller
|
|
27126
|
+
*/ isTabletOrSmaller() {
|
|
27127
|
+
return "mobile" === this.currentDevice || "tablet" === this.currentDevice;
|
|
27128
|
+
}
|
|
27129
|
+
/**
|
|
27130
|
+
* Check if the current device is desktop or larger
|
|
27131
|
+
*/ isDesktopOrLarger() {
|
|
27132
|
+
return "desktop" === this.currentDevice || "wide" === this.currentDevice;
|
|
27133
|
+
}
|
|
27134
|
+
/**
|
|
27135
|
+
* Update the responsive configuration
|
|
27136
|
+
*/ updateConfig(config) {
|
|
27137
|
+
this.config = config, this.currentDevice = this.getCurrentDeviceType();
|
|
27138
|
+
}
|
|
27139
|
+
/**
|
|
27140
|
+
* Destroy the responsive utility and clean up listeners
|
|
27141
|
+
*/ destroy() {
|
|
27142
|
+
this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler),
|
|
27143
|
+
this.resizeHandler = null), this.observer && (this.observer.disconnect(), this.observer = null);
|
|
27144
|
+
}
|
|
27145
|
+
/**
|
|
27146
|
+
* Parse a CSS value to pixels
|
|
27147
|
+
*/ parsePxValue(value) {
|
|
27148
|
+
return value.endsWith("px") ? parseFloat(value.slice(0, -2)) :
|
|
27149
|
+
// For other units, we'll use a rough conversion assuming 16px base
|
|
27150
|
+
value.endsWith("rem") ? 16 * parseFloat(value.slice(0, -3)) : value.endsWith("em") ? 16 * parseFloat(value.slice(0, -2)) : parseFloat(value) || 0;
|
|
27151
|
+
}
|
|
27152
|
+
/**
|
|
27153
|
+
* Set up the resize listener
|
|
27154
|
+
*/ setupResizeListener() {
|
|
27155
|
+
if ("undefined" == typeof window) return;
|
|
27156
|
+
// Throttled resize handler
|
|
27157
|
+
let resizeTimeout = null;
|
|
27158
|
+
const handleResize = () => {
|
|
27159
|
+
resizeTimeout && window.clearTimeout(resizeTimeout), resizeTimeout = window.setTimeout((() => {
|
|
27160
|
+
const newDeviceType = this.getCurrentDeviceType();
|
|
27161
|
+
newDeviceType !== this.currentDevice && (this.currentDevice = newDeviceType);
|
|
27162
|
+
}), 150);
|
|
27163
|
+
} // Throttle to 150ms
|
|
27164
|
+
;
|
|
27165
|
+
this.resizeHandler = handleResize, window.addEventListener("resize", handleResize),
|
|
27166
|
+
// Also observe the document body for size changes
|
|
27167
|
+
"undefined" != typeof ResizeObserver && (this.observer = new ResizeObserver(handleResize),
|
|
27168
|
+
this.observer.observe(document.body));
|
|
27169
|
+
}
|
|
27170
|
+
}
|
|
27171
|
+
|
|
27172
|
+
/**
|
|
27173
|
+
* Create a responsive utility instance
|
|
25561
27174
|
*
|
|
25562
|
-
*
|
|
27175
|
+
* @param config Responsive configuration
|
|
27176
|
+
* @returns ResponsiveUtil instance
|
|
27177
|
+
*/ function createResponsiveUtil(config) {
|
|
27178
|
+
return new ResponsiveUtil(config);
|
|
27179
|
+
}
|
|
27180
|
+
|
|
27181
|
+
/**
|
|
27182
|
+
* Hook for React components to use responsive features
|
|
25563
27183
|
*
|
|
25564
|
-
* @param
|
|
25565
|
-
* @returns
|
|
25566
|
-
*/ function
|
|
25567
|
-
|
|
25568
|
-
|
|
25569
|
-
|
|
25570
|
-
|
|
25571
|
-
|
|
25572
|
-
|
|
25573
|
-
|
|
25574
|
-
|
|
25575
|
-
|
|
27184
|
+
* @param config Responsive configuration
|
|
27185
|
+
* @returns Current device type and utility functions
|
|
27186
|
+
*/ function useResponsive(config) {
|
|
27187
|
+
const [util] = React__default.default.useState((() => createResponsiveUtil(config))), [deviceType, setDeviceType] = React__default.default.useState((() => "undefined" != typeof window ? util.getCurrentDeviceType() : "desktop"));
|
|
27188
|
+
return React__default.default.useEffect((() => {
|
|
27189
|
+
if ("undefined" == typeof window) return;
|
|
27190
|
+
const handleResize = () => {
|
|
27191
|
+
const newDeviceType = util.getCurrentDeviceType();
|
|
27192
|
+
newDeviceType !== deviceType && setDeviceType(newDeviceType);
|
|
27193
|
+
};
|
|
27194
|
+
// Update device type on mount
|
|
27195
|
+
return setDeviceType(util.getCurrentDeviceType()),
|
|
27196
|
+
// Listen for resize events
|
|
27197
|
+
window.addEventListener("resize", handleResize), () => {
|
|
27198
|
+
window.removeEventListener("resize", handleResize), util.destroy();
|
|
27199
|
+
};
|
|
27200
|
+
}), [ util, deviceType ]), "undefined" == typeof window ? {
|
|
27201
|
+
deviceType: "desktop",
|
|
27202
|
+
isMobile: !1,
|
|
27203
|
+
isTablet: !1,
|
|
27204
|
+
isDesktop: !0,
|
|
27205
|
+
isWide: !1,
|
|
27206
|
+
scaleValue: value => value,
|
|
27207
|
+
getCurrentDeviceType: () => "desktop",
|
|
27208
|
+
getCurrentScalingFactor: () => 1,
|
|
27209
|
+
isMobileOrSmaller: () => !1,
|
|
27210
|
+
isTabletOrSmaller: () => !0,
|
|
27211
|
+
isDesktopOrLarger: () => !0
|
|
27212
|
+
} : {
|
|
27213
|
+
deviceType: deviceType,
|
|
27214
|
+
isMobile: "mobile" === deviceType,
|
|
27215
|
+
isTablet: "tablet" === deviceType,
|
|
27216
|
+
isDesktop: "desktop" === deviceType,
|
|
27217
|
+
isWide: "wide" === deviceType,
|
|
27218
|
+
scaleValue: value => util.scaleValue(value),
|
|
27219
|
+
getCurrentDeviceType: () => util.getCurrentDeviceType(),
|
|
27220
|
+
getCurrentScalingFactor: () => util.getCurrentScalingFactor(),
|
|
27221
|
+
isMobileOrSmaller: () => util.isMobileOrSmaller(),
|
|
27222
|
+
isTabletOrSmaller: () => util.isTabletOrSmaller(),
|
|
27223
|
+
isDesktopOrLarger: () => util.isDesktopOrLarger()
|
|
27224
|
+
};
|
|
25576
27225
|
}
|
|
25577
27226
|
|
|
25578
27227
|
/**
|
|
@@ -25760,6 +27409,32 @@ class RTLManager {
|
|
|
25760
27409
|
}
|
|
25761
27410
|
}
|
|
25762
27411
|
|
|
27412
|
+
/**
|
|
27413
|
+
* Create RTL manager instance
|
|
27414
|
+
*/ function createRTLManager(config) {
|
|
27415
|
+
return new RTLManager(config);
|
|
27416
|
+
}
|
|
27417
|
+
|
|
27418
|
+
/**
|
|
27419
|
+
* Check if locale is RTL
|
|
27420
|
+
*/ function isRTLLocale(locale) {
|
|
27421
|
+
return RTL_LOCALES.has(locale.toLowerCase());
|
|
27422
|
+
}
|
|
27423
|
+
|
|
27424
|
+
/**
|
|
27425
|
+
* Get direction from locale
|
|
27426
|
+
*/ function getDirectionFromLocale(locale) {
|
|
27427
|
+
return isRTLLocale(locale) ? "rtl" : "ltr";
|
|
27428
|
+
}
|
|
27429
|
+
|
|
27430
|
+
/**
|
|
27431
|
+
* RTL-aware CSS helper
|
|
27432
|
+
*
|
|
27433
|
+
* Returns appropriate CSS based on direction
|
|
27434
|
+
*/ function rtlCSS(ltrCSS, rtlCSS, direction = "ltr") {
|
|
27435
|
+
return "rtl" === direction ? rtlCSS : ltrCSS;
|
|
27436
|
+
}
|
|
27437
|
+
|
|
25763
27438
|
/**
|
|
25764
27439
|
* Theme System Exports
|
|
25765
27440
|
*
|
|
@@ -25782,8 +27457,6 @@ class RTLManager {
|
|
|
25782
27457
|
// ============================================================================
|
|
25783
27458
|
// Core Theme Functions
|
|
25784
27459
|
// ============================================================================
|
|
25785
|
-
// Create theme CSS from DesignTokens
|
|
25786
|
-
// File saving utilities removed to prevent bundling Node.js modules in browser
|
|
25787
27460
|
/**
|
|
25788
27461
|
* Inject theme CSS into DOM
|
|
25789
27462
|
*/ function injectTheme(css, id = "atomix-theme") {
|
|
@@ -25796,6 +27469,115 @@ class RTLManager {
|
|
|
25796
27469
|
removeCSS(id);
|
|
25797
27470
|
}
|
|
25798
27471
|
|
|
27472
|
+
/**
|
|
27473
|
+
* Main theme module interface
|
|
27474
|
+
*/ var index = {
|
|
27475
|
+
// Core
|
|
27476
|
+
createTheme: createTheme,
|
|
27477
|
+
injectTheme: injectTheme,
|
|
27478
|
+
removeTheme: removeTheme,
|
|
27479
|
+
// Context and Provider
|
|
27480
|
+
ThemeProvider: ThemeProvider,
|
|
27481
|
+
useTheme: useTheme,
|
|
27482
|
+
useThemeTokens: useThemeTokens,
|
|
27483
|
+
ThemeContext: ThemeContext,
|
|
27484
|
+
ThemeErrorBoundary: ThemeErrorBoundary,
|
|
27485
|
+
// Adapters
|
|
27486
|
+
configToTokens: configToTokens,
|
|
27487
|
+
designTokensToCSSVars: designTokensToCSSVars,
|
|
27488
|
+
// Theme Utils
|
|
27489
|
+
switchTheme: switchTheme,
|
|
27490
|
+
toggleTheme: toggleTheme,
|
|
27491
|
+
getCurrentTheme: getCurrentTheme,
|
|
27492
|
+
getSystemTheme: getSystemTheme,
|
|
27493
|
+
initializeTheme: initializeTheme,
|
|
27494
|
+
listenToSystemTheme: listenToSystemTheme,
|
|
27495
|
+
persistTheme: persistTheme,
|
|
27496
|
+
clearThemePreference: clearThemePreference,
|
|
27497
|
+
// Token Manipulation
|
|
27498
|
+
mergeTokens: mergeTokens,
|
|
27499
|
+
overrideTokens: overrideTokens,
|
|
27500
|
+
pickTokens: pickTokens,
|
|
27501
|
+
omitTokens: omitTokens,
|
|
27502
|
+
// Color Utilities
|
|
27503
|
+
hexToRgb: hexToRgb$1,
|
|
27504
|
+
rgbToHex: rgbToHex,
|
|
27505
|
+
getLuminance: getLuminance,
|
|
27506
|
+
getContrastRatio: getContrastRatio,
|
|
27507
|
+
isAccessible: isAccessible,
|
|
27508
|
+
getContrastText: getContrastText,
|
|
27509
|
+
lighten: lighten,
|
|
27510
|
+
darken: darken,
|
|
27511
|
+
alpha: alpha,
|
|
27512
|
+
emphasize: emphasize,
|
|
27513
|
+
createSpacing: createSpacing,
|
|
27514
|
+
// Performance utilities
|
|
27515
|
+
createPerformanceMonitor: createPerformanceMonitor,
|
|
27516
|
+
usePerformanceMonitor: usePerformanceMonitor,
|
|
27517
|
+
// Responsive utilities
|
|
27518
|
+
createResponsiveUtil: createResponsiveUtil,
|
|
27519
|
+
useResponsive: useResponsive,
|
|
27520
|
+
// Components
|
|
27521
|
+
ThemeToggle: ThemeToggle,
|
|
27522
|
+
ThemeApplicator: ThemeApplicator,
|
|
27523
|
+
applyTheme: applyTheme,
|
|
27524
|
+
getThemeApplicator: getThemeApplicator,
|
|
27525
|
+
// Registry
|
|
27526
|
+
createThemeRegistry: createThemeRegistry,
|
|
27527
|
+
registerTheme: registerTheme,
|
|
27528
|
+
unregisterTheme: unregisterTheme,
|
|
27529
|
+
hasTheme: hasTheme,
|
|
27530
|
+
getTheme: getTheme,
|
|
27531
|
+
getAllThemes: getAllThemes,
|
|
27532
|
+
getThemeIds: getThemeIds,
|
|
27533
|
+
clearThemes: clearThemes,
|
|
27534
|
+
getThemeCount: getThemeCount,
|
|
27535
|
+
// Composition
|
|
27536
|
+
deepMerge: deepMerge,
|
|
27537
|
+
mergeTheme: mergeTheme,
|
|
27538
|
+
extendTheme: extendTheme,
|
|
27539
|
+
// Tokens
|
|
27540
|
+
createTokens: createTokens,
|
|
27541
|
+
defaultTokens: defaultTokens,
|
|
27542
|
+
// Generators
|
|
27543
|
+
generateCSSVariables: generateCSSVariables$1,
|
|
27544
|
+
generateCSSVariablesForSelector: generateCSSVariablesForSelector,
|
|
27545
|
+
// Naming
|
|
27546
|
+
generateClassName: generateClassName,
|
|
27547
|
+
generateCSSVariableName: generateCSSVariableName,
|
|
27548
|
+
normalizeThemeTokens: normalizeThemeTokens,
|
|
27549
|
+
camelToKebab: camelToKebab,
|
|
27550
|
+
themePropertyToCSSVar: themePropertyToCSSVar,
|
|
27551
|
+
// Component Theming
|
|
27552
|
+
getComponentThemeValue: getComponentThemeValue,
|
|
27553
|
+
generateComponentCSSVars: generateComponentCSSVars,
|
|
27554
|
+
applyComponentTheme: applyComponentTheme,
|
|
27555
|
+
useComponentTheme: useComponentTheme,
|
|
27556
|
+
// Hooks
|
|
27557
|
+
useThemeSwitcher: useThemeSwitcher,
|
|
27558
|
+
// Helpers
|
|
27559
|
+
isDesignTokens: isDesignTokens,
|
|
27560
|
+
// CSS Variable Mapper
|
|
27561
|
+
mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
|
|
27562
|
+
applyCSSVariables: applyCSSVariables,
|
|
27563
|
+
removeCSSVariables: removeCSSVariables,
|
|
27564
|
+
getCSSVariable: getCSSVariable,
|
|
27565
|
+
cssVarsToStyle: cssVarsToStyle,
|
|
27566
|
+
mergeCSSVars: mergeCSSVars,
|
|
27567
|
+
isValidCSSVariableName: isValidCSSVariableName,
|
|
27568
|
+
extractComponentName: extractComponentName,
|
|
27569
|
+
// Injection Utils
|
|
27570
|
+
injectCSS: injectCSS$1,
|
|
27571
|
+
removeCSS: removeCSS,
|
|
27572
|
+
isCSSInjected: isCSSInjected,
|
|
27573
|
+
// I18n
|
|
27574
|
+
RTLManager: RTLManager,
|
|
27575
|
+
createRTLManager: createRTLManager,
|
|
27576
|
+
isRTLLocale: isRTLLocale,
|
|
27577
|
+
getDirectionFromLocale: getDirectionFromLocale,
|
|
27578
|
+
rtlCSS: rtlCSS
|
|
27579
|
+
};
|
|
27580
|
+
|
|
25799
27581
|
/**
|
|
25800
27582
|
* CSS Variables Constants
|
|
25801
27583
|
*
|
|
@@ -26086,46 +27868,138 @@ function mergePartStyles(base, override) {
|
|
|
26086
27868
|
}
|
|
26087
27869
|
|
|
26088
27870
|
/**
|
|
26089
|
-
*
|
|
27871
|
+
* Hook to merge theme overrides with component props
|
|
26090
27872
|
*
|
|
26091
|
-
*
|
|
26092
|
-
*
|
|
26093
|
-
*
|
|
26094
|
-
*
|
|
26095
|
-
*
|
|
27873
|
+
* @example
|
|
27874
|
+
* function Button(props: ButtonProps) {
|
|
27875
|
+
* const customization = useComponentCustomization('Button', props);
|
|
27876
|
+
*
|
|
27877
|
+
* return (
|
|
27878
|
+
* <button
|
|
27879
|
+
* className={customization.className}
|
|
27880
|
+
* style={customization.style}
|
|
27881
|
+
* >
|
|
27882
|
+
* {props.children}
|
|
27883
|
+
* </button>
|
|
27884
|
+
* );
|
|
27885
|
+
* }
|
|
27886
|
+
*/
|
|
27887
|
+
/**
|
|
27888
|
+
* Configuration Validator
|
|
27889
|
+
*
|
|
27890
|
+
* Provides detailed validation and feedback for Atomix configurations,
|
|
27891
|
+
* especially for advanced features (Phases 2, 3, and 4).
|
|
27892
|
+
*/
|
|
27893
|
+
/**
|
|
27894
|
+
* Validate an Atomix configuration with detailed feedback
|
|
27895
|
+
*
|
|
27896
|
+
* @param config - The configuration to validate
|
|
27897
|
+
* @param options - Validation options
|
|
27898
|
+
* @returns Detailed validation result
|
|
26096
27899
|
*
|
|
26097
27900
|
* @example
|
|
26098
|
-
*
|
|
26099
|
-
*
|
|
26100
|
-
*
|
|
26101
|
-
*
|
|
26102
|
-
|
|
26103
|
-
|
|
26104
|
-
|
|
26105
|
-
|
|
26106
|
-
|
|
26107
|
-
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
|
|
26111
|
-
|
|
26112
|
-
|
|
26113
|
-
|
|
26114
|
-
|
|
26115
|
-
|
|
26116
|
-
|
|
26117
|
-
|
|
27901
|
+
* ```typescript
|
|
27902
|
+
* import { validateConfiguration } from '@shohojdhara/atomix/config';
|
|
27903
|
+
*
|
|
27904
|
+
* const config = { /* your config *\/ };
|
|
27905
|
+
* const result = validateConfiguration(config);
|
|
27906
|
+
*
|
|
27907
|
+
* if (!result.isValid) {
|
|
27908
|
+
* console.warn('Warnings:', result.warnings);
|
|
27909
|
+
* console.info('Suggestions:', result.suggestions);
|
|
27910
|
+
* }
|
|
27911
|
+
* ```
|
|
27912
|
+
*/
|
|
27913
|
+
function validateConfiguration(config, options) {
|
|
27914
|
+
const {performanceAnalysis: performanceAnalysis = !0, compatibilityReport: compatibilityReport = !0} = options || {}, warnings = [], suggestions = [];
|
|
27915
|
+
let performanceImpact = "low";
|
|
27916
|
+
// Use the existing validation
|
|
27917
|
+
const baseWarnings = validateConfig$1(config);
|
|
27918
|
+
warnings.push(...baseWarnings),
|
|
27919
|
+
// Analyze advanced features for performance impact
|
|
27920
|
+
performanceAnalysis && (performanceImpact =
|
|
27921
|
+
/**
|
|
27922
|
+
* Analyze the performance impact of a configuration
|
|
27923
|
+
*/
|
|
27924
|
+
function(config) {
|
|
27925
|
+
let impactScore = 0;
|
|
27926
|
+
// Analyze interactive effects
|
|
27927
|
+
if (config.interactiveEffects) {
|
|
27928
|
+
const ie = config.interactiveEffects;
|
|
27929
|
+
ie.vortex?.enabled && (impactScore += 2), ie.chromaticAberration?.enabled && (impactScore += 1),
|
|
27930
|
+
ie.mouseInteraction?.trailEffect && (impactScore += 1), ie.mouseInteraction?.pressureSensitivity && (impactScore += 1);
|
|
26118
27931
|
}
|
|
26119
|
-
//
|
|
26120
|
-
if (
|
|
27932
|
+
// Analyze visual polish effects
|
|
27933
|
+
if (config.visualPolish) {
|
|
27934
|
+
const vp = config.visualPolish;
|
|
27935
|
+
vp.borders?.iridescentGlow && (impactScore += 1), vp.borders?.shimmerEffect && (impactScore += 1),
|
|
27936
|
+
vp.contentAwareBlur?.enabled && (impactScore += 2), vp.holographicEffects?.enabled && (impactScore += 2),
|
|
27937
|
+
vp.holographicEffects?.scanlineAnimation && (impactScore += 1), vp.holographicEffects?.dataStream && (impactScore += 1),
|
|
27938
|
+
vp.holographicEffects?.pulseRings && (impactScore += 1);
|
|
27939
|
+
}
|
|
27940
|
+
// Analyze optimization settings
|
|
27941
|
+
return config.optimization?.autoScaling?.enabled && (impactScore -= 1),
|
|
27942
|
+
impactScore >= 6 ? "high" : impactScore >= 3 ? "medium" : "low";
|
|
26121
27943
|
}
|
|
26122
|
-
|
|
26123
|
-
|
|
27944
|
+
/**
|
|
27945
|
+
* Generate suggestions based on the configuration
|
|
27946
|
+
*/ (config)),
|
|
27947
|
+
// Generate suggestions based on configuration
|
|
27948
|
+
function(config, suggestions) {
|
|
27949
|
+
// Suggest enabling performance optimizations if heavy effects are used
|
|
27950
|
+
(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"),
|
|
27951
|
+
config.optimization?.performance?.fpsTarget || suggestions.push("Set a target FPS in optimization.performance.fpsTarget to ensure smooth performance when using interactive effects")),
|
|
27952
|
+
// Suggest responsive breakpoints if optimization is partially configured
|
|
27953
|
+
config.optimization && !config.optimization.responsive && suggestions.push("Consider adding responsive breakpoints in optimization.responsive.breakpoints to adapt advanced effects based on device type"),
|
|
27954
|
+
// Suggest disabling heavy effects on lower-end devices
|
|
27955
|
+
config.visualPolish?.holographicEffects?.enabled && suggestions.push("For better performance on lower-end devices, consider conditionally disabling holographic effects based on device capabilities"),
|
|
27956
|
+
// Suggest using content-aware blur with performance considerations
|
|
27957
|
+
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"),
|
|
27958
|
+
// Suggest using chromatic aberration适度
|
|
27959
|
+
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"),
|
|
27960
|
+
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"));
|
|
27961
|
+
}
|
|
27962
|
+
/**
|
|
27963
|
+
* Generate a compatibility report for the configuration
|
|
27964
|
+
*/ (config, suggestions);
|
|
27965
|
+
// Determine overall validity
|
|
27966
|
+
const isValid = 0 === warnings.length, compatibility = compatibilityReport ? function(config) {
|
|
27967
|
+
return {
|
|
27968
|
+
browsers: !(config.visualPolish?.holographicEffects?.enabled || config.visualPolish?.contentAwareBlur?.enabled || config.interactiveEffects?.vortex?.enabled || config.interactiveEffects?.chromaticAberration?.enabled),
|
|
27969
|
+
// May have issues on older browsers
|
|
27970
|
+
ssr: !0,
|
|
27971
|
+
// Works fine with SSR
|
|
27972
|
+
frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
|
|
27973
|
+
};
|
|
27974
|
+
}
|
|
27975
|
+
/**
|
|
27976
|
+
* Print a detailed configuration report to the console
|
|
27977
|
+
*
|
|
27978
|
+
* @param config - The configuration to analyze
|
|
27979
|
+
* @param title - Optional title for the report
|
|
27980
|
+
*
|
|
27981
|
+
* @example
|
|
27982
|
+
* ```typescript
|
|
27983
|
+
* import { printConfigReport } from '@shohojdhara/atomix/config';
|
|
27984
|
+
*
|
|
27985
|
+
* const config = { /* your config *\/ };
|
|
27986
|
+
* printConfigReport(config, 'My Application Config');
|
|
27987
|
+
* ```
|
|
27988
|
+
*/ (config) : {
|
|
27989
|
+
browsers: !0,
|
|
27990
|
+
ssr: !0,
|
|
27991
|
+
frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
|
|
27992
|
+
};
|
|
27993
|
+
// Generate compatibility report
|
|
27994
|
+
return {
|
|
27995
|
+
isValid: isValid,
|
|
27996
|
+
warnings: warnings,
|
|
27997
|
+
suggestions: suggestions,
|
|
27998
|
+
performanceImpact: performanceImpact,
|
|
27999
|
+
compatibility: compatibility
|
|
28000
|
+
};
|
|
26124
28001
|
}
|
|
26125
28002
|
|
|
26126
|
-
/**
|
|
26127
|
-
* Check if a value is a slot configuration
|
|
26128
|
-
*/
|
|
26129
28003
|
// Import and re-export as namespaces with proper typing
|
|
26130
28004
|
// Export as namespaces with explicit typing
|
|
26131
28005
|
const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
|
|
@@ -26140,19 +28014,30 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
|
|
|
26140
28014
|
ThemeLiveEditor: ThemeLiveEditor,
|
|
26141
28015
|
ThemePreview: ThemePreview,
|
|
26142
28016
|
ThemeProvider: ThemeProvider,
|
|
28017
|
+
ThemeToggle: ThemeToggle,
|
|
26143
28018
|
ThemeValidator: ThemeValidator,
|
|
28019
|
+
alpha: alpha,
|
|
26144
28020
|
applyCSSVariables: applyCSSVariables,
|
|
26145
28021
|
applyComponentTheme: applyComponentTheme,
|
|
26146
28022
|
applyTheme: applyTheme,
|
|
26147
28023
|
camelToKebab: camelToKebab,
|
|
28024
|
+
clearThemePreference: clearThemePreference,
|
|
26148
28025
|
clearThemes: clearThemes,
|
|
28026
|
+
configToTokens: configToTokens,
|
|
28027
|
+
createPerformanceMonitor: createPerformanceMonitor,
|
|
28028
|
+
createRTLManager: createRTLManager,
|
|
28029
|
+
createResponsiveUtil: createResponsiveUtil,
|
|
28030
|
+
createSpacing: createSpacing,
|
|
26149
28031
|
createTheme: createTheme,
|
|
26150
28032
|
createThemeRegistry: createThemeRegistry,
|
|
26151
28033
|
createTokens: createTokens,
|
|
26152
28034
|
cssVarsToStyle: cssVarsToStyle,
|
|
28035
|
+
darken: darken,
|
|
26153
28036
|
deepMerge: deepMerge,
|
|
28037
|
+
default: index,
|
|
26154
28038
|
defaultTokens: defaultTokens,
|
|
26155
28039
|
designTokensToCSSVars: designTokensToCSSVars,
|
|
28040
|
+
emphasize: emphasize,
|
|
26156
28041
|
extendTheme: extendTheme,
|
|
26157
28042
|
extractComponentName: extractComponentName,
|
|
26158
28043
|
generateCSSVariableName: generateCSSVariableName,
|
|
@@ -26163,29 +28048,53 @@ const composables = composablesImport, utils = utilsImport, types = typesImport,
|
|
|
26163
28048
|
getAllThemes: getAllThemes,
|
|
26164
28049
|
getCSSVariable: getCSSVariable,
|
|
26165
28050
|
getComponentThemeValue: getComponentThemeValue,
|
|
28051
|
+
getContrastRatio: getContrastRatio,
|
|
28052
|
+
getContrastText: getContrastText,
|
|
28053
|
+
getCurrentTheme: getCurrentTheme,
|
|
28054
|
+
getDirectionFromLocale: getDirectionFromLocale,
|
|
28055
|
+
getLuminance: getLuminance,
|
|
28056
|
+
getSystemTheme: getSystemTheme,
|
|
26166
28057
|
getTheme: getTheme,
|
|
26167
28058
|
getThemeApplicator: getThemeApplicator,
|
|
26168
28059
|
getThemeCount: getThemeCount,
|
|
26169
28060
|
getThemeIds: getThemeIds,
|
|
26170
28061
|
hasTheme: hasTheme,
|
|
28062
|
+
hexToRgb: hexToRgb$1,
|
|
28063
|
+
initializeTheme: initializeTheme,
|
|
26171
28064
|
injectCSS: injectCSS$1,
|
|
26172
28065
|
injectTheme: injectTheme,
|
|
28066
|
+
isAccessible: isAccessible,
|
|
26173
28067
|
isCSSInjected: isCSSInjected,
|
|
26174
28068
|
isDesignTokens: isDesignTokens,
|
|
28069
|
+
isRTLLocale: isRTLLocale,
|
|
26175
28070
|
isValidCSSVariableName: isValidCSSVariableName,
|
|
28071
|
+
lighten: lighten,
|
|
28072
|
+
listenToSystemTheme: listenToSystemTheme,
|
|
26176
28073
|
mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
|
|
26177
28074
|
mergeCSSVars: mergeCSSVars,
|
|
26178
28075
|
mergeTheme: mergeTheme,
|
|
28076
|
+
mergeTokens: mergeTokens,
|
|
26179
28077
|
normalizeThemeTokens: normalizeThemeTokens,
|
|
28078
|
+
omitTokens: omitTokens,
|
|
28079
|
+
overrideTokens: overrideTokens,
|
|
28080
|
+
persistTheme: persistTheme,
|
|
28081
|
+
pickTokens: pickTokens,
|
|
26180
28082
|
registerTheme: registerTheme,
|
|
26181
28083
|
removeCSS: removeCSS,
|
|
26182
28084
|
removeCSSVariables: removeCSSVariables,
|
|
26183
28085
|
removeTheme: removeTheme,
|
|
28086
|
+
rgbToHex: rgbToHex,
|
|
28087
|
+
rtlCSS: rtlCSS,
|
|
28088
|
+
switchTheme: switchTheme,
|
|
26184
28089
|
themePropertyToCSSVar: themePropertyToCSSVar,
|
|
28090
|
+
toggleTheme: toggleTheme,
|
|
26185
28091
|
unregisterTheme: unregisterTheme,
|
|
26186
28092
|
useComponentTheme: useComponentTheme,
|
|
26187
28093
|
useHistory: useHistory,
|
|
28094
|
+
usePerformanceMonitor: usePerformanceMonitor,
|
|
28095
|
+
useResponsive: useResponsive,
|
|
26188
28096
|
useTheme: useTheme,
|
|
28097
|
+
useThemeSwitcher: useThemeSwitcher,
|
|
26189
28098
|
useThemeTokens: useThemeTokens
|
|
26190
28099
|
}), atomix = {
|
|
26191
28100
|
// Re-export all components and utilities
|
|
@@ -26253,10 +28162,11 @@ exports.TYPEDBUTTON = TYPEDBUTTON, exports.Tabs = Tabs, exports.Testimonial = Te
|
|
|
26253
28162
|
exports.Textarea = Textarea, exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
|
|
26254
28163
|
exports.ThemeContext = ThemeContext, exports.ThemeErrorBoundary = ThemeErrorBoundary,
|
|
26255
28164
|
exports.ThemeInspector = ThemeInspector, exports.ThemeLiveEditor = ThemeLiveEditor,
|
|
26256
|
-
exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.
|
|
26257
|
-
exports.
|
|
26258
|
-
exports.
|
|
26259
|
-
exports.
|
|
28165
|
+
exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeToggle = ThemeToggle,
|
|
28166
|
+
exports.ThemeValidator = ThemeValidator, exports.Todo = Todo, exports.Toggle = Toggle,
|
|
28167
|
+
exports.Tooltip = Tooltip, exports.TreemapChart = TreemapChart, exports.UPLOAD = UPLOAD,
|
|
28168
|
+
exports.Upload = Upload, exports.VIDEO_PLAYER = VIDEO_PLAYER, exports.VideoPlayer = VideoPlayer,
|
|
28169
|
+
exports.WaterfallChart = WaterfallChart, exports.alpha = alpha, exports.applyCSSVariables = applyCSSVariables,
|
|
26260
28170
|
exports.applyCSSVarsToStyle =
|
|
26261
28171
|
/**
|
|
26262
28172
|
* Utility to apply CSS variables to style object
|
|
@@ -26270,60 +28180,16 @@ function(cssVars, baseStyle) {
|
|
|
26270
28180
|
};
|
|
26271
28181
|
}
|
|
26272
28182
|
/**
|
|
26273
|
-
*
|
|
26274
|
-
*
|
|
26275
|
-
* Tailwind-like configuration for customizing the Atomix Design System.
|
|
26276
|
-
*
|
|
26277
|
-
* External developers can create `atomix.config.ts` in their project root
|
|
26278
|
-
* to customize design tokens, similar to Tailwind's tailwind.config.js
|
|
26279
|
-
*
|
|
26280
|
-
* @example
|
|
26281
|
-
* ```typescript
|
|
26282
|
-
* // atomix.config.ts (in your project)
|
|
26283
|
-
* import { defineConfig } from '@shohojdhara/atomix/config';
|
|
26284
|
-
*
|
|
26285
|
-
* export default defineConfig({
|
|
26286
|
-
* theme: {
|
|
26287
|
-
* extend: {
|
|
26288
|
-
* colors: {
|
|
26289
|
-
* primary: { main: '#7AFFD7' },
|
|
26290
|
-
* },
|
|
26291
|
-
* },
|
|
26292
|
-
* },
|
|
26293
|
-
* });
|
|
26294
|
-
* ```
|
|
26295
|
-
*/
|
|
26296
|
-
/**
|
|
26297
|
-
* Helper function to define Atomix configuration with type safety
|
|
28183
|
+
* Configuration Types
|
|
26298
28184
|
*
|
|
26299
|
-
*
|
|
26300
|
-
* @returns The configuration object
|
|
28185
|
+
* Type definitions for the Atomix configuration system.
|
|
26301
28186
|
*/
|
|
26302
28187
|
/**
|
|
26303
28188
|
* Helper function to define Atomix configuration with type safety
|
|
26304
|
-
*
|
|
26305
|
-
* Similar to Tailwind's defineConfig, provides autocomplete and type checking.
|
|
26306
|
-
*
|
|
26307
|
-
* @param config - Atomix configuration object
|
|
26308
|
-
* @returns The configuration object
|
|
26309
|
-
*
|
|
26310
|
-
* @example
|
|
26311
|
-
* ```typescript
|
|
26312
|
-
* import { defineConfig } from '@shohojdhara/atomix/config';
|
|
26313
|
-
*
|
|
26314
|
-
* export default defineConfig({
|
|
26315
|
-
* theme: {
|
|
26316
|
-
* extend: {
|
|
26317
|
-
* colors: {
|
|
26318
|
-
* primary: { main: '#7AFFD7' },
|
|
26319
|
-
* },
|
|
26320
|
-
* },
|
|
26321
|
-
* },
|
|
26322
|
-
* });
|
|
26323
|
-
* ```
|
|
26324
28189
|
*/ , exports.applyComponentTheme = applyComponentTheme, exports.applyPartStyles = applyPartStyles,
|
|
26325
|
-
exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.
|
|
26326
|
-
exports.
|
|
28190
|
+
exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemePreference = clearThemePreference,
|
|
28191
|
+
exports.clearThemes = clearThemes, exports.composables = composables, exports.configToTokens = configToTokens,
|
|
28192
|
+
exports.constants = constants, exports.createBreakpoints = createBreakpoints$1,
|
|
26327
28193
|
exports.createCSSVarStyle = createCSSVarStyle, exports.createDarkVariant =
|
|
26328
28194
|
/**
|
|
26329
28195
|
* Create a dark theme variant from a light theme
|
|
@@ -26380,7 +28246,9 @@ function(lightTheme) {
|
|
|
26380
28246
|
/**
|
|
26381
28247
|
* Validate theme structure
|
|
26382
28248
|
*/ , exports.createDebugAttrs = createDebugAttrs, exports.createFontPreloadLink = createFontPreloadLink,
|
|
26383
|
-
exports.createPartProps = createPartProps, exports.
|
|
28249
|
+
exports.createPartProps = createPartProps, exports.createPerformanceMonitor = createPerformanceMonitor,
|
|
28250
|
+
exports.createRTLManager = createRTLManager, exports.createResponsiveUtil = createResponsiveUtil,
|
|
28251
|
+
exports.createSlotComponent =
|
|
26384
28252
|
/**
|
|
26385
28253
|
* Create a slot wrapper component
|
|
26386
28254
|
*
|
|
@@ -26418,11 +28286,13 @@ function(defaultElement = "div") {
|
|
|
26418
28286
|
}
|
|
26419
28287
|
/**
|
|
26420
28288
|
* Hook to manage slot rendering
|
|
26421
|
-
*/ , exports.
|
|
26422
|
-
exports.
|
|
28289
|
+
*/ , exports.createSpacing = createSpacing, exports.createTheme = createTheme,
|
|
28290
|
+
exports.createThemeRegistry = createThemeRegistry, exports.createTokens = createTokens,
|
|
28291
|
+
exports.cssVarsToStyle = cssVarsToStyle, exports.darken = darken, exports.deepMerge = deepMerge,
|
|
26423
28292
|
exports.default = atomix, exports.defaultTokens = defaultTokens, exports.defineConfig = function(config) {
|
|
26424
28293
|
return config;
|
|
26425
|
-
}, exports.designTokensToCSSVars = designTokensToCSSVars, exports.
|
|
28294
|
+
}, exports.designTokensToCSSVars = designTokensToCSSVars, exports.emphasize = emphasize,
|
|
28295
|
+
exports.exportTheme =
|
|
26426
28296
|
/**
|
|
26427
28297
|
* Export theme as JSON
|
|
26428
28298
|
*/
|
|
@@ -26442,9 +28312,12 @@ exports.getAllThemes = getAllThemes, exports.getCSSVariable = getCSSVariable, ex
|
|
|
26442
28312
|
*/
|
|
26443
28313
|
function(component) {
|
|
26444
28314
|
return COMPONENT_CSS_VARS[component];
|
|
26445
|
-
}, exports.getComponentThemeValue = getComponentThemeValue, exports.
|
|
26446
|
-
exports.
|
|
26447
|
-
exports.
|
|
28315
|
+
}, exports.getComponentThemeValue = getComponentThemeValue, exports.getContrastRatio = getContrastRatio,
|
|
28316
|
+
exports.getContrastText = getContrastText, exports.getCurrentTheme = getCurrentTheme,
|
|
28317
|
+
exports.getDefaultBreakpoints = getDefaultBreakpoints, exports.getDevicePreset = getDevicePreset,
|
|
28318
|
+
exports.getDirectionFromLocale = getDirectionFromLocale, exports.getLuminance = getLuminance,
|
|
28319
|
+
exports.getMobileOptimizedParams = getMobileOptimizedParams, exports.getPartStyles = getPartStyles,
|
|
28320
|
+
exports.getQualityMultipliers = getQualityMultipliers, exports.getSystemTheme = getSystemTheme,
|
|
26448
28321
|
exports.getTheme = getTheme, exports.getThemeApplicator = getThemeApplicator, exports.getThemeCount = getThemeCount,
|
|
26449
28322
|
exports.getThemeIds = getThemeIds, exports.getThemeMetadata =
|
|
26450
28323
|
/**
|
|
@@ -26465,7 +28338,7 @@ function(theme) {
|
|
|
26465
28338
|
/**
|
|
26466
28339
|
* Check if theme supports dark mode
|
|
26467
28340
|
*/ , exports.hasCustomization = hasCustomization, exports.hasTheme = hasTheme,
|
|
26468
|
-
exports.importTheme = function(json) {
|
|
28341
|
+
exports.hexToRgb = hexToRgb$1, exports.importTheme = function(json) {
|
|
26469
28342
|
try {
|
|
26470
28343
|
return JSON.parse(json);
|
|
26471
28344
|
} catch (error) {
|
|
@@ -26476,15 +28349,49 @@ exports.importTheme = function(json) {
|
|
|
26476
28349
|
// are already exported from './theme' module. Import them directly from there.
|
|
26477
28350
|
// This file only exports theme-tools specific utilities.
|
|
26478
28351
|
// Export all components individually for better tree-shaking
|
|
26479
|
-
, exports.
|
|
26480
|
-
exports.
|
|
28352
|
+
, exports.initializeTheme = initializeTheme, exports.injectCSS = injectCSS$1, exports.injectTheme = injectTheme,
|
|
28353
|
+
exports.isAccessible = isAccessible, exports.isCSSInjected = isCSSInjected, exports.isDesignTokens = isDesignTokens,
|
|
28354
|
+
exports.isRTLLocale = isRTLLocale, exports.isSlot = function(value) {
|
|
26481
28355
|
return "object" == typeof value && null !== value && ("render" in value || "component" in value || "children" in value);
|
|
26482
28356
|
}
|
|
26483
28357
|
/**
|
|
26484
28358
|
* Merge multiple slot configurations
|
|
26485
28359
|
* Later slots override earlier ones
|
|
26486
28360
|
*/ , exports.isValidCSSVariableName = isValidCSSVariableName, exports.isYouTubeUrl = isYouTubeUrl,
|
|
26487
|
-
exports.
|
|
28361
|
+
exports.lighten = lighten, exports.listenToSystemTheme = listenToSystemTheme, exports.loadAtomixConfig = loadAtomixConfig,
|
|
28362
|
+
exports.loadConfig =
|
|
28363
|
+
/**
|
|
28364
|
+
* Public API for loading and managing Atomix configuration
|
|
28365
|
+
*
|
|
28366
|
+
* This module provides the public-facing API for configuration loading
|
|
28367
|
+
* in external projects.
|
|
28368
|
+
*/
|
|
28369
|
+
/**
|
|
28370
|
+
* Load Atomix configuration from an external project.
|
|
28371
|
+
*
|
|
28372
|
+
* @param options - Loading options
|
|
28373
|
+
* @returns The loaded configuration
|
|
28374
|
+
*
|
|
28375
|
+
* @example
|
|
28376
|
+
* ```typescript
|
|
28377
|
+
* import { loadConfig } from '@shohojdhara/atomix/config';
|
|
28378
|
+
*
|
|
28379
|
+
* const config = loadConfig();
|
|
28380
|
+
* console.log(config.prefix); // 'atomix' or user's custom prefix
|
|
28381
|
+
* ```
|
|
28382
|
+
*/
|
|
28383
|
+
function(options) {
|
|
28384
|
+
return loadAtomixConfig({
|
|
28385
|
+
configPath: options?.configPath,
|
|
28386
|
+
required: options?.required ?? !1
|
|
28387
|
+
});
|
|
28388
|
+
}
|
|
28389
|
+
/**
|
|
28390
|
+
* Validate Atomix configuration structure.
|
|
28391
|
+
*
|
|
28392
|
+
* @param config - Configuration object to validate
|
|
28393
|
+
* @returns Array of validation warnings (empty if valid)
|
|
28394
|
+
*/ , exports.mapSCSSTokensToCSSVars = mapSCSSTokensToCSSVars, exports.mergeCSSVars = mergeCSSVars,
|
|
26488
28395
|
exports.mergeClassNames = mergeClassNames, exports.mergeComponentProps = mergeComponentProps,
|
|
26489
28396
|
exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slots) {
|
|
26490
28397
|
const filtered = slots.filter((s => void 0 !== s));
|
|
@@ -26492,8 +28399,17 @@ exports.mergePartStyles = mergePartStyles, exports.mergeSlots = function(...slot
|
|
|
26492
28399
|
...acc,
|
|
26493
28400
|
...slot
|
|
26494
28401
|
})));
|
|
26495
|
-
}, exports.mergeTheme = mergeTheme, exports.normalizeThemeTokens = normalizeThemeTokens,
|
|
26496
|
-
exports.
|
|
28402
|
+
}, exports.mergeTheme = mergeTheme, exports.mergeTokens = mergeTokens, exports.normalizeThemeTokens = normalizeThemeTokens,
|
|
28403
|
+
exports.omitTokens = omitTokens, exports.overrideTokens = overrideTokens, exports.persistTheme = persistTheme,
|
|
28404
|
+
exports.pickTokens = pickTokens, exports.preloadFonts = preloadFonts, exports.printConfigReport = function(config, title) {
|
|
28405
|
+
const result = validateConfiguration(config);
|
|
28406
|
+
result.warnings.length > 0 && result.warnings.forEach((warning => {})), result.suggestions.length > 0 && result.suggestions.forEach((suggestion => {}));
|
|
28407
|
+
const featuresDetected = [];
|
|
28408
|
+
config.interactiveEffects && featuresDetected.push("Interactive Effects"), config.optimization && featuresDetected.push("Optimization"),
|
|
28409
|
+
config.visualPolish && featuresDetected.push("Visual Polish"), config.ai && featuresDetected.push("AI Integration"),
|
|
28410
|
+
config.tokenEngine && featuresDetected.push("Token Engine"), config.generator && featuresDetected.push("Component Generator"),
|
|
28411
|
+
featuresDetected.length > 0 && featuresDetected.forEach((feature => {}));
|
|
28412
|
+
}, exports.quickTheme =
|
|
26497
28413
|
/**
|
|
26498
28414
|
* Quick theme creator with sensible defaults
|
|
26499
28415
|
*/
|
|
@@ -26510,11 +28426,23 @@ function(name, primaryColor, secondaryColor) {
|
|
|
26510
28426
|
}
|
|
26511
28427
|
});
|
|
26512
28428
|
}, exports.registerTheme = registerTheme, exports.removeCSS = removeCSS, exports.removeCSSVariables = removeCSSVariables,
|
|
26513
|
-
exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.
|
|
28429
|
+
exports.removeTheme = removeTheme, exports.renderSlot = renderSlot, exports.resolveConfigPath = function(configPath) {
|
|
28430
|
+
// In browser environments, config resolution is not possible
|
|
28431
|
+
if ("undefined" != typeof window) return null;
|
|
28432
|
+
// If a specific config path is provided, check if it exists
|
|
28433
|
+
if (configPath) {
|
|
28434
|
+
const absPath = path$4.join(process.cwd(), configPath);
|
|
28435
|
+
return fs.existsSync(absPath) ? absPath : null;
|
|
28436
|
+
}
|
|
28437
|
+
// Otherwise, check standard locations
|
|
28438
|
+
const possiblePaths = [ path$4.join(process.cwd(), "atomix.config.ts"), path$4.join(process.cwd(), "atomix.config.js"), path$4.join(process.cwd(), "atomix.config.json") ];
|
|
28439
|
+
for (const path of possiblePaths) if (fs.existsSync(path)) return path;
|
|
28440
|
+
return null;
|
|
28441
|
+
}, exports.rgbToHex = rgbToHex, exports.rtlCSS = rtlCSS, exports.sliderConstants = sliderConstants,
|
|
26514
28442
|
exports.supportsDarkMode = function(theme) {
|
|
26515
28443
|
var _context;
|
|
26516
28444
|
return "dark" === theme.palette?.mode || !0 === theme.supportsDarkMode || Boolean((null == (_context = theme.a11y?.modes) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("dark"));
|
|
26517
|
-
}, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
|
|
28445
|
+
}, exports.switchTheme = switchTheme, exports.theme = theme, exports.themePropertyToCSSVar = themePropertyToCSSVar,
|
|
26518
28446
|
exports.themeToCSS =
|
|
26519
28447
|
/**
|
|
26520
28448
|
* Generate CSS string from theme
|
|
@@ -26524,28 +28452,11 @@ function(theme, selector = ":root") {
|
|
|
26524
28452
|
selector: selector,
|
|
26525
28453
|
prefix: "atomix"
|
|
26526
28454
|
});
|
|
26527
|
-
}, exports.
|
|
26528
|
-
exports.
|
|
26529
|
-
exports.
|
|
26530
|
-
exports.
|
|
26531
|
-
|
|
26532
|
-
* Hook to merge theme overrides with component props
|
|
26533
|
-
*
|
|
26534
|
-
* @example
|
|
26535
|
-
* function Button(props: ButtonProps) {
|
|
26536
|
-
* const customization = useComponentCustomization('Button', props);
|
|
26537
|
-
*
|
|
26538
|
-
* return (
|
|
26539
|
-
* <button
|
|
26540
|
-
* className={customization.className}
|
|
26541
|
-
* style={customization.style}
|
|
26542
|
-
* >
|
|
26543
|
-
* {props.children}
|
|
26544
|
-
* </button>
|
|
26545
|
-
* );
|
|
26546
|
-
* }
|
|
26547
|
-
*/
|
|
26548
|
-
function(component, props) {
|
|
28455
|
+
}, exports.toggleTheme = toggleTheme, exports.types = types, exports.unregisterTheme = unregisterTheme,
|
|
28456
|
+
exports.useAccordion = useAccordion, exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge,
|
|
28457
|
+
exports.useBarChart = useBarChart, exports.useBlock = useBlock, exports.useChartData = useChartData,
|
|
28458
|
+
exports.useChartInteraction = useChartInteraction, exports.useChartScale = useChartScale,
|
|
28459
|
+
exports.useComponentCustomization = function(component, props) {
|
|
26549
28460
|
const {theme: theme} = useTheme(), cssVars = React.useMemo((() => mergeCSSVars(theme?.components?.[component]?.cssVars || {}, props.cssVars || {})), [ theme, component, props.cssVars ]), parts = React.useMemo((() => {
|
|
26550
28461
|
const themeParts = theme?.components?.[component]?.parts || {}, propParts = props.parts || {}, merged = {};
|
|
26551
28462
|
return new Set([ ...Object.keys(themeParts), ...Object.keys(propParts) ]).forEach((partName => {
|
|
@@ -26584,14 +28495,16 @@ exports.useMergedProps = function(defaultProps, props) {
|
|
|
26584
28495
|
...props
|
|
26585
28496
|
})), [ defaultProps, props ]);
|
|
26586
28497
|
}, exports.useNav = useNav, exports.useNavDropdown = useNavDropdown, exports.useNavItem = useNavItem,
|
|
26587
|
-
exports.useNavbar = useNavbar, exports.
|
|
26588
|
-
exports.
|
|
28498
|
+
exports.useNavbar = useNavbar, exports.usePieChart = usePieChart, exports.useRadio = useRadio,
|
|
28499
|
+
exports.useResponsive = useResponsive, exports.useResponsiveGlass = useResponsiveGlass,
|
|
26589
28500
|
exports.useRiver = useRiver, exports.useSelect = useSelect, exports.useSideMenu = useSideMenu,
|
|
26590
28501
|
exports.useSideMenuItem = useSideMenuItem, exports.useSlot = function(slot, props, fallback) {
|
|
26591
28502
|
return React__default.default.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
|
|
26592
28503
|
}, exports.useSpinner = useSpinner, exports.useTextarea = useTextarea, exports.useTheme = useTheme,
|
|
26593
|
-
exports.
|
|
26594
|
-
exports.
|
|
28504
|
+
exports.useThemeSwitcher = useThemeSwitcher, exports.useThemeTokens = useThemeTokens,
|
|
28505
|
+
exports.useTodo = useTodo, exports.utils = utils, exports.validateConfig = function(config) {
|
|
28506
|
+
return validateConfig$1(config);
|
|
28507
|
+
}, exports.validateConfiguration = validateConfiguration, exports.validateTheme = function(theme) {
|
|
26595
28508
|
const errors = [];
|
|
26596
28509
|
return theme.name || errors.push("Theme must have a name"), theme.palette || errors.push("Theme must have a palette"),
|
|
26597
28510
|
theme.palette && !theme.palette.primary && errors.push("Theme palette must have a primary color"),
|