jvetrau-ds 0.2.4 → 0.2.6

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/panel/panel.tsx"],"names":[],"mappings":";;;;AAWA,MAAM,QAA8B,CAAC;AAAA,EACnC,MAAA,GAAS,MAAA;AAAA,EACT,OAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAU,UAAA,CAAW,OAAA,EAAS,SAAA,EAAW;AAAA,IAC7C,sBAAsB,MAAA,KAAW;AAAA,GAClC,CAAA;AAED,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACV,GAAG,KAAA;AAAA,MAEF,QAAA,EAAA;AAAA,QAAA,CAAA,OAAA,IAAW,WAAA,qBACX,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eAAA,EACZ,QAAA,EAAA;AAAA,UAAA,OAAA,oBACC,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,gBAAA,EACX,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,UAGD,WAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,sBACV,QAAA,EAAA,WAAA,EACH;AAAA,SAAA,EAEJ,CAAA;AAAA,QAGD,QAAA,oBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kBACZ,QAAA,EACH;AAAA;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"panel.js","sourcesContent":["import React from 'react';\nimport './panel.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface PanelProps\n extends React.HTMLAttributes<HTMLElement> {\n layout?: 'card' | 'transparent';\n heading?: React.ReactNode;\n description?: React.ReactNode;\n}\n\nconst Panel: React.FC<PanelProps> = ({\n layout = 'card',\n heading,\n description,\n className = '',\n children,\n ...props\n}) => {\n const classes = classnames('panel', className, {\n 'panel--transparent': layout === 'transparent',\n });\n\n return (\n <section\n className={classes}\n {...props}\n >\n {(heading || description) && (\n <div className=\"panel__header\">\n {heading && (\n <h2 className=\"panel__heading\">\n {heading}\n </h2>\n )}\n\n {description && (\n <p className=\"panel__description\">\n {description}\n </p>\n )}\n </div>\n )}\n\n {children && (\n <div className=\"panel__content\">\n {children}\n </div>\n )}\n </section>\n );\n};\n\nexport default Panel;"]}
1
+ {"version":3,"sources":["../../../src/components/panel/panel.tsx"],"names":[],"mappings":";;;;AAaA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OACE,KAAA,KAAU,QACV,KAAA,KAAU,MAAA;AAEd;AAEA,MAAM,QAA8B,CAAC;AAAA,EACnC,MAAA,GAAS,MAAA;AAAA,EACT,OAAA;AAAA,EACA,YAAA,GAAe,CAAA;AAAA,EACf,WAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,OAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,sBACE,MAAA,KAAW;AAAA;AACf,GACF;AAEA,EAAA,MAAM,UAAA,GACJ,IAAI,YAAY,CAAA,CAAA;AAElB,EAAA,MAAM,UAAA,GACJ,WAAW,OAAO,CAAA;AAEpB,EAAA,MAAM,cAAA,GACJ,WAAW,WAAW,CAAA;AAExB,EAAA,MAAM,YACJ,UAAA,IACA,cAAA;AAEF,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACV,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,SAAA,oBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eAAA,EACZ,QAAA,EAAA;AAAA,UAAA,UAAA,oBACC,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,UAAA;AAAA,gBACT,gBAAA;AAAA,gBACA,oBAAoB,YAAY,CAAA,CAAA;AAAA,gBAChC;AAAC,eACH;AAAA,cAEC,QAAA,EAAA;AAAA;AAAA,WACH;AAAA,UAGD,cAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,sBACV,QAAA,EAAA,WAAA,EACH;AAAA,SAAA,EAEJ,CAAA;AAAA,QAGD,WAAW,QAAQ,CAAA,wBACjB,KAAA,EAAA,EAAI,SAAA,EAAU,kBACZ,QAAA,EACH;AAAA;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"panel.js","sourcesContent":["import React from 'react';\n\nimport './panel.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface PanelProps\n extends React.HTMLAttributes<HTMLElement> {\n layout?: 'card' | 'transparent';\n heading?: React.ReactNode;\n headingLevel?: 2 | 3;\n description?: React.ReactNode;\n}\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return (\n value !== null &&\n value !== undefined\n );\n}\n\nconst Panel: React.FC<PanelProps> = ({\n layout = 'card',\n heading,\n headingLevel = 2,\n description,\n className = '',\n children,\n ...props\n}) => {\n const classes = classnames(\n 'panel',\n className,\n {\n 'panel--transparent':\n layout === 'transparent',\n },\n );\n\n const HeadingTag =\n `h${headingLevel}` as 'h2' | 'h3';\n\n const hasHeading =\n hasContent(heading);\n\n const hasDescription =\n hasContent(description);\n\n const hasHeader =\n hasHeading ||\n hasDescription;\n\n return (\n <section\n className={classes}\n {...props}\n >\n {hasHeader && (\n <div className=\"panel__header\">\n {hasHeading && (\n <HeadingTag\n className={classnames(\n 'panel__heading',\n `panel__heading--h${headingLevel}`,\n {},\n )}\n >\n {heading}\n </HeadingTag>\n )}\n\n {hasDescription && (\n <p className=\"panel__description\">\n {description}\n </p>\n )}\n </div>\n )}\n\n {hasContent(children) && (\n <div className=\"panel__content\">\n {children}\n </div>\n )}\n </section>\n );\n};\n\nexport default Panel;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvetrau-ds",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Multi-brand React design system with semantic tokens",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -18,6 +18,7 @@ const Header = ({
18
18
  avatar,
19
19
  avatarDropdown,
20
20
  avatarLabel,
21
+ avatarOnClick,
21
22
  className = "",
22
23
  children,
23
24
  ...props
@@ -48,6 +49,7 @@ const Header = ({
48
49
  type: "button",
49
50
  className: "header__avatar-trigger",
50
51
  "aria-label": avatarLabel,
52
+ onClick: avatarOnClick,
51
53
  children: avatar
52
54
  }
53
55
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/patterns/header/header.tsx"],"names":["classnames","jsxs","jsx","Dropdown"],"mappings":";;;;;;;;;;;AAuCA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OACE,KAAA,KAAU,QACV,KAAA,KAAU,MAAA;AAEd;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAUA,qBAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,MAAM,YAAA,GACJ,UAAA,CAAW,IAAI,CAAA,GACX,IAAA,GACA,QAAA;AAEN,EAAA,MAAM,SAAA,GACJ,WAAW,MAAM,CAAA;AAEnB,EAAA,uBACEC,eAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACV,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,UAAA,CAAW,IAAI,CAAA,oBACdC,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,QAGD,WAAW,YAAY,CAAA,mCACrB,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,YAAA,EACH,CAAA;AAAA,QAGD,SAAA,oBACCA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kBACZ,QAAA,EAAA,cAAA,mBACCA,cAAA;AAAA,UAACC,yBAAA;AAAA,UAAA;AAAA,YACE,GAAG,cAAA;AAAA,YACJ,WAAA,EAAY,OAAA;AAAA,YACZ,OAAA,kBACED,cAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,SAAA,EAAU,wBAAA;AAAA,gBACV,YAAA,EACE,WAAA;AAAA,gBAGD,QAAA,EAAA;AAAA;AAAA;AACH;AAAA,YAIJ,MAAA,EAEJ;AAAA;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"header.cjs","sourcesContent":["import React from 'react';\n\nimport './header.css';\nimport Dropdown, {\n type DropdownProps,\n} from '../../components/dropdown';\nimport { classnames } from '../../components/helpers/classnames';\n\ntype HeaderNativeProps =\n React.HTMLAttributes<HTMLElement>;\n\ntype HeaderBaseProps =\n HeaderNativeProps & {\n logo?: React.ReactNode;\n menu?: React.ReactNode;\n };\n\ntype HeaderWithoutAvatarDropdown = {\n avatar?: React.ReactNode;\n avatarDropdown?: never;\n avatarLabel?: never;\n};\n\ntype HeaderWithAvatarDropdown = {\n avatar: React.ReactNode;\n avatarDropdown: Omit<\n DropdownProps,\n 'trigger' | 'interaction'\n >;\n avatarLabel: string;\n};\n\nexport type HeaderProps =\n HeaderBaseProps &\n (\n | HeaderWithoutAvatarDropdown\n | HeaderWithAvatarDropdown\n );\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return (\n value !== null &&\n value !== undefined\n );\n}\n\nconst Header: React.FC<HeaderProps> = ({\n logo,\n menu,\n avatar,\n avatarDropdown,\n avatarLabel,\n className = '',\n children,\n ...props\n}) => {\n const classes = classnames(\n 'header',\n className,\n {},\n );\n\n const resolvedMenu =\n hasContent(menu)\n ? menu\n : children;\n\n const hasAvatar =\n hasContent(avatar);\n\n return (\n <header\n className={classes}\n {...props}\n >\n {hasContent(logo) && (\n <div className=\"header__logo\">\n {logo}\n </div>\n )}\n\n {hasContent(resolvedMenu) && (\n <div className=\"header__menu\">\n {resolvedMenu}\n </div>\n )}\n\n {hasAvatar && (\n <div className=\"header__avatar\">\n {avatarDropdown ? (\n <Dropdown\n {...avatarDropdown}\n interaction=\"hover\"\n trigger={\n <button\n type=\"button\"\n className=\"header__avatar-trigger\"\n aria-label={\n avatarLabel\n }\n >\n {avatar}\n </button>\n }\n />\n ) : (\n avatar\n )}\n </div>\n )}\n </header>\n );\n};\n\nexport default Header;\n"]}
1
+ {"version":3,"sources":["../../../src/patterns/header/header.tsx"],"names":["classnames","jsxs","jsx","Dropdown"],"mappings":";;;;;;;;;;;AAyCA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OACE,KAAA,KAAU,QACV,KAAA,KAAU,MAAA;AAEd;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAUA,qBAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,MAAM,YAAA,GACJ,UAAA,CAAW,IAAI,CAAA,GACX,IAAA,GACA,QAAA;AAEN,EAAA,MAAM,SAAA,GACJ,WAAW,MAAM,CAAA;AAEnB,EAAA,uBACEC,eAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACV,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,UAAA,CAAW,IAAI,CAAA,oBACdC,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,QAGD,WAAW,YAAY,CAAA,mCACrB,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,YAAA,EACH,CAAA;AAAA,QAGD,SAAA,oBACCA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kBACZ,QAAA,EAAA,cAAA,mBACCA,cAAA;AAAA,UAACC,yBAAA;AAAA,UAAA;AAAA,YACE,GAAG,cAAA;AAAA,YACJ,WAAA,EAAY,OAAA;AAAA,YACZ,OAAA,kBACED,cAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,SAAA,EAAU,wBAAA;AAAA,gBACV,YAAA,EACE,WAAA;AAAA,gBAEF,OAAA,EACE,aAAA;AAAA,gBAGD,QAAA,EAAA;AAAA;AAAA;AACH;AAAA,YAIJ,MAAA,EAEJ;AAAA;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"header.cjs","sourcesContent":["import React from 'react';\n\nimport './header.css';\nimport Dropdown, {\n type DropdownProps,\n} from '../../components/dropdown';\nimport { classnames } from '../../components/helpers/classnames';\n\ntype HeaderNativeProps =\n React.HTMLAttributes<HTMLElement>;\n\ntype HeaderBaseProps =\n HeaderNativeProps & {\n logo?: React.ReactNode;\n menu?: React.ReactNode;\n };\n\ntype HeaderWithoutAvatarDropdown = {\n avatar?: React.ReactNode;\n avatarDropdown?: never;\n avatarLabel?: never;\n avatarOnClick?: never;\n};\n\ntype HeaderWithAvatarDropdown = {\n avatar: React.ReactNode;\n avatarDropdown: Omit<\n DropdownProps,\n 'trigger' | 'interaction'\n >;\n avatarLabel: string;\n avatarOnClick?: React.MouseEventHandler<HTMLButtonElement>;\n};\n\nexport type HeaderProps =\n HeaderBaseProps &\n (\n | HeaderWithoutAvatarDropdown\n | HeaderWithAvatarDropdown\n );\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return (\n value !== null &&\n value !== undefined\n );\n}\n\nconst Header: React.FC<HeaderProps> = ({\n logo,\n menu,\n avatar,\n avatarDropdown,\n avatarLabel,\n avatarOnClick,\n className = '',\n children,\n ...props\n}) => {\n const classes = classnames(\n 'header',\n className,\n {},\n );\n\n const resolvedMenu =\n hasContent(menu)\n ? menu\n : children;\n\n const hasAvatar =\n hasContent(avatar);\n\n return (\n <header\n className={classes}\n {...props}\n >\n {hasContent(logo) && (\n <div className=\"header__logo\">\n {logo}\n </div>\n )}\n\n {hasContent(resolvedMenu) && (\n <div className=\"header__menu\">\n {resolvedMenu}\n </div>\n )}\n\n {hasAvatar && (\n <div className=\"header__avatar\">\n {avatarDropdown ? (\n <Dropdown\n {...avatarDropdown}\n interaction=\"hover\"\n trigger={\n <button\n type=\"button\"\n className=\"header__avatar-trigger\"\n aria-label={\n avatarLabel\n }\n onClick={\n avatarOnClick\n }\n >\n {avatar}\n </button>\n }\n />\n ) : (\n avatar\n )}\n </div>\n )}\n </header>\n );\n};\n\nexport default Header;\n"]}
@@ -10,11 +10,13 @@ type HeaderWithoutAvatarDropdown = {
10
10
  avatar?: React.ReactNode;
11
11
  avatarDropdown?: never;
12
12
  avatarLabel?: never;
13
+ avatarOnClick?: never;
13
14
  };
14
15
  type HeaderWithAvatarDropdown = {
15
16
  avatar: React.ReactNode;
16
17
  avatarDropdown: Omit<DropdownProps, 'trigger' | 'interaction'>;
17
18
  avatarLabel: string;
19
+ avatarOnClick?: React.MouseEventHandler<HTMLButtonElement>;
18
20
  };
19
21
  export type HeaderProps = HeaderBaseProps & (HeaderWithoutAvatarDropdown | HeaderWithAvatarDropdown);
20
22
  declare const Header: React.FC<HeaderProps>;
@@ -12,6 +12,7 @@ const Header = ({
12
12
  avatar,
13
13
  avatarDropdown,
14
14
  avatarLabel,
15
+ avatarOnClick,
15
16
  className = "",
16
17
  children,
17
18
  ...props
@@ -42,6 +43,7 @@ const Header = ({
42
43
  type: "button",
43
44
  className: "header__avatar-trigger",
44
45
  "aria-label": avatarLabel,
46
+ onClick: avatarOnClick,
45
47
  children: avatar
46
48
  }
47
49
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/patterns/header/header.tsx"],"names":[],"mappings":";;;;;AAuCA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OACE,KAAA,KAAU,QACV,KAAA,KAAU,MAAA;AAEd;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,MAAM,YAAA,GACJ,UAAA,CAAW,IAAI,CAAA,GACX,IAAA,GACA,QAAA;AAEN,EAAA,MAAM,SAAA,GACJ,WAAW,MAAM,CAAA;AAEnB,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACV,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,UAAA,CAAW,IAAI,CAAA,oBACd,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,QAGD,WAAW,YAAY,CAAA,wBACrB,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,YAAA,EACH,CAAA;AAAA,QAGD,SAAA,oBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kBACZ,QAAA,EAAA,cAAA,mBACC,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACE,GAAG,cAAA;AAAA,YACJ,WAAA,EAAY,OAAA;AAAA,YACZ,OAAA,kBACE,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,SAAA,EAAU,wBAAA;AAAA,gBACV,YAAA,EACE,WAAA;AAAA,gBAGD,QAAA,EAAA;AAAA;AAAA;AACH;AAAA,YAIJ,MAAA,EAEJ;AAAA;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"header.js","sourcesContent":["import React from 'react';\n\nimport './header.css';\nimport Dropdown, {\n type DropdownProps,\n} from '../../components/dropdown';\nimport { classnames } from '../../components/helpers/classnames';\n\ntype HeaderNativeProps =\n React.HTMLAttributes<HTMLElement>;\n\ntype HeaderBaseProps =\n HeaderNativeProps & {\n logo?: React.ReactNode;\n menu?: React.ReactNode;\n };\n\ntype HeaderWithoutAvatarDropdown = {\n avatar?: React.ReactNode;\n avatarDropdown?: never;\n avatarLabel?: never;\n};\n\ntype HeaderWithAvatarDropdown = {\n avatar: React.ReactNode;\n avatarDropdown: Omit<\n DropdownProps,\n 'trigger' | 'interaction'\n >;\n avatarLabel: string;\n};\n\nexport type HeaderProps =\n HeaderBaseProps &\n (\n | HeaderWithoutAvatarDropdown\n | HeaderWithAvatarDropdown\n );\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return (\n value !== null &&\n value !== undefined\n );\n}\n\nconst Header: React.FC<HeaderProps> = ({\n logo,\n menu,\n avatar,\n avatarDropdown,\n avatarLabel,\n className = '',\n children,\n ...props\n}) => {\n const classes = classnames(\n 'header',\n className,\n {},\n );\n\n const resolvedMenu =\n hasContent(menu)\n ? menu\n : children;\n\n const hasAvatar =\n hasContent(avatar);\n\n return (\n <header\n className={classes}\n {...props}\n >\n {hasContent(logo) && (\n <div className=\"header__logo\">\n {logo}\n </div>\n )}\n\n {hasContent(resolvedMenu) && (\n <div className=\"header__menu\">\n {resolvedMenu}\n </div>\n )}\n\n {hasAvatar && (\n <div className=\"header__avatar\">\n {avatarDropdown ? (\n <Dropdown\n {...avatarDropdown}\n interaction=\"hover\"\n trigger={\n <button\n type=\"button\"\n className=\"header__avatar-trigger\"\n aria-label={\n avatarLabel\n }\n >\n {avatar}\n </button>\n }\n />\n ) : (\n avatar\n )}\n </div>\n )}\n </header>\n );\n};\n\nexport default Header;\n"]}
1
+ {"version":3,"sources":["../../../src/patterns/header/header.tsx"],"names":[],"mappings":";;;;;AAyCA,SAAS,WACP,KAAA,EAIA;AACA,EAAA,OACE,KAAA,KAAU,QACV,KAAA,KAAU,MAAA;AAEd;AAEA,MAAM,SAAgC,CAAC;AAAA,EACrC,IAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,QAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,MAAM,YAAA,GACJ,UAAA,CAAW,IAAI,CAAA,GACX,IAAA,GACA,QAAA;AAEN,EAAA,MAAM,SAAA,GACJ,WAAW,MAAM,CAAA;AAEnB,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACV,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,UAAA,CAAW,IAAI,CAAA,oBACd,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,QAGD,WAAW,YAAY,CAAA,wBACrB,KAAA,EAAA,EAAI,SAAA,EAAU,gBACZ,QAAA,EAAA,YAAA,EACH,CAAA;AAAA,QAGD,SAAA,oBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kBACZ,QAAA,EAAA,cAAA,mBACC,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACE,GAAG,cAAA;AAAA,YACJ,WAAA,EAAY,OAAA;AAAA,YACZ,OAAA,kBACE,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,SAAA,EAAU,wBAAA;AAAA,gBACV,YAAA,EACE,WAAA;AAAA,gBAEF,OAAA,EACE,aAAA;AAAA,gBAGD,QAAA,EAAA;AAAA;AAAA;AACH;AAAA,YAIJ,MAAA,EAEJ;AAAA;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"header.js","sourcesContent":["import React from 'react';\n\nimport './header.css';\nimport Dropdown, {\n type DropdownProps,\n} from '../../components/dropdown';\nimport { classnames } from '../../components/helpers/classnames';\n\ntype HeaderNativeProps =\n React.HTMLAttributes<HTMLElement>;\n\ntype HeaderBaseProps =\n HeaderNativeProps & {\n logo?: React.ReactNode;\n menu?: React.ReactNode;\n };\n\ntype HeaderWithoutAvatarDropdown = {\n avatar?: React.ReactNode;\n avatarDropdown?: never;\n avatarLabel?: never;\n avatarOnClick?: never;\n};\n\ntype HeaderWithAvatarDropdown = {\n avatar: React.ReactNode;\n avatarDropdown: Omit<\n DropdownProps,\n 'trigger' | 'interaction'\n >;\n avatarLabel: string;\n avatarOnClick?: React.MouseEventHandler<HTMLButtonElement>;\n};\n\nexport type HeaderProps =\n HeaderBaseProps &\n (\n | HeaderWithoutAvatarDropdown\n | HeaderWithAvatarDropdown\n );\n\nfunction hasContent(\n value: React.ReactNode,\n): value is Exclude<\n React.ReactNode,\n null | undefined\n> {\n return (\n value !== null &&\n value !== undefined\n );\n}\n\nconst Header: React.FC<HeaderProps> = ({\n logo,\n menu,\n avatar,\n avatarDropdown,\n avatarLabel,\n avatarOnClick,\n className = '',\n children,\n ...props\n}) => {\n const classes = classnames(\n 'header',\n className,\n {},\n );\n\n const resolvedMenu =\n hasContent(menu)\n ? menu\n : children;\n\n const hasAvatar =\n hasContent(avatar);\n\n return (\n <header\n className={classes}\n {...props}\n >\n {hasContent(logo) && (\n <div className=\"header__logo\">\n {logo}\n </div>\n )}\n\n {hasContent(resolvedMenu) && (\n <div className=\"header__menu\">\n {resolvedMenu}\n </div>\n )}\n\n {hasAvatar && (\n <div className=\"header__avatar\">\n {avatarDropdown ? (\n <Dropdown\n {...avatarDropdown}\n interaction=\"hover\"\n trigger={\n <button\n type=\"button\"\n className=\"header__avatar-trigger\"\n aria-label={\n avatarLabel\n }\n onClick={\n avatarOnClick\n }\n >\n {avatar}\n </button>\n }\n />\n ) : (\n avatar\n )}\n </div>\n )}\n </header>\n );\n};\n\nexport default Header;\n"]}
@@ -3,66 +3,99 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  require('./modal.css');
6
+ var Button = require('../../components/button');
6
7
  var classnames = require('../../components/helpers/classnames');
8
+ var Panel = require('../../components/panel');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var Button__default = /*#__PURE__*/_interopDefault(Button);
13
+ var Panel__default = /*#__PURE__*/_interopDefault(Panel);
7
14
 
8
15
  const Modal = ({
9
16
  open,
10
17
  onClose,
11
- ariaLabel,
18
+ heading,
19
+ description,
20
+ closeLabel,
12
21
  presentation = "dialog",
13
22
  size = "default",
14
23
  closeOnBackdrop = true,
15
24
  closeOnEscape = true,
16
25
  className = "",
17
26
  children,
27
+ onClick,
18
28
  ...props
19
29
  }) => {
30
+ const dialogRef = react.useRef(null);
31
+ const classes = classnames.classnames(
32
+ "modal",
33
+ className,
34
+ {
35
+ "modal--wide": size === "wide",
36
+ "modal--fullscreen": presentation === "fullscreen"
37
+ }
38
+ );
39
+ const panelLayout = presentation === "fullscreen" ? "transparent" : "card";
20
40
  react.useEffect(() => {
21
- if (!open || !closeOnEscape) {
41
+ const dialog = dialogRef.current;
42
+ if (!dialog) {
22
43
  return;
23
44
  }
24
- const handleKeyDown = (event) => {
25
- if (event.key === "Escape") {
26
- onClose();
45
+ if (open) {
46
+ if (!dialog.open) {
47
+ dialog.showModal();
27
48
  }
28
- };
29
- document.addEventListener("keydown", handleKeyDown);
30
- return () => {
31
- document.removeEventListener("keydown", handleKeyDown);
32
- };
33
- }, [open, closeOnEscape, onClose]);
34
- if (!open) {
35
- return null;
36
- }
37
- const classes = classnames.classnames("modal", className, {
38
- "modal--wide": size === "wide",
39
- "modal--fullscreen": presentation === "fullscreen"
40
- });
41
- const handleBackdropClick = () => {
42
- if (!closeOnBackdrop) {
49
+ return;
50
+ }
51
+ if (dialog.open) {
52
+ dialog.close();
53
+ }
54
+ }, [open]);
55
+ const handleCancel = (event) => {
56
+ event.preventDefault();
57
+ if (!closeOnEscape) {
58
+ return;
59
+ }
60
+ onClose();
61
+ };
62
+ const handleClick = (event) => {
63
+ onClick?.(event);
64
+ if (event.defaultPrevented || !closeOnBackdrop || event.target !== event.currentTarget) {
43
65
  return;
44
66
  }
45
67
  onClose();
46
68
  };
47
69
  return /* @__PURE__ */ jsxRuntime.jsx(
48
- "div",
70
+ "dialog",
49
71
  {
72
+ ...props,
73
+ ref: dialogRef,
50
74
  className: classes,
51
- onClick: handleBackdropClick,
52
- children: /* @__PURE__ */ jsxRuntime.jsx(
53
- "div",
54
- {
55
- className: "modal__content",
56
- role: "dialog",
57
- "aria-modal": "true",
58
- "aria-label": ariaLabel,
59
- onClick: (event) => {
60
- event.stopPropagation();
61
- },
62
- ...props,
63
- children
64
- }
65
- )
75
+ onCancel: handleCancel,
76
+ onClick: handleClick,
77
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "modal__surface", children: [
78
+ /* @__PURE__ */ jsxRuntime.jsx(
79
+ Panel__default.default,
80
+ {
81
+ layout: panelLayout,
82
+ heading,
83
+ description,
84
+ children
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsxRuntime.jsx(
88
+ Button__default.default,
89
+ {
90
+ type: "button",
91
+ mode: "toolbar",
92
+ icon: "close",
93
+ className: "modal__close",
94
+ "aria-label": closeLabel,
95
+ onClick: onClose
96
+ }
97
+ )
98
+ ] })
66
99
  }
67
100
  );
68
101
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":["useEffect","classnames","jsx"],"mappings":";;;;;;;AAeA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,aAAA,EAAe;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyB;AAC9C,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,aAAa,CAAA;AAElD,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,aAAa,CAAA;AAAA,IACvD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,aAAA,EAAe,OAAO,CAAC,CAAA;AAEjC,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAUC,qBAAA,CAAW,OAAA,EAAS,SAAA,EAAW;AAAA,IAC7C,eAAe,IAAA,KAAS,MAAA;AAAA,IACxB,qBAAqB,YAAA,KAAiB;AAAA,GACvC,CAAA;AAED,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACEC,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACX,OAAA,EAAS,mBAAA;AAAA,MAET,QAAA,kBAAAA,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,gBAAA;AAAA,UACV,IAAA,EAAK,QAAA;AAAA,UACL,YAAA,EAAW,MAAA;AAAA,UACX,YAAA,EAAY,SAAA;AAAA,UACZ,OAAA,EAAS,CAAC,KAAA,KAAU;AAClB,YAAA,KAAA,CAAM,eAAA,EAAgB;AAAA,UACxB,CAAA;AAAA,UACC,GAAG,KAAA;AAAA,UAEH;AAAA;AAAA;AACH;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.cjs","sourcesContent":["import React, { useEffect } from 'react';\nimport './modal.css';\nimport { classnames } from '../../components/helpers/classnames';\n\nexport interface ModalProps\n extends React.HTMLAttributes<HTMLDivElement> {\n open: boolean;\n onClose: () => void;\n ariaLabel: string;\n presentation?: 'dialog' | 'fullscreen';\n size?: 'default' | 'wide';\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n ariaLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n ...props\n}) => {\n useEffect(() => {\n if (!open || !closeOnEscape) {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [open, closeOnEscape, onClose]);\n\n if (!open) {\n return null;\n }\n\n const classes = classnames('modal', className, {\n 'modal--wide': size === 'wide',\n 'modal--fullscreen': presentation === 'fullscreen',\n });\n\n const handleBackdropClick = () => {\n if (!closeOnBackdrop) {\n return;\n }\n\n onClose();\n };\n\n return (\n <div\n className={classes}\n onClick={handleBackdropClick}\n >\n <div\n className=\"modal__content\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation();\n }}\n {...props}\n >\n {children}\n </div>\n </div>\n );\n};\n\nexport default Modal;"]}
1
+ {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":["useRef","classnames","useEffect","jsx","jsxs","Panel","Button"],"mappings":";;;;;;;;;;;;;;AA0CA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,SAAA,GACJA,aAA0B,IAAI,CAAA;AAEhC,EAAA,MAAM,OAAA,GAAUC,qBAAA;AAAA,IACd,OAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,eACE,IAAA,KAAS,MAAA;AAAA,MACX,qBACE,YAAA,KACA;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,WAAA,GACJ,YAAA,KAAiB,YAAA,GACb,aAAA,GACA,MAAA;AAEN,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,SACJ,SAAA,CAAU,OAAA;AAEZ,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAI,CAAC,OAAO,IAAA,EAAM;AAChB,QAAA,MAAA,CAAO,SAAA,EAAU;AAAA,MACnB;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAA,CAAO,KAAA,EAAM;AAAA,IACf;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,YAAA,GAAe,CACnB,KAAA,KAGG;AACH,IAAA,KAAA,CAAM,cAAA,EAAe;AAErB,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAClB,KAAA,KAGG;AACH,IAAA,OAAA,GAAU,KAAK,CAAA;AAEf,IAAA,IACE,MAAM,gBAAA,IACN,CAAC,mBACD,KAAA,CAAM,MAAA,KACJ,MAAM,aAAA,EACR;AACA,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACEC,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,GAAA,EAAK,SAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MAET,QAAA,kBAAAC,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,wBAAAD,cAAA;AAAA,UAACE,sBAAA;AAAA,UAAA;AAAA,YACC,MAAA,EAAQ,WAAA;AAAA,YACR,OAAA;AAAA,YACA,WAAA;AAAA,YAIC;AAAA;AAAA,SACH;AAAA,wBAEAF,cAAA;AAAA,UAACG,uBAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,SAAA;AAAA,YACL,IAAA,EAAK,OAAA;AAAA,YACL,SAAA,EAAU,cAAA;AAAA,YACV,YAAA,EAAY,UAAA;AAAA,YACZ,OAAA,EAAS;AAAA;AAAA;AACX,OAAA,EACF;AAAA;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.cjs","sourcesContent":["import React, {\n useEffect,\n useRef,\n} from 'react';\n\nimport './modal.css';\nimport Button from '../../components/button';\nimport { classnames } from '../../components/helpers/classnames';\nimport Panel from '../../components/panel';\n\ntype ModalNativeProps = Omit<\n React.DialogHTMLAttributes<HTMLDialogElement>,\n | 'children'\n | 'onCancel'\n | 'onClose'\n | 'open'\n>;\n\nexport interface ModalProps\n extends ModalNativeProps {\n open: boolean;\n onClose: () => void;\n\n heading?: React.ReactNode;\n description?: React.ReactNode;\n\n closeLabel: string;\n\n presentation?:\n | 'dialog'\n | 'fullscreen';\n\n size?:\n | 'default'\n | 'wide';\n\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n\n children?: React.ReactNode;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n heading,\n description,\n closeLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n onClick,\n ...props\n}) => {\n const dialogRef =\n useRef<HTMLDialogElement>(null);\n\n const classes = classnames(\n 'modal',\n className,\n {\n 'modal--wide':\n size === 'wide',\n 'modal--fullscreen':\n presentation ===\n 'fullscreen',\n },\n );\n\n const panelLayout =\n presentation === 'fullscreen'\n ? 'transparent'\n : 'card';\n\n useEffect(() => {\n const dialog =\n dialogRef.current;\n\n if (!dialog) {\n return;\n }\n\n if (open) {\n if (!dialog.open) {\n dialog.showModal();\n }\n\n return;\n }\n\n if (dialog.open) {\n dialog.close();\n }\n }, [open]);\n\n const handleCancel = (\n event: React.SyntheticEvent<\n HTMLDialogElement\n >,\n ) => {\n event.preventDefault();\n\n if (!closeOnEscape) {\n return;\n }\n\n onClose();\n };\n\n const handleClick = (\n event: React.MouseEvent<\n HTMLDialogElement\n >,\n ) => {\n onClick?.(event);\n\n if (\n event.defaultPrevented ||\n !closeOnBackdrop ||\n event.target !==\n event.currentTarget\n ) {\n return;\n }\n\n onClose();\n };\n\n return (\n <dialog\n {...props}\n ref={dialogRef}\n className={classes}\n onCancel={handleCancel}\n onClick={handleClick}\n >\n <div className=\"modal__surface\">\n <Panel\n layout={panelLayout}\n heading={heading}\n description={\n description\n }\n >\n {children}\n </Panel>\n\n <Button\n type=\"button\"\n mode=\"toolbar\"\n icon=\"close\"\n className=\"modal__close\"\n aria-label={closeLabel}\n onClick={onClose}\n />\n </div>\n </dialog>\n );\n};\n\nexport default Modal;\n"]}
@@ -2,7 +2,7 @@
2
2
  /* color */
3
3
  --modal-backdrop-bg: rgb(0 0 0 / 40%);
4
4
 
5
- background: var(--modal-backdrop-bg);
5
+ color: inherit;
6
6
 
7
7
  /* typography */
8
8
 
@@ -10,17 +10,36 @@
10
10
  --modal-padding: var(--size-grid-padding-horz);
11
11
  --modal-content-width: min(640px, 100%);
12
12
  --modal-content-width-wide: min(1120px, 100%);
13
- --modal-content-height-fullscreen: 100%;
13
+ --modal-close-offset: var(--padding-container);
14
+
15
+ width: 100%;
16
+ max-width: none;
17
+ height: 100%;
18
+ max-height: none;
19
+
20
+ margin: 0;
21
+ padding: var(--modal-padding);
14
22
 
15
- position: fixed;
16
- inset: 0;
17
- z-index: 1000;
23
+ border: 0;
18
24
 
19
25
  display: flex;
20
26
  align-items: center;
21
27
  justify-content: center;
22
28
 
23
- padding: var(--modal-padding);
29
+ /* border */
30
+
31
+ /* depth */
32
+
33
+ /* motion */
34
+ }
35
+
36
+ .modal::backdrop {
37
+ /* color */
38
+ background: var(--modal-backdrop-bg);
39
+
40
+ /* typography */
41
+
42
+ /* size */
24
43
 
25
44
  /* border */
26
45
 
@@ -29,14 +48,17 @@
29
48
  /* motion */
30
49
  }
31
50
 
32
- .modal__content {
51
+ .modal__surface {
33
52
  /* color */
34
53
 
35
54
  /* typography */
36
55
 
37
56
  /* size */
57
+ position: relative;
58
+
38
59
  width: var(--modal-content-width);
39
60
  max-height: 100%;
61
+
40
62
  overflow: auto;
41
63
 
42
64
  /* border */
@@ -46,34 +68,90 @@
46
68
  /* motion */
47
69
  }
48
70
 
49
- .modal--wide .modal__content {
71
+ .modal__close {
72
+ /* color */
73
+
74
+ /* typography */
75
+
76
+ /* size */
77
+ position: absolute;
78
+ top: var(--modal-close-offset);
79
+ right: var(--modal-close-offset);
80
+
81
+ /* border */
82
+
83
+ /* depth */
84
+
85
+ /* motion */
86
+ }
87
+
88
+ .modal--wide .modal__surface {
89
+ /* color */
90
+
91
+ /* typography */
92
+
50
93
  /* size */
51
94
  width: var(--modal-content-width-wide);
95
+
96
+ /* border */
97
+
98
+ /* depth */
99
+
100
+ /* motion */
52
101
  }
53
102
 
54
103
  .modal--fullscreen {
104
+ /* color */
105
+
106
+ /* typography */
107
+
55
108
  /* size */
56
- align-items: flex-start;
109
+ align-items: stretch;
57
110
  justify-content: stretch;
58
111
 
59
112
  padding: 0;
113
+
114
+ /* border */
115
+
116
+ /* depth */
117
+
118
+ /* motion */
60
119
  }
61
120
 
62
- .modal--fullscreen .modal__content {
121
+ .modal--fullscreen .modal__surface {
122
+ /* color */
123
+
124
+ /* typography */
125
+
63
126
  /* size */
64
127
  display: flex;
65
- align-items: flex-start;
66
- justify-content: flex-start;
128
+ align-items: stretch;
67
129
 
68
130
  width: 100%;
69
- height: var(--modal-content-height-fullscreen);
70
-
131
+ height: 100%;
71
132
  max-height: none;
133
+
134
+ overflow: auto;
135
+
136
+ /* border */
137
+
138
+ /* depth */
139
+
140
+ /* motion */
72
141
  }
73
142
 
74
- .modal--fullscreen .modal__content > * {
143
+ .modal--fullscreen .panel {
144
+ /* color */
145
+
146
+ /* typography */
147
+
75
148
  /* size */
76
149
  flex: 1;
77
- width: 100%;
78
150
  min-height: 100%;
151
+
152
+ /* border */
153
+
154
+ /* depth */
155
+
156
+ /* motion */
79
157
  }
@@ -1,13 +1,17 @@
1
1
  import React from 'react';
2
2
  import './modal.css';
3
- export interface ModalProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ type ModalNativeProps = Omit<React.DialogHTMLAttributes<HTMLDialogElement>, 'children' | 'onCancel' | 'onClose' | 'open'>;
4
+ export interface ModalProps extends ModalNativeProps {
4
5
  open: boolean;
5
6
  onClose: () => void;
6
- ariaLabel: string;
7
+ heading?: React.ReactNode;
8
+ description?: React.ReactNode;
9
+ closeLabel: string;
7
10
  presentation?: 'dialog' | 'fullscreen';
8
11
  size?: 'default' | 'wide';
9
12
  closeOnBackdrop?: boolean;
10
13
  closeOnEscape?: boolean;
14
+ children?: React.ReactNode;
11
15
  }
12
16
  declare const Modal: React.FC<ModalProps>;
13
17
  export default Modal;
@@ -1,66 +1,94 @@
1
- import { jsx } from 'react/jsx-runtime';
2
- import { useEffect } from 'react';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useRef, useEffect } from 'react';
3
3
  import './modal.css';
4
+ import Button from '../../components/button';
4
5
  import { classnames } from '../../components/helpers/classnames';
6
+ import Panel from '../../components/panel';
5
7
 
6
8
  const Modal = ({
7
9
  open,
8
10
  onClose,
9
- ariaLabel,
11
+ heading,
12
+ description,
13
+ closeLabel,
10
14
  presentation = "dialog",
11
15
  size = "default",
12
16
  closeOnBackdrop = true,
13
17
  closeOnEscape = true,
14
18
  className = "",
15
19
  children,
20
+ onClick,
16
21
  ...props
17
22
  }) => {
23
+ const dialogRef = useRef(null);
24
+ const classes = classnames(
25
+ "modal",
26
+ className,
27
+ {
28
+ "modal--wide": size === "wide",
29
+ "modal--fullscreen": presentation === "fullscreen"
30
+ }
31
+ );
32
+ const panelLayout = presentation === "fullscreen" ? "transparent" : "card";
18
33
  useEffect(() => {
19
- if (!open || !closeOnEscape) {
34
+ const dialog = dialogRef.current;
35
+ if (!dialog) {
20
36
  return;
21
37
  }
22
- const handleKeyDown = (event) => {
23
- if (event.key === "Escape") {
24
- onClose();
38
+ if (open) {
39
+ if (!dialog.open) {
40
+ dialog.showModal();
25
41
  }
26
- };
27
- document.addEventListener("keydown", handleKeyDown);
28
- return () => {
29
- document.removeEventListener("keydown", handleKeyDown);
30
- };
31
- }, [open, closeOnEscape, onClose]);
32
- if (!open) {
33
- return null;
34
- }
35
- const classes = classnames("modal", className, {
36
- "modal--wide": size === "wide",
37
- "modal--fullscreen": presentation === "fullscreen"
38
- });
39
- const handleBackdropClick = () => {
40
- if (!closeOnBackdrop) {
42
+ return;
43
+ }
44
+ if (dialog.open) {
45
+ dialog.close();
46
+ }
47
+ }, [open]);
48
+ const handleCancel = (event) => {
49
+ event.preventDefault();
50
+ if (!closeOnEscape) {
51
+ return;
52
+ }
53
+ onClose();
54
+ };
55
+ const handleClick = (event) => {
56
+ onClick?.(event);
57
+ if (event.defaultPrevented || !closeOnBackdrop || event.target !== event.currentTarget) {
41
58
  return;
42
59
  }
43
60
  onClose();
44
61
  };
45
62
  return /* @__PURE__ */ jsx(
46
- "div",
63
+ "dialog",
47
64
  {
65
+ ...props,
66
+ ref: dialogRef,
48
67
  className: classes,
49
- onClick: handleBackdropClick,
50
- children: /* @__PURE__ */ jsx(
51
- "div",
52
- {
53
- className: "modal__content",
54
- role: "dialog",
55
- "aria-modal": "true",
56
- "aria-label": ariaLabel,
57
- onClick: (event) => {
58
- event.stopPropagation();
59
- },
60
- ...props,
61
- children
62
- }
63
- )
68
+ onCancel: handleCancel,
69
+ onClick: handleClick,
70
+ children: /* @__PURE__ */ jsxs("div", { className: "modal__surface", children: [
71
+ /* @__PURE__ */ jsx(
72
+ Panel,
73
+ {
74
+ layout: panelLayout,
75
+ heading,
76
+ description,
77
+ children
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsx(
81
+ Button,
82
+ {
83
+ type: "button",
84
+ mode: "toolbar",
85
+ icon: "close",
86
+ className: "modal__close",
87
+ "aria-label": closeLabel,
88
+ onClick: onClose
89
+ }
90
+ )
91
+ ] })
64
92
  }
65
93
  );
66
94
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":[],"mappings":";;;;;AAeA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,aAAA,EAAe;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyB;AAC9C,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,aAAa,CAAA;AAElD,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,aAAa,CAAA;AAAA,IACvD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,aAAA,EAAe,OAAO,CAAC,CAAA;AAEjC,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,UAAA,CAAW,OAAA,EAAS,SAAA,EAAW;AAAA,IAC7C,eAAe,IAAA,KAAS,MAAA;AAAA,IACxB,qBAAqB,YAAA,KAAiB;AAAA,GACvC,CAAA;AAED,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACX,OAAA,EAAS,mBAAA;AAAA,MAET,QAAA,kBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,gBAAA;AAAA,UACV,IAAA,EAAK,QAAA;AAAA,UACL,YAAA,EAAW,MAAA;AAAA,UACX,YAAA,EAAY,SAAA;AAAA,UACZ,OAAA,EAAS,CAAC,KAAA,KAAU;AAClB,YAAA,KAAA,CAAM,eAAA,EAAgB;AAAA,UACxB,CAAA;AAAA,UACC,GAAG,KAAA;AAAA,UAEH;AAAA;AAAA;AACH;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.js","sourcesContent":["import React, { useEffect } from 'react';\nimport './modal.css';\nimport { classnames } from '../../components/helpers/classnames';\n\nexport interface ModalProps\n extends React.HTMLAttributes<HTMLDivElement> {\n open: boolean;\n onClose: () => void;\n ariaLabel: string;\n presentation?: 'dialog' | 'fullscreen';\n size?: 'default' | 'wide';\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n ariaLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n ...props\n}) => {\n useEffect(() => {\n if (!open || !closeOnEscape) {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [open, closeOnEscape, onClose]);\n\n if (!open) {\n return null;\n }\n\n const classes = classnames('modal', className, {\n 'modal--wide': size === 'wide',\n 'modal--fullscreen': presentation === 'fullscreen',\n });\n\n const handleBackdropClick = () => {\n if (!closeOnBackdrop) {\n return;\n }\n\n onClose();\n };\n\n return (\n <div\n className={classes}\n onClick={handleBackdropClick}\n >\n <div\n className=\"modal__content\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation();\n }}\n {...props}\n >\n {children}\n </div>\n </div>\n );\n};\n\nexport default Modal;"]}
1
+ {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":[],"mappings":";;;;;;;AA0CA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,SAAA,GACJ,OAA0B,IAAI,CAAA;AAEhC,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,OAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,eACE,IAAA,KAAS,MAAA;AAAA,MACX,qBACE,YAAA,KACA;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,WAAA,GACJ,YAAA,KAAiB,YAAA,GACb,aAAA,GACA,MAAA;AAEN,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,SACJ,SAAA,CAAU,OAAA;AAEZ,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAI,CAAC,OAAO,IAAA,EAAM;AAChB,QAAA,MAAA,CAAO,SAAA,EAAU;AAAA,MACnB;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAA,CAAO,KAAA,EAAM;AAAA,IACf;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,YAAA,GAAe,CACnB,KAAA,KAGG;AACH,IAAA,KAAA,CAAM,cAAA,EAAe;AAErB,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAClB,KAAA,KAGG;AACH,IAAA,OAAA,GAAU,KAAK,CAAA;AAEf,IAAA,IACE,MAAM,gBAAA,IACN,CAAC,mBACD,KAAA,CAAM,MAAA,KACJ,MAAM,aAAA,EACR;AACA,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,GAAA,EAAK,SAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MAET,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,MAAA,EAAQ,WAAA;AAAA,YACR,OAAA;AAAA,YACA,WAAA;AAAA,YAIC;AAAA;AAAA,SACH;AAAA,wBAEA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,SAAA;AAAA,YACL,IAAA,EAAK,OAAA;AAAA,YACL,SAAA,EAAU,cAAA;AAAA,YACV,YAAA,EAAY,UAAA;AAAA,YACZ,OAAA,EAAS;AAAA;AAAA;AACX,OAAA,EACF;AAAA;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.js","sourcesContent":["import React, {\n useEffect,\n useRef,\n} from 'react';\n\nimport './modal.css';\nimport Button from '../../components/button';\nimport { classnames } from '../../components/helpers/classnames';\nimport Panel from '../../components/panel';\n\ntype ModalNativeProps = Omit<\n React.DialogHTMLAttributes<HTMLDialogElement>,\n | 'children'\n | 'onCancel'\n | 'onClose'\n | 'open'\n>;\n\nexport interface ModalProps\n extends ModalNativeProps {\n open: boolean;\n onClose: () => void;\n\n heading?: React.ReactNode;\n description?: React.ReactNode;\n\n closeLabel: string;\n\n presentation?:\n | 'dialog'\n | 'fullscreen';\n\n size?:\n | 'default'\n | 'wide';\n\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n\n children?: React.ReactNode;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n heading,\n description,\n closeLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n onClick,\n ...props\n}) => {\n const dialogRef =\n useRef<HTMLDialogElement>(null);\n\n const classes = classnames(\n 'modal',\n className,\n {\n 'modal--wide':\n size === 'wide',\n 'modal--fullscreen':\n presentation ===\n 'fullscreen',\n },\n );\n\n const panelLayout =\n presentation === 'fullscreen'\n ? 'transparent'\n : 'card';\n\n useEffect(() => {\n const dialog =\n dialogRef.current;\n\n if (!dialog) {\n return;\n }\n\n if (open) {\n if (!dialog.open) {\n dialog.showModal();\n }\n\n return;\n }\n\n if (dialog.open) {\n dialog.close();\n }\n }, [open]);\n\n const handleCancel = (\n event: React.SyntheticEvent<\n HTMLDialogElement\n >,\n ) => {\n event.preventDefault();\n\n if (!closeOnEscape) {\n return;\n }\n\n onClose();\n };\n\n const handleClick = (\n event: React.MouseEvent<\n HTMLDialogElement\n >,\n ) => {\n onClick?.(event);\n\n if (\n event.defaultPrevented ||\n !closeOnBackdrop ||\n event.target !==\n event.currentTarget\n ) {\n return;\n }\n\n onClose();\n };\n\n return (\n <dialog\n {...props}\n ref={dialogRef}\n className={classes}\n onCancel={handleCancel}\n onClick={handleClick}\n >\n <div className=\"modal__surface\">\n <Panel\n layout={panelLayout}\n heading={heading}\n description={\n description\n }\n >\n {children}\n </Panel>\n\n <Button\n type=\"button\"\n mode=\"toolbar\"\n icon=\"close\"\n className=\"modal__close\"\n aria-label={closeLabel}\n onClick={onClose}\n />\n </div>\n </dialog>\n );\n};\n\nexport default Modal;\n"]}