@axzydev/axzy_ui_system 1.4.2 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +322 -211
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.cts +143 -69
- package/dist/index.d.ts +143 -69
- package/dist/index.js +224 -114
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/molecules/card/card.tsx +22 -9
- package/src/components/organisms/page-header/page-header.tsx +14 -3
- package/src/components/organisms/sidebar/sidebar.doc.mdx +2 -0
- package/src/components/organisms/sidebar/sidebar.props.ts +30 -2
- package/src/components/organisms/sidebar/sidebar.tsx +77 -26
- package/src/components/organisms/topbar/topbar.props.ts +13 -0
- package/src/components/organisms/topbar/topbar.tsx +35 -9
- package/src/components/templates/layout/layout.props.ts +8 -0
- package/src/components/templates/layout/layout.tsx +111 -54
- package/src/components/theme-provider/themeProvider.doc.mdx +1 -0
- package/src/components/theme-provider/themeProvider.props.ts +6 -0
- package/src/components/theme-provider/themeProvider.tsx +11 -1
- package/src/index.ts +6 -6
- package/src/theme/theme-context.ts +11 -1
- package/src/theme/theme.types.ts +7 -0
|
@@ -4,6 +4,7 @@ import ITTopBar from "@/components/organisms/topbar/topbar";
|
|
|
4
4
|
import ITSidebar from "@/components/organisms/sidebar/sidebar";
|
|
5
5
|
import { ITLayoutProps } from "./layout.props";
|
|
6
6
|
import { theme } from "@/theme/theme";
|
|
7
|
+
import { useITFlatAppearance } from "@/theme/theme-context";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Main application shell with sidebar, topbar, and content area.
|
|
@@ -27,6 +28,16 @@ import { theme } from "@/theme/theme";
|
|
|
27
28
|
* >
|
|
28
29
|
* <SettingsPage />
|
|
29
30
|
* </ITLayout>
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Full-height sidebar with the brand on top; the top bar covers only the content.
|
|
34
|
+
* <ITLayout
|
|
35
|
+
* sidebarFullHeight
|
|
36
|
+
* topBar={{ logo: <Logo />, logoText: "Acme", centerContent: <SearchBox /> }}
|
|
37
|
+
* sidebar={{ navigationItems, isCollapsed: false }}
|
|
38
|
+
* >
|
|
39
|
+
* <Dashboard />
|
|
40
|
+
* </ITLayout>
|
|
30
41
|
*/
|
|
31
42
|
export default function ITLayout({
|
|
32
43
|
topBar,
|
|
@@ -34,77 +45,123 @@ export default function ITLayout({
|
|
|
34
45
|
children,
|
|
35
46
|
className = "",
|
|
36
47
|
contentClassName = "",
|
|
48
|
+
sidebarFullHeight = false,
|
|
37
49
|
}: ITLayoutProps) {
|
|
38
50
|
const [internalCollapsed, setInternalCollapsed] = useState(true);
|
|
39
51
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
|
52
|
+
const flat = useITFlatAppearance();
|
|
40
53
|
|
|
41
54
|
const isControlled = sidebar.isCollapsed !== undefined;
|
|
42
55
|
const desktopCollapsed = isControlled ? sidebar.isCollapsed : internalCollapsed;
|
|
43
56
|
const handleToggleCollapse = isControlled ? (sidebar.onToggleCollapse ?? (() => {})) : () => setInternalCollapsed(v => !v);
|
|
44
57
|
|
|
45
58
|
const layoutTokens = theme.layout;
|
|
59
|
+
// Must match ITSidebar's own at-rest width (88px rail / 280px; 72px / 248px when flat).
|
|
60
|
+
const reservedWidth = desktopCollapsed
|
|
61
|
+
? flat ? "w-[72px]" : "w-[88px]"
|
|
62
|
+
: flat ? "w-[248px]" : "w-[280px]";
|
|
63
|
+
// The sidebar collapses by button instead of hover: the top bar's menu
|
|
64
|
+
// button toggles the rail on desktop and still opens the drawer on mobile.
|
|
65
|
+
const toggleByButton = sidebar.expandOnHover === false;
|
|
66
|
+
const handleMenuButton = () => {
|
|
67
|
+
if (toggleByButton && window.matchMedia("(min-width: 1024px)").matches) handleToggleCollapse();
|
|
68
|
+
else setMobileSidebarOpen(v => !v);
|
|
69
|
+
};
|
|
70
|
+
// With a full-height sidebar the brand moves from the top bar to the sidebar.
|
|
71
|
+
const brand = sidebarFullHeight
|
|
72
|
+
? (sidebar.brand ?? { logo: topBar.logo, text: topBar.logoText })
|
|
73
|
+
: sidebar.brand;
|
|
46
74
|
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
const topBarNode = (
|
|
76
|
+
<ITTopBar
|
|
77
|
+
{...topBar}
|
|
78
|
+
hideBrandOnDesktop={sidebarFullHeight || topBar.hideBrandOnDesktop}
|
|
79
|
+
showMobileMenuButton
|
|
80
|
+
showDesktopMenuButton={toggleByButton || topBar.showDesktopMenuButton}
|
|
81
|
+
onToggleMobileMenu={handleMenuButton}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
54
84
|
|
|
85
|
+
const desktopSidebar = (
|
|
86
|
+
// Full-height: the sidebar sits beside the top bar, so it needs to win the
|
|
87
|
+
// stacking order when the collapsed rail expands over the content on hover.
|
|
88
|
+
<div className={`hidden lg:block relative h-full ${sidebarFullHeight ? "z-50" : "z-40"}`}>
|
|
89
|
+
{/* Reserves the sidebar's at-rest width. When the sidebar is collapsed
|
|
90
|
+
(default), this is the 88px rail and hover expands over the content.
|
|
91
|
+
When controlled-expanded (`sidebar.isCollapsed === false`), it
|
|
92
|
+
reserves the full width so the sidebar never overlays content. */}
|
|
93
|
+
<div className={`${reservedWidth} h-full flex-shrink-0`} />
|
|
94
|
+
<div className="absolute top-0 left-0 h-full">
|
|
95
|
+
<ITSidebar
|
|
96
|
+
{...sidebar}
|
|
97
|
+
brand={brand}
|
|
98
|
+
isCollapsed={desktopCollapsed}
|
|
99
|
+
onToggleCollapse={handleToggleCollapse}
|
|
100
|
+
visibleOnMobile={false}
|
|
101
|
+
className={`h-full ${flat ? "" : "drop-shadow-2xl"} transition-all duration-400 ease-[cubic-bezier(0.2,0,0,1)] flex-shrink-0`}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const mobileSidebar = mobileSidebarOpen && (
|
|
108
|
+
<div
|
|
109
|
+
className="lg:hidden fixed inset-0 z-[40] transition-opacity duration-300 backdrop-blur-sm bg-black/40"
|
|
110
|
+
onClick={() => setMobileSidebarOpen(false)}
|
|
111
|
+
>
|
|
55
112
|
<div
|
|
56
|
-
className="flex
|
|
113
|
+
className="h-full w-fit flex transform transition-transform duration-300 ease-[cubic-bezier(0.2,0,0,1)]"
|
|
114
|
+
onClick={(e) => e.stopPropagation()}
|
|
115
|
+
>
|
|
116
|
+
<ITSidebar
|
|
117
|
+
{...sidebar}
|
|
118
|
+
brand={brand}
|
|
119
|
+
isCollapsed={false}
|
|
120
|
+
visibleOnMobile={true}
|
|
121
|
+
className="h-full shadow-2xl relative z-[60]"
|
|
122
|
+
onToggleCollapse={() => setMobileSidebarOpen(false)}
|
|
123
|
+
onItemClick={() => setMobileSidebarOpen(false)}
|
|
124
|
+
onSubItemClick={() => setMobileSidebarOpen(false)}
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const main = (
|
|
131
|
+
<main className="flex-1 overflow-y-auto w-full custom-scrollbar relative z-0">
|
|
132
|
+
<div className={clsx("mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8 py-6 h-full", contentClassName)}>
|
|
133
|
+
{children}
|
|
134
|
+
</div>
|
|
135
|
+
</main>
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
if (sidebarFullHeight) {
|
|
139
|
+
return (
|
|
140
|
+
<div
|
|
141
|
+
className={`flex h-screen overflow-hidden w-full relative ${className}`}
|
|
57
142
|
style={{ backgroundColor: layoutTokens.backgroundColor }}
|
|
58
143
|
>
|
|
59
|
-
{
|
|
60
|
-
<div className="
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
When controlled-expanded (`sidebar.isCollapsed === false`), it
|
|
64
|
-
reserves the full 280px so the sidebar never overlays content. */}
|
|
65
|
-
<div
|
|
66
|
-
className={`${desktopCollapsed ? "w-[88px]" : "w-[280px]"} h-full flex-shrink-0`}
|
|
67
|
-
/>
|
|
68
|
-
<div className="absolute top-0 left-0 h-full">
|
|
69
|
-
<ITSidebar
|
|
70
|
-
{...sidebar}
|
|
71
|
-
isCollapsed={desktopCollapsed}
|
|
72
|
-
onToggleCollapse={handleToggleCollapse}
|
|
73
|
-
visibleOnMobile={false}
|
|
74
|
-
className="h-full drop-shadow-2xl transition-all duration-400 ease-[cubic-bezier(0.2,0,0,1)] flex-shrink-0"
|
|
75
|
-
/>
|
|
76
|
-
</div>
|
|
144
|
+
{desktopSidebar}
|
|
145
|
+
<div className="flex flex-col flex-1 min-w-0 overflow-hidden">
|
|
146
|
+
{topBarNode}
|
|
147
|
+
{main}
|
|
77
148
|
</div>
|
|
149
|
+
{mobileSidebar}
|
|
150
|
+
</div>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
78
153
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
className="lg:hidden fixed inset-0 z-[40] transition-opacity duration-300 backdrop-blur-sm bg-black/40"
|
|
83
|
-
onClick={() => setMobileSidebarOpen(false)}
|
|
84
|
-
>
|
|
85
|
-
<div
|
|
86
|
-
className="h-full w-fit flex transform transition-transform duration-300 ease-[cubic-bezier(0.2,0,0,1)]"
|
|
87
|
-
onClick={(e) => e.stopPropagation()}
|
|
88
|
-
>
|
|
89
|
-
<ITSidebar
|
|
90
|
-
{...sidebar}
|
|
91
|
-
isCollapsed={false}
|
|
92
|
-
visibleOnMobile={true}
|
|
93
|
-
className="h-full shadow-2xl relative z-[60]"
|
|
94
|
-
onToggleCollapse={() => setMobileSidebarOpen(false)}
|
|
95
|
-
onItemClick={() => setMobileSidebarOpen(false)}
|
|
96
|
-
onSubItemClick={() => setMobileSidebarOpen(false)}
|
|
97
|
-
/>
|
|
98
|
-
</div>
|
|
99
|
-
</div>
|
|
100
|
-
)}
|
|
154
|
+
return (
|
|
155
|
+
<div className={`flex flex-col h-screen overflow-hidden w-full ${className}`}>
|
|
156
|
+
{topBarNode}
|
|
101
157
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
158
|
+
<div
|
|
159
|
+
className="flex flex-1 overflow-hidden relative"
|
|
160
|
+
style={{ backgroundColor: layoutTokens.backgroundColor }}
|
|
161
|
+
>
|
|
162
|
+
{desktopSidebar}
|
|
163
|
+
{mobileSidebar}
|
|
164
|
+
{main}
|
|
108
165
|
</div>
|
|
109
166
|
</div>
|
|
110
167
|
);
|
|
@@ -17,6 +17,7 @@ Root theme context that injects CSS custom properties into the entire component
|
|
|
17
17
|
| `density` | `number` | `1` | Global density/compactness factor: values below `1` shrink base sizes (fonts, paddings, gaps), above `1` grow them. Applies by scaling the root font-size so every `rem`-based token compacts together while the layout stays fluid. Clamped to `0.5`–`1.5`. |
|
|
18
18
|
| `radius` | `number` | — | Global border radius in **px** applied to the whole rounding scale. `2` ⇒ 2px corners (near-square), `8` ⇒ 8px, `0` ⇒ square. No override when omitted (Tailwind defaults). |
|
|
19
19
|
| `shadow` | `number` | `2` | Global shadow strength level: `0` ⇒ none, `1` ⇒ subtle, `2` ⇒ default current look, `3` ⇒ pronounced. No override when omitted (keeps defaults). |
|
|
20
|
+
| `appearance` | `"soft" \| "flat"` | `"soft"` | Visual language. `"flat"` switches `ITCard`, `ITSidebar`, `ITTopBar` and `ITPageHeader` to flat surfaces (hairline borders, no shadows, no header icon tile) and sets `data-it-appearance` on `<html>`. Read it in your own components with `useITFlatAppearance()`. |
|
|
20
21
|
|
|
21
22
|
### ITThemePalette Shape
|
|
22
23
|
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { ITThemeAppearance } from "@/theme/theme.types";
|
|
2
|
+
|
|
3
|
+
export type { ITThemeAppearance };
|
|
4
|
+
|
|
1
5
|
export interface ITThemePalette {
|
|
2
6
|
/** Main brand accent color (hex). Drives primary buttons, active nav items, focus rings, links, and the `--color-primary` CSS variable. @default "#06b6d4" */
|
|
3
7
|
primary: string;
|
|
@@ -54,4 +58,6 @@ export interface ITThemeProviderProps {
|
|
|
54
58
|
radius?: number;
|
|
55
59
|
/** Global shadow strength level. `0` ⇒ no shadows, `1` ⇒ subtle, `2` ⇒ default current look, `3` ⇒ pronounced. Shadows are injected as `--shadow-*`/`.shadow-*` overrides so cards, dropdowns and dialogs follow the level. @default 2 (keeps current default when omitted) */
|
|
56
60
|
shadow?: number;
|
|
61
|
+
/** Visual language of the whole system. `"soft"` keeps the current look (floating cards, tinted shadows, glass sidebar/top bar). `"flat"` switches the app shell and surfaces to flat ones: hairline borders instead of shadows on `ITCard`, a plain `ITSidebar` (no glow, no accent bar, narrower), a plain `ITTopBar` (no shadow, initials avatar) and a compact `ITPageHeader` without the icon tile. It also sets `data-it-appearance` on `<html>` so app CSS can follow it. Combine it with `shadow` and `radius` to finish the look. @default "soft" */
|
|
62
|
+
appearance?: ITThemeAppearance;
|
|
57
63
|
}
|
|
@@ -73,7 +73,7 @@ import { DEFAULT_PALETTE, PRESETS } from "./themePresets";
|
|
|
73
73
|
// Contexto y hooks (useITTheme / useITThemeSafe) viven en @/theme/theme-context.
|
|
74
74
|
// Re-exportados desde aquí para mantener compatibilidad de la API pública.
|
|
75
75
|
// eslint-disable-next-line react-refresh/only-export-components
|
|
76
|
-
export { useITTheme, useITThemeSafe } from "@/theme/theme-context";
|
|
76
|
+
export { useITTheme, useITThemeSafe, useITFlatAppearance } from "@/theme/theme-context";
|
|
77
77
|
|
|
78
78
|
const getNestedValue = (obj: any, path: string) => {
|
|
79
79
|
return path.split(".").reduce((acc, part) => acc && acc[part], obj);
|
|
@@ -143,6 +143,7 @@ export default function ITThemeProvider({
|
|
|
143
143
|
density = 1,
|
|
144
144
|
radius,
|
|
145
145
|
shadow,
|
|
146
|
+
appearance = "soft",
|
|
146
147
|
}: ITThemeProviderProps) {
|
|
147
148
|
const [palette, setPaletteState] = useState<ITThemePalette>(() => {
|
|
148
149
|
const basePalette = {
|
|
@@ -276,6 +277,14 @@ export default function ITThemeProvider({
|
|
|
276
277
|
};
|
|
277
278
|
}, [density]);
|
|
278
279
|
|
|
280
|
+
// Lenguaje visual: se publica en <html> para que el CSS de la app pueda
|
|
281
|
+
// seguirlo; los componentes lo leen del contexto (useITFlatAppearance).
|
|
282
|
+
useLayoutEffect(() => {
|
|
283
|
+
const root = document.documentElement;
|
|
284
|
+
root.setAttribute("data-it-appearance", appearance);
|
|
285
|
+
return () => root.removeAttribute("data-it-appearance");
|
|
286
|
+
}, [appearance]);
|
|
287
|
+
|
|
279
288
|
// Overrides globales de radius y sombras.
|
|
280
289
|
// Radius: en Tailwind v4 cada `rounded-*` resuelve a var(--radius-*), así que
|
|
281
290
|
// setear los vars en :root (en px) cuadra/redondea todo el sistema sin tocar
|
|
@@ -1611,6 +1620,7 @@ export default function ITThemeProvider({
|
|
|
1611
1620
|
resolvedTheme,
|
|
1612
1621
|
darkModeMode,
|
|
1613
1622
|
setDarkModeMode,
|
|
1623
|
+
appearance,
|
|
1614
1624
|
}}
|
|
1615
1625
|
>
|
|
1616
1626
|
{children}
|
package/src/index.ts
CHANGED
|
@@ -103,7 +103,7 @@ import type { ITSearchSelectProps } from "./components/molecules/search-select/s
|
|
|
103
103
|
import type { ITSelectProps } from "./components/molecules/select/select.props";
|
|
104
104
|
import type { ITSearchTableProps } from "./components/organisms/searchTable/searchTable.props";
|
|
105
105
|
import type { ITSegmentedControlProps } from "./components/atoms/segmented-control/segmented-control.props";
|
|
106
|
-
import type { ITSidebarProps, ITSidebarNotification, ITNavigationItem, ITNavigationSubItem, ITNavigationSubItemEntry, ITNavigationSubItemGroup } from "./components/organisms/sidebar/sidebar.props";
|
|
106
|
+
import type { ITSidebarProps, ITSidebarNotification, ITSidebarBrand, ITNavigationItem, ITNavigationSubItem, ITNavigationSubItemEntry, ITNavigationSubItemGroup } from "./components/organisms/sidebar/sidebar.props";
|
|
107
107
|
import type { ITSkeletonProps } from "./components/atoms/skeleton/skeleton.props";
|
|
108
108
|
import type { ITSlideToggleProps } from "./components/atoms/slide/slide.props";
|
|
109
109
|
import type { ITSliderProps } from "./components/atoms/slider/slider.props";
|
|
@@ -127,8 +127,8 @@ import ITLoader from "./components/atoms/loader/loader";
|
|
|
127
127
|
import type { LoaderProps as ITLoaderProps } from "./components/atoms/loader/loader.props";
|
|
128
128
|
import ITStepper from "./components/molecules/stepper/stepper";
|
|
129
129
|
import type { ITStepperProps } from "./components/molecules/stepper/stepper.props";
|
|
130
|
-
import ITThemeProvider, { useITTheme, useITThemeSafe } from "./components/theme-provider/themeProvider";
|
|
131
|
-
import type { ITThemeProviderProps, ITThemePalette } from "./components/theme-provider/themeProvider.props";
|
|
130
|
+
import ITThemeProvider, { useITTheme, useITThemeSafe, useITFlatAppearance } from "./components/theme-provider/themeProvider";
|
|
131
|
+
import type { ITThemeProviderProps, ITThemePalette, ITThemeAppearance } from "./components/theme-provider/themeProvider.props";
|
|
132
132
|
import ITTimePicker from "./components/molecules/time-picker/timePicker";
|
|
133
133
|
import type { ITTimePickerProps } from "./components/molecules/time-picker/timePicker.props";
|
|
134
134
|
import type { ITThemeConfig } from "./theme/theme.types";
|
|
@@ -153,7 +153,7 @@ export {
|
|
|
153
153
|
ITSearchTable,
|
|
154
154
|
ITSegmentedControl, ITSidebar, ITSkeleton, ITSlideToggle, ITSlider, ITStack, ITStatCard, ITStepper,
|
|
155
155
|
ITTable, ITTabs, ITText, ITTextarea, ITTripleFilter, ITThemeProvider,
|
|
156
|
-
useITTheme, useITThemeSafe, ITTimePicker, ITToast, ITWysiwyg,
|
|
156
|
+
useITTheme, useITThemeSafe, useITFlatAppearance, ITTimePicker, ITToast, ITWysiwyg,
|
|
157
157
|
UploadStatus, FileTypeEnum,
|
|
158
158
|
getContrastTextColor, isLightColor, resolveCssColor
|
|
159
159
|
};
|
|
@@ -176,7 +176,7 @@ export {
|
|
|
176
176
|
ITPageProps, ITPageHeaderProps,
|
|
177
177
|
ITNavigationItem, ITNavigationSubItem,
|
|
178
178
|
ITNavigationSubItemEntry, ITNavigationSubItemGroup,
|
|
179
|
-
ITSidebarNotification,
|
|
179
|
+
ITSidebarNotification, ITSidebarBrand,
|
|
180
180
|
ITPaginationProps, ITPopoverProps, ITProgressProps,
|
|
181
181
|
ITRadioGroupProps, ITRadioOption, ITSelectProps, ITSearchSelectProps,
|
|
182
182
|
ITSearchTableProps,
|
|
@@ -184,7 +184,7 @@ export {
|
|
|
184
184
|
ITStackProps, ITStatCardProps, ITStepperProps,
|
|
185
185
|
ITTableProps, ITTabsProps, ITTabItem, ITTextProps, ITTextareaProps,
|
|
186
186
|
TableDensity,
|
|
187
|
-
ITTripleFilterProps, ITTripleFilterOption, ITThemeConfig, ITThemeProviderProps, ITThemePalette,
|
|
187
|
+
ITTripleFilterProps, ITTripleFilterOption, ITThemeConfig, ITThemeProviderProps, ITThemePalette, ITThemeAppearance,
|
|
188
188
|
ITTimePickerProps, ITToastProps,
|
|
189
189
|
ITWysiwygProps,
|
|
190
190
|
UseTableStateOptions, UseTableStateResult
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, useContext } from "react";
|
|
2
|
-
import type { ITThemePalette } from "./theme.types";
|
|
2
|
+
import type { ITThemeAppearance, ITThemePalette } from "./theme.types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Contexto de theming compartido por ITThemeProvider y componentes que lo
|
|
@@ -16,6 +16,8 @@ export interface ITThemeContextType {
|
|
|
16
16
|
resolvedTheme: "light" | "dark";
|
|
17
17
|
darkModeMode: "light" | "dark" | "system";
|
|
18
18
|
setDarkModeMode: (mode: "light" | "dark" | "system") => void;
|
|
19
|
+
/** Visual language chosen on the provider (`"soft"` unless `appearance` says otherwise). */
|
|
20
|
+
appearance: ITThemeAppearance;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export const ITThemeContext = createContext<ITThemeContextType | undefined>(undefined);
|
|
@@ -34,4 +36,12 @@ export const useITTheme = () => {
|
|
|
34
36
|
*/
|
|
35
37
|
export const useITThemeSafe = (): ITThemeContextType | undefined => {
|
|
36
38
|
return useContext(ITThemeContext);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* `true` cuando el provider pide el lenguaje visual plano (`appearance="flat"`).
|
|
43
|
+
* Fuera de un ITThemeProvider devuelve `false` (aspecto por defecto).
|
|
44
|
+
*/
|
|
45
|
+
export const useITFlatAppearance = (): boolean => {
|
|
46
|
+
return useContext(ITThemeContext)?.appearance === "flat";
|
|
37
47
|
};
|
package/src/theme/theme.types.ts
CHANGED
|
@@ -12,6 +12,13 @@ export type ColorScale = {
|
|
|
12
12
|
950?: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Visual language of the whole system.
|
|
17
|
+
* - `"soft"`: soft depth — floating cards, tinted shadows, glass sidebar and top bar (default).
|
|
18
|
+
* - `"flat"`: flat surfaces — hairline borders instead of shadows, plain sidebar and top bar, compact page headers.
|
|
19
|
+
*/
|
|
20
|
+
export type ITThemeAppearance = "soft" | "flat";
|
|
21
|
+
|
|
15
22
|
export interface ITThemePalette {
|
|
16
23
|
/** Main brand accent color (hex). Drives primary buttons, active nav items, focus rings, links, and the `--color-primary` CSS variable. @default "#06b6d4" */
|
|
17
24
|
primary: string;
|