@purpurds/drawer 6.10.0 → 6.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- ._purpur-drawer-content_1qg14_1{animation:_drawerSmallScreenAnimation_1qg14_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);height:90vh;height:90dvh;max-width:100%;position:absolute;right:0;top:10%;transition:transform var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);width:100%}@media screen and (min-width: 600px){._purpur-drawer-content_1qg14_1{animation:_drawerLargeScreenAnimation_1qg14_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);height:100vh;height:100dvh;max-width:calc(30rem * var(--purpur-rescale));top:0}}._purpur-drawer-content_1qg14_1:focus{outline:none}._purpur-drawer-content__content-container_1qg14_24{display:flex;flex-direction:column;gap:var(--purpur-spacing-400)}._purpur-drawer-content__drawer-frame_1qg14_29[data-swipe=cancel]{transform:translateY(0);transition:transform var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out)}._purpur-drawer-content__drawer-frame_1qg14_29[data-swipe=move]{transform:translateY(var(--purpur-drawer-swipe-move-y))}._purpur-drawer-content__drawer-frame_1qg14_29[data-swipe=end]{animation:_slideDown_1qg14_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out) forwards}._purpur-drawer-content__description_1qg14_39{color:var(--purpur-color-text-default);display:block;font-family:var(--purpur-typography-family-default);font-size:var(--purpur-typography-scale-100);font-weight:var(--purpur-typography-weight-normal);-webkit-hyphens:none;hyphens:none;line-height:var(--purpur-typography-line-height-loose);margin:0}._purpur-drawer-overlay_1qg14_50{animation:_overlayAnimation_1qg14_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);background:var(--purpur-color-overlay-default);top:0;right:0;bottom:0;left:0;position:fixed;transition:opacity var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out)}@keyframes _slideDown_1qg14_1{0%{transform:translateY(var(--purpur-drawer-swipe-end-y))}to{transform:translateY(100%)}}@keyframes _overlayAnimation_1qg14_1{0%{opacity:0}to{opacity:1}}@keyframes _drawerLargeScreenAnimation_1qg14_1{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes _drawerSmallScreenAnimation_1qg14_1{0%{transform:translateY(100%)}to{transform:translateY(0)}}._purpur-drawer-container--header_1r6tb_1{padding:var(--purpur-spacing-250) var(--purpur-spacing-300) var(--purpur-spacing-200);border-bottom:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak)}._purpur-drawer-container--body_1r6tb_5{padding:var(--purpur-spacing-400) var(--purpur-spacing-300) 0}._purpur-drawer-container--body_1r6tb_5._purpur-drawer-container--sticky_1r6tb_8{padding:var(--purpur-spacing-400) var(--purpur-spacing-300)}._purpur-drawer-container--footer_1r6tb_11{padding:0 var(--purpur-spacing-300) var(--purpur-spacing-200)}._purpur-drawer-container--footer_1r6tb_11._purpur-drawer-container--sticky_1r6tb_8{border-top:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak);padding:var(--purpur-spacing-200) var(--purpur-spacing-300)}._purpur-drawer-frame_jj7dt_1{background-color:var(--purpur-color-background-primary);border-top-left-radius:var(--purpur-border-radius-lg);border-top-right-radius:var(--purpur-border-radius-lg);box-shadow:var(--purpur-shadow-lg);display:flex;flex-direction:column;height:100%;position:relative}@media screen and (min-width: 600px){._purpur-drawer-frame_jj7dt_1{border-bottom-left-radius:var(--purpur-border-radius-lg);border-top-right-radius:0}}._purpur-drawer-frame--sticky-footer_jj7dt_17{gap:0}._purpur-drawer-frame__header_jj7dt_20{flex:0 0 auto}._purpur-drawer-frame__body_jj7dt_23{flex:1 1 auto;overflow:hidden}._purpur-drawer-frame__footer_jj7dt_27{flex:0 0 auto}._purpur-drawer-frame__content-container_jj7dt_30{display:flex;flex-direction:column;gap:var(--purpur-spacing-400)}._purpur-drawer-frame__content-container--no-footer_jj7dt_35{margin-bottom:var(--purpur-spacing-400)}._purpur-drawer-handle_3n0ew_1{align-items:center;display:flex;height:var(--purpur-spacing-250);justify-content:center;position:absolute;top:0;width:100%}@media screen and (min-width: 600px){._purpur-drawer-handle_3n0ew_1{display:none}}._purpur-drawer-handle_3n0ew_1:before{content:"";background:var(--purpur-color-border-weak);border-radius:var(--purpur-border-radius-full);height:var(--purpur-spacing-50);width:var(--purpur-spacing-600)}._purpur-drawer-header__row_1yg5w_1{display:flex;align-items:center;gap:var(--purpur-spacing-100)}._purpur-drawer-header__row--with-back-button_1yg5w_6{margin-bottom:var(--purpur-spacing-100)}._purpur-drawer-header__left_1yg5w_9{flex:1 1 auto}._purpur-drawer-header__right_1yg5w_12{flex:0 0 auto}._purpur-drawer-header__close-button_1yg5w_15{margin-right:calc(-1 * var(--purpur-spacing-100))}._purpur-drawer-header__back-button--only-icon_1yg5w_18{margin-left:calc(-1 * var(--purpur-spacing-100))}._purpur-drawer-scroll-area__root_1p63i_1,._purpur-drawer-scroll-area__viewport_1p63i_4{height:100%}._purpur-drawer-scroll-area__scrollbar_1p63i_7{display:flex;-webkit-user-select:none;user-select:none;touch-action:none;padding:var(--purpur-spacing-25);background:var(--purpur-color-functional-white);transition:background var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);width:var(--purpur-spacing-100)}._purpur-drawer-scroll-area__thumb_1p63i_18{background:var(--purpur-color-gray-200);border-radius:var(--purpur-spacing-200);flex:1;position:relative}._purpur-drawer-scroll-area__thumb_1p63i_18:before{content:"";height:100%;left:50%;min-height:var(--purpur-spacing-300);min-width:var(--purpur-spacing-300);position:absolute;top:50%;transform:translate(-50%,-50%);width:100%}
1
+ ._purpur-drawer-content_1xk2s_1{animation:_drawerSmallScreenAnimation_1xk2s_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);bottom:0;height:90vh;height:90dvh;max-width:100%;position:absolute;right:0;transition:transform var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);width:100%}._purpur-drawer-content--fit-to-content_1xk2s_12{display:flex;flex-direction:column;height:auto;max-height:90vh;max-height:90dvh}@media screen and (min-width: 600px){._purpur-drawer-content_1xk2s_1{animation:_drawerLargeScreenAnimation_1xk2s_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);height:100vh;height:100dvh;max-width:calc(30rem * var(--purpur-rescale));top:0}._purpur-drawer-content--fit-to-content_1xk2s_12{max-height:100vh;max-height:100dvh}}._purpur-drawer-content_1xk2s_1:focus{outline:none}._purpur-drawer-content__content-container_1xk2s_35{display:flex;flex-direction:column;gap:var(--purpur-spacing-400)}._purpur-drawer-content__drawer-frame_1xk2s_40[data-swipe=cancel]{transform:translateY(0);transition:transform var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out)}._purpur-drawer-content__drawer-frame_1xk2s_40[data-swipe=move]{transform:translateY(var(--purpur-drawer-swipe-move-y))}._purpur-drawer-content__drawer-frame_1xk2s_40[data-swipe=end]{animation:_slideDown_1xk2s_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out) forwards}._purpur-drawer-content__description_1xk2s_50{color:var(--purpur-color-text-default);display:block;font-family:var(--purpur-typography-family-default);font-size:var(--purpur-typography-scale-100);font-weight:var(--purpur-typography-weight-normal);-webkit-hyphens:none;hyphens:none;line-height:var(--purpur-typography-line-height-loose);margin:0}._purpur-drawer-overlay_1xk2s_61{animation:_overlayAnimation_1xk2s_1 var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);background:var(--purpur-color-overlay-default);top:0;right:0;bottom:0;left:0;position:fixed;transition:opacity var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out)}@keyframes _slideDown_1xk2s_1{0%{transform:translateY(var(--purpur-drawer-swipe-end-y))}to{transform:translateY(100%)}}@keyframes _overlayAnimation_1xk2s_1{0%{opacity:0}to{opacity:1}}@keyframes _drawerLargeScreenAnimation_1xk2s_1{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes _drawerSmallScreenAnimation_1xk2s_1{0%{transform:translateY(100%)}to{transform:translateY(0)}}._purpur-drawer-container--header_1r6tb_1{padding:var(--purpur-spacing-250) var(--purpur-spacing-300) var(--purpur-spacing-200);border-bottom:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak)}._purpur-drawer-container--body_1r6tb_5{padding:var(--purpur-spacing-400) var(--purpur-spacing-300) 0}._purpur-drawer-container--body_1r6tb_5._purpur-drawer-container--sticky_1r6tb_8{padding:var(--purpur-spacing-400) var(--purpur-spacing-300)}._purpur-drawer-container--footer_1r6tb_11{padding:0 var(--purpur-spacing-300) var(--purpur-spacing-200)}._purpur-drawer-container--footer_1r6tb_11._purpur-drawer-container--sticky_1r6tb_8{border-top:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak);padding:var(--purpur-spacing-200) var(--purpur-spacing-300)}._purpur-drawer-frame_1gdvv_1{background-color:var(--purpur-color-background-primary);border-top-left-radius:var(--purpur-border-radius-lg);border-top-right-radius:var(--purpur-border-radius-lg);box-shadow:var(--purpur-shadow-lg);display:flex;flex-direction:column;height:100%;position:relative}@media screen and (min-width: 600px){._purpur-drawer-frame_1gdvv_1{border-bottom-left-radius:var(--purpur-border-radius-lg);border-top-right-radius:0}}._purpur-drawer-frame--sticky-footer_1gdvv_17{gap:0}._purpur-drawer-frame__header_1gdvv_20{flex:0 0 auto}._purpur-drawer-frame__body_1gdvv_23{flex:1 1 auto;overflow:hidden}._purpur-drawer-frame--fit-to-content_1gdvv_27{flex:1 1 auto;height:auto;overflow:hidden}._purpur-drawer-frame--fit-to-content_1gdvv_27 ._purpur-drawer-frame__body_1gdvv_23{display:flex;flex-direction:column}._purpur-drawer-frame__footer_1gdvv_36{flex:0 0 auto}._purpur-drawer-frame__content-container_1gdvv_39{display:flex;flex-direction:column;gap:var(--purpur-spacing-400)}._purpur-drawer-frame__content-container--no-footer_1gdvv_44{margin-bottom:var(--purpur-spacing-400)}._purpur-drawer-handle_3n0ew_1{align-items:center;display:flex;height:var(--purpur-spacing-250);justify-content:center;position:absolute;top:0;width:100%}@media screen and (min-width: 600px){._purpur-drawer-handle_3n0ew_1{display:none}}._purpur-drawer-handle_3n0ew_1:before{content:"";background:var(--purpur-color-border-weak);border-radius:var(--purpur-border-radius-full);height:var(--purpur-spacing-50);width:var(--purpur-spacing-600)}._purpur-drawer-header__row_1yg5w_1{display:flex;align-items:center;gap:var(--purpur-spacing-100)}._purpur-drawer-header__row--with-back-button_1yg5w_6{margin-bottom:var(--purpur-spacing-100)}._purpur-drawer-header__left_1yg5w_9{flex:1 1 auto}._purpur-drawer-header__right_1yg5w_12{flex:0 0 auto}._purpur-drawer-header__close-button_1yg5w_15{margin-right:calc(-1 * var(--purpur-spacing-100))}._purpur-drawer-header__back-button--only-icon_1yg5w_18{margin-left:calc(-1 * var(--purpur-spacing-100))}._purpur-drawer-scroll-area__root_1r0fa_1{height:100%}._purpur-drawer-scroll-area__root--fit-to-content_1r0fa_4{display:flex;flex-direction:column;height:auto;overflow:hidden}._purpur-drawer-scroll-area__viewport_1r0fa_10{height:100%}._purpur-drawer-scroll-area__scrollbar_1r0fa_13{display:flex;-webkit-user-select:none;user-select:none;touch-action:none;padding:var(--purpur-spacing-25);background:var(--purpur-color-functional-white);transition:background var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);width:var(--purpur-spacing-100)}._purpur-drawer-scroll-area__thumb_1r0fa_24{background:var(--purpur-color-gray-200);border-radius:var(--purpur-spacing-200);flex:1;position:relative}._purpur-drawer-scroll-area__thumb_1r0fa_24:before{content:"";height:100%;left:50%;min-height:var(--purpur-spacing-300);min-width:var(--purpur-spacing-300);position:absolute;top:50%;transform:translate(-50%,-50%);width:100%}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@purpurds/drawer",
3
- "version": "6.10.0",
3
+ "version": "6.11.1",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "./dist/drawer.cjs.js",
6
6
  "types": "./dist/drawer.d.ts",
@@ -18,11 +18,12 @@
18
18
  "@radix-ui/react-dialog": "~1.1.6",
19
19
  "@radix-ui/react-scroll-area": "~1.2.3",
20
20
  "classnames": "~2.5.0",
21
- "@purpurds/button": "6.10.0",
22
- "@purpurds/heading": "6.10.0",
23
- "@purpurds/icon": "6.10.0",
24
- "@purpurds/tokens": "6.10.0",
25
- "@purpurds/paragraph": "6.10.0"
21
+ "@purpurds/button": "6.11.1",
22
+ "@purpurds/paragraph": "6.11.1",
23
+ "@purpurds/icon": "6.11.1",
24
+ "@purpurds/tokens": "6.11.1",
25
+ "@purpurds/visually-hidden": "6.11.1",
26
+ "@purpurds/heading": "6.11.1"
26
27
  },
27
28
  "devDependencies": {
28
29
  "eslint": "9.24.0",
@@ -4,21 +4,34 @@ $animation-settings: var(--purpur-motion-duration-200) var(--purpur-motion-easin
4
4
 
5
5
  .purpur-drawer-content {
6
6
  animation: drawerSmallScreenAnimation $animation-settings;
7
+ bottom: 0;
7
8
  height: 90vh; /* Fallback for older browsers */
8
9
  height: 90dvh;
9
10
  max-width: 100%;
10
11
  position: absolute;
11
12
  right: 0;
12
- top: 10%;
13
13
  transition: transform $animation-settings;
14
14
  width: 100%;
15
15
 
16
+ &--fit-to-content {
17
+ display: flex;
18
+ flex-direction: column;
19
+ height: auto;
20
+ max-height: 90vh; /* Fallback for older browsers */
21
+ max-height: 90dvh;
22
+ }
23
+
16
24
  @media screen and (min-width: $purpur-breakpoint-md) {
17
25
  animation: drawerLargeScreenAnimation $animation-settings;
18
26
  height: 100vh; /* Fallback for older browsers */
19
27
  height: 100dvh;
20
28
  max-width: calc(30rem * var(--purpur-rescale));
21
29
  top: 0;
30
+
31
+ &--fit-to-content {
32
+ max-height: 100vh; /* Fallback for older browsers */
33
+ max-height: 100dvh;
34
+ }
22
35
  }
23
36
 
24
37
  &:focus {
@@ -95,10 +95,36 @@ describe("DrawerContent", () => {
95
95
  const dialogOverlayElement = screen.getByTestId(Selectors.DRAWER_CONTENT_OVERLAY);
96
96
  expect(dialogOverlayElement.style.zIndex).toBe("200");
97
97
  });
98
+
99
+ it("should show the header content if it is provided", () => {
100
+ render(
101
+ <RadixDialog.Root open={true}>
102
+ <DrawerContent
103
+ data-testid={Selectors.DRAWER_CONTENT}
104
+ bodyText="bodyText"
105
+ closeButtonText="Close"
106
+ stickyFooter
107
+ title="Title"
108
+ zIndex={200}
109
+ headerContent={
110
+ <div data-testid={Selectors.DRAWER_HEADER_CONTENT}>This is the header content</div>
111
+ }
112
+ >
113
+ Some drawer-content
114
+ </DrawerContent>
115
+ </RadixDialog.Root>
116
+ );
117
+
118
+ expect(screen.getByTestId(Selectors.DRAWER_HEADER_CONTENT)).toBeInTheDocument();
119
+ expect(screen.getByTestId(Selectors.DRAWER_HEADER_CONTENT)).toHaveTextContent(
120
+ "This is the header content"
121
+ );
122
+ });
98
123
  });
99
124
 
100
125
  const Selectors = {
101
126
  DRAWER_CONTENT: "purpur-drawer-content",
102
127
  DRAWER_CONTENT_OVERLAY: "purpur-drawer-content-overlay",
103
128
  BODY_TEXT: "purpur-drawer-content-description",
129
+ DRAWER_HEADER_CONTENT: "purpur-drawer-header-content",
104
130
  };
@@ -30,7 +30,12 @@ export type DrawerContentProps = {
30
30
  className?: string;
31
31
  closeButtonText: string;
32
32
  disableCloseOnClickOutside?: boolean;
33
+ /**
34
+ * If true, the drawer height will fit to its content on small screens.
35
+ */
36
+ fitToContent?: boolean;
33
37
  footerContent?: ReactNode;
38
+ headerContent?: ReactNode;
34
39
  stickyFooter?: boolean;
35
40
  title: string;
36
41
  zIndex?: number;
@@ -50,7 +55,9 @@ export const DrawerContent = forwardRef(
50
55
  className,
51
56
  closeButtonText,
52
57
  disableCloseOnClickOutside = false,
58
+ fitToContent = false,
53
59
  footerContent,
60
+ headerContent,
54
61
  onBackButtonClick,
55
62
  stickyFooter = false,
56
63
  title,
@@ -59,7 +66,11 @@ export const DrawerContent = forwardRef(
59
66
  }: DrawerContentProps,
60
67
  ref: ForwardedRef<HTMLDivElement>
61
68
  ) => {
62
- const classes = cx([className, rootClassName]);
69
+ const classes = cx([
70
+ className,
71
+ rootClassName,
72
+ { [`${rootClassName}--fit-to-content`]: fitToContent },
73
+ ]);
63
74
 
64
75
  const drawerFrameRef = useRef<HTMLDivElement>(null);
65
76
  const onOpenChange = useContext(DrawerContext);
@@ -92,7 +103,9 @@ export const DrawerContent = forwardRef(
92
103
  backButtonOnlyIcon={backButtonOnlyIcon}
93
104
  closeButtonText={closeButtonText}
94
105
  className={cx(`${rootClassName}__drawer-frame`)}
106
+ fitToContent={fitToContent}
95
107
  footerContent={footerContent}
108
+ headerContent={headerContent}
96
109
  ref={drawerFrameRef}
97
110
  onAnimationEnd={onAnimationEnd}
98
111
  onBackButtonClick={onBackButtonClick}
@@ -1,6 +1,8 @@
1
1
  @use "@purpurds/tokens/breakpoint/variables" as *;
2
2
 
3
3
  .purpur-drawer-frame {
4
+ $root: &;
5
+
4
6
  background-color: var(--purpur-color-background-primary);
5
7
  border-top-left-radius: var(--purpur-border-radius-lg);
6
8
  border-top-right-radius: var(--purpur-border-radius-lg);
@@ -28,6 +30,17 @@
28
30
  overflow: hidden;
29
31
  }
30
32
 
33
+ &--fit-to-content {
34
+ flex: 1 1 auto;
35
+ height: auto;
36
+ overflow: hidden;
37
+
38
+ #{$root}__body {
39
+ display: flex;
40
+ flex-direction: column;
41
+ }
42
+ }
43
+
31
44
  &__footer {
32
45
  flex: 0 0 auto;
33
46
  }
@@ -17,7 +17,9 @@ export type DrawerFrameProps = {
17
17
  children: ReactNode;
18
18
  className?: string;
19
19
  closeButtonText: string;
20
+ fitToContent?: boolean;
20
21
  footerContent?: ReactNode;
22
+ headerContent?: ReactNode;
21
23
  onAnimationEnd: (event: React.AnimationEvent<HTMLDivElement>) => void;
22
24
  onBackButtonClick?: () => void;
23
25
  onSwipeStart(): void;
@@ -40,7 +42,9 @@ export const DrawerFrame = forwardRef(
40
42
  children,
41
43
  className,
42
44
  closeButtonText,
45
+ fitToContent = false,
43
46
  footerContent,
47
+ headerContent,
44
48
  onAnimationEnd,
45
49
  onBackButtonClick,
46
50
  onSwipeStart,
@@ -57,6 +61,7 @@ export const DrawerFrame = forwardRef(
57
61
  className,
58
62
  rootClassName,
59
63
  {
64
+ [`${rootClassName}--fit-to-content`]: fitToContent,
60
65
  [`${rootClassName}--sticky-footer`]: stickyFooter,
61
66
  },
62
67
  ]);
@@ -82,6 +87,7 @@ export const DrawerFrame = forwardRef(
82
87
  >
83
88
  <DrawerHeader
84
89
  title={title}
90
+ headerContent={headerContent}
85
91
  backButtonOnlyIcon={backButtonOnlyIcon}
86
92
  backButton={backButton}
87
93
  backButtonText={backButtonText}
@@ -94,6 +100,7 @@ export const DrawerFrame = forwardRef(
94
100
  <DrawerScrollArea
95
101
  className={cx(`${rootClassName}__body`)}
96
102
  data-testid={`${dataTestId}-sticky-footer-scroll-area`}
103
+ fitToContent={fitToContent}
97
104
  >
98
105
  <DrawerContainer stickyFooter>{children}</DrawerContainer>
99
106
  </DrawerScrollArea>
@@ -112,6 +119,7 @@ export const DrawerFrame = forwardRef(
112
119
  <DrawerScrollArea
113
120
  className={cx(`${rootClassName}__body`)}
114
121
  data-testid={`${dataTestId}-scroll-area`}
122
+ fitToContent={fitToContent}
115
123
  >
116
124
  <div
117
125
  className={cx([
@@ -3,10 +3,12 @@ import { Button, BUTTON_VARIANT } from "@purpurds/button";
3
3
  import { Heading, TitleVariant } from "@purpurds/heading";
4
4
  import { IconArrowLeft } from "@purpurds/icon/arrow-left";
5
5
  import { IconClose } from "@purpurds/icon/close";
6
+ import { VisuallyHidden } from "@purpurds/visually-hidden";
6
7
  import * as RadixDialog from "@radix-ui/react-dialog";
7
8
  import c from "classnames/bind";
8
9
 
9
10
  import styles from "./drawer-header.module.scss";
11
+
10
12
  const cx = c.bind(styles);
11
13
 
12
14
  export type DrawerHeaderProps = {
@@ -16,6 +18,7 @@ export type DrawerHeaderProps = {
16
18
  backButtonOnlyIcon: boolean;
17
19
  className?: string;
18
20
  closeButtonText: string;
21
+ headerContent?: React.ReactNode;
19
22
  onBackButtonClick?: () => void;
20
23
  title: string;
21
24
  };
@@ -31,6 +34,7 @@ export const DrawerHeader = forwardRef(
31
34
  backButtonOnlyIcon,
32
35
  className,
33
36
  closeButtonText,
37
+ headerContent,
34
38
  onBackButtonClick,
35
39
  title,
36
40
  ...props
@@ -70,6 +74,13 @@ export const DrawerHeader = forwardRef(
70
74
  <IconArrowLeft size="sm" />
71
75
  {!backButtonOnlyIcon && backButtonText}
72
76
  </Button>
77
+ ) : headerContent ? (
78
+ <>
79
+ {headerContent}
80
+ <VisuallyHidden asChild>
81
+ <RadixDialog.Title asChild>{title}</RadixDialog.Title>
82
+ </VisuallyHidden>
83
+ </>
73
84
  ) : (
74
85
  <RadixDialog.Title asChild>
75
86
  <Heading
@@ -97,18 +108,27 @@ export const DrawerHeader = forwardRef(
97
108
  </RadixDialog.Close>
98
109
  </div>
99
110
  </div>
100
- {backButton && backButtonText && onBackButtonClick && (
101
- <RadixDialog.Title asChild>
102
- <Heading
103
- className={cx(`${rootClassName}__heading`)}
104
- data-testid={`${dataTestId}-title-with-back-button`}
105
- tag="h2"
106
- variant={TitleVariant.TITLE200}
107
- >
108
- {title}
109
- </Heading>
110
- </RadixDialog.Title>
111
- )}
111
+ {backButton &&
112
+ backButtonText &&
113
+ onBackButtonClick &&
114
+ (headerContent ? (
115
+ <>
116
+ {headerContent}
117
+ <VisuallyHidden asChild>
118
+ <RadixDialog.Title asChild>{title}</RadixDialog.Title>
119
+ </VisuallyHidden>
120
+ </>
121
+ ) : (
122
+ <RadixDialog.Title asChild>
123
+ <Heading
124
+ data-testid={`${dataTestId}-title-with-back-button`}
125
+ tag="h2"
126
+ variant={TitleVariant.TITLE200}
127
+ >
128
+ {title}
129
+ </Heading>
130
+ </RadixDialog.Title>
131
+ ))}
112
132
  </div>
113
133
  );
114
134
  }
@@ -3,6 +3,13 @@ $animation-settings: var(--purpur-motion-duration-200) var(--purpur-motion-easin
3
3
  .purpur-drawer-scroll-area {
4
4
  &__root {
5
5
  height: 100%;
6
+
7
+ &--fit-to-content {
8
+ display: flex;
9
+ flex-direction: column;
10
+ height: auto;
11
+ overflow: hidden;
12
+ }
6
13
  }
7
14
 
8
15
  &__viewport {
@@ -9,6 +9,7 @@ export type DrawerScrollAreaProps = {
9
9
  ["data-testid"]?: string;
10
10
  children: ReactNode;
11
11
  className?: string;
12
+ fitToContent?: boolean;
12
13
  };
13
14
 
14
15
  const rootClassName = "purpur-drawer-scroll-area";
@@ -19,6 +20,7 @@ export const DrawerScrollArea = forwardRef(
19
20
  ["data-testid"]: dataTestId = "purpur-drawer-scroll-area",
20
21
  children,
21
22
  className,
23
+ fitToContent = false,
22
24
  ...props
23
25
  }: DrawerScrollAreaProps,
24
26
  ref: ForwardedRef<HTMLDivElement>
@@ -26,7 +28,11 @@ export const DrawerScrollArea = forwardRef(
26
28
  const classes = cx([className, rootClassName]);
27
29
  return (
28
30
  <div className={classes} data-testid={dataTestId} ref={ref} {...props}>
29
- <RadixScrollArea.Root className={cx(`${rootClassName}__root`)}>
31
+ <RadixScrollArea.Root
32
+ className={cx(`${rootClassName}__root`, {
33
+ [`${rootClassName}__root--fit-to-content`]: fitToContent,
34
+ })}
35
+ >
30
36
  <RadixScrollArea.Viewport className={cx(`${rootClassName}__viewport`)}>
31
37
  {children}
32
38
  </RadixScrollArea.Viewport>
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
2
  import { Button } from "@purpurds/button";
3
3
  import { Heading } from "@purpurds/heading";
4
+ import { IconAiRobot } from "@purpurds/icon/ai-robot";
4
5
  import { Paragraph } from "@purpurds/paragraph";
5
6
  import { useArgs } from "@storybook/preview-api";
6
7
  import type { Meta, StoryObj } from "@storybook/react";
@@ -142,12 +143,19 @@ const StorybookMultiDrawerTestComponent = () => {
142
143
  onBackButtonClick={() => {
143
144
  return undefined;
144
145
  }}
146
+ fitToContent
145
147
  footerContent={<StorybookTestFooterContent />}
148
+ headerContent={<IconAiRobot />}
146
149
  title="This is drawer 3"
147
150
  stickyFooter
148
151
  zIndex={20}
149
152
  >
150
- <StorybookTestBodyContent />
153
+ <Heading variant="subsection-100" tag="h3">
154
+ The standard Lorem Ipsum passage, used since the 1500s
155
+ </Heading>
156
+ <Paragraph variant="paragraph-100" style={{ marginBottom: "32px" }}>
157
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
158
+ </Paragraph>
151
159
  </Drawer.Content>
152
160
  </Drawer>
153
161
  </div>
@@ -227,7 +235,9 @@ export const ShowcaseForDrawerContent: DrawerContentStory = {
227
235
  bodyText: "This is the body text",
228
236
  closeButtonText: "Close drawer",
229
237
  disableCloseOnClickOutside: false,
238
+ fitToContent: false,
230
239
  footerContent: <StorybookTestFooterContent />,
240
+ headerContent: undefined,
231
241
  onBackButtonClick: () => {
232
242
  return undefined;
233
243
  },