@shohojdhara/atomix 0.3.12 → 0.3.14
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/CHANGELOG.md +19 -0
- package/README.md +2 -0
- package/dist/atomix.css +101 -88
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +5 -15258
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +1 -1
- package/dist/charts.js +17 -19
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +41 -11
- package/dist/core.js +55 -41
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +28 -11
- package/dist/forms.js +25 -24
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +1 -1
- package/dist/heavy.js +32 -25
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +122 -46
- package/dist/index.esm.js +865 -200
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +870 -204
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +27 -2
- package/dist/theme.js +721 -108
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/scripts/atomix-cli.js +610 -1111
- package/scripts/cli/component-generator.js +610 -0
- package/scripts/cli/documentation-sync.js +542 -0
- package/scripts/cli/interactive-init.js +84 -288
- package/scripts/cli/mappings.js +211 -0
- package/scripts/cli/migration-tools.js +95 -288
- package/scripts/cli/template-manager.js +107 -0
- package/scripts/cli/templates/README.md +123 -0
- package/scripts/cli/templates/composable-templates.js +149 -0
- package/scripts/cli/templates/config-templates.js +126 -0
- package/scripts/cli/templates/index.js +95 -0
- package/scripts/cli/templates/project-templates.js +214 -0
- package/scripts/cli/templates/react-templates.js +261 -0
- package/scripts/cli/templates/scss-templates.js +156 -0
- package/scripts/cli/templates/storybook-templates.js +236 -0
- package/scripts/cli/templates/testing-templates.js +45 -0
- package/scripts/cli/templates/token-templates.js +447 -0
- package/scripts/cli/templates/types-templates.js +133 -0
- package/scripts/cli/templates-original-backup.js +1655 -0
- package/scripts/cli/templates.js +35 -0
- package/scripts/cli/templates_backup.js +684 -0
- package/scripts/cli/theme-bridge.js +20 -14
- package/scripts/cli/token-manager.js +150 -77
- package/scripts/cli/utils.js +37 -25
- package/src/components/Accordion/Accordion.stories.tsx +5 -5
- package/src/components/Accordion/Accordion.test.tsx +57 -0
- package/src/components/Accordion/Accordion.tsx +4 -0
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +41 -44
- package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -1
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +37 -37
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -2
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +50 -51
- package/src/components/Avatar/Avatar.stories.tsx +26 -26
- package/src/components/Badge/Badge.stories.tsx +31 -31
- package/src/components/Badge/Badge.test.tsx +51 -0
- package/src/components/Badge/Badge.tsx +20 -1
- package/src/components/Block/Block.stories.tsx +5 -5
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -1
- package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
- package/src/components/Button/Button.stories.tsx +13 -13
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Button/ButtonGroup.stories.tsx +2 -2
- package/src/components/Button/README.md +5 -0
- package/src/components/Callout/Callout.stories.tsx +11 -11
- package/src/components/Callout/Callout.test.tsx +10 -10
- package/src/components/Callout/Callout.tsx +7 -7
- package/src/components/Callout/README.md +9 -8
- package/src/components/Card/Card.tsx +2 -2
- package/src/components/Chart/Chart.stories.tsx +6 -6
- package/src/components/Chart/Chart.tsx +1 -1
- package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +1 -1
- package/src/components/DataTable/DataTable.tsx +14 -12
- package/src/components/DatePicker/DatePicker.stories.tsx +6 -6
- package/src/components/Dropdown/Dropdown.stories.tsx +4 -4
- package/src/components/Form/Checkbox.stories.tsx +3 -3
- package/src/components/Form/Checkbox.tsx +4 -2
- package/src/components/Form/Form.stories.tsx +3 -3
- package/src/components/Form/FormGroup.stories.tsx +1 -1
- package/src/components/Form/Input.stories.tsx +28 -16
- package/src/components/Form/Input.test.tsx +59 -0
- package/src/components/Form/Input.tsx +97 -95
- package/src/components/Form/Radio.stories.tsx +94 -94
- package/src/components/Form/Radio.tsx +2 -2
- package/src/components/Form/Select.stories.tsx +4 -4
- package/src/components/Form/Select.tsx +2 -2
- package/src/components/Form/Textarea.stories.tsx +22 -7
- package/src/components/Form/Textarea.test.tsx +45 -0
- package/src/components/Form/Textarea.tsx +88 -86
- package/src/components/List/List.stories.tsx +2 -2
- package/src/components/Modal/Modal.stories.tsx +4 -4
- package/src/components/Navigation/Navbar/Navbar.stories.tsx +5 -5
- package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
- package/src/components/Navigation/README.md +1 -1
- package/src/components/Pagination/Pagination.stories.tsx +5 -2
- package/src/components/Pagination/Pagination.tsx +1 -1
- package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -10
- package/src/components/Popover/Popover.stories.tsx +1 -1
- package/src/components/ProductReview/ProductReview.tsx +1 -1
- package/src/components/Progress/Progress.tsx +46 -46
- package/src/components/Rating/Rating.stories.tsx +4 -4
- package/src/components/Rating/Rating.tsx +8 -8
- package/src/components/Slider/Slider.stories.tsx +63 -63
- package/src/components/Spinner/Spinner.stories.tsx +2 -2
- package/src/components/Spinner/Spinner.test.tsx +35 -0
- package/src/components/Spinner/Spinner.tsx +9 -2
- package/src/components/Testimonial/Testimonial.stories.tsx +1 -1
- package/src/components/Toggle/Toggle.stories.tsx +32 -9
- package/src/components/Toggle/Toggle.test.tsx +91 -0
- package/src/components/Toggle/Toggle.tsx +44 -27
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/layouts/Grid/Grid.stories.tsx +49 -49
- package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +2 -2
- package/src/lib/composables/useAccordion.ts +12 -3
- package/src/lib/composables/useBreadcrumb.ts +2 -2
- package/src/lib/composables/useCallout.ts +7 -7
- package/src/lib/composables/useNavbar.ts +1 -1
- package/src/lib/constants/components.ts +1 -1
- package/src/lib/storybook/InteractiveDemo.tsx +113 -0
- package/src/lib/storybook/PreviewContainer.tsx +36 -0
- package/src/lib/storybook/VariantsGrid.tsx +21 -0
- package/src/lib/storybook/index.ts +3 -0
- package/src/lib/theme/core/createThemeObject.ts +9 -5
- package/src/lib/theme/devtools/CLI.ts +155 -0
- package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +213 -0
- package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +566 -0
- package/src/lib/theme/devtools/LiveEditor.tsx +2 -1
- package/src/lib/theme/devtools/index.ts +3 -0
- package/src/lib/theme/errors/errors.ts +8 -0
- package/src/lib/theme/runtime/ThemeProvider.tsx +117 -57
- package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +305 -0
- package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +588 -0
- package/src/lib/theme/utils/__tests__/themeValidation.test.ts +264 -0
- package/src/lib/theme/utils/index.ts +1 -0
- package/src/lib/theme/utils/themeValidation.ts +501 -0
- package/src/lib/theme-tools.ts +32 -3
- package/src/lib/types/components.ts +81 -26
- package/src/lib/utils/themeNaming.ts +1 -1
- package/src/styles/06-components/_components.atomix-glass.scss +14 -15
- package/src/styles/06-components/_components.callout.scss +29 -33
- package/src/styles/06-components/_index.scss +1 -1
- package/src/styles/99-utilities/_utilities.display.scss +14 -3
- package/src/styles/99-utilities/_utilities.flex.scss +10 -10
- package/src/styles/99-utilities/_utilities.text.scss +28 -8
- package/scripts/cli/__tests__/cli-commands.test.js +0 -204
- package/scripts/cli/__tests__/utils.test.js +0 -201
- package/scripts/cli/__tests__/vitest.config.js +0 -26
package/dist/index.js
CHANGED
|
@@ -73,7 +73,7 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
|
|
|
73
73
|
CLOSE_BTN_CLASS: "c-callout__close-btn",
|
|
74
74
|
VARIANT_PREFIX: "c-callout--",
|
|
75
75
|
CLASSES: {
|
|
76
|
-
|
|
76
|
+
COMPACT: "c-callout--compact",
|
|
77
77
|
TOAST: "c-callout--toast",
|
|
78
78
|
HIDE: "is-hide"
|
|
79
79
|
}
|
|
@@ -1604,7 +1604,12 @@ function useAccordion(initialProps) {
|
|
|
1604
1604
|
panelHeight: panelHeight
|
|
1605
1605
|
},
|
|
1606
1606
|
toggle: () => {
|
|
1607
|
-
|
|
1607
|
+
if (!defaultProps.disabled) {
|
|
1608
|
+
const nextOpen = !isOpen;
|
|
1609
|
+
isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen),
|
|
1610
|
+
// Call legacy handlers
|
|
1611
|
+
nextOpen ? defaultProps.onOpen?.() : defaultProps.onClose?.();
|
|
1612
|
+
}
|
|
1608
1613
|
},
|
|
1609
1614
|
updatePanelHeight: updatePanelHeight,
|
|
1610
1615
|
panelRef: panelRef,
|
|
@@ -1848,7 +1853,13 @@ const {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
|
|
|
1848
1853
|
*/ GlassFilterComponent.displayName = "GlassFilter";
|
|
1849
1854
|
|
|
1850
1855
|
// Memoize component to prevent unnecessary re-renders
|
|
1851
|
-
const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount))
|
|
1856
|
+
const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount));
|
|
1857
|
+
|
|
1858
|
+
// Module-level counter for deterministic ID generation
|
|
1859
|
+
let idCounter = 0;
|
|
1860
|
+
|
|
1861
|
+
// Module-level shared shader cache with LRU eviction
|
|
1862
|
+
const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
|
|
1852
1863
|
x: 0,
|
|
1853
1864
|
y: 0
|
|
1854
1865
|
}, globalMousePosition: globalMousePosition = {
|
|
@@ -1859,10 +1870,8 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
|
|
|
1859
1870
|
height: 0
|
|
1860
1871
|
}, onClick: onClick, mode: mode = "standard", effectiveDisableEffects: effectiveDisableEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", enableLiquidBlur: enableLiquidBlur = !1, elasticity: elasticity = 0, contentRef: contentRef}, ref) => {
|
|
1861
1872
|
// Generate a stable, deterministic ID for SSR compatibility
|
|
1862
|
-
// Use a
|
|
1863
|
-
const [
|
|
1864
|
-
// Use a simple counter for deterministic IDs
|
|
1865
|
-
"undefined" == typeof window ? `atomix-glass-filter-ssr-${Math.random().toString(36).substring(2, 11)}` : `atomix-glass-filter-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`)), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null);
|
|
1873
|
+
// Use a module-level counter that's consistent across server and client
|
|
1874
|
+
const filterId = React.useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null);
|
|
1866
1875
|
// Lazy load shader utilities only when shader mode is needed
|
|
1867
1876
|
React.useEffect((() => {
|
|
1868
1877
|
"shader" === mode ?
|
|
@@ -1905,9 +1914,9 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
|
|
|
1905
1914
|
width: glassSize.width,
|
|
1906
1915
|
height: glassSize.height,
|
|
1907
1916
|
fragment: selectedShader
|
|
1908
|
-
})
|
|
1909
|
-
//
|
|
1910
|
-
|
|
1917
|
+
}),
|
|
1918
|
+
// Defer shader generation with longer delay to avoid blocking
|
|
1919
|
+
setTimeout((() => {
|
|
1911
1920
|
const url = shaderGeneratorRef.current?.updateShader() || "";
|
|
1912
1921
|
((key, url) => {
|
|
1913
1922
|
// Evict oldest entries if at capacity
|
|
@@ -1926,20 +1935,15 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
|
|
|
1926
1935
|
// Development mode: log cache size
|
|
1927
1936
|
"undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
|
|
1928
1937
|
})(cacheKey, url), setShaderMapUrl(url);
|
|
1929
|
-
};
|
|
1930
|
-
"undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
|
|
1931
|
-
timeout: 1e3
|
|
1932
|
-
}) :
|
|
1933
|
-
// Fallback to setTimeout for browsers without requestIdleCallback
|
|
1934
|
-
setTimeout(generate, 0);
|
|
1938
|
+
}), 100);
|
|
1935
1939
|
} catch (error) {
|
|
1936
1940
|
console.warn("AtomixGlassContainer: Error generating shader map", error), setShaderMapUrl("");
|
|
1937
1941
|
} else
|
|
1938
1942
|
// Shader utils not loaded yet, retry after a short delay
|
|
1939
1943
|
shaderDebounceTimeoutRef.current = setTimeout(generateShader, 100);
|
|
1940
1944
|
};
|
|
1941
|
-
// Debounce with
|
|
1942
|
-
shaderDebounceTimeoutRef.current = setTimeout(generateShader,
|
|
1945
|
+
// Debounce with 500ms delay to reduce frequency
|
|
1946
|
+
shaderDebounceTimeoutRef.current = setTimeout(generateShader, 500);
|
|
1943
1947
|
} else
|
|
1944
1948
|
// Not in shader mode, clear URL
|
|
1945
1949
|
setShaderMapUrl("");
|
|
@@ -2006,7 +2010,7 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
|
|
|
2006
2010
|
backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
|
|
2007
2011
|
};
|
|
2008
2012
|
}
|
|
2009
|
-
}), [
|
|
2013
|
+
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveDisableEffects, enableLiquidBlur ]), containerVars = React.useMemo((() => {
|
|
2010
2014
|
try {
|
|
2011
2015
|
// Safe extraction of mouse offset values
|
|
2012
2016
|
const mx = mouseOffset && "number" == typeof mouseOffset.x && !isNaN(mouseOffset.x) ? mouseOffset.x : 0, my = mouseOffset && "number" == typeof mouseOffset.y && !isNaN(mouseOffset.y) ? mouseOffset.y : 0;
|
|
@@ -2095,7 +2099,6 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
|
|
|
2095
2099
|
});
|
|
2096
2100
|
}));
|
|
2097
2101
|
|
|
2098
|
-
// Module-level shared shader cache with LRU eviction
|
|
2099
2102
|
AtomixGlassContainer.displayName = "AtomixGlassContainer";
|
|
2100
2103
|
|
|
2101
2104
|
// Singleton instance
|
|
@@ -2843,14 +2846,16 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
2843
2846
|
});
|
|
2844
2847
|
}
|
|
2845
2848
|
|
|
2846
|
-
const Accordion = React.memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
|
|
2849
|
+
const Accordion = React.memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, onOpen: onOpen, onClose: onClose, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
|
|
2847
2850
|
// Generate unique IDs for accessibility
|
|
2848
2851
|
const instanceId = React.useId(), buttonId = `accordion-header-${instanceId}`, panelId = `accordion-panel-${instanceId}`, {state: state, toggle: toggle, updatePanelHeight: updatePanelHeight, panelRef: panelRef, contentRef: contentRef, generateClassNames: generateClassNames, generateHeaderClassNames: generateHeaderClassNames} = useAccordion({
|
|
2849
2852
|
defaultOpen: defaultOpen,
|
|
2850
2853
|
disabled: disabled,
|
|
2851
2854
|
iconPosition: iconPosition,
|
|
2852
2855
|
isOpen: controlledOpen,
|
|
2853
|
-
onOpenChange: onOpenChange
|
|
2856
|
+
onOpenChange: onOpenChange,
|
|
2857
|
+
onOpen: onOpen,
|
|
2858
|
+
onClose: onClose
|
|
2854
2859
|
}), defaultIcon = jsxRuntime.jsx("i", {
|
|
2855
2860
|
className: "c-accordion__icon",
|
|
2856
2861
|
"aria-hidden": "true",
|
|
@@ -3337,7 +3342,7 @@ function useBadge(initialProps) {
|
|
|
3337
3342
|
|
|
3338
3343
|
AvatarGroup.displayName = "AvatarGroup";
|
|
3339
3344
|
|
|
3340
|
-
const Badge = React.memo((({label: label, variant: variant = "primary", size: size = "md", disabled: disabled = !1, icon: icon, className: className = "", glass: glass, style: style}) => {
|
|
3345
|
+
const Badge = React.memo((({label: label, variant: variant = "primary", size: size = "md", disabled: disabled = !1, icon: icon, onRemove: onRemove, "aria-label": ariaLabel, className: className = "", glass: glass, style: style}) => {
|
|
3341
3346
|
const {generateBadgeClass: generateBadgeClass} = useBadge({
|
|
3342
3347
|
variant: variant,
|
|
3343
3348
|
size: size,
|
|
@@ -3350,6 +3355,7 @@ const Badge = React.memo((({label: label, variant: variant = "primary", size: s
|
|
|
3350
3355
|
}), badgeElement = jsxRuntime.jsxs("span", {
|
|
3351
3356
|
className: badgeClass,
|
|
3352
3357
|
"aria-disabled": disabled,
|
|
3358
|
+
"aria-label": ariaLabel,
|
|
3353
3359
|
ref: ref,
|
|
3354
3360
|
style: style,
|
|
3355
3361
|
children: [ icon && jsxRuntime.jsx("span", {
|
|
@@ -3357,6 +3363,13 @@ const Badge = React.memo((({label: label, variant: variant = "primary", size: s
|
|
|
3357
3363
|
children: icon
|
|
3358
3364
|
}), jsxRuntime.jsx("span", {
|
|
3359
3365
|
children: label
|
|
3366
|
+
}), onRemove && jsxRuntime.jsx("button", {
|
|
3367
|
+
type: "button",
|
|
3368
|
+
className: "c-badge__close",
|
|
3369
|
+
onClick: onRemove,
|
|
3370
|
+
"aria-label": "Remove badge",
|
|
3371
|
+
disabled: disabled,
|
|
3372
|
+
children: "×"
|
|
3360
3373
|
}) ]
|
|
3361
3374
|
});
|
|
3362
3375
|
if (glass) {
|
|
@@ -3484,7 +3497,7 @@ const useBlock = () => ({
|
|
|
3484
3497
|
* ```
|
|
3485
3498
|
*/ Block.displayName = "Block";
|
|
3486
3499
|
|
|
3487
|
-
const Breadcrumb = React.memo((({items: items, divider: divider, className: className = "",
|
|
3500
|
+
const Breadcrumb = React.memo((({items: items, divider: divider, className: className = "", "aria-label": ariaLabel = "Breadcrumb", LinkComponent: LinkComponent, style: style}) => {
|
|
3488
3501
|
const breadcrumbClasses = [ BREADCRUMB.CLASSES.BASE, className ].filter(Boolean).join(" ");
|
|
3489
3502
|
return jsxRuntime.jsx("nav", {
|
|
3490
3503
|
"aria-label": ariaLabel,
|
|
@@ -3587,7 +3600,7 @@ function useButton(initialProps) {
|
|
|
3587
3600
|
|
|
3588
3601
|
Breadcrumb.displayName = "Breadcrumb";
|
|
3589
3602
|
|
|
3590
|
-
const Spinner = React.memo((({size: size = "md", variant: variant = "primary", fullscreen: fullscreen = !1, className: className = "", style: style, glass: glass}) => {
|
|
3603
|
+
const Spinner = React.memo((({size: size = "md", variant: variant = "primary", fullscreen: fullscreen = !1, className: className = "", style: style, glass: glass, "aria-label": ariaLabel, role: role = "status"}) => {
|
|
3591
3604
|
const {generateSpinnerClass: generateSpinnerClass} = useSpinner({
|
|
3592
3605
|
size: size,
|
|
3593
3606
|
variant: variant,
|
|
@@ -3600,10 +3613,11 @@ const Spinner = React.memo((({size: size = "md", variant: variant = "primary",
|
|
|
3600
3613
|
}), spinnerContent = jsxRuntime.jsx("div", {
|
|
3601
3614
|
className: spinnerClass,
|
|
3602
3615
|
style: style,
|
|
3603
|
-
role:
|
|
3616
|
+
role: role,
|
|
3617
|
+
"aria-label": ariaLabel || "Loading",
|
|
3604
3618
|
children: jsxRuntime.jsx("span", {
|
|
3605
3619
|
className: SPINNER.VISUALLY_HIDDEN,
|
|
3606
|
-
children: "Loading..."
|
|
3620
|
+
children: ariaLabel || "Loading..."
|
|
3607
3621
|
})
|
|
3608
3622
|
});
|
|
3609
3623
|
if (glass) {
|
|
@@ -3655,7 +3669,7 @@ class ThemeNaming {
|
|
|
3655
3669
|
* Convert kebab-case to camelCase for JavaScript properties
|
|
3656
3670
|
* @param str - String to convert
|
|
3657
3671
|
*/ static kebabToCamel(str) {
|
|
3658
|
-
return str.replace(/-([a-z])/g, (g => g[1]
|
|
3672
|
+
return str.replace(/-([a-z])/g, (g => g[1]?.toUpperCase() ?? ""));
|
|
3659
3673
|
}
|
|
3660
3674
|
/**
|
|
3661
3675
|
* Create a CSS variable name
|
|
@@ -3716,7 +3730,7 @@ class ThemeNaming {
|
|
|
3716
3730
|
|
|
3717
3731
|
ThemeNaming.prefix = "atomix";
|
|
3718
3732
|
|
|
3719
|
-
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,
|
|
3733
|
+
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, ...props}, ref) => {
|
|
3720
3734
|
const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsxRuntime.jsx(Icon, {
|
|
3721
3735
|
name: iconName,
|
|
3722
3736
|
size: iconSize
|
|
@@ -4245,7 +4259,7 @@ var includes$3 = getBuiltInPrototypeMethod$3("String", "includes"), isPrototypeO
|
|
|
4245
4259
|
/**
|
|
4246
4260
|
* Callout component for displaying important messages, notifications, or alerts
|
|
4247
4261
|
*/
|
|
4248
|
-
const Callout = ({title: title, children: children, icon: icon, variant: variant = "primary", onClose: onClose, actions: actions,
|
|
4262
|
+
const Callout = ({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}) => {
|
|
4249
4263
|
const {generateCalloutClass: generateCalloutClass, handleClose: handleClose} =
|
|
4250
4264
|
/**
|
|
4251
4265
|
* Callout state and functionality
|
|
@@ -4256,8 +4270,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
|
|
|
4256
4270
|
// Default callout properties
|
|
4257
4271
|
const defaultProps = {
|
|
4258
4272
|
variant: "primary",
|
|
4259
|
-
|
|
4260
|
-
|
|
4273
|
+
compact: !1,
|
|
4274
|
+
isToast: !1,
|
|
4261
4275
|
glass: !1,
|
|
4262
4276
|
...initialProps
|
|
4263
4277
|
};
|
|
@@ -4268,8 +4282,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
|
|
|
4268
4282
|
*/ return {
|
|
4269
4283
|
defaultProps: defaultProps,
|
|
4270
4284
|
generateCalloutClass: props => {
|
|
4271
|
-
const {variant: variant = defaultProps.variant,
|
|
4272
|
-
return `c-callout ${variant ? `c-callout--${variant}` : ""} ${
|
|
4285
|
+
const {variant: variant = defaultProps.variant, compact: compact = defaultProps.compact, isToast: isToast = defaultProps.isToast, glass: glass = defaultProps.glass, className: className = ""} = props;
|
|
4286
|
+
return `c-callout ${variant ? `c-callout--${variant}` : ""} ${compact ? "c-callout--compact" : ""} ${isToast ? "c-callout--toast" : ""} ${glass ? "c-callout--glass" : ""} ${className}`.trim();
|
|
4273
4287
|
},
|
|
4274
4288
|
handleClose: handler => () => {
|
|
4275
4289
|
handler && handler();
|
|
@@ -4277,8 +4291,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
|
|
|
4277
4291
|
};
|
|
4278
4292
|
}({
|
|
4279
4293
|
variant: variant,
|
|
4280
|
-
|
|
4281
|
-
|
|
4294
|
+
compact: compact,
|
|
4295
|
+
isToast: isToast,
|
|
4282
4296
|
glass: glass,
|
|
4283
4297
|
className: className,
|
|
4284
4298
|
style: style
|
|
@@ -4288,7 +4302,7 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
|
|
|
4288
4302
|
role: "region"
|
|
4289
4303
|
};
|
|
4290
4304
|
// For toast notifications or alerts, use appropriate role and live region
|
|
4291
|
-
return
|
|
4305
|
+
return isToast ? (baseAttributes.role = "alert", baseAttributes["aria-live"] = "polite") : _includesInstanceProperty(_context = [ "warning", "error" ]).call(_context, variant) ? (baseAttributes.role = "alert",
|
|
4292
4306
|
baseAttributes["aria-live"] = "assertive") : _includesInstanceProperty(_context2 = [ "info", "success" ]).call(_context2, variant) && (baseAttributes.role = "status",
|
|
4293
4307
|
baseAttributes["aria-live"] = "polite"), baseAttributes;
|
|
4294
4308
|
}, calloutContent = jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
@@ -4334,8 +4348,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
|
|
|
4334
4348
|
return jsxRuntime.jsx("div", {
|
|
4335
4349
|
className: generateCalloutClass({
|
|
4336
4350
|
variant: variant,
|
|
4337
|
-
|
|
4338
|
-
|
|
4351
|
+
compact: compact,
|
|
4352
|
+
isToast: isToast,
|
|
4339
4353
|
glass: glass,
|
|
4340
4354
|
className: className
|
|
4341
4355
|
}),
|
|
@@ -4357,8 +4371,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
|
|
|
4357
4371
|
return jsxRuntime.jsx("div", {
|
|
4358
4372
|
className: generateCalloutClass({
|
|
4359
4373
|
variant: variant,
|
|
4360
|
-
|
|
4361
|
-
|
|
4374
|
+
compact: compact,
|
|
4375
|
+
isToast: isToast,
|
|
4362
4376
|
glass: glass,
|
|
4363
4377
|
className: className
|
|
4364
4378
|
}),
|
|
@@ -4385,7 +4399,7 @@ onClick: onClick, onHover: onHover, onFocus: onFocus, href: href, target: target
|
|
|
4385
4399
|
// Glass
|
|
4386
4400
|
glass: glass,
|
|
4387
4401
|
// Accessibility
|
|
4388
|
-
role: role,
|
|
4402
|
+
role: role, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, tabIndex: tabIndex,
|
|
4389
4403
|
// Styling
|
|
4390
4404
|
className: className = "", style: style, ...rest}, ref) => {
|
|
4391
4405
|
// Determine if card is clickable/interactive
|
|
@@ -5933,7 +5947,7 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
|
|
|
5933
5947
|
tabIndex: 0,
|
|
5934
5948
|
...props,
|
|
5935
5949
|
children: [ (title || subtitle || showToolbar) && jsxRuntime.jsxs("div", {
|
|
5936
|
-
className: `${CHART.HEADER_CLASS} u-
|
|
5950
|
+
className: `${CHART.HEADER_CLASS} u-flex u-justify-between u-items-start u-gap-4`,
|
|
5937
5951
|
children: [ jsxRuntime.jsxs("div", {
|
|
5938
5952
|
className: `${CHART.HEADER_CONTENT_CLASS} u-flex-1`,
|
|
5939
5953
|
children: [ title && jsxRuntime.jsx("h3", {
|
|
@@ -9247,7 +9261,7 @@ const range = (start, end) => {
|
|
|
9247
9261
|
"aria-hidden": "true"
|
|
9248
9262
|
})
|
|
9249
9263
|
})
|
|
9250
|
-
}))), Pagination = React.memo((({currentPage: currentPage = PAGINATION_DEFAULTS.currentPage, totalPages: totalPages = PAGINATION_DEFAULTS.totalPages, onPageChange: onPageChange, siblingCount: siblingCount = PAGINATION_DEFAULTS.siblingCount, showFirstLastButtons: showFirstLastButtons = PAGINATION_DEFAULTS.showFirstLastButtons, showPrevNextButtons: showPrevNextButtons = PAGINATION_DEFAULTS.showPrevNextButtons, showSearch: showSearch = !1, searchPlaceholder: searchPlaceholder = "Go to page", size: size = PAGINATION_DEFAULTS.size, className: className = "", style: style,
|
|
9264
|
+
}))), Pagination = React.memo((({currentPage: currentPage = PAGINATION_DEFAULTS.currentPage, totalPages: totalPages = PAGINATION_DEFAULTS.totalPages, onPageChange: onPageChange, siblingCount: siblingCount = PAGINATION_DEFAULTS.siblingCount, showFirstLastButtons: showFirstLastButtons = PAGINATION_DEFAULTS.showFirstLastButtons, showPrevNextButtons: showPrevNextButtons = PAGINATION_DEFAULTS.showPrevNextButtons, showSearch: showSearch = !1, searchPlaceholder: searchPlaceholder = "Go to page", size: size = PAGINATION_DEFAULTS.size, className: className = "", style: style, "aria-label": ariaLabel = "Pagination", glass: glass}) => {
|
|
9251
9265
|
const {paginationRange: paginationRange, goToPage: goToPage, nextPage: nextPage, prevPage: prevPage, firstPage: firstPage, lastPage: lastPage} = usePagination({
|
|
9252
9266
|
currentPage: currentPage,
|
|
9253
9267
|
totalPages: totalPages,
|
|
@@ -9414,7 +9428,7 @@ function useCheckbox(initialProps) {
|
|
|
9414
9428
|
|
|
9415
9429
|
/**
|
|
9416
9430
|
* Checkbox - A component for checkbox inputs
|
|
9417
|
-
*/ const Checkbox = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, indeterminate: indeterminate = !1,
|
|
9431
|
+
*/ const Checkbox = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, indeterminate: indeterminate = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onClick: onClick, glass: glass}) => {
|
|
9418
9432
|
const {generateCheckboxClass: generateCheckboxClass, checkboxRef: checkboxRef} = useCheckbox({
|
|
9419
9433
|
indeterminate: indeterminate,
|
|
9420
9434
|
disabled: disabled,
|
|
@@ -9435,6 +9449,7 @@ function useCheckbox(initialProps) {
|
|
|
9435
9449
|
className: "c-checkbox__input",
|
|
9436
9450
|
checked: checked,
|
|
9437
9451
|
onChange: onChange,
|
|
9452
|
+
onClick: onClick,
|
|
9438
9453
|
disabled: disabled,
|
|
9439
9454
|
required: required,
|
|
9440
9455
|
id: id,
|
|
@@ -9732,7 +9747,7 @@ const DataTable = React.memo((({data: data, columns: columns, className: classN
|
|
|
9732
9747
|
}), []), handleDrop = React.useCallback(((e, dropIndex) => {
|
|
9733
9748
|
if (e.preventDefault(), null !== dragStartIndex && dragStartIndex !== dropIndex && onColumnReorder) {
|
|
9734
9749
|
const newOrder = [ ...visibleColumns.map((col => col.key)) ], [removed] = newOrder.splice(dragStartIndex, 1);
|
|
9735
|
-
newOrder.splice(dropIndex, 0, removed), onColumnReorder(newOrder);
|
|
9750
|
+
removed && (newOrder.splice(dropIndex, 0, removed), onColumnReorder(newOrder));
|
|
9736
9751
|
}
|
|
9737
9752
|
setDragStartIndex(null), setDragOverIndex(null);
|
|
9738
9753
|
}), [ dragStartIndex, visibleColumns, onColumnReorder ]), handleExport = React.useCallback((format => {
|
|
@@ -10042,7 +10057,7 @@ const DataTable = React.memo((({data: data, columns: columns, className: classN
|
|
|
10042
10057
|
showFirstLastButtons: !0,
|
|
10043
10058
|
showPrevNextButtons: !0,
|
|
10044
10059
|
size: "sm",
|
|
10045
|
-
|
|
10060
|
+
"aria-label": "Data table pagination",
|
|
10046
10061
|
className: "c-data-table__pagination"
|
|
10047
10062
|
})
|
|
10048
10063
|
}) ]
|
|
@@ -11026,7 +11041,7 @@ function useInput(initialProps) {
|
|
|
11026
11041
|
* Input - A component for text input fields
|
|
11027
11042
|
*/ FormGroup.displayName = "FormGroup";
|
|
11028
11043
|
|
|
11029
|
-
const Input = React.memo( React.forwardRef((({type: type = "text", value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, autoComplete: autoComplete, autoFocus: autoFocus = !1, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, maxLength: maxLength, minLength: minLength, pattern: pattern, min: min, max: max, step: step,
|
|
11044
|
+
const Input = React.memo( React.forwardRef((({type: type = "text", value: value, defaultValue: defaultValue, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, autoComplete: autoComplete, autoFocus: autoFocus = !1, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, maxLength: maxLength, minLength: minLength, pattern: pattern, min: min, max: max, step: step, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass}, ref) => {
|
|
11030
11045
|
const {generateInputClass: generateInputClass} = useInput({
|
|
11031
11046
|
size: size,
|
|
11032
11047
|
variant: variant,
|
|
@@ -11046,6 +11061,7 @@ const Input = React.memo( React.forwardRef((({type: type = "text", value: value
|
|
|
11046
11061
|
type: type,
|
|
11047
11062
|
className: inputClass,
|
|
11048
11063
|
value: value,
|
|
11064
|
+
defaultValue: defaultValue,
|
|
11049
11065
|
onChange: onChange,
|
|
11050
11066
|
onBlur: onBlur,
|
|
11051
11067
|
onFocus: onFocus,
|
|
@@ -11300,7 +11316,7 @@ function useHero(initialProps) {
|
|
|
11300
11316
|
backdrop: !1,
|
|
11301
11317
|
closeOnOutsideClick: !0,
|
|
11302
11318
|
closeOnEscape: !0,
|
|
11303
|
-
|
|
11319
|
+
"aria-label": "Main navigation",
|
|
11304
11320
|
...initialProps
|
|
11305
11321
|
}, [isExpanded, setIsExpanded] = React.useState(defaultProps.expanded || !1);
|
|
11306
11322
|
// Local expanded state for when not controlled externally
|
|
@@ -12100,7 +12116,7 @@ const DEFAULT_ATOMIX_FONTS = [ {
|
|
|
12100
12116
|
items: [],
|
|
12101
12117
|
divider: BREADCRUMB.DEFAULTS.DIVIDER,
|
|
12102
12118
|
className: "",
|
|
12103
|
-
|
|
12119
|
+
"aria-label": "Breadcrumb",
|
|
12104
12120
|
...initialOptions
|
|
12105
12121
|
},
|
|
12106
12122
|
generateBreadcrumbClass: options => {
|
|
@@ -12433,21 +12449,21 @@ function useSlider(options) {
|
|
|
12433
12449
|
const [interaction, setInteraction] = React.useState({
|
|
12434
12450
|
hoveredIndex: null,
|
|
12435
12451
|
selectedIndex: null
|
|
12436
|
-
})
|
|
12437
|
-
setInteraction((prev => ({
|
|
12438
|
-
...prev,
|
|
12439
|
-
hoveredIndex: index
|
|
12440
|
-
})));
|
|
12441
|
-
}), []), handlePointClick = React.useCallback((index => {
|
|
12442
|
-
setInteraction((prev => ({
|
|
12443
|
-
...prev,
|
|
12444
|
-
selectedIndex: prev.selectedIndex === index ? null : index
|
|
12445
|
-
})));
|
|
12446
|
-
}), []);
|
|
12452
|
+
});
|
|
12447
12453
|
return {
|
|
12448
12454
|
interaction: interaction,
|
|
12449
|
-
handlePointHover:
|
|
12450
|
-
|
|
12455
|
+
handlePointHover: React.useCallback((index => {
|
|
12456
|
+
setInteraction((prev => ({
|
|
12457
|
+
...prev,
|
|
12458
|
+
hoveredIndex: index
|
|
12459
|
+
})));
|
|
12460
|
+
}), []),
|
|
12461
|
+
handlePointClick: React.useCallback((index => {
|
|
12462
|
+
setInteraction((prev => ({
|
|
12463
|
+
...prev,
|
|
12464
|
+
selectedIndex: prev.selectedIndex === index ? null : index
|
|
12465
|
+
})));
|
|
12466
|
+
}), []),
|
|
12451
12467
|
clearInteraction: React.useCallback((() => {
|
|
12452
12468
|
setInteraction({
|
|
12453
12469
|
hoveredIndex: null,
|
|
@@ -12501,7 +12517,7 @@ var composablesImport = Object.freeze({
|
|
|
12501
12517
|
|
|
12502
12518
|
/**
|
|
12503
12519
|
* Select - A component for dropdown selection
|
|
12504
|
-
*/ const Select = React.memo((({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,
|
|
12520
|
+
*/ const Select = React.memo((({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}) => {
|
|
12505
12521
|
const {generateSelectClass: generateSelectClass} = useSelect({
|
|
12506
12522
|
size: size,
|
|
12507
12523
|
disabled: disabled,
|
|
@@ -12647,7 +12663,7 @@ Select.displayName = "Select";
|
|
|
12647
12663
|
/**
|
|
12648
12664
|
* Radio - A component for radio button inputs
|
|
12649
12665
|
*/
|
|
12650
|
-
const Radio = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1,
|
|
12666
|
+
const Radio = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass}) => {
|
|
12651
12667
|
const {generateRadioClass: generateRadioClass} = useRadio({
|
|
12652
12668
|
disabled: disabled,
|
|
12653
12669
|
invalid: invalid,
|
|
@@ -12705,7 +12721,7 @@ Radio.displayName = "Radio";
|
|
|
12705
12721
|
/**
|
|
12706
12722
|
* Textarea - A component for multiline text input
|
|
12707
12723
|
*/
|
|
12708
|
-
const Textarea = React.memo( React.forwardRef((({value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, rows: rows = 4, cols: cols, maxLength: maxLength, minLength: minLength, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, autoFocus: autoFocus = !1,
|
|
12724
|
+
const Textarea = React.memo( React.forwardRef((({value: value, defaultValue: defaultValue, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, rows: rows = 4, cols: cols, maxLength: maxLength, minLength: minLength, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, autoFocus: autoFocus = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass}, ref) => {
|
|
12709
12725
|
const {generateTextareaClass: generateTextareaClass} = useTextarea({
|
|
12710
12726
|
size: size,
|
|
12711
12727
|
variant: variant,
|
|
@@ -12723,6 +12739,7 @@ const Textarea = React.memo( React.forwardRef((({value: value, onChange: onChan
|
|
|
12723
12739
|
ref: ref,
|
|
12724
12740
|
className: textareaClass,
|
|
12725
12741
|
value: value,
|
|
12742
|
+
defaultValue: defaultValue,
|
|
12726
12743
|
onChange: onChange,
|
|
12727
12744
|
onBlur: onBlur,
|
|
12728
12745
|
onFocus: onFocus,
|
|
@@ -14271,7 +14288,7 @@ NavItem.displayName = "NavItem";
|
|
|
14271
14288
|
* </Navbar>
|
|
14272
14289
|
* ```
|
|
14273
14290
|
*/
|
|
14274
|
-
const Navbar = React.forwardRef((({brand: brand, children: children, variant: variant, position: position = "static", containerWidth: containerWidth, collapsible: collapsible = !0, expanded: expanded, onToggle: onToggle, className: className = "", style: style, disabled: disabled = !1, backdrop: backdrop = !1, closeOnOutsideClick: closeOnOutsideClick = !0, closeOnEscape: closeOnEscape = !0,
|
|
14291
|
+
const Navbar = React.forwardRef((({brand: brand, children: children, variant: variant, position: position = "static", containerWidth: containerWidth, collapsible: collapsible = !0, expanded: expanded, onToggle: onToggle, className: className = "", style: style, disabled: disabled = !1, backdrop: backdrop = !1, closeOnOutsideClick: closeOnOutsideClick = !0, closeOnEscape: closeOnEscape = !0, "aria-label": ariaLabel = "Main navigation", id: id, glass: glass}, ref) => {
|
|
14275
14292
|
const {generateNavbarClass: generateNavbarClass, generateContainerStyle: generateContainerStyle, generateCollapseClass: generateCollapseClass} = useNavbar({
|
|
14276
14293
|
position: position,
|
|
14277
14294
|
collapsible: collapsible,
|
|
@@ -16355,7 +16372,7 @@ const PopoverContext = React.createContext({
|
|
|
16355
16372
|
/**
|
|
16356
16373
|
* Hook for managing rating component state and interactions
|
|
16357
16374
|
*/
|
|
16358
|
-
const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultValue, maxValue: maxValue = 5, allowHalf: allowHalf = !1, readOnly: readOnly = !1, size: size = "md",
|
|
16375
|
+
const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultValue, maxValue: maxValue = 5, allowHalf: allowHalf = !1, readOnly: readOnly = !1, size: size = "md", variant: variant, onChange: onChange, className: className = "", style: style, label: label, id: id, useVanillaJS: useVanillaJS = !1, glass: glass, ...restProps}, ref) => {
|
|
16359
16376
|
const internalRef = React.useRef(null), ratingInstance = React.useRef(null), {currentValue: currentValue, hoverValue: hoverValue, focusedIndex: focusedIndex, setHoverValue: setHoverValue, setFocused: setFocused, handleKeyDown: handleKeyDown} = (({value: value = 0, maxValue: maxValue = 5, allowHalf: allowHalf = !1, readOnly: readOnly = !1, onChange: onChange}) => {
|
|
16360
16377
|
// Determine if component is in controlled mode
|
|
16361
16378
|
const isControlled = void 0 !== onChange, [internalValue, setInternalValue] = React.useState(value), [hoverValue, setHoverValue] = React.useState(null), [focusedIndex, setFocusedIndex] = React.useState(null), currentValue = isControlled ? value : internalValue, handleMouseEnter = React.useCallback((starValue => {
|
|
@@ -16450,7 +16467,7 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
|
|
|
16450
16467
|
return () => {
|
|
16451
16468
|
ratingInstance.current && ratingInstance.current.destroy();
|
|
16452
16469
|
};
|
|
16453
|
-
}), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size,
|
|
16470
|
+
}), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, variant, onChange ]),
|
|
16454
16471
|
// Update vanilla JS implementation when props change
|
|
16455
16472
|
React.useEffect((() => {
|
|
16456
16473
|
useVanillaJS && ratingInstance.current && ratingInstance.current.updateOptions({
|
|
@@ -16459,11 +16476,11 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
|
|
|
16459
16476
|
allowHalf: allowHalf,
|
|
16460
16477
|
readOnly: readOnly,
|
|
16461
16478
|
size: size,
|
|
16462
|
-
|
|
16479
|
+
variant: variant
|
|
16463
16480
|
});
|
|
16464
|
-
}), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size,
|
|
16481
|
+
}), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, variant ]);
|
|
16465
16482
|
// Determine CSS classes
|
|
16466
|
-
const ratingClasses = [ "c-rating", "sm" === size ? RATING.CLASSES.SMALL : "", "lg" === size ? RATING.CLASSES.LARGE : "",
|
|
16483
|
+
const ratingClasses = [ "c-rating", "sm" === size ? RATING.CLASSES.SMALL : "", "lg" === size ? RATING.CLASSES.LARGE : "", variant ? `c-rating--${variant}` : "", className ].filter(Boolean).join(" ");
|
|
16467
16484
|
// If using vanilla JS, just render the container
|
|
16468
16485
|
if (useVanillaJS) return jsxRuntime.jsx("div", {
|
|
16469
16486
|
className: ratingClasses,
|
|
@@ -16487,7 +16504,7 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
|
|
|
16487
16504
|
const stars = [], roundedValue = allowHalf ? Math.floor(2 * effectiveValue) / 2 : Math.round(effectiveValue), componentId = id || `rating-${Math.random().toString(36).substring(2, 9)}`;
|
|
16488
16505
|
for (let i = 1; i <= maxValue; i++) {
|
|
16489
16506
|
// For half-star support
|
|
16490
|
-
const isFullStar = i <= Math.floor(roundedValue), isHalfStar = allowHalf && i - .5 === roundedValue, starClass = [ "c-rating__star", isFullStar ? RATING.CLASSES.FULL : "", isHalfStar ? RATING.CLASSES.HALF : "",
|
|
16507
|
+
const isFullStar = i <= Math.floor(roundedValue), isHalfStar = allowHalf && i - .5 === roundedValue, starClass = [ "c-rating__star", isFullStar ? RATING.CLASSES.FULL : "", isHalfStar ? RATING.CLASSES.HALF : "", variant ? `c-rating__star--${variant}` : "", focusedIndex === i ? "c-rating__star--focused" : "" ].filter(Boolean).join(" "), starId = `${componentId}-star-${i}`;
|
|
16491
16508
|
stars.push(jsxRuntime.jsx("div", {
|
|
16492
16509
|
id: starId,
|
|
16493
16510
|
className: starClass,
|
|
@@ -16567,8 +16584,8 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
|
|
|
16567
16584
|
* <Rating value={3} onChange={handleRatingChange} />
|
|
16568
16585
|
*
|
|
16569
16586
|
* @example
|
|
16570
|
-
* // Read-only with custom
|
|
16571
|
-
* <Rating value={4.5} readOnly
|
|
16587
|
+
* // Read-only with custom variant
|
|
16588
|
+
* <Rating value={4.5} readOnly variant="warning" />
|
|
16572
16589
|
*
|
|
16573
16590
|
* @example
|
|
16574
16591
|
* // With half-star support
|
|
@@ -16642,7 +16659,7 @@ const ProductReview = ({productName: productName, productImage: productImage, in
|
|
|
16642
16659
|
allowHalf: allowHalf,
|
|
16643
16660
|
maxValue: maxRating,
|
|
16644
16661
|
size: "lg",
|
|
16645
|
-
|
|
16662
|
+
variant: ratingColor
|
|
16646
16663
|
}), jsxRuntime.jsx("span", {
|
|
16647
16664
|
className: "c-rating__value",
|
|
16648
16665
|
children: rating > 0 ? rating.toFixed(1) : "Select a rating"
|
|
@@ -16680,7 +16697,7 @@ ProductReview.displayName = "ProductReview";
|
|
|
16680
16697
|
/**
|
|
16681
16698
|
* Hook for managing Progress component state and behavior
|
|
16682
16699
|
*/
|
|
16683
|
-
const Progress = React.memo( React.forwardRef((({value: value, variant: variant = "primary", size: size = "md", className: className = "", style: style, disabled: disabled = !1,
|
|
16700
|
+
const Progress = React.memo( React.forwardRef((({value: value, variant: variant = "primary", size: size = "md", className: className = "", style: style, disabled: disabled = !1, "aria-label": ariaLabel = PROGRESS.DEFAULTS.ARIA_LABEL, glass: glass}, ref) => {
|
|
16684
16701
|
const {progressValue: progressValue, progressStyle: progressStyle, progressClasses: progressClasses} = (({value: value, variant: variant = "primary", size: size = "md", className: className = ""}) => {
|
|
16685
16702
|
// Clamp value between 0 and 100
|
|
16686
16703
|
const progressValue = Math.min(Math.max(value, 0), 100), baseClass = "c-progress";
|
|
@@ -17370,28 +17387,29 @@ Todo.displayName = "Todo";
|
|
|
17370
17387
|
/**
|
|
17371
17388
|
* Toggle component for switching between two states
|
|
17372
17389
|
*/
|
|
17373
|
-
const Toggle = ({
|
|
17374
|
-
const [
|
|
17390
|
+
const Toggle = ({checked: controlledChecked, defaultChecked: defaultChecked = !1, onChange: onChange, disabled: disabled = !1, className: className = "", style: style, glass: glass, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy}) => {
|
|
17391
|
+
const isControlled = void 0 !== controlledChecked, [internalChecked, setInternalChecked] = React.useState(defaultChecked), isChecked = isControlled ? controlledChecked : internalChecked, handleClick = React.useCallback((() => {
|
|
17375
17392
|
if (disabled) return;
|
|
17376
|
-
const
|
|
17377
|
-
|
|
17378
|
-
}, toggleContent = jsxRuntime.jsx("div", {
|
|
17379
|
-
className:
|
|
17393
|
+
const nextChecked = !isChecked;
|
|
17394
|
+
isControlled || setInternalChecked(nextChecked), onChange?.(nextChecked);
|
|
17395
|
+
}), [ disabled, isChecked, isControlled, onChange ]), toggleClass = [ "c-toggle", isChecked && TOGGLE.CLASSES.IS_ON, disabled && "is-disabled", className ].filter(Boolean).join(" "), toggleContent = jsxRuntime.jsx("div", {
|
|
17396
|
+
className: toggleClass,
|
|
17380
17397
|
style: style,
|
|
17381
17398
|
onClick: handleClick,
|
|
17382
17399
|
onKeyDown: e => {
|
|
17383
17400
|
disabled || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), handleClick());
|
|
17384
17401
|
},
|
|
17385
17402
|
role: "switch",
|
|
17386
|
-
"aria-checked":
|
|
17403
|
+
"aria-checked": isChecked,
|
|
17387
17404
|
tabIndex: disabled ? -1 : 0,
|
|
17388
17405
|
"aria-disabled": disabled,
|
|
17406
|
+
"aria-label": ariaLabel,
|
|
17407
|
+
"aria-describedby": ariaDescribedBy,
|
|
17389
17408
|
children: jsxRuntime.jsx("div", {
|
|
17390
17409
|
className: "c-toggle__switch"
|
|
17391
17410
|
})
|
|
17392
17411
|
});
|
|
17393
|
-
|
|
17394
|
-
if (glass) {
|
|
17412
|
+
if (glass) {
|
|
17395
17413
|
// Default glass settings for toggles
|
|
17396
17414
|
const defaultGlassProps = {
|
|
17397
17415
|
displacementScale: 60,
|
|
@@ -17537,7 +17555,7 @@ const Tooltip = React.memo((({content: content, children: children, position: p
|
|
|
17537
17555
|
delay: delay
|
|
17538
17556
|
});
|
|
17539
17557
|
return jsxRuntime.jsxs("div", {
|
|
17540
|
-
className: "u-position-relative u-
|
|
17558
|
+
className: "u-position-relative u-inline-block",
|
|
17541
17559
|
style: style,
|
|
17542
17560
|
...wrapperProps,
|
|
17543
17561
|
children: [ jsxRuntime.jsx("div", {
|
|
@@ -19192,6 +19210,14 @@ const defaultTokens = {
|
|
|
19192
19210
|
ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
|
|
19193
19211
|
/** CSS injection failed */
|
|
19194
19212
|
ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
|
|
19213
|
+
/** Invalid color format */
|
|
19214
|
+
ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
|
|
19215
|
+
/** Missing required token */
|
|
19216
|
+
ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
|
|
19217
|
+
/** Accessibility contrast violation */
|
|
19218
|
+
ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
|
|
19219
|
+
/** Invalid token type */
|
|
19220
|
+
ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
|
|
19195
19221
|
/** Unknown error */
|
|
19196
19222
|
ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
|
|
19197
19223
|
}(ThemeErrorCode || (ThemeErrorCode = {}));
|
|
@@ -19493,27 +19519,6 @@ class ThemeLogger {
|
|
|
19493
19519
|
return Object.keys(registry).length;
|
|
19494
19520
|
}
|
|
19495
19521
|
|
|
19496
|
-
/**
|
|
19497
|
-
* Core Theme Engine
|
|
19498
|
-
*
|
|
19499
|
-
* Core theme creation, composition, and registry functionality
|
|
19500
|
-
*/ var index = Object.freeze({
|
|
19501
|
-
__proto__: null,
|
|
19502
|
-
clearThemes: clearThemes,
|
|
19503
|
-
createTheme: createTheme,
|
|
19504
|
-
createThemeRegistry: createThemeRegistry,
|
|
19505
|
-
deepMerge: deepMerge,
|
|
19506
|
-
extendTheme: extendTheme,
|
|
19507
|
-
getAllThemes: getAllThemes,
|
|
19508
|
-
getTheme: getTheme,
|
|
19509
|
-
getThemeCount: getThemeCount,
|
|
19510
|
-
getThemeIds: getThemeIds,
|
|
19511
|
-
hasTheme: hasTheme,
|
|
19512
|
-
mergeTheme: mergeTheme,
|
|
19513
|
-
registerTheme: registerTheme,
|
|
19514
|
-
unregisterTheme: unregisterTheme
|
|
19515
|
-
});
|
|
19516
|
-
|
|
19517
19522
|
/**
|
|
19518
19523
|
* CSS Injection Utilities
|
|
19519
19524
|
*
|
|
@@ -19684,7 +19689,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
19684
19689
|
// ============================================================================
|
|
19685
19690
|
/**
|
|
19686
19691
|
* Convert hex color to RGB object
|
|
19687
|
-
*/ function hexToRgb(hex) {
|
|
19692
|
+
*/ function hexToRgb$1(hex) {
|
|
19688
19693
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
19689
19694
|
return result ? {
|
|
19690
19695
|
r: parseInt(result[1], 16),
|
|
@@ -19704,7 +19709,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
19704
19709
|
* Calculate relative luminance of a color
|
|
19705
19710
|
* Used for determining contrast ratios
|
|
19706
19711
|
*/ function getLuminance(color) {
|
|
19707
|
-
const rgb = hexToRgb(color);
|
|
19712
|
+
const rgb = hexToRgb$1(color);
|
|
19708
19713
|
if (!rgb) return 0;
|
|
19709
19714
|
const {r: r, g: g, b: b} = rgb, [rs, gs, bs] = [ r ?? 0, g ?? 0, b ?? 0 ].map((c => {
|
|
19710
19715
|
const val = c / 255;
|
|
@@ -19734,7 +19739,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
19734
19739
|
* @param amount - Amount to lighten (0-1), default 0.2
|
|
19735
19740
|
* @returns Lightened hex color
|
|
19736
19741
|
*/ function lighten(color, amount = .2) {
|
|
19737
|
-
const rgb = hexToRgb(color);
|
|
19742
|
+
const rgb = hexToRgb$1(color);
|
|
19738
19743
|
if (!rgb) return color;
|
|
19739
19744
|
const {r: r, g: g, b: b} = rgb, lightenValue = val => Math.min(255, Math.round(val + (255 - val) * amount));
|
|
19740
19745
|
return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
|
|
@@ -19747,7 +19752,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
19747
19752
|
* @param amount - Amount to darken (0-1), default 0.2
|
|
19748
19753
|
* @returns Darkened hex color
|
|
19749
19754
|
*/ function darken(color, amount = .2) {
|
|
19750
|
-
const rgb = hexToRgb(color);
|
|
19755
|
+
const rgb = hexToRgb$1(color);
|
|
19751
19756
|
if (!rgb) return color;
|
|
19752
19757
|
const {r: r, g: g, b: b} = rgb, darkenValue = val => Math.max(0, Math.round(val * (1 - amount)));
|
|
19753
19758
|
return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
|
|
@@ -19760,7 +19765,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
19760
19765
|
* @param opacity - Opacity value (0-1)
|
|
19761
19766
|
* @returns RGBA color string
|
|
19762
19767
|
*/ function alpha(color, opacity) {
|
|
19763
|
-
const rgb = hexToRgb(color);
|
|
19768
|
+
const rgb = hexToRgb$1(color);
|
|
19764
19769
|
if (!rgb) return color;
|
|
19765
19770
|
const {r: r, g: g, b: b} = rgb;
|
|
19766
19771
|
return `rgba(${r}, ${g}, ${b}, ${Math.max(0, Math.min(1, opacity))})`;
|
|
@@ -19779,7 +19784,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
|
|
|
19779
19784
|
*/
|
|
19780
19785
|
function generateColorScale(baseColor, prefix, colorName) {
|
|
19781
19786
|
const vars = {};
|
|
19782
|
-
if (!hexToRgb(baseColor)) return vars;
|
|
19787
|
+
if (!hexToRgb$1(baseColor)) return vars;
|
|
19783
19788
|
// Generate 10-step scale
|
|
19784
19789
|
// Steps 1-5: lighter variations
|
|
19785
19790
|
// Step 6: base color
|
|
@@ -19825,7 +19830,7 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
19825
19830
|
// Main color (flat structure, matches SCSS: --atomix-primary)
|
|
19826
19831
|
vars[`${prefix}-${key}`] = color.main;
|
|
19827
19832
|
// Generate RGB for transparency support (matches SCSS: --atomix-primary-rgb)
|
|
19828
|
-
const rgb = hexToRgb(color.main);
|
|
19833
|
+
const rgb = hexToRgb$1(color.main);
|
|
19829
19834
|
// Generate full color scale (1-10) - matches SCSS: --atomix-primary-1 through --atomix-primary-10
|
|
19830
19835
|
// Only for primary, secondary, error, warning, info, success (not for light/dark)
|
|
19831
19836
|
if (rgb && (vars[`${prefix}-${key}-rgb`] = `${rgb.r}, ${rgb.g}, ${rgb.b}`), "light" !== key && "dark" !== key) {
|
|
@@ -19908,11 +19913,11 @@ function generateCSSVariables(theme, options = {}) {
|
|
|
19908
19913
|
// Heading color (defaults to text primary) - matches SCSS: --atomix-heading-color
|
|
19909
19914
|
palette.text && (vars[`${prefix}-heading-color`] = palette.text.primary), palette.primary) {
|
|
19910
19915
|
vars[`${prefix}-link-color`] = palette.primary.main;
|
|
19911
|
-
const linkRgb = hexToRgb(palette.primary.main);
|
|
19916
|
+
const linkRgb = hexToRgb$1(palette.primary.main);
|
|
19912
19917
|
linkRgb && (vars[`${prefix}-link-color-rgb`] = `${linkRgb.r}, ${linkRgb.g}, ${linkRgb.b}`),
|
|
19913
19918
|
// Link hover color (slightly darker)
|
|
19914
19919
|
vars[`${prefix}-link-hover-color`] = palette.primary.dark || darken(palette.primary.main, .1);
|
|
19915
|
-
const linkHoverRgb = hexToRgb(palette.primary.dark || darken(palette.primary.main, .1));
|
|
19920
|
+
const linkHoverRgb = hexToRgb$1(palette.primary.dark || darken(palette.primary.main, .1));
|
|
19916
19921
|
linkHoverRgb && (vars[`${prefix}-link-hover-color-rgb`] = `${linkHoverRgb.r}, ${linkHoverRgb.g}, ${linkHoverRgb.b}`),
|
|
19917
19922
|
// Link decoration (default: none, matching tokens list)
|
|
19918
19923
|
vars[`${prefix}-link-decoration`] = "none";
|
|
@@ -20370,17 +20375,292 @@ function generateClassName(block, element, modifiers) {
|
|
|
20370
20375
|
ThemeContext.displayName = "ThemeContext";
|
|
20371
20376
|
|
|
20372
20377
|
/**
|
|
20373
|
-
* Theme
|
|
20378
|
+
* Theme Validation Utilities
|
|
20374
20379
|
*
|
|
20375
|
-
*
|
|
20376
|
-
*
|
|
20377
|
-
* - String-based themes (CSS files)
|
|
20378
|
-
* - DesignTokens (dynamic themes)
|
|
20379
|
-
* - Persistence via localStorage
|
|
20380
|
-
*
|
|
20381
|
-
* Falls back to 'default' theme if no configuration is found.
|
|
20380
|
+
* Comprehensive validation utilities for DesignTokens objects.
|
|
20381
|
+
* Includes color format validation, accessibility checks, and required properties verification.
|
|
20382
20382
|
*/
|
|
20383
|
-
const
|
|
20383
|
+
const logger$1 = getLogger(), COLOR_PATTERNS = {
|
|
20384
|
+
/** Hex color: #RGB, #RRGGBB, #RRGGBBAA */
|
|
20385
|
+
hex: /^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/,
|
|
20386
|
+
/** RGB color: rgb(r, g, b) or rgb(r, g, b, a) */
|
|
20387
|
+
rgb: /^rgb\(\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*(?:,\s*([01]?\.?\d+))?\s*\)$/,
|
|
20388
|
+
/** RGBA color: rgba(r, g, b, a) */
|
|
20389
|
+
rgba: /^rgba\(\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*,\s*([01]?\.?\d+)\s*\)$/,
|
|
20390
|
+
/** HSL color: hsl(h, s%, l%) */
|
|
20391
|
+
hsl: /^hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)$/,
|
|
20392
|
+
/** HSLA color: hsla(h, s%, l%, a) */
|
|
20393
|
+
hsla: /^hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,\s*([01]?\.?\d+)\s*\)$/
|
|
20394
|
+
}, REQUIRED_COLOR_TOKENS = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ], REQUIRED_TEXT_EMPHASIS_TOKENS = [ "primary-text-emphasis", "secondary-text-emphasis", "tertiary-text-emphasis", "disabled-text-emphasis" ], ACCESSIBILITY_CHECKS = [ {
|
|
20395
|
+
text: "primary-text-emphasis",
|
|
20396
|
+
background: "primary-bg-subtle",
|
|
20397
|
+
name: "Primary text on subtle background"
|
|
20398
|
+
}, {
|
|
20399
|
+
text: "secondary-text-emphasis",
|
|
20400
|
+
background: "secondary-bg-subtle",
|
|
20401
|
+
name: "Secondary text on subtle background"
|
|
20402
|
+
}, {
|
|
20403
|
+
text: "error-text-emphasis",
|
|
20404
|
+
background: "error-bg-subtle",
|
|
20405
|
+
name: "Error text on subtle background"
|
|
20406
|
+
}, {
|
|
20407
|
+
text: "success-text-emphasis",
|
|
20408
|
+
background: "success-bg-subtle",
|
|
20409
|
+
name: "Success text on subtle background"
|
|
20410
|
+
} ];
|
|
20411
|
+
|
|
20412
|
+
/**
|
|
20413
|
+
* Color format validation patterns
|
|
20414
|
+
*/
|
|
20415
|
+
/**
|
|
20416
|
+
* Parse RGB/RGBA color string to RGB values
|
|
20417
|
+
*/
|
|
20418
|
+
function rgbToRgb(rgb) {
|
|
20419
|
+
const match = rgb.match(COLOR_PATTERNS.rgb) || rgb.match(COLOR_PATTERNS.rgba);
|
|
20420
|
+
if (!match) return null;
|
|
20421
|
+
const r = parseInt(match[1] ?? "0", 10), g = parseInt(match[2] ?? "0", 10), b = parseInt(match[3] ?? "0", 10);
|
|
20422
|
+
// Validate RGB ranges
|
|
20423
|
+
return r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 ? null : {
|
|
20424
|
+
r: r,
|
|
20425
|
+
g: g,
|
|
20426
|
+
b: b
|
|
20427
|
+
};
|
|
20428
|
+
}
|
|
20429
|
+
|
|
20430
|
+
/**
|
|
20431
|
+
* Parse HSL/HSLA color string to RGB values
|
|
20432
|
+
*/ function hslToRgb(hsl) {
|
|
20433
|
+
const match = hsl.match(COLOR_PATTERNS.hsl) || hsl.match(COLOR_PATTERNS.hsla);
|
|
20434
|
+
if (!match) return null;
|
|
20435
|
+
let h = parseInt(match[1] ?? "0", 10) / 360, s = parseInt(match[2] ?? "0", 10) / 100, l = parseInt(match[3] ?? "0", 10) / 100;
|
|
20436
|
+
// Validate HSL ranges
|
|
20437
|
+
if (h < 0 || h > 1 || s < 0 || s > 1 || l < 0 || l > 1) return null;
|
|
20438
|
+
const hue2rgb = (p, q, t) => (t < 0 && (t += 1), t > 1 && (t -= 1), t < 1 / 6 ? p + 6 * (q - p) * t : t < .5 ? q : t < 2 / 3 ? p + (q - p) * (2 / 3 - t) * 6 : p);
|
|
20439
|
+
let r, g, b;
|
|
20440
|
+
if (0 === s) r = g = b = l; // achromatic
|
|
20441
|
+
else {
|
|
20442
|
+
const q = l < .5 ? l * (1 + s) : l + s - l * s, p = 2 * l - q;
|
|
20443
|
+
r = hue2rgb(p, q, h + 1 / 3), g = hue2rgb(p, q, h), b = hue2rgb(p, q, h - 1 / 3);
|
|
20444
|
+
}
|
|
20445
|
+
return {
|
|
20446
|
+
r: Math.round(255 * r),
|
|
20447
|
+
g: Math.round(255 * g),
|
|
20448
|
+
b: Math.round(255 * b)
|
|
20449
|
+
};
|
|
20450
|
+
}
|
|
20451
|
+
|
|
20452
|
+
/**
|
|
20453
|
+
* Convert any valid color format to RGB values
|
|
20454
|
+
*/ function colorToRgb(color) {
|
|
20455
|
+
// Try hex first
|
|
20456
|
+
return COLOR_PATTERNS.hex.test(color) ?
|
|
20457
|
+
/**
|
|
20458
|
+
* Convert hex color to RGB values
|
|
20459
|
+
*/
|
|
20460
|
+
function(hex) {
|
|
20461
|
+
const result = COLOR_PATTERNS.hex.exec(hex);
|
|
20462
|
+
if (!result || !result[1]) return null;
|
|
20463
|
+
const digits = result[1];
|
|
20464
|
+
let r, g, b;
|
|
20465
|
+
switch (digits.length) {
|
|
20466
|
+
case 3:
|
|
20467
|
+
case 4:
|
|
20468
|
+
// #RGBA (ignore alpha)
|
|
20469
|
+
r = parseInt((digits[0] ?? "0") + (digits[0] ?? "0"), 16), g = parseInt((digits[1] ?? "0") + (digits[1] ?? "0"), 16),
|
|
20470
|
+
b = parseInt((digits[2] ?? "0") + (digits[2] ?? "0"), 16);
|
|
20471
|
+
break;
|
|
20472
|
+
|
|
20473
|
+
case 6:
|
|
20474
|
+
case 8:
|
|
20475
|
+
// #RRGGBBAA (ignore alpha)
|
|
20476
|
+
r = parseInt(digits.slice(0, 2), 16), g = parseInt(digits.slice(2, 4), 16), b = parseInt(digits.slice(4, 6), 16);
|
|
20477
|
+
break;
|
|
20478
|
+
|
|
20479
|
+
default:
|
|
20480
|
+
return null;
|
|
20481
|
+
}
|
|
20482
|
+
return {
|
|
20483
|
+
r: r,
|
|
20484
|
+
g: g,
|
|
20485
|
+
b: b
|
|
20486
|
+
};
|
|
20487
|
+
}(color) :
|
|
20488
|
+
// Try RGB/RGBA
|
|
20489
|
+
color.startsWith("rgb") ? rgbToRgb(color) :
|
|
20490
|
+
// Try HSL/HSLA
|
|
20491
|
+
color.startsWith("hsl") ? hslToRgb(color) : null;
|
|
20492
|
+
}
|
|
20493
|
+
|
|
20494
|
+
/**
|
|
20495
|
+
* Validate that a color string is in a valid format (hex, rgb, hsl, etc.)
|
|
20496
|
+
* Includes validation of value ranges for RGB and HSL
|
|
20497
|
+
*/
|
|
20498
|
+
/**
|
|
20499
|
+
* Calculate relative luminance of a color
|
|
20500
|
+
* Based on WCAG guidelines: https://www.w3.org/TR/WCAG20-TECHS/G17.html
|
|
20501
|
+
*/
|
|
20502
|
+
function getRelativeLuminance(r, g, b) {
|
|
20503
|
+
const normalize = val => (val /= 255) <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
|
|
20504
|
+
return .2126 * normalize(r) + .7152 * normalize(g) + .0722 * normalize(b);
|
|
20505
|
+
}
|
|
20506
|
+
|
|
20507
|
+
/**
|
|
20508
|
+
* Calculate contrast ratio between two colors (supports multiple formats)
|
|
20509
|
+
*/
|
|
20510
|
+
/**
|
|
20511
|
+
* Check if contrast ratio meets WCAG AA standards
|
|
20512
|
+
* AA requires 4.5:1 for normal text, 3:1 for large text
|
|
20513
|
+
*/
|
|
20514
|
+
function validateContrastRatio(foreground, background, isLargeText = !1) {
|
|
20515
|
+
const ratio = function(color1, color2) {
|
|
20516
|
+
const rgb1 = colorToRgb(color1), rgb2 = colorToRgb(color2);
|
|
20517
|
+
if (!rgb1 || !rgb2) return null;
|
|
20518
|
+
const lum1 = getRelativeLuminance(rgb1.r, rgb1.g, rgb1.b), lum2 = getRelativeLuminance(rgb2.r, rgb2.g, rgb2.b);
|
|
20519
|
+
return (Math.max(lum1, lum2) + .05) / (Math.min(lum1, lum2) + .05);
|
|
20520
|
+
}(foreground, background);
|
|
20521
|
+
if (null === ratio) return {
|
|
20522
|
+
valid: !1,
|
|
20523
|
+
ratio: 0,
|
|
20524
|
+
requiredRatio: isLargeText ? 3 : 4.5
|
|
20525
|
+
};
|
|
20526
|
+
const requiredRatio = isLargeText ? 3 : 4.5;
|
|
20527
|
+
return {
|
|
20528
|
+
valid: ratio >= requiredRatio,
|
|
20529
|
+
ratio: ratio,
|
|
20530
|
+
requiredRatio: requiredRatio
|
|
20531
|
+
};
|
|
20532
|
+
}
|
|
20533
|
+
|
|
20534
|
+
/**
|
|
20535
|
+
* Validate all color formats in DesignTokens
|
|
20536
|
+
*/
|
|
20537
|
+
/**
|
|
20538
|
+
* Comprehensive validation of DesignTokens
|
|
20539
|
+
*/
|
|
20540
|
+
function validateDesignTokens(tokens, options = {}) {
|
|
20541
|
+
const results = [];
|
|
20542
|
+
options.skipRequiredTokens || results.push(
|
|
20543
|
+
/**
|
|
20544
|
+
* Validate that all required tokens are present
|
|
20545
|
+
*/
|
|
20546
|
+
function(tokens) {
|
|
20547
|
+
const errors = [], warnings = [];
|
|
20548
|
+
// Check required color tokens
|
|
20549
|
+
for (const token of REQUIRED_COLOR_TOKENS) token in tokens || errors.push(`Required color token '${token}' is missing`);
|
|
20550
|
+
// Check required text emphasis tokens
|
|
20551
|
+
for (const token of REQUIRED_TEXT_EMPHASIS_TOKENS) token in tokens || errors.push(`Required text emphasis token '${token}' is missing`);
|
|
20552
|
+
// Check for RGB versions of base colors
|
|
20553
|
+
for (const token of REQUIRED_COLOR_TOKENS) {
|
|
20554
|
+
const rgbToken = `${token}-rgb`;
|
|
20555
|
+
rgbToken in tokens || warnings.push(`RGB version of '${token}' token '${rgbToken}' is missing`);
|
|
20556
|
+
}
|
|
20557
|
+
return {
|
|
20558
|
+
valid: 0 === errors.length,
|
|
20559
|
+
errors: errors,
|
|
20560
|
+
warnings: warnings
|
|
20561
|
+
};
|
|
20562
|
+
}
|
|
20563
|
+
/**
|
|
20564
|
+
* Validate accessibility contrast ratios
|
|
20565
|
+
*/ (tokens)), options.skipColorValidation || results.push(function(tokens) {
|
|
20566
|
+
const errors = [], colorTokenKeys = new Set([
|
|
20567
|
+
// Base colors
|
|
20568
|
+
"primary", "secondary", "success", "info", "warning", "error", "light", "dark",
|
|
20569
|
+
// Text emphasis
|
|
20570
|
+
"primary-text-emphasis", "secondary-text-emphasis", "tertiary-text-emphasis", "disabled-text-emphasis", "invert-text-emphasis", "brand-text-emphasis", "error-text-emphasis", "success-text-emphasis", "warning-text-emphasis", "info-text-emphasis", "light-text-emphasis", "dark-text-emphasis",
|
|
20571
|
+
// Background subtle
|
|
20572
|
+
"primary-bg-subtle", "secondary-bg-subtle", "tertiary-bg-subtle", "invert-bg-subtle", "brand-bg-subtle", "error-bg-subtle", "success-bg-subtle", "warning-bg-subtle", "info-bg-subtle", "light-bg-subtle", "dark-bg-subtle",
|
|
20573
|
+
// Border subtle
|
|
20574
|
+
"primary-border-subtle", "secondary-border-subtle", "success-border-subtle", "error-border-subtle", "warning-border-subtle", "info-border-subtle", "brand-border-subtle", "light-border-subtle", "dark-border-subtle",
|
|
20575
|
+
// Hover states
|
|
20576
|
+
"primary-hover", "secondary-hover", "light-hover", "dark-hover", "error-hover", "success-hover", "warning-hover", "info-hover",
|
|
20577
|
+
// Colors from scales (primary, red, green, blue, yellow)
|
|
20578
|
+
...Array.from({
|
|
20579
|
+
length: 10
|
|
20580
|
+
}, ((_, i) => [ `primary-${i + 1}`, `red-${i + 1}`, `green-${i + 1}`, `blue-${i + 1}`, `yellow-${i + 1}` ])).flat(),
|
|
20581
|
+
// Gray scale
|
|
20582
|
+
...Array.from({
|
|
20583
|
+
length: 10
|
|
20584
|
+
}, ((_, i) => `gray-${i + 1}`)),
|
|
20585
|
+
// Body colors
|
|
20586
|
+
"body-color", "heading-color",
|
|
20587
|
+
// Link colors
|
|
20588
|
+
"link-color", "link-hover-color",
|
|
20589
|
+
// Highlight & code
|
|
20590
|
+
"highlight-bg", "code-color",
|
|
20591
|
+
// Border colors
|
|
20592
|
+
"border-color", "border-color-translucent",
|
|
20593
|
+
// Focus ring
|
|
20594
|
+
"focus-border-color",
|
|
20595
|
+
// Form validation
|
|
20596
|
+
"form-valid-color", "form-valid-border-color", "form-invalid-color", "form-invalid-border-color" ]);
|
|
20597
|
+
for (const key of colorTokenKeys) {
|
|
20598
|
+
if (!(key in tokens)) continue;
|
|
20599
|
+
// Skip if token not present
|
|
20600
|
+
const value = tokens[key];
|
|
20601
|
+
"string" == typeof value ? (color = value,
|
|
20602
|
+
// Check hex first (regex is sufficient)
|
|
20603
|
+
COLOR_PATTERNS.hex.test(color) || (
|
|
20604
|
+
// Check RGB/RGBA with value validation
|
|
20605
|
+
COLOR_PATTERNS.rgb.test(color) || COLOR_PATTERNS.rgba.test(color) ? null !== rgbToRgb(color) :
|
|
20606
|
+
// Check HSL/HSLA with value validation
|
|
20607
|
+
(COLOR_PATTERNS.hsl.test(color) || COLOR_PATTERNS.hsla.test(color)) && null !== hslToRgb(color)) || errors.push(`Token '${key}' has invalid color format: '${value}'`)) : errors.push(`Token '${key}' must be a string, got ${typeof value}`);
|
|
20608
|
+
}
|
|
20609
|
+
var color;
|
|
20610
|
+
return {
|
|
20611
|
+
valid: 0 === errors.length,
|
|
20612
|
+
errors: errors,
|
|
20613
|
+
warnings: []
|
|
20614
|
+
};
|
|
20615
|
+
}(tokens)), options.skipAccessibility || results.push(function(tokens) {
|
|
20616
|
+
const errors = [], warnings = [];
|
|
20617
|
+
for (const check of ACCESSIBILITY_CHECKS) {
|
|
20618
|
+
const textColor = tokens[check.text], bgColor = tokens[check.background];
|
|
20619
|
+
if (!textColor || !bgColor) {
|
|
20620
|
+
warnings.push(`Cannot validate contrast for ${check.name}: missing tokens`);
|
|
20621
|
+
continue;
|
|
20622
|
+
}
|
|
20623
|
+
const contrast = validateContrastRatio(textColor, bgColor);
|
|
20624
|
+
if (!contrast.valid) {
|
|
20625
|
+
const level = 3 === contrast.requiredRatio ? "large text (AA)" : "normal text (AA)";
|
|
20626
|
+
errors.push(`${check.name}: contrast ratio ${contrast.ratio.toFixed(2)}:1 is below required ${contrast.requiredRatio}:1 for ${level}`);
|
|
20627
|
+
}
|
|
20628
|
+
}
|
|
20629
|
+
return {
|
|
20630
|
+
valid: 0 === errors.length,
|
|
20631
|
+
errors: errors,
|
|
20632
|
+
warnings: warnings
|
|
20633
|
+
};
|
|
20634
|
+
}(tokens));
|
|
20635
|
+
const allErrors = results.flatMap((r => r.errors)), allWarnings = results.flatMap((r => r.warnings)), valid = 0 === allErrors.length;
|
|
20636
|
+
// Log validation results
|
|
20637
|
+
return valid ? allWarnings.length > 0 ? logger$1.warn(`DesignTokens validation passed with ${allWarnings.length} warnings`, {
|
|
20638
|
+
warnings: allWarnings
|
|
20639
|
+
}) : logger$1.debug("DesignTokens validation passed") : logger$1.error("DesignTokens validation failed", new Error(`Validation failed with ${allErrors.length} errors and ${allWarnings.length} warnings`), {
|
|
20640
|
+
errors: allErrors,
|
|
20641
|
+
warnings: allWarnings,
|
|
20642
|
+
tokenCount: Object.keys(tokens).length
|
|
20643
|
+
}), {
|
|
20644
|
+
valid: valid,
|
|
20645
|
+
errors: allErrors,
|
|
20646
|
+
warnings: allWarnings
|
|
20647
|
+
};
|
|
20648
|
+
}
|
|
20649
|
+
|
|
20650
|
+
/**
|
|
20651
|
+
* Safely validate and merge partial tokens with defaults
|
|
20652
|
+
*/ function validateAndMergeTokens(partialTokens) {
|
|
20653
|
+
const merged = {
|
|
20654
|
+
...defaultTokens,
|
|
20655
|
+
...partialTokens
|
|
20656
|
+
};
|
|
20657
|
+
return {
|
|
20658
|
+
tokens: merged,
|
|
20659
|
+
validation: validateDesignTokens(merged)
|
|
20660
|
+
};
|
|
20661
|
+
}
|
|
20662
|
+
|
|
20663
|
+
const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes: themes = {}, basePath: basePath = "/themes", cdnPath: cdnPath = null, useMinified: useMinified = !1, storageKey: storageKey = "atomix-theme", dataAttribute: dataAttribute = "data-theme", enablePersistence: enablePersistence = !0, onThemeChange: onThemeChange, onError: onError}) => {
|
|
20384
20664
|
// Store callbacks in refs to avoid recreating when they change
|
|
20385
20665
|
const onThemeChangeRef = React.useRef(onThemeChange), onErrorRef = React.useRef(onError);
|
|
20386
20666
|
// Update ref when callback changes
|
|
@@ -20401,12 +20681,20 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
|
|
|
20401
20681
|
// If defaultTheme is provided, use it
|
|
20402
20682
|
return null != defaultTheme ? defaultTheme : "default";
|
|
20403
20683
|
// Default fallback
|
|
20404
|
-
}), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() =>
|
|
20405
|
-
|
|
20406
|
-
|
|
20684
|
+
}), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
|
|
20685
|
+
// If defaultTheme is DesignTokens, validate and store them
|
|
20686
|
+
if (defaultTheme && "string" != typeof defaultTheme) {
|
|
20687
|
+
const {tokens: tokens, validation: validation} = validateAndMergeTokens(defaultTheme);
|
|
20688
|
+
return validation.valid ? tokens : (logger.warn("Invalid default theme tokens, using defaults", {
|
|
20689
|
+
errors: validation.errors,
|
|
20690
|
+
warnings: validation.warnings
|
|
20691
|
+
}), createTokens({}));
|
|
20692
|
+
}
|
|
20693
|
+
return null;
|
|
20694
|
+
})), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
|
|
20407
20695
|
// Handle initial DesignTokens defaultTheme
|
|
20408
20696
|
React.useEffect((() => {
|
|
20409
|
-
defaultTheme && "string" != typeof defaultTheme && activeTokens && !isServer() && injectCSS$1(createTheme(
|
|
20697
|
+
defaultTheme && "string" != typeof defaultTheme && activeTokens && !isServer() && injectCSS$1(createTheme(activeTokens), "theme-tokens-theme");
|
|
20410
20698
|
}), [ defaultTheme, activeTokens ]), // Run when defaultTheme or activeTokens change
|
|
20411
20699
|
// Apply initial theme attributes to document element
|
|
20412
20700
|
React.useEffect((() => {
|
|
@@ -20436,21 +20724,42 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
|
|
|
20436
20724
|
if ("string" != typeof theme) {
|
|
20437
20725
|
// Check if aborted before processing
|
|
20438
20726
|
if (abortController.signal.aborted) return;
|
|
20439
|
-
//
|
|
20440
|
-
const {
|
|
20441
|
-
|
|
20442
|
-
|
|
20727
|
+
// Validate and merge DesignTokens
|
|
20728
|
+
const {tokens: validatedTokens, validation: validation} = validateAndMergeTokens(theme);
|
|
20729
|
+
if (!validation.valid) {
|
|
20730
|
+
const errorMsg = `Invalid DesignTokens provided: ${validation.errors.join(", ")}`, validationError = new Error(errorMsg);
|
|
20731
|
+
// Default to true
|
|
20732
|
+
if (logger.error("Theme validation failed", validationError, {
|
|
20733
|
+
errors: validation.errors,
|
|
20734
|
+
warnings: validation.warnings
|
|
20735
|
+
}), !1 !== options?.fallbackOnError) {
|
|
20736
|
+
logger.warn("Falling back to default theme due to validation errors");
|
|
20737
|
+
// Use default tokens instead
|
|
20738
|
+
const {tokens: defaultTokens} = validateAndMergeTokens({}), css = createTheme(defaultTokens), themeId = "tokens-theme-fallback";
|
|
20739
|
+
// Check if aborted before state update
|
|
20740
|
+
if (abortController.signal.aborted) return;
|
|
20741
|
+
// Remove any previously loaded theme CSS
|
|
20742
|
+
return removeCSS(`theme-${currentTheme}`),
|
|
20743
|
+
// Inject new theme CSS
|
|
20744
|
+
injectCSS$1(css, `theme-${themeId}`),
|
|
20745
|
+
// Store default tokens
|
|
20746
|
+
setActiveTokens(defaultTokens), setCurrentTheme(themeId), handleThemeChange(defaultTokens),
|
|
20747
|
+
handleError(validationError, themeId), void setIsLoading(!1);
|
|
20748
|
+
}
|
|
20749
|
+
// No fallback, throw the error
|
|
20750
|
+
throw validationError;
|
|
20751
|
+
}
|
|
20752
|
+
// For valid DesignTokens, create CSS and inject it
|
|
20753
|
+
const css = createTheme(validatedTokens), themeId = "tokens-theme";
|
|
20443
20754
|
// Check if aborted after async operation
|
|
20444
20755
|
if (abortController.signal.aborted) return;
|
|
20445
20756
|
// Remove any previously loaded theme CSS
|
|
20446
|
-
|
|
20447
|
-
// Inject new theme CSS
|
|
20448
|
-
injectCSS$1(css, `theme-${themeId}`);
|
|
20449
|
-
// Store tokens for reference
|
|
20450
|
-
const fullTokens = createTokens(theme);
|
|
20757
|
+
// Store validated tokens for reference
|
|
20451
20758
|
// Check if aborted before state update
|
|
20452
|
-
|
|
20453
|
-
|
|
20759
|
+
if (removeCSS(`theme-${currentTheme}`),
|
|
20760
|
+
// Inject new theme CSS
|
|
20761
|
+
injectCSS$1(css, `theme-${themeId}`), abortController.signal.aborted) return;
|
|
20762
|
+
return setActiveTokens(validatedTokens), setCurrentTheme(themeId), handleThemeChange(validatedTokens),
|
|
20454
20763
|
void setIsLoading(!1);
|
|
20455
20764
|
}
|
|
20456
20765
|
// If it's a string theme name, load the associated CSS
|
|
@@ -20465,32 +20774,35 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
|
|
|
20465
20774
|
// If previous load failed, continue with new load
|
|
20466
20775
|
}
|
|
20467
20776
|
// Load CSS theme
|
|
20468
|
-
const themeLoadPromise = new Promise((
|
|
20469
|
-
|
|
20470
|
-
|
|
20471
|
-
|
|
20472
|
-
if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
|
|
20473
|
-
{
|
|
20474
|
-
// Build CSS path using utility function
|
|
20475
|
-
const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
|
|
20777
|
+
const themeLoadPromise = new Promise(((resolve, reject) => {
|
|
20778
|
+
// Start the async operation
|
|
20779
|
+
(async () => {
|
|
20780
|
+
try {
|
|
20476
20781
|
// Check if aborted
|
|
20477
|
-
|
|
20478
|
-
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
|
|
20483
|
-
|
|
20484
|
-
|
|
20485
|
-
|
|
20486
|
-
|
|
20782
|
+
if (abortController.signal.aborted) return void resolve();
|
|
20783
|
+
if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
|
|
20784
|
+
{
|
|
20785
|
+
// Build CSS path using utility function
|
|
20786
|
+
const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
|
|
20787
|
+
// Check if aborted
|
|
20788
|
+
if (abortController.signal.aborted) return void resolve();
|
|
20789
|
+
// Load CSS file (using loadThemeCSS from domUtils)
|
|
20790
|
+
const {loadThemeCSS: loadThemeCSS} = await Promise.resolve().then((function() {
|
|
20791
|
+
return domUtils;
|
|
20792
|
+
}));
|
|
20793
|
+
// Check if aborted after async operation
|
|
20794
|
+
if (await loadThemeCSS(cssPath, `theme-${theme}`), abortController.signal.aborted) return void resolve();
|
|
20795
|
+
// Remove any previously loaded theme CSS
|
|
20796
|
+
removeCSS(`theme-${String(currentTheme)}`), loadedThemesRef.current.add(theme),
|
|
20797
|
+
setCurrentTheme(theme), setActiveTokens(null), handleThemeChange(theme), resolve();
|
|
20798
|
+
}
|
|
20799
|
+
} catch (err) {
|
|
20800
|
+
// Don't reject if aborted
|
|
20801
|
+
if (abortController.signal.aborted) return void resolve();
|
|
20802
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
20803
|
+
setError(error), handleError(error, String(theme)), reject(error);
|
|
20487
20804
|
}
|
|
20488
|
-
}
|
|
20489
|
-
// Don't reject if aborted
|
|
20490
|
-
if (abortController.signal.aborted) return void resolve();
|
|
20491
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
20492
|
-
setError(error), handleError(error, String(theme)), reject(error);
|
|
20493
|
-
}
|
|
20805
|
+
})();
|
|
20494
20806
|
}));
|
|
20495
20807
|
themePromisesRef.current[theme] = themeLoadPromise;
|
|
20496
20808
|
try {
|
|
@@ -20555,6 +20867,17 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
|
|
|
20555
20867
|
});
|
|
20556
20868
|
};
|
|
20557
20869
|
|
|
20870
|
+
/**
|
|
20871
|
+
* Theme Provider
|
|
20872
|
+
*
|
|
20873
|
+
* React context provider for theme management with separated concerns.
|
|
20874
|
+
* Simplified version focusing on core functionality:
|
|
20875
|
+
* - String-based themes (CSS files)
|
|
20876
|
+
* - DesignTokens (dynamic themes)
|
|
20877
|
+
* - Persistence via localStorage
|
|
20878
|
+
*
|
|
20879
|
+
* Falls back to 'default' theme if no configuration is found.
|
|
20880
|
+
*/
|
|
20558
20881
|
/**
|
|
20559
20882
|
* useTheme Hook
|
|
20560
20883
|
*
|
|
@@ -20580,7 +20903,8 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
|
|
|
20580
20903
|
* );
|
|
20581
20904
|
* }
|
|
20582
20905
|
* ```
|
|
20583
|
-
*/
|
|
20906
|
+
*/
|
|
20907
|
+
function useTheme() {
|
|
20584
20908
|
const context = React.useContext(ThemeContext);
|
|
20585
20909
|
if (!context) throw new Error("useTheme must be used within a ThemeProvider");
|
|
20586
20910
|
return {
|
|
@@ -22597,8 +22921,8 @@ function createPaletteColor(color) {
|
|
|
22597
22921
|
* @returns Complete theme object
|
|
22598
22922
|
*/
|
|
22599
22923
|
function createThemeObject(...options) {
|
|
22600
|
-
// Merge all options
|
|
22601
|
-
const mergedOptions = _reduceInstanceProperty(options).call(options, ((acc, option) => deepMerge(acc, option)), {}), palette = {
|
|
22924
|
+
// Merge all options by spreading them into a single object
|
|
22925
|
+
const mergedOptions = _reduceInstanceProperty(options).call(options, ((acc, option) => deepMerge(acc, option || {})), {}), palette = {
|
|
22602
22926
|
primary: createPaletteColor(mergedOptions.palette?.primary || DEFAULT_PALETTE.primary),
|
|
22603
22927
|
secondary: createPaletteColor(mergedOptions.palette?.secondary || DEFAULT_PALETTE.secondary),
|
|
22604
22928
|
error: createPaletteColor(mergedOptions.palette?.error || DEFAULT_PALETTE.error),
|
|
@@ -22783,43 +23107,45 @@ function createThemeObject(...options) {
|
|
|
22783
23107
|
|
|
22784
23108
|
case "hsl":
|
|
22785
23109
|
case "hsla":
|
|
22786
|
-
|
|
22787
|
-
|
|
22788
|
-
|
|
23110
|
+
{
|
|
23111
|
+
// Convert RGB to HSL (simplified)
|
|
23112
|
+
const hsl =
|
|
23113
|
+
/**
|
|
22789
23114
|
* Convert RGB to HSL
|
|
22790
23115
|
*/
|
|
22791
|
-
|
|
22792
|
-
|
|
22793
|
-
|
|
22794
|
-
|
|
22795
|
-
|
|
22796
|
-
|
|
22797
|
-
|
|
22798
|
-
|
|
22799
|
-
|
|
22800
|
-
|
|
22801
|
-
|
|
22802
|
-
|
|
22803
|
-
|
|
22804
|
-
|
|
22805
|
-
|
|
22806
|
-
|
|
22807
|
-
|
|
22808
|
-
|
|
23116
|
+
function(r, g, b) {
|
|
23117
|
+
r /= 255, g /= 255, b /= 255;
|
|
23118
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
23119
|
+
let h = 0, s = 0;
|
|
23120
|
+
const l = (max + min) / 2;
|
|
23121
|
+
if (max !== min) {
|
|
23122
|
+
const d = max - min;
|
|
23123
|
+
switch (s = l > .5 ? d / (2 - max - min) : d / (max + min), max) {
|
|
23124
|
+
case r:
|
|
23125
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
23126
|
+
break;
|
|
23127
|
+
|
|
23128
|
+
case g:
|
|
23129
|
+
h = ((b - r) / d + 2) / 6;
|
|
23130
|
+
break;
|
|
23131
|
+
|
|
23132
|
+
case b:
|
|
23133
|
+
h = ((r - g) / d + 4) / 6;
|
|
23134
|
+
}
|
|
22809
23135
|
}
|
|
23136
|
+
return {
|
|
23137
|
+
h: Math.round(360 * h),
|
|
23138
|
+
s: Math.round(100 * s),
|
|
23139
|
+
l: Math.round(100 * l)
|
|
23140
|
+
};
|
|
22810
23141
|
}
|
|
22811
|
-
|
|
22812
|
-
h: Math.round(360 * h),
|
|
22813
|
-
s: Math.round(100 * s),
|
|
22814
|
-
l: Math.round(100 * l)
|
|
22815
|
-
};
|
|
22816
|
-
}
|
|
22817
|
-
/**
|
|
23142
|
+
/**
|
|
22818
23143
|
* Theme Live Editor Component
|
|
22819
23144
|
*
|
|
22820
23145
|
* Allows live editing of theme properties with instant preview
|
|
22821
23146
|
*/ (r, g, b);
|
|
22822
|
-
|
|
23147
|
+
return "hsl" === format ? `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)` : `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${a})`;
|
|
23148
|
+
}
|
|
22823
23149
|
|
|
22824
23150
|
default:
|
|
22825
23151
|
return color;
|
|
@@ -23145,8 +23471,312 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
|
|
|
23145
23471
|
children: "\n .atomix-theme-live-editor {\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n background: white;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n .editor-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 24px;\n border-bottom: 1px solid #e0e0e0;\n background: #f5f5f5;\n border-radius: 8px 8px 0 0;\n }\n\n .editor-header h2 {\n margin: 0;\n font-size: 20px;\n color: #333;\n }\n\n .editor-controls {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .history-controls,\n .mode-controls,\n .action-controls {\n display: flex;\n gap: 8px;\n }\n\n .history-button,\n .mode-button,\n .export-button,\n .copy-button {\n padding: 8px 16px;\n border: 1px solid #e0e0e0;\n background: white;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s;\n }\n\n .history-button:hover:not(:disabled),\n .mode-button:hover,\n .export-button:hover,\n .copy-button:hover {\n background: #f5f5f5;\n }\n\n .history-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .mode-button.active {\n background: #2196f3;\n color: white;\n border-color: #2196f3;\n }\n\n .export-button {\n background: #4caf50;\n color: white;\n border-color: #4caf50;\n }\n\n .copy-button {\n background: #ff9800;\n color: white;\n border-color: #ff9800;\n }\n\n .editor-content {\n display: flex;\n position: relative;\n min-height: 600px;\n }\n\n .editor-panel,\n .preview-panel {\n overflow-y: auto;\n padding: 24px;\n }\n\n .resizer {\n width: 4px;\n background: #e0e0e0;\n cursor: col-resize;\n position: relative;\n flex-shrink: 0;\n transition: background 0.2s;\n }\n\n .resizer:hover,\n .resizer.resizing {\n background: #2196f3;\n }\n\n .resizer::before {\n content: '';\n position: absolute;\n left: -2px;\n right: -2px;\n top: 0;\n bottom: 0;\n }\n\n .editor-panel h3,\n .preview-panel h3 {\n margin: 0 0 16px 0;\n font-size: 16px;\n color: #333;\n border-bottom: 2px solid #2196f3;\n padding-bottom: 8px;\n }\n\n .visual-editor {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n .editor-section {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .color-format-selector {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n }\n\n .color-format-selector label {\n font-size: 14px;\n font-weight: 500;\n color: #666;\n }\n\n .color-format-selector select {\n padding: 6px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 14px;\n background: white;\n cursor: pointer;\n }\n\n .editor-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .editor-field label {\n font-size: 14px;\n font-weight: 500;\n color: #666;\n }\n\n .color-input-group {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .color-input-group input[type=\"color\"] {\n width: 50px;\n height: 40px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n cursor: pointer;\n }\n\n .color-input-group input[type=\"text\"],\n .editor-field input[type=\"text\"],\n .editor-field input[type=\"number\"] {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 14px;\n font-family: 'Monaco', 'Menlo', monospace;\n }\n\n .json-editor {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .json-editor textarea {\n flex: 1;\n padding: 16px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-family: 'Monaco', 'Menlo', monospace;\n font-size: 12px;\n line-height: 1.5;\n resize: none;\n }\n\n .error-message {\n padding: 12px;\n background: #ffebee;\n color: #d32f2f;\n border-radius: 4px;\n margin-top: 8px;\n font-size: 14px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .error-dismiss {\n background: none;\n border: none;\n color: #d32f2f;\n font-size: 20px;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .error-dismiss:hover {\n background: rgba(211, 47, 47, 0.1);\n border-radius: 50%;\n }\n\n .preview-panel {\n border-left: 1px solid #e0e0e0;\n }\n "
|
|
23146
23472
|
}) ]
|
|
23147
23473
|
});
|
|
23474
|
+
}, DesignTokensCustomizer = ({initialTokens: initialTokens = {}, onTokensChange: onTokensChange, className: className, style: style}) => {
|
|
23475
|
+
// Current tokens state
|
|
23476
|
+
const [tokens, setTokens] = React.useState((() => createTokens(initialTokens))), [colorFormat, setColorFormat] = React.useState("hex"), [activeCategory, setActiveCategory] = React.useState("colors"), [cssPreview, setCssPreview] = React.useState("");
|
|
23477
|
+
// Generate CSS when tokens change
|
|
23478
|
+
React.useEffect((() => {
|
|
23479
|
+
const css = createTheme(tokens, {
|
|
23480
|
+
selector: ":root",
|
|
23481
|
+
prefix: "atomix-preview"
|
|
23482
|
+
});
|
|
23483
|
+
setCssPreview(css), onTokensChange?.(tokens);
|
|
23484
|
+
}), [ tokens, onTokensChange ]);
|
|
23485
|
+
// Create theme object for preview
|
|
23486
|
+
const previewTheme = React.useMemo((() => createThemeObject({
|
|
23487
|
+
palette: {
|
|
23488
|
+
primary: {
|
|
23489
|
+
main: tokens.primary
|
|
23490
|
+
},
|
|
23491
|
+
secondary: {
|
|
23492
|
+
main: tokens.secondary
|
|
23493
|
+
},
|
|
23494
|
+
error: {
|
|
23495
|
+
main: tokens.error
|
|
23496
|
+
},
|
|
23497
|
+
warning: {
|
|
23498
|
+
main: tokens.warning
|
|
23499
|
+
},
|
|
23500
|
+
info: {
|
|
23501
|
+
main: tokens.info
|
|
23502
|
+
},
|
|
23503
|
+
success: {
|
|
23504
|
+
main: tokens.success
|
|
23505
|
+
},
|
|
23506
|
+
background: {
|
|
23507
|
+
default: "#ffffff",
|
|
23508
|
+
subtle: tokens["secondary-bg-subtle"] || "#f3f4f6"
|
|
23509
|
+
},
|
|
23510
|
+
text: {
|
|
23511
|
+
primary: tokens["primary-text-emphasis"] || "#111827",
|
|
23512
|
+
secondary: tokens["secondary-text-emphasis"] || "#374151",
|
|
23513
|
+
disabled: tokens["disabled-text-emphasis"] || "#9ca3af"
|
|
23514
|
+
}
|
|
23515
|
+
},
|
|
23516
|
+
typography: {
|
|
23517
|
+
fontFamily: tokens["body-font-family"] || '"Roboto", sans-serif',
|
|
23518
|
+
fontSize: parseInt(tokens["body-font-size"] || "16")
|
|
23519
|
+
},
|
|
23520
|
+
spacing: factor => .25 * factor + "rem"
|
|
23521
|
+
})), [ tokens ]), updateToken = React.useCallback(((key, value) => {
|
|
23522
|
+
setTokens((prev => ({
|
|
23523
|
+
...prev,
|
|
23524
|
+
[key]: value
|
|
23525
|
+
})));
|
|
23526
|
+
}), []), convertColorFormat = React.useCallback(((color, format) => {
|
|
23527
|
+
// Parse current color
|
|
23528
|
+
const temp = document.createElement("div");
|
|
23529
|
+
temp.style.color = color, document.body.appendChild(temp);
|
|
23530
|
+
const computed = window.getComputedStyle(temp).color;
|
|
23531
|
+
document.body.removeChild(temp);
|
|
23532
|
+
const rgbMatch = computed.match(/\d+/g);
|
|
23533
|
+
if (!rgbMatch || rgbMatch.length < 3) return color;
|
|
23534
|
+
const r = parseInt(rgbMatch[0] || "0", 10), g = parseInt(rgbMatch[1] || "0", 10), b = parseInt(rgbMatch[2] || "0", 10), a = rgbMatch[3] ? parseFloat(rgbMatch[3]) : 1;
|
|
23535
|
+
switch (format) {
|
|
23536
|
+
case "hex":
|
|
23537
|
+
return `#${[ r, g, b ].map((x => x.toString(16).padStart(2, "0"))).join("")}`;
|
|
23538
|
+
|
|
23539
|
+
case "rgb":
|
|
23540
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
23541
|
+
|
|
23542
|
+
case "rgba":
|
|
23543
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
23544
|
+
|
|
23545
|
+
case "hsl":
|
|
23546
|
+
case "hsla":
|
|
23547
|
+
{
|
|
23548
|
+
const hsl =
|
|
23549
|
+
// RGB to HSL conversion
|
|
23550
|
+
function(r, g, b) {
|
|
23551
|
+
r /= 255, g /= 255, b /= 255;
|
|
23552
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
23553
|
+
let h = 0, s = 0;
|
|
23554
|
+
const l = (max + min) / 2;
|
|
23555
|
+
if (max !== min) {
|
|
23556
|
+
const d = max - min;
|
|
23557
|
+
switch (s = l > .5 ? d / (2 - max - min) : d / (max + min), max) {
|
|
23558
|
+
case r:
|
|
23559
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
23560
|
+
break;
|
|
23561
|
+
|
|
23562
|
+
case g:
|
|
23563
|
+
h = ((b - r) / d + 2) / 6;
|
|
23564
|
+
break;
|
|
23565
|
+
|
|
23566
|
+
case b:
|
|
23567
|
+
h = ((r - g) / d + 4) / 6;
|
|
23568
|
+
}
|
|
23569
|
+
}
|
|
23570
|
+
return {
|
|
23571
|
+
h: Math.round(360 * h),
|
|
23572
|
+
s: Math.round(100 * s),
|
|
23573
|
+
l: Math.round(100 * l)
|
|
23574
|
+
};
|
|
23575
|
+
}
|
|
23576
|
+
// Export functions
|
|
23577
|
+
(r, g, b);
|
|
23578
|
+
return "hsl" === format ? `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)` : `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${a})`;
|
|
23579
|
+
}
|
|
23580
|
+
|
|
23581
|
+
default:
|
|
23582
|
+
return color;
|
|
23583
|
+
}
|
|
23584
|
+
}), []), exportTokens = React.useCallback((() => {
|
|
23585
|
+
const dataStr = JSON.stringify(tokens, null, 2), dataUri = "data:application/json;charset=utf-8," + encodeURIComponent(dataStr), linkElement = document.createElement("a");
|
|
23586
|
+
linkElement.setAttribute("href", dataUri), linkElement.setAttribute("download", "design-tokens.json"),
|
|
23587
|
+
linkElement.click();
|
|
23588
|
+
}), [ tokens ]), exportTheme = React.useCallback((() => {
|
|
23589
|
+
const themeCss = createTheme(tokens), dataUri = "data:text/css;charset=utf-8," + encodeURIComponent(themeCss), linkElement = document.createElement("a");
|
|
23590
|
+
linkElement.setAttribute("href", dataUri), linkElement.setAttribute("download", "theme.css"),
|
|
23591
|
+
linkElement.click();
|
|
23592
|
+
}), [ tokens ]), copyToClipboard = React.useCallback((() => {
|
|
23593
|
+
navigator.clipboard?.writeText(JSON.stringify(tokens, null, 2));
|
|
23594
|
+
}), [ tokens ]), resetToDefaults = React.useCallback((() => {
|
|
23595
|
+
setTokens(defaultTokens);
|
|
23596
|
+
}), []), loadTokensFromFile = React.useCallback((event => {
|
|
23597
|
+
const file = event.target.files?.[0];
|
|
23598
|
+
if (!file) return;
|
|
23599
|
+
const reader = new FileReader;
|
|
23600
|
+
reader.onload = e => {
|
|
23601
|
+
try {
|
|
23602
|
+
const content = e.target?.result, mergedTokens = createTokens(JSON.parse(content));
|
|
23603
|
+
setTokens(mergedTokens);
|
|
23604
|
+
} catch (error) {
|
|
23605
|
+
console.error("Failed to load tokens:", error), alert("Invalid JSON file. Please select a valid design tokens JSON file.");
|
|
23606
|
+
}
|
|
23607
|
+
}, reader.readAsText(file);
|
|
23608
|
+
}), []), tokenCategories = {
|
|
23609
|
+
colors: {
|
|
23610
|
+
label: "Colors",
|
|
23611
|
+
tokens: [
|
|
23612
|
+
// Base colors
|
|
23613
|
+
"primary", "secondary", "success", "info", "warning", "error", "light", "dark",
|
|
23614
|
+
// RGB versions
|
|
23615
|
+
"primary-rgb", "secondary-rgb", "success-rgb", "info-rgb", "warning-rgb", "error-rgb", "light-rgb", "dark-rgb",
|
|
23616
|
+
// Gray scale
|
|
23617
|
+
"gray-1", "gray-2", "gray-3", "gray-4", "gray-5", "gray-6", "gray-7", "gray-8", "gray-9", "gray-10",
|
|
23618
|
+
// Primary scale
|
|
23619
|
+
"primary-1", "primary-2", "primary-3", "primary-4", "primary-5", "primary-6", "primary-7", "primary-8", "primary-9", "primary-10",
|
|
23620
|
+
// Text emphasis
|
|
23621
|
+
"primary-text-emphasis", "secondary-text-emphasis", "tertiary-text-emphasis", "disabled-text-emphasis", "invert-text-emphasis", "brand-text-emphasis", "error-text-emphasis", "success-text-emphasis", "warning-text-emphasis", "info-text-emphasis", "light-text-emphasis", "dark-text-emphasis",
|
|
23622
|
+
// Background subtle
|
|
23623
|
+
"primary-bg-subtle", "secondary-bg-subtle", "tertiary-bg-subtle", "invert-bg-subtle", "brand-bg-subtle", "error-bg-subtle", "success-bg-subtle", "warning-bg-subtle", "info-bg-subtle", "light-bg-subtle", "dark-bg-subtle",
|
|
23624
|
+
// Border subtle
|
|
23625
|
+
"primary-border-subtle", "secondary-border-subtle", "success-border-subtle", "error-border-subtle", "warning-border-subtle", "info-border-subtle", "brand-border-subtle", "light-border-subtle", "dark-border-subtle",
|
|
23626
|
+
// Hover states
|
|
23627
|
+
"primary-hover", "secondary-hover", "light-hover", "dark-hover", "error-hover", "success-hover", "warning-hover", "info-hover",
|
|
23628
|
+
// Gradients
|
|
23629
|
+
"primary-gradient", "secondary-gradient", "light-gradient", "dark-gradient", "success-gradient", "info-gradient", "warning-gradient", "error-gradient", "gradient" ]
|
|
23630
|
+
},
|
|
23631
|
+
typography: {
|
|
23632
|
+
label: "Typography",
|
|
23633
|
+
tokens: [ "font-sans-serif", "font-monospace", "body-font-family", "body-font-size", "body-font-weight", "body-line-height", "body-color", "body-bg", "heading-color", "font-size-xl", "font-size-2xl", "display-1", "font-weight-light", "font-weight-normal", "font-weight-medium", "font-weight-semibold", "font-weight-bold", "font-weight-heavy", "font-weight-black", "line-height-base", "line-height-sm", "line-height-lg", "letter-spacing-h1", "letter-spacing-h2", "letter-spacing-h3", "letter-spacing-h4", "letter-spacing-h5", "letter-spacing-h6", "link-color", "link-color-rgb", "link-decoration", "link-hover-color", "link-hover-color-rgb", "highlight-bg", "code-color" ]
|
|
23634
|
+
},
|
|
23635
|
+
spacing: {
|
|
23636
|
+
label: "Spacing",
|
|
23637
|
+
tokens: [ "spacing-0", "spacing-1", "spacing-px-6", "spacing-2", "spacing-px-10", "spacing-3", "spacing-px-14", "spacing-4", "spacing-5", "spacing-px-22", "spacing-6", "spacing-7", "spacing-px-30", "spacing-8", "spacing-9", "spacing-10", "spacing-11", "spacing-12", "spacing-14", "spacing-16", "spacing-20", "spacing-24", "spacing-28", "spacing-32", "spacing-36", "spacing-40", "spacing-44", "spacing-48", "spacing-52", "spacing-56", "spacing-60", "spacing-64", "spacing-72", "spacing-80", "spacing-90", "spacing-200" ]
|
|
23638
|
+
},
|
|
23639
|
+
shadows: {
|
|
23640
|
+
label: "Shadows",
|
|
23641
|
+
tokens: [ "box-shadow", "box-shadow-xs", "box-shadow-sm", "box-shadow-lg", "box-shadow-xl", "box-shadow-inset" ]
|
|
23642
|
+
},
|
|
23643
|
+
borders: {
|
|
23644
|
+
label: "Borders",
|
|
23645
|
+
tokens: [ "border-width", "border-style", "border-color", "border-color-translucent", "border-radius", "border-radius-sm", "border-radius-lg", "border-radius-xl", "border-radius-xxl", "border-radius-2xl", "border-radius-3xl", "border-radius-4xl", "border-radius-pill", "focus-border-color", "focus-ring-width", "focus-ring-offset", "focus-ring-opacity", "form-valid-color", "form-valid-border-color", "form-invalid-color", "form-invalid-border-color" ]
|
|
23646
|
+
},
|
|
23647
|
+
transitions: {
|
|
23648
|
+
label: "Transitions",
|
|
23649
|
+
tokens: [ "transition-duration-fast", "transition-duration-base", "transition-duration-slow", "transition-duration-slower", "easing-base", "easing-ease-in-out", "easing-ease-out", "easing-ease-in", "easing-ease-linear", "transition-fast", "transition-base", "transition-slow" ]
|
|
23650
|
+
},
|
|
23651
|
+
zindex: {
|
|
23652
|
+
label: "Z-Index",
|
|
23653
|
+
tokens: [ "z-n1", "z-0", "z-1", "z-2", "z-3", "z-4", "z-5", "z-dropdown", "z-sticky", "z-fixed", "z-modal", "z-popover", "z-tooltip", "z-drawer" ]
|
|
23654
|
+
},
|
|
23655
|
+
breakpoints: {
|
|
23656
|
+
label: "Breakpoints",
|
|
23657
|
+
tokens: [ "breakpoint-xs", "breakpoint-sm", "breakpoint-md", "breakpoint-lg", "breakpoint-xl", "breakpoint-xxl" ]
|
|
23658
|
+
}
|
|
23659
|
+
};
|
|
23660
|
+
// Update token value
|
|
23661
|
+
return jsxRuntime.jsxs("div", {
|
|
23662
|
+
className: `design-tokens-customizer ${className || ""}`,
|
|
23663
|
+
style: style,
|
|
23664
|
+
children: [ jsxRuntime.jsxs("div", {
|
|
23665
|
+
className: "customizer-header",
|
|
23666
|
+
children: [ jsxRuntime.jsx("h2", {
|
|
23667
|
+
children: "Interactive Theme Customizer"
|
|
23668
|
+
}), jsxRuntime.jsxs("div", {
|
|
23669
|
+
className: "customizer-controls",
|
|
23670
|
+
children: [ jsxRuntime.jsxs("select", {
|
|
23671
|
+
value: colorFormat,
|
|
23672
|
+
onChange: e => setColorFormat(e.target.value),
|
|
23673
|
+
children: [ jsxRuntime.jsx("option", {
|
|
23674
|
+
value: "hex",
|
|
23675
|
+
children: "HEX"
|
|
23676
|
+
}), jsxRuntime.jsx("option", {
|
|
23677
|
+
value: "rgb",
|
|
23678
|
+
children: "RGB"
|
|
23679
|
+
}), jsxRuntime.jsx("option", {
|
|
23680
|
+
value: "rgba",
|
|
23681
|
+
children: "RGBA"
|
|
23682
|
+
}), jsxRuntime.jsx("option", {
|
|
23683
|
+
value: "hsl",
|
|
23684
|
+
children: "HSL"
|
|
23685
|
+
}), jsxRuntime.jsx("option", {
|
|
23686
|
+
value: "hsla",
|
|
23687
|
+
children: "HSLA"
|
|
23688
|
+
}) ]
|
|
23689
|
+
}), jsxRuntime.jsx("button", {
|
|
23690
|
+
onClick: resetToDefaults,
|
|
23691
|
+
children: "Reset to Defaults"
|
|
23692
|
+
}), jsxRuntime.jsxs("label", {
|
|
23693
|
+
className: "file-input-button",
|
|
23694
|
+
children: [ "Load Tokens", jsxRuntime.jsx("input", {
|
|
23695
|
+
type: "file",
|
|
23696
|
+
accept: ".json",
|
|
23697
|
+
onChange: loadTokensFromFile,
|
|
23698
|
+
style: {
|
|
23699
|
+
display: "none"
|
|
23700
|
+
}
|
|
23701
|
+
}) ]
|
|
23702
|
+
}), jsxRuntime.jsx("button", {
|
|
23703
|
+
onClick: copyToClipboard,
|
|
23704
|
+
children: "Copy Tokens"
|
|
23705
|
+
}), jsxRuntime.jsx("button", {
|
|
23706
|
+
onClick: exportTokens,
|
|
23707
|
+
children: "Export Tokens"
|
|
23708
|
+
}), jsxRuntime.jsx("button", {
|
|
23709
|
+
onClick: exportTheme,
|
|
23710
|
+
children: "Export Theme CSS"
|
|
23711
|
+
}) ]
|
|
23712
|
+
}) ]
|
|
23713
|
+
}), jsxRuntime.jsxs("div", {
|
|
23714
|
+
className: "customizer-content",
|
|
23715
|
+
children: [ jsxRuntime.jsx("div", {
|
|
23716
|
+
className: "customizer-sidebar",
|
|
23717
|
+
children: Object.entries(tokenCategories).map((([key, category]) => jsxRuntime.jsx("button", {
|
|
23718
|
+
className: "category-button " + (activeCategory === key ? "active" : ""),
|
|
23719
|
+
onClick: () => setActiveCategory(key),
|
|
23720
|
+
children: category.label
|
|
23721
|
+
}, key)))
|
|
23722
|
+
}), jsxRuntime.jsxs("div", {
|
|
23723
|
+
className: "customizer-editor",
|
|
23724
|
+
children: [ jsxRuntime.jsx("h3", {
|
|
23725
|
+
children: tokenCategories[activeCategory].label
|
|
23726
|
+
}), jsxRuntime.jsx("div", {
|
|
23727
|
+
className: "tokens-grid",
|
|
23728
|
+
children: tokenCategories[activeCategory].tokens.map((tokenKey => {
|
|
23729
|
+
var _context;
|
|
23730
|
+
const value = tokens[tokenKey] || "", isColor = _includesInstanceProperty(tokenKey).call(tokenKey, "color") || _includesInstanceProperty(tokenKey).call(tokenKey, "bg") || _includesInstanceProperty(tokenKey).call(tokenKey, "gradient") || _includesInstanceProperty(_context = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context, tokenKey) || tokenKey.match(/^(gray|primary|red|green|blue|yellow)-\d+$/);
|
|
23731
|
+
return jsxRuntime.jsxs("div", {
|
|
23732
|
+
className: "token-item",
|
|
23733
|
+
children: [ jsxRuntime.jsx("label", {
|
|
23734
|
+
children: tokenKey
|
|
23735
|
+
}), isColor ? jsxRuntime.jsxs("div", {
|
|
23736
|
+
className: "color-input-group",
|
|
23737
|
+
children: [ jsxRuntime.jsx("input", {
|
|
23738
|
+
type: "color",
|
|
23739
|
+
value: value.startsWith("#") ? value : convertColorFormat(value, "hex"),
|
|
23740
|
+
onChange: e => updateToken(tokenKey, e.target.value)
|
|
23741
|
+
}), jsxRuntime.jsx("input", {
|
|
23742
|
+
type: "text",
|
|
23743
|
+
value: convertColorFormat(value, colorFormat),
|
|
23744
|
+
onChange: e => {
|
|
23745
|
+
const converted = convertColorFormat(e.target.value, "hex");
|
|
23746
|
+
updateToken(tokenKey, converted);
|
|
23747
|
+
}
|
|
23748
|
+
}) ]
|
|
23749
|
+
}) : jsxRuntime.jsx("input", {
|
|
23750
|
+
type: "text",
|
|
23751
|
+
value: value,
|
|
23752
|
+
onChange: e => updateToken(tokenKey, e.target.value)
|
|
23753
|
+
}) ]
|
|
23754
|
+
}, tokenKey);
|
|
23755
|
+
}))
|
|
23756
|
+
}) ]
|
|
23757
|
+
}), jsxRuntime.jsxs("div", {
|
|
23758
|
+
className: "customizer-preview",
|
|
23759
|
+
children: [ jsxRuntime.jsx("h3", {
|
|
23760
|
+
children: "Live Preview"
|
|
23761
|
+
}), jsxRuntime.jsx("style", {
|
|
23762
|
+
children: cssPreview
|
|
23763
|
+
}), jsxRuntime.jsx(ThemePreview, {
|
|
23764
|
+
theme: previewTheme,
|
|
23765
|
+
showDetails: !1,
|
|
23766
|
+
showPalette: !0,
|
|
23767
|
+
showTypography: !0,
|
|
23768
|
+
showSpacing: !0
|
|
23769
|
+
}) ]
|
|
23770
|
+
}) ]
|
|
23771
|
+
}), jsxRuntime.jsx("style", {
|
|
23772
|
+
children: "\n .design-tokens-customizer {\n display: flex;\n flex-direction: column;\n height: 100vh;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n .customizer-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 24px;\n border-bottom: 1px solid #e0e0e0;\n background: #f5f5f5;\n }\n\n .customizer-header h2 {\n margin: 0;\n font-size: 24px;\n color: #333;\n }\n\n .customizer-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .customizer-controls select,\n .customizer-controls button {\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n background: white;\n cursor: pointer;\n }\n\n .customizer-controls button:hover,\n .file-input-button:hover {\n background: #f0f0f0;\n }\n\n .file-input-button {\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n background: white;\n cursor: pointer;\n font-size: 14px;\n display: inline-block;\n }\n\n .customizer-content {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .customizer-sidebar {\n width: 200px;\n border-right: 1px solid #e0e0e0;\n padding: 16px;\n background: #fafafa;\n overflow-y: auto;\n }\n\n .category-button {\n display: block;\n width: 100%;\n padding: 12px;\n margin-bottom: 8px;\n border: none;\n background: white;\n border-radius: 4px;\n cursor: pointer;\n text-align: left;\n font-size: 14px;\n }\n\n .category-button:hover,\n .category-button.active {\n background: #e0e0e0;\n }\n\n .customizer-editor {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n }\n\n .customizer-editor h3 {\n margin-top: 0;\n margin-bottom: 16px;\n color: #333;\n }\n\n .tokens-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n }\n\n .token-item {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .token-item label {\n font-size: 14px;\n font-weight: 500;\n color: #666;\n }\n\n .color-input-group {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .color-input-group input[type=\"color\"] {\n width: 50px;\n height: 40px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n cursor: pointer;\n }\n\n .color-input-group input[type=\"text\"],\n .token-item input[type=\"text\"] {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 14px;\n font-family: 'Monaco', 'Menlo', monospace;\n }\n\n .customizer-preview {\n width: 400px;\n border-left: 1px solid #e0e0e0;\n padding: 24px;\n overflow-y: auto;\n background: #fafafa;\n }\n\n .customizer-preview h3 {\n margin-top: 0;\n margin-bottom: 16px;\n color: #333;\n }\n "
|
|
23773
|
+
}) ]
|
|
23774
|
+
});
|
|
23148
23775
|
};
|
|
23149
23776
|
|
|
23777
|
+
/**
|
|
23778
|
+
* Design Tokens Customizer Component
|
|
23779
|
+
*/
|
|
23150
23780
|
/**
|
|
23151
23781
|
* Theme Adapter
|
|
23152
23782
|
*
|
|
@@ -23157,7 +23787,8 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
|
|
|
23157
23787
|
*
|
|
23158
23788
|
* @param tokens - DesignTokens object
|
|
23159
23789
|
* @returns CSS variables object compatible with Theme.cssVars
|
|
23160
|
-
*/
|
|
23790
|
+
*/
|
|
23791
|
+
function designTokensToCSSVars(tokens) {
|
|
23161
23792
|
const cssVars = {};
|
|
23162
23793
|
return Object.entries(tokens).forEach((([key, value]) => {
|
|
23163
23794
|
void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
|
|
@@ -23743,6 +24374,7 @@ function mergePartStyles(base, override) {
|
|
|
23743
24374
|
// Export as namespaces with explicit typing
|
|
23744
24375
|
const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
|
|
23745
24376
|
__proto__: null,
|
|
24377
|
+
DesignTokensCustomizer: DesignTokensCustomizer,
|
|
23746
24378
|
RTLManager: RTLManager,
|
|
23747
24379
|
ThemeApplicator: ThemeApplicator,
|
|
23748
24380
|
ThemeComparator: ThemeComparator,
|
|
@@ -23827,9 +24459,10 @@ exports.Countdown = Countdown, exports.DATA_TABLE_CLASSES = DATA_TABLE_CLASSES,
|
|
|
23827
24459
|
exports.DATA_TABLE_SELECTORS = DATA_TABLE_SELECTORS, exports.DATEPICKER = DATEPICKER,
|
|
23828
24460
|
exports.DEFAULT_ATOMIX_FONTS = DEFAULT_ATOMIX_FONTS, exports.DOTS = "...", exports.DROPDOWN = DROPDOWN,
|
|
23829
24461
|
exports.DROPDOWN_CSS_VARS = DROPDOWN_CSS_VARS, exports.DataTable = DataTable, exports.DatePicker = DatePicker,
|
|
23830
|
-
exports.
|
|
23831
|
-
exports.
|
|
23832
|
-
exports.
|
|
24462
|
+
exports.DesignTokensCustomizer = DesignTokensCustomizer, exports.DonutChart = DonutChart,
|
|
24463
|
+
exports.Dropdown = Dropdown, exports.EDGE_PANEL = EDGE_PANEL, exports.EdgePanel = EdgePanel,
|
|
24464
|
+
exports.ElevationCard = ElevationCard, exports.FOOTER = FOOTER, exports.FORM = FORM,
|
|
24465
|
+
exports.FORM_GROUP = FORM_GROUP, exports.Footer = Footer, exports.FooterLink = FooterLink,
|
|
23833
24466
|
exports.FooterSection = FooterSection, exports.FooterSocialLink = FooterSocialLink,
|
|
23834
24467
|
exports.Form = Form, exports.FormGroup = FormGroup, exports.FunnelChart = FunnelChart,
|
|
23835
24468
|
exports.GLASS_CONTAINER = GLASS_CONTAINER, exports.GaugeChart = GaugeChart, exports.Grid = Grid,
|
|
@@ -23938,20 +24571,53 @@ exports.createDarkVariant =
|
|
|
23938
24571
|
* Create a dark theme variant from a light theme
|
|
23939
24572
|
*/
|
|
23940
24573
|
function(lightTheme) {
|
|
23941
|
-
|
|
24574
|
+
// We'll extend the theme by merging the new properties with the existing theme
|
|
24575
|
+
const darkVariant = {
|
|
23942
24576
|
name: `${lightTheme.name} Dark`,
|
|
23943
24577
|
palette: {
|
|
23944
24578
|
mode: "dark",
|
|
24579
|
+
primary: lightTheme.palette?.primary,
|
|
24580
|
+
// Preserve original primary
|
|
24581
|
+
secondary: lightTheme.palette?.secondary,
|
|
24582
|
+
// Preserve original secondary
|
|
24583
|
+
error: lightTheme.palette?.error,
|
|
24584
|
+
// Preserve original error
|
|
24585
|
+
warning: lightTheme.palette?.warning,
|
|
24586
|
+
// Preserve original warning
|
|
24587
|
+
info: lightTheme.palette?.info,
|
|
24588
|
+
// Preserve original info
|
|
24589
|
+
success: lightTheme.palette?.success,
|
|
24590
|
+
// Preserve original success
|
|
23945
24591
|
background: {
|
|
23946
24592
|
default: "#121212",
|
|
24593
|
+
paper: "#1e1e1e",
|
|
24594
|
+
// Added missing paper property
|
|
23947
24595
|
subtle: "#1e1e1e"
|
|
23948
24596
|
},
|
|
23949
24597
|
text: {
|
|
23950
24598
|
primary: "#ffffff",
|
|
23951
|
-
secondary: "rgba(255, 255, 255, 0.7)"
|
|
24599
|
+
secondary: "rgba(255, 255, 255, 0.7)",
|
|
24600
|
+
disabled: "rgba(255, 255, 255, 0.38)"
|
|
23952
24601
|
}
|
|
23953
24602
|
}
|
|
23954
|
-
}
|
|
24603
|
+
};
|
|
24604
|
+
// Create a new theme by extending the light theme with the dark variant
|
|
24605
|
+
return {
|
|
24606
|
+
...lightTheme,
|
|
24607
|
+
...darkVariant,
|
|
24608
|
+
palette: {
|
|
24609
|
+
...lightTheme.palette,
|
|
24610
|
+
...darkVariant.palette,
|
|
24611
|
+
background: {
|
|
24612
|
+
...lightTheme.palette?.background,
|
|
24613
|
+
...darkVariant.palette?.background
|
|
24614
|
+
},
|
|
24615
|
+
text: {
|
|
24616
|
+
...lightTheme.palette?.text,
|
|
24617
|
+
...darkVariant.palette?.text
|
|
24618
|
+
}
|
|
24619
|
+
}
|
|
24620
|
+
};
|
|
23955
24621
|
}
|
|
23956
24622
|
/**
|
|
23957
24623
|
* Validate theme structure
|