Repository navigation
fix(BottomSheet): resting content starts below the grab bar, whatever the padding #8558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a6642d3
c65c74a
812b064
1c54a3a
18aee67
1eb521c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| '@astryxdesign/core': patch | ||
| '@astryxdesign/cli': patch | ||
| --- | ||
|
|
||
| [feat] BottomSheet: at rest, a sheet's content starts below the grab bar whatever its `padding`, so the first line is no longer drawn through the bar's fade. The block-start inset is never less than the bar's height (`--spacing-6`): the band under the bar is not padding a child escapes, so a lone `Section` starts below the bar too; scrolled content still passes beneath it. A sheet at the default padding starts its content 8 px lower, one with `padding={0}` starts it below the bar, and one whose only child is a `Section` starts that Section 24 px lower and grows by the same amount. Core's own `padding={0}` sheets (the touch date and time pickers, DropdownMenu and ContextMenu sheets) no longer reserve that band themselves, so the pickers look the same and a menu's first row sits 8 px lower. The CLI's `table-filter` and `table-inbox` page templates drop their own band too, so it is not doubled. | ||
|
|
||
| @vjeux |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -120,14 +120,21 @@ pads caller content and publishes the applied inset. The inset resolves from the | |
| `padding` prop on the public spacing scale, then the theme's `padding` properties | ||
| on the `bottom-sheet` component, then `--spacing-4` on every logical edge, | ||
| matching Dialog. This prop and theme property are BottomSheet's projection of | ||
| container lowering. | ||
| container lowering. At the block start a sheet keeps a band under its floating | ||
| grab bar (`--spacing-6`) that is not container padding: it publishes only the | ||
| padding past that band and applies the band on top, so its applied block-start | ||
| inset is `max(padding, --spacing-6)` and a lone Section or Layout that escapes | ||
| the published padding still starts below the bar (`component:BottomSheet`, | ||
| Content area inset). | ||
|
|
||
| Edge compensation is a two-sided geometry contract, not a token contract: | ||
|
|
||
| 1. **Host side.** An eligible container or region state publishes the padding | ||
| currently available at each logical edge through the existing private | ||
| `--container-padding-*` variables. Those values must match that state's | ||
| applied padding and follow nesting and overlay reset; missing values mean zero. | ||
| applied padding, except BottomSheet's block start, which publishes only the | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this exception the host-side rule treats BottomSheet's block start as an intended split, but INV11 (line 289) still says a host state "whose published inset does not match its applied padding is ineligible until that conformance gap is fixed". Nothing compensates at a sheet's block start today, so behavior is unaffected; naming the exception in INV11 too, or saying the block start stays ineligible by design, would keep the record consistent for whoever approves it. |
||
| padding past its grab bar's band (above), and follow nesting and overlay | ||
| reset; missing values mean zero. | ||
| A state with a known publication mismatch is ineligible. Publication does not | ||
| itself opt a descendant into compensation. | ||
| 2. **Component side.** A participating component owns the inset retained around | ||
|
|
@@ -363,16 +370,16 @@ evidence, not part of this documentation stack. | |
|
|
||
| ## Verification | ||
|
|
||
| | Invariant | Evidence | Failure signal | | ||
| | ---------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | INV2, INV5 | `Section.test.tsx` per-edge and nested-propagation tests | A per-edge prop leaves a stale geometry variable, or nested Sections lose the shipped propagation order | | ||
| | INV2, INV3, INV8 | `ScrollableArea.test.tsx` padding and full-bleed tests | The content box publishes inset different from its applied padding, or the viewport escapes inherited padding without explicit full bleed | | ||
| | INV4 | Layout source review plus `Layout.test.tsx` and `LayoutSlots.test.tsx` | Slot presence stops selecting the shipped applied outer/inner edge styles; exact republished geometry remains limited by the named conformance gap | | ||
| | INV2 | `BottomSheetPanel.test.tsx` padding tests | The Content area publishes an inset that differs from its applied padding, or the `padding` prop or theme `padding` does not reach it | | ||
| | INV6 | `overlayPaddingReset.test.tsx` | An overlay inherits page inset, loses its theme's Section padding, or lets ancestor Section propagation cross the boundary | | ||
| | INV3, INV7 | `Layout/__tests__/edgeCompensation.test.tsx` plus component tests | An unmarked child is compensated, or marked edge content loses direct-child discoverability | | ||
| | INV9, INV10 | `List.test.tsx` plus real-browser geometry evidence | The header moves; a row reads the wrong logical edge, diverges from themed/density padding, applies the wrong bounded movement, or loses paint inset | | ||
| | INV10, INV11 | `TabList.test.tsx` plus real-browser overflow, divider, and indicator evidence | Full host-inset consumption, bounded content movement, divider span, interaction, focus, overflow, scroll controls, or indicator geometry regresses | | ||
| | Invariant | Evidence | Failure signal | | ||
| | ---------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | INV2, INV5 | `Section.test.tsx` per-edge and nested-propagation tests | A per-edge prop leaves a stale geometry variable, or nested Sections lose the shipped propagation order | | ||
| | INV2, INV3, INV8 | `ScrollableArea.test.tsx` padding and full-bleed tests | The content box publishes inset different from its applied padding, or the viewport escapes inherited padding without explicit full bleed | | ||
| | INV4 | Layout source review plus `Layout.test.tsx` and `LayoutSlots.test.tsx` | Slot presence stops selecting the shipped applied outer/inner edge styles; exact republished geometry remains limited by the named conformance gap | | ||
| | INV2 | `BottomSheetPanel.test.tsx` padding tests | The Content area publishes an inset that differs from its applied padding on any edge but the block start, its block start publishes more than the padding past the grab bar's band, or the `padding` prop or theme `padding` does not reach it | | ||
| | INV6 | `overlayPaddingReset.test.tsx` | An overlay inherits page inset, loses its theme's Section padding, or lets ancestor Section propagation cross the boundary | | ||
| | INV3, INV7 | `Layout/__tests__/edgeCompensation.test.tsx` plus component tests | An unmarked child is compensated, or marked edge content loses direct-child discoverability | | ||
| | INV9, INV10 | `List.test.tsx` plus real-browser geometry evidence | The header moves; a row reads the wrong logical edge, diverges from themed/density padding, applies the wrong bounded movement, or loses paint inset | | ||
| | INV10, INV11 | `TabList.test.tsx` plus real-browser overflow, divider, and indicator evidence | Full host-inset consumption, bounded content movement, divider span, interaction, focus, overflow, scroll controls, or indicator geometry regresses | | ||
|
|
||
| The List evidence must cover each `edge` value in its neutral root and in each | ||
| bounded host List admits (Card, Section, Dialog, BottomSheet), with the optional | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,7 +95,7 @@ export const docs = { | |
| derived: [{property: 'padding', expand: 'container'}], | ||
| }, | ||
| description: | ||
| "A mobile touch sheet that rises from the bottom edge, with animated entrance and exit, a grab handle, optional drag-to-resize snap points, and purpose-controlled dismissal. Like Dialog, it is a padded container: content starts at the theme's bottom-sheet padding (--spacing-4 by default), and a lone Section child or bleed children such as Table and Divider align against it. A sheet always owns a native <dialog>; inside the deprecated BottomSheetSwitcher the switcher presents and closes that dialog as the flow moves between steps. In both modes, ref and shared DOM props target the visual panel <div>. Sheets stack: a sheet opened while another is open sits on top of it, the covered sheet stays mounted and recedes, and one scrim covers the page. A sheet that closes as another opens in the same update is replaced by it, with the step-to-step handoff a multi-step flow needs.", | ||
| "A mobile touch sheet that rises from the bottom edge, with animated entrance and exit, a grab handle, optional drag-to-resize snap points, and purpose-controlled dismissal. Like Dialog, it is a padded container: content starts at the theme's bottom-sheet padding (--spacing-4 by default), and a lone Section child or bleed children such as Table and Divider align against it. At the top the content always starts below the grab bar's 24px band, which is not padding a child escapes, so the first row never sits under the bar; scrolled content passes beneath it. A sheet always owns a native <dialog>; inside the deprecated BottomSheetSwitcher the switcher presents and closes that dialog as the flow moves between steps. In both modes, ref and shared DOM props target the visual panel <div>. Sheets stack: a sheet opened while another is open sits on top of it, the covered sheet stays mounted and recedes, and one scrim covers the page. A sheet that closes as another opens in the same update is replaced by it, with the step-to-step handoff a multi-step flow needs.", | ||
| props: [ | ||
| { | ||
| name: 'isOpen', | ||
|
|
@@ -146,7 +146,7 @@ export const docs = { | |
| name: 'padding', | ||
| type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10', | ||
| description: | ||
| 'Internal padding of the sheet content using the spacing scale, matching Dialog. When omitted, uses the theme default for bottom sheets (--spacing-4 unless the theme sets padding on bottom-sheet). A lone Section child escapes the padding, and bleed children such as Table and Divider compensate against it. Use 0 for edge-to-edge content that supplies its own inset.', | ||
| "Internal padding of the sheet content using the spacing scale, matching Dialog. When omitted, uses the theme default for bottom sheets (--spacing-4 unless the theme sets padding on bottom-sheet). A lone Section child escapes the padding, and bleed children such as Table and Divider compensate against it. Use 0 for edge-to-edge content that supplies its own inset. Whatever the padding, the block-start inset is never less than the grab bar's height (--spacing-6), so resting content starts below the bar.", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The component description at line 98 still says 'content starts at the theme's bottom-sheet padding (--spacing-4 by default)', and the Container Padding story still says ' |
||
| }, | ||
| { | ||
| name: 'height', | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This paragraph now says the block start publishes only the padding past the band, but the INV2 verification row further down (line 376) still fails BottomSheet when "The Content area publishes an inset that differs from its applied padding". Could it get the same band exception FR4's row now has, e.g. "…on an edge other than the block start, its block start publishes more than the padding past the grab bar's band, or…"?