@camstack/ui-library 1.1.32 → 1.1.33

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.
@@ -6,6 +6,30 @@ export interface SlideOverPanelProps {
6
6
  readonly subtitle?: ReactNode;
7
7
  readonly footer?: ReactNode;
8
8
  readonly children: ReactNode;
9
+ /**
10
+ * Width of the DESKTOP (`md+`) in-container slide-over. Ignored on mobile,
11
+ * where the panel is a full-width, viewport-anchored bottom sheet. Pass a
12
+ * responsive class (e.g. `md:w-[420px]`) — a bare `w-*` would also constrain
13
+ * the mobile sheet. Default: `md:w-[360px]`.
14
+ */
9
15
  readonly widthClass?: string;
10
16
  }
17
+ /**
18
+ * SlideOverPanel — a detail surface anchored to context on desktop and to the
19
+ * viewport on mobile.
20
+ *
21
+ * - **Desktop (`md+`):** an in-container, NON-modal slide-over pinned to the
22
+ * right edge of the nearest positioned ancestor. The host reserves space with
23
+ * a matching `md:pr-*` so the panel sits beside its content (e.g. the
24
+ * multi-node pipeline matrix), not over it.
25
+ * - **Mobile (`< md`):** a MODAL bottom sheet pinned to the viewport
26
+ * (`position: fixed`). It never derives its size from the surrounding
27
+ * container, so it can't stretch across a horizontally-laid-out node matrix
28
+ * and overflow the page — the previous behaviour when it was a fixed-width
29
+ * `absolute` panel anchored to the wide matrix wrapper.
30
+ *
31
+ * The whole desktop⇄mobile transform is pure Tailwind responsive classes on one
32
+ * element — no layout-shift on hydration, no portal. JS is used only to lock
33
+ * body scroll behind the mobile sheet and to wire Escape-to-close.
34
+ */
11
35
  export declare function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass, }: SlideOverPanelProps): import("react").JSX.Element | null;
package/dist/index.cjs CHANGED
@@ -13129,7 +13129,26 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
13129
13129
  }
13130
13130
  //#endregion
13131
13131
  //#region src/composites/slide-over-panel.tsx
13132
- function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass = "w-[360px]" }) {
13132
+ /**
13133
+ * SlideOverPanel — a detail surface anchored to context on desktop and to the
13134
+ * viewport on mobile.
13135
+ *
13136
+ * - **Desktop (`md+`):** an in-container, NON-modal slide-over pinned to the
13137
+ * right edge of the nearest positioned ancestor. The host reserves space with
13138
+ * a matching `md:pr-*` so the panel sits beside its content (e.g. the
13139
+ * multi-node pipeline matrix), not over it.
13140
+ * - **Mobile (`< md`):** a MODAL bottom sheet pinned to the viewport
13141
+ * (`position: fixed`). It never derives its size from the surrounding
13142
+ * container, so it can't stretch across a horizontally-laid-out node matrix
13143
+ * and overflow the page — the previous behaviour when it was a fixed-width
13144
+ * `absolute` panel anchored to the wide matrix wrapper.
13145
+ *
13146
+ * The whole desktop⇄mobile transform is pure Tailwind responsive classes on one
13147
+ * element — no layout-shift on hydration, no portal. JS is used only to lock
13148
+ * body scroll behind the mobile sheet and to wire Escape-to-close.
13149
+ */
13150
+ function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass = "md:w-[360px]" }) {
13151
+ const isMobile = useIsMobile();
13133
13152
  (0, react$1.useEffect)(() => {
13134
13153
  if (!open) return;
13135
13154
  const onEsc = (e) => {
@@ -13138,14 +13157,31 @@ function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widt
13138
13157
  window.addEventListener("keydown", onEsc);
13139
13158
  return () => window.removeEventListener("keydown", onEsc);
13140
13159
  }, [open, onClose]);
13160
+ (0, react$1.useEffect)(() => {
13161
+ if (!open || !isMobile) return;
13162
+ const previous = document.body.style.overflow;
13163
+ document.body.style.overflow = "hidden";
13164
+ return () => {
13165
+ document.body.style.overflow = previous;
13166
+ };
13167
+ }, [open, isMobile]);
13141
13168
  if (!open) return null;
13142
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
13143
- className: cn("absolute top-0 right-0 bottom-0 z-20 flex flex-col", "bg-surface border-l border-border shadow-xl", widthClass),
13169
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13170
+ className: "fixed inset-0 z-40 bg-black/50 md:hidden",
13171
+ onClick: onClose,
13172
+ "aria-hidden": "true"
13173
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
13174
+ className: cn("fixed inset-x-0 bottom-0 z-50 flex flex-col", "max-h-[85dvh] rounded-t-2xl border-t border-border", "bg-surface shadow-2xl pb-[env(safe-area-inset-bottom)]", "md:absolute md:inset-x-auto md:top-0 md:right-0 md:bottom-0 md:z-20", "md:max-h-none md:rounded-none md:border-t-0 md:border-l md:pb-0", widthClass),
13144
13175
  role: "dialog",
13145
- "aria-modal": "false",
13176
+ "aria-modal": isMobile ? "true" : "false",
13146
13177
  children: [
13178
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13179
+ className: "flex shrink-0 justify-center pt-2 pb-1 md:hidden",
13180
+ "aria-hidden": "true",
13181
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "h-1 w-9 rounded-full bg-foreground-subtle/30" })
13182
+ }),
13147
13183
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
13148
- className: "flex items-start justify-between gap-2 px-4 py-3 border-b border-border",
13184
+ className: "flex shrink-0 items-start justify-between gap-2 px-4 py-3 border-b border-border",
13149
13185
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13150
13186
  className: "min-w-0",
13151
13187
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13164,15 +13200,15 @@ function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widt
13164
13200
  })]
13165
13201
  }),
13166
13202
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13167
- className: "flex-1 min-h-0 overflow-y-auto px-4 py-3",
13203
+ className: "flex-1 min-h-0 overflow-y-auto overscroll-contain px-4 py-3",
13168
13204
  children
13169
13205
  }),
13170
13206
  footer !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("footer", {
13171
- className: "flex items-center gap-2 justify-end px-4 py-3 border-t border-border",
13207
+ className: "flex shrink-0 items-center gap-2 justify-end px-4 py-3 border-t border-border",
13172
13208
  children: footer
13173
13209
  })
13174
13210
  ]
13175
- });
13211
+ })] });
13176
13212
  }
13177
13213
  //#endregion
13178
13214
  //#region src/composites/step-tree-master.tsx
package/dist/index.js CHANGED
@@ -13105,7 +13105,26 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
13105
13105
  }
13106
13106
  //#endregion
13107
13107
  //#region src/composites/slide-over-panel.tsx
13108
- function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass = "w-[360px]" }) {
13108
+ /**
13109
+ * SlideOverPanel — a detail surface anchored to context on desktop and to the
13110
+ * viewport on mobile.
13111
+ *
13112
+ * - **Desktop (`md+`):** an in-container, NON-modal slide-over pinned to the
13113
+ * right edge of the nearest positioned ancestor. The host reserves space with
13114
+ * a matching `md:pr-*` so the panel sits beside its content (e.g. the
13115
+ * multi-node pipeline matrix), not over it.
13116
+ * - **Mobile (`< md`):** a MODAL bottom sheet pinned to the viewport
13117
+ * (`position: fixed`). It never derives its size from the surrounding
13118
+ * container, so it can't stretch across a horizontally-laid-out node matrix
13119
+ * and overflow the page — the previous behaviour when it was a fixed-width
13120
+ * `absolute` panel anchored to the wide matrix wrapper.
13121
+ *
13122
+ * The whole desktop⇄mobile transform is pure Tailwind responsive classes on one
13123
+ * element — no layout-shift on hydration, no portal. JS is used only to lock
13124
+ * body scroll behind the mobile sheet and to wire Escape-to-close.
13125
+ */
13126
+ function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widthClass = "md:w-[360px]" }) {
13127
+ const isMobile = useIsMobile();
13109
13128
  useEffect(() => {
13110
13129
  if (!open) return;
13111
13130
  const onEsc = (e) => {
@@ -13114,14 +13133,31 @@ function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widt
13114
13133
  window.addEventListener("keydown", onEsc);
13115
13134
  return () => window.removeEventListener("keydown", onEsc);
13116
13135
  }, [open, onClose]);
13136
+ useEffect(() => {
13137
+ if (!open || !isMobile) return;
13138
+ const previous = document.body.style.overflow;
13139
+ document.body.style.overflow = "hidden";
13140
+ return () => {
13141
+ document.body.style.overflow = previous;
13142
+ };
13143
+ }, [open, isMobile]);
13117
13144
  if (!open) return null;
13118
- return /* @__PURE__ */ jsxs("aside", {
13119
- className: cn("absolute top-0 right-0 bottom-0 z-20 flex flex-col", "bg-surface border-l border-border shadow-xl", widthClass),
13145
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
13146
+ className: "fixed inset-0 z-40 bg-black/50 md:hidden",
13147
+ onClick: onClose,
13148
+ "aria-hidden": "true"
13149
+ }), /* @__PURE__ */ jsxs("aside", {
13150
+ className: cn("fixed inset-x-0 bottom-0 z-50 flex flex-col", "max-h-[85dvh] rounded-t-2xl border-t border-border", "bg-surface shadow-2xl pb-[env(safe-area-inset-bottom)]", "md:absolute md:inset-x-auto md:top-0 md:right-0 md:bottom-0 md:z-20", "md:max-h-none md:rounded-none md:border-t-0 md:border-l md:pb-0", widthClass),
13120
13151
  role: "dialog",
13121
- "aria-modal": "false",
13152
+ "aria-modal": isMobile ? "true" : "false",
13122
13153
  children: [
13154
+ /* @__PURE__ */ jsx("div", {
13155
+ className: "flex shrink-0 justify-center pt-2 pb-1 md:hidden",
13156
+ "aria-hidden": "true",
13157
+ children: /* @__PURE__ */ jsx("div", { className: "h-1 w-9 rounded-full bg-foreground-subtle/30" })
13158
+ }),
13123
13159
  /* @__PURE__ */ jsxs("header", {
13124
- className: "flex items-start justify-between gap-2 px-4 py-3 border-b border-border",
13160
+ className: "flex shrink-0 items-start justify-between gap-2 px-4 py-3 border-b border-border",
13125
13161
  children: [/* @__PURE__ */ jsxs("div", {
13126
13162
  className: "min-w-0",
13127
13163
  children: [/* @__PURE__ */ jsx("div", {
@@ -13140,15 +13176,15 @@ function SlideOverPanel({ open, onClose, title, subtitle, footer, children, widt
13140
13176
  })]
13141
13177
  }),
13142
13178
  /* @__PURE__ */ jsx("div", {
13143
- className: "flex-1 min-h-0 overflow-y-auto px-4 py-3",
13179
+ className: "flex-1 min-h-0 overflow-y-auto overscroll-contain px-4 py-3",
13144
13180
  children
13145
13181
  }),
13146
13182
  footer !== void 0 && /* @__PURE__ */ jsx("footer", {
13147
- className: "flex items-center gap-2 justify-end px-4 py-3 border-t border-border",
13183
+ className: "flex shrink-0 items-center gap-2 justify-end px-4 py-3 border-t border-border",
13148
13184
  children: footer
13149
13185
  })
13150
13186
  ]
13151
- });
13187
+ })] });
13152
13188
  }
13153
13189
  //#endregion
13154
13190
  //#region src/composites/step-tree-master.tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/ui-library",
3
- "version": "1.1.32",
3
+ "version": "1.1.33",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",