|
| 1 | +import type {Meta, StoryFn} from '@storybook/react-vite' |
| 2 | +import {Placeholder} from '../Placeholder' |
| 3 | +import {PageLayout} from './PageLayout' |
| 4 | + |
| 5 | +const meta: Meta = { |
| 6 | + title: 'Components/PageLayout/Responsive Variants', |
| 7 | + parameters: { |
| 8 | + layout: 'fullscreen', |
| 9 | + controls: {expanded: true}, |
| 10 | + }, |
| 11 | +} |
| 12 | + |
| 13 | +export default meta |
| 14 | + |
| 15 | +/** |
| 16 | + * Test responsive divider variants on Header. |
| 17 | + * Resize the viewport to see different divider styles at different breakpoints. |
| 18 | + */ |
| 19 | +export const HeaderDividerResponsive: StoryFn = () => ( |
| 20 | + <PageLayout> |
| 21 | + <PageLayout.Header divider={{narrow: 'filled', regular: 'line', wide: 'none'}}> |
| 22 | + <Placeholder height={64} label="Header with responsive divider: filled (narrow) → line (regular) → none (wide)" /> |
| 23 | + </PageLayout.Header> |
| 24 | + <PageLayout.Content> |
| 25 | + <Placeholder height={400} label="Content" /> |
| 26 | + </PageLayout.Content> |
| 27 | + </PageLayout> |
| 28 | +) |
| 29 | + |
| 30 | +HeaderDividerResponsive.parameters = { |
| 31 | + docs: { |
| 32 | + description: { |
| 33 | + story: |
| 34 | + 'The header divider changes based on viewport width: **filled** on narrow viewports (< 768px), **line** on regular viewports (>= 768px), and **none** on wide viewports (>= 1400px).', |
| 35 | + }, |
| 36 | + }, |
| 37 | +} |
| 38 | + |
| 39 | +/** |
| 40 | + * Test responsive hidden state on Header. |
| 41 | + * Resize the viewport to see the header hide/show at different breakpoints. |
| 42 | + */ |
| 43 | +export const HeaderHiddenResponsive: StoryFn = () => ( |
| 44 | + <PageLayout> |
| 45 | + <PageLayout.Header hidden={{narrow: true, regular: false, wide: false}}> |
| 46 | + <Placeholder height={64} label="Header (hidden on narrow viewports)" /> |
| 47 | + </PageLayout.Header> |
| 48 | + <PageLayout.Content> |
| 49 | + <Placeholder height={400} label="Content" /> |
| 50 | + </PageLayout.Content> |
| 51 | + </PageLayout> |
| 52 | +) |
| 53 | + |
| 54 | +HeaderHiddenResponsive.parameters = { |
| 55 | + docs: { |
| 56 | + description: { |
| 57 | + story: |
| 58 | + 'The header is **hidden** on narrow viewports (< 768px) and **visible** on regular and wide viewports (>= 768px).', |
| 59 | + }, |
| 60 | + }, |
| 61 | +} |
| 62 | + |
| 63 | +/** |
| 64 | + * Test responsive divider variants on Footer. |
| 65 | + * Resize the viewport to see different divider styles at different breakpoints. |
| 66 | + */ |
| 67 | +export const FooterDividerResponsive: StoryFn = () => ( |
| 68 | + <PageLayout> |
| 69 | + <PageLayout.Content> |
| 70 | + <Placeholder height={400} label="Content" /> |
| 71 | + </PageLayout.Content> |
| 72 | + <PageLayout.Footer divider={{narrow: 'filled', regular: 'line', wide: 'none'}}> |
| 73 | + <Placeholder height={64} label="Footer with responsive divider: filled (narrow) → line (regular) → none (wide)" /> |
| 74 | + </PageLayout.Footer> |
| 75 | + </PageLayout> |
| 76 | +) |
| 77 | + |
| 78 | +FooterDividerResponsive.parameters = { |
| 79 | + docs: { |
| 80 | + description: { |
| 81 | + story: |
| 82 | + 'The footer divider changes based on viewport width: **filled** on narrow viewports (< 768px), **line** on regular viewports (>= 768px), and **none** on wide viewports (>= 1400px).', |
| 83 | + }, |
| 84 | + }, |
| 85 | +} |
| 86 | + |
| 87 | +/** |
| 88 | + * Test responsive hidden state on Footer. |
| 89 | + * Resize the viewport to see the footer hide/show at different breakpoints. |
| 90 | + */ |
| 91 | +export const FooterHiddenResponsive: StoryFn = () => ( |
| 92 | + <PageLayout> |
| 93 | + <PageLayout.Content> |
| 94 | + <Placeholder height={400} label="Content" /> |
| 95 | + </PageLayout.Content> |
| 96 | + <PageLayout.Footer hidden={{narrow: false, regular: false, wide: true}}> |
| 97 | + <Placeholder height={64} label="Footer (hidden on wide viewports)" /> |
| 98 | + </PageLayout.Footer> |
| 99 | + </PageLayout> |
| 100 | +) |
| 101 | + |
| 102 | +FooterHiddenResponsive.parameters = { |
| 103 | + docs: { |
| 104 | + description: { |
| 105 | + story: 'The footer is **visible** on narrow and regular viewports and **hidden** on wide viewports (>= 1400px).', |
| 106 | + }, |
| 107 | + }, |
| 108 | +} |
| 109 | + |
| 110 | +/** |
| 111 | + * Test responsive hidden state on Content. |
| 112 | + * Resize the viewport to see the content hide/show at different breakpoints. |
| 113 | + */ |
| 114 | +export const ContentHiddenResponsive: StoryFn = () => ( |
| 115 | + <PageLayout> |
| 116 | + <PageLayout.Header> |
| 117 | + <Placeholder height={64} label="Header" /> |
| 118 | + </PageLayout.Header> |
| 119 | + <PageLayout.Content hidden={{narrow: true, regular: false, wide: false}}> |
| 120 | + <Placeholder height={400} label="Content (hidden on narrow viewports)" /> |
| 121 | + </PageLayout.Content> |
| 122 | + <PageLayout.Pane> |
| 123 | + <Placeholder height={200} label="Pane" /> |
| 124 | + </PageLayout.Pane> |
| 125 | + </PageLayout> |
| 126 | +) |
| 127 | + |
| 128 | +ContentHiddenResponsive.parameters = { |
| 129 | + docs: { |
| 130 | + description: { |
| 131 | + story: |
| 132 | + 'The content is **hidden** on narrow viewports (< 768px) and **visible** on regular and wide viewports (>= 768px).', |
| 133 | + }, |
| 134 | + }, |
| 135 | +} |
| 136 | + |
| 137 | +/** |
| 138 | + * Test responsive position on Pane. |
| 139 | + * Resize the viewport to see the pane move between start and end positions. |
| 140 | + */ |
| 141 | +export const PanePositionResponsive: StoryFn = () => ( |
| 142 | + <PageLayout> |
| 143 | + <PageLayout.Header> |
| 144 | + <Placeholder height={64} label="Header" /> |
| 145 | + </PageLayout.Header> |
| 146 | + <PageLayout.Content> |
| 147 | + <Placeholder height={400} label="Content" /> |
| 148 | + </PageLayout.Content> |
| 149 | + <PageLayout.Pane position={{narrow: 'end', regular: 'start', wide: 'end'}}> |
| 150 | + <Placeholder height={200} label="Pane with responsive position: end (narrow) → start (regular) → end (wide)" /> |
| 151 | + </PageLayout.Pane> |
| 152 | + </PageLayout> |
| 153 | +) |
| 154 | + |
| 155 | +PanePositionResponsive.parameters = { |
| 156 | + docs: { |
| 157 | + description: { |
| 158 | + story: |
| 159 | + 'The pane position changes based on viewport width: **end** on narrow viewports (< 768px), **start** on regular viewports (768px - 1399px), and **end** on wide viewports (>= 1400px).', |
| 160 | + }, |
| 161 | + }, |
| 162 | +} |
| 163 | + |
| 164 | +/** |
| 165 | + * Test responsive divider variants on Pane. |
| 166 | + * Resize the viewport to see different divider styles at different breakpoints. |
| 167 | + */ |
| 168 | +export const PaneDividerResponsive: StoryFn = () => ( |
| 169 | + <PageLayout> |
| 170 | + <PageLayout.Content> |
| 171 | + <Placeholder height={400} label="Content" /> |
| 172 | + </PageLayout.Content> |
| 173 | + <PageLayout.Pane divider={{narrow: 'filled', regular: 'line', wide: 'none'}}> |
| 174 | + <Placeholder height={200} label="Pane with responsive divider: filled (narrow) → line (regular) → none (wide)" /> |
| 175 | + </PageLayout.Pane> |
| 176 | + </PageLayout> |
| 177 | +) |
| 178 | + |
| 179 | +PaneDividerResponsive.parameters = { |
| 180 | + docs: { |
| 181 | + description: { |
| 182 | + story: |
| 183 | + 'The pane divider changes based on viewport width: **filled** on narrow viewports (< 768px), **line** on regular viewports (>= 768px), and **none** on wide viewports (>= 1400px).', |
| 184 | + }, |
| 185 | + }, |
| 186 | +} |
| 187 | + |
| 188 | +/** |
| 189 | + * Test responsive hidden state on Pane. |
| 190 | + * Resize the viewport to see the pane hide/show at different breakpoints. |
| 191 | + */ |
| 192 | +export const PaneHiddenResponsive: StoryFn = () => ( |
| 193 | + <PageLayout> |
| 194 | + <PageLayout.Content> |
| 195 | + <Placeholder height={400} label="Content" /> |
| 196 | + </PageLayout.Content> |
| 197 | + <PageLayout.Pane hidden={{narrow: false, regular: true, wide: false}}> |
| 198 | + <Placeholder height={200} label="Pane (hidden on regular viewports)" /> |
| 199 | + </PageLayout.Pane> |
| 200 | + </PageLayout> |
| 201 | +) |
| 202 | + |
| 203 | +PaneHiddenResponsive.parameters = { |
| 204 | + docs: { |
| 205 | + description: { |
| 206 | + story: |
| 207 | + 'The pane is **visible** on narrow and wide viewports and **hidden** on regular viewports (768px - 1399px).', |
| 208 | + }, |
| 209 | + }, |
| 210 | +} |
| 211 | + |
| 212 | +/** |
| 213 | + * Test all responsive variants together in a complex layout. |
| 214 | + * This story demonstrates multiple responsive properties working together. |
| 215 | + */ |
| 216 | +export const ComplexResponsiveLayout: StoryFn = () => ( |
| 217 | + <PageLayout> |
| 218 | + <PageLayout.Header |
| 219 | + divider={{narrow: 'filled', regular: 'line', wide: 'none'}} |
| 220 | + hidden={{narrow: false, regular: false, wide: false}} |
| 221 | + > |
| 222 | + <Placeholder height={64} label="Header with responsive divider" /> |
| 223 | + </PageLayout.Header> |
| 224 | + <PageLayout.Content hidden={{narrow: false, regular: false, wide: false}}> |
| 225 | + <Placeholder height={400} label="Content" /> |
| 226 | + </PageLayout.Content> |
| 227 | + <PageLayout.Pane |
| 228 | + position={{narrow: 'end', regular: 'start', wide: 'start'}} |
| 229 | + divider={{narrow: 'filled', regular: 'line', wide: 'line'}} |
| 230 | + hidden={{narrow: false, regular: false, wide: false}} |
| 231 | + > |
| 232 | + <Placeholder height={200} label="Pane with responsive position and divider" /> |
| 233 | + </PageLayout.Pane> |
| 234 | + <PageLayout.Footer divider={{narrow: 'filled', regular: 'line', wide: 'none'}}> |
| 235 | + <Placeholder height={64} label="Footer with responsive divider" /> |
| 236 | + </PageLayout.Footer> |
| 237 | + </PageLayout> |
| 238 | +) |
| 239 | + |
| 240 | +ComplexResponsiveLayout.parameters = { |
| 241 | + docs: { |
| 242 | + description: { |
| 243 | + story: |
| 244 | + 'A complex layout demonstrating multiple responsive properties working together. Resize the viewport to see how all the responsive variants change at different breakpoints.', |
| 245 | + }, |
| 246 | + }, |
| 247 | +} |
| 248 | + |
| 249 | +/** |
| 250 | + * Test responsive behavior with backward compatibility props. |
| 251 | + * This ensures the deprecated props still work correctly. |
| 252 | + */ |
| 253 | +export const BackwardCompatibilityTest: StoryFn = () => ( |
| 254 | + <PageLayout> |
| 255 | + <PageLayout.Header divider="line" dividerWhenNarrow="filled"> |
| 256 | + <Placeholder height={64} label="Header using deprecated dividerWhenNarrow prop" /> |
| 257 | + </PageLayout.Header> |
| 258 | + <PageLayout.Content> |
| 259 | + <Placeholder height={400} label="Content" /> |
| 260 | + </PageLayout.Content> |
| 261 | + <PageLayout.Pane position="start" positionWhenNarrow="end" divider="line" dividerWhenNarrow="filled"> |
| 262 | + <Placeholder height={200} label="Pane using deprecated positionWhenNarrow and dividerWhenNarrow props" /> |
| 263 | + </PageLayout.Pane> |
| 264 | + <PageLayout.Footer divider="line" dividerWhenNarrow="filled"> |
| 265 | + <Placeholder height={64} label="Footer using deprecated dividerWhenNarrow prop" /> |
| 266 | + </PageLayout.Footer> |
| 267 | + </PageLayout> |
| 268 | +) |
| 269 | + |
| 270 | +BackwardCompatibilityTest.parameters = { |
| 271 | + docs: { |
| 272 | + description: { |
| 273 | + story: |
| 274 | + 'Tests backward compatibility with deprecated props like `dividerWhenNarrow` and `positionWhenNarrow`. These should still work correctly alongside the new responsive value format.', |
| 275 | + }, |
| 276 | + }, |
| 277 | +} |
| 278 | + |
| 279 | +/** |
| 280 | + * Test SSR-safe responsive behavior. |
| 281 | + * This story ensures no layout shift occurs during hydration. |
| 282 | + */ |
| 283 | +export const SSRSafeResponsive: StoryFn = () => ( |
| 284 | + <PageLayout> |
| 285 | + <PageLayout.Header divider={{narrow: 'filled', regular: 'line'}}> |
| 286 | + <Placeholder height={64} label="SSR-safe: No layout shift - responsive behavior handled by CSS media queries" /> |
| 287 | + </PageLayout.Header> |
| 288 | + <PageLayout.Content> |
| 289 | + <Placeholder height={400} label="Content" /> |
| 290 | + </PageLayout.Content> |
| 291 | + <PageLayout.Pane position={{narrow: 'end', regular: 'start'}} divider={{narrow: 'filled', regular: 'line'}}> |
| 292 | + <Placeholder height={200} label="Pane with SSR-safe responsive properties" /> |
| 293 | + </PageLayout.Pane> |
| 294 | + </PageLayout> |
| 295 | +) |
| 296 | + |
| 297 | +SSRSafeResponsive.parameters = { |
| 298 | + docs: { |
| 299 | + description: { |
| 300 | + story: |
| 301 | + 'Demonstrates SSR-safe responsive behavior. All responsive values are now handled through CSS data attributes and media queries, preventing layout shift during hydration. This follows ADR-018 for responsive values.', |
| 302 | + }, |
| 303 | + }, |
| 304 | +} |
0 commit comments