@gryt/ui-native 0.8.0 → 0.8.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Sheet.d.ts","sourceRoot":"","sources":["../../../src/components/Sheet/Sheet.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAerF,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAE7D;AAeD,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,iBAAS,IAAI,CAAC,EACZ,UAAoB,EACpB,QAAQ,EACR,GAAG,SAAS,EACb,EAAE,UAAU,+BAqBZ;AAWD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BAOtD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BA8LtD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAOlD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAiBlD;AAED,eAAO,MAAM,KAAK;;;;;CAA0D,CAAC"}
1
+ {"version":3,"file":"Sheet.d.ts","sourceRoot":"","sources":["../../../src/components/Sheet/Sheet.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAerF,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAI/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAE7D;AAeD,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,iBAAS,IAAI,CAAC,EACZ,UAAoB,EACpB,QAAQ,EACR,GAAG,SAAS,EACb,EAAE,UAAU,+BAqBZ;AAWD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BAOtD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BAuNtD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAOlD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAiBlD;AAED,eAAO,MAAM,KAAK;;;;;CAA0D,CAAC"}
@@ -4,9 +4,10 @@ import { Pressable, Text, View } from "react-native";
4
4
  import { BottomSheetBackdrop, BottomSheetModal, BottomSheetModalProvider, BottomSheetView, useBottomSheetTimingConfigs, } from "@gorhom/bottom-sheet";
5
5
  import { useSafeAreaInsets } from "react-native-safe-area-context";
6
6
  import { grytDrawerBleed } from "@gryt/theme";
7
- import { durations, easeSpring } from "../../motion/index.js";
7
+ import { durations, easeSpringTight } from "../../motion/index.js";
8
8
  import { useOpenState } from "../../overlay/useOpenState.js";
9
9
  import { useTheme } from "../../theme/index.js";
10
+ import { nextPresentation } from "./presentation.js";
10
11
  /** Mount once, at the root. See the note above for why it is required. */
11
12
  export function SheetProvider({ children }) {
12
13
  return _jsx(BottomSheetModalProvider, { children: children });
@@ -87,17 +88,23 @@ function Content({ children, style }) {
87
88
  * has never been presented takes it *out* of the provider's registry — after
88
89
  * which `present()` is a no-op and the sheet never opens again. It looks like
89
90
  * the open prop being ignored, and it is not: it is the close that ran first.
91
+ *
92
+ * **It has to be cleared by `onDismiss` as well**, which is the other way a
93
+ * sheet stops being presented and the one this missed. A flick down dismisses
94
+ * the modal itself and *then* tells React, so the effect that follows finds
95
+ * `presented` still true and calls `dismiss()` on a modal that is already
96
+ * gone — the same unregistering call the ref exists to prevent, arriving by
97
+ * the other door. Every sheet in the app so far was opened by a trigger and
98
+ * closed for good, so nothing noticed until something wanted one back.
90
99
  */
91
100
  const presented = useRef(false);
92
101
  useEffect(() => {
93
- if (isOpen) {
94
- presented.current = true;
102
+ const next = nextPresentation(isOpen, presented.current);
103
+ presented.current = next.presented;
104
+ if (next.action === "present")
95
105
  ref.current?.present();
96
- }
97
- else if (presented.current) {
98
- presented.current = false;
106
+ else if (next.action === "dismiss")
99
107
  ref.current?.dismiss();
100
- }
101
108
  }, [isOpen, ref]);
102
109
  // The modal renders nothing until it is presented, so there is no invisible
103
110
  // backdrop sitting over the screen eating taps while it is closed. That was
@@ -147,10 +154,22 @@ function Content({ children, style }) {
147
154
  * bottom edge and covers nearly all of it. The same duration over a longer
148
155
  * distance is a faster animation, and at 700 this arrived quickly enough to
149
156
  * read as a snap rather than a slide.
157
+ *
158
+ * **`easeSpringTight`, not `easeSpring`.** This used the loose curve and
159
+ * bounced, and the two are labelled in `easing.ts` in a way that decides it:
160
+ * `easeSpring` "overshoots ~12%, for things that scale in place", and
161
+ * `easeSpringTight` is "critically damped, no overshoot, for things that
162
+ * travel inside bounds". A sheet sliding up from the bottom edge to a snap
163
+ * point is the second thing, not the first — so this was the wrong curve by
164
+ * the package's own rule, and it is the curve the Drawer already uses.
165
+ *
166
+ * Overshoot on a sheet is worse than on a button, too: the thing that
167
+ * overshoots is the top edge, so it travels past its snap point and comes
168
+ * back, which reads as the sheet failing to land rather than as bounce.
150
169
  */
151
170
  const animationConfigs = useBottomSheetTimingConfigs({
152
171
  duration: durations.springSlow,
153
- easing: easeSpring,
172
+ easing: easeSpringTight,
154
173
  });
155
174
  const renderBackdrop = useCallback((props) => (_jsx(BottomSheetBackdrop, { ...props, appearsOnIndex: 0, disappearsOnIndex: -1,
156
175
  // Tracks the drag, so dragging the sheet down lightens the scrim
@@ -172,7 +191,14 @@ function Content({ children, style }) {
172
191
  // React asking, so the state has to be told. Uncontrolled, this is what
173
192
  // makes the next `present` work; controlled, it is how the parent finds
174
193
  // out its sheet is gone.
175
- onDismiss: () => setOpen(false), animationConfigs: animationConfigs, backdropComponent: renderBackdrop, backgroundComponent: renderBackground, handleIndicatorStyle: {
194
+ //
195
+ // `presented` first, and not as a tidy-up: the modal has already
196
+ // dismissed itself by the time this runs, and leaving the ref true lets
197
+ // the effect below dismiss it a second time. See the note on the ref.
198
+ onDismiss: () => {
199
+ presented.current = false;
200
+ setOpen(false);
201
+ }, animationConfigs: animationConfigs, backdropComponent: renderBackdrop, backgroundComponent: renderBackground, handleIndicatorStyle: {
176
202
  backgroundColor: theme.color.border,
177
203
  width: 36,
178
204
  height: 4,
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Whether a sheet should be presented, dismissed, or left alone.
3
+ *
4
+ * A three-line decision in its own file, for the reason `sliderValue.ts` and
5
+ * `placePopup.ts` are: it is the part a screenshot cannot check, and it is the
6
+ * part that has now been wrong twice.
7
+ *
8
+ * The rule the whole thing exists for is that **`dismiss()` must only be
9
+ * called on a modal that is actually presented**. `@gorhom/bottom-sheet`'s
10
+ * provider keeps a registry of presented sheets, and dismissing one that is not
11
+ * in it takes it out — after which `present()` is a no-op and the sheet never
12
+ * opens again. It looks exactly like the `open` prop being ignored.
13
+ *
14
+ * There are two ways to end up asking. One is a sheet that has never been on
15
+ * screen: it runs its effect once on mount with `open` false, and without this
16
+ * it would dismiss a modal the provider has never heard of. The other is a
17
+ * flick down, which dismisses the modal itself and *then* tells React — so the
18
+ * effect that follows would dismiss it a second time.
19
+ */
20
+ export type SheetAction = "present" | "dismiss" | "none";
21
+ export interface SheetPresentation {
22
+ action: SheetAction;
23
+ /** What `presented` becomes. The caller stores it. */
24
+ presented: boolean;
25
+ }
26
+ export declare function nextPresentation(open: boolean, presented: boolean): SheetPresentation;
27
+ //# sourceMappingURL=presentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../../src/components/Sheet/presentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,sDAAsD;IACtD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,iBAAiB,CAIrF"}
@@ -0,0 +1,7 @@
1
+ export function nextPresentation(open, presented) {
2
+ if (open)
3
+ return { action: "present", presented: true };
4
+ if (presented)
5
+ return { action: "dismiss", presented: false };
6
+ return { action: "none", presented: false };
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gryt/ui-native",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Gryt's design system on React Native. Same tokens as @gryt/ui, a different renderer.",