ab-nextjs-core 0.1.4 โ†’ 0.1.6

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.
@@ -24,7 +24,7 @@
24
24
  * SOFTWARE.
25
25
  *
26
26
  * @project: ab-nextjs-core
27
- * @authors: Abraham Ukachi <abraham.ukachi@laplateforme.io>
27
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
28
28
  */
29
29
 
30
30
  /*
@@ -37,6 +37,10 @@ import type { ReactElement, ReactNode } from 'react';
37
37
  import clsx from 'clsx';
38
38
  import AbLinearProgress from '../../ab-linear-progress';
39
39
  import styles from './styles.module.css';
40
+ // ๐Ÿซฅ G52: empty-slot helper (strings get a <span>, so the :has() collapse never hides text)
41
+ import { toAbSlot } from '../../ab-page-provider/slot';
42
+ // ๐Ÿ“Œ G55 (Joseph): client island that publishes this pane's scroller on useAbPage()
43
+ import AbScrollRegistrar from '../../ab-page-provider/scroll-registrar';
40
44
 
41
45
  export interface AbMainLayoutProps {
42
46
  orientation: 'vertical' | 'horizontal';
@@ -44,11 +48,22 @@ export interface AbMainLayoutProps {
44
48
  hidden?: boolean;
45
49
  pageName?: string;
46
50
  screenName?: string;
51
+ /** ๐Ÿ” 0.1.6 (G52): the main pane's header slot (data-ab-part="main-header"); 0px and not rendered when empty. */
52
+ mainHeader?: ReactNode;
53
+ /** ๐Ÿ”š 0.1.6 (G52): the main pane's bottom bar slot (data-ab-part="main-bar"); 0px and not rendered when empty. */
54
+ mainBar?: ReactNode;
55
+ /** @deprecated 0.1.6: use `mainHeader` (kept as an alias for one minor). */
47
56
  header?: ReactNode;
48
57
  content?: ReactNode;
58
+ /** @deprecated 0.1.6: use `mainBar` (kept as an alias for one minor). */
49
59
  footer?: ReactNode;
50
60
  children?: ReactNode;
51
61
  menus?: ReactNode;
62
+ /** ๐Ÿ†” 0.1.6: element id (e.g. the skip-link target), no inner wrapper needed. */
63
+ id?: string;
64
+ /** @deprecated 0.1.6: `false` drops the legacy backdrop / menus / dialogs / toasts / progress / canvas layers.
65
+ * Empty header / bar slots are never rendered any more, so this only gates those layers (default `true`). */
66
+ chrome?: boolean;
52
67
  }
53
68
 
54
69
  /**
@@ -60,14 +75,22 @@ const AbMainLayout = ({
60
75
  hidden,
61
76
  pageName,
62
77
  screenName,
63
- header,
78
+ mainHeader,
79
+ mainBar,
80
+ header, // ๐Ÿ•ฐ๏ธ deprecated alias
64
81
  content,
65
- footer,
82
+ footer, // ๐Ÿ•ฐ๏ธ deprecated alias
66
83
  children,
67
84
  menus,
85
+ id, // ๐Ÿ†”
86
+ chrome = true, // ๐Ÿงฐ
68
87
  }: AbMainLayoutProps): ReactElement => {
88
+ // ๐Ÿ”๐Ÿ”š G52: the new slot names win, the 0.1.5 names still work
89
+ const top = toAbSlot(mainHeader ?? header);
90
+ const bar = toAbSlot(mainBar ?? footer);
69
91
  return (
70
92
  <main
93
+ id={id} // ๐Ÿ†” 0.1.6
71
94
  className={clsx(
72
95
  ['AbMainLayout', 'group-mainLayout', styles.abMainLayout, className],
73
96
  { 'has-screen-name': !!screenName },
@@ -78,9 +101,11 @@ const AbMainLayout = ({
78
101
  data-ab-part="main"
79
102
  data-screen-name={screenName}
80
103
  >
81
- <header className={clsx(['HeaderWrapper', styles.abMainLayout__headerWrapper])}>
82
- {header}
83
- </header>
104
+ {top != null && ( // ๐Ÿซฅ not rendered when empty (D37)
105
+ <header className={clsx(['HeaderWrapper', styles.abMainLayout__headerWrapper])} data-ab-part="main-header">
106
+ {top}
107
+ </header>
108
+ )}
84
109
 
85
110
  <div
86
111
  className={clsx([
@@ -88,31 +113,40 @@ const AbMainLayout = ({
88
113
  styles.abMainLayout__contentWrapper,
89
114
  orientation === 'horizontal' && 'md:!flex-row',
90
115
  ])}
116
+ data-ab-part="main-content" // ๐Ÿ“œ G51/G55: THE scroller of this pane (useAbScrollSpy root)
91
117
  data-orientation={orientation ? orientation.toString() : undefined}
92
118
  >
119
+ {/* ๐Ÿ“œ sets mainScrollElement (server components can't hold refs) */}
120
+ <AbScrollRegistrar pane="main" />
93
121
  {content ?? children}
94
122
  </div>
95
123
 
96
- <footer className={clsx(['FooterWrapper', styles.abMainLayout__footerWrapper])}>
97
- {footer}
98
- </footer>
99
-
100
- <div className={clsx(['Backdrop', styles.abMainLayout__backdrop])} hidden />
101
- <div className={clsx(['Menus', styles.abMainLayout__menus])} hidden>
102
- {menus}
103
- </div>
104
- <div className={clsx(['Dialogs', styles.abMainLayout__dialogs])} hidden />
105
- <div className={clsx(['Toasts', styles.abMainLayout__toasts])} hidden />
106
-
107
- <AbLinearProgress
108
- className="absolute top-0 left-0 right-0 z-50 !w-1/2 place-self-center !my-1 3xl:!my-2 !mx-auto !h-0.5 lg:!h-1 3xl:!h-1.5"
109
- color="secondary"
110
- hidden={true}
111
- isIndeterminate={true}
112
- progress={25}
113
- />
124
+ {bar != null && ( // ๐Ÿซฅ not rendered when empty (D37)
125
+ <footer className={clsx(['FooterWrapper', styles.abMainLayout__footerWrapper])} data-ab-part="main-bar">
126
+ {bar}
127
+ </footer>
128
+ )}
114
129
 
115
- <canvas className={clsx(['Canvas', styles.abMainLayout__canvas])} />
130
+ {chrome && ( // ๐Ÿงฐ 0.1.6: legacy layers
131
+ <>
132
+ <div className={clsx(['Backdrop', styles.abMainLayout__backdrop])} hidden />
133
+ <div className={clsx(['Menus', styles.abMainLayout__menus])} hidden>
134
+ {menus}
135
+ </div>
136
+ <div className={clsx(['Dialogs', styles.abMainLayout__dialogs])} hidden />
137
+ <div className={clsx(['Toasts', styles.abMainLayout__toasts])} hidden />
138
+
139
+ <AbLinearProgress
140
+ className="absolute top-0 left-0 right-0 z-50 !w-1/2 place-self-center !my-1 3xl:!my-2 !mx-auto !h-0.5 lg:!h-1 3xl:!h-1.5"
141
+ color="secondary"
142
+ hidden={true}
143
+ isIndeterminate={true}
144
+ progress={25}
145
+ />
146
+
147
+ <canvas className={clsx(['Canvas', styles.abMainLayout__canvas])} />
148
+ </>
149
+ )}
116
150
  </main>
117
151
  );
118
152
  };
@@ -27,7 +27,7 @@
27
27
  * @name: AB Main Layout - Component Stylesheet (plain CSS, Tailwind-independent)
28
28
  * @file: server/ab-main-layout/styles.module.css
29
29
  * @type: CSS Module
30
- * @authors: Abraham Ukachi <abraham.ukachi@laplateforme.io>
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
31
  */
32
32
 
33
33
  /*
@@ -165,3 +165,45 @@
165
165
  from { opacity: 0; }
166
166
  to { opacity: 1; }
167
167
  }
168
+
169
+ /* ================================================================== */
170
+ /* ๐Ÿ“ 0.1.6 layout rule (G51 + G52 + G54): a bounded box whose CONTENT */
171
+ /* scrolls on its own; main-header / main-bar collapse when empty */
172
+ /* ================================================================== */
173
+ /* ๐Ÿซฅ D37: an empty slot is 0px (also outside panes: an empty wrapper had no size anyway) */
174
+ .abMainLayout__headerWrapper:empty,
175
+ .abMainLayout__footerWrapper:empty,
176
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout__headerWrapper:not(:has(> *)),
177
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout__footerWrapper:not(:has(> *)) {
178
+ display: none; /* ๐Ÿ“ 0px, and no footer gradient */
179
+ }
180
+ /* ๐Ÿงญ inside AbAppLayout variant="panes": a full-height column, only the content wrapper scrolls */
181
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout {
182
+ height: 100%; /* ๐Ÿ“ the pane */
183
+ min-height: 0; /* ๐Ÿšซ */
184
+ max-height: none; /* ๐Ÿงน the legacy 100vh caps */
185
+ overflow: hidden; /* ๐Ÿ”’ */
186
+ display: flex; /* ๐Ÿงฑ header ยท content ยท bar */
187
+ flex-direction: column;
188
+ margin: 0; /* ๐Ÿงน legacy 2xl margins */
189
+ }
190
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout__headerWrapper,
191
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout__footerWrapper {
192
+ flex: none; /* ๐Ÿ“ rows size to their content: no hard-coded heights */
193
+ pointer-events: auto; /* ๐Ÿ–ฑ๏ธ real chrome, not an overlay */
194
+ }
195
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout__footerWrapper {
196
+ padding-bottom: env(safe-area-inset-bottom, 0px); /* ๐Ÿ“ฑ home indicator */
197
+ }
198
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout__footerWrapper::before {
199
+ content: none; /* ๐Ÿงน no gradient over the scroller */
200
+ }
201
+ :global(.AbAppLayout[data-variant="panes"]) .abMainLayout__contentWrapper {
202
+ flex: 1 1 0; /* โ†•๏ธ the rest */
203
+ height: auto; /* ๐Ÿ“ */
204
+ min-height: 0; /* ๐Ÿšซ lets it scroll */
205
+ overflow: hidden auto; /* ๐Ÿ“œ THE scroller of this pane */
206
+ overscroll-behavior: contain; /* ๐Ÿšซ never chains to the page (G54) */
207
+ scrollbar-gutter: stable; /* ๐Ÿ“ no layout jump */
208
+ justify-content: flex-start; /* โฌ†๏ธ */
209
+ }
@@ -24,7 +24,7 @@
24
24
  * SOFTWARE.
25
25
  *
26
26
  * @project: ab-nextjs-core
27
- * @authors: Abraham Ukachi <abraham.ukachi@laplateforme.io>
27
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
28
28
  */
29
29
 
30
30
  /*
@@ -72,7 +72,7 @@ const AbScreenLayout = ({
72
72
  data-screen-name={screenName}
73
73
  data-orientation={orientation ?? ''}
74
74
  >
75
- <header className={clsx(['HeaderWrapper', styles.abScreenLayout__headerWrapper])}>
75
+ <header className={clsx(['HeaderWrapper', styles.abScreenLayout__headerWrapper])} data-ab-part="header">
76
76
  {header}
77
77
  </header>
78
78
 
@@ -80,7 +80,7 @@ const AbScreenLayout = ({
80
80
  {content ?? children}
81
81
  </div>
82
82
 
83
- <footer className={clsx(['FooterWrapper', styles.abScreenLayout__footerWrapper])}>
83
+ <footer className={clsx(['FooterWrapper', styles.abScreenLayout__footerWrapper])} data-ab-part="footer">
84
84
  {footer}
85
85
  </footer>
86
86
 
@@ -27,7 +27,7 @@
27
27
  * @name: AB Screen Layout - Component Stylesheet (plain CSS, Tailwind-independent)
28
28
  * @file: server/ab-screen-layout/styles.module.css
29
29
  * @type: CSS Module
30
- * @authors: Abraham Ukachi <abraham.ukachi@laplateforme.io>
30
+ * @authors: Abraham Ukachi <abrahamukachi@gmail.com>
31
31
  */
32
32
 
33
33
  /*