Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/bottom-sheet-drag-close.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@astryxdesign/core': patch
---

[fix] BottomSheet: a sheet a touch drag closes leaves on its close spring, starting at the speed of the drag, and its scrim fades out with it on one clock, at the theme's tempo. A BottomSheetSwitcher flow's scrim does too. A mouse or pen drag is unchanged.

@vjeux
7 changes: 7 additions & 0 deletions .changeset/motion-settle-clock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@astryxdesign/core': patch
---

[chore] Internal: the motion foundation's `resolveSettleMs` gives a spring role's settling time at the theme's tempo, so a CSS part that plays with the spring can start and land with it. Not exported from the package entry point.

@vjeux
1 change: 1 addition & 0 deletions docs/specs/AST-094-touch-presentations/motion-roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The owner's goal: "The main goals are consistent timings and well-coordinated pi
| `springs.menuOpen` | spring | response 0.32 s, damping ratio 0.8 | `spec:AST-094` FR4 |
| `springs.quickChange` | spring | duration 0.5 s, bounce 0.15 | `spec:AST-094` FR4 |
| `springs.settle` | spring | duration 0.5 s, bounce 0 | `spec:AST-094` FR4 |
| `springs.sheetDismissSwipe` | spring | response 0.3441442326 s, damping ratio 0.8 | `component:BottomSheet` |
| `springs.sliderDrop` | spring | response 0.5 s, damping ratio 0.7 | `component:Slider` |
| `springs.sliderLift` | spring | response 0.215 s, damping ratio 0.6 | `component:Slider` |
| `springs.sliderRelease` | spring | response 0.4 s, damping ratio 1 | `component:Slider` |
Expand Down
4 changes: 2 additions & 2 deletions docs/specs/components/BottomSheet/BottomSheet.spec.md

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions packages/core/src/BottomSheet/BottomSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,37 @@ function scrimOpacityForView(view: BottomSheetStackView): '0' | '1' {
return view.isStacked && !view.ownsScrim ? '0' : '1';
}

/**
* Writes the fade a touch drag's close paces on `dialog`'s scrim, or clears
* it when `ms` is null. `written` keeps the value the host wrote, so a clear
* removes only that value.
*/
function writeScrimFadeDuration(
dialog: HTMLDialogElement | null,
ms: number | null,
written: {current: string | null},
): void {
if (dialog == null) {
return;
}
const current = dialog.style.getPropertyValue('--_sheet-scrim-duration');
if (ms == null) {
// Remove only the value this host wrote. A stack's 0s pin written since
// then stays.
if (written.current != null && current === written.current) {
dialog.style.removeProperty('--_sheet-scrim-duration');
}
written.current = null;
return;
}
// A stack's 0s pin hands the scrim over with no fade; it stays.
if (current === '0s') {
return;
}
written.current = `${ms}ms`;
dialog.style.setProperty('--_sheet-scrim-duration', written.current);
}

interface BottomSheetSharedProps extends BaseProps<HTMLDivElement> {
/** Ref forwarded to the visual sheet panel <div>. */
ref?: React.Ref<HTMLDivElement>;
Expand Down Expand Up @@ -544,6 +575,18 @@ function StandaloneBottomSheet({
String(opacity),
);
}, []);
// The fade duration a touch drag's close wrote, until that close ends.
const scrimFadeRef = useRef<string | null>(null);
const handleScrimFadeDuration = useCallback(
(panel: HTMLElement, ms: number | null) => {
const view = stackViewRef.current;
if (view.isStacked && !view.ownsScrim) {
return;
}
writeScrimFadeDuration(panel.closest('dialog'), ms, scrimFadeRef);
},
[],
);

// A sheet joins the registry for as long as it is presented. For a modal
// sheet the registry shows the dialog (in open order, repairing same-commit
Expand Down Expand Up @@ -946,6 +989,7 @@ function StandaloneBottomSheet({
xstyle={xstyle}
onDismiss={dismissOnLightInteraction}
onScrimOpacity={handleScrimOpacity}
onScrimFadeDuration={handleScrimFadeDuration}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the standalone host passes this. SwitcherBottomSheetItem's panel (around line 1326) plays the same drag exit with no fade handler, so after a touch drag closes a switcher flow the scrim clears on the stylesheet's 300 ms while the dialog stays up about 730 ms; in Chromium a tap on the page 450 ms after the release is lost (spec:AST-108 FR4a). Passing the same handler for the scrim-owning step, or having the panel write the fade on its own dialog, would cover both hosts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7ab8a89. The switcher step passes the same fade handler, and both hosts share one writer. A drag-closed switcher flow's scrim now fades with its 710 ms close instead of 300 ms (a new drag-exit unit case and a Chromium case cover it).

onElementChange={handlePanelElementChange}
onMotionStart={handleMotionStart}
onMotionComplete={handleMotionComplete}>
Expand Down Expand Up @@ -1095,6 +1139,16 @@ function SwitcherBottomSheetItem({
},
[hasValidSheetId, onSheetScrimOpacityChange, sheetId],
);
// The fade a touch drag's close wrote on this step's dialog, until that
// close ends. The step a drag closes becomes the flow's retained step, so
// its backdrop is the flow's scrim.
const scrimFadeRef = useRef<string | null>(null);
const handleScrimFadeDuration = useCallback(
(panel: HTMLElement, ms: number | null) => {
writeScrimFadeDuration(panel.closest('dialog'), ms, scrimFadeRef);
},
[],
);

useLayoutEffect(() => {
if (!hasValidSheetId) {
Expand Down Expand Up @@ -1297,6 +1351,7 @@ function SwitcherBottomSheetItem({
xstyle={xstyle}
onDismiss={dismissOnSwipe}
onScrimOpacity={handleScrimOpacity}
onScrimFadeDuration={handleScrimFadeDuration}
onElementChange={handlePanelElementChange}
onMotionStart={handleMotionStart}
onMotionComplete={handleMotionComplete}>
Expand Down
Loading
Loading