@oxyhq/bloom 0.35.6 → 0.35.7

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.
@@ -18,11 +18,20 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
18
18
  * the rounded corners / lateral gutters is masked while a single seamless border
19
19
  * is drawn around the panel — see `index.web.tsx`.
20
20
  *
21
- * On NATIVE none of that applies: there is no document scroll, no sticky
22
- * positioning, and no bleed to mask, so the panel is simply a rounded, bordered
23
- * surface wrapping its content. The `framed` and `showStickyFrame` props are
24
- * accepted for cross-platform API parity but are intentionally no-ops here
25
- * (mirroring the no-op native fork of `../scroll`).
21
+ * On NATIVE none of the WEB overlay machinery applies: there is no document
22
+ * scroll, no sticky positioning, and no bleed to mask, so the panel is simply a
23
+ * surface wrapping its content. The `framed` prop still drives whether that
24
+ * surface is rounded + bordered, tri-state and resolved with pure NativeWind
25
+ * (`md:` evaluates against the window width on native too no JS breakpoint
26
+ * hook needed):
27
+ *
28
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
29
+ * bordered at `md`+ (`md:rounded-radius-28 md:border md:border-border`).
30
+ * - `false` → never framed (plain full-bleed at every size).
31
+ * - `true` → always rounded + bordered.
32
+ *
33
+ * `showStickyFrame` and `maskColor` are accepted for cross-platform API parity
34
+ * but are no-ops here (there are no sticky overlays on native).
26
35
  *
27
36
  * Web bundlers select `./index.web` via the `"browser"` export condition in
28
37
  * `package.json`; native bundlers fall through to this file.
@@ -43,6 +52,7 @@ const PANEL_TOP_INSET = exports.PANEL_TOP_INSET = 8;
43
52
  const PANEL_BOTTOM_INSET = exports.PANEL_BOTTOM_INSET = 8;
44
53
  const ContentPanelComponent = ({
45
54
  children,
55
+ framed,
46
56
  surfaceClassName,
47
57
  surfaceStyle,
48
58
  contentClassName,
@@ -50,7 +60,13 @@ const ContentPanelComponent = ({
50
60
  }) => {
51
61
  // Dev-only invariant — a ContentPanel must never be nested inside another.
52
62
  (0, _nestingContext.useContentPanelNestingGuard)();
53
- const surfaceClass = ['flex-1', 'rounded-radius-28', 'overflow-hidden border border-border', surfaceClassName ?? 'bg-card'].join(' ');
63
+
64
+ // Tri-state: `undefined` → responsive (md:-gated), `true` → always framed,
65
+ // `false` → never framed (plain full-bleed). Whole literal class strings are
66
+ // selected per mode so the Tailwind content-scan over `src/**` picks up every
67
+ // `md:` / `rounded-radius-28` token verbatim (no dynamic concatenation).
68
+ const surfaceBase = framed === undefined ? 'flex-1 md:overflow-hidden md:rounded-radius-28 md:border md:border-border' : framed ? 'flex-1 overflow-hidden rounded-radius-28 border border-border' : 'flex-1';
69
+ const surfaceClass = [surfaceBase, surfaceClassName ?? 'bg-card'].join(' ');
54
70
  const contentClass = ['flex-1', contentClassName].filter(Boolean).join(' ');
55
71
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_nestingContext.ContentPanelNestingContext.Provider, {
56
72
  value: true,
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_nestingContext","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","GUTTER_MASK_SPREAD","exports","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","surfaceClassName","surfaceStyle","contentClassName","contentStyle","useContentPanelNestingGuard","surfaceClass","join","contentClass","filter","Boolean","jsx","ContentPanelNestingContext","Provider","value","View","className","style","ContentPanel","memo","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_nestingContext","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","GUTTER_MASK_SPREAD","exports","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","framed","surfaceClassName","surfaceStyle","contentClassName","contentStyle","useContentPanelNestingGuard","surfaceBase","undefined","surfaceClass","join","contentClass","filter","Boolean","jsx","ContentPanelNestingContext","Provider","value","View","className","style","ContentPanel","memo","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.tsx"],"mappings":"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","ignoreList":[]}
@@ -35,16 +35,29 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
35
35
  * content rather than displacing it). They render BEFORE the content wrapper so
36
36
  * z-index — not DOM order — decides layering.
37
37
  *
38
- * When `framed` is false (narrow screens) the panel is full-bleed: a single
39
- * flat surface, no rounding, no overlays.
38
+ * Framing is tri-state via the `framed` prop:
39
+ *
40
+ * - `undefined` (DEFAULT) → RESPONSIVE, driven purely by NativeWind: full-bleed
41
+ * below `md`, framed at `md`+. The rounding is `md:`-gated and both overlays
42
+ * are always rendered but carry `max-md:hidden` (`display:none` below `md`),
43
+ * so the breakpoint is decided in CSS — no consumer JS breakpoint hook.
44
+ * - `false` → NEVER framed (full-bleed at every size): a single flat surface,
45
+ * no rounding, no overlays.
46
+ * - `true` → ALWAYS framed (rounded + overlays at every size).
47
+ *
48
+ * The overlays are gated by VISIBILITY (a `max-md:hidden` literal) rather than
49
+ * by conditional mounting for the responsive case, so crossing the breakpoint
50
+ * never remounts them. The content wrapper likewise keeps a stable `key` so
51
+ * `{children}` reconciles in place across the breakpoint instead of remounting
52
+ * (which would reset feed scroll / the virtualizer + refetch).
40
53
  *
41
54
  * Native bundlers use `./index.tsx` (a plain rounded surface); web bundlers
42
55
  * select this file via the `"browser"` export condition in `package.json`.
43
56
  *
44
57
  * Styling is NativeWind-className-first; the literal class strings below MUST
45
58
  * stay literal so a consumer's Tailwind content-scan over `lib/**` picks them up
46
- * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28`
47
- * parts).
59
+ * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28` /
60
+ * `md:` parts — whole class strings are selected per mode instead).
48
61
  */
49
62
 
50
63
  /** Width (in px) of the sticky gutter-mask box-shadow ring. */
@@ -63,28 +76,40 @@ const ContentPanelComponent = ({
63
76
  showStickyFrame,
64
77
  maskColor
65
78
  }) => {
66
- // Dev-only invariant — must run unconditionally before the early `!framed`
67
- // return so the hook order stays stable across renders (rules of hooks).
79
+ // Dev-only invariant — must run unconditionally (before deriving any
80
+ // mode-specific branch) so the hook order stays stable (rules of hooks).
68
81
  (0, _nestingContext.useContentPanelNestingGuard)();
69
82
  const {
70
83
  colors
71
84
  } = (0, _useTheme.useTheme)();
72
- const surfaceClass = framed ? ['flex-1 rounded-radius-28', surfaceClassName ?? 'bg-card'].join(' ') : ['flex-1', surfaceClassName ?? 'bg-card'].join(' ');
73
- const contentClass = framed ? ['flex-1 rounded-radius-28 web:overflow-x-clip', contentClassName].filter(Boolean).join(' ') : ['flex-1', contentClassName].filter(Boolean).join(' ');
85
+
86
+ // Tri-state: `undefined` responsive (md:-gated), `true` always framed,
87
+ // `false` → never framed (full-bleed).
88
+ const responsive = framed === undefined;
89
+ const showOverlays = framed !== false;
90
+
91
+ // Whole literal class strings selected per mode (the Tailwind content-scan
92
+ // over `lib/**` requires each arbitrary/`md:`/`web:` token stay literal).
93
+ // `web:md:overflow-x-clip` is platform-first-then-breakpoint, matching the
94
+ // consumer convention (`web:sm:flex` in `@mercaria/ui`).
95
+ const surfaceBase = responsive ? 'flex-1 md:rounded-radius-28' : framed ? 'flex-1 rounded-radius-28' : 'flex-1';
96
+ const contentBase = responsive ? 'flex-1 md:rounded-radius-28 web:md:overflow-x-clip' : framed ? 'flex-1 rounded-radius-28 web:overflow-x-clip' : 'flex-1';
97
+ const surfaceClass = [surfaceBase, surfaceClassName ?? 'bg-card'].join(' ');
98
+ const contentClass = [contentBase, contentClassName].filter(Boolean).join(' ');
74
99
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_nestingContext.ContentPanelNestingContext.Provider, {
75
100
  value: true,
76
101
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
77
102
  className: surfaceClass,
78
103
  style: surfaceStyle,
79
- children: [framed && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
104
+ children: [showOverlays && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
80
105
  pointerEvents: "none",
81
- className: 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]',
106
+ className: responsive ? 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 max-md:hidden web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]' : 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]',
82
107
  style: {
83
108
  boxShadow: `0 0 0 ${GUTTER_MASK_SPREAD}px ${maskColor ?? colors.background}`
84
109
  }
85
- }, "bleed-mask"), framed && showStickyFrame !== false && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
110
+ }, "bleed-mask"), showOverlays && showStickyFrame !== false && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
86
111
  pointerEvents: "none",
87
- className: 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border web:[margin-bottom:calc(-100dvh+16px)]'
112
+ className: responsive ? 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border max-md:hidden web:[margin-bottom:calc(-100dvh+16px)]' : 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border web:[margin-bottom:calc(-100dvh+16px)]'
88
113
  }, "border-frame"), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
89
114
  className: contentClass,
90
115
  style: contentStyle,
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_useTheme","_nestingContext","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","GUTTER_MASK_SPREAD","exports","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","framed","surfaceClassName","surfaceStyle","contentClassName","contentStyle","showStickyFrame","maskColor","useContentPanelNestingGuard","colors","useTheme","surfaceClass","join","contentClass","filter","Boolean","jsx","ContentPanelNestingContext","Provider","value","jsxs","View","className","style","pointerEvents","boxShadow","background","ContentPanel","memo","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.web.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_useTheme","_nestingContext","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","GUTTER_MASK_SPREAD","exports","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","framed","surfaceClassName","surfaceStyle","contentClassName","contentStyle","showStickyFrame","maskColor","useContentPanelNestingGuard","colors","useTheme","responsive","undefined","showOverlays","surfaceBase","contentBase","surfaceClass","join","contentClass","filter","Boolean","jsx","ContentPanelNestingContext","Provider","value","jsxs","View","className","style","pointerEvents","boxShadow","background","ContentPanel","memo","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.web.tsx"],"mappings":"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","ignoreList":[]}
@@ -9,11 +9,20 @@
9
9
  * the rounded corners / lateral gutters is masked while a single seamless border
10
10
  * is drawn around the panel — see `index.web.tsx`.
11
11
  *
12
- * On NATIVE none of that applies: there is no document scroll, no sticky
13
- * positioning, and no bleed to mask, so the panel is simply a rounded, bordered
14
- * surface wrapping its content. The `framed` and `showStickyFrame` props are
15
- * accepted for cross-platform API parity but are intentionally no-ops here
16
- * (mirroring the no-op native fork of `../scroll`).
12
+ * On NATIVE none of the WEB overlay machinery applies: there is no document
13
+ * scroll, no sticky positioning, and no bleed to mask, so the panel is simply a
14
+ * surface wrapping its content. The `framed` prop still drives whether that
15
+ * surface is rounded + bordered, tri-state and resolved with pure NativeWind
16
+ * (`md:` evaluates against the window width on native too no JS breakpoint
17
+ * hook needed):
18
+ *
19
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
20
+ * bordered at `md`+ (`md:rounded-radius-28 md:border md:border-border`).
21
+ * - `false` → never framed (plain full-bleed at every size).
22
+ * - `true` → always rounded + bordered.
23
+ *
24
+ * `showStickyFrame` and `maskColor` are accepted for cross-platform API parity
25
+ * but are no-ops here (there are no sticky overlays on native).
17
26
  *
18
27
  * Web bundlers select `./index.web` via the `"browser"` export condition in
19
28
  * `package.json`; native bundlers fall through to this file.
@@ -38,6 +47,7 @@ export const PANEL_TOP_INSET = 8;
38
47
  export const PANEL_BOTTOM_INSET = 8;
39
48
  const ContentPanelComponent = ({
40
49
  children,
50
+ framed,
41
51
  surfaceClassName,
42
52
  surfaceStyle,
43
53
  contentClassName,
@@ -45,7 +55,13 @@ const ContentPanelComponent = ({
45
55
  }) => {
46
56
  // Dev-only invariant — a ContentPanel must never be nested inside another.
47
57
  useContentPanelNestingGuard();
48
- const surfaceClass = ['flex-1', 'rounded-radius-28', 'overflow-hidden border border-border', surfaceClassName ?? 'bg-card'].join(' ');
58
+
59
+ // Tri-state: `undefined` → responsive (md:-gated), `true` → always framed,
60
+ // `false` → never framed (plain full-bleed). Whole literal class strings are
61
+ // selected per mode so the Tailwind content-scan over `src/**` picks up every
62
+ // `md:` / `rounded-radius-28` token verbatim (no dynamic concatenation).
63
+ const surfaceBase = framed === undefined ? 'flex-1 md:overflow-hidden md:rounded-radius-28 md:border md:border-border' : framed ? 'flex-1 overflow-hidden rounded-radius-28 border border-border' : 'flex-1';
64
+ const surfaceClass = [surfaceBase, surfaceClassName ?? 'bg-card'].join(' ');
49
65
  const contentClass = ['flex-1', contentClassName].filter(Boolean).join(' ');
50
66
  return /*#__PURE__*/_jsx(ContentPanelNestingContext.Provider, {
51
67
  value: true,
@@ -1 +1 @@
1
- {"version":3,"names":["React","memo","View","ContentPanelNestingContext","useContentPanelNestingGuard","jsx","_jsx","GUTTER_MASK_SPREAD","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","surfaceClassName","surfaceStyle","contentClassName","contentStyle","surfaceClass","join","contentClass","filter","Boolean","Provider","value","className","style","ContentPanel","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAOA,KAAK,IAAIC,IAAI,QAAQ,OAAO;AACnC,SAASC,IAAI,QAAwC,cAAc;AAEnE,SACEC,0BAA0B,EAC1BC,2BAA2B,QACtB,sBAAmB;;AAE1B;AACA;AACA;AACA;AAHA,SAAAC,GAAA,IAAAC,IAAA;AAIA,OAAO,MAAMC,kBAAkB,GAAG,EAAE;AACpC;AACA,OAAO,MAAMC,eAAe,GAAG,CAAC;AAChC;AACA,OAAO,MAAMC,kBAAkB,GAAG,CAAC;AA2BnC,MAAMC,qBAAkD,GAAGA,CAAC;EAC1DC,QAAQ;EACRC,gBAAgB;EAChBC,YAAY;EACZC,gBAAgB;EAChBC;AACF,CAAC,KAAK;EACJ;EACAX,2BAA2B,CAAC,CAAC;EAE7B,MAAMY,YAAY,GAAG,CACnB,QAAQ,EACR,mBAAmB,EACnB,sCAAsC,EACtCJ,gBAAgB,IAAI,SAAS,CAC9B,CAACK,IAAI,CAAC,GAAG,CAAC;EACX,MAAMC,YAAY,GAAG,CAAC,QAAQ,EAAEJ,gBAAgB,CAAC,CAACK,MAAM,CAACC,OAAO,CAAC,CAACH,IAAI,CAAC,GAAG,CAAC;EAE3E,oBACEX,IAAA,CAACH,0BAA0B,CAACkB,QAAQ;IAACC,KAAK,EAAE,IAAK;IAAAX,QAAA,eAC/CL,IAAA,CAACJ,IAAI;MACIqB,SAAS,EAAEP,YAAY;MAC9BQ,KAAK,EAAEX,YAAa;MAAAF,QAAA,eAEpBL,IAAA,CAACJ,IAAI;QACIqB,SAAS,EAAEL,YAAY;QAC9BM,KAAK,EAAET,YAAa;QAAAJ,QAAA,EAEnBA;MAAQ,CACL;IAAC,CACH;EAAC,CAC4B,CAAC;AAE1C,CAAC;AAED,OAAO,MAAMc,YAAY,gBAAGxB,IAAI,CAACS,qBAAqB,CAAC;AACvDe,YAAY,CAACC,WAAW,GAAG,cAAc","ignoreList":[]}
1
+ {"version":3,"names":["React","memo","View","ContentPanelNestingContext","useContentPanelNestingGuard","jsx","_jsx","GUTTER_MASK_SPREAD","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","framed","surfaceClassName","surfaceStyle","contentClassName","contentStyle","surfaceBase","undefined","surfaceClass","join","contentClass","filter","Boolean","Provider","value","className","style","ContentPanel","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAOA,KAAK,IAAIC,IAAI,QAAQ,OAAO;AACnC,SAASC,IAAI,QAAwC,cAAc;AAEnE,SACEC,0BAA0B,EAC1BC,2BAA2B,QACtB,sBAAmB;;AAE1B;AACA;AACA;AACA;AAHA,SAAAC,GAAA,IAAAC,IAAA;AAIA,OAAO,MAAMC,kBAAkB,GAAG,EAAE;AACpC;AACA,OAAO,MAAMC,eAAe,GAAG,CAAC;AAChC;AACA,OAAO,MAAMC,kBAAkB,GAAG,CAAC;AA+BnC,MAAMC,qBAAkD,GAAGA,CAAC;EAC1DC,QAAQ;EACRC,MAAM;EACNC,gBAAgB;EAChBC,YAAY;EACZC,gBAAgB;EAChBC;AACF,CAAC,KAAK;EACJ;EACAZ,2BAA2B,CAAC,CAAC;;EAE7B;EACA;EACA;EACA;EACA,MAAMa,WAAW,GACfL,MAAM,KAAKM,SAAS,GAChB,2EAA2E,GAC3EN,MAAM,GACJ,+DAA+D,GAC/D,QAAQ;EAChB,MAAMO,YAAY,GAAG,CAACF,WAAW,EAAEJ,gBAAgB,IAAI,SAAS,CAAC,CAACO,IAAI,CAAC,GAAG,CAAC;EAC3E,MAAMC,YAAY,GAAG,CAAC,QAAQ,EAAEN,gBAAgB,CAAC,CAACO,MAAM,CAACC,OAAO,CAAC,CAACH,IAAI,CAAC,GAAG,CAAC;EAE3E,oBACEd,IAAA,CAACH,0BAA0B,CAACqB,QAAQ;IAACC,KAAK,EAAE,IAAK;IAAAd,QAAA,eAC/CL,IAAA,CAACJ,IAAI;MACIwB,SAAS,EAAEP,YAAY;MAC9BQ,KAAK,EAAEb,YAAa;MAAAH,QAAA,eAEpBL,IAAA,CAACJ,IAAI;QACIwB,SAAS,EAAEL,YAAY;QAC9BM,KAAK,EAAEX,YAAa;QAAAL,QAAA,EAEnBA;MAAQ,CACL;IAAC,CACH;EAAC,CAC4B,CAAC;AAE1C,CAAC;AAED,OAAO,MAAMiB,YAAY,gBAAG3B,IAAI,CAACS,qBAAqB,CAAC;AACvDkB,YAAY,CAACC,WAAW,GAAG,cAAc","ignoreList":[]}
@@ -25,16 +25,29 @@
25
25
  * content rather than displacing it). They render BEFORE the content wrapper so
26
26
  * z-index — not DOM order — decides layering.
27
27
  *
28
- * When `framed` is false (narrow screens) the panel is full-bleed: a single
29
- * flat surface, no rounding, no overlays.
28
+ * Framing is tri-state via the `framed` prop:
29
+ *
30
+ * - `undefined` (DEFAULT) → RESPONSIVE, driven purely by NativeWind: full-bleed
31
+ * below `md`, framed at `md`+. The rounding is `md:`-gated and both overlays
32
+ * are always rendered but carry `max-md:hidden` (`display:none` below `md`),
33
+ * so the breakpoint is decided in CSS — no consumer JS breakpoint hook.
34
+ * - `false` → NEVER framed (full-bleed at every size): a single flat surface,
35
+ * no rounding, no overlays.
36
+ * - `true` → ALWAYS framed (rounded + overlays at every size).
37
+ *
38
+ * The overlays are gated by VISIBILITY (a `max-md:hidden` literal) rather than
39
+ * by conditional mounting for the responsive case, so crossing the breakpoint
40
+ * never remounts them. The content wrapper likewise keeps a stable `key` so
41
+ * `{children}` reconciles in place across the breakpoint instead of remounting
42
+ * (which would reset feed scroll / the virtualizer + refetch).
30
43
  *
31
44
  * Native bundlers use `./index.tsx` (a plain rounded surface); web bundlers
32
45
  * select this file via the `"browser"` export condition in `package.json`.
33
46
  *
34
47
  * Styling is NativeWind-className-first; the literal class strings below MUST
35
48
  * stay literal so a consumer's Tailwind content-scan over `lib/**` picks them up
36
- * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28`
37
- * parts).
49
+ * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28` /
50
+ * `md:` parts — whole class strings are selected per mode instead).
38
51
  */
39
52
  import React, { memo } from 'react';
40
53
  import { View } from 'react-native';
@@ -58,28 +71,40 @@ const ContentPanelComponent = ({
58
71
  showStickyFrame,
59
72
  maskColor
60
73
  }) => {
61
- // Dev-only invariant — must run unconditionally before the early `!framed`
62
- // return so the hook order stays stable across renders (rules of hooks).
74
+ // Dev-only invariant — must run unconditionally (before deriving any
75
+ // mode-specific branch) so the hook order stays stable (rules of hooks).
63
76
  useContentPanelNestingGuard();
64
77
  const {
65
78
  colors
66
79
  } = useTheme();
67
- const surfaceClass = framed ? ['flex-1 rounded-radius-28', surfaceClassName ?? 'bg-card'].join(' ') : ['flex-1', surfaceClassName ?? 'bg-card'].join(' ');
68
- const contentClass = framed ? ['flex-1 rounded-radius-28 web:overflow-x-clip', contentClassName].filter(Boolean).join(' ') : ['flex-1', contentClassName].filter(Boolean).join(' ');
80
+
81
+ // Tri-state: `undefined` responsive (md:-gated), `true` always framed,
82
+ // `false` → never framed (full-bleed).
83
+ const responsive = framed === undefined;
84
+ const showOverlays = framed !== false;
85
+
86
+ // Whole literal class strings selected per mode (the Tailwind content-scan
87
+ // over `lib/**` requires each arbitrary/`md:`/`web:` token stay literal).
88
+ // `web:md:overflow-x-clip` is platform-first-then-breakpoint, matching the
89
+ // consumer convention (`web:sm:flex` in `@mercaria/ui`).
90
+ const surfaceBase = responsive ? 'flex-1 md:rounded-radius-28' : framed ? 'flex-1 rounded-radius-28' : 'flex-1';
91
+ const contentBase = responsive ? 'flex-1 md:rounded-radius-28 web:md:overflow-x-clip' : framed ? 'flex-1 rounded-radius-28 web:overflow-x-clip' : 'flex-1';
92
+ const surfaceClass = [surfaceBase, surfaceClassName ?? 'bg-card'].join(' ');
93
+ const contentClass = [contentBase, contentClassName].filter(Boolean).join(' ');
69
94
  return /*#__PURE__*/_jsx(ContentPanelNestingContext.Provider, {
70
95
  value: true,
71
96
  children: /*#__PURE__*/_jsxs(View, {
72
97
  className: surfaceClass,
73
98
  style: surfaceStyle,
74
- children: [framed && /*#__PURE__*/_jsx(View, {
99
+ children: [showOverlays && /*#__PURE__*/_jsx(View, {
75
100
  pointerEvents: "none",
76
- className: 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]',
101
+ className: responsive ? 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 max-md:hidden web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]' : 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]',
77
102
  style: {
78
103
  boxShadow: `0 0 0 ${GUTTER_MASK_SPREAD}px ${maskColor ?? colors.background}`
79
104
  }
80
- }, "bleed-mask"), framed && showStickyFrame !== false && /*#__PURE__*/_jsx(View, {
105
+ }, "bleed-mask"), showOverlays && showStickyFrame !== false && /*#__PURE__*/_jsx(View, {
81
106
  pointerEvents: "none",
82
- className: 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border web:[margin-bottom:calc(-100dvh+16px)]'
107
+ className: responsive ? 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border max-md:hidden web:[margin-bottom:calc(-100dvh+16px)]' : 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border web:[margin-bottom:calc(-100dvh+16px)]'
83
108
  }, "border-frame"), /*#__PURE__*/_jsx(View, {
84
109
  className: contentClass,
85
110
  style: contentStyle,
@@ -1 +1 @@
1
- {"version":3,"names":["React","memo","View","useTheme","ContentPanelNestingContext","useContentPanelNestingGuard","jsx","_jsx","jsxs","_jsxs","GUTTER_MASK_SPREAD","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","framed","surfaceClassName","surfaceStyle","contentClassName","contentStyle","showStickyFrame","maskColor","colors","surfaceClass","join","contentClass","filter","Boolean","Provider","value","className","style","pointerEvents","boxShadow","background","ContentPanel","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.web.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAOA,KAAK,IAAIC,IAAI,QAAQ,OAAO;AACnC,SAASC,IAAI,QAAwC,cAAc;AAEnE,SAASC,QAAQ,QAAQ,uBAAoB;AAC7C,SACEC,0BAA0B,EAC1BC,2BAA2B,QACtB,sBAAmB;;AAE1B;AAAA,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AACA,OAAO,MAAMC,kBAAkB,GAAG,EAAE;AACpC;AACA,OAAO,MAAMC,eAAe,GAAG,CAAC;AAChC;AACA,OAAO,MAAMC,kBAAkB,GAAG,CAAC;AAyBnC,MAAMC,qBAAkD,GAAGA,CAAC;EAC1DC,QAAQ;EACRC,MAAM;EACNC,gBAAgB;EAChBC,YAAY;EACZC,gBAAgB;EAChBC,YAAY;EACZC,eAAe;EACfC;AACF,CAAC,KAAK;EACJ;EACA;EACAhB,2BAA2B,CAAC,CAAC;EAC7B,MAAM;IAAEiB;EAAO,CAAC,GAAGnB,QAAQ,CAAC,CAAC;EAE7B,MAAMoB,YAAY,GAAGR,MAAM,GACvB,CAAC,0BAA0B,EAAEC,gBAAgB,IAAI,SAAS,CAAC,CAACQ,IAAI,CAAC,GAAG,CAAC,GACrE,CAAC,QAAQ,EAAER,gBAAgB,IAAI,SAAS,CAAC,CAACQ,IAAI,CAAC,GAAG,CAAC;EACvD,MAAMC,YAAY,GAAGV,MAAM,GACvB,CAAC,8CAA8C,EAAEG,gBAAgB,CAAC,CAACQ,MAAM,CAACC,OAAO,CAAC,CAACH,IAAI,CAAC,GAAG,CAAC,GAC5F,CAAC,QAAQ,EAAEN,gBAAgB,CAAC,CAACQ,MAAM,CAACC,OAAO,CAAC,CAACH,IAAI,CAAC,GAAG,CAAC;EAE1D,oBACEjB,IAAA,CAACH,0BAA0B,CAACwB,QAAQ;IAACC,KAAK,EAAE,IAAK;IAAAf,QAAA,eAC/CL,KAAA,CAACP,IAAI;MACI4B,SAAS,EAAEP,YAAY;MAC9BQ,KAAK,EAAEd,YAAa;MAAAH,QAAA,GAGnBC,MAAM,iBACLR,IAAA,CAACL,IAAI;QAEH8B,aAAa,EAAC,MAAM;QAElBF,SAAS,EACP,8IAA8I;QAElJC,KAAK,EAAE;UAAEE,SAAS,EAAE,SAASvB,kBAAkB,MAAMW,SAAS,IAAIC,MAAM,CAACY,UAAU;QAAG;MAAE,GANpF,YAOL,CACF,EAEAnB,MAAM,IAAIK,eAAe,KAAK,KAAK,iBAClCb,IAAA,CAACL,IAAI;QAEH8B,aAAa,EAAC,MAAM;QAElBF,SAAS,EACP;MAAyI,GAJzI,cAML,CACF,eAKDvB,IAAA,CAACL,IAAI;QAEI4B,SAAS,EAAEL,YAAY;QAC9BM,KAAK,EAAEZ,YAAa;QAAAL,QAAA,EAEnBA;MAAQ,GAJL,SAKA,CAAC;IAAA,CACH;EAAC,CAC4B,CAAC;AAE1C,CAAC;AAED,OAAO,MAAMqB,YAAY,gBAAGlC,IAAI,CAACY,qBAAqB,CAAC;AACvDsB,YAAY,CAACC,WAAW,GAAG,cAAc","ignoreList":[]}
1
+ {"version":3,"names":["React","memo","View","useTheme","ContentPanelNestingContext","useContentPanelNestingGuard","jsx","_jsx","jsxs","_jsxs","GUTTER_MASK_SPREAD","PANEL_TOP_INSET","PANEL_BOTTOM_INSET","ContentPanelComponent","children","framed","surfaceClassName","surfaceStyle","contentClassName","contentStyle","showStickyFrame","maskColor","colors","responsive","undefined","showOverlays","surfaceBase","contentBase","surfaceClass","join","contentClass","filter","Boolean","Provider","value","className","style","pointerEvents","boxShadow","background","ContentPanel","displayName"],"sourceRoot":"../../../src","sources":["content-panel/index.web.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAOA,KAAK,IAAIC,IAAI,QAAQ,OAAO;AACnC,SAASC,IAAI,QAAwC,cAAc;AAEnE,SAASC,QAAQ,QAAQ,uBAAoB;AAC7C,SACEC,0BAA0B,EAC1BC,2BAA2B,QACtB,sBAAmB;;AAE1B;AAAA,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AACA,OAAO,MAAMC,kBAAkB,GAAG,EAAE;AACpC;AACA,OAAO,MAAMC,eAAe,GAAG,CAAC;AAChC;AACA,OAAO,MAAMC,kBAAkB,GAAG,CAAC;AAgCnC,MAAMC,qBAAkD,GAAGA,CAAC;EAC1DC,QAAQ;EACRC,MAAM;EACNC,gBAAgB;EAChBC,YAAY;EACZC,gBAAgB;EAChBC,YAAY;EACZC,eAAe;EACfC;AACF,CAAC,KAAK;EACJ;EACA;EACAhB,2BAA2B,CAAC,CAAC;EAC7B,MAAM;IAAEiB;EAAO,CAAC,GAAGnB,QAAQ,CAAC,CAAC;;EAE7B;EACA;EACA,MAAMoB,UAAU,GAAGR,MAAM,KAAKS,SAAS;EACvC,MAAMC,YAAY,GAAGV,MAAM,KAAK,KAAK;;EAErC;EACA;EACA;EACA;EACA,MAAMW,WAAW,GAAGH,UAAU,GAC1B,6BAA6B,GAC7BR,MAAM,GACJ,0BAA0B,GAC1B,QAAQ;EACd,MAAMY,WAAW,GAAGJ,UAAU,GAC1B,oDAAoD,GACpDR,MAAM,GACJ,8CAA8C,GAC9C,QAAQ;EACd,MAAMa,YAAY,GAAG,CAACF,WAAW,EAAEV,gBAAgB,IAAI,SAAS,CAAC,CAACa,IAAI,CAAC,GAAG,CAAC;EAC3E,MAAMC,YAAY,GAAG,CAACH,WAAW,EAAET,gBAAgB,CAAC,CAACa,MAAM,CAACC,OAAO,CAAC,CAACH,IAAI,CAAC,GAAG,CAAC;EAE9E,oBACEtB,IAAA,CAACH,0BAA0B,CAAC6B,QAAQ;IAACC,KAAK,EAAE,IAAK;IAAApB,QAAA,eAC/CL,KAAA,CAACP,IAAI;MACIiC,SAAS,EAAEP,YAAY;MAC9BQ,KAAK,EAAEnB,YAAa;MAAAH,QAAA,GAKnBW,YAAY,iBACXlB,IAAA,CAACL,IAAI;QAEHmC,aAAa,EAAC,MAAM;QAElBF,SAAS,EAAEZ,UAAU,GACjB,4JAA4J,GAC5J,8IAA8I;QAEpJa,KAAK,EAAE;UAAEE,SAAS,EAAE,SAAS5B,kBAAkB,MAAMW,SAAS,IAAIC,MAAM,CAACiB,UAAU;QAAG;MAAE,GAPpF,YAQL,CACF,EAGAd,YAAY,IAAIL,eAAe,KAAK,KAAK,iBACxCb,IAAA,CAACL,IAAI;QAEHmC,aAAa,EAAC,MAAM;QAElBF,SAAS,EAAEZ,UAAU,GACjB,uJAAuJ,GACvJ;MAAyI,GAL3I,cAOL,CACF,eAKDhB,IAAA,CAACL,IAAI;QAEIiC,SAAS,EAAEL,YAAY;QAC9BM,KAAK,EAAEjB,YAAa;QAAAL,QAAA,EAEnBA;MAAQ,GAJL,SAKA,CAAC;IAAA,CACH;EAAC,CAC4B,CAAC;AAE1C,CAAC;AAED,OAAO,MAAM0B,YAAY,gBAAGvC,IAAI,CAACY,qBAAqB,CAAC;AACvD2B,YAAY,CAACC,WAAW,GAAG,cAAc","ignoreList":[]}
@@ -7,11 +7,20 @@
7
7
  * the rounded corners / lateral gutters is masked while a single seamless border
8
8
  * is drawn around the panel — see `index.web.tsx`.
9
9
  *
10
- * On NATIVE none of that applies: there is no document scroll, no sticky
11
- * positioning, and no bleed to mask, so the panel is simply a rounded, bordered
12
- * surface wrapping its content. The `framed` and `showStickyFrame` props are
13
- * accepted for cross-platform API parity but are intentionally no-ops here
14
- * (mirroring the no-op native fork of `../scroll`).
10
+ * On NATIVE none of the WEB overlay machinery applies: there is no document
11
+ * scroll, no sticky positioning, and no bleed to mask, so the panel is simply a
12
+ * surface wrapping its content. The `framed` prop still drives whether that
13
+ * surface is rounded + bordered, tri-state and resolved with pure NativeWind
14
+ * (`md:` evaluates against the window width on native too no JS breakpoint
15
+ * hook needed):
16
+ *
17
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
18
+ * bordered at `md`+ (`md:rounded-radius-28 md:border md:border-border`).
19
+ * - `false` → never framed (plain full-bleed at every size).
20
+ * - `true` → always rounded + bordered.
21
+ *
22
+ * `showStickyFrame` and `maskColor` are accepted for cross-platform API parity
23
+ * but are no-ops here (there are no sticky overlays on native).
15
24
  *
16
25
  * Web bundlers select `./index.web` via the `"browser"` export condition in
17
26
  * `package.json`; native bundlers fall through to this file.
@@ -34,10 +43,14 @@ export declare const PANEL_BOTTOM_INSET = 8;
34
43
  export interface ContentPanelProps {
35
44
  children: React.ReactNode;
36
45
  /**
37
- * Whether the panel is framed (wide screens) or full-bleed (narrow screens).
38
- * No-op on native — the surface is always a rounded, bordered View.
46
+ * Framing mode. Tri-state, resolved purely with NativeWind no consumer
47
+ * breakpoint hook needed:
48
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
49
+ * bordered at `md`+.
50
+ * - `false` → never framed (plain full-bleed at every size).
51
+ * - `true` → always rounded + bordered.
39
52
  */
40
- framed: boolean;
53
+ framed?: boolean;
41
54
  /** Override the surface background utility (defaults to `bg-card`). */
42
55
  surfaceClassName?: string;
43
56
  surfaceStyle?: StyleProp<ViewStyle>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAOpE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,wDAAwD;AACxD,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqCD,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAOpE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,wDAAwD;AACxD,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2CD,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
@@ -23,16 +23,29 @@
23
23
  * content rather than displacing it). They render BEFORE the content wrapper so
24
24
  * z-index — not DOM order — decides layering.
25
25
  *
26
- * When `framed` is false (narrow screens) the panel is full-bleed: a single
27
- * flat surface, no rounding, no overlays.
26
+ * Framing is tri-state via the `framed` prop:
27
+ *
28
+ * - `undefined` (DEFAULT) → RESPONSIVE, driven purely by NativeWind: full-bleed
29
+ * below `md`, framed at `md`+. The rounding is `md:`-gated and both overlays
30
+ * are always rendered but carry `max-md:hidden` (`display:none` below `md`),
31
+ * so the breakpoint is decided in CSS — no consumer JS breakpoint hook.
32
+ * - `false` → NEVER framed (full-bleed at every size): a single flat surface,
33
+ * no rounding, no overlays.
34
+ * - `true` → ALWAYS framed (rounded + overlays at every size).
35
+ *
36
+ * The overlays are gated by VISIBILITY (a `max-md:hidden` literal) rather than
37
+ * by conditional mounting for the responsive case, so crossing the breakpoint
38
+ * never remounts them. The content wrapper likewise keeps a stable `key` so
39
+ * `{children}` reconciles in place across the breakpoint instead of remounting
40
+ * (which would reset feed scroll / the virtualizer + refetch).
28
41
  *
29
42
  * Native bundlers use `./index.tsx` (a plain rounded surface); web bundlers
30
43
  * select this file via the `"browser"` export condition in `package.json`.
31
44
  *
32
45
  * Styling is NativeWind-className-first; the literal class strings below MUST
33
46
  * stay literal so a consumer's Tailwind content-scan over `lib/**` picks them up
34
- * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28`
35
- * parts).
47
+ * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28` /
48
+ * `md:` parts — whole class strings are selected per mode instead).
36
49
  */
37
50
  import React from 'react';
38
51
  import { type StyleProp, type ViewStyle } from 'react-native';
@@ -44,8 +57,15 @@ export declare const PANEL_TOP_INSET = 8;
44
57
  export declare const PANEL_BOTTOM_INSET = 8;
45
58
  export interface ContentPanelProps {
46
59
  children: React.ReactNode;
47
- /** Framed (wide screens) vs full-bleed (narrow screens). */
48
- framed: boolean;
60
+ /**
61
+ * Framing mode. Tri-state, resolved purely with NativeWind — no consumer
62
+ * breakpoint hook needed:
63
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, framed at
64
+ * `md`+ (rounded corners + sticky bleed-mask/border overlays).
65
+ * - `false` → never framed (full-bleed at every size).
66
+ * - `true` → always framed (rounded + overlays at every size).
67
+ */
68
+ framed?: boolean;
49
69
  /** Override the surface background utility (defaults to `bg-card`). */
50
70
  surfaceClassName?: string;
51
71
  surfaceStyle?: StyleProp<ViewStyle>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.web.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAQpE,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,6DAA6D;AAC7D,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,4DAA4D;IAC5D,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qEAAqE;IACrE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqED,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.web.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAQpE,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,6DAA6D;AAC7D,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qEAAqE;IACrE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyFD,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
@@ -7,11 +7,20 @@
7
7
  * the rounded corners / lateral gutters is masked while a single seamless border
8
8
  * is drawn around the panel — see `index.web.tsx`.
9
9
  *
10
- * On NATIVE none of that applies: there is no document scroll, no sticky
11
- * positioning, and no bleed to mask, so the panel is simply a rounded, bordered
12
- * surface wrapping its content. The `framed` and `showStickyFrame` props are
13
- * accepted for cross-platform API parity but are intentionally no-ops here
14
- * (mirroring the no-op native fork of `../scroll`).
10
+ * On NATIVE none of the WEB overlay machinery applies: there is no document
11
+ * scroll, no sticky positioning, and no bleed to mask, so the panel is simply a
12
+ * surface wrapping its content. The `framed` prop still drives whether that
13
+ * surface is rounded + bordered, tri-state and resolved with pure NativeWind
14
+ * (`md:` evaluates against the window width on native too no JS breakpoint
15
+ * hook needed):
16
+ *
17
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
18
+ * bordered at `md`+ (`md:rounded-radius-28 md:border md:border-border`).
19
+ * - `false` → never framed (plain full-bleed at every size).
20
+ * - `true` → always rounded + bordered.
21
+ *
22
+ * `showStickyFrame` and `maskColor` are accepted for cross-platform API parity
23
+ * but are no-ops here (there are no sticky overlays on native).
15
24
  *
16
25
  * Web bundlers select `./index.web` via the `"browser"` export condition in
17
26
  * `package.json`; native bundlers fall through to this file.
@@ -34,10 +43,14 @@ export declare const PANEL_BOTTOM_INSET = 8;
34
43
  export interface ContentPanelProps {
35
44
  children: React.ReactNode;
36
45
  /**
37
- * Whether the panel is framed (wide screens) or full-bleed (narrow screens).
38
- * No-op on native — the surface is always a rounded, bordered View.
46
+ * Framing mode. Tri-state, resolved purely with NativeWind no consumer
47
+ * breakpoint hook needed:
48
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
49
+ * bordered at `md`+.
50
+ * - `false` → never framed (plain full-bleed at every size).
51
+ * - `true` → always rounded + bordered.
39
52
  */
40
- framed: boolean;
53
+ framed?: boolean;
41
54
  /** Override the surface background utility (defaults to `bg-card`). */
42
55
  surfaceClassName?: string;
43
56
  surfaceStyle?: StyleProp<ViewStyle>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAOpE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,wDAAwD;AACxD,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqCD,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAOpE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,wDAAwD;AACxD,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2CD,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
@@ -23,16 +23,29 @@
23
23
  * content rather than displacing it). They render BEFORE the content wrapper so
24
24
  * z-index — not DOM order — decides layering.
25
25
  *
26
- * When `framed` is false (narrow screens) the panel is full-bleed: a single
27
- * flat surface, no rounding, no overlays.
26
+ * Framing is tri-state via the `framed` prop:
27
+ *
28
+ * - `undefined` (DEFAULT) → RESPONSIVE, driven purely by NativeWind: full-bleed
29
+ * below `md`, framed at `md`+. The rounding is `md:`-gated and both overlays
30
+ * are always rendered but carry `max-md:hidden` (`display:none` below `md`),
31
+ * so the breakpoint is decided in CSS — no consumer JS breakpoint hook.
32
+ * - `false` → NEVER framed (full-bleed at every size): a single flat surface,
33
+ * no rounding, no overlays.
34
+ * - `true` → ALWAYS framed (rounded + overlays at every size).
35
+ *
36
+ * The overlays are gated by VISIBILITY (a `max-md:hidden` literal) rather than
37
+ * by conditional mounting for the responsive case, so crossing the breakpoint
38
+ * never remounts them. The content wrapper likewise keeps a stable `key` so
39
+ * `{children}` reconciles in place across the breakpoint instead of remounting
40
+ * (which would reset feed scroll / the virtualizer + refetch).
28
41
  *
29
42
  * Native bundlers use `./index.tsx` (a plain rounded surface); web bundlers
30
43
  * select this file via the `"browser"` export condition in `package.json`.
31
44
  *
32
45
  * Styling is NativeWind-className-first; the literal class strings below MUST
33
46
  * stay literal so a consumer's Tailwind content-scan over `lib/**` picks them up
34
- * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28`
35
- * parts).
47
+ * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28` /
48
+ * `md:` parts — whole class strings are selected per mode instead).
36
49
  */
37
50
  import React from 'react';
38
51
  import { type StyleProp, type ViewStyle } from 'react-native';
@@ -44,8 +57,15 @@ export declare const PANEL_TOP_INSET = 8;
44
57
  export declare const PANEL_BOTTOM_INSET = 8;
45
58
  export interface ContentPanelProps {
46
59
  children: React.ReactNode;
47
- /** Framed (wide screens) vs full-bleed (narrow screens). */
48
- framed: boolean;
60
+ /**
61
+ * Framing mode. Tri-state, resolved purely with NativeWind — no consumer
62
+ * breakpoint hook needed:
63
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, framed at
64
+ * `md`+ (rounded corners + sticky bleed-mask/border overlays).
65
+ * - `false` → never framed (full-bleed at every size).
66
+ * - `true` → always framed (rounded + overlays at every size).
67
+ */
68
+ framed?: boolean;
49
69
  /** Override the surface background utility (defaults to `bg-card`). */
50
70
  surfaceClassName?: string;
51
71
  surfaceStyle?: StyleProp<ViewStyle>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.web.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAQpE,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,6DAA6D;AAC7D,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,4DAA4D;IAC5D,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qEAAqE;IACrE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqED,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/content-panel/index.web.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAQpE,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,6DAA6D;AAC7D,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,qEAAqE;IACrE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyFD,eAAO,MAAM,YAAY,+CAA8B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/bloom",
3
- "version": "0.35.6",
3
+ "version": "0.35.7",
4
4
  "description": "Bloom UI — Oxy ecosystem component library for React Native + Expo + Web",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -7,11 +7,20 @@
7
7
  * the rounded corners / lateral gutters is masked while a single seamless border
8
8
  * is drawn around the panel — see `index.web.tsx`.
9
9
  *
10
- * On NATIVE none of that applies: there is no document scroll, no sticky
11
- * positioning, and no bleed to mask, so the panel is simply a rounded, bordered
12
- * surface wrapping its content. The `framed` and `showStickyFrame` props are
13
- * accepted for cross-platform API parity but are intentionally no-ops here
14
- * (mirroring the no-op native fork of `../scroll`).
10
+ * On NATIVE none of the WEB overlay machinery applies: there is no document
11
+ * scroll, no sticky positioning, and no bleed to mask, so the panel is simply a
12
+ * surface wrapping its content. The `framed` prop still drives whether that
13
+ * surface is rounded + bordered, tri-state and resolved with pure NativeWind
14
+ * (`md:` evaluates against the window width on native too no JS breakpoint
15
+ * hook needed):
16
+ *
17
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
18
+ * bordered at `md`+ (`md:rounded-radius-28 md:border md:border-border`).
19
+ * - `false` → never framed (plain full-bleed at every size).
20
+ * - `true` → always rounded + bordered.
21
+ *
22
+ * `showStickyFrame` and `maskColor` are accepted for cross-platform API parity
23
+ * but are no-ops here (there are no sticky overlays on native).
15
24
  *
16
25
  * Web bundlers select `./index.web` via the `"browser"` export condition in
17
26
  * `package.json`; native bundlers fall through to this file.
@@ -41,10 +50,14 @@ export const PANEL_BOTTOM_INSET = 8;
41
50
  export interface ContentPanelProps {
42
51
  children: React.ReactNode;
43
52
  /**
44
- * Whether the panel is framed (wide screens) or full-bleed (narrow screens).
45
- * No-op on native — the surface is always a rounded, bordered View.
53
+ * Framing mode. Tri-state, resolved purely with NativeWind no consumer
54
+ * breakpoint hook needed:
55
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, rounded +
56
+ * bordered at `md`+.
57
+ * - `false` → never framed (plain full-bleed at every size).
58
+ * - `true` → always rounded + bordered.
46
59
  */
47
- framed: boolean;
60
+ framed?: boolean;
48
61
  /** Override the surface background utility (defaults to `bg-card`). */
49
62
  surfaceClassName?: string;
50
63
  surfaceStyle?: StyleProp<ViewStyle>;
@@ -65,6 +78,7 @@ export interface ContentPanelProps {
65
78
 
66
79
  const ContentPanelComponent: React.FC<ContentPanelProps> = ({
67
80
  children,
81
+ framed,
68
82
  surfaceClassName,
69
83
  surfaceStyle,
70
84
  contentClassName,
@@ -73,12 +87,17 @@ const ContentPanelComponent: React.FC<ContentPanelProps> = ({
73
87
  // Dev-only invariant — a ContentPanel must never be nested inside another.
74
88
  useContentPanelNestingGuard();
75
89
 
76
- const surfaceClass = [
77
- 'flex-1',
78
- 'rounded-radius-28',
79
- 'overflow-hidden border border-border',
80
- surfaceClassName ?? 'bg-card',
81
- ].join(' ');
90
+ // Tri-state: `undefined` → responsive (md:-gated), `true` → always framed,
91
+ // `false` → never framed (plain full-bleed). Whole literal class strings are
92
+ // selected per mode so the Tailwind content-scan over `src/**` picks up every
93
+ // `md:` / `rounded-radius-28` token verbatim (no dynamic concatenation).
94
+ const surfaceBase =
95
+ framed === undefined
96
+ ? 'flex-1 md:overflow-hidden md:rounded-radius-28 md:border md:border-border'
97
+ : framed
98
+ ? 'flex-1 overflow-hidden rounded-radius-28 border border-border'
99
+ : 'flex-1';
100
+ const surfaceClass = [surfaceBase, surfaceClassName ?? 'bg-card'].join(' ');
82
101
  const contentClass = ['flex-1', contentClassName].filter(Boolean).join(' ');
83
102
 
84
103
  return (
@@ -23,16 +23,29 @@
23
23
  * content rather than displacing it). They render BEFORE the content wrapper so
24
24
  * z-index — not DOM order — decides layering.
25
25
  *
26
- * When `framed` is false (narrow screens) the panel is full-bleed: a single
27
- * flat surface, no rounding, no overlays.
26
+ * Framing is tri-state via the `framed` prop:
27
+ *
28
+ * - `undefined` (DEFAULT) → RESPONSIVE, driven purely by NativeWind: full-bleed
29
+ * below `md`, framed at `md`+. The rounding is `md:`-gated and both overlays
30
+ * are always rendered but carry `max-md:hidden` (`display:none` below `md`),
31
+ * so the breakpoint is decided in CSS — no consumer JS breakpoint hook.
32
+ * - `false` → NEVER framed (full-bleed at every size): a single flat surface,
33
+ * no rounding, no overlays.
34
+ * - `true` → ALWAYS framed (rounded + overlays at every size).
35
+ *
36
+ * The overlays are gated by VISIBILITY (a `max-md:hidden` literal) rather than
37
+ * by conditional mounting for the responsive case, so crossing the breakpoint
38
+ * never remounts them. The content wrapper likewise keeps a stable `key` so
39
+ * `{children}` reconciles in place across the breakpoint instead of remounting
40
+ * (which would reset feed scroll / the virtualizer + refetch).
28
41
  *
29
42
  * Native bundlers use `./index.tsx` (a plain rounded surface); web bundlers
30
43
  * select this file via the `"browser"` export condition in `package.json`.
31
44
  *
32
45
  * Styling is NativeWind-className-first; the literal class strings below MUST
33
46
  * stay literal so a consumer's Tailwind content-scan over `lib/**` picks them up
34
- * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28`
35
- * parts).
47
+ * (no dynamic concatenation of the arbitrary `web:[…]` / `rounded-radius-28` /
48
+ * `md:` parts — whole class strings are selected per mode instead).
36
49
  */
37
50
  import React, { memo } from 'react';
38
51
  import { View, type StyleProp, type ViewStyle } from 'react-native';
@@ -52,8 +65,15 @@ export const PANEL_BOTTOM_INSET = 8;
52
65
 
53
66
  export interface ContentPanelProps {
54
67
  children: React.ReactNode;
55
- /** Framed (wide screens) vs full-bleed (narrow screens). */
56
- framed: boolean;
68
+ /**
69
+ * Framing mode. Tri-state, resolved purely with NativeWind — no consumer
70
+ * breakpoint hook needed:
71
+ * - `undefined` (DEFAULT) → responsive: full-bleed below `md`, framed at
72
+ * `md`+ (rounded corners + sticky bleed-mask/border overlays).
73
+ * - `false` → never framed (full-bleed at every size).
74
+ * - `true` → always framed (rounded + overlays at every size).
75
+ */
76
+ framed?: boolean;
57
77
  /** Override the surface background utility (defaults to `bg-card`). */
58
78
  surfaceClassName?: string;
59
79
  surfaceStyle?: StyleProp<ViewStyle>;
@@ -83,17 +103,32 @@ const ContentPanelComponent: React.FC<ContentPanelProps> = ({
83
103
  showStickyFrame,
84
104
  maskColor,
85
105
  }) => {
86
- // Dev-only invariant — must run unconditionally before the early `!framed`
87
- // return so the hook order stays stable across renders (rules of hooks).
106
+ // Dev-only invariant — must run unconditionally (before deriving any
107
+ // mode-specific branch) so the hook order stays stable (rules of hooks).
88
108
  useContentPanelNestingGuard();
89
109
  const { colors } = useTheme();
90
110
 
91
- const surfaceClass = framed
92
- ? ['flex-1 rounded-radius-28', surfaceClassName ?? 'bg-card'].join(' ')
93
- : ['flex-1', surfaceClassName ?? 'bg-card'].join(' ');
94
- const contentClass = framed
95
- ? ['flex-1 rounded-radius-28 web:overflow-x-clip', contentClassName].filter(Boolean).join(' ')
96
- : ['flex-1', contentClassName].filter(Boolean).join(' ');
111
+ // Tri-state: `undefined` → responsive (md:-gated), `true` → always framed,
112
+ // `false` never framed (full-bleed).
113
+ const responsive = framed === undefined;
114
+ const showOverlays = framed !== false;
115
+
116
+ // Whole literal class strings selected per mode (the Tailwind content-scan
117
+ // over `lib/**` requires each arbitrary/`md:`/`web:` token stay literal).
118
+ // `web:md:overflow-x-clip` is platform-first-then-breakpoint, matching the
119
+ // consumer convention (`web:sm:flex` in `@mercaria/ui`).
120
+ const surfaceBase = responsive
121
+ ? 'flex-1 md:rounded-radius-28'
122
+ : framed
123
+ ? 'flex-1 rounded-radius-28'
124
+ : 'flex-1';
125
+ const contentBase = responsive
126
+ ? 'flex-1 md:rounded-radius-28 web:md:overflow-x-clip'
127
+ : framed
128
+ ? 'flex-1 rounded-radius-28 web:overflow-x-clip'
129
+ : 'flex-1';
130
+ const surfaceClass = [surfaceBase, surfaceClassName ?? 'bg-card'].join(' ');
131
+ const contentClass = [contentBase, contentClassName].filter(Boolean).join(' ');
97
132
 
98
133
  return (
99
134
  <ContentPanelNestingContext.Provider value={true}>
@@ -101,26 +136,31 @@ const ContentPanelComponent: React.FC<ContentPanelProps> = ({
101
136
  {...({ className: surfaceClass } as Record<string, string>)}
102
137
  style={surfaceStyle}
103
138
  >
104
- {/* (1) Bleed-mask overlay — gutter box-shadow ring, below chrome. Framed only. */}
105
- {framed && (
139
+ {/* (1) Bleed-mask overlay — gutter box-shadow ring, below chrome. Not
140
+ rendered when never-framed; `max-md:hidden` (display:none <md) when
141
+ responsive, so the breakpoint is decided in CSS, not by remounting. */}
142
+ {showOverlays && (
106
143
  <View
107
144
  key="bleed-mask"
108
145
  pointerEvents="none"
109
146
  {...({
110
- className:
111
- 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]',
147
+ className: responsive
148
+ ? 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 max-md:hidden web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]'
149
+ : 'web:sticky web:top-2 z-30 h-[calc(100dvh-16px)] w-full rounded-radius-28 web:[margin-bottom:calc(-100dvh+16px)] web:[clip-path:inset(-12px)]',
112
150
  } as Record<string, string>)}
113
151
  style={{ boxShadow: `0 0 0 ${GUTTER_MASK_SPREAD}px ${maskColor ?? colors.background}` }}
114
152
  />
115
153
  )}
116
- {/* (2) Border-frame overlay — one continuous rounded border, above all. Framed only. */}
117
- {framed && showStickyFrame !== false && (
154
+ {/* (2) Border-frame overlay — one continuous rounded border, above all.
155
+ Same visibility gating as the bleed-mask. */}
156
+ {showOverlays && showStickyFrame !== false && (
118
157
  <View
119
158
  key="border-frame"
120
159
  pointerEvents="none"
121
160
  {...({
122
- className:
123
- 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border web:[margin-bottom:calc(-100dvh+16px)]',
161
+ className: responsive
162
+ ? 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border max-md:hidden web:[margin-bottom:calc(-100dvh+16px)]'
163
+ : 'web:sticky web:top-2 z-[120] h-[calc(100dvh-16px)] w-full rounded-radius-28 border border-border web:[margin-bottom:calc(-100dvh+16px)]',
124
164
  } as Record<string, string>)}
125
165
  />
126
166
  )}