@tapcart/mobile-components 0.19.0 → 0.19.1

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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=drawer-glass-inset.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-glass-inset.test.d.ts","sourceRoot":"","sources":["../../../../components/ui/__tests__/drawer-glass-inset.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,84 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import { render, screen } from "@testing-library/react";
5
+ import { Drawer, DrawerContentBase } from "../drawer";
6
+ // A bottom sheet portals to <body> and pins itself with `position: fixed;
7
+ // bottom: 0`, so it lives OUTSIDE #tc-vgsl and never receives the frame
8
+ // clearance that element carries. Its bottom cushion is therefore the only
9
+ // thing keeping content off an overlay bottom bar (iOS Liquid Glass).
10
+ //
11
+ // `pb-safe` alone is just env(safe-area-inset-bottom) - the home indicator,
12
+ // not the bar. `tc-pb-frame` is the glass-gated rule in styles/globals.css
13
+ // that raises the cushion to max(env(safe-area-inset-bottom),
14
+ // --tc-frame-bottom). jsdom does not evaluate the cascade, so this asserts the
15
+ // contract the stylesheet keys off; the geometry itself is proven in the
16
+ // browser A/B (qa-evidence/glass-sheet-insets).
17
+ describe("DrawerContentBase bottom-overlay clearance", () => {
18
+ it("carries both the legacy safe cushion and the glass frame cushion", () => {
19
+ render(_jsx(Drawer, Object.assign({ open: true }, { children: _jsx(DrawerContentBase, { children: "content" }) })));
20
+ const sheet = screen.getByTestId("drawer-content");
21
+ expect(sheet.className).toContain("pb-safe");
22
+ expect(sheet.className).toContain("tc-pb-frame");
23
+ });
24
+ it("keeps the cushion when a caller passes its own className", () => {
25
+ render(_jsx(Drawer, Object.assign({ open: true }, { children: _jsx(DrawerContentBase, Object.assign({ className: "bg-red-500" }, { children: "content" })) })));
26
+ const sheet = screen.getByTestId("drawer-content");
27
+ expect(sheet.className).toContain("tc-pb-frame");
28
+ expect(sheet.className).toContain("bg-red-500");
29
+ });
30
+ // FORWARD GUARD, not proof of the glass fix: this assertion is already green
31
+ // on the pre-fix component, because `bottom-0` predates it. It exists to go
32
+ // red if someone later moves the clearance out of padding and into `bottom`.
33
+ it("stays anchored to the bottom edge instead of floating above the bar", () => {
34
+ // The clearance must live in padding, not in `bottom`: the sheet surface
35
+ // keeps bleeding to the physical bottom edge the way a native sheet does,
36
+ // and only its CONTENT is lifted. A `bottom` offset would leave a strip of
37
+ // backdrop under the sheet.
38
+ render(_jsx(Drawer, Object.assign({ open: true }, { children: _jsx(DrawerContentBase, { children: "content" }) })));
39
+ const sheet = screen.getByTestId("drawer-content");
40
+ expect(sheet.className).toContain("bottom-0");
41
+ expect(sheet.style.bottom).toBe("");
42
+ });
43
+ // The two assertions above only pin the class NAME. jest has no CSS
44
+ // transform and the component imports no stylesheet, so deleting or renaming
45
+ // the rule in styles/globals.css would leave them green while the clearance
46
+ // silently stopped existing. This closes that drift: it reads the AUTHORED
47
+ // stylesheet (styles/globals.css) and checks a rule really is keyed to the
48
+ // class the component emits, with the right variable in it.
49
+ //
50
+ // Source, not dist/: dist/styles.css is gitignored and only exists after a
51
+ // build, so asserting against it would make this test pass or fail on build
52
+ // state rather than on the committed CSS. The build step for this file is
53
+ // postcss with no selector rewriting, so source and shipped agree - but the
54
+ // guard is on the input, and a transform that ever changed that would slip
55
+ // past it.
56
+ it("has a stylesheet rule keyed to the class the component emits", () => {
57
+ render(_jsx(Drawer, Object.assign({ open: true }, { children: _jsx(DrawerContentBase, { children: "content" }) })));
58
+ const emitted = screen
59
+ .getByTestId("drawer-content")
60
+ .className.split(/\s+/)
61
+ .find((c) => c === "tc-pb-frame");
62
+ expect(emitted).toBe("tc-pb-frame");
63
+ const css = fs
64
+ .readFileSync(path.join(__dirname, "../../../styles/globals.css"), "utf8")
65
+ // Comments in this file quote CSS ("pin themselves with position: fixed;
66
+ // bottom: 0"), which would otherwise be read as declarations below.
67
+ .replace(/\/\*[\s\S]*?\*\//g, "");
68
+ // Whole selector token: a substring match would still find the class
69
+ // inside a renamed `.tc-pb-frame-something`, which is exactly the drift
70
+ // this test exists to catch.
71
+ const selector = new RegExp(`\\.${emitted}(?![\\w-])`);
72
+ const rule = css
73
+ .split("}")
74
+ .map((block) => block + "}")
75
+ .find((block) => selector.test(block) && block.includes("padding-bottom"));
76
+ expect(rule).toBeDefined();
77
+ // Glass-gated, and reading the frame inset rather than a hardcoded value.
78
+ expect(rule).toContain("tc-glass");
79
+ expect(rule).toContain("--tc-frame-bottom");
80
+ // Clearance lives in padding, never in `bottom`. Anchored to a declaration
81
+ // start so it does not also match the `bottom` inside `padding-bottom`.
82
+ expect(rule).not.toMatch(/[;{]\s*bottom:/);
83
+ });
84
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../components/ui/drawer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,MAAM,CAAA;AAKhD,KAAK,kBAAkB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACnE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,KAAK,gBAAgB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,QAAA,MAAM,aAAa,8BAA0D,CAAA;AAG7E,QAAA,MAAM,YAAY;iCAAgC,iBAAiB;;CAgBlE,CAAA;AAGD,QAAA,MAAM,WAAW,4BAAsD,CAAA;AAGvE,KAAK,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG;IACrE,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,QAAA,MAAM,MAAM;0CAAyC,WAAW;;CAS/D,CAAA;AAOD,QAAA,MAAM,aAAa;;wCAYlB,CAAA;AAWD,QAAA,MAAM,iBAAiB;;;;;;wCA2CtB,CAAA;AAWD,QAAA,MAAM,WAAW,qLAYf,CAAA;AAGF,QAAA,MAAM,YAAY;8BAGf,MAAM,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,iBAAiB,+LASrB,CAAA;AAGF,KAAK,iBAAiB,GAAG;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAA;CACjD,CAAA;AAED,QAAA,MAAM,YAAY,0DAKf,iBAAiB,4CA8BnB,CAAA;AAED,QAAA,MAAM,aAAa,sCAIhB,MAAM,cAAc,CAAC,cAAc,CAAC,4CAMtC,CAAA;AAED,OAAO,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,YAAY,GACb,CAAA"}
1
+ {"version":3,"file":"drawer.d.ts","sourceRoot":"","sources":["../../../components/ui/drawer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,MAAM,CAAA;AAKhD,KAAK,kBAAkB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACnE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,KAAK,gBAAgB,GAAG,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG;IACjE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,QAAA,MAAM,aAAa,8BAA0D,CAAA;AAG7E,QAAA,MAAM,YAAY;iCAAgC,iBAAiB;;CAgBlE,CAAA;AAGD,QAAA,MAAM,WAAW,4BAAsD,CAAA;AAGvE,KAAK,WAAW,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG;IACrE,YAAY,CAAC,EAAE,WAAW,CAAA;CAC3B,CAAA;AAED,QAAA,MAAM,MAAM;0CAAyC,WAAW;;CAS/D,CAAA;AAOD,QAAA,MAAM,aAAa;;wCAYlB,CAAA;AAWD,QAAA,MAAM,iBAAiB;;;;;;wCA+CtB,CAAA;AAWD,QAAA,MAAM,WAAW,qLAYf,CAAA;AAGF,QAAA,MAAM,YAAY;8BAGf,MAAM,cAAc,CAAC,cAAc,CAAC;;CAQtC,CAAA;AAGD,QAAA,MAAM,iBAAiB,+LASrB,CAAA;AAGF,KAAK,iBAAiB,GAAG;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAA;CACjD,CAAA;AAED,QAAA,MAAM,YAAY,0DAKf,iBAAiB,4CA8BnB,CAAA;AAED,QAAA,MAAM,aAAa,sCAIhB,MAAM,cAAc,CAAC,cAAc,CAAC,4CAMtC,CAAA;AAED,OAAO,EACL,MAAM,EACN,YAAY,EACZ,aAAa,EACb,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,YAAY,GACb,CAAA"}
@@ -51,7 +51,12 @@ const DrawerContentBase = React.forwardRef((_a, ref) => {
51
51
  const baseStyles = isSheet
52
52
  ? { height: "calc(100dvh - 112px)" }
53
53
  : { maxHeight: maxHeight || "calc(100dvh - 112px)" };
54
- return (_jsxs(DrawerPortal, Object.assign({ containerRef: containerRef }, { children: [hideBackdrop ? null : (_jsx(DrawerOverlay, { backdropHexColor: backdropHexColor })), _jsxs(DrawerPrimitive.Content, Object.assign({ ref: ref, style: Object.assign(Object.assign({}, baseStyles), style), className: cn("fixed inset-x-0 bottom-0 z-50 flex h-auto flex-col rounded-t-2xl bg-coreColors-modalBackground pb-safe", className) }, props, { "data-testid": "drawer-content" }, { children: [_jsx("div", { className: "mx-auto mb-2 mt-2 h-[4px] w-[40px] rounded-full bg-coreColors-dividingLines" }), children] }))] })));
54
+ return (_jsxs(DrawerPortal, Object.assign({ containerRef: containerRef }, { children: [hideBackdrop ? null : (_jsx(DrawerOverlay, { backdropHexColor: backdropHexColor })), _jsxs(DrawerPrimitive.Content, Object.assign({ ref: ref, style: Object.assign(Object.assign({}, baseStyles), style), className: cn(
55
+ // tc-pb-frame: bottom-overlay (iOS Liquid Glass) clearance. The
56
+ // sheet is viewport-anchored, so it never inherits #tc-vgsl's
57
+ // --tc-frame-bottom padding; see styles/globals.css. Inert off
58
+ // glass, where pb-safe alone stays authoritative.
59
+ "fixed inset-x-0 bottom-0 z-50 flex h-auto flex-col rounded-t-2xl bg-coreColors-modalBackground pb-safe tc-pb-frame", className) }, props, { "data-testid": "drawer-content" }, { children: [_jsx("div", { className: "mx-auto mb-2 mt-2 h-[4px] w-[40px] rounded-full bg-coreColors-dividingLines" }), children] }))] })));
55
60
  });
56
61
  DrawerContentBase.displayName = "DrawerContentBase";
57
62
  const DrawerHeaderBase = (_a) => {
package/dist/styles.css CHANGED
@@ -2336,6 +2336,10 @@ video {
2336
2336
  --tw-bg-opacity: 1;
2337
2337
  background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));
2338
2338
  }
2339
+ .bg-red-500 {
2340
+ --tw-bg-opacity: 1;
2341
+ background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));
2342
+ }
2339
2343
  .bg-stateColors-disabled {
2340
2344
  background-color: var(--stateColors-disabled);
2341
2345
  }
@@ -3395,10 +3399,17 @@ body::-webkit-scrollbar {
3395
3399
  * home indicator) dedupe instead of double-counting.
3396
3400
  */
3397
3401
 
3398
- /* SLIM SCOPE — bottom-overlay iOS adapter only. Top-edge, cutout, generalized
3399
- --tc-content-* / drawer vars and their Tailwind utilities are deferred to
3400
- Insets V2 (they had zero consumers). Everything here is inert unless the
3401
- shell reports an overlay bottom bar (.tc-glass; see the gated block below). */
3402
+ /* SLIM SCOPE — bottom-overlay iOS adapter only. Top-edge, cutout and the
3403
+ generalized --tc-content-* var API are deferred to Insets V2. Everything here
3404
+ is inert unless the shell reports an overlay bottom bar (.tc-glass; see the
3405
+ gated block below).
3406
+
3407
+ Drawer clearance is NO LONGER part of that deferral. #3407 deferred "drawer
3408
+ APIs" on the rationale that they had zero consumers; that rationale expired
3409
+ once bottom sheets were found painting behind the bar on 22 block templates
3410
+ plus the quickadd and wishlist modals. What landed is one narrow utility
3411
+ class (.tc-pb-frame, at the end of this file) consumed by DrawerContentBase —
3412
+ NOT the generalized drawer var API, which stays deferred. */
3402
3413
 
3403
3414
  /* --tc-bar-bottom is @property-registered so the hide-on-scroll bar collapse
3404
3415
  animates smoothly (300ms native bar). */
@@ -3457,6 +3468,38 @@ body::-webkit-scrollbar {
3457
3468
  var(--tc-bar-bottom, 0px)
3458
3469
  );
3459
3470
  }
3471
+
3472
+ /* Bottom cushion for VIEWPORT-ANCHORED overlays (bottom sheets / drawers).
3473
+ These portal to <body> and pin themselves with `position: fixed; bottom: 0`,
3474
+ so they sit outside #tc-vgsl and never receive the frame clearance it carries
3475
+ (--tc-frame-bottom-gated on the native path, --tc-frame-bottom in web mode;
3476
+ see apps/tapcart-ssr-app/app/layout.tsx). Under an overlay bottom bar their
3477
+ last row of content therefore paints behind the bar.
3478
+
3479
+ This rule reads the NON-gated --tc-frame-bottom on purpose. #tc-vgsl needs
3480
+ the gated variant so it goes IACVT-invalid and collapses to 0 on a shell that
3481
+ never wrote --tc-safe-bottom, leaving the legacy RN bridge authoritative over
3482
+ the same element. Nothing competes for this padding, and the injection script
3483
+ writes --tc-safe-bottom and --tc-bar-bottom-glass together, so under .tc-glass
3484
+ the two variants are equal anyway; the non-gated one additionally keeps the
3485
+ env()/--rn-* fallback chain alive.
3486
+
3487
+ The sheet's own surface should keep bleeding to the physical bottom edge
3488
+ (native sheets do), so the clearance goes into padding and lifts the CONTENT
3489
+ instead of floating the whole sheet. max() against the pre-PR env() cushion
3490
+ keeps the two from double-counting when the bar hides on scroll and
3491
+ --tc-frame-bottom collapses to the safe area.
3492
+
3493
+ Gated on .tc-glass: on every non-glass shell this rule never matches and the
3494
+ element's existing `pb-safe` stays byte-for-byte authoritative.
3495
+
3496
+ Specificity note: this is (0,4,0), well above a Tailwind pb-* utility, and
3497
+ tailwind-merge does not treat `tc-pb-frame` as a padding-bottom conflict. A
3498
+ caller passing `pb-0`/`p-0` to DrawerContentBase would therefore keep the
3499
+ cushion under glass and lose it everywhere else. No caller does today. */
3500
+ :root.tc-platform-ios.tc-glass .tc-pb-frame {
3501
+ padding-bottom: max(env(safe-area-inset-bottom), var(--tc-frame-bottom, 0px));
3502
+ }
3460
3503
  .file\:border-0::file-selector-button {
3461
3504
  border-width: 0px;
3462
3505
  }
@@ -3949,4 +3992,3 @@ body::-webkit-scrollbar {
3949
3992
  .\[\&_p\]\:text-stateColors-disabled p {
3950
3993
  color: var(--stateColors-disabled);
3951
3994
  }
3952
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapcart/mobile-components",
3
- "version": "0.19.0",
3
+ "version": "0.19.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "style": "dist/styles.css",