@sproutsocial/seeds-react-panel 0.3.7 → 1.0.0

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.
@@ -8,14 +8,14 @@ $ tsup --dts
8
8
  CLI Cleaning output folder
9
9
  CJS Build start
10
10
  ESM Build start
11
- CJS dist/index.js 13.98 KB
12
- CJS dist/index.js.map 25.98 KB
13
- CJS ⚡️ Build success in 63ms
14
- ESM dist/esm/index.js 10.33 KB
15
- ESM dist/esm/index.js.map 25.64 KB
16
- ESM ⚡️ Build success in 63ms
11
+ CJS dist/index.js 15.02 KB
12
+ CJS dist/index.js.map 28.30 KB
13
+ CJS ⚡️ Build success in 85ms
14
+ ESM dist/esm/index.js 11.33 KB
15
+ ESM dist/esm/index.js.map 27.96 KB
16
+ ESM ⚡️ Build success in 85ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 3708ms
19
- DTS dist/index.d.ts 8.35 KB
20
- DTS dist/index.d.mts 8.35 KB
21
- Done in 5.00s.
18
+ DTS ⚡️ Build success in 4107ms
19
+ DTS dist/index.d.ts 9.03 KB
20
+ DTS dist/index.d.mts 9.03 KB
21
+ Done in 5.72s.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @sproutsocial/seeds-react-panel
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 54918f6: Add a `headerless` prop to `Panel`. When set, the panel renders children flush —
8
+ no built-in header/close button or content padding — and lets the children own
9
+ overflow scrolling. Use it for content that brings its own chrome; provide
10
+ `aria-label` for an accessible name. Defaults to `false`.
11
+
12
+ **Breaking:** `Panel` now automatically wraps children in `PanelContent` (padding,
13
+ scroll, flex layout). Consumers that previously wrapped children in `Panel.Content`
14
+ explicitly must remove the wrapper to avoid double-nesting.
15
+
16
+ ### Patch Changes
17
+
18
+ - 54918f6: Fix side `Panel` overflowing its parent when given a vertical margin. The
19
+ container previously hardcoded `height: 100%`, which fills the parent's content
20
+ box but ignores the element's own margin — so a `mb`/`mt` pushed the panel's
21
+ edge (and any gap) off-screen in a `100vh` layout. It now uses
22
+ `align-self: stretch`, filling the flex-row parent's height while honoring its
23
+ own top/bottom margins, so spacing overrides (`mt`, `mb`, `mr`, `ml`, …) behave
24
+ correctly.
25
+ - 54918f6: Fix the mobile bottom-sheet footer falling below the fold. On mobile, `Panel` now
26
+ wraps children in `Panel.Content` (matching the desktop path) so the body scrolls
27
+ within the sheet, and the footer is lifted clear of the Drawer popup's 3rem
28
+ overscroll "bleed" so its actions stay fully visible above the fold.
29
+
3
30
  ## 0.3.7
4
31
 
5
32
  ### Patch Changes
package/dist/esm/index.js CHANGED
@@ -103,7 +103,7 @@ var PanelContainer = styled.aside`
103
103
  ${(props) => props.$direction === "bottom" ? css`
104
104
  width: 100%;
105
105
  ` : css`
106
- height: 100%;
106
+ align-self: stretch;
107
107
  `}
108
108
 
109
109
  ${COMMON}
@@ -121,27 +121,41 @@ var PanelInner = styled.div`
121
121
  overflow: hidden;
122
122
  `;
123
123
  var Content = styled(Box2)`
124
- overflow-y: auto;
124
+ overflow-y: ${({ $scroll = true }) => $scroll ? "auto" : "hidden"};
125
125
  `;
126
126
  var Footer = styled(Box2)`
127
127
  flex: 0 0 auto;
128
128
  overflow: hidden;
129
+ /*
130
+ * On mobile the Panel renders inside the Drawer's bottom sheet, whose popup
131
+ * deliberately bleeds 3rem (--bleed) below the viewport for elastic
132
+ * overscroll (see seeds-react-drawer/src/styles.ts). A footer pinned to the
133
+ * end of that popup would land inside the bleed and clip below the fold, so
134
+ * we lift it by the inherited --bleed; the gap left behind shows the popup's
135
+ * own background, so there is no visible seam. On desktop --bleed is unset,
136
+ * so the 0px fallback leaves the footer untouched.
137
+ */
138
+ margin-bottom: var(--bleed, 0px);
129
139
  `;
130
140
 
131
141
  // src/PanelContent.tsx
132
142
  import { jsx as jsx3 } from "react/jsx-runtime";
133
- var PanelContent = ({ children, ...rest }) => /* @__PURE__ */ jsx3(
134
- Content,
135
- {
136
- flex: "1 1 auto",
137
- minHeight: "0",
138
- p: 450,
139
- color: "text.body",
140
- "data-panel-content": "",
141
- ...rest,
142
- children
143
- }
144
- );
143
+ var PanelContent = ({ children, ...rest }) => {
144
+ const { headerless } = usePanelContext();
145
+ return /* @__PURE__ */ jsx3(
146
+ Content,
147
+ {
148
+ flex: "1 1 auto",
149
+ minHeight: "0",
150
+ p: headerless ? 0 : 450,
151
+ $scroll: !headerless,
152
+ color: "text.body",
153
+ "data-panel-content": "",
154
+ ...rest,
155
+ children
156
+ }
157
+ );
158
+ };
145
159
  PanelContent.displayName = "Panel.Content";
146
160
 
147
161
  // src/PanelFooter.tsx
@@ -221,6 +235,7 @@ var PanelComponent = ({
221
235
  children,
222
236
  closeButtonLabel,
223
237
  header,
238
+ headerless = false,
224
239
  footer,
225
240
  title,
226
241
  titleId,
@@ -245,17 +260,28 @@ var PanelComponent = ({
245
260
  const { isPanelOpen, closePanel } = panelContext;
246
261
  const isMobile = useIsMobile(mobileBreakpoint);
247
262
  const enrichedValue = React6.useMemo(
248
- () => ({ ...panelContext, closeButtonLabel }),
249
- [panelContext, closeButtonLabel]
263
+ () => ({ ...panelContext, closeButtonLabel, headerless }),
264
+ [panelContext, closeButtonLabel, headerless]
250
265
  );
251
266
  const prevChildrenRef = React6.useRef(null);
252
267
  if (isPanelOpen) {
253
268
  prevChildrenRef.current = children;
254
269
  }
255
270
  const renderedChildren = isPanelOpen ? children : prevChildrenRef.current;
256
- const effectiveAriaLabelledBy = ariaLabelledByProp ?? (header == null ? titleId : void 0);
271
+ const effectiveAriaLabelledBy = ariaLabelledByProp ?? (!headerless && header == null ? titleId : void 0);
257
272
  if (isMobile) {
258
- const shouldRenderActionsHeader = header == null && actionsInHeader === true && !!actions && actions.length > 0;
273
+ const shouldRenderActionsHeader = !headerless && header == null && actionsInHeader === true && !!actions && actions.length > 0;
274
+ let defaultMobileHeader = null;
275
+ if (!headerless) {
276
+ defaultMobileHeader = shouldRenderActionsHeader ? /* @__PURE__ */ jsx6(
277
+ PanelMobileActionsHeader,
278
+ {
279
+ title,
280
+ titleId,
281
+ actions
282
+ }
283
+ ) : /* @__PURE__ */ jsx6(Drawer2.Header, { title, id: titleId });
284
+ }
259
285
  return /* @__PURE__ */ jsx6(PanelContext.Provider, { value: enrichedValue, children: /* @__PURE__ */ jsxs3(
260
286
  Drawer2,
261
287
  {
@@ -275,15 +301,8 @@ var PanelComponent = ({
275
301
  "aria-labelledby": effectiveAriaLabelledBy,
276
302
  "aria-label": ariaLabel,
277
303
  children: [
278
- header ?? (shouldRenderActionsHeader ? /* @__PURE__ */ jsx6(
279
- PanelMobileActionsHeader,
280
- {
281
- title,
282
- titleId,
283
- actions
284
- }
285
- ) : /* @__PURE__ */ jsx6(Drawer2.Header, { title, id: titleId })),
286
- children,
304
+ header ?? defaultMobileHeader,
305
+ /* @__PURE__ */ jsx6(PanelContent, { children }),
287
306
  footer
288
307
  ]
289
308
  }
@@ -302,8 +321,8 @@ var PanelComponent = ({
302
321
  "aria-labelledby": effectiveAriaLabelledBy,
303
322
  "aria-label": ariaLabel,
304
323
  children: /* @__PURE__ */ jsxs3(PanelInner, { $direction: direction, $width: width, children: [
305
- header ?? /* @__PURE__ */ jsx6(PanelHeader, { title, id: titleId }),
306
- renderedChildren,
324
+ header ?? (headerless ? null : /* @__PURE__ */ jsx6(PanelHeader, { title, id: titleId })),
325
+ /* @__PURE__ */ jsx6(PanelContent, { children: renderedChildren }),
307
326
  footer
308
327
  ] })
309
328
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Panel.tsx","../../src/PanelContext.tsx","../../src/PanelHeader.tsx","../../src/PanelCloseButton.tsx","../../src/PanelContent.tsx","../../src/styles.ts","../../src/PanelFooter.tsx","../../src/PanelMobileActionsHeader.tsx","../../src/PanelProvider.tsx","../../src/PanelTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport { useIsMobile } from \"@sproutsocial/seeds-react-hooks\";\nimport { usePanelContext, PanelContext } from \"./PanelContext\";\nimport { PanelHeader } from \"./PanelHeader\";\nimport { PanelContent } from \"./PanelContent\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport { PanelFooter } from \"./PanelFooter\";\nimport { PanelMobileActionsHeader } from \"./PanelMobileActionsHeader\";\nimport { PanelContainer, PanelInner } from \"./styles\";\nimport type { TypePanelProps, TypePanelContext } from \"./PanelTypes\";\n\nconst PanelComponent = ({\n children,\n closeButtonLabel,\n header,\n footer,\n title,\n titleId,\n direction = \"right\",\n width = 384,\n gap = 4,\n mobileBreakpoint,\n zIndex,\n id,\n snapPoints,\n defaultSnapPoint,\n snapPoint,\n onSnapPointChange,\n snapToSequentialPoints,\n actions,\n actionsInHeader,\n \"aria-labelledby\": ariaLabelledByProp,\n \"aria-label\": ariaLabel,\n ...rest\n}: TypePanelProps) => {\n const panelContext = usePanelContext();\n const { isPanelOpen, closePanel } = panelContext;\n const isMobile = useIsMobile(mobileBreakpoint);\n\n // Expose closeButtonLabel through context so PanelCloseButton can read it\n // without prop drilling — same pattern as DrawerContext.\n const enrichedValue = React.useMemo<TypePanelContext>(\n () => ({ ...panelContext, closeButtonLabel }),\n [panelContext, closeButtonLabel]\n );\n\n // Freeze the last-rendered children during the collapse so consumers that\n // conditionally render content don't produce an empty panel shell while the\n // flex-basis animation runs.\n const prevChildrenRef = React.useRef<React.ReactNode>(null);\n if (isPanelOpen) {\n prevChildrenRef.current = children;\n }\n const renderedChildren = isPanelOpen ? children : prevChildrenRef.current;\n\n // When the consumer relies on the default header, its title element renders\n // with `id={titleId}`. Auto-wire `aria-labelledby` so the dialog/aside has an\n // accessible name without forcing every caller to repeat the id.\n const effectiveAriaLabelledBy =\n ariaLabelledByProp ?? (header == null ? titleId : undefined);\n\n if (isMobile) {\n // With `actionsInHeader`, Drawer suppresses the floating rail and expects\n // the consumer to render the actions inside a custom header. Auto-compose\n // one (title + action pills + close pill) when the consumer hasn't\n // supplied their own header; otherwise we'd drop `actions` on the floor.\n const shouldRenderActionsHeader =\n header == null &&\n actionsInHeader === true &&\n !!actions &&\n actions.length > 0;\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <Drawer\n {...rest}\n open={isPanelOpen}\n onClose={closePanel}\n direction=\"bottom\"\n closeButtonLabel={closeButtonLabel}\n zIndex={zIndex}\n snapPoints={snapPoints}\n defaultSnapPoint={defaultSnapPoint}\n snapPoint={snapPoint}\n onSnapPointChange={onSnapPointChange}\n snapToSequentialPoints={snapToSequentialPoints}\n actions={actions}\n actionsInHeader={actionsInHeader}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n {header ??\n (shouldRenderActionsHeader ? (\n <PanelMobileActionsHeader\n title={title}\n titleId={titleId}\n actions={actions!}\n />\n ) : (\n <Drawer.Header title={title} id={titleId} />\n ))}\n {children}\n {footer}\n </Drawer>\n </PanelContext.Provider>\n );\n }\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <PanelContainer\n {...rest}\n $isOpen={isPanelOpen}\n $direction={direction}\n $width={width}\n $gap={gap}\n data-qa-panel={id}\n data-qa-panel-isopen={isPanelOpen}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n <PanelInner $direction={direction} $width={width}>\n {header ?? <PanelHeader title={title} id={titleId} />}\n {renderedChildren}\n {footer}\n </PanelInner>\n </PanelContainer>\n </PanelContext.Provider>\n );\n};\n\nPanelComponent.Header = PanelHeader;\nPanelComponent.Content = PanelContent;\nPanelComponent.CloseButton = PanelCloseButton;\nPanelComponent.Footer = PanelFooter;\n\nexport const Panel = PanelComponent;\nexport default PanelComponent;\n","import * as React from \"react\";\nimport type { TypePanelContext } from \"./PanelTypes\";\n\nexport const PanelContext = React.createContext<TypePanelContext | null>(null);\n\nexport const usePanelContext = (): TypePanelContext => {\n const ctx = React.useContext(PanelContext);\n if (!ctx) {\n throw new Error(\n \"usePanelContext must be used within a <PanelProvider>. Wrap the consuming tree in <PanelProvider> to provide isPanelOpen / togglePanel.\"\n );\n }\n return ctx;\n};\n","import Box from \"@sproutsocial/seeds-react-box\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { usePanelContext } from \"./PanelContext\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport type { TypePanelHeaderProps } from \"./PanelTypes\";\n\nexport const PanelHeader = ({\n title = \"\",\n id = undefined,\n children,\n render,\n ...rest\n}: TypePanelHeaderProps) => {\n const panelContext = usePanelContext();\n\n if (render) {\n return render(panelContext);\n }\n\n return (\n <Box\n display=\"flex\"\n flex=\"0 0 auto\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n p={400}\n borderBottom=\"1px solid\"\n borderColor=\"container.border.base\"\n {...rest}\n >\n {children || (\n <>\n <Text.Headline id={id}>{title}</Text.Headline>\n <PanelCloseButton />\n </>\n )}\n </Box>\n );\n};\n\nPanelHeader.displayName = \"Panel.Header\";\n","import * as React from \"react\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport { usePanelContext } from \"./PanelContext\";\nimport type { TypePanelCloseButtonProps } from \"./PanelTypes\";\n\nexport const PanelCloseButton = (props: TypePanelCloseButtonProps) => {\n const panelContext = usePanelContext();\n\n if (props.render) {\n return props.render(panelContext) ?? null;\n }\n\n return (\n <Button\n appearance=\"pill\"\n aria-label={panelContext.closeButtonLabel}\n onClick={panelContext.closePanel}\n {...props}\n >\n {props.children || <Icon aria-hidden name=\"x-outline\" />}\n </Button>\n );\n};\n\nPanelCloseButton.displayName = \"Panel.CloseButton\";\n","import * as React from \"react\";\nimport { Content } from \"./styles\";\nimport type { TypePanelContentProps } from \"./PanelTypes\";\n\nexport const PanelContent = ({ children, ...rest }: TypePanelContentProps) => (\n <Content\n flex=\"1 1 auto\"\n minHeight=\"0\"\n p={450}\n color=\"text.body\"\n data-panel-content=\"\"\n {...rest}\n >\n {children}\n </Content>\n);\n\nPanelContent.displayName = \"Panel.Content\";\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSystemCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport { MOTION_DURATION_MEDIUM } from \"@sproutsocial/seeds-motion/unitless\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { PanelDirection } from \"./PanelTypes\";\n\ninterface PanelContainerProps extends TypeSystemCommonProps {\n $isOpen: boolean;\n $direction: PanelDirection;\n $width: number;\n $gap: number;\n}\n\nconst gapSide = (direction: PanelDirection): \"left\" | \"right\" | \"top\" => {\n if (direction === \"right\") return \"left\";\n if (direction === \"left\") return \"right\";\n return \"top\";\n};\n\nexport const PanelContainer = styled.aside<PanelContainerProps>`\n background: ${(props) => props.theme.colors.container.background.base};\n flex-grow: 0;\n flex-shrink: 0;\n overflow: hidden;\n transition: flex-basis ${MOTION_DURATION_MEDIUM}s ease-in-out,\n margin ${MOTION_DURATION_MEDIUM}s ease-in-out;\n flex-basis: ${(props) => (props.$isOpen ? `${props.$width}px` : \"0px\")};\n margin-${(props) => gapSide(props.$direction)}: ${(props) =>\n props.$isOpen && props.$gap ? `${props.$gap}px` : \"0px\"};\n border-radius: ${({ theme }) => theme.radii[800]};\n\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n width: 100%;\n `\n : css`\n height: 100%;\n `}\n\n ${COMMON}\n`;\n\nexport const PanelInner = styled.div<{\n $direction: PanelDirection;\n $width: number;\n}>`\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n min-height: ${props.$width}px;\n width: 100%;\n `\n : css`\n min-width: ${props.$width}px;\n height: 100%;\n `}\n display: flex;\n flex-direction: column;\n overflow: hidden;\n`;\n\nexport const Content = styled(Box)`\n overflow-y: auto;\n`;\n\nexport const Footer = styled(Box)`\n flex: 0 0 auto;\n overflow: hidden;\n`;\n","import * as React from \"react\";\nimport { Footer } from \"./styles\";\nimport type { TypePanelFooterProps } from \"./PanelTypes\";\n\nexport const PanelFooter = ({ children, ...rest }: TypePanelFooterProps) => (\n <Footer p={450} data-panel-footer=\"\" {...rest}>\n {children}\n </Footer>\n);\n\nPanelFooter.displayName = \"Panel.Footer\";\n","import * as React from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\n// eslint-disable-next-line import/no-deprecated\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeDrawerActionProps } from \"@sproutsocial/seeds-react-drawer\";\n\ninterface TypePanelMobileActionsHeaderProps {\n title?: string;\n titleId?: string;\n actions: TypeDrawerActionProps[];\n}\n\n/**\n * Mobile bottom-sheet header used by Panel when `actionsInHeader` is set and\n * no custom `header` is provided. Renders the title on the left and the\n * forwarded actions plus a close button as pills on the right — mirrors the\n * pattern in `seeds-react-peek-in/PeekIn.tsx`. The Drawer's floating rail is\n * suppressed in this combination (`actionsInHeader` opts out), so without this\n * header the actions would render nowhere.\n */\nexport const PanelMobileActionsHeader = ({\n title,\n titleId,\n actions,\n}: TypePanelMobileActionsHeaderProps) => (\n <Drawer.Header\n render={(ctx) => (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n pt={400}\n px={450}\n flex=\"0 0 auto\"\n >\n <Text\n as=\"h2\"\n fontSize={400}\n fontWeight=\"semibold\"\n color=\"text.headline\"\n id={titleId}\n >\n {title}\n </Text>\n <Box display=\"flex\" alignItems=\"center\" gap={200}>\n {actions.map((action, i) => (\n <Button\n key={i}\n appearance=\"pill\"\n aria-label={action[\"aria-label\"]}\n onClick={action.onClick}\n disabled={action.disabled}\n >\n {action.iconName && <Icon aria-hidden name={action.iconName} />}\n </Button>\n ))}\n <Button\n appearance=\"pill\"\n aria-label={ctx.closeButtonLabel}\n onClick={ctx.onClose}\n >\n <Icon aria-hidden name=\"x-outline\" />\n </Button>\n </Box>\n </Box>\n )}\n />\n);\n\nPanelMobileActionsHeader.displayName = \"PanelMobileActionsHeader\";\n","import * as React from \"react\";\nimport { PanelContext } from \"./PanelContext\";\nimport type { TypePanelContext, TypePanelProviderProps } from \"./PanelTypes\";\n\nexport const PanelProvider = ({\n children,\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n}: TypePanelProviderProps) => {\n const [internalOpen, setInternalOpen] = React.useState(defaultOpen);\n const isControlled = controlledOpen !== undefined;\n const isPanelOpen = isControlled ? controlledOpen : internalOpen;\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange]\n );\n\n const openPanel = React.useCallback(() => setOpen(true), [setOpen]);\n const closePanel = React.useCallback(() => setOpen(false), [setOpen]);\n const togglePanel = React.useCallback(\n () => setOpen(!isPanelOpen),\n [setOpen, isPanelOpen]\n );\n\n const value = React.useMemo<TypePanelContext>(\n () => ({ isPanelOpen, openPanel, closePanel, togglePanel }),\n [isPanelOpen, openPanel, closePanel, togglePanel]\n );\n\n return (\n <PanelContext.Provider value={value}>{children}</PanelContext.Provider>\n );\n};\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\nimport type {\n TypeDrawerSnapPoint,\n TypeDrawerActionProps,\n} from \"@sproutsocial/seeds-react-drawer\";\n\nexport type { TypeDrawerActionProps as TypePanelActionProps };\n\nexport type PanelDirection = \"left\" | \"right\" | \"bottom\";\n\nexport interface TypePanelContext {\n isPanelOpen: boolean;\n togglePanel: () => void;\n openPanel: () => void;\n closePanel: () => void;\n closeButtonLabel?: string;\n}\n\nexport interface TypePanelProviderProps {\n children: React.ReactNode;\n /** Initial open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Controlled open state. When provided, the provider becomes controlled. */\n open?: boolean;\n /** Called whenever the open state changes. Required for controlled usage. */\n onOpenChange?: (open: boolean) => void;\n}\n\nexport interface TypePanelProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\"> {\n children: React.ReactNode;\n\n /** Label for the close button. Usually \"Close\". */\n closeButtonLabel: string;\n\n /**\n * Custom header content. When provided, replaces the auto-rendered default\n * header entirely — `title` and `titleId` are ignored.\n */\n header?: React.ReactNode;\n\n /** Custom footer content. Not rendered when omitted. */\n footer?: React.ReactNode;\n\n /** Title shown in the auto-rendered default header. Ignored when `header` is provided. */\n title?: string;\n\n /**\n * Sets the `id` on the title element of the auto-rendered header. When the\n * default header is used, Panel automatically wires `aria-labelledby` to this\n * id so the dialog/aside has an accessible name. Pass an explicit\n * `aria-labelledby` to override (e.g. when pointing at a different element).\n * Ignored when `header` is provided — supply your own `aria-labelledby` in\n * that case.\n */\n titleId?: string;\n\n /** Side the panel anchors to on desktop. Defaults to \"right\". */\n direction?: PanelDirection;\n\n /**\n * Width (px) when direction is \"left\" or \"right\", or height (px) when\n * direction is \"bottom\". Defaults to 384 to match the existing web-app-core\n * Panel.\n */\n width?: number;\n\n /**\n * Visual gap (px) between the panel and the adjacent content. Applied as\n * margin on the side facing the content (left when direction=\"right\",\n * right when direction=\"left\", top when direction=\"bottom\"). Animates with\n * the panel's open/close transition and collapses to 0 when closed so the\n * gap does not remain visible alongside a zero-width panel. Defaults to 0.\n */\n gap?: number;\n\n /**\n * Forwarded to `useIsMobile`. Accepts a px number or any CSS media-query\n * length. Below this width, the panel renders as an overlay bottom sheet\n * (via seeds-react-drawer). Defaults to the theme's `breakpoints.sm`.\n */\n mobileBreakpoint?: number | string;\n\n /** Applies only to the mobile bottom-sheet rendering. */\n zIndex?: number;\n\n /** Optional id used for data-qa-panel attributes. */\n id?: string;\n\n /**\n * Snap points the panel can rest at when rendered as a mobile bottom sheet.\n * Numbers 0–1 are viewport-height fractions; numbers > 1 are pixels; strings\n * accept `px`/`rem` (e.g. `\"480px\"`, `\"30rem\"`). Order matters — the last\n * entry is the \"expanded\" state. Ignored on the desktop side-panel rendering.\n */\n snapPoints?: TypeDrawerSnapPoint[];\n\n /** Initial snap point for uncontrolled use. Mobile only. */\n defaultSnapPoint?: TypeDrawerSnapPoint | null;\n\n /** Controlled active snap point. Pair with `onSnapPointChange`. Mobile only. */\n snapPoint?: TypeDrawerSnapPoint | null;\n\n /** Fires when the active snap point changes. Mobile only. */\n onSnapPointChange?: (snapPoint: TypeDrawerSnapPoint | null) => void;\n\n /**\n * When true, fast swipes can't skip past adjacent snap points. Mobile only.\n */\n snapToSequentialPoints?: boolean;\n\n /**\n * Action buttons shown in a floating rail above the panel on mobile (the\n * bottom-sheet rendering). Ignored on desktop side-panel rendering — pass\n * actions through `header`/`footer` slots there. The rail owns the close\n * button so the default header omits its built-in close affordance.\n */\n actions?: TypeDrawerActionProps[];\n\n /**\n * Opt out of the floating mobile rail and render the `actions` inline in the\n * header as pill buttons instead. Useful for nested bottom sheets and\n * snap-point layouts where the floating rail would collide with surrounding\n * UI. Defaults to `false`.\n *\n * When `header` is omitted, Panel auto-composes a mobile header that renders\n * the title, the `actions` as pills, and a close-button pill. When `header`\n * is provided, the consumer is responsible for rendering the actions inside\n * their own header — `actions` is forwarded for context only.\n */\n actionsInHeader?: boolean;\n}\n\nexport interface TypePanelHeaderProps extends TypeBoxProps {\n title?: string;\n /**\n * When children are provided, `<Panel.CloseButton />` is NOT rendered\n * automatically. Include it yourself to preserve keyboard accessibility.\n */\n children?: React.ReactNode;\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n}\n\nexport interface TypePanelContentProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelFooterProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelCloseButtonProps\n extends Omit<TypeButtonProps, \"children\"> {\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n children?: React.ReactNode;\n}\n","import Panel from \"./Panel\";\n\nexport default Panel;\nexport { Panel };\nexport { PanelContext, usePanelContext } from \"./PanelContext\";\nexport { PanelProvider } from \"./PanelProvider\";\nexport { PanelHeader } from \"./PanelHeader\";\nexport { PanelContent } from \"./PanelContent\";\nexport { PanelCloseButton } from \"./PanelCloseButton\";\nexport { PanelFooter } from \"./PanelFooter\";\nexport * from \"./PanelTypes\";\n"],"mappings":"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","names":["React","Drawer","jsx","Box","jsx","jsx","Box","Button","Icon","Text","jsx","jsxs","jsx","jsxs","Drawer","React","jsx"]}
1
+ {"version":3,"sources":["../../src/Panel.tsx","../../src/PanelContext.tsx","../../src/PanelHeader.tsx","../../src/PanelCloseButton.tsx","../../src/PanelContent.tsx","../../src/styles.ts","../../src/PanelFooter.tsx","../../src/PanelMobileActionsHeader.tsx","../../src/PanelProvider.tsx","../../src/PanelTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport { useIsMobile } from \"@sproutsocial/seeds-react-hooks\";\nimport { usePanelContext, PanelContext } from \"./PanelContext\";\nimport { PanelHeader } from \"./PanelHeader\";\nimport { PanelContent } from \"./PanelContent\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport { PanelFooter } from \"./PanelFooter\";\nimport { PanelMobileActionsHeader } from \"./PanelMobileActionsHeader\";\nimport { PanelContainer, PanelInner } from \"./styles\";\nimport type { TypePanelProps, TypePanelContext } from \"./PanelTypes\";\n\nconst PanelComponent = ({\n children,\n closeButtonLabel,\n header,\n headerless = false,\n footer,\n title,\n titleId,\n direction = \"right\",\n width = 384,\n gap = 4,\n mobileBreakpoint,\n zIndex,\n id,\n snapPoints,\n defaultSnapPoint,\n snapPoint,\n onSnapPointChange,\n snapToSequentialPoints,\n actions,\n actionsInHeader,\n \"aria-labelledby\": ariaLabelledByProp,\n \"aria-label\": ariaLabel,\n ...rest\n}: TypePanelProps) => {\n const panelContext = usePanelContext();\n const { isPanelOpen, closePanel } = panelContext;\n const isMobile = useIsMobile(mobileBreakpoint);\n\n // Expose closeButtonLabel through context so PanelCloseButton can read it\n // without prop drilling — same pattern as DrawerContext.\n const enrichedValue = React.useMemo<TypePanelContext>(\n () => ({ ...panelContext, closeButtonLabel, headerless }),\n [panelContext, closeButtonLabel, headerless]\n );\n\n // Freeze the last-rendered children during the collapse so consumers that\n // conditionally render content don't produce an empty panel shell while the\n // flex-basis animation runs.\n const prevChildrenRef = React.useRef<React.ReactNode>(null);\n if (isPanelOpen) {\n prevChildrenRef.current = children;\n }\n const renderedChildren = isPanelOpen ? children : prevChildrenRef.current;\n\n // When the consumer relies on the default header, its title element renders\n // with `id={titleId}`. Auto-wire `aria-labelledby` so the dialog/aside has an\n // accessible name without forcing every caller to repeat the id.\n const effectiveAriaLabelledBy =\n ariaLabelledByProp ?? (!headerless && header == null ? titleId : undefined);\n\n if (isMobile) {\n // With `actionsInHeader`, Drawer suppresses the floating rail and expects\n // the consumer to render the actions inside a custom header. Auto-compose\n // one (title + action pills + close pill) when the consumer hasn't\n // supplied their own header; otherwise we'd drop `actions` on the floor.\n const shouldRenderActionsHeader =\n !headerless &&\n header == null &&\n actionsInHeader === true &&\n !!actions &&\n actions.length > 0;\n\n // Headerless suppresses the built-in header entirely; the children own all\n // chrome in that mode.\n let defaultMobileHeader: React.ReactNode = null;\n if (!headerless) {\n defaultMobileHeader = shouldRenderActionsHeader ? (\n <PanelMobileActionsHeader\n title={title}\n titleId={titleId}\n actions={actions!}\n />\n ) : (\n <Drawer.Header title={title} id={titleId} />\n );\n }\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <Drawer\n {...rest}\n open={isPanelOpen}\n onClose={closePanel}\n direction=\"bottom\"\n closeButtonLabel={closeButtonLabel}\n zIndex={zIndex}\n snapPoints={snapPoints}\n defaultSnapPoint={defaultSnapPoint}\n snapPoint={snapPoint}\n onSnapPointChange={onSnapPointChange}\n snapToSequentialPoints={snapToSequentialPoints}\n actions={actions}\n actionsInHeader={actionsInHeader}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n {header ?? defaultMobileHeader}\n <PanelContent>{children}</PanelContent>\n {footer}\n </Drawer>\n </PanelContext.Provider>\n );\n }\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <PanelContainer\n {...rest}\n $isOpen={isPanelOpen}\n $direction={direction}\n $width={width}\n $gap={gap}\n data-qa-panel={id}\n data-qa-panel-isopen={isPanelOpen}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n <PanelInner $direction={direction} $width={width}>\n {header ??\n (headerless ? null : <PanelHeader title={title} id={titleId} />)}\n <PanelContent>{renderedChildren}</PanelContent>\n {footer}\n </PanelInner>\n </PanelContainer>\n </PanelContext.Provider>\n );\n};\n\nPanelComponent.Header = PanelHeader;\nPanelComponent.Content = PanelContent;\nPanelComponent.CloseButton = PanelCloseButton;\nPanelComponent.Footer = PanelFooter;\n\nexport const Panel = PanelComponent;\nexport default PanelComponent;\n","import * as React from \"react\";\nimport type { TypePanelContext } from \"./PanelTypes\";\n\nexport const PanelContext = React.createContext<TypePanelContext | null>(null);\n\nexport const usePanelContext = (): TypePanelContext => {\n const ctx = React.useContext(PanelContext);\n if (!ctx) {\n throw new Error(\n \"usePanelContext must be used within a <PanelProvider>. Wrap the consuming tree in <PanelProvider> to provide isPanelOpen / togglePanel.\"\n );\n }\n return ctx;\n};\n","import Box from \"@sproutsocial/seeds-react-box\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { usePanelContext } from \"./PanelContext\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport type { TypePanelHeaderProps } from \"./PanelTypes\";\n\nexport const PanelHeader = ({\n title = \"\",\n id = undefined,\n children,\n render,\n ...rest\n}: TypePanelHeaderProps) => {\n const panelContext = usePanelContext();\n\n if (render) {\n return render(panelContext);\n }\n\n return (\n <Box\n display=\"flex\"\n flex=\"0 0 auto\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n p={400}\n borderBottom=\"1px solid\"\n borderColor=\"container.border.base\"\n {...rest}\n >\n {children || (\n <>\n <Text.Headline id={id}>{title}</Text.Headline>\n <PanelCloseButton />\n </>\n )}\n </Box>\n );\n};\n\nPanelHeader.displayName = \"Panel.Header\";\n","import * as React from \"react\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport { usePanelContext } from \"./PanelContext\";\nimport type { TypePanelCloseButtonProps } from \"./PanelTypes\";\n\nexport const PanelCloseButton = (props: TypePanelCloseButtonProps) => {\n const panelContext = usePanelContext();\n\n if (props.render) {\n return props.render(panelContext) ?? null;\n }\n\n return (\n <Button\n appearance=\"pill\"\n aria-label={panelContext.closeButtonLabel}\n onClick={panelContext.closePanel}\n {...props}\n >\n {props.children || <Icon aria-hidden name=\"x-outline\" />}\n </Button>\n );\n};\n\nPanelCloseButton.displayName = \"Panel.CloseButton\";\n","import * as React from \"react\";\nimport { Content } from \"./styles\";\nimport { usePanelContext } from \"./PanelContext\";\nimport type { TypePanelContentProps } from \"./PanelTypes\";\n\nexport const PanelContent = ({ children, ...rest }: TypePanelContentProps) => {\n // In headerless mode the content renders flush and defers overflow scrolling\n // to its children, so the panel can host content that owns its own chrome.\n const { headerless } = usePanelContext();\n\n return (\n <Content\n flex=\"1 1 auto\"\n minHeight=\"0\"\n p={headerless ? 0 : 450}\n $scroll={!headerless}\n color=\"text.body\"\n data-panel-content=\"\"\n {...rest}\n >\n {children}\n </Content>\n );\n};\n\nPanelContent.displayName = \"Panel.Content\";\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSystemCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport { MOTION_DURATION_MEDIUM } from \"@sproutsocial/seeds-motion/unitless\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { PanelDirection } from \"./PanelTypes\";\n\ninterface PanelContainerProps extends TypeSystemCommonProps {\n $isOpen: boolean;\n $direction: PanelDirection;\n $width: number;\n $gap: number;\n}\n\nconst gapSide = (direction: PanelDirection): \"left\" | \"right\" | \"top\" => {\n if (direction === \"right\") return \"left\";\n if (direction === \"left\") return \"right\";\n return \"top\";\n};\n\nexport const PanelContainer = styled.aside<PanelContainerProps>`\n background: ${(props) => props.theme.colors.container.background.base};\n flex-grow: 0;\n flex-shrink: 0;\n overflow: hidden;\n transition: flex-basis ${MOTION_DURATION_MEDIUM}s ease-in-out,\n margin ${MOTION_DURATION_MEDIUM}s ease-in-out;\n flex-basis: ${(props) => (props.$isOpen ? `${props.$width}px` : \"0px\")};\n margin-${(props) => gapSide(props.$direction)}: ${(props) =>\n props.$isOpen && props.$gap ? `${props.$gap}px` : \"0px\"};\n border-radius: ${({ theme }) => theme.radii[800]};\n\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n width: 100%;\n `\n : css`\n align-self: stretch;\n `}\n\n ${COMMON}\n`;\n\nexport const PanelInner = styled.div<{\n $direction: PanelDirection;\n $width: number;\n}>`\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n min-height: ${props.$width}px;\n width: 100%;\n `\n : css`\n min-width: ${props.$width}px;\n height: 100%;\n `}\n display: flex;\n flex-direction: column;\n overflow: hidden;\n`;\n\nexport const Content = styled(Box)<{ $scroll?: boolean }>`\n overflow-y: ${({ $scroll = true }) => ($scroll ? \"auto\" : \"hidden\")};\n`;\n\nexport const Footer = styled(Box)`\n flex: 0 0 auto;\n overflow: hidden;\n /*\n * On mobile the Panel renders inside the Drawer's bottom sheet, whose popup\n * deliberately bleeds 3rem (--bleed) below the viewport for elastic\n * overscroll (see seeds-react-drawer/src/styles.ts). A footer pinned to the\n * end of that popup would land inside the bleed and clip below the fold, so\n * we lift it by the inherited --bleed; the gap left behind shows the popup's\n * own background, so there is no visible seam. On desktop --bleed is unset,\n * so the 0px fallback leaves the footer untouched.\n */\n margin-bottom: var(--bleed, 0px);\n`;\n","import * as React from \"react\";\nimport { Footer } from \"./styles\";\nimport type { TypePanelFooterProps } from \"./PanelTypes\";\n\nexport const PanelFooter = ({ children, ...rest }: TypePanelFooterProps) => (\n <Footer p={450} data-panel-footer=\"\" {...rest}>\n {children}\n </Footer>\n);\n\nPanelFooter.displayName = \"Panel.Footer\";\n","import * as React from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\n// eslint-disable-next-line import/no-deprecated\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeDrawerActionProps } from \"@sproutsocial/seeds-react-drawer\";\n\ninterface TypePanelMobileActionsHeaderProps {\n title?: string;\n titleId?: string;\n actions: TypeDrawerActionProps[];\n}\n\n/**\n * Mobile bottom-sheet header used by Panel when `actionsInHeader` is set and\n * no custom `header` is provided. Renders the title on the left and the\n * forwarded actions plus a close button as pills on the right — mirrors the\n * pattern in `seeds-react-peek-in/PeekIn.tsx`. The Drawer's floating rail is\n * suppressed in this combination (`actionsInHeader` opts out), so without this\n * header the actions would render nowhere.\n */\nexport const PanelMobileActionsHeader = ({\n title,\n titleId,\n actions,\n}: TypePanelMobileActionsHeaderProps) => (\n <Drawer.Header\n render={(ctx) => (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n pt={400}\n px={450}\n flex=\"0 0 auto\"\n >\n <Text\n as=\"h2\"\n fontSize={400}\n fontWeight=\"semibold\"\n color=\"text.headline\"\n id={titleId}\n >\n {title}\n </Text>\n <Box display=\"flex\" alignItems=\"center\" gap={200}>\n {actions.map((action, i) => (\n <Button\n key={i}\n appearance=\"pill\"\n aria-label={action[\"aria-label\"]}\n onClick={action.onClick}\n disabled={action.disabled}\n >\n {action.iconName && <Icon aria-hidden name={action.iconName} />}\n </Button>\n ))}\n <Button\n appearance=\"pill\"\n aria-label={ctx.closeButtonLabel}\n onClick={ctx.onClose}\n >\n <Icon aria-hidden name=\"x-outline\" />\n </Button>\n </Box>\n </Box>\n )}\n />\n);\n\nPanelMobileActionsHeader.displayName = \"PanelMobileActionsHeader\";\n","import * as React from \"react\";\nimport { PanelContext } from \"./PanelContext\";\nimport type { TypePanelContext, TypePanelProviderProps } from \"./PanelTypes\";\n\nexport const PanelProvider = ({\n children,\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n}: TypePanelProviderProps) => {\n const [internalOpen, setInternalOpen] = React.useState(defaultOpen);\n const isControlled = controlledOpen !== undefined;\n const isPanelOpen = isControlled ? controlledOpen : internalOpen;\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange]\n );\n\n const openPanel = React.useCallback(() => setOpen(true), [setOpen]);\n const closePanel = React.useCallback(() => setOpen(false), [setOpen]);\n const togglePanel = React.useCallback(\n () => setOpen(!isPanelOpen),\n [setOpen, isPanelOpen]\n );\n\n const value = React.useMemo<TypePanelContext>(\n () => ({ isPanelOpen, openPanel, closePanel, togglePanel }),\n [isPanelOpen, openPanel, closePanel, togglePanel]\n );\n\n return (\n <PanelContext.Provider value={value}>{children}</PanelContext.Provider>\n );\n};\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\nimport type {\n TypeDrawerSnapPoint,\n TypeDrawerActionProps,\n} from \"@sproutsocial/seeds-react-drawer\";\n\nexport type { TypeDrawerActionProps as TypePanelActionProps };\n\nexport type PanelDirection = \"left\" | \"right\" | \"bottom\";\n\nexport interface TypePanelContext {\n isPanelOpen: boolean;\n togglePanel: () => void;\n openPanel: () => void;\n closePanel: () => void;\n closeButtonLabel?: string;\n /**\n * Set by `Panel` when rendered headerless. `Panel.Content` reads this to\n * render flush (no padding) and defer overflow scrolling to its children.\n */\n headerless?: boolean;\n}\n\nexport interface TypePanelProviderProps {\n children: React.ReactNode;\n /** Initial open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Controlled open state. When provided, the provider becomes controlled. */\n open?: boolean;\n /** Called whenever the open state changes. Required for controlled usage. */\n onOpenChange?: (open: boolean) => void;\n}\n\nexport interface TypePanelProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\"> {\n children: React.ReactNode;\n\n /** Label for the close button. Usually \"Close\". */\n closeButtonLabel: string;\n\n /**\n * Custom header content. When provided, replaces the auto-rendered default\n * header entirely — `title` and `titleId` are ignored.\n */\n header?: React.ReactNode;\n\n /** Custom footer content. Not rendered when omitted. */\n footer?: React.ReactNode;\n\n /**\n * Renders children flush, without the built-in header/close button or content\n * padding, and lets the children own overflow scrolling. Use when the content\n * provides its own chrome (e.g. an embedded agent UI). Provide `aria-label`\n * (or `aria-labelledby`) for an accessible name, since no header title is\n * rendered. `title`, `titleId`, and `closeButtonLabel` are ignored in this\n * mode. Defaults to false.\n */\n headerless?: boolean;\n\n /** Title shown in the auto-rendered default header. Ignored when `header` is provided. */\n title?: string;\n\n /**\n * Sets the `id` on the title element of the auto-rendered header. When the\n * default header is used, Panel automatically wires `aria-labelledby` to this\n * id so the dialog/aside has an accessible name. Pass an explicit\n * `aria-labelledby` to override (e.g. when pointing at a different element).\n * Ignored when `header` is provided — supply your own `aria-labelledby` in\n * that case.\n */\n titleId?: string;\n\n /** Side the panel anchors to on desktop. Defaults to \"right\". */\n direction?: PanelDirection;\n\n /**\n * Width (px) when direction is \"left\" or \"right\", or height (px) when\n * direction is \"bottom\". Defaults to 384 to match the existing web-app-core\n * Panel.\n */\n width?: number;\n\n /**\n * Visual gap (px) between the panel and the adjacent content. Applied as\n * margin on the side facing the content (left when direction=\"right\",\n * right when direction=\"left\", top when direction=\"bottom\"). Animates with\n * the panel's open/close transition and collapses to 0 when closed so the\n * gap does not remain visible alongside a zero-width panel. Defaults to 0.\n */\n gap?: number;\n\n /**\n * Forwarded to `useIsMobile`. Accepts a px number or any CSS media-query\n * length. Below this width, the panel renders as an overlay bottom sheet\n * (via seeds-react-drawer). Defaults to the theme's `breakpoints.sm`.\n */\n mobileBreakpoint?: number | string;\n\n /** Applies only to the mobile bottom-sheet rendering. */\n zIndex?: number;\n\n /** Optional id used for data-qa-panel attributes. */\n id?: string;\n\n /**\n * Snap points the panel can rest at when rendered as a mobile bottom sheet.\n * Numbers 0–1 are viewport-height fractions; numbers > 1 are pixels; strings\n * accept `px`/`rem` (e.g. `\"480px\"`, `\"30rem\"`). Order matters — the last\n * entry is the \"expanded\" state. Ignored on the desktop side-panel rendering.\n */\n snapPoints?: TypeDrawerSnapPoint[];\n\n /** Initial snap point for uncontrolled use. Mobile only. */\n defaultSnapPoint?: TypeDrawerSnapPoint | null;\n\n /** Controlled active snap point. Pair with `onSnapPointChange`. Mobile only. */\n snapPoint?: TypeDrawerSnapPoint | null;\n\n /** Fires when the active snap point changes. Mobile only. */\n onSnapPointChange?: (snapPoint: TypeDrawerSnapPoint | null) => void;\n\n /**\n * When true, fast swipes can't skip past adjacent snap points. Mobile only.\n */\n snapToSequentialPoints?: boolean;\n\n /**\n * Action buttons shown in a floating rail above the panel on mobile (the\n * bottom-sheet rendering). Ignored on desktop side-panel rendering — pass\n * actions through `header`/`footer` slots there. The rail owns the close\n * button so the default header omits its built-in close affordance.\n */\n actions?: TypeDrawerActionProps[];\n\n /**\n * Opt out of the floating mobile rail and render the `actions` inline in the\n * header as pill buttons instead. Useful for nested bottom sheets and\n * snap-point layouts where the floating rail would collide with surrounding\n * UI. Defaults to `false`.\n *\n * When `header` is omitted, Panel auto-composes a mobile header that renders\n * the title, the `actions` as pills, and a close-button pill. When `header`\n * is provided, the consumer is responsible for rendering the actions inside\n * their own header — `actions` is forwarded for context only.\n */\n actionsInHeader?: boolean;\n}\n\nexport interface TypePanelHeaderProps extends TypeBoxProps {\n title?: string;\n /**\n * When children are provided, `<Panel.CloseButton />` is NOT rendered\n * automatically. Include it yourself to preserve keyboard accessibility.\n */\n children?: React.ReactNode;\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n}\n\nexport interface TypePanelContentProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelFooterProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelCloseButtonProps\n extends Omit<TypeButtonProps, \"children\"> {\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n children?: React.ReactNode;\n}\n","import Panel from \"./Panel\";\n\nexport default Panel;\nexport { Panel };\nexport { PanelContext, usePanelContext } from \"./PanelContext\";\nexport { PanelProvider } from \"./PanelProvider\";\nexport { PanelHeader } from \"./PanelHeader\";\nexport { PanelContent } from \"./PanelContent\";\nexport { PanelCloseButton } from \"./PanelCloseButton\";\nexport { PanelFooter } from \"./PanelFooter\";\nexport * from \"./PanelTypes\";\n"],"mappings":"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","names":["React","Drawer","jsx","Box","jsx","jsx","Box","Button","Icon","Text","jsx","jsxs","jsx","jsxs","Drawer","React","jsx"]}
package/dist/index.d.mts CHANGED
@@ -13,6 +13,11 @@ interface TypePanelContext {
13
13
  openPanel: () => void;
14
14
  closePanel: () => void;
15
15
  closeButtonLabel?: string;
16
+ /**
17
+ * Set by `Panel` when rendered headerless. `Panel.Content` reads this to
18
+ * render flush (no padding) and defer overflow scrolling to its children.
19
+ */
20
+ headerless?: boolean;
16
21
  }
17
22
  interface TypePanelProviderProps {
18
23
  children: React.ReactNode;
@@ -34,6 +39,15 @@ interface TypePanelProps extends TypeStyledComponentsCommonProps, TypeSystemComm
34
39
  header?: React.ReactNode;
35
40
  /** Custom footer content. Not rendered when omitted. */
36
41
  footer?: React.ReactNode;
42
+ /**
43
+ * Renders children flush, without the built-in header/close button or content
44
+ * padding, and lets the children own overflow scrolling. Use when the content
45
+ * provides its own chrome (e.g. an embedded agent UI). Provide `aria-label`
46
+ * (or `aria-labelledby`) for an accessible name, since no header title is
47
+ * rendered. `title`, `titleId`, and `closeButtonLabel` are ignored in this
48
+ * mode. Defaults to false.
49
+ */
50
+ headerless?: boolean;
37
51
  /** Title shown in the auto-rendered default header. Ignored when `header` is provided. */
38
52
  title?: string;
39
53
  /**
@@ -131,7 +145,7 @@ interface TypePanelCloseButtonProps extends Omit<TypeButtonProps, "children"> {
131
145
  }
132
146
 
133
147
  declare const PanelComponent: {
134
- ({ children, closeButtonLabel, header, footer, title, titleId, direction, width, gap, mobileBreakpoint, zIndex, id, snapPoints, defaultSnapPoint, snapPoint, onSnapPointChange, snapToSequentialPoints, actions, actionsInHeader, "aria-labelledby": ariaLabelledByProp, "aria-label": ariaLabel, ...rest }: TypePanelProps): react_jsx_runtime.JSX.Element;
148
+ ({ children, closeButtonLabel, header, headerless, footer, title, titleId, direction, width, gap, mobileBreakpoint, zIndex, id, snapPoints, defaultSnapPoint, snapPoint, onSnapPointChange, snapToSequentialPoints, actions, actionsInHeader, "aria-labelledby": ariaLabelledByProp, "aria-label": ariaLabel, ...rest }: TypePanelProps): react_jsx_runtime.JSX.Element;
135
149
  Header: {
136
150
  ({ title, id, children, render, ...rest }: TypePanelHeaderProps): string | number | boolean | Iterable<React.ReactNode> | react_jsx_runtime.JSX.Element | null | undefined;
137
151
  displayName: string;
package/dist/index.d.ts CHANGED
@@ -13,6 +13,11 @@ interface TypePanelContext {
13
13
  openPanel: () => void;
14
14
  closePanel: () => void;
15
15
  closeButtonLabel?: string;
16
+ /**
17
+ * Set by `Panel` when rendered headerless. `Panel.Content` reads this to
18
+ * render flush (no padding) and defer overflow scrolling to its children.
19
+ */
20
+ headerless?: boolean;
16
21
  }
17
22
  interface TypePanelProviderProps {
18
23
  children: React.ReactNode;
@@ -34,6 +39,15 @@ interface TypePanelProps extends TypeStyledComponentsCommonProps, TypeSystemComm
34
39
  header?: React.ReactNode;
35
40
  /** Custom footer content. Not rendered when omitted. */
36
41
  footer?: React.ReactNode;
42
+ /**
43
+ * Renders children flush, without the built-in header/close button or content
44
+ * padding, and lets the children own overflow scrolling. Use when the content
45
+ * provides its own chrome (e.g. an embedded agent UI). Provide `aria-label`
46
+ * (or `aria-labelledby`) for an accessible name, since no header title is
47
+ * rendered. `title`, `titleId`, and `closeButtonLabel` are ignored in this
48
+ * mode. Defaults to false.
49
+ */
50
+ headerless?: boolean;
37
51
  /** Title shown in the auto-rendered default header. Ignored when `header` is provided. */
38
52
  title?: string;
39
53
  /**
@@ -131,7 +145,7 @@ interface TypePanelCloseButtonProps extends Omit<TypeButtonProps, "children"> {
131
145
  }
132
146
 
133
147
  declare const PanelComponent: {
134
- ({ children, closeButtonLabel, header, footer, title, titleId, direction, width, gap, mobileBreakpoint, zIndex, id, snapPoints, defaultSnapPoint, snapPoint, onSnapPointChange, snapToSequentialPoints, actions, actionsInHeader, "aria-labelledby": ariaLabelledByProp, "aria-label": ariaLabel, ...rest }: TypePanelProps): react_jsx_runtime.JSX.Element;
148
+ ({ children, closeButtonLabel, header, headerless, footer, title, titleId, direction, width, gap, mobileBreakpoint, zIndex, id, snapPoints, defaultSnapPoint, snapPoint, onSnapPointChange, snapToSequentialPoints, actions, actionsInHeader, "aria-labelledby": ariaLabelledByProp, "aria-label": ariaLabel, ...rest }: TypePanelProps): react_jsx_runtime.JSX.Element;
135
149
  Header: {
136
150
  ({ title, id, children, render, ...rest }: TypePanelHeaderProps): string | number | boolean | Iterable<React.ReactNode> | react_jsx_runtime.JSX.Element | null | undefined;
137
151
  displayName: string;
package/dist/index.js CHANGED
@@ -147,7 +147,7 @@ var PanelContainer = import_styled_components.default.aside`
147
147
  ${(props) => props.$direction === "bottom" ? import_styled_components.css`
148
148
  width: 100%;
149
149
  ` : import_styled_components.css`
150
- height: 100%;
150
+ align-self: stretch;
151
151
  `}
152
152
 
153
153
  ${import_seeds_react_system_props.COMMON}
@@ -165,27 +165,41 @@ var PanelInner = import_styled_components.default.div`
165
165
  overflow: hidden;
166
166
  `;
167
167
  var Content = (0, import_styled_components.default)(import_seeds_react_box2.default)`
168
- overflow-y: auto;
168
+ overflow-y: ${({ $scroll = true }) => $scroll ? "auto" : "hidden"};
169
169
  `;
170
170
  var Footer = (0, import_styled_components.default)(import_seeds_react_box2.default)`
171
171
  flex: 0 0 auto;
172
172
  overflow: hidden;
173
+ /*
174
+ * On mobile the Panel renders inside the Drawer's bottom sheet, whose popup
175
+ * deliberately bleeds 3rem (--bleed) below the viewport for elastic
176
+ * overscroll (see seeds-react-drawer/src/styles.ts). A footer pinned to the
177
+ * end of that popup would land inside the bleed and clip below the fold, so
178
+ * we lift it by the inherited --bleed; the gap left behind shows the popup's
179
+ * own background, so there is no visible seam. On desktop --bleed is unset,
180
+ * so the 0px fallback leaves the footer untouched.
181
+ */
182
+ margin-bottom: var(--bleed, 0px);
173
183
  `;
174
184
 
175
185
  // src/PanelContent.tsx
176
186
  var import_jsx_runtime3 = require("react/jsx-runtime");
177
- var PanelContent = ({ children, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
178
- Content,
179
- {
180
- flex: "1 1 auto",
181
- minHeight: "0",
182
- p: 450,
183
- color: "text.body",
184
- "data-panel-content": "",
185
- ...rest,
186
- children
187
- }
188
- );
187
+ var PanelContent = ({ children, ...rest }) => {
188
+ const { headerless } = usePanelContext();
189
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
190
+ Content,
191
+ {
192
+ flex: "1 1 auto",
193
+ minHeight: "0",
194
+ p: headerless ? 0 : 450,
195
+ $scroll: !headerless,
196
+ color: "text.body",
197
+ "data-panel-content": "",
198
+ ...rest,
199
+ children
200
+ }
201
+ );
202
+ };
189
203
  PanelContent.displayName = "Panel.Content";
190
204
 
191
205
  // src/PanelFooter.tsx
@@ -265,6 +279,7 @@ var PanelComponent = ({
265
279
  children,
266
280
  closeButtonLabel,
267
281
  header,
282
+ headerless = false,
268
283
  footer,
269
284
  title,
270
285
  titleId,
@@ -289,17 +304,28 @@ var PanelComponent = ({
289
304
  const { isPanelOpen, closePanel } = panelContext;
290
305
  const isMobile = (0, import_seeds_react_hooks.useIsMobile)(mobileBreakpoint);
291
306
  const enrichedValue = React6.useMemo(
292
- () => ({ ...panelContext, closeButtonLabel }),
293
- [panelContext, closeButtonLabel]
307
+ () => ({ ...panelContext, closeButtonLabel, headerless }),
308
+ [panelContext, closeButtonLabel, headerless]
294
309
  );
295
310
  const prevChildrenRef = React6.useRef(null);
296
311
  if (isPanelOpen) {
297
312
  prevChildrenRef.current = children;
298
313
  }
299
314
  const renderedChildren = isPanelOpen ? children : prevChildrenRef.current;
300
- const effectiveAriaLabelledBy = ariaLabelledByProp ?? (header == null ? titleId : void 0);
315
+ const effectiveAriaLabelledBy = ariaLabelledByProp ?? (!headerless && header == null ? titleId : void 0);
301
316
  if (isMobile) {
302
- const shouldRenderActionsHeader = header == null && actionsInHeader === true && !!actions && actions.length > 0;
317
+ const shouldRenderActionsHeader = !headerless && header == null && actionsInHeader === true && !!actions && actions.length > 0;
318
+ let defaultMobileHeader = null;
319
+ if (!headerless) {
320
+ defaultMobileHeader = shouldRenderActionsHeader ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
321
+ PanelMobileActionsHeader,
322
+ {
323
+ title,
324
+ titleId,
325
+ actions
326
+ }
327
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_seeds_react_drawer2.default.Header, { title, id: titleId });
328
+ }
303
329
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PanelContext.Provider, { value: enrichedValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
304
330
  import_seeds_react_drawer2.default,
305
331
  {
@@ -319,15 +345,8 @@ var PanelComponent = ({
319
345
  "aria-labelledby": effectiveAriaLabelledBy,
320
346
  "aria-label": ariaLabel,
321
347
  children: [
322
- header ?? (shouldRenderActionsHeader ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
323
- PanelMobileActionsHeader,
324
- {
325
- title,
326
- titleId,
327
- actions
328
- }
329
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_seeds_react_drawer2.default.Header, { title, id: titleId })),
330
- children,
348
+ header ?? defaultMobileHeader,
349
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PanelContent, { children }),
331
350
  footer
332
351
  ]
333
352
  }
@@ -346,8 +365,8 @@ var PanelComponent = ({
346
365
  "aria-labelledby": effectiveAriaLabelledBy,
347
366
  "aria-label": ariaLabel,
348
367
  children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(PanelInner, { $direction: direction, $width: width, children: [
349
- header ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PanelHeader, { title, id: titleId }),
350
- renderedChildren,
368
+ header ?? (headerless ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PanelHeader, { title, id: titleId })),
369
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PanelContent, { children: renderedChildren }),
351
370
  footer
352
371
  ] })
353
372
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Panel.tsx","../src/PanelContext.tsx","../src/PanelHeader.tsx","../src/PanelCloseButton.tsx","../src/PanelContent.tsx","../src/styles.ts","../src/PanelFooter.tsx","../src/PanelMobileActionsHeader.tsx","../src/PanelProvider.tsx","../src/PanelTypes.ts"],"sourcesContent":["import Panel from \"./Panel\";\n\nexport default Panel;\nexport { Panel };\nexport { PanelContext, usePanelContext } from \"./PanelContext\";\nexport { PanelProvider } from \"./PanelProvider\";\nexport { PanelHeader } from \"./PanelHeader\";\nexport { PanelContent } from \"./PanelContent\";\nexport { PanelCloseButton } from \"./PanelCloseButton\";\nexport { PanelFooter } from \"./PanelFooter\";\nexport * from \"./PanelTypes\";\n","import * as React from \"react\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport { useIsMobile } from \"@sproutsocial/seeds-react-hooks\";\nimport { usePanelContext, PanelContext } from \"./PanelContext\";\nimport { PanelHeader } from \"./PanelHeader\";\nimport { PanelContent } from \"./PanelContent\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport { PanelFooter } from \"./PanelFooter\";\nimport { PanelMobileActionsHeader } from \"./PanelMobileActionsHeader\";\nimport { PanelContainer, PanelInner } from \"./styles\";\nimport type { TypePanelProps, TypePanelContext } from \"./PanelTypes\";\n\nconst PanelComponent = ({\n children,\n closeButtonLabel,\n header,\n footer,\n title,\n titleId,\n direction = \"right\",\n width = 384,\n gap = 4,\n mobileBreakpoint,\n zIndex,\n id,\n snapPoints,\n defaultSnapPoint,\n snapPoint,\n onSnapPointChange,\n snapToSequentialPoints,\n actions,\n actionsInHeader,\n \"aria-labelledby\": ariaLabelledByProp,\n \"aria-label\": ariaLabel,\n ...rest\n}: TypePanelProps) => {\n const panelContext = usePanelContext();\n const { isPanelOpen, closePanel } = panelContext;\n const isMobile = useIsMobile(mobileBreakpoint);\n\n // Expose closeButtonLabel through context so PanelCloseButton can read it\n // without prop drilling — same pattern as DrawerContext.\n const enrichedValue = React.useMemo<TypePanelContext>(\n () => ({ ...panelContext, closeButtonLabel }),\n [panelContext, closeButtonLabel]\n );\n\n // Freeze the last-rendered children during the collapse so consumers that\n // conditionally render content don't produce an empty panel shell while the\n // flex-basis animation runs.\n const prevChildrenRef = React.useRef<React.ReactNode>(null);\n if (isPanelOpen) {\n prevChildrenRef.current = children;\n }\n const renderedChildren = isPanelOpen ? children : prevChildrenRef.current;\n\n // When the consumer relies on the default header, its title element renders\n // with `id={titleId}`. Auto-wire `aria-labelledby` so the dialog/aside has an\n // accessible name without forcing every caller to repeat the id.\n const effectiveAriaLabelledBy =\n ariaLabelledByProp ?? (header == null ? titleId : undefined);\n\n if (isMobile) {\n // With `actionsInHeader`, Drawer suppresses the floating rail and expects\n // the consumer to render the actions inside a custom header. Auto-compose\n // one (title + action pills + close pill) when the consumer hasn't\n // supplied their own header; otherwise we'd drop `actions` on the floor.\n const shouldRenderActionsHeader =\n header == null &&\n actionsInHeader === true &&\n !!actions &&\n actions.length > 0;\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <Drawer\n {...rest}\n open={isPanelOpen}\n onClose={closePanel}\n direction=\"bottom\"\n closeButtonLabel={closeButtonLabel}\n zIndex={zIndex}\n snapPoints={snapPoints}\n defaultSnapPoint={defaultSnapPoint}\n snapPoint={snapPoint}\n onSnapPointChange={onSnapPointChange}\n snapToSequentialPoints={snapToSequentialPoints}\n actions={actions}\n actionsInHeader={actionsInHeader}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n {header ??\n (shouldRenderActionsHeader ? (\n <PanelMobileActionsHeader\n title={title}\n titleId={titleId}\n actions={actions!}\n />\n ) : (\n <Drawer.Header title={title} id={titleId} />\n ))}\n {children}\n {footer}\n </Drawer>\n </PanelContext.Provider>\n );\n }\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <PanelContainer\n {...rest}\n $isOpen={isPanelOpen}\n $direction={direction}\n $width={width}\n $gap={gap}\n data-qa-panel={id}\n data-qa-panel-isopen={isPanelOpen}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n <PanelInner $direction={direction} $width={width}>\n {header ?? <PanelHeader title={title} id={titleId} />}\n {renderedChildren}\n {footer}\n </PanelInner>\n </PanelContainer>\n </PanelContext.Provider>\n );\n};\n\nPanelComponent.Header = PanelHeader;\nPanelComponent.Content = PanelContent;\nPanelComponent.CloseButton = PanelCloseButton;\nPanelComponent.Footer = PanelFooter;\n\nexport const Panel = PanelComponent;\nexport default PanelComponent;\n","import * as React from \"react\";\nimport type { TypePanelContext } from \"./PanelTypes\";\n\nexport const PanelContext = React.createContext<TypePanelContext | null>(null);\n\nexport const usePanelContext = (): TypePanelContext => {\n const ctx = React.useContext(PanelContext);\n if (!ctx) {\n throw new Error(\n \"usePanelContext must be used within a <PanelProvider>. Wrap the consuming tree in <PanelProvider> to provide isPanelOpen / togglePanel.\"\n );\n }\n return ctx;\n};\n","import Box from \"@sproutsocial/seeds-react-box\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { usePanelContext } from \"./PanelContext\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport type { TypePanelHeaderProps } from \"./PanelTypes\";\n\nexport const PanelHeader = ({\n title = \"\",\n id = undefined,\n children,\n render,\n ...rest\n}: TypePanelHeaderProps) => {\n const panelContext = usePanelContext();\n\n if (render) {\n return render(panelContext);\n }\n\n return (\n <Box\n display=\"flex\"\n flex=\"0 0 auto\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n p={400}\n borderBottom=\"1px solid\"\n borderColor=\"container.border.base\"\n {...rest}\n >\n {children || (\n <>\n <Text.Headline id={id}>{title}</Text.Headline>\n <PanelCloseButton />\n </>\n )}\n </Box>\n );\n};\n\nPanelHeader.displayName = \"Panel.Header\";\n","import * as React from \"react\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport { usePanelContext } from \"./PanelContext\";\nimport type { TypePanelCloseButtonProps } from \"./PanelTypes\";\n\nexport const PanelCloseButton = (props: TypePanelCloseButtonProps) => {\n const panelContext = usePanelContext();\n\n if (props.render) {\n return props.render(panelContext) ?? null;\n }\n\n return (\n <Button\n appearance=\"pill\"\n aria-label={panelContext.closeButtonLabel}\n onClick={panelContext.closePanel}\n {...props}\n >\n {props.children || <Icon aria-hidden name=\"x-outline\" />}\n </Button>\n );\n};\n\nPanelCloseButton.displayName = \"Panel.CloseButton\";\n","import * as React from \"react\";\nimport { Content } from \"./styles\";\nimport type { TypePanelContentProps } from \"./PanelTypes\";\n\nexport const PanelContent = ({ children, ...rest }: TypePanelContentProps) => (\n <Content\n flex=\"1 1 auto\"\n minHeight=\"0\"\n p={450}\n color=\"text.body\"\n data-panel-content=\"\"\n {...rest}\n >\n {children}\n </Content>\n);\n\nPanelContent.displayName = \"Panel.Content\";\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSystemCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport { MOTION_DURATION_MEDIUM } from \"@sproutsocial/seeds-motion/unitless\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { PanelDirection } from \"./PanelTypes\";\n\ninterface PanelContainerProps extends TypeSystemCommonProps {\n $isOpen: boolean;\n $direction: PanelDirection;\n $width: number;\n $gap: number;\n}\n\nconst gapSide = (direction: PanelDirection): \"left\" | \"right\" | \"top\" => {\n if (direction === \"right\") return \"left\";\n if (direction === \"left\") return \"right\";\n return \"top\";\n};\n\nexport const PanelContainer = styled.aside<PanelContainerProps>`\n background: ${(props) => props.theme.colors.container.background.base};\n flex-grow: 0;\n flex-shrink: 0;\n overflow: hidden;\n transition: flex-basis ${MOTION_DURATION_MEDIUM}s ease-in-out,\n margin ${MOTION_DURATION_MEDIUM}s ease-in-out;\n flex-basis: ${(props) => (props.$isOpen ? `${props.$width}px` : \"0px\")};\n margin-${(props) => gapSide(props.$direction)}: ${(props) =>\n props.$isOpen && props.$gap ? `${props.$gap}px` : \"0px\"};\n border-radius: ${({ theme }) => theme.radii[800]};\n\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n width: 100%;\n `\n : css`\n height: 100%;\n `}\n\n ${COMMON}\n`;\n\nexport const PanelInner = styled.div<{\n $direction: PanelDirection;\n $width: number;\n}>`\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n min-height: ${props.$width}px;\n width: 100%;\n `\n : css`\n min-width: ${props.$width}px;\n height: 100%;\n `}\n display: flex;\n flex-direction: column;\n overflow: hidden;\n`;\n\nexport const Content = styled(Box)`\n overflow-y: auto;\n`;\n\nexport const Footer = styled(Box)`\n flex: 0 0 auto;\n overflow: hidden;\n`;\n","import * as React from \"react\";\nimport { Footer } from \"./styles\";\nimport type { TypePanelFooterProps } from \"./PanelTypes\";\n\nexport const PanelFooter = ({ children, ...rest }: TypePanelFooterProps) => (\n <Footer p={450} data-panel-footer=\"\" {...rest}>\n {children}\n </Footer>\n);\n\nPanelFooter.displayName = \"Panel.Footer\";\n","import * as React from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\n// eslint-disable-next-line import/no-deprecated\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeDrawerActionProps } from \"@sproutsocial/seeds-react-drawer\";\n\ninterface TypePanelMobileActionsHeaderProps {\n title?: string;\n titleId?: string;\n actions: TypeDrawerActionProps[];\n}\n\n/**\n * Mobile bottom-sheet header used by Panel when `actionsInHeader` is set and\n * no custom `header` is provided. Renders the title on the left and the\n * forwarded actions plus a close button as pills on the right — mirrors the\n * pattern in `seeds-react-peek-in/PeekIn.tsx`. The Drawer's floating rail is\n * suppressed in this combination (`actionsInHeader` opts out), so without this\n * header the actions would render nowhere.\n */\nexport const PanelMobileActionsHeader = ({\n title,\n titleId,\n actions,\n}: TypePanelMobileActionsHeaderProps) => (\n <Drawer.Header\n render={(ctx) => (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n pt={400}\n px={450}\n flex=\"0 0 auto\"\n >\n <Text\n as=\"h2\"\n fontSize={400}\n fontWeight=\"semibold\"\n color=\"text.headline\"\n id={titleId}\n >\n {title}\n </Text>\n <Box display=\"flex\" alignItems=\"center\" gap={200}>\n {actions.map((action, i) => (\n <Button\n key={i}\n appearance=\"pill\"\n aria-label={action[\"aria-label\"]}\n onClick={action.onClick}\n disabled={action.disabled}\n >\n {action.iconName && <Icon aria-hidden name={action.iconName} />}\n </Button>\n ))}\n <Button\n appearance=\"pill\"\n aria-label={ctx.closeButtonLabel}\n onClick={ctx.onClose}\n >\n <Icon aria-hidden name=\"x-outline\" />\n </Button>\n </Box>\n </Box>\n )}\n />\n);\n\nPanelMobileActionsHeader.displayName = \"PanelMobileActionsHeader\";\n","import * as React from \"react\";\nimport { PanelContext } from \"./PanelContext\";\nimport type { TypePanelContext, TypePanelProviderProps } from \"./PanelTypes\";\n\nexport const PanelProvider = ({\n children,\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n}: TypePanelProviderProps) => {\n const [internalOpen, setInternalOpen] = React.useState(defaultOpen);\n const isControlled = controlledOpen !== undefined;\n const isPanelOpen = isControlled ? controlledOpen : internalOpen;\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange]\n );\n\n const openPanel = React.useCallback(() => setOpen(true), [setOpen]);\n const closePanel = React.useCallback(() => setOpen(false), [setOpen]);\n const togglePanel = React.useCallback(\n () => setOpen(!isPanelOpen),\n [setOpen, isPanelOpen]\n );\n\n const value = React.useMemo<TypePanelContext>(\n () => ({ isPanelOpen, openPanel, closePanel, togglePanel }),\n [isPanelOpen, openPanel, closePanel, togglePanel]\n );\n\n return (\n <PanelContext.Provider value={value}>{children}</PanelContext.Provider>\n );\n};\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\nimport type {\n TypeDrawerSnapPoint,\n TypeDrawerActionProps,\n} from \"@sproutsocial/seeds-react-drawer\";\n\nexport type { TypeDrawerActionProps as TypePanelActionProps };\n\nexport type PanelDirection = \"left\" | \"right\" | \"bottom\";\n\nexport interface TypePanelContext {\n isPanelOpen: boolean;\n togglePanel: () => void;\n openPanel: () => void;\n closePanel: () => void;\n closeButtonLabel?: string;\n}\n\nexport interface TypePanelProviderProps {\n children: React.ReactNode;\n /** Initial open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Controlled open state. When provided, the provider becomes controlled. */\n open?: boolean;\n /** Called whenever the open state changes. Required for controlled usage. */\n onOpenChange?: (open: boolean) => void;\n}\n\nexport interface TypePanelProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\"> {\n children: React.ReactNode;\n\n /** Label for the close button. Usually \"Close\". */\n closeButtonLabel: string;\n\n /**\n * Custom header content. When provided, replaces the auto-rendered default\n * header entirely — `title` and `titleId` are ignored.\n */\n header?: React.ReactNode;\n\n /** Custom footer content. Not rendered when omitted. */\n footer?: React.ReactNode;\n\n /** Title shown in the auto-rendered default header. Ignored when `header` is provided. */\n title?: string;\n\n /**\n * Sets the `id` on the title element of the auto-rendered header. When the\n * default header is used, Panel automatically wires `aria-labelledby` to this\n * id so the dialog/aside has an accessible name. Pass an explicit\n * `aria-labelledby` to override (e.g. when pointing at a different element).\n * Ignored when `header` is provided — supply your own `aria-labelledby` in\n * that case.\n */\n titleId?: string;\n\n /** Side the panel anchors to on desktop. Defaults to \"right\". */\n direction?: PanelDirection;\n\n /**\n * Width (px) when direction is \"left\" or \"right\", or height (px) when\n * direction is \"bottom\". Defaults to 384 to match the existing web-app-core\n * Panel.\n */\n width?: number;\n\n /**\n * Visual gap (px) between the panel and the adjacent content. Applied as\n * margin on the side facing the content (left when direction=\"right\",\n * right when direction=\"left\", top when direction=\"bottom\"). Animates with\n * the panel's open/close transition and collapses to 0 when closed so the\n * gap does not remain visible alongside a zero-width panel. Defaults to 0.\n */\n gap?: number;\n\n /**\n * Forwarded to `useIsMobile`. Accepts a px number or any CSS media-query\n * length. Below this width, the panel renders as an overlay bottom sheet\n * (via seeds-react-drawer). Defaults to the theme's `breakpoints.sm`.\n */\n mobileBreakpoint?: number | string;\n\n /** Applies only to the mobile bottom-sheet rendering. */\n zIndex?: number;\n\n /** Optional id used for data-qa-panel attributes. */\n id?: string;\n\n /**\n * Snap points the panel can rest at when rendered as a mobile bottom sheet.\n * Numbers 0–1 are viewport-height fractions; numbers > 1 are pixels; strings\n * accept `px`/`rem` (e.g. `\"480px\"`, `\"30rem\"`). Order matters — the last\n * entry is the \"expanded\" state. Ignored on the desktop side-panel rendering.\n */\n snapPoints?: TypeDrawerSnapPoint[];\n\n /** Initial snap point for uncontrolled use. Mobile only. */\n defaultSnapPoint?: TypeDrawerSnapPoint | null;\n\n /** Controlled active snap point. Pair with `onSnapPointChange`. Mobile only. */\n snapPoint?: TypeDrawerSnapPoint | null;\n\n /** Fires when the active snap point changes. Mobile only. */\n onSnapPointChange?: (snapPoint: TypeDrawerSnapPoint | null) => void;\n\n /**\n * When true, fast swipes can't skip past adjacent snap points. Mobile only.\n */\n snapToSequentialPoints?: boolean;\n\n /**\n * Action buttons shown in a floating rail above the panel on mobile (the\n * bottom-sheet rendering). Ignored on desktop side-panel rendering — pass\n * actions through `header`/`footer` slots there. The rail owns the close\n * button so the default header omits its built-in close affordance.\n */\n actions?: TypeDrawerActionProps[];\n\n /**\n * Opt out of the floating mobile rail and render the `actions` inline in the\n * header as pill buttons instead. Useful for nested bottom sheets and\n * snap-point layouts where the floating rail would collide with surrounding\n * UI. Defaults to `false`.\n *\n * When `header` is omitted, Panel auto-composes a mobile header that renders\n * the title, the `actions` as pills, and a close-button pill. When `header`\n * is provided, the consumer is responsible for rendering the actions inside\n * their own header — `actions` is forwarded for context only.\n */\n actionsInHeader?: boolean;\n}\n\nexport interface TypePanelHeaderProps extends TypeBoxProps {\n title?: string;\n /**\n * When children are provided, `<Panel.CloseButton />` is NOT rendered\n * automatically. Include it yourself to preserve keyboard accessibility.\n */\n children?: React.ReactNode;\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n}\n\nexport interface TypePanelContentProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelFooterProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelCloseButtonProps\n extends Omit<TypeButtonProps, \"children\"> {\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n children?: React.ReactNode;\n}\n"],"mappings":"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","names":["React","import_seeds_react_drawer","React","Button","Icon","import_jsx_runtime","Box","Text","React","import_seeds_react_box","styled","Box","import_jsx_runtime","React","import_jsx_runtime","React","import_seeds_react_box","import_seeds_react_button","import_seeds_react_icon","import_seeds_react_text","import_jsx_runtime","Drawer","Box","Text","Button","Icon","import_jsx_runtime","Drawer","React","import_jsx_runtime","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Panel.tsx","../src/PanelContext.tsx","../src/PanelHeader.tsx","../src/PanelCloseButton.tsx","../src/PanelContent.tsx","../src/styles.ts","../src/PanelFooter.tsx","../src/PanelMobileActionsHeader.tsx","../src/PanelProvider.tsx","../src/PanelTypes.ts"],"sourcesContent":["import Panel from \"./Panel\";\n\nexport default Panel;\nexport { Panel };\nexport { PanelContext, usePanelContext } from \"./PanelContext\";\nexport { PanelProvider } from \"./PanelProvider\";\nexport { PanelHeader } from \"./PanelHeader\";\nexport { PanelContent } from \"./PanelContent\";\nexport { PanelCloseButton } from \"./PanelCloseButton\";\nexport { PanelFooter } from \"./PanelFooter\";\nexport * from \"./PanelTypes\";\n","import * as React from \"react\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport { useIsMobile } from \"@sproutsocial/seeds-react-hooks\";\nimport { usePanelContext, PanelContext } from \"./PanelContext\";\nimport { PanelHeader } from \"./PanelHeader\";\nimport { PanelContent } from \"./PanelContent\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport { PanelFooter } from \"./PanelFooter\";\nimport { PanelMobileActionsHeader } from \"./PanelMobileActionsHeader\";\nimport { PanelContainer, PanelInner } from \"./styles\";\nimport type { TypePanelProps, TypePanelContext } from \"./PanelTypes\";\n\nconst PanelComponent = ({\n children,\n closeButtonLabel,\n header,\n headerless = false,\n footer,\n title,\n titleId,\n direction = \"right\",\n width = 384,\n gap = 4,\n mobileBreakpoint,\n zIndex,\n id,\n snapPoints,\n defaultSnapPoint,\n snapPoint,\n onSnapPointChange,\n snapToSequentialPoints,\n actions,\n actionsInHeader,\n \"aria-labelledby\": ariaLabelledByProp,\n \"aria-label\": ariaLabel,\n ...rest\n}: TypePanelProps) => {\n const panelContext = usePanelContext();\n const { isPanelOpen, closePanel } = panelContext;\n const isMobile = useIsMobile(mobileBreakpoint);\n\n // Expose closeButtonLabel through context so PanelCloseButton can read it\n // without prop drilling — same pattern as DrawerContext.\n const enrichedValue = React.useMemo<TypePanelContext>(\n () => ({ ...panelContext, closeButtonLabel, headerless }),\n [panelContext, closeButtonLabel, headerless]\n );\n\n // Freeze the last-rendered children during the collapse so consumers that\n // conditionally render content don't produce an empty panel shell while the\n // flex-basis animation runs.\n const prevChildrenRef = React.useRef<React.ReactNode>(null);\n if (isPanelOpen) {\n prevChildrenRef.current = children;\n }\n const renderedChildren = isPanelOpen ? children : prevChildrenRef.current;\n\n // When the consumer relies on the default header, its title element renders\n // with `id={titleId}`. Auto-wire `aria-labelledby` so the dialog/aside has an\n // accessible name without forcing every caller to repeat the id.\n const effectiveAriaLabelledBy =\n ariaLabelledByProp ?? (!headerless && header == null ? titleId : undefined);\n\n if (isMobile) {\n // With `actionsInHeader`, Drawer suppresses the floating rail and expects\n // the consumer to render the actions inside a custom header. Auto-compose\n // one (title + action pills + close pill) when the consumer hasn't\n // supplied their own header; otherwise we'd drop `actions` on the floor.\n const shouldRenderActionsHeader =\n !headerless &&\n header == null &&\n actionsInHeader === true &&\n !!actions &&\n actions.length > 0;\n\n // Headerless suppresses the built-in header entirely; the children own all\n // chrome in that mode.\n let defaultMobileHeader: React.ReactNode = null;\n if (!headerless) {\n defaultMobileHeader = shouldRenderActionsHeader ? (\n <PanelMobileActionsHeader\n title={title}\n titleId={titleId}\n actions={actions!}\n />\n ) : (\n <Drawer.Header title={title} id={titleId} />\n );\n }\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <Drawer\n {...rest}\n open={isPanelOpen}\n onClose={closePanel}\n direction=\"bottom\"\n closeButtonLabel={closeButtonLabel}\n zIndex={zIndex}\n snapPoints={snapPoints}\n defaultSnapPoint={defaultSnapPoint}\n snapPoint={snapPoint}\n onSnapPointChange={onSnapPointChange}\n snapToSequentialPoints={snapToSequentialPoints}\n actions={actions}\n actionsInHeader={actionsInHeader}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n {header ?? defaultMobileHeader}\n <PanelContent>{children}</PanelContent>\n {footer}\n </Drawer>\n </PanelContext.Provider>\n );\n }\n\n return (\n <PanelContext.Provider value={enrichedValue}>\n <PanelContainer\n {...rest}\n $isOpen={isPanelOpen}\n $direction={direction}\n $width={width}\n $gap={gap}\n data-qa-panel={id}\n data-qa-panel-isopen={isPanelOpen}\n aria-labelledby={effectiveAriaLabelledBy}\n aria-label={ariaLabel}\n >\n <PanelInner $direction={direction} $width={width}>\n {header ??\n (headerless ? null : <PanelHeader title={title} id={titleId} />)}\n <PanelContent>{renderedChildren}</PanelContent>\n {footer}\n </PanelInner>\n </PanelContainer>\n </PanelContext.Provider>\n );\n};\n\nPanelComponent.Header = PanelHeader;\nPanelComponent.Content = PanelContent;\nPanelComponent.CloseButton = PanelCloseButton;\nPanelComponent.Footer = PanelFooter;\n\nexport const Panel = PanelComponent;\nexport default PanelComponent;\n","import * as React from \"react\";\nimport type { TypePanelContext } from \"./PanelTypes\";\n\nexport const PanelContext = React.createContext<TypePanelContext | null>(null);\n\nexport const usePanelContext = (): TypePanelContext => {\n const ctx = React.useContext(PanelContext);\n if (!ctx) {\n throw new Error(\n \"usePanelContext must be used within a <PanelProvider>. Wrap the consuming tree in <PanelProvider> to provide isPanelOpen / togglePanel.\"\n );\n }\n return ctx;\n};\n","import Box from \"@sproutsocial/seeds-react-box\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { usePanelContext } from \"./PanelContext\";\nimport { PanelCloseButton } from \"./PanelCloseButton\";\nimport type { TypePanelHeaderProps } from \"./PanelTypes\";\n\nexport const PanelHeader = ({\n title = \"\",\n id = undefined,\n children,\n render,\n ...rest\n}: TypePanelHeaderProps) => {\n const panelContext = usePanelContext();\n\n if (render) {\n return render(panelContext);\n }\n\n return (\n <Box\n display=\"flex\"\n flex=\"0 0 auto\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n p={400}\n borderBottom=\"1px solid\"\n borderColor=\"container.border.base\"\n {...rest}\n >\n {children || (\n <>\n <Text.Headline id={id}>{title}</Text.Headline>\n <PanelCloseButton />\n </>\n )}\n </Box>\n );\n};\n\nPanelHeader.displayName = \"Panel.Header\";\n","import * as React from \"react\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport { usePanelContext } from \"./PanelContext\";\nimport type { TypePanelCloseButtonProps } from \"./PanelTypes\";\n\nexport const PanelCloseButton = (props: TypePanelCloseButtonProps) => {\n const panelContext = usePanelContext();\n\n if (props.render) {\n return props.render(panelContext) ?? null;\n }\n\n return (\n <Button\n appearance=\"pill\"\n aria-label={panelContext.closeButtonLabel}\n onClick={panelContext.closePanel}\n {...props}\n >\n {props.children || <Icon aria-hidden name=\"x-outline\" />}\n </Button>\n );\n};\n\nPanelCloseButton.displayName = \"Panel.CloseButton\";\n","import * as React from \"react\";\nimport { Content } from \"./styles\";\nimport { usePanelContext } from \"./PanelContext\";\nimport type { TypePanelContentProps } from \"./PanelTypes\";\n\nexport const PanelContent = ({ children, ...rest }: TypePanelContentProps) => {\n // In headerless mode the content renders flush and defers overflow scrolling\n // to its children, so the panel can host content that owns its own chrome.\n const { headerless } = usePanelContext();\n\n return (\n <Content\n flex=\"1 1 auto\"\n minHeight=\"0\"\n p={headerless ? 0 : 450}\n $scroll={!headerless}\n color=\"text.body\"\n data-panel-content=\"\"\n {...rest}\n >\n {children}\n </Content>\n );\n};\n\nPanelContent.displayName = \"Panel.Content\";\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSystemCommonProps } from \"@sproutsocial/seeds-react-system-props\";\nimport { MOTION_DURATION_MEDIUM } from \"@sproutsocial/seeds-motion/unitless\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { PanelDirection } from \"./PanelTypes\";\n\ninterface PanelContainerProps extends TypeSystemCommonProps {\n $isOpen: boolean;\n $direction: PanelDirection;\n $width: number;\n $gap: number;\n}\n\nconst gapSide = (direction: PanelDirection): \"left\" | \"right\" | \"top\" => {\n if (direction === \"right\") return \"left\";\n if (direction === \"left\") return \"right\";\n return \"top\";\n};\n\nexport const PanelContainer = styled.aside<PanelContainerProps>`\n background: ${(props) => props.theme.colors.container.background.base};\n flex-grow: 0;\n flex-shrink: 0;\n overflow: hidden;\n transition: flex-basis ${MOTION_DURATION_MEDIUM}s ease-in-out,\n margin ${MOTION_DURATION_MEDIUM}s ease-in-out;\n flex-basis: ${(props) => (props.$isOpen ? `${props.$width}px` : \"0px\")};\n margin-${(props) => gapSide(props.$direction)}: ${(props) =>\n props.$isOpen && props.$gap ? `${props.$gap}px` : \"0px\"};\n border-radius: ${({ theme }) => theme.radii[800]};\n\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n width: 100%;\n `\n : css`\n align-self: stretch;\n `}\n\n ${COMMON}\n`;\n\nexport const PanelInner = styled.div<{\n $direction: PanelDirection;\n $width: number;\n}>`\n ${(props) =>\n props.$direction === \"bottom\"\n ? css`\n min-height: ${props.$width}px;\n width: 100%;\n `\n : css`\n min-width: ${props.$width}px;\n height: 100%;\n `}\n display: flex;\n flex-direction: column;\n overflow: hidden;\n`;\n\nexport const Content = styled(Box)<{ $scroll?: boolean }>`\n overflow-y: ${({ $scroll = true }) => ($scroll ? \"auto\" : \"hidden\")};\n`;\n\nexport const Footer = styled(Box)`\n flex: 0 0 auto;\n overflow: hidden;\n /*\n * On mobile the Panel renders inside the Drawer's bottom sheet, whose popup\n * deliberately bleeds 3rem (--bleed) below the viewport for elastic\n * overscroll (see seeds-react-drawer/src/styles.ts). A footer pinned to the\n * end of that popup would land inside the bleed and clip below the fold, so\n * we lift it by the inherited --bleed; the gap left behind shows the popup's\n * own background, so there is no visible seam. On desktop --bleed is unset,\n * so the 0px fallback leaves the footer untouched.\n */\n margin-bottom: var(--bleed, 0px);\n`;\n","import * as React from \"react\";\nimport { Footer } from \"./styles\";\nimport type { TypePanelFooterProps } from \"./PanelTypes\";\n\nexport const PanelFooter = ({ children, ...rest }: TypePanelFooterProps) => (\n <Footer p={450} data-panel-footer=\"\" {...rest}>\n {children}\n </Footer>\n);\n\nPanelFooter.displayName = \"Panel.Footer\";\n","import * as React from \"react\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Button from \"@sproutsocial/seeds-react-button\";\nimport Drawer from \"@sproutsocial/seeds-react-drawer\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\n// eslint-disable-next-line import/no-deprecated\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport type { TypeDrawerActionProps } from \"@sproutsocial/seeds-react-drawer\";\n\ninterface TypePanelMobileActionsHeaderProps {\n title?: string;\n titleId?: string;\n actions: TypeDrawerActionProps[];\n}\n\n/**\n * Mobile bottom-sheet header used by Panel when `actionsInHeader` is set and\n * no custom `header` is provided. Renders the title on the left and the\n * forwarded actions plus a close button as pills on the right — mirrors the\n * pattern in `seeds-react-peek-in/PeekIn.tsx`. The Drawer's floating rail is\n * suppressed in this combination (`actionsInHeader` opts out), so without this\n * header the actions would render nowhere.\n */\nexport const PanelMobileActionsHeader = ({\n title,\n titleId,\n actions,\n}: TypePanelMobileActionsHeaderProps) => (\n <Drawer.Header\n render={(ctx) => (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n pt={400}\n px={450}\n flex=\"0 0 auto\"\n >\n <Text\n as=\"h2\"\n fontSize={400}\n fontWeight=\"semibold\"\n color=\"text.headline\"\n id={titleId}\n >\n {title}\n </Text>\n <Box display=\"flex\" alignItems=\"center\" gap={200}>\n {actions.map((action, i) => (\n <Button\n key={i}\n appearance=\"pill\"\n aria-label={action[\"aria-label\"]}\n onClick={action.onClick}\n disabled={action.disabled}\n >\n {action.iconName && <Icon aria-hidden name={action.iconName} />}\n </Button>\n ))}\n <Button\n appearance=\"pill\"\n aria-label={ctx.closeButtonLabel}\n onClick={ctx.onClose}\n >\n <Icon aria-hidden name=\"x-outline\" />\n </Button>\n </Box>\n </Box>\n )}\n />\n);\n\nPanelMobileActionsHeader.displayName = \"PanelMobileActionsHeader\";\n","import * as React from \"react\";\nimport { PanelContext } from \"./PanelContext\";\nimport type { TypePanelContext, TypePanelProviderProps } from \"./PanelTypes\";\n\nexport const PanelProvider = ({\n children,\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n}: TypePanelProviderProps) => {\n const [internalOpen, setInternalOpen] = React.useState(defaultOpen);\n const isControlled = controlledOpen !== undefined;\n const isPanelOpen = isControlled ? controlledOpen : internalOpen;\n\n const setOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange]\n );\n\n const openPanel = React.useCallback(() => setOpen(true), [setOpen]);\n const closePanel = React.useCallback(() => setOpen(false), [setOpen]);\n const togglePanel = React.useCallback(\n () => setOpen(!isPanelOpen),\n [setOpen, isPanelOpen]\n );\n\n const value = React.useMemo<TypePanelContext>(\n () => ({ isPanelOpen, openPanel, closePanel, togglePanel }),\n [isPanelOpen, openPanel, closePanel, togglePanel]\n );\n\n return (\n <PanelContext.Provider value={value}>{children}</PanelContext.Provider>\n );\n};\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\nimport type {\n TypeDrawerSnapPoint,\n TypeDrawerActionProps,\n} from \"@sproutsocial/seeds-react-drawer\";\n\nexport type { TypeDrawerActionProps as TypePanelActionProps };\n\nexport type PanelDirection = \"left\" | \"right\" | \"bottom\";\n\nexport interface TypePanelContext {\n isPanelOpen: boolean;\n togglePanel: () => void;\n openPanel: () => void;\n closePanel: () => void;\n closeButtonLabel?: string;\n /**\n * Set by `Panel` when rendered headerless. `Panel.Content` reads this to\n * render flush (no padding) and defer overflow scrolling to its children.\n */\n headerless?: boolean;\n}\n\nexport interface TypePanelProviderProps {\n children: React.ReactNode;\n /** Initial open state for uncontrolled usage. */\n defaultOpen?: boolean;\n /** Controlled open state. When provided, the provider becomes controlled. */\n open?: boolean;\n /** Called whenever the open state changes. Required for controlled usage. */\n onOpenChange?: (open: boolean) => void;\n}\n\nexport interface TypePanelProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\"> {\n children: React.ReactNode;\n\n /** Label for the close button. Usually \"Close\". */\n closeButtonLabel: string;\n\n /**\n * Custom header content. When provided, replaces the auto-rendered default\n * header entirely — `title` and `titleId` are ignored.\n */\n header?: React.ReactNode;\n\n /** Custom footer content. Not rendered when omitted. */\n footer?: React.ReactNode;\n\n /**\n * Renders children flush, without the built-in header/close button or content\n * padding, and lets the children own overflow scrolling. Use when the content\n * provides its own chrome (e.g. an embedded agent UI). Provide `aria-label`\n * (or `aria-labelledby`) for an accessible name, since no header title is\n * rendered. `title`, `titleId`, and `closeButtonLabel` are ignored in this\n * mode. Defaults to false.\n */\n headerless?: boolean;\n\n /** Title shown in the auto-rendered default header. Ignored when `header` is provided. */\n title?: string;\n\n /**\n * Sets the `id` on the title element of the auto-rendered header. When the\n * default header is used, Panel automatically wires `aria-labelledby` to this\n * id so the dialog/aside has an accessible name. Pass an explicit\n * `aria-labelledby` to override (e.g. when pointing at a different element).\n * Ignored when `header` is provided — supply your own `aria-labelledby` in\n * that case.\n */\n titleId?: string;\n\n /** Side the panel anchors to on desktop. Defaults to \"right\". */\n direction?: PanelDirection;\n\n /**\n * Width (px) when direction is \"left\" or \"right\", or height (px) when\n * direction is \"bottom\". Defaults to 384 to match the existing web-app-core\n * Panel.\n */\n width?: number;\n\n /**\n * Visual gap (px) between the panel and the adjacent content. Applied as\n * margin on the side facing the content (left when direction=\"right\",\n * right when direction=\"left\", top when direction=\"bottom\"). Animates with\n * the panel's open/close transition and collapses to 0 when closed so the\n * gap does not remain visible alongside a zero-width panel. Defaults to 0.\n */\n gap?: number;\n\n /**\n * Forwarded to `useIsMobile`. Accepts a px number or any CSS media-query\n * length. Below this width, the panel renders as an overlay bottom sheet\n * (via seeds-react-drawer). Defaults to the theme's `breakpoints.sm`.\n */\n mobileBreakpoint?: number | string;\n\n /** Applies only to the mobile bottom-sheet rendering. */\n zIndex?: number;\n\n /** Optional id used for data-qa-panel attributes. */\n id?: string;\n\n /**\n * Snap points the panel can rest at when rendered as a mobile bottom sheet.\n * Numbers 0–1 are viewport-height fractions; numbers > 1 are pixels; strings\n * accept `px`/`rem` (e.g. `\"480px\"`, `\"30rem\"`). Order matters — the last\n * entry is the \"expanded\" state. Ignored on the desktop side-panel rendering.\n */\n snapPoints?: TypeDrawerSnapPoint[];\n\n /** Initial snap point for uncontrolled use. Mobile only. */\n defaultSnapPoint?: TypeDrawerSnapPoint | null;\n\n /** Controlled active snap point. Pair with `onSnapPointChange`. Mobile only. */\n snapPoint?: TypeDrawerSnapPoint | null;\n\n /** Fires when the active snap point changes. Mobile only. */\n onSnapPointChange?: (snapPoint: TypeDrawerSnapPoint | null) => void;\n\n /**\n * When true, fast swipes can't skip past adjacent snap points. Mobile only.\n */\n snapToSequentialPoints?: boolean;\n\n /**\n * Action buttons shown in a floating rail above the panel on mobile (the\n * bottom-sheet rendering). Ignored on desktop side-panel rendering — pass\n * actions through `header`/`footer` slots there. The rail owns the close\n * button so the default header omits its built-in close affordance.\n */\n actions?: TypeDrawerActionProps[];\n\n /**\n * Opt out of the floating mobile rail and render the `actions` inline in the\n * header as pill buttons instead. Useful for nested bottom sheets and\n * snap-point layouts where the floating rail would collide with surrounding\n * UI. Defaults to `false`.\n *\n * When `header` is omitted, Panel auto-composes a mobile header that renders\n * the title, the `actions` as pills, and a close-button pill. When `header`\n * is provided, the consumer is responsible for rendering the actions inside\n * their own header — `actions` is forwarded for context only.\n */\n actionsInHeader?: boolean;\n}\n\nexport interface TypePanelHeaderProps extends TypeBoxProps {\n title?: string;\n /**\n * When children are provided, `<Panel.CloseButton />` is NOT rendered\n * automatically. Include it yourself to preserve keyboard accessibility.\n */\n children?: React.ReactNode;\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n}\n\nexport interface TypePanelContentProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelFooterProps extends TypeBoxProps {\n children?: React.ReactNode;\n}\n\nexport interface TypePanelCloseButtonProps\n extends Omit<TypeButtonProps, \"children\"> {\n /** Render-prop override that receives the parent panel context. */\n render?: React.FC<TypePanelContext>;\n children?: React.ReactNode;\n}\n"],"mappings":"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","names":["React","import_seeds_react_drawer","React","Button","Icon","import_jsx_runtime","Box","Text","React","import_seeds_react_box","styled","Box","import_jsx_runtime","React","import_jsx_runtime","React","import_seeds_react_box","import_seeds_react_button","import_seeds_react_icon","import_seeds_react_text","import_jsx_runtime","Drawer","Box","Text","Button","Icon","import_jsx_runtime","Drawer","React","import_jsx_runtime","React"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-panel",
3
- "version": "0.3.7",
3
+ "version": "1.0.0",
4
4
  "description": "Seeds React Panel",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
@@ -40,12 +40,10 @@ const MainContent = () => (
40
40
  );
41
41
 
42
42
  const PanelBody = () => (
43
- <Panel.Content>
44
- <Text.BodyCopy as="p">
45
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ac
46
- consectetur tortor.
47
- </Text.BodyCopy>
48
- </Panel.Content>
43
+ <Text.BodyCopy as="p">
44
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ac consectetur
45
+ tortor.
46
+ </Text.BodyCopy>
49
47
  );
50
48
 
51
49
  const meta: Meta<typeof Panel> = {
@@ -94,6 +92,27 @@ export const LeftSide: Story = {
94
92
  ),
95
93
  };
96
94
 
95
+ export const WithMargin: Story = {
96
+ render: () => (
97
+ <PanelProvider defaultOpen>
98
+ <LayoutFrame>
99
+ <MainContent />
100
+ <Panel
101
+ closeButtonLabel="Close"
102
+ title="Panel title"
103
+ titleId="panel-header"
104
+ aria-labelledby="panel-header"
105
+ mt={200}
106
+ mb={200}
107
+ mr={200}
108
+ >
109
+ <PanelBody />
110
+ </Panel>
111
+ </LayoutFrame>
112
+ </PanelProvider>
113
+ ),
114
+ };
115
+
97
116
  export const CustomWidth: Story = {
98
117
  render: () => (
99
118
  <PanelProvider defaultOpen>
@@ -127,12 +146,48 @@ export const CustomHeader: Story = {
127
146
  </Panel.Header>
128
147
  }
129
148
  >
130
- <Panel.Content>
131
- <Text.BodyCopy as="p">
132
- When you supply a custom header via the header prop, you are
133
- responsible for rendering Panel.CloseButton yourself.
134
- </Text.BodyCopy>
135
- </Panel.Content>
149
+ <Text.BodyCopy as="p">
150
+ When you supply a custom header via the header prop, you are
151
+ responsible for rendering Panel.CloseButton yourself.
152
+ </Text.BodyCopy>
153
+ </Panel>
154
+ </LayoutFrame>
155
+ </PanelProvider>
156
+ ),
157
+ };
158
+
159
+ export const Headerless: Story = {
160
+ render: () => (
161
+ <PanelProvider defaultOpen>
162
+ <LayoutFrame>
163
+ <MainContent />
164
+ <Panel closeButtonLabel="Close" headerless aria-label="Assistant">
165
+ {/*
166
+ * In headerless mode the children own all chrome and overflow — no
167
+ * built-in header, padding, or close button. The auto-wrapped
168
+ * Panel.Content renders flush (p=0) and is bounded to the panel
169
+ * height, so the children supply their own flex column + scroll
170
+ * region. Here a fixed bar stays put while the body scrolls flush to
171
+ * the panel edges.
172
+ */}
173
+ <Box display="flex" flexDirection="column" height="100%">
174
+ <Box
175
+ flex="0 0 auto"
176
+ bg="container.background.base"
177
+ borderBottom="1px solid"
178
+ borderColor="container.border.base"
179
+ p={400}
180
+ >
181
+ <Text.Headline as="h2">Custom chrome</Text.Headline>
182
+ </Box>
183
+ <Box flex="1 1 auto" minHeight={0} overflow="auto" p={400}>
184
+ {Array.from({ length: 30 }, (_, i) => (
185
+ <Text.BodyCopy key={i} as="p">
186
+ Scrollable line {i + 1}
187
+ </Text.BodyCopy>
188
+ ))}
189
+ </Box>
190
+ </Box>
136
191
  </Panel>
137
192
  </LayoutFrame>
138
193
  </PanelProvider>
@@ -149,20 +204,20 @@ export const WithFooter: Story = {
149
204
  title="Panel title"
150
205
  titleId="panel-header"
151
206
  aria-labelledby="panel-header"
207
+ footer={
208
+ <Panel.Footer>
209
+ <Box display="flex" justifyContent="flex-end" gap={300}>
210
+ <Button appearance="secondary">Cancel</Button>
211
+ <Button appearance="primary">Save</Button>
212
+ </Box>
213
+ </Panel.Footer>
214
+ }
152
215
  >
153
- <Panel.Content>
154
- {Array.from({ length: 20 }, (_, i) => (
155
- <Text.BodyCopy key={i} as="p">
156
- Scrollable content line {i + 1}
157
- </Text.BodyCopy>
158
- ))}
159
- </Panel.Content>
160
- <Panel.Footer>
161
- <Box display="flex" justifyContent="flex-end" gap={300}>
162
- <Button appearance="secondary">Cancel</Button>
163
- <Button appearance="primary">Save</Button>
164
- </Box>
165
- </Panel.Footer>
216
+ {Array.from({ length: 20 }, (_, i) => (
217
+ <Text.BodyCopy key={i} as="p">
218
+ Scrollable content line {i + 1}
219
+ </Text.BodyCopy>
220
+ ))}
166
221
  </Panel>
167
222
  </LayoutFrame>
168
223
  </PanelProvider>
@@ -221,20 +276,20 @@ export const MobileWithFooter: Story = {
221
276
  title="Panel title"
222
277
  titleId="panel-header"
223
278
  aria-labelledby="panel-header"
279
+ footer={
280
+ <Panel.Footer>
281
+ <Box display="flex" justifyContent="flex-end" gap={300}>
282
+ <Button appearance="secondary">Cancel</Button>
283
+ <Button appearance="primary">Save</Button>
284
+ </Box>
285
+ </Panel.Footer>
286
+ }
224
287
  >
225
- <Panel.Content>
226
- {Array.from({ length: 20 }, (_, i) => (
227
- <Text.BodyCopy key={i} as="p">
228
- Scrollable content line {i + 1}
229
- </Text.BodyCopy>
230
- ))}
231
- </Panel.Content>
232
- <Panel.Footer>
233
- <Box display="flex" justifyContent="flex-end" gap={300}>
234
- <Button appearance="secondary">Cancel</Button>
235
- <Button appearance="primary">Save</Button>
236
- </Box>
237
- </Panel.Footer>
288
+ {Array.from({ length: 20 }, (_, i) => (
289
+ <Text.BodyCopy key={i} as="p">
290
+ Scrollable content line {i + 1}
291
+ </Text.BodyCopy>
292
+ ))}
238
293
  </Panel>
239
294
  </LayoutFrame>
240
295
  </PanelProvider>
@@ -316,20 +371,20 @@ export const CustomHeaderAndFooter: Story = {
316
371
  <Panel.CloseButton />
317
372
  </Panel.Header>
318
373
  }
374
+ footer={
375
+ <Panel.Footer>
376
+ <Box display="flex" justifyContent="flex-end" gap={300}>
377
+ <Button appearance="secondary">Cancel</Button>
378
+ <Button appearance="primary">Save</Button>
379
+ </Box>
380
+ </Panel.Footer>
381
+ }
319
382
  >
320
- <Panel.Content>
321
- {Array.from({ length: 20 }, (_, i) => (
322
- <Text.BodyCopy key={i} as="p">
323
- Scrollable content line {i + 1}
324
- </Text.BodyCopy>
325
- ))}
326
- </Panel.Content>
327
- <Panel.Footer>
328
- <Box display="flex" justifyContent="flex-end" gap={300}>
329
- <Button appearance="secondary">Cancel</Button>
330
- <Button appearance="primary">Save</Button>
331
- </Box>
332
- </Panel.Footer>
383
+ {Array.from({ length: 20 }, (_, i) => (
384
+ <Text.BodyCopy key={i} as="p">
385
+ Scrollable content line {i + 1}
386
+ </Text.BodyCopy>
387
+ ))}
333
388
  </Panel>
334
389
  </LayoutFrame>
335
390
  </PanelProvider>
package/src/Panel.tsx CHANGED
@@ -14,6 +14,7 @@ const PanelComponent = ({
14
14
  children,
15
15
  closeButtonLabel,
16
16
  header,
17
+ headerless = false,
17
18
  footer,
18
19
  title,
19
20
  titleId,
@@ -41,8 +42,8 @@ const PanelComponent = ({
41
42
  // Expose closeButtonLabel through context so PanelCloseButton can read it
42
43
  // without prop drilling — same pattern as DrawerContext.
43
44
  const enrichedValue = React.useMemo<TypePanelContext>(
44
- () => ({ ...panelContext, closeButtonLabel }),
45
- [panelContext, closeButtonLabel]
45
+ () => ({ ...panelContext, closeButtonLabel, headerless }),
46
+ [panelContext, closeButtonLabel, headerless]
46
47
  );
47
48
 
48
49
  // Freeze the last-rendered children during the collapse so consumers that
@@ -58,7 +59,7 @@ const PanelComponent = ({
58
59
  // with `id={titleId}`. Auto-wire `aria-labelledby` so the dialog/aside has an
59
60
  // accessible name without forcing every caller to repeat the id.
60
61
  const effectiveAriaLabelledBy =
61
- ariaLabelledByProp ?? (header == null ? titleId : undefined);
62
+ ariaLabelledByProp ?? (!headerless && header == null ? titleId : undefined);
62
63
 
63
64
  if (isMobile) {
64
65
  // With `actionsInHeader`, Drawer suppresses the floating rail and expects
@@ -66,11 +67,27 @@ const PanelComponent = ({
66
67
  // one (title + action pills + close pill) when the consumer hasn't
67
68
  // supplied their own header; otherwise we'd drop `actions` on the floor.
68
69
  const shouldRenderActionsHeader =
70
+ !headerless &&
69
71
  header == null &&
70
72
  actionsInHeader === true &&
71
73
  !!actions &&
72
74
  actions.length > 0;
73
75
 
76
+ // Headerless suppresses the built-in header entirely; the children own all
77
+ // chrome in that mode.
78
+ let defaultMobileHeader: React.ReactNode = null;
79
+ if (!headerless) {
80
+ defaultMobileHeader = shouldRenderActionsHeader ? (
81
+ <PanelMobileActionsHeader
82
+ title={title}
83
+ titleId={titleId}
84
+ actions={actions!}
85
+ />
86
+ ) : (
87
+ <Drawer.Header title={title} id={titleId} />
88
+ );
89
+ }
90
+
74
91
  return (
75
92
  <PanelContext.Provider value={enrichedValue}>
76
93
  <Drawer
@@ -90,17 +107,8 @@ const PanelComponent = ({
90
107
  aria-labelledby={effectiveAriaLabelledBy}
91
108
  aria-label={ariaLabel}
92
109
  >
93
- {header ??
94
- (shouldRenderActionsHeader ? (
95
- <PanelMobileActionsHeader
96
- title={title}
97
- titleId={titleId}
98
- actions={actions!}
99
- />
100
- ) : (
101
- <Drawer.Header title={title} id={titleId} />
102
- ))}
103
- {children}
110
+ {header ?? defaultMobileHeader}
111
+ <PanelContent>{children}</PanelContent>
104
112
  {footer}
105
113
  </Drawer>
106
114
  </PanelContext.Provider>
@@ -121,8 +129,9 @@ const PanelComponent = ({
121
129
  aria-label={ariaLabel}
122
130
  >
123
131
  <PanelInner $direction={direction} $width={width}>
124
- {header ?? <PanelHeader title={title} id={titleId} />}
125
- {renderedChildren}
132
+ {header ??
133
+ (headerless ? null : <PanelHeader title={title} id={titleId} />)}
134
+ <PanelContent>{renderedChildren}</PanelContent>
126
135
  {footer}
127
136
  </PanelInner>
128
137
  </PanelContainer>
@@ -1,18 +1,26 @@
1
1
  import * as React from "react";
2
2
  import { Content } from "./styles";
3
+ import { usePanelContext } from "./PanelContext";
3
4
  import type { TypePanelContentProps } from "./PanelTypes";
4
5
 
5
- export const PanelContent = ({ children, ...rest }: TypePanelContentProps) => (
6
- <Content
7
- flex="1 1 auto"
8
- minHeight="0"
9
- p={450}
10
- color="text.body"
11
- data-panel-content=""
12
- {...rest}
13
- >
14
- {children}
15
- </Content>
16
- );
6
+ export const PanelContent = ({ children, ...rest }: TypePanelContentProps) => {
7
+ // In headerless mode the content renders flush and defers overflow scrolling
8
+ // to its children, so the panel can host content that owns its own chrome.
9
+ const { headerless } = usePanelContext();
10
+
11
+ return (
12
+ <Content
13
+ flex="1 1 auto"
14
+ minHeight="0"
15
+ p={headerless ? 0 : 450}
16
+ $scroll={!headerless}
17
+ color="text.body"
18
+ data-panel-content=""
19
+ {...rest}
20
+ >
21
+ {children}
22
+ </Content>
23
+ );
24
+ };
17
25
 
18
26
  PanelContent.displayName = "Panel.Content";
package/src/PanelTypes.ts CHANGED
@@ -20,6 +20,11 @@ export interface TypePanelContext {
20
20
  openPanel: () => void;
21
21
  closePanel: () => void;
22
22
  closeButtonLabel?: string;
23
+ /**
24
+ * Set by `Panel` when rendered headerless. `Panel.Content` reads this to
25
+ * render flush (no padding) and defer overflow scrolling to its children.
26
+ */
27
+ headerless?: boolean;
23
28
  }
24
29
 
25
30
  export interface TypePanelProviderProps {
@@ -50,6 +55,16 @@ export interface TypePanelProps
50
55
  /** Custom footer content. Not rendered when omitted. */
51
56
  footer?: React.ReactNode;
52
57
 
58
+ /**
59
+ * Renders children flush, without the built-in header/close button or content
60
+ * padding, and lets the children own overflow scrolling. Use when the content
61
+ * provides its own chrome (e.g. an embedded agent UI). Provide `aria-label`
62
+ * (or `aria-labelledby`) for an accessible name, since no header title is
63
+ * rendered. `title`, `titleId`, and `closeButtonLabel` are ignored in this
64
+ * mode. Defaults to false.
65
+ */
66
+ headerless?: boolean;
67
+
53
68
  /** Title shown in the auto-rendered default header. Ignored when `header` is provided. */
54
69
  title?: string;
55
70
 
@@ -19,11 +19,7 @@ const renderPanel = ({
19
19
  defaultOpen = false,
20
20
  direction,
21
21
  width,
22
- children = (
23
- <Panel.Content>
24
- <p>Panel Content</p>
25
- </Panel.Content>
26
- ),
22
+ children = <p>Panel Content</p>,
27
23
  title = "Panel Header",
28
24
  titleId = "panel-1-header",
29
25
  closeButtonLabel = "close button",
@@ -97,7 +93,7 @@ describe("Panel (desktop / inline mode)", () => {
97
93
  );
98
94
  });
99
95
 
100
- it("Panel.Content sets data-panel-content attribute", () => {
96
+ it("auto-wraps children in Panel.Content (data-panel-content)", () => {
101
97
  renderPanel({ defaultOpen: true });
102
98
  expect(
103
99
  screen.getByText(/panel content/i).closest("[data-panel-content]")
@@ -138,6 +134,51 @@ describe("Panel (desktop / inline mode)", () => {
138
134
  renderPanel({ defaultOpen: false });
139
135
  expect(screen.getByRole("complementary")).toHaveStyle("flex-basis: 0px");
140
136
  });
137
+
138
+ describe("headerless", () => {
139
+ it("suppresses the built-in header and close button", () => {
140
+ renderPanel({ defaultOpen: true, headerless: true });
141
+
142
+ expect(screen.queryByText("Panel Header")).not.toBeInTheDocument();
143
+ expect(screen.queryByLabelText("close button")).not.toBeInTheDocument();
144
+ });
145
+
146
+ it("still auto-wraps children in Panel.Content", () => {
147
+ renderPanel({ defaultOpen: true, headerless: true });
148
+
149
+ expect(screen.getByText(/panel content/i)).toBeInTheDocument();
150
+ expect(
151
+ screen.getByText(/panel content/i).closest("[data-panel-content]")
152
+ ).toBeInTheDocument();
153
+ });
154
+
155
+ it("still opens and closes via context", async () => {
156
+ const { user } = renderPanel({ defaultOpen: false, headerless: true });
157
+ const panel = screen.getByRole("complementary");
158
+ expect(panel).toHaveAttribute("data-qa-panel-isopen", "false");
159
+
160
+ await act(async () => {
161
+ await user.click(screen.getByText("toggle"));
162
+ });
163
+
164
+ await waitFor(() => {
165
+ expect(panel).toHaveAttribute("data-qa-panel-isopen", "true");
166
+ });
167
+ expect(screen.getByText(/panel content/i)).toBeInTheDocument();
168
+ });
169
+
170
+ it("takes its accessible name from aria-label without a dangling aria-labelledby", () => {
171
+ renderPanel({
172
+ defaultOpen: true,
173
+ headerless: true,
174
+ "aria-label": "Assistant",
175
+ });
176
+
177
+ const panel = screen.getByRole("complementary");
178
+ expect(panel).toHaveAttribute("aria-label", "Assistant");
179
+ expect(panel).not.toHaveAttribute("aria-labelledby");
180
+ });
181
+ });
141
182
  });
142
183
 
143
184
  describe("Panel (mobile / drawer mode)", () => {
@@ -303,6 +344,47 @@ describe("Panel (mobile / drawer mode)", () => {
303
344
  // The consumer owns rendering — Panel must not duplicate the action pill.
304
345
  expect(screen.queryByLabelText("Expand")).not.toBeInTheDocument();
305
346
  });
347
+
348
+ it("suppresses the default Drawer header when headerless", () => {
349
+ renderPanel({ defaultOpen: true, headerless: true });
350
+
351
+ expect(screen.queryByText("Panel Header")).not.toBeInTheDocument();
352
+ expect(screen.getByText(/panel content/i)).toBeInTheDocument();
353
+ });
354
+
355
+ it("wraps children in the scrollable Panel.Content region", () => {
356
+ renderPanel({ defaultOpen: true });
357
+
358
+ expect(
359
+ screen.getByText(/panel content/i).closest("[data-panel-content]")
360
+ ).toBeInTheDocument();
361
+ });
362
+
363
+ it("renders the footer outside the scroll region so it stays pinned", () => {
364
+ renderPanel({
365
+ defaultOpen: true,
366
+ footer: <Panel.Footer>footer content</Panel.Footer>,
367
+ });
368
+
369
+ const footer = screen.getByText("footer content");
370
+ expect(footer).toBeInTheDocument();
371
+ // The footer must be a sibling of the scroll region, not nested inside it,
372
+ // or it would scroll away with the content and fall below the fold.
373
+ expect(footer.closest("[data-panel-content]")).not.toBeInTheDocument();
374
+ });
375
+
376
+ it("lifts the footer above the Drawer's bottom-sheet bleed", () => {
377
+ renderPanel({
378
+ defaultOpen: true,
379
+ footer: <Panel.Footer>footer content</Panel.Footer>,
380
+ });
381
+
382
+ // The footer compensates for the Drawer popup's --bleed (3rem of overscroll
383
+ // below the viewport) so its actions stay fully visible above the fold.
384
+ expect(
385
+ screen.getByText("footer content").closest("[data-panel-footer]")
386
+ ).toHaveStyleRule("margin-bottom", "var(--bleed,0px)");
387
+ });
306
388
  });
307
389
 
308
390
  describe("PanelProvider (controlled)", () => {
@@ -320,9 +402,7 @@ describe("PanelProvider (controlled)", () => {
320
402
  >
321
403
  <ToggleButton />
322
404
  <Panel closeButtonLabel="close button">
323
- <Panel.Content>
324
- <p>controlled content</p>
325
- </Panel.Content>
405
+ <p>controlled content</p>
326
406
  </Panel>
327
407
  </PanelProvider>
328
408
  );
package/src/styles.ts CHANGED
@@ -36,7 +36,7 @@ export const PanelContainer = styled.aside<PanelContainerProps>`
36
36
  width: 100%;
37
37
  `
38
38
  : css`
39
- height: 100%;
39
+ align-self: stretch;
40
40
  `}
41
41
 
42
42
  ${COMMON}
@@ -61,11 +61,21 @@ export const PanelInner = styled.div<{
61
61
  overflow: hidden;
62
62
  `;
63
63
 
64
- export const Content = styled(Box)`
65
- overflow-y: auto;
64
+ export const Content = styled(Box)<{ $scroll?: boolean }>`
65
+ overflow-y: ${({ $scroll = true }) => ($scroll ? "auto" : "hidden")};
66
66
  `;
67
67
 
68
68
  export const Footer = styled(Box)`
69
69
  flex: 0 0 auto;
70
70
  overflow: hidden;
71
+ /*
72
+ * On mobile the Panel renders inside the Drawer's bottom sheet, whose popup
73
+ * deliberately bleeds 3rem (--bleed) below the viewport for elastic
74
+ * overscroll (see seeds-react-drawer/src/styles.ts). A footer pinned to the
75
+ * end of that popup would land inside the bleed and clip below the fold, so
76
+ * we lift it by the inherited --bleed; the gap left behind shows the popup's
77
+ * own background, so there is no visible seam. On desktop --bleed is unset,
78
+ * so the 0px fallback leaves the footer untouched.
79
+ */
80
+ margin-bottom: var(--bleed, 0px);
71
81
  `;