From 14ec96f0e2a0ebe3289c52cf7e818ca3f3a661b9 Mon Sep 17 00:00:00 2001 From: ENvironmentSet Date: Fri, 23 Oct 2026 20:00:03 +0900 Subject: [PATCH] fix(plugin-basic-ui): respect modal and bottom sheet safe areas --- .changeset/tidy-modals-respect-insets.md | 5 +++++ .../plugins/plugin-basic-ui.en.mdx | 6 ++++++ .../plugins/plugin-basic-ui.ko.mdx | 6 ++++++ .../src/components/BottomSheet.css.ts | 13 +++++++++++++ .../plugin-basic-ui/src/components/Modal.css.ts | 17 +++++++++++++++++ 5 files changed, 47 insertions(+) create mode 100644 .changeset/tidy-modals-respect-insets.md diff --git a/.changeset/tidy-modals-respect-insets.md b/.changeset/tidy-modals-respect-insets.md new file mode 100644 index 000000000..48040929d --- /dev/null +++ b/.changeset/tidy-modals-respect-insets.md @@ -0,0 +1,5 @@ +--- +"@stackflow/plugin-basic-ui": patch +--- + +Center Modal within the safe area while preserving its margins and full-screen backdrop. Add left, right, and bottom safe area padding to BottomSheet content while keeping its background full-width and bottom-aligned. Remove any duplicate safe area adjustments from children when upgrading. diff --git a/docs/pages/api-references/plugins/plugin-basic-ui.en.mdx b/docs/pages/api-references/plugins/plugin-basic-ui.en.mdx index 1f8f4d19b..e2a9fe04f 100644 --- a/docs/pages/api-references/plugins/plugin-basic-ui.en.mdx +++ b/docs/pages/api-references/plugins/plugin-basic-ui.en.mdx @@ -77,6 +77,12 @@ const Something = () => { `AppScreen` automatically applies the device's left and right safe area insets to its content and app bar in both themes. The Cupertino title is centered within the safe area. Backgrounds and navigation transitions still span the full screen. +`Modal` is centered within the area remaining after the top, right, bottom, and left safe area insets are excluded. Its existing `2.5rem` horizontal margins and `maxWidth` still apply within that area, while the dimmed backdrop covers the full screen. + +`BottomSheet` keeps its background at the bottom of the screen and spans the full width. It applies the left, right, and bottom safe area insets as internal padding, in addition to any padding on its children. It does not apply the top inset. + +If children already apply safe area insets, remove only the adjustments duplicated by the component: all four sides for `Modal`, and the left, right, and bottom for `BottomSheet`. Keep any regular content padding and any existing top inset handling in `BottomSheet` children. + Include `viewport-fit=cover` in the viewport meta tag so the browser exposes the safe area insets. ```html copy diff --git a/docs/pages/api-references/plugins/plugin-basic-ui.ko.mdx b/docs/pages/api-references/plugins/plugin-basic-ui.ko.mdx index 0692b9b2f..c56112244 100644 --- a/docs/pages/api-references/plugins/plugin-basic-ui.ko.mdx +++ b/docs/pages/api-references/plugins/plugin-basic-ui.ko.mdx @@ -75,6 +75,12 @@ const Something = () => { `AppScreen`은 두 테마 모두에서 본문과 앱 바에 기기의 좌우 Safe Area Inset을 자동으로 반영해요. Cupertino 제목은 안전 영역 안에서 가운데에 배치돼요. 배경과 화면 전환은 화면 전체 너비를 유지해요. +`Modal`은 상하좌우 Safe Area Inset을 제외한 안전 영역의 가운데에 배치돼요. 기존 좌우 `2.5rem` 마진과 `maxWidth`는 안전 영역 안에서 그대로 적용되고, dim 배경은 화면 전체를 덮어요. + +`BottomSheet` 배경은 화면 전체 너비와 하단 위치를 유지해요. 내부에는 좌우와 하단 Safe Area Inset을 패딩으로 적용하며, 자식 요소의 기존 패딩은 그 안에 추가로 유지돼요. 상단 Inset은 적용하지 않아요. + +자식 요소에서 이미 Safe Area Inset을 적용하고 있다면, 컴포넌트가 자동 적용하는 방향과 중복되는 처리만 제거해 주세요. `Modal`은 상하좌우, `BottomSheet`는 좌우와 하단이 대상이에요. 일반적인 콘텐츠 패딩과 `BottomSheet` 자식의 기존 상단 Inset 처리는 유지해 주세요. + 브라우저가 Safe Area Inset을 제공하도록 viewport 메타 태그에 `viewport-fit=cover`를 포함해 주세요. ```html copy diff --git a/extensions/plugin-basic-ui/src/components/BottomSheet.css.ts b/extensions/plugin-basic-ui/src/components/BottomSheet.css.ts index 2783436b3..07fc7c500 100644 --- a/extensions/plugin-basic-ui/src/components/BottomSheet.css.ts +++ b/extensions/plugin-basic-ui/src/components/BottomSheet.css.ts @@ -56,9 +56,22 @@ export const dim = style([ ]); export const paper = style([ + f.borderBox, f.overflowHidden, allTransitions, { + paddingRight: [ + "constant(safe-area-inset-right)", + "env(safe-area-inset-right, 0px)", + ], + paddingBottom: [ + "constant(safe-area-inset-bottom)", + "env(safe-area-inset-bottom, 0px)", + ], + paddingLeft: [ + "constant(safe-area-inset-left)", + "env(safe-area-inset-left, 0px)", + ], backgroundColor: globalVars.backgroundColor, backgroundImage: globalVars.backgroundImage, width: "100%", diff --git a/extensions/plugin-basic-ui/src/components/Modal.css.ts b/extensions/plugin-basic-ui/src/components/Modal.css.ts index 75e48389a..657a07a5a 100644 --- a/extensions/plugin-basic-ui/src/components/Modal.css.ts +++ b/extensions/plugin-basic-ui/src/components/Modal.css.ts @@ -37,11 +37,28 @@ export const container = recipe({ export const dim = style([ f.posAbsFull, + f.borderBox, f.overflowHidden, f.flexAlignCenter, f.flexJustifyCenter, allTransitions, { + paddingTop: [ + "constant(safe-area-inset-top)", + "env(safe-area-inset-top, 0px)", + ], + paddingRight: [ + "constant(safe-area-inset-right)", + "env(safe-area-inset-right, 0px)", + ], + paddingBottom: [ + "constant(safe-area-inset-bottom)", + "env(safe-area-inset-bottom, 0px)", + ], + paddingLeft: [ + "constant(safe-area-inset-left)", + "env(safe-area-inset-left, 0px)", + ], backgroundColor: globalVars.dimBackgroundColor, zIndex: vars.zIndexes.dim, opacity: 0,