@ttoss/layouts 0.4.36 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ttoss/layouts
2
2
 
3
- **@ttoss/layouts** is a collection of React components that implement the layouts to use in your application.
3
+ Professional layout components for React applications with responsive design and accessibility built-in.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,51 +8,166 @@
8
8
  pnpm add @ttoss/layouts @ttoss/ui @emotion/react
9
9
  ```
10
10
 
11
- ## Quickstart
11
+ ## Available Layouts
12
12
 
13
- Use a layout as `StackedLayout` to add specific layout to your application:
13
+ ### StackedLayout - Simple Vertical Layout
14
+
15
+ Perfect for traditional websites with header, main content, and footer.
14
16
 
15
17
  ```tsx
16
18
  import { Layout, StackedLayout } from '@ttoss/layouts';
17
19
 
18
20
  const App = () => (
19
21
  <StackedLayout>
20
- <Layout.Header>Header</Layout.Header>
21
- <Layout.Main>Main</Layout.Main>
22
- <Layout.Footer>Footer</Layout.Footer>
22
+ <Layout.Header>Navigation & Branding</Layout.Header>
23
+ <Layout.Main>Page Content</Layout.Main>
24
+ <Layout.Footer>Copyright & Links</Layout.Footer>
23
25
  </StackedLayout>
24
26
  );
25
27
  ```
26
28
 
27
- ## Layouts
29
+ ### SidebarCollapseLayout - Dashboard & Admin Interfaces
30
+
31
+ Responsive sidebar that collapses on mobile, perfect for dashboards and admin panels.
32
+
33
+ ```tsx
34
+ import { Layout, SidebarCollapseLayout } from '@ttoss/layouts';
35
+
36
+ const Dashboard = () => (
37
+ <SidebarCollapseLayout>
38
+ <Layout.Header showSidebarButton>App Header with Menu Toggle</Layout.Header>
39
+ <Layout.Sidebar>Navigation Menu</Layout.Sidebar>
40
+ <Layout.Main.Header>Page Title & Actions</Layout.Main.Header>
41
+ <Layout.Main>Dashboard Content</Layout.Main>
42
+ <Layout.Main.Footer>Status Bar</Layout.Main.Footer>
43
+ </SidebarCollapseLayout>
44
+ );
45
+ ```
28
46
 
29
- Check the [Layouts Stories](http://localhost:6006/?path=/story/layouts-layout) to see the available layouts.
47
+ ## Core Components
30
48
 
31
- ## Custom Layout Components
49
+ ### Layout.Main Sub-Components
32
50
 
33
- You can create your own layout components by using the `Layout` sub-components:
51
+ Enhanced main content area with optional header and footer sections.
34
52
 
35
53
  ```tsx
36
- import { Layout, StackedLayout } from '@ttoss/layouts';
54
+ <Layout.Main.Header>
55
+ <h1>Page Title</h1>
56
+ <button>Action Button</button>
57
+ </Layout.Main.Header>
58
+
59
+ <Layout.Main>
60
+ Main content with consistent padding and overflow handling
61
+ </Layout.Main>
62
+
63
+ <Layout.Main.Footer>
64
+ <span>Last updated: Today</span>
65
+ </Layout.Main.Footer>
66
+ ```
37
67
 
38
- const CustomHeader = (props) => (
39
- <Layout.Header {...props} style={{ backgroundColor: 'red' }}>
40
- Header
41
- </Layout.Header>
68
+ ## Automatic Layout Composition
69
+
70
+ **Key Concept**: Layout components automatically detect and organize their child components by `displayName`, even when components are distributed across different files or routing structures.
71
+
72
+ ### React Router Integration
73
+
74
+ Perfect for apps where layout components come from different routes:
75
+
76
+ ```tsx
77
+ // App.tsx - Layout wrapper
78
+ import { Layout, SidebarCollapseLayout } from '@ttoss/layouts';
79
+ import { Outlet } from 'react-router-dom';
80
+
81
+ const AppLayout = () => (
82
+ <SidebarCollapseLayout>
83
+ <AppHeader />
84
+ <AppSidebar />
85
+ <Outlet /> {/* Routes render here */}
86
+ </SidebarCollapseLayout>
42
87
  );
43
88
 
44
- CustomHeader.displayName = Layout.Header.displayName;
89
+ // pages/Dashboard.tsx - Page-specific components
90
+ const Dashboard = () => (
91
+ <>
92
+ <Layout.Main.Header>
93
+ <h1>Dashboard</h1>
94
+ </Layout.Main.Header>
95
+ <Layout.Main>
96
+ <DashboardCharts />
97
+ </Layout.Main>
98
+ <Layout.Main.Footer>Last updated: {lastUpdate}</Layout.Main.Footer>
99
+ </>
100
+ );
101
+ ```
45
102
 
46
- const App = () => (
47
- <StackedLayout>
48
- <CustomHeader />
49
- <Layout.Main>Main</Layout.Main>
50
- <Layout.Footer>Footer</Layout.Footer>
51
- </StackedLayout>
103
+ The layout **automatically composes** itself by finding components with matching `displayName` properties, regardless of component hierarchy or file structure.
104
+
105
+ ### Component Detection System
106
+
107
+ ```tsx
108
+ // These components can be anywhere in your component tree:
109
+ <Layout.Header /> // → Detected as "Header"
110
+ <Layout.Sidebar /> // → Detected as "Sidebar"
111
+ <Layout.Main /> // → Detected as "Main"
112
+ <Layout.Footer /> // → Detected as "Footer"
113
+ <Layout.Main.Header /> // → Detected as "MainHeader"
114
+ <Layout.Main.Footer /> // → Detected as "MainFooter"
115
+ ```
116
+
117
+ ## Component Properties
118
+
119
+ ### Responsive Behavior
120
+
121
+ - **Desktop**: Sidebar remains visible, toggleable via button
122
+ - **Mobile**: Sidebar becomes slide-out drawer, auto-closes on navigation
123
+ - **Accessible**: Full keyboard navigation and screen reader support
124
+
125
+ ### Styling Integration
126
+
127
+ All components integrate seamlessly with `@ttoss/ui` theme system via `sx` prop:
128
+
129
+ ```tsx
130
+ <Layout.Header
131
+ sx={{
132
+ backgroundColor: 'brand.primary',
133
+ borderBottom: '2px solid',
134
+ }}
135
+ >
136
+ Custom styled header
137
+ </Layout.Header>
138
+ ```
139
+
140
+ ## Advanced Usage
141
+
142
+ ### Custom Components with displayName
143
+
144
+ Create reusable layout components by preserving the required `displayName`:
145
+
146
+ ```tsx
147
+ const AppHeader = ({ children, ...props }) => (
148
+ <Layout.Header {...props}>
149
+ <Logo />
150
+ {children}
151
+ <UserMenu />
152
+ </Layout.Header>
52
153
  );
154
+
155
+ AppHeader.displayName = Layout.Header.displayName; // Required for layout detection
53
156
  ```
54
157
 
55
- For the layout to work correctly, you must use the `displayName` property of the `Layout` sub-components, because the layout components use the `displayName` to identify the layout sub-components.
158
+ ### Sidebar with Logo Slot
159
+
160
+ Add branding or controls to the sidebar area:
161
+
162
+ ```tsx
163
+ <Layout.Header sidebarSlot={<CompanyLogo />} showSidebarButton>
164
+ Main header content
165
+ </Layout.Header>
166
+ ```
167
+
168
+ ## Examples
169
+
170
+ View complete examples in [Storybook](https://storybook.ttoss.dev/?path=/story/layouts-layout).
56
171
 
57
172
  ## License
58
173
 
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
2
 
3
3
  // src/components/Layout.tsx
4
- import { Box as Box5, Container } from "@ttoss/ui";
4
+ import { Box as Box7, Container } from "@ttoss/ui";
5
5
 
6
6
  // src/components/Footer.tsx
7
7
  import { Box } from "@ttoss/ui";
@@ -16,10 +16,10 @@ var Footer = props => {
16
16
  };
17
17
  Footer.displayName = "Footer";
18
18
 
19
- // ../../node_modules/.pnpm/@iconify-icon+react@2.2.0_react@19.1.0/node_modules/@iconify-icon/react/dist/iconify.mjs
19
+ // ../../node_modules/.pnpm/@iconify-icon+react@2.3.0_react@19.1.1/node_modules/@iconify-icon/react/dist/iconify.mjs
20
20
  import React from "react";
21
21
 
22
- // ../../node_modules/.pnpm/iconify-icon@2.2.0/node_modules/iconify-icon/dist/iconify-icon.mjs
22
+ // ../../node_modules/.pnpm/iconify-icon@2.3.0/node_modules/iconify-icon/dist/iconify-icon.mjs
23
23
  var defaultIconDimensions = Object.freeze({
24
24
  left: 0,
25
25
  top: 0,
@@ -869,181 +869,6 @@ function sendAPIQuery(target, query, callback) {
869
869
  }
870
870
  return redundancy.query(query, send2, callback)().abort;
871
871
  }
872
- var browserCacheVersion = "iconify2";
873
- var browserCachePrefix = "iconify";
874
- var browserCacheCountKey = browserCachePrefix + "-count";
875
- var browserCacheVersionKey = browserCachePrefix + "-version";
876
- var browserStorageHour = 36e5;
877
- var browserStorageCacheExpiration = 168;
878
- var browserStorageLimit = 50;
879
- function getStoredItem(func, key) {
880
- try {
881
- return func.getItem(key);
882
- } catch (err) {}
883
- }
884
- function setStoredItem(func, key, value) {
885
- try {
886
- func.setItem(key, value);
887
- return true;
888
- } catch (err) {}
889
- }
890
- function removeStoredItem(func, key) {
891
- try {
892
- func.removeItem(key);
893
- } catch (err) {}
894
- }
895
- function setBrowserStorageItemsCount(storage2, value) {
896
- return setStoredItem(storage2, browserCacheCountKey, value.toString());
897
- }
898
- function getBrowserStorageItemsCount(storage2) {
899
- return parseInt(getStoredItem(storage2, browserCacheCountKey)) || 0;
900
- }
901
- var browserStorageConfig = {
902
- local: true,
903
- session: true
904
- };
905
- var browserStorageEmptyItems = {
906
- local: /* @__PURE__ */new Set(),
907
- session: /* @__PURE__ */new Set()
908
- };
909
- var browserStorageStatus = false;
910
- function setBrowserStorageStatus(status) {
911
- browserStorageStatus = status;
912
- }
913
- var _window = typeof window === "undefined" ? {} : window;
914
- function getBrowserStorage(key) {
915
- const attr = key + "Storage";
916
- try {
917
- if (_window && _window[attr] && typeof _window[attr].length === "number") {
918
- return _window[attr];
919
- }
920
- } catch (err) {}
921
- browserStorageConfig[key] = false;
922
- }
923
- function iterateBrowserStorage(key, callback) {
924
- const func = getBrowserStorage(key);
925
- if (!func) {
926
- return;
927
- }
928
- const version = getStoredItem(func, browserCacheVersionKey);
929
- if (version !== browserCacheVersion) {
930
- if (version) {
931
- const total2 = getBrowserStorageItemsCount(func);
932
- for (let i = 0; i < total2; i++) {
933
- removeStoredItem(func, browserCachePrefix + i.toString());
934
- }
935
- }
936
- setStoredItem(func, browserCacheVersionKey, browserCacheVersion);
937
- setBrowserStorageItemsCount(func, 0);
938
- return;
939
- }
940
- const minTime = Math.floor(Date.now() / browserStorageHour) - browserStorageCacheExpiration;
941
- const parseItem = index => {
942
- const name = browserCachePrefix + index.toString();
943
- const item = getStoredItem(func, name);
944
- if (typeof item !== "string") {
945
- return;
946
- }
947
- try {
948
- const data = JSON.parse(item);
949
- if (typeof data === "object" && typeof data.cached === "number" && data.cached > minTime && typeof data.provider === "string" && typeof data.data === "object" && typeof data.data.prefix === "string" &&
950
- // Valid item: run callback
951
- callback(data, index)) {
952
- return true;
953
- }
954
- } catch (err) {}
955
- removeStoredItem(func, name);
956
- };
957
- let total = getBrowserStorageItemsCount(func);
958
- for (let i = total - 1; i >= 0; i--) {
959
- if (!parseItem(i)) {
960
- if (i === total - 1) {
961
- total--;
962
- setBrowserStorageItemsCount(func, total);
963
- } else {
964
- browserStorageEmptyItems[key].add(i);
965
- }
966
- }
967
- }
968
- }
969
- function initBrowserStorage() {
970
- if (browserStorageStatus) {
971
- return;
972
- }
973
- setBrowserStorageStatus(true);
974
- for (const key in browserStorageConfig) {
975
- iterateBrowserStorage(key, item => {
976
- const iconSet = item.data;
977
- const provider = item.provider;
978
- const prefix = iconSet.prefix;
979
- const storage2 = getStorage(provider, prefix);
980
- if (!addIconSet(storage2, iconSet).length) {
981
- return false;
982
- }
983
- const lastModified = iconSet.lastModified || -1;
984
- storage2.lastModifiedCached = storage2.lastModifiedCached ? Math.min(storage2.lastModifiedCached, lastModified) : lastModified;
985
- return true;
986
- });
987
- }
988
- }
989
- function updateLastModified(storage2, lastModified) {
990
- const lastValue = storage2.lastModifiedCached;
991
- if (
992
- // Matches or newer
993
- lastValue && lastValue >= lastModified) {
994
- return lastValue === lastModified;
995
- }
996
- storage2.lastModifiedCached = lastModified;
997
- if (lastValue) {
998
- for (const key in browserStorageConfig) {
999
- iterateBrowserStorage(key, item => {
1000
- const iconSet = item.data;
1001
- return item.provider !== storage2.provider || iconSet.prefix !== storage2.prefix || iconSet.lastModified === lastModified;
1002
- });
1003
- }
1004
- }
1005
- return true;
1006
- }
1007
- function storeInBrowserStorage(storage2, data) {
1008
- if (!browserStorageStatus) {
1009
- initBrowserStorage();
1010
- }
1011
- function store(key) {
1012
- let func;
1013
- if (!browserStorageConfig[key] || !(func = getBrowserStorage(key))) {
1014
- return;
1015
- }
1016
- const set = browserStorageEmptyItems[key];
1017
- let index;
1018
- if (set.size) {
1019
- set.delete(index = Array.from(set).shift());
1020
- } else {
1021
- index = getBrowserStorageItemsCount(func);
1022
- if (index >= browserStorageLimit || !setBrowserStorageItemsCount(func, index + 1)) {
1023
- return;
1024
- }
1025
- }
1026
- const item = {
1027
- cached: Math.floor(Date.now() / browserStorageHour),
1028
- provider: storage2.provider,
1029
- data
1030
- };
1031
- return setStoredItem(func, browserCachePrefix + index.toString(), JSON.stringify(item));
1032
- }
1033
- if (data.lastModified && !updateLastModified(storage2, data.lastModified)) {
1034
- return;
1035
- }
1036
- if (!Object.keys(data.icons).length) {
1037
- return;
1038
- }
1039
- if (data.not_found) {
1040
- data = Object.assign({}, data);
1041
- delete data.not_found;
1042
- }
1043
- if (!store("local")) {
1044
- store("session");
1045
- }
1046
- }
1047
872
  function emptyCallback() {}
1048
873
  function loadedNewIcons(storage2) {
1049
874
  if (!storage2.iconsLoaderFlag) {
@@ -1065,7 +890,7 @@ function checkIconNamesForAPI(icons) {
1065
890
  invalid
1066
891
  };
1067
892
  }
1068
- function parseLoaderResponse(storage2, icons, data, isAPIResponse) {
893
+ function parseLoaderResponse(storage2, icons, data) {
1069
894
  function checkMissing() {
1070
895
  const pending = storage2.pendingIcons;
1071
896
  icons.forEach(name => {
@@ -1084,9 +909,6 @@ function parseLoaderResponse(storage2, icons, data, isAPIResponse) {
1084
909
  checkMissing();
1085
910
  return;
1086
911
  }
1087
- if (isAPIResponse) {
1088
- storeInBrowserStorage(storage2, data);
1089
- }
1090
912
  } catch (err) {
1091
913
  console.error(err);
1092
914
  }
@@ -1127,7 +949,7 @@ function loadNewIcons(storage2, icons) {
1127
949
  const customIconLoader = storage2.loadIcon;
1128
950
  if (storage2.loadIcons && (icons2.length > 1 || !customIconLoader)) {
1129
951
  parsePossiblyAsyncResponse(storage2.loadIcons(icons2, prefix, provider), data => {
1130
- parseLoaderResponse(storage2, icons2, data, false);
952
+ parseLoaderResponse(storage2, icons2, data);
1131
953
  });
1132
954
  return;
1133
955
  }
@@ -1141,7 +963,7 @@ function loadNewIcons(storage2, icons) {
1141
963
  [name]: data
1142
964
  }
1143
965
  } : null;
1144
- parseLoaderResponse(storage2, [name], iconSet, false);
966
+ parseLoaderResponse(storage2, [name], iconSet);
1145
967
  });
1146
968
  });
1147
969
  return;
@@ -1151,20 +973,20 @@ function loadNewIcons(storage2, icons) {
1151
973
  invalid
1152
974
  } = checkIconNamesForAPI(icons2);
1153
975
  if (invalid.length) {
1154
- parseLoaderResponse(storage2, invalid, null, false);
976
+ parseLoaderResponse(storage2, invalid, null);
1155
977
  }
1156
978
  if (!valid.length) {
1157
979
  return;
1158
980
  }
1159
981
  const api = prefix.match(matchIconName) ? getAPIModule(provider) : null;
1160
982
  if (!api) {
1161
- parseLoaderResponse(storage2, valid, null, false);
983
+ parseLoaderResponse(storage2, valid, null);
1162
984
  return;
1163
985
  }
1164
986
  const params = api.prepare(provider, prefix, valid);
1165
987
  params.forEach(item => {
1166
988
  sendAPIQuery(provider, item, data => {
1167
- parseLoaderResponse(storage2, item.icons, data, true);
989
+ parseLoaderResponse(storage2, item.icons, data);
1168
990
  });
1169
991
  });
1170
992
  });
@@ -1641,19 +1463,6 @@ function setCustomIconsLoader$1(loader, prefix, provider) {
1641
1463
  function setCustomIconLoader$1(loader, prefix, provider) {
1642
1464
  getStorage(provider || "", prefix).loadIcon = loader;
1643
1465
  }
1644
- function toggleBrowserCache(storage2, value) {
1645
- switch (storage2) {
1646
- case "local":
1647
- case "session":
1648
- browserStorageConfig[storage2] = value;
1649
- break;
1650
- case "all":
1651
- for (const key in browserStorageConfig) {
1652
- browserStorageConfig[key] = value;
1653
- }
1654
- break;
1655
- }
1656
- }
1657
1466
  var nodeAttr = "data-style";
1658
1467
  var customStyle = "";
1659
1468
  function appendCustomStyle(style) {
@@ -1671,14 +1480,13 @@ function updateStyle(parent, inline) {
1671
1480
  function exportFunctions() {
1672
1481
  setAPIModule("", fetchAPIModule);
1673
1482
  allowSimpleNames(true);
1674
- let _window2;
1483
+ let _window;
1675
1484
  try {
1676
- _window2 = window;
1485
+ _window = window;
1677
1486
  } catch (err) {}
1678
- if (_window2) {
1679
- initBrowserStorage();
1680
- if (_window2.IconifyPreload !== void 0) {
1681
- const preload = _window2.IconifyPreload;
1487
+ if (_window) {
1488
+ if (_window.IconifyPreload !== void 0) {
1489
+ const preload = _window.IconifyPreload;
1682
1490
  const err = "Invalid IconifyPreload syntax.";
1683
1491
  if (typeof preload === "object" && preload !== null) {
1684
1492
  (preload instanceof Array ? preload : [preload]).forEach(item => {
@@ -1698,8 +1506,8 @@ function exportFunctions() {
1698
1506
  });
1699
1507
  }
1700
1508
  }
1701
- if (_window2.IconifyProviders !== void 0) {
1702
- const providers = _window2.IconifyProviders;
1509
+ if (_window.IconifyProviders !== void 0) {
1510
+ const providers = _window.IconifyProviders;
1703
1511
  if (typeof providers === "object" && providers !== null) {
1704
1512
  for (const key in providers) {
1705
1513
  const err = "IconifyProviders[" + key + "] is invalid.";
@@ -1727,8 +1535,10 @@ function exportFunctions() {
1727
1535
  listAPIProviders
1728
1536
  };
1729
1537
  return {
1730
- enableCache: storage2 => toggleBrowserCache(storage2, true),
1731
- disableCache: storage2 => toggleBrowserCache(storage2, false),
1538
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1539
+ enableCache: storage2 => {},
1540
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1541
+ disableCache: storage2 => {},
1732
1542
  iconLoaded: iconLoaded$1,
1733
1543
  iconExists: iconLoaded$1,
1734
1544
  // deprecated, kept to avoid breaking changes
@@ -2242,7 +2052,7 @@ var {
2242
2052
  _api
2243
2053
  } = IconifyIconComponent;
2244
2054
 
2245
- // ../../node_modules/.pnpm/@iconify-icon+react@2.2.0_react@19.1.0/node_modules/@iconify-icon/react/dist/iconify.mjs
2055
+ // ../../node_modules/.pnpm/@iconify-icon+react@2.3.0_react@19.1.1/node_modules/@iconify-icon/react/dist/iconify.mjs
2246
2056
  var Icon = React.forwardRef((props, ref) => {
2247
2057
  const newProps = {
2248
2058
  ...props,
@@ -2542,10 +2352,55 @@ var Header = ({
2542
2352
  Header.displayName = "Header";
2543
2353
 
2544
2354
  // src/components/Main.tsx
2355
+ import { Box as Box6 } from "@ttoss/ui";
2356
+
2357
+ // src/components/MainFooter.tsx
2545
2358
  import { Box as Box4 } from "@ttoss/ui";
2546
2359
  import { jsx as jsx6 } from "react/jsx-runtime";
2547
- var Main = props => {
2360
+ var MainFooter = props => {
2548
2361
  return /* @__PURE__ */jsx6(Box4, {
2362
+ variant: "layout.main.footer",
2363
+ ...props,
2364
+ sx: {
2365
+ paddingX: "10",
2366
+ paddingY: "3",
2367
+ borderTop: "sm",
2368
+ borderColor: "display.border.muted.default",
2369
+ backgroundColor: "navigation.background.primary.default",
2370
+ width: "full",
2371
+ ...props.sx
2372
+ },
2373
+ children: props.children
2374
+ });
2375
+ };
2376
+ MainFooter.displayName = "MainFooter";
2377
+
2378
+ // src/components/MainHeader.tsx
2379
+ import { Box as Box5 } from "@ttoss/ui";
2380
+ import { jsx as jsx7 } from "react/jsx-runtime";
2381
+ var MainHeader = props => {
2382
+ return /* @__PURE__ */jsx7(Box5, {
2383
+ variant: "layout.main.header",
2384
+ ...props,
2385
+ as: "header",
2386
+ sx: {
2387
+ paddingX: "4",
2388
+ paddingY: "3",
2389
+ borderBottom: "sm",
2390
+ borderColor: "display.border.muted.default",
2391
+ backgroundColor: "navigation.background.primary.default",
2392
+ width: "full",
2393
+ ...props.sx
2394
+ },
2395
+ children: props.children
2396
+ });
2397
+ };
2398
+ MainHeader.displayName = "MainHeader";
2399
+
2400
+ // src/components/Main.tsx
2401
+ import { jsx as jsx8 } from "react/jsx-runtime";
2402
+ var Main = props => {
2403
+ return /* @__PURE__ */jsx8(Box6, {
2549
2404
  variant: "layout.main",
2550
2405
  ...props,
2551
2406
  as: "main",
@@ -2561,13 +2416,15 @@ var Main = props => {
2561
2416
  });
2562
2417
  };
2563
2418
  Main.displayName = "Main";
2419
+ Main.Header = MainHeader;
2420
+ Main.Footer = MainFooter;
2564
2421
 
2565
2422
  // src/components/Layout.tsx
2566
- import { jsx as jsx7 } from "react/jsx-runtime";
2423
+ import { jsx as jsx9 } from "react/jsx-runtime";
2567
2424
  var Layout = ({
2568
2425
  children
2569
2426
  }) => {
2570
- return /* @__PURE__ */jsx7(Box5, {
2427
+ return /* @__PURE__ */jsx9(Box7, {
2571
2428
  variant: "layout.layout",
2572
2429
  children
2573
2430
  });
@@ -2587,7 +2444,9 @@ var semanticComponents = {
2587
2444
  Header: "header",
2588
2445
  Sidebar: "sidebar",
2589
2446
  Footer: "footer",
2590
- Main: "main"
2447
+ Main: "main",
2448
+ MainHeader: "mainHeader",
2449
+ MainFooter: "mainFooter"
2591
2450
  };
2592
2451
  var getSematicElements = ({
2593
2452
  children
@@ -2606,7 +2465,7 @@ var getSematicElements = ({
2606
2465
  };
2607
2466
 
2608
2467
  // src/components/SidebarCollapseLayout.tsx
2609
- import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
2468
+ import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
2610
2469
  var SidebarCollapseLayout = ({
2611
2470
  children,
2612
2471
  ...props
@@ -2614,11 +2473,13 @@ var SidebarCollapseLayout = ({
2614
2473
  const {
2615
2474
  header,
2616
2475
  main,
2617
- sidebar
2476
+ sidebar,
2477
+ mainFooter,
2478
+ mainHeader
2618
2479
  } = getSematicElements({
2619
2480
  children
2620
2481
  });
2621
- return /* @__PURE__ */jsx8(LayoutProvider, {
2482
+ return /* @__PURE__ */jsx10(LayoutProvider, {
2622
2483
  children: /* @__PURE__ */jsxs3(Stack, {
2623
2484
  ...props,
2624
2485
  sx: {
@@ -2634,7 +2495,14 @@ var SidebarCollapseLayout = ({
2634
2495
  overflow: "hidden",
2635
2496
  flexDirection: ["row"]
2636
2497
  },
2637
- children: [sidebar, main]
2498
+ children: [sidebar, /* @__PURE__ */jsxs3(Stack, {
2499
+ sx: {
2500
+ flex: 1,
2501
+ height: "full",
2502
+ overflow: "hidden"
2503
+ },
2504
+ children: [mainHeader, main, mainFooter]
2505
+ })]
2638
2506
  })]
2639
2507
  })
2640
2508
  });
@@ -2642,7 +2510,7 @@ var SidebarCollapseLayout = ({
2642
2510
 
2643
2511
  // src/components/StackedLayout.tsx
2644
2512
  import { Stack as Stack2 } from "@ttoss/ui";
2645
- import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
2513
+ import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
2646
2514
  var StackedLayout = ({
2647
2515
  children,
2648
2516
  ...props
@@ -2654,7 +2522,7 @@ var StackedLayout = ({
2654
2522
  } = getSematicElements({
2655
2523
  children
2656
2524
  });
2657
- return /* @__PURE__ */jsx9(LayoutProvider, {
2525
+ return /* @__PURE__ */jsx11(LayoutProvider, {
2658
2526
  children: /* @__PURE__ */jsxs4(Stack2, {
2659
2527
  ...props,
2660
2528
  children: [header, main, footer]
@@ -2674,6 +2542,6 @@ iconify-icon/dist/iconify-icon.mjs:
2674
2542
  * Licensed under MIT.
2675
2543
  *
2676
2544
  * @license MIT
2677
- * @version 2.2.0
2545
+ * @version 2.3.0
2678
2546
  *)
2679
2547
  */
package/dist/index.d.ts CHANGED
@@ -21,6 +21,14 @@ declare const Layout: {
21
21
  Main: {
22
22
  (props: BoxProps): react_jsx_runtime.JSX.Element;
23
23
  displayName: string;
24
+ Header: {
25
+ (props: BoxProps): react_jsx_runtime.JSX.Element;
26
+ displayName: string;
27
+ };
28
+ Footer: {
29
+ (props: BoxProps): react_jsx_runtime.JSX.Element;
30
+ displayName: string;
31
+ };
24
32
  };
25
33
  Footer: {
26
34
  (props: BoxProps): react_jsx_runtime.JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/layouts",
3
- "version": "0.4.36",
3
+ "version": "0.5.0",
4
4
  "description": "Layout components for React",
5
5
  "license": "MIT",
6
6
  "author": "ttoss",
@@ -25,8 +25,8 @@
25
25
  "sideEffects": false,
26
26
  "peerDependencies": {
27
27
  "react": ">=16.8.0",
28
- "@ttoss/components": "^2.2.25",
29
- "@ttoss/ui": "^5.9.1"
28
+ "@ttoss/components": "^2.2.26",
29
+ "@ttoss/ui": "^5.9.2"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/jest": "^30.0.0",
@@ -34,11 +34,11 @@
34
34
  "jest": "^30.0.4",
35
35
  "react": "^19.1.0",
36
36
  "tsup": "^8.5.0",
37
- "@ttoss/config": "^1.35.5",
38
- "@ttoss/test-utils": "^2.1.25",
39
- "@ttoss/ui": "^5.9.1",
40
- "@ttoss/react-icons": "^0.4.14",
41
- "@ttoss/components": "^2.2.25"
37
+ "@ttoss/components": "^2.2.26",
38
+ "@ttoss/config": "^1.35.6",
39
+ "@ttoss/react-icons": "^0.4.15",
40
+ "@ttoss/ui": "^5.9.2",
41
+ "@ttoss/test-utils": "^2.1.26"
42
42
  },
43
43
  "keywords": [
44
44
  "React"