@salemcobalt/ui 0.2.0-rc.33 → 0.2.0-rc.34

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.
package/dist/styles.css CHANGED
@@ -1,4 +1,4 @@
1
- /* @salemcobalt/ui 0.2.0-rc.33 — requires @salemcobalt/tokens/css. */
1
+ /* @salemcobalt/ui 0.2.0-rc.34 — requires @salemcobalt/tokens/css. */
2
2
  @layer sc {
3
3
  /* ---- base.css ---- */
4
4
  /* Shared: focus ring, reduced motion. Component files follow. */
@@ -853,11 +853,21 @@
853
853
 
854
854
  /* ---- dialog.css ---- */
855
855
  /* ---- Dialog ---------------------------------------------------------------- */
856
+ /* `--_overhang`: how far a docked surface (the scrim, a phone sheet, a full-screen dialog) runs past the bottom edge
857
+ of the layout viewport, out of sight. It covers what a collapsing or floating browser toolbar uncovers there. */
858
+ .sc-dialog__backdrop,
859
+ .sc-dialog__popup {
860
+ --_overhang: 160px;
861
+ }
856
862
  .sc-dialog__backdrop {
857
863
  position: fixed;
858
- inset: 0;
864
+ /* The scrim runs past the bottom edge: when a phone's browser toolbar collapses or floats, the strip it uncovers
865
+ is still dimmed instead of showing the page undimmed beneath it. */
866
+ inset: 0 0 calc(-1 * var(--_overhang));
859
867
  z-index: var(--sc-z-backdrop);
860
868
  background: var(--sc-color-surface-backdrop);
869
+ /* A drag on the scrim never pans the page behind it (iOS rubber-banding included); a tap still closes. */
870
+ touch-action: none;
861
871
  transition: opacity var(--sc-duration-base) var(--sc-ease-enter);
862
872
  }
863
873
  /* A dialog opened from inside another (Base UI nests its portal after the parent's popup): its scrim covers the
@@ -1001,22 +1011,45 @@
1001
1011
  /* Below 640px the sheet docks to the bottom edge, full width, and slides up. The breakpoint is fixed
1002
1012
  here because custom properties cannot drive a media query. */
1003
1013
  @media (width < 640px) {
1014
+ /* The sheet's surface runs on past the bottom edge as a bottom border in its own colour (the overhang), so no
1015
+ strip of page shows under it when the browser toolbar collapses; the content and its safe-area padding end at
1016
+ the edge as before. `touch-action: none`: a drag on the sheet outside a scroller never pans the page behind
1017
+ it, while `Dialog.Body` and any other scroll container inside keep scrolling (touch-action resets at a
1018
+ scroll container). The drag (sheetSwipe.ts) moves it with `transform`, on top of the `translate` that
1019
+ opens and closes it.
1020
+ Motion: the sheet and its scrim share one duration and curve each way, so the scrim never goes before the
1021
+ sheet does. In: `slow` on `standard`, which leaves the bottom edge gently instead of jumping a quarter of its
1022
+ height in the first frame. Out: 75% of that on `exit`, accelerating, so it is in view until it leaves.
1023
+ After a swipe it decelerates instead (`data-swiped`), carrying on from the finger's speed. */
1004
1024
  .sc-dialog__popup[data-variant='sheet'] {
1005
- inset: auto 0 0 0;
1025
+ inset: auto 0 calc(-1 * var(--_overhang)) 0;
1006
1026
  margin: 0;
1007
1027
  inline-size: 100%;
1008
1028
  max-inline-size: none;
1009
- max-block-size: calc(100dvh - env(safe-area-inset-top, 0px) - var(--sc-spacing-xl));
1029
+ max-block-size: calc(100dvh - env(safe-area-inset-top, 0px) - var(--sc-spacing-xl) + var(--_overhang));
1010
1030
  padding-block-end: calc(var(--sc-spacing-lg) + env(safe-area-inset-bottom, 0px));
1011
1031
  padding-inline: calc(var(--sc-spacing-lg) + env(safe-area-inset-left, 0px))
1012
1032
  calc(var(--sc-spacing-lg) + env(safe-area-inset-right, 0px));
1013
- border-block-end: 0;
1033
+ border-block-end: var(--_overhang) solid var(--sc-color-surface-raised);
1014
1034
  border-radius: var(--sc-radius-xl) var(--sc-radius-xl) 0 0;
1035
+ touch-action: none;
1015
1036
  transition:
1016
- opacity var(--sc-duration-base) var(--sc-ease-enter),
1017
- translate var(--sc-duration-base) var(--sc-ease-enter),
1037
+ translate var(--sc-duration-slow) var(--sc-ease-standard),
1018
1038
  transform var(--sc-duration-slow) var(--sc-ease-standard);
1019
1039
  }
1040
+ .sc-dialog__backdrop[data-variant='sheet'] {
1041
+ transition-duration: var(--sc-duration-slow);
1042
+ transition-timing-function: var(--sc-ease-standard);
1043
+ }
1044
+ .sc-dialog__popup[data-variant='sheet'][data-ending-style],
1045
+ .sc-dialog__backdrop[data-variant='sheet'][data-ending-style] {
1046
+ transition-duration: calc(var(--sc-duration-slow) * 0.75);
1047
+ transition-timing-function: var(--sc-ease-exit);
1048
+ }
1049
+ .sc-dialog__popup[data-variant='sheet'][data-ending-style][data-swiped] {
1050
+ transition-duration: var(--sc-duration-base);
1051
+ transition-timing-function: var(--sc-ease-enter);
1052
+ }
1020
1053
  /* The handle: a 36 × 4 bar centred in a 64 × 24 target, where the bar alone used to sit. */
1021
1054
  .sc-dialog__popup[data-variant='sheet'] > .sc-dialog__handle {
1022
1055
  display: grid;
@@ -1043,12 +1076,6 @@
1043
1076
  border-radius: var(--sc-radius-full);
1044
1077
  background: currentColor;
1045
1078
  }
1046
- /* Swipe to dismiss (sheetSwipe.ts): the page never pans under the sheet, while `Dialog.Body` and any other
1047
- scroll container inside keep scrolling, because touch-action resets at a scroll container. The drag
1048
- moves the sheet with `transform`, which adds to the `translate` the exit transition animates. */
1049
- .sc-dialog__popup[data-variant='sheet'][data-swipe-dismiss] {
1050
- touch-action: none;
1051
- }
1052
1079
  .sc-dialog__popup[data-variant='sheet'][data-swipe-dismiss] > .sc-dialog__handle {
1053
1080
  cursor: grab;
1054
1081
  }
@@ -1057,10 +1084,11 @@
1057
1084
  user-select: none;
1058
1085
  transition: none;
1059
1086
  }
1087
+ /* Just below the edge: its visible height, not counting the overhang already out of sight. */
1060
1088
  .sc-dialog__popup[data-variant='sheet'][data-starting-style],
1061
1089
  .sc-dialog__popup[data-variant='sheet'][data-ending-style] {
1062
1090
  opacity: 1;
1063
- translate: 0 100%;
1091
+ translate: 0 calc(100% - var(--_overhang));
1064
1092
  scale: none;
1065
1093
  }
1066
1094
  /* Actions stack full width, confirming action on top, in thumb reach. */
@@ -1125,6 +1153,14 @@
1125
1153
  overflow: hidden auto; /* vertical only: a 44px touch target on an edge button must not scroll it sideways */
1126
1154
  overscroll-behavior: contain;
1127
1155
  }
1156
+ /* Below 900px the full-screen surface runs past the bottom edge like the sheet (the overhang, a bottom border in
1157
+ its own colour), so a collapsing browser toolbar uncovers more of it, not the page. */
1158
+ @media (width < 900px) {
1159
+ .sc-dialog__popup[data-variant='fullscreen'] {
1160
+ inset-block-end: calc(-1 * var(--_overhang));
1161
+ border-block-end: var(--_overhang) solid var(--sc-color-surface-default);
1162
+ }
1163
+ }
1128
1164
  /* From 900px the backdrop shows a margin around it, so it still reads as a layer over the app. */
1129
1165
  @media (width >= 900px) {
1130
1166
  .sc-dialog__popup[data-variant='fullscreen'] {
@@ -1161,7 +1197,11 @@
1161
1197
  /* Reduced motion: a docked sheet appears and goes without sliding, and a released swipe closes or snaps
1162
1198
  back in place without the spring. */
1163
1199
  @media (width < 640px) and (prefers-reduced-motion: reduce) {
1164
- .sc-dialog__popup[data-variant='sheet'] {
1200
+ .sc-dialog__popup[data-variant='sheet'],
1201
+ .sc-dialog__popup[data-variant='sheet'][data-ending-style],
1202
+ .sc-dialog__popup[data-variant='sheet'][data-ending-style][data-swiped],
1203
+ .sc-dialog__backdrop[data-variant='sheet'],
1204
+ .sc-dialog__backdrop[data-variant='sheet'][data-ending-style] {
1165
1205
  transition-duration: 0ms;
1166
1206
  }
1167
1207
  .sc-dialog__popup[data-variant='sheet'][data-starting-style],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salemcobalt/ui",
3
- "version": "0.2.0-rc.33",
3
+ "version": "0.2.0-rc.34",
4
4
  "description": "React components for the Salem Cobalt design system: Button, IconButton, Icon set, BroomIcon, Badge, Card, Stack, Inline, Kbd, Dialog, FullScreenFlow, Tooltip, Menu, Popover, PriorityNav, Toolbar, Banner, Spinner, Progress, Tabs, Input, Textarea, Select, FileInput, Checkbox, Switch, Heading, Text, Table, Stat, Chip, Disclosure, EmptyState, Skeleton, Score, ReasonList, WordDiff, Quote; TextEditor (CodeMirror 6, inline word diffs) at @salemcobalt/ui/editor.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -46,7 +46,7 @@
46
46
  "diff": "^8.0.4",
47
47
  "react": "^19.0.0",
48
48
  "react-dom": "^19.0.0",
49
- "@salemcobalt/tokens": "^0.2.0-rc.33"
49
+ "@salemcobalt/tokens": "^0.2.0-rc.34"
50
50
  },
51
51
  "peerDependenciesMeta": {
52
52
  "@codemirror/commands": {
@@ -109,7 +109,7 @@
109
109
  "tsup": "^9.0.0",
110
110
  "typescript": "^5.9.3",
111
111
  "vitest": "^5.0.5",
112
- "@salemcobalt/tokens": "^0.2.0-rc.33"
112
+ "@salemcobalt/tokens": "^0.2.0-rc.34"
113
113
  },
114
114
  "publishConfig": {
115
115
  "access": "public"