@doist/reactist 24.1.5-beta → 25.0.0-beta

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.
Files changed (80) hide show
  1. package/dist/reactist.cjs.development.js +227 -177
  2. package/dist/reactist.cjs.development.js.map +1 -1
  3. package/dist/reactist.cjs.production.min.js +1 -1
  4. package/dist/reactist.cjs.production.min.js.map +1 -1
  5. package/es/badge/badge.js.map +1 -1
  6. package/es/badge/badge.module.css.js +1 -1
  7. package/es/box/box.js +94 -19
  8. package/es/box/box.js.map +1 -1
  9. package/es/button/button.js +93 -18
  10. package/es/button/button.js.map +1 -1
  11. package/es/button/button.module.css.js +4 -0
  12. package/es/button/button.module.css.js.map +1 -0
  13. package/es/index.js +2 -3
  14. package/es/index.js.map +1 -1
  15. package/es/loading/loading.js.map +1 -1
  16. package/es/menu/menu.js.map +1 -1
  17. package/es/modal/modal.js +2 -2
  18. package/es/modal/modal.js.map +1 -1
  19. package/es/password-field/password-field.js +2 -2
  20. package/es/password-field/password-field.js.map +1 -1
  21. package/es/toast/static-toast.js +2 -2
  22. package/es/toast/static-toast.js.map +1 -1
  23. package/es/utils/polymorphism.js.map +1 -1
  24. package/lib/badge/badge.d.ts +1 -1
  25. package/lib/badge/badge.js.map +1 -1
  26. package/lib/badge/badge.module.css.js +1 -1
  27. package/lib/box/box.d.ts +2 -1
  28. package/lib/box/box.js +1 -1
  29. package/lib/box/box.js.map +1 -1
  30. package/lib/button/button.d.ts +123 -11
  31. package/lib/button/button.js +1 -1
  32. package/lib/button/button.js.map +1 -1
  33. package/lib/button/button.module.css.js +2 -0
  34. package/lib/button/button.module.css.js.map +1 -0
  35. package/lib/index.d.ts +0 -1
  36. package/lib/index.js +1 -1
  37. package/lib/loading/loading.d.ts +2 -2
  38. package/lib/loading/loading.js.map +1 -1
  39. package/lib/menu/menu.d.ts +1 -2
  40. package/lib/menu/menu.js.map +1 -1
  41. package/lib/modal/modal.d.ts +5 -8
  42. package/lib/modal/modal.js +1 -1
  43. package/lib/modal/modal.js.map +1 -1
  44. package/lib/password-field/password-field.js +1 -1
  45. package/lib/password-field/password-field.js.map +1 -1
  46. package/lib/toast/static-toast.js +1 -1
  47. package/lib/toast/static-toast.js.map +1 -1
  48. package/lib/utils/common-types.d.ts +19 -0
  49. package/lib/utils/polymorphism.d.ts +1 -19
  50. package/lib/utils/polymorphism.js.map +1 -1
  51. package/package.json +1 -1
  52. package/styles/alert.css +2 -2
  53. package/styles/badge.css +1 -1
  54. package/styles/badge.module.css.css +1 -1
  55. package/styles/{base-button.css → button.css} +2 -2
  56. package/styles/button.module.css.css +1 -0
  57. package/styles/modal.css +2 -2
  58. package/styles/password-field.css +2 -2
  59. package/styles/reactist.css +2 -2
  60. package/styles/static-toast.css +2 -2
  61. package/styles/use-toasts.css +2 -2
  62. package/es/base-button/base-button.js +0 -75
  63. package/es/base-button/base-button.js.map +0 -1
  64. package/es/base-button/base-button.module.css.js +0 -4
  65. package/es/base-button/base-button.module.css.js.map +0 -1
  66. package/es/button-link/button-link.js +0 -38
  67. package/es/button-link/button-link.js.map +0 -1
  68. package/lib/base-button/base-button.d.ts +0 -80
  69. package/lib/base-button/base-button.js +0 -2
  70. package/lib/base-button/base-button.js.map +0 -1
  71. package/lib/base-button/base-button.module.css.js +0 -2
  72. package/lib/base-button/base-button.module.css.js.map +0 -1
  73. package/lib/base-button/index.d.ts +0 -1
  74. package/lib/button-link/button-link-story-wrapper.d.ts +0 -7
  75. package/lib/button-link/button-link.d.ts +0 -13
  76. package/lib/button-link/button-link.js +0 -2
  77. package/lib/button-link/button-link.js.map +0 -1
  78. package/lib/button-link/button-link.test.d.ts +0 -1
  79. package/lib/button-link/index.d.ts +0 -1
  80. package/styles/base-button.module.css.css +0 -1
package/lib/index.d.ts CHANGED
@@ -15,7 +15,6 @@ export * from './heading';
15
15
  export * from './text';
16
16
  export * from './prose';
17
17
  export * from './button';
18
- export * from './button-link';
19
18
  export * from './text-link';
20
19
  export * from './checkbox-field';
21
20
  export * from './password-field';
package/lib/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./box/box.js"),r=require("./columns/columns.js"),t=require("./divider/divider.js"),o=require("./inline/inline.js"),s=require("./stack/stack.js"),i=require("./hidden/hidden.js"),a=require("./hidden-visually/hidden-visually.js"),n=require("./tooltip/tooltip.js"),d=require("./button/button.js"),u=require("./alert/alert.js"),p=require("./banner/banner.js"),x=require("./loading/loading.js"),l=require("./notice/notice.js"),c=require("./text/text.js"),j=require("./toast/static-toast.js"),q=require("./toast/use-toasts.js"),b=require("./heading/heading.js"),T=require("./prose/prose.js"),M=require("./button-link/button-link.js"),m=require("./text-link/text-link.js"),k=require("./checkbox-field/checkbox-field.js"),f=require("./text-field/text-field.js"),S=require("./password-field/password-field.js"),g=require("./select-field/select-field.js"),B=require("./switch-field/switch-field.js"),h=require("./text-area/text-area.js"),P=require("./avatar/avatar.js"),v=require("./badge/badge.js"),C=require("./modal/modal.js"),y=require("./tabs/tabs.js"),w=require("./menu/menu.js"),F=require("./components/deprecated-button/index.js"),L=require("./components/deprecated-dropdown/index.js"),A=require("./components/color-picker/color-picker.js"),D=require("./components/color-picker/index.js"),H=require("./components/keyboard-shortcut/index.js"),O=require("./components/key-capturer/key-capturer.js"),I=require("./components/key-capturer/index.js"),E=require("./components/progress-bar/index.js"),K=require("./components/time/index.js"),R=require("./components/deprecated-input/index.js"),_=require("./components/deprecated-select/index.js");exports.Box=e.Box,exports.Column=r.Column,exports.Columns=r.Columns,exports.Divider=t.Divider,exports.Inline=o.Inline,exports.Stack=s.Stack,exports.Hidden=i.Hidden,exports.HiddenVisually=a.HiddenVisually,exports.Tooltip=n.Tooltip,exports.Button=d.Button,exports.Alert=u.Alert,exports.Banner=p.Banner,exports.Loading=x.Loading,exports.Notice=l.Notice,exports.Text=c.Text,exports.StaticToast=j.StaticToast,exports.Toast=q.Toast,exports.ToastsProvider=q.ToastsProvider,exports.useToasts=q.useToasts,exports.Heading=b.Heading,exports.Prose=T.Prose,exports.ButtonLink=M.ButtonLink,exports.TextLink=m.TextLink,exports.CheckboxField=k.CheckboxField,exports.TextField=f.TextField,exports.PasswordField=S.PasswordField,exports.SelectField=g.SelectField,exports.SwitchField=B.SwitchField,exports.TextArea=h.TextArea,exports.Avatar=P.Avatar,exports.Badge=v.Badge,exports.Modal=C.Modal,exports.ModalActions=C.ModalActions,exports.ModalBody=C.ModalBody,exports.ModalCloseButton=C.ModalCloseButton,exports.ModalFooter=C.ModalFooter,exports.ModalHeader=C.ModalHeader,exports.Tab=y.Tab,exports.TabAwareSlot=y.TabAwareSlot,exports.TabList=y.TabList,exports.TabPanel=y.TabPanel,exports.Tabs=y.Tabs,exports.ContextMenuTrigger=w.ContextMenuTrigger,exports.Menu=w.Menu,exports.MenuButton=w.MenuButton,exports.MenuGroup=w.MenuGroup,exports.MenuItem=w.MenuItem,exports.MenuList=w.MenuList,exports.SubMenu=w.SubMenu,exports.DeprecatedButton=F.default,exports.DeprecatedDropdown=L.default,exports.COLORS=A.COLORS,exports.ColorPicker=D.default,exports.KeyboardShortcut=H.default,exports.SUPPORTED_KEYS=O.SUPPORTED_KEYS,exports.KeyCapturer=I.default,exports.ProgressBar=E.default,exports.Time=K.default,exports.DeprecatedInput=R.default,exports.DeprecatedSelect=_.default;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("./box/box.js"),r=require("./columns/columns.js"),t=require("./divider/divider.js"),o=require("./inline/inline.js"),s=require("./stack/stack.js"),i=require("./hidden/hidden.js"),a=require("./hidden-visually/hidden-visually.js"),n=require("./tooltip/tooltip.js"),d=require("./button/button.js"),u=require("./alert/alert.js"),p=require("./banner/banner.js"),x=require("./loading/loading.js"),l=require("./notice/notice.js"),c=require("./text/text.js"),j=require("./toast/static-toast.js"),q=require("./toast/use-toasts.js"),T=require("./heading/heading.js"),b=require("./prose/prose.js"),m=require("./text-link/text-link.js"),M=require("./checkbox-field/checkbox-field.js"),f=require("./text-field/text-field.js"),g=require("./password-field/password-field.js"),k=require("./select-field/select-field.js"),B=require("./switch-field/switch-field.js"),S=require("./text-area/text-area.js"),h=require("./avatar/avatar.js"),C=require("./badge/badge.js"),P=require("./modal/modal.js"),v=require("./tabs/tabs.js"),y=require("./menu/menu.js"),w=require("./components/deprecated-button/index.js"),F=require("./components/deprecated-dropdown/index.js"),A=require("./components/color-picker/color-picker.js"),L=require("./components/color-picker/index.js"),D=require("./components/keyboard-shortcut/index.js"),H=require("./components/key-capturer/key-capturer.js"),I=require("./components/key-capturer/index.js"),O=require("./components/progress-bar/index.js"),E=require("./components/time/index.js"),K=require("./components/deprecated-input/index.js"),N=require("./components/deprecated-select/index.js");exports.Box=e.Box,exports.getBoxClassNames=e.getBoxClassNames,exports.Column=r.Column,exports.Columns=r.Columns,exports.Divider=t.Divider,exports.Inline=o.Inline,exports.Stack=s.Stack,exports.Hidden=i.Hidden,exports.HiddenVisually=a.HiddenVisually,exports.Tooltip=n.Tooltip,exports.Button=d.Button,exports.IconButton=d.IconButton,exports.Alert=u.Alert,exports.Banner=p.Banner,exports.Loading=x.Loading,exports.Notice=l.Notice,exports.Text=c.Text,exports.StaticToast=j.StaticToast,exports.Toast=q.Toast,exports.ToastsProvider=q.ToastsProvider,exports.useToasts=q.useToasts,exports.Heading=T.Heading,exports.Prose=b.Prose,exports.TextLink=m.TextLink,exports.CheckboxField=M.CheckboxField,exports.TextField=f.TextField,exports.PasswordField=g.PasswordField,exports.SelectField=k.SelectField,exports.SwitchField=B.SwitchField,exports.TextArea=S.TextArea,exports.Avatar=h.Avatar,exports.Badge=C.Badge,exports.Modal=P.Modal,exports.ModalActions=P.ModalActions,exports.ModalBody=P.ModalBody,exports.ModalCloseButton=P.ModalCloseButton,exports.ModalFooter=P.ModalFooter,exports.ModalHeader=P.ModalHeader,exports.Tab=v.Tab,exports.TabAwareSlot=v.TabAwareSlot,exports.TabList=v.TabList,exports.TabPanel=v.TabPanel,exports.Tabs=v.Tabs,exports.ContextMenuTrigger=y.ContextMenuTrigger,exports.Menu=y.Menu,exports.MenuButton=y.MenuButton,exports.MenuGroup=y.MenuGroup,exports.MenuItem=y.MenuItem,exports.MenuList=y.MenuList,exports.SubMenu=y.SubMenu,exports.DeprecatedButton=w.default,exports.DeprecatedDropdown=F.default,exports.COLORS=A.COLORS,exports.ColorPicker=L.default,exports.KeyboardShortcut=D.default,exports.SUPPORTED_KEYS=H.SUPPORTED_KEYS,exports.KeyCapturer=I.default,exports.ProgressBar=O.default,exports.Time=E.default,exports.DeprecatedInput=K.default,exports.DeprecatedSelect=N.default;
2
2
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
- /// <reference types="react" />
1
+ import * as React from 'react';
2
2
  declare type Size = 'xsmall' | 'small' | 'medium' | 'large';
3
- declare type NativeProps = Omit<JSX.IntrinsicElements['div'], 'className' | 'aria-describedby' | 'aria-label' | 'aria-labelledby' | 'role' | 'size'>;
3
+ declare type NativeProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'className' | 'aria-describedby' | 'aria-label' | 'aria-labelledby' | 'role' | 'size'>;
4
4
  declare type LoadingProps = NativeProps & {
5
5
  /**
6
6
  * The size of the loading spinner.
@@ -1 +1 @@
1
- {"version":3,"file":"loading.js","sources":["../../src/loading/loading.tsx"],"sourcesContent":["import * as React from 'react'\nimport { Box } from '../box'\nimport { Spinner } from '../spinner'\n\ntype Size = 'xsmall' | 'small' | 'medium' | 'large'\n\ntype NativeProps = Omit<\n JSX.IntrinsicElements['div'],\n 'className' | 'aria-describedby' | 'aria-label' | 'aria-labelledby' | 'role' | 'size'\n>\n\ntype LoadingProps = NativeProps & {\n /**\n * The size of the loading spinner.\n * @default 'small'\n */\n size?: Size\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n /** Identifies the element (or elements) that describes the loading component for assistive technologies. */\n 'aria-describedby'?: string\n} & (\n | {\n /** Defines a string value that labels the current loading component for assistive technologies. */\n 'aria-label': string\n 'aria-labelledby'?: never\n }\n | {\n /** Identifies the element (or elements) that labels the current loading component for assistive technologies. */\n 'aria-labelledby': string\n 'aria-label'?: never\n }\n )\n\nconst sizeMapping: Record<Size, number> = {\n xsmall: 16,\n small: 24,\n medium: 36,\n large: 48,\n}\n\nfunction Loading({ size = 'small', exceptionallySetClassName, ...props }: LoadingProps) {\n const numericSize = sizeMapping[size] ?? sizeMapping.small\n const ariaLabel = props['aria-label']\n ? props['aria-label']\n : !props['aria-labelledby']\n ? 'Loading…'\n : undefined\n\n return (\n <Box\n {...props}\n aria-label={ariaLabel}\n className={exceptionallySetClassName}\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n role=\"progressbar\"\n >\n <Spinner size={numericSize} aria-hidden />\n </Box>\n )\n}\n\nexport { Loading }\nexport type { LoadingProps }\n"],"names":["sizeMapping","xsmall","small","medium","large","size","exceptionallySetClassName","props","numericSize","ariaLabel","undefined","React","Box","className","display","alignItems","justifyContent","role","Spinner"],"mappings":"4PAoCMA,EAAoC,CACtCC,OAAQ,GACRC,MAAO,GACPC,OAAQ,GACRC,MAAO,oBAGX,sBAAiBC,KAAEA,EAAO,QAATC,0BAAkBA,KAA8BC,iCAC7D,MAAMC,WAAcR,EAAYK,MAASL,EAAYE,MAC/CO,EAAYF,EAAM,cAClBA,EAAM,cACLA,EAAM,wBAEPG,EADA,WAGN,OACIC,gBAACC,yCACOL,oBACQE,EACZI,UAAWP,EACXQ,QAAQ,OACRC,WAAW,SACXC,eAAe,SACfC,KAAK,gBAELN,gBAACO,WAAQb,KAAMG"}
1
+ {"version":3,"file":"loading.js","sources":["../../src/loading/loading.tsx"],"sourcesContent":["import * as React from 'react'\nimport { Box } from '../box'\nimport { Spinner } from '../spinner'\n\ntype Size = 'xsmall' | 'small' | 'medium' | 'large'\n\ntype NativeProps = Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'className' | 'aria-describedby' | 'aria-label' | 'aria-labelledby' | 'role' | 'size'\n>\n\ntype LoadingProps = NativeProps & {\n /**\n * The size of the loading spinner.\n * @default 'small'\n */\n size?: Size\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n /** Identifies the element (or elements) that describes the loading component for assistive technologies. */\n 'aria-describedby'?: string\n} & (\n | {\n /** Defines a string value that labels the current loading component for assistive technologies. */\n 'aria-label': string\n 'aria-labelledby'?: never\n }\n | {\n /** Identifies the element (or elements) that labels the current loading component for assistive technologies. */\n 'aria-labelledby': string\n 'aria-label'?: never\n }\n )\n\nconst sizeMapping: Record<Size, number> = {\n xsmall: 16,\n small: 24,\n medium: 36,\n large: 48,\n}\n\nfunction Loading({ size = 'small', exceptionallySetClassName, ...props }: LoadingProps) {\n const numericSize = sizeMapping[size] ?? sizeMapping.small\n const ariaLabel = props['aria-label']\n ? props['aria-label']\n : !props['aria-labelledby']\n ? 'Loading…'\n : undefined\n\n return (\n <Box\n {...props}\n aria-label={ariaLabel}\n className={exceptionallySetClassName}\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n role=\"progressbar\"\n >\n <Spinner size={numericSize} aria-hidden />\n </Box>\n )\n}\n\nexport { Loading }\nexport type { LoadingProps }\n"],"names":["sizeMapping","xsmall","small","medium","large","size","exceptionallySetClassName","props","numericSize","ariaLabel","undefined","React","Box","className","display","alignItems","justifyContent","role","Spinner"],"mappings":"4PAoCMA,EAAoC,CACtCC,OAAQ,GACRC,MAAO,GACPC,OAAQ,GACRC,MAAO,oBAGX,sBAAiBC,KAAEA,EAAO,QAATC,0BAAkBA,KAA8BC,iCAC7D,MAAMC,WAAcR,EAAYK,MAASL,EAAYE,MAC/CO,EAAYF,EAAM,cAClBA,EAAM,cACLA,EAAM,wBAEPG,EADA,WAGN,OACIC,gBAACC,yCACOL,oBACQE,EACZI,UAAWP,EACXQ,QAAQ,OACRC,WAAW,SACXC,eAAe,SACfC,KAAK,gBAELN,gBAACO,WAAQb,KAAMG"}
@@ -1,7 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { MenuStoreProps, MenuProps as AriakitMenuProps, MenuButtonProps as AriakitMenuButtonProps } from '@ariakit/react';
3
3
  import './menu.less';
4
- declare type NativeProps<E extends HTMLElement> = React.DetailedHTMLProps<React.HTMLAttributes<E>, E>;
5
4
  declare type MenuProps = Omit<MenuStoreProps, 'visible'> & {
6
5
  /**
7
6
  * The `Menu` must contain a `MenuList` that defines the menu options. It must also contain a
@@ -111,7 +110,7 @@ declare type SubMenuProps = Pick<MenuProps, 'children' | 'onItemSelect'>;
111
110
  * opening a sub-menu with the menu items list below it.
112
111
  */
113
112
  declare const SubMenu: React.ForwardRefExoticComponent<SubMenuProps & React.RefAttributes<HTMLDivElement>>;
114
- declare type MenuGroupProps = Omit<NativeProps<HTMLDivElement>, 'className'> & {
113
+ declare type MenuGroupProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'className'> & {
115
114
  /**
116
115
  * A label to be shown visually and also used to semantically label the group.
117
116
  */
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","sources":["../../src/menu/menu.tsx"],"sourcesContent":["import * as React from 'react'\nimport classNames from 'classnames'\n\nimport { polymorphicComponent } from '../utils/polymorphism'\n\n//\n// Reactist menu is a thin wrapper around Ariakit's menu components. This may or may not be\n// temporary. Our goal is to make it transparent for the users of Reactist of this implementation\n// detail. We may change in the future the external lib we use, or even implement it all internally,\n// as long as we keep the same outer interface as intact as possible.\n//\n// Around the heavy lifting of the external lib we just add some features to better integrate the\n// menu to Reactist's more opinionated approach (e.g. using our button with its custom variants and\n// other features, easily show keyboard shortcuts in menu items, etc.)\n//\nimport {\n Portal,\n MenuStore,\n MenuStoreProps,\n useMenuStore,\n MenuProps as AriakitMenuProps,\n Menu as AriakitMenu,\n MenuGroup as AriakitMenuGroup,\n MenuItem as AriakitMenuItem,\n MenuButton as AriakitMenuButton,\n MenuButtonProps as AriakitMenuButtonProps,\n} from '@ariakit/react'\n\nimport './menu.less'\n\ntype NativeProps<E extends HTMLElement> = React.DetailedHTMLProps<React.HTMLAttributes<E>, E>\n\ntype MenuContextState = {\n menuStore: MenuStore\n handleItemSelect?: (value: string | null | undefined) => void\n getAnchorRect: (() => { x: number; y: number }) | null\n setAnchorRect: (rect: { x: number; y: number } | null) => void\n}\n\nconst MenuContext = React.createContext<MenuContextState>(\n // Ariakit gives us no means to obtain a valid initial/default value of type MenuStateReturn\n // (it is normally obtained by calling useMenuState but we can't call hooks outside components).\n // This is however of little consequence since this value is only used if some of the components\n // are used outside Menu, something that should not happen and we do not support.\n // @ts-expect-error\n {},\n)\n\n//\n// Menu\n//\n\ntype MenuProps = Omit<MenuStoreProps, 'visible'> & {\n /**\n * The `Menu` must contain a `MenuList` that defines the menu options. It must also contain a\n * `MenuButton` that triggers the menu to be opened or closed.\n */\n children: React.ReactNode\n\n /**\n * An optional callback that will be called back whenever a menu item is selected. It receives\n * the `value` of the selected `MenuItem`.\n *\n * If you pass down this callback, it is recommended that you properly memoize it so it does not\n * change on every render.\n */\n onItemSelect?: (value: string | null | undefined) => void\n}\n\n/**\n * Wrapper component to control a menu. It does not render anything, only providing the state\n * management for the menu components inside it.\n */\nfunction Menu({ children, onItemSelect, ...props }: MenuProps) {\n const [anchorRect, setAnchorRect] = React.useState<{ x: number; y: number } | null>(null)\n const getAnchorRect = React.useMemo(() => (anchorRect ? () => anchorRect : null), [anchorRect])\n const menuStore = useMenuStore({ focusLoop: true, ...props })\n\n const value: MenuContextState = React.useMemo(\n () => ({ menuStore, handleItemSelect: onItemSelect, getAnchorRect, setAnchorRect }),\n [menuStore, onItemSelect, getAnchorRect, setAnchorRect],\n )\n\n return <MenuContext.Provider value={value}>{children}</MenuContext.Provider>\n}\n\n//\n// MenuButton\n//\n\ntype MenuButtonProps = Omit<AriakitMenuButtonProps, 'store' | 'className' | 'as'>\n\n/**\n * A button to toggle a dropdown menu open or closed.\n */\nconst MenuButton = polymorphicComponent<'button', MenuButtonProps>(function MenuButton(\n { exceptionallySetClassName, ...props },\n ref,\n) {\n const { menuStore } = React.useContext(MenuContext)\n return (\n <AriakitMenuButton\n {...props}\n store={menuStore}\n ref={ref}\n className={classNames('reactist_menubutton', exceptionallySetClassName)}\n />\n )\n})\n\n//\n// ContextMenuTrigger\n//\nconst ContextMenuTrigger = polymorphicComponent<'div', unknown>(function ContextMenuTrigger(\n { as: component = 'div', ...props },\n ref,\n) {\n const { setAnchorRect, menuStore } = React.useContext(MenuContext)\n\n const handleContextMenu = React.useCallback(\n function handleContextMenu(event: React.MouseEvent) {\n event.preventDefault()\n setAnchorRect({ x: event.clientX, y: event.clientY })\n menuStore.show()\n },\n [setAnchorRect, menuStore],\n )\n\n const isOpen = menuStore.useState('open')\n React.useEffect(() => {\n if (!isOpen) setAnchorRect(null)\n }, [isOpen, setAnchorRect])\n\n return React.createElement(component, { ...props, onContextMenu: handleContextMenu, ref })\n})\n\n//\n// MenuList\n//\n\ntype MenuListProps = Omit<AriakitMenuProps, 'store' | 'className'>\n\n/**\n * The dropdown menu itself, containing a list of menu items.\n */\nconst MenuList = polymorphicComponent<'div', MenuListProps>(function MenuList(\n { exceptionallySetClassName, modal = true, ...props },\n ref,\n) {\n const { menuStore, getAnchorRect } = React.useContext(MenuContext)\n const isOpen = menuStore.useState('open')\n\n return isOpen ? (\n <Portal preserveTabOrder>\n <AriakitMenu\n {...props}\n store={menuStore}\n gutter={8}\n shift={4}\n ref={ref}\n className={classNames('reactist_menulist', exceptionallySetClassName)}\n getAnchorRect={getAnchorRect ?? undefined}\n modal={modal}\n />\n </Portal>\n ) : null\n})\n\n//\n// MenuItem\n//\n\ntype MenuItemProps = {\n /**\n * An optional value given to this menu item. It is passed on to the parent `Menu`'s\n * `onItemSelect` when you provide that instead of (or alongside) providing individual\n * `onSelect` callbacks to each menu item.\n */\n value?: string\n\n /**\n * The content inside the menu item.\n */\n children: React.ReactNode\n\n /**\n * When `true` the menu item is disabled and won't be selectable or be part of the keyboard\n * navigation across the menu options.\n *\n * @default true\n */\n disabled?: boolean\n\n /**\n * When `true` the menu will close when the menu item is selected, in addition to performing the\n * action that the menu item is set out to do.\n *\n * Set this to `false` to make sure that a given menu item does not auto-closes the menu when\n * selected. This should be the exception and not the norm, as the default is to auto-close.\n *\n * @default true\n */\n hideOnSelect?: boolean\n\n /**\n * The action to perform when the menu item is selected.\n *\n * If you return `false` from this function, the menu will not auto-close when this menu item\n * is selected. Though you should use `hideOnSelect` for this purpose, this allows you to\n * achieve the same effect conditionally and dynamically deciding at run time.\n */\n onSelect?: () => unknown\n\n /**\n * The event handler called when the menu item is clicked.\n *\n * This is similar to `onSelect`, but a bit different. You can certainly use it to trigger the\n * action that the menu item represents. But in general you should prefer `onSelect` for that.\n *\n * The main use for this handler is to get access to the click event. This can be used, for\n * example, to call `event.preventDefault()`, which will effectively prevent the rest of the\n * consequences of the click, including preventing `onSelect` from being called. In particular,\n * this is useful in menu items that are links, and you want the click to not trigger navigation\n * under some circumstances.\n */\n onClick?: (event: React.MouseEvent) => void\n}\n\n/**\n * A menu item inside a menu list. It can be selected by the user, triggering the `onSelect`\n * callback.\n */\nconst MenuItem = polymorphicComponent<'button', MenuItemProps>(function MenuItem(\n {\n value,\n children,\n onSelect,\n hideOnSelect = true,\n onClick,\n exceptionallySetClassName,\n as = 'button',\n ...props\n },\n ref,\n) {\n const { handleItemSelect, menuStore } = React.useContext(MenuContext)\n const { hide } = menuStore\n\n const handleClick = React.useCallback(\n function handleClick(event: React.MouseEvent<HTMLButtonElement>) {\n onClick?.(event)\n const onSelectResult: unknown =\n onSelect && !event.defaultPrevented ? onSelect() : undefined\n const shouldClose = onSelectResult !== false && hideOnSelect\n handleItemSelect?.(value)\n if (shouldClose) hide()\n },\n [onSelect, onClick, handleItemSelect, hideOnSelect, hide, value],\n )\n\n return (\n <AriakitMenuItem\n {...props}\n as={as}\n store={menuStore}\n ref={ref}\n onClick={handleClick}\n className={exceptionallySetClassName}\n hideOnClick={false}\n >\n {children}\n </AriakitMenuItem>\n )\n})\n\n//\n// SubMenu\n//\n\ntype SubMenuProps = Pick<MenuProps, 'children' | 'onItemSelect'>\n\n/**\n * This component can be rendered alongside other `MenuItem` inside a `MenuList` in order to have\n * a sub-menu.\n *\n * Its children are expected to have the structure of a first level menu (a `MenuButton` and a\n * `MenuList`).\n *\n * ```jsx\n * <MenuItem label=\"Edit profile\" />\n * <SubMenu>\n * <MenuButton>More options</MenuButton>\n * <MenuList>\n * <MenuItem label=\"Preferences\" />\n * <MenuItem label=\"Sign out\" />\n * </MenuList>\n * </SubMenu>\n * ```\n *\n * The `MenuButton` will become a menu item in the current menu items list, and it will lead to\n * opening a sub-menu with the menu items list below it.\n */\nconst SubMenu = React.forwardRef<HTMLDivElement, SubMenuProps>(function SubMenu(\n { children, onItemSelect },\n ref,\n) {\n const { handleItemSelect: parentMenuItemSelect, menuStore } = React.useContext(MenuContext)\n const { hide: parentMenuHide } = menuStore\n\n const handleSubItemSelect = React.useCallback(\n function handleSubItemSelect(value: string | null | undefined) {\n onItemSelect?.(value)\n parentMenuItemSelect?.(value)\n parentMenuHide()\n },\n [parentMenuHide, parentMenuItemSelect, onItemSelect],\n )\n\n const [button, list] = React.Children.toArray(children)\n\n // Ariakit needs to be able to pass props to the MenuButton and combine it with the MenuItem component\n const renderMenuButton = React.useCallback(\n function renderMenuButton(props: MenuButtonProps) {\n return React.cloneElement(button as React.ReactElement, props)\n },\n [button],\n )\n\n return (\n <Menu onItemSelect={handleSubItemSelect}>\n <AriakitMenuItem as=\"div\" store={menuStore} ref={ref} hideOnClick={false}>\n {renderMenuButton}\n </AriakitMenuItem>\n {list}\n </Menu>\n )\n})\n\n//\n// MenuGroup\n//\n\ntype MenuGroupProps = Omit<NativeProps<HTMLDivElement>, 'className'> & {\n /**\n * A label to be shown visually and also used to semantically label the group.\n */\n label: string\n}\n\n/**\n * A way to semantically group some menu items.\n *\n * This group does not add any visual separator. You can do that yourself adding `<hr />` elements\n * before and/or after the group if you so wish.\n */\nconst MenuGroup = polymorphicComponent<'div', MenuGroupProps>(function MenuGroup(\n { label, children, exceptionallySetClassName, ...props },\n ref,\n) {\n const { menuStore } = React.useContext(MenuContext)\n return (\n <AriakitMenuGroup\n {...props}\n ref={ref}\n store={menuStore}\n className={exceptionallySetClassName}\n >\n {label ? (\n <div role=\"presentation\" className=\"reactist_menugroup__label\">\n {label}\n </div>\n ) : null}\n {children}\n </AriakitMenuGroup>\n )\n})\n\nexport { ContextMenuTrigger, Menu, MenuButton, MenuList, MenuItem, SubMenu, MenuGroup }\nexport type { MenuButtonProps, MenuListProps, MenuItemProps, MenuGroupProps }\n"],"names":["MenuContext","React","Menu","children","onItemSelect","props","anchorRect","setAnchorRect","getAnchorRect","menuStore","useMenuStore","focusLoop","value","handleItemSelect","Provider","MenuButton","polymorphicComponent","ref","exceptionallySetClassName","AriakitMenuButton","store","className","classNames","ContextMenuTrigger","as","component","handleContextMenu","event","preventDefault","x","clientX","y","clientY","show","isOpen","useState","onContextMenu","MenuList","modal","Portal","preserveTabOrder","AriakitMenu","gutter","shift","undefined","MenuItem","onSelect","hideOnSelect","onClick","hide","handleClick","shouldClose","defaultPrevented","AriakitMenuItem","hideOnClick","SubMenu","parentMenuItemSelect","parentMenuHide","handleSubItemSelect","button","list","toArray","renderMenuButton","MenuGroup","label","AriakitMenuGroup","role"],"mappings":"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"}
1
+ {"version":3,"file":"menu.js","sources":["../../src/menu/menu.tsx"],"sourcesContent":["import * as React from 'react'\nimport classNames from 'classnames'\n\nimport { polymorphicComponent } from '../utils/polymorphism'\n\n//\n// Reactist menu is a thin wrapper around Ariakit's menu components. This may or may not be\n// temporary. Our goal is to make it transparent for the users of Reactist of this implementation\n// detail. We may change in the future the external lib we use, or even implement it all internally,\n// as long as we keep the same outer interface as intact as possible.\n//\n// Around the heavy lifting of the external lib we just add some features to better integrate the\n// menu to Reactist's more opinionated approach (e.g. using our button with its custom variants and\n// other features, easily show keyboard shortcuts in menu items, etc.)\n//\nimport {\n Portal,\n MenuStore,\n MenuStoreProps,\n useMenuStore,\n MenuProps as AriakitMenuProps,\n Menu as AriakitMenu,\n MenuGroup as AriakitMenuGroup,\n MenuItem as AriakitMenuItem,\n MenuButton as AriakitMenuButton,\n MenuButtonProps as AriakitMenuButtonProps,\n} from '@ariakit/react'\n\nimport './menu.less'\n\ntype MenuContextState = {\n menuStore: MenuStore\n handleItemSelect?: (value: string | null | undefined) => void\n getAnchorRect: (() => { x: number; y: number }) | null\n setAnchorRect: (rect: { x: number; y: number } | null) => void\n}\n\nconst MenuContext = React.createContext<MenuContextState>(\n // Ariakit gives us no means to obtain a valid initial/default value of type MenuStateReturn\n // (it is normally obtained by calling useMenuState but we can't call hooks outside components).\n // This is however of little consequence since this value is only used if some of the components\n // are used outside Menu, something that should not happen and we do not support.\n // @ts-expect-error\n {},\n)\n\n//\n// Menu\n//\n\ntype MenuProps = Omit<MenuStoreProps, 'visible'> & {\n /**\n * The `Menu` must contain a `MenuList` that defines the menu options. It must also contain a\n * `MenuButton` that triggers the menu to be opened or closed.\n */\n children: React.ReactNode\n\n /**\n * An optional callback that will be called back whenever a menu item is selected. It receives\n * the `value` of the selected `MenuItem`.\n *\n * If you pass down this callback, it is recommended that you properly memoize it so it does not\n * change on every render.\n */\n onItemSelect?: (value: string | null | undefined) => void\n}\n\n/**\n * Wrapper component to control a menu. It does not render anything, only providing the state\n * management for the menu components inside it.\n */\nfunction Menu({ children, onItemSelect, ...props }: MenuProps) {\n const [anchorRect, setAnchorRect] = React.useState<{ x: number; y: number } | null>(null)\n const getAnchorRect = React.useMemo(() => (anchorRect ? () => anchorRect : null), [anchorRect])\n const menuStore = useMenuStore({ focusLoop: true, ...props })\n\n const value: MenuContextState = React.useMemo(\n () => ({ menuStore, handleItemSelect: onItemSelect, getAnchorRect, setAnchorRect }),\n [menuStore, onItemSelect, getAnchorRect, setAnchorRect],\n )\n\n return <MenuContext.Provider value={value}>{children}</MenuContext.Provider>\n}\n\n//\n// MenuButton\n//\n\ntype MenuButtonProps = Omit<AriakitMenuButtonProps, 'store' | 'className' | 'as'>\n\n/**\n * A button to toggle a dropdown menu open or closed.\n */\nconst MenuButton = polymorphicComponent<'button', MenuButtonProps>(function MenuButton(\n { exceptionallySetClassName, ...props },\n ref,\n) {\n const { menuStore } = React.useContext(MenuContext)\n return (\n <AriakitMenuButton\n {...props}\n store={menuStore}\n ref={ref}\n className={classNames('reactist_menubutton', exceptionallySetClassName)}\n />\n )\n})\n\n//\n// ContextMenuTrigger\n//\nconst ContextMenuTrigger = polymorphicComponent<'div', unknown>(function ContextMenuTrigger(\n { as: component = 'div', ...props },\n ref,\n) {\n const { setAnchorRect, menuStore } = React.useContext(MenuContext)\n\n const handleContextMenu = React.useCallback(\n function handleContextMenu(event: React.MouseEvent) {\n event.preventDefault()\n setAnchorRect({ x: event.clientX, y: event.clientY })\n menuStore.show()\n },\n [setAnchorRect, menuStore],\n )\n\n const isOpen = menuStore.useState('open')\n React.useEffect(() => {\n if (!isOpen) setAnchorRect(null)\n }, [isOpen, setAnchorRect])\n\n return React.createElement(component, { ...props, onContextMenu: handleContextMenu, ref })\n})\n\n//\n// MenuList\n//\n\ntype MenuListProps = Omit<AriakitMenuProps, 'store' | 'className'>\n\n/**\n * The dropdown menu itself, containing a list of menu items.\n */\nconst MenuList = polymorphicComponent<'div', MenuListProps>(function MenuList(\n { exceptionallySetClassName, modal = true, ...props },\n ref,\n) {\n const { menuStore, getAnchorRect } = React.useContext(MenuContext)\n const isOpen = menuStore.useState('open')\n\n return isOpen ? (\n <Portal preserveTabOrder>\n <AriakitMenu\n {...props}\n store={menuStore}\n gutter={8}\n shift={4}\n ref={ref}\n className={classNames('reactist_menulist', exceptionallySetClassName)}\n getAnchorRect={getAnchorRect ?? undefined}\n modal={modal}\n />\n </Portal>\n ) : null\n})\n\n//\n// MenuItem\n//\n\ntype MenuItemProps = {\n /**\n * An optional value given to this menu item. It is passed on to the parent `Menu`'s\n * `onItemSelect` when you provide that instead of (or alongside) providing individual\n * `onSelect` callbacks to each menu item.\n */\n value?: string\n\n /**\n * The content inside the menu item.\n */\n children: React.ReactNode\n\n /**\n * When `true` the menu item is disabled and won't be selectable or be part of the keyboard\n * navigation across the menu options.\n *\n * @default true\n */\n disabled?: boolean\n\n /**\n * When `true` the menu will close when the menu item is selected, in addition to performing the\n * action that the menu item is set out to do.\n *\n * Set this to `false` to make sure that a given menu item does not auto-closes the menu when\n * selected. This should be the exception and not the norm, as the default is to auto-close.\n *\n * @default true\n */\n hideOnSelect?: boolean\n\n /**\n * The action to perform when the menu item is selected.\n *\n * If you return `false` from this function, the menu will not auto-close when this menu item\n * is selected. Though you should use `hideOnSelect` for this purpose, this allows you to\n * achieve the same effect conditionally and dynamically deciding at run time.\n */\n onSelect?: () => unknown\n\n /**\n * The event handler called when the menu item is clicked.\n *\n * This is similar to `onSelect`, but a bit different. You can certainly use it to trigger the\n * action that the menu item represents. But in general you should prefer `onSelect` for that.\n *\n * The main use for this handler is to get access to the click event. This can be used, for\n * example, to call `event.preventDefault()`, which will effectively prevent the rest of the\n * consequences of the click, including preventing `onSelect` from being called. In particular,\n * this is useful in menu items that are links, and you want the click to not trigger navigation\n * under some circumstances.\n */\n onClick?: (event: React.MouseEvent) => void\n}\n\n/**\n * A menu item inside a menu list. It can be selected by the user, triggering the `onSelect`\n * callback.\n */\nconst MenuItem = polymorphicComponent<'button', MenuItemProps>(function MenuItem(\n {\n value,\n children,\n onSelect,\n hideOnSelect = true,\n onClick,\n exceptionallySetClassName,\n as = 'button',\n ...props\n },\n ref,\n) {\n const { handleItemSelect, menuStore } = React.useContext(MenuContext)\n const { hide } = menuStore\n\n const handleClick = React.useCallback(\n function handleClick(event: React.MouseEvent<HTMLButtonElement>) {\n onClick?.(event)\n const onSelectResult: unknown =\n onSelect && !event.defaultPrevented ? onSelect() : undefined\n const shouldClose = onSelectResult !== false && hideOnSelect\n handleItemSelect?.(value)\n if (shouldClose) hide()\n },\n [onSelect, onClick, handleItemSelect, hideOnSelect, hide, value],\n )\n\n return (\n <AriakitMenuItem\n {...props}\n as={as}\n store={menuStore}\n ref={ref}\n onClick={handleClick}\n className={exceptionallySetClassName}\n hideOnClick={false}\n >\n {children}\n </AriakitMenuItem>\n )\n})\n\n//\n// SubMenu\n//\n\ntype SubMenuProps = Pick<MenuProps, 'children' | 'onItemSelect'>\n\n/**\n * This component can be rendered alongside other `MenuItem` inside a `MenuList` in order to have\n * a sub-menu.\n *\n * Its children are expected to have the structure of a first level menu (a `MenuButton` and a\n * `MenuList`).\n *\n * ```jsx\n * <MenuItem label=\"Edit profile\" />\n * <SubMenu>\n * <MenuButton>More options</MenuButton>\n * <MenuList>\n * <MenuItem label=\"Preferences\" />\n * <MenuItem label=\"Sign out\" />\n * </MenuList>\n * </SubMenu>\n * ```\n *\n * The `MenuButton` will become a menu item in the current menu items list, and it will lead to\n * opening a sub-menu with the menu items list below it.\n */\nconst SubMenu = React.forwardRef<HTMLDivElement, SubMenuProps>(function SubMenu(\n { children, onItemSelect },\n ref,\n) {\n const { handleItemSelect: parentMenuItemSelect, menuStore } = React.useContext(MenuContext)\n const { hide: parentMenuHide } = menuStore\n\n const handleSubItemSelect = React.useCallback(\n function handleSubItemSelect(value: string | null | undefined) {\n onItemSelect?.(value)\n parentMenuItemSelect?.(value)\n parentMenuHide()\n },\n [parentMenuHide, parentMenuItemSelect, onItemSelect],\n )\n\n const [button, list] = React.Children.toArray(children)\n\n // Ariakit needs to be able to pass props to the MenuButton and combine it with the MenuItem component\n const renderMenuButton = React.useCallback(\n function renderMenuButton(props: MenuButtonProps) {\n return React.cloneElement(button as React.ReactElement, props)\n },\n [button],\n )\n\n return (\n <Menu onItemSelect={handleSubItemSelect}>\n <AriakitMenuItem as=\"div\" store={menuStore} ref={ref} hideOnClick={false}>\n {renderMenuButton}\n </AriakitMenuItem>\n {list}\n </Menu>\n )\n})\n\n//\n// MenuGroup\n//\n\ntype MenuGroupProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'className'> & {\n /**\n * A label to be shown visually and also used to semantically label the group.\n */\n label: string\n}\n\n/**\n * A way to semantically group some menu items.\n *\n * This group does not add any visual separator. You can do that yourself adding `<hr />` elements\n * before and/or after the group if you so wish.\n */\nconst MenuGroup = polymorphicComponent<'div', MenuGroupProps>(function MenuGroup(\n { label, children, exceptionallySetClassName, ...props },\n ref,\n) {\n const { menuStore } = React.useContext(MenuContext)\n return (\n <AriakitMenuGroup\n {...props}\n ref={ref}\n store={menuStore}\n className={exceptionallySetClassName}\n >\n {label ? (\n <div role=\"presentation\" className=\"reactist_menugroup__label\">\n {label}\n </div>\n ) : null}\n {children}\n </AriakitMenuGroup>\n )\n})\n\nexport { ContextMenuTrigger, Menu, MenuButton, MenuList, MenuItem, SubMenu, MenuGroup }\nexport type { MenuButtonProps, MenuListProps, MenuItemProps, MenuGroupProps }\n"],"names":["MenuContext","React","Menu","children","onItemSelect","props","anchorRect","setAnchorRect","getAnchorRect","menuStore","useMenuStore","focusLoop","value","handleItemSelect","Provider","MenuButton","polymorphicComponent","ref","exceptionallySetClassName","AriakitMenuButton","store","className","classNames","ContextMenuTrigger","as","component","handleContextMenu","event","preventDefault","x","clientX","y","clientY","show","isOpen","useState","onContextMenu","MenuList","modal","Portal","preserveTabOrder","AriakitMenu","gutter","shift","undefined","MenuItem","onSelect","hideOnSelect","onClick","hide","handleClick","shouldClose","defaultPrevented","AriakitMenuItem","hideOnClick","SubMenu","parentMenuItemSelect","parentMenuHide","handleSubItemSelect","button","list","toArray","renderMenuButton","MenuGroup","label","AriakitMenuGroup","role"],"mappings":"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"}
@@ -1,10 +1,11 @@
1
1
  import * as React from 'react';
2
2
  import { DialogOptions, PortalOptions } from '@ariakit/react';
3
- import { ButtonProps } from '../button';
3
+ import { IconButtonProps } from '../button';
4
+ import type { ObfuscatedClassName } from '../utils/common-types';
4
5
  declare type ModalWidth = 'small' | 'medium' | 'large' | 'xlarge' | 'full';
5
6
  declare type ModalHeightMode = 'expand' | 'fitContent';
6
7
  declare type DivProps = Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLDivElement>, HTMLDivElement>, 'className' | 'children' | `aria-label` | `aria-labelledby`>;
7
- export declare type ModalProps = DivProps & {
8
+ export interface ModalProps extends DivProps, ObfuscatedClassName {
8
9
  /**
9
10
  * The content of the modal.
10
11
  */
@@ -50,10 +51,6 @@ export declare type ModalProps = DivProps & {
50
51
  * Controls if the modal is dismissed when clicking outside the modal body, on the overlay.
51
52
  */
52
53
  hideOnInteractOutside?: DialogOptions['hideOnInteractOutside'];
53
- /**
54
- * An escape hatch in case you need to provide a custom class name to the container element.
55
- */
56
- exceptionallySetClassName?: string;
57
54
  /**
58
55
  * An escape hatch in case you need to provide a custom class name to the overlay element.
59
56
  */
@@ -84,7 +81,7 @@ export declare type ModalProps = DivProps & {
84
81
  * <Portal portalElement={getPortalElement} />;
85
82
  */
86
83
  portalElement?: PortalOptions['portalElement'];
87
- };
84
+ }
88
85
  /**
89
86
  * Renders a modal that sits on top of the rest of the content in the entire page.
90
87
  *
@@ -95,7 +92,7 @@ export declare type ModalProps = DivProps & {
95
92
  * @see ModalBody
96
93
  */
97
94
  export declare function Modal({ isOpen, onDismiss, height, width, exceptionallySetClassName, exceptionallySetOverlayClassName, autoFocus, hideOnEscape, hideOnInteractOutside, children, portalElement, onKeyDown, ...props }: ModalProps): JSX.Element | null;
98
- export declare type ModalCloseButtonProps = Omit<ButtonProps, 'type' | 'children' | 'variant' | 'icon' | 'startIcon' | 'endIcon' | 'disabled' | 'loading' | 'tabIndex' | 'width' | 'align'> & {
95
+ export declare type ModalCloseButtonProps = Omit<IconButtonProps, 'type' | 'variant' | 'icon' | 'disabled' | 'loading' | 'tabIndex' | 'ref'> & {
99
96
  /**
100
97
  * The descriptive label of the button.
101
98
  */
@@ -1,2 +1,2 @@
1
- "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var t=require("../_virtual/_rollupPluginBabelHelpers.js"),a=require("react"),n=(e(a),e(require("classnames"))),l=require("../box/box.js"),o=require("../columns/columns.js"),r=require("../divider/divider.js"),i=require("../inline/inline.js"),s=require("@ariakit/react"),u=require("../button/button.js"),c=require("../icons/close-icon.js"),d=e(require("react-focus-lock")),m=require("aria-hidden"),p=require("./modal.module.css.js");const h=["isOpen","onDismiss","height","width","exceptionallySetClassName","exceptionallySetOverlayClassName","autoFocus","hideOnEscape","hideOnInteractOutside","children","portalElement","onKeyDown"],f=["children","button","withDivider","exceptionallySetClassName"],x=["exceptionallySetClassName","children"],b=["exceptionallySetClassName","withDivider"],g=["children"],E=a.createContext({onDismiss:void 0,height:"fitContent"});function v(e){return!(e.ownerDocument===document&&"iframe"===e.tagName.toLowerCase())}function C(e){const{onDismiss:n}=a.useContext(E),[l,o]=a.useState(!1),[r,i]=a.useState(!1);return a.useEffect((function(){r?o(!0):i(!0)}),[r]),a.createElement(u.Button,t.objectSpread2(t.objectSpread2({},e),{},{variant:"quaternary",onClick:n,icon:a.createElement(c.CloseIcon,null),tabIndex:l?0:-1}))}function y(e){let{exceptionallySetClassName:n,withDivider:o=!1}=e,i=t.objectWithoutProperties(e,b);return a.createElement(a.Fragment,null,o?a.createElement(r.Divider,null):null,a.createElement(l.Box,t.objectSpread2(t.objectSpread2({as:"footer"},i),{},{className:n,padding:"large"})))}exports.Modal=function(e){let{isOpen:o,onDismiss:r,height:i="fitContent",width:u="medium",exceptionallySetClassName:c,exceptionallySetOverlayClassName:f,autoFocus:x=!0,hideOnEscape:b=!0,hideOnInteractOutside:g=!0,children:C,portalElement:y,onKeyDown:S}=e,j=t.objectWithoutProperties(e,h);const w=a.useCallback(e=>{e||null==r||r()},[r]),D=s.useDialogStore({open:o,setOpen:w}),N=a.useMemo(()=>({onDismiss:r,height:i}),[r,i]),O=a.useRef(null),q=a.useRef(null),P=a.useRef(null),B=a.useCallback(e=>{var t,a;null!=(t=q.current)&&t.contains(e.target)||null==(a=P.current)||!a.contains(e.target)||(e.stopPropagation(),null==r||r())},[r]);a.useLayoutEffect((function(){if(o&&O.current)return m.hideOthers(O.current)}),[o]);const F=a.useCallback((function(e){b&&null!=r&&"Escape"===e.key&&!e.defaultPrevented&&(e.stopPropagation(),r()),null==S||S(e)}),[r,b,S]);return o?a.createElement(s.Portal,{portalRef:O,portalElement:y},a.createElement(l.Box,{"data-testid":"modal-overlay","data-overlay":!0,className:n(p.default.overlay,p.default[i],p.default[u],f),onPointerDown:g?B:void 0,ref:P},a.createElement(d,{autoFocus:x,whiteList:v,returnFocus:!0},a.createElement(s.Dialog,t.objectSpread2(t.objectSpread2({},j),{},{ref:q,as:l.Box,store:D,preventBodyScroll:!0,borderRadius:"full",background:"default",display:"flex",flexDirection:"column",overflow:"hidden",height:"expand"===i?"full":void 0,flexGrow:"expand"===i?1:0,className:[c,p.default.container],modal:!1,autoFocus:!1,autoFocusOnShow:!1,autoFocusOnHide:!1,portal:!1,backdrop:!1,hideOnInteractOutside:!1,hideOnEscape:!1,onKeyDown:F}),a.createElement(E.Provider,{value:N},C))))):null},exports.ModalActions=function(e){let{children:n}=e,l=t.objectWithoutProperties(e,g);return a.createElement(y,t.objectSpread2({},l),a.createElement(i.Inline,{align:"right",space:"large"},n))},exports.ModalBody=function(e){let{exceptionallySetClassName:n,children:o}=e,r=t.objectWithoutProperties(e,x);const{height:i}=a.useContext(E);return a.createElement(l.Box,t.objectSpread2(t.objectSpread2({},r),{},{className:n,flexGrow:"expand"===i?1:0,height:"expand"===i?"full":void 0,overflow:"auto"}),a.createElement(l.Box,{padding:"large",paddingBottom:"xxlarge"},o))},exports.ModalCloseButton=C,exports.ModalFooter=y,exports.ModalHeader=function(e){let{children:n,button:i=!0,withDivider:s=!1,exceptionallySetClassName:u}=e,c=t.objectWithoutProperties(e,f);return a.createElement(a.Fragment,null,a.createElement(l.Box,t.objectSpread2(t.objectSpread2({},c),{},{as:"header",paddingLeft:"large",paddingRight:!1===i||null===i?"large":"small",paddingY:"small",className:u}),a.createElement(o.Columns,{space:"large",alignY:"center"},a.createElement(o.Column,{width:"auto"},n),!1===i||null===i?a.createElement("div",{className:p.default.headerContent}):a.createElement(o.Column,{width:"content",exceptionallySetClassName:p.default.buttonContainer,"data-testid":"button-container"},"boolean"==typeof i?a.createElement(C,{"aria-label":"Close modal",autoFocus:!1}):i))),s?a.createElement(r.Divider,null):null)};
1
+ "use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var t=require("../_virtual/_rollupPluginBabelHelpers.js"),a=require("react"),n=(e(a),e(require("classnames"))),l=require("../box/box.js"),o=require("../columns/columns.js"),r=require("../divider/divider.js"),i=require("../inline/inline.js"),s=require("@ariakit/react"),c=require("../button/button.js"),u=require("../icons/close-icon.js"),d=e(require("react-focus-lock")),m=require("aria-hidden"),p=require("./modal.module.css.js");const h=["isOpen","onDismiss","height","width","exceptionallySetClassName","exceptionallySetOverlayClassName","autoFocus","hideOnEscape","hideOnInteractOutside","children","portalElement","onKeyDown"],f=["children","button","withDivider","exceptionallySetClassName"],x=["exceptionallySetClassName","children"],b=["exceptionallySetClassName","withDivider"],g=["children"],E=a.createContext({onDismiss:void 0,height:"fitContent"});function v(e){return!(e.ownerDocument===document&&"iframe"===e.tagName.toLowerCase())}function C(e){const{onDismiss:n}=a.useContext(E),[l,o]=a.useState(!1),[r,i]=a.useState(!1);return a.useEffect((function(){r?o(!0):i(!0)}),[r]),a.createElement(c.IconButton,t.objectSpread2(t.objectSpread2({},e),{},{variant:"quaternary",onClick:n,icon:a.createElement(u.CloseIcon,null),tabIndex:l?0:-1}))}function y(e){let{exceptionallySetClassName:n,withDivider:o=!1}=e,i=t.objectWithoutProperties(e,b);return a.createElement(a.Fragment,null,o?a.createElement(r.Divider,null):null,a.createElement(l.Box,t.objectSpread2(t.objectSpread2({as:"footer"},i),{},{className:n,padding:"large"})))}exports.Modal=function(e){let{isOpen:o,onDismiss:r,height:i="fitContent",width:c="medium",exceptionallySetClassName:u,exceptionallySetOverlayClassName:f,autoFocus:x=!0,hideOnEscape:b=!0,hideOnInteractOutside:g=!0,children:C,portalElement:y,onKeyDown:S}=e,j=t.objectWithoutProperties(e,h);const w=a.useCallback(e=>{e||null==r||r()},[r]),D=s.useDialogStore({open:o,setOpen:w}),N=a.useMemo(()=>({onDismiss:r,height:i}),[r,i]),O=a.useRef(null),q=a.useRef(null),P=a.useRef(null),B=a.useCallback(e=>{var t,a;null!=(t=q.current)&&t.contains(e.target)||null==(a=P.current)||!a.contains(e.target)||(e.stopPropagation(),null==r||r())},[r]);a.useLayoutEffect((function(){if(o&&O.current)return m.hideOthers(O.current)}),[o]);const F=a.useCallback((function(e){b&&null!=r&&"Escape"===e.key&&!e.defaultPrevented&&(e.stopPropagation(),r()),null==S||S(e)}),[r,b,S]);return o?a.createElement(s.Portal,{portalRef:O,portalElement:y},a.createElement(l.Box,{"data-testid":"modal-overlay","data-overlay":!0,className:n(p.default.overlay,p.default[i],p.default[c],f),onPointerDown:g?B:void 0,ref:P},a.createElement(d,{autoFocus:x,whiteList:v,returnFocus:!0},a.createElement(s.Dialog,t.objectSpread2(t.objectSpread2({},j),{},{ref:q,as:l.Box,store:D,preventBodyScroll:!0,borderRadius:"full",background:"default",display:"flex",flexDirection:"column",overflow:"hidden",height:"expand"===i?"full":void 0,flexGrow:"expand"===i?1:0,className:[u,p.default.container],modal:!1,autoFocus:!1,autoFocusOnShow:!1,autoFocusOnHide:!1,portal:!1,backdrop:!1,hideOnInteractOutside:!1,hideOnEscape:!1,onKeyDown:F}),a.createElement(E.Provider,{value:N},C))))):null},exports.ModalActions=function(e){let{children:n}=e,l=t.objectWithoutProperties(e,g);return a.createElement(y,t.objectSpread2({},l),a.createElement(i.Inline,{align:"right",space:"large"},n))},exports.ModalBody=function(e){let{exceptionallySetClassName:n,children:o}=e,r=t.objectWithoutProperties(e,x);const{height:i}=a.useContext(E);return a.createElement(l.Box,t.objectSpread2(t.objectSpread2({},r),{},{className:n,flexGrow:"expand"===i?1:0,height:"expand"===i?"full":void 0,overflow:"auto"}),a.createElement(l.Box,{padding:"large",paddingBottom:"xxlarge"},o))},exports.ModalCloseButton=C,exports.ModalFooter=y,exports.ModalHeader=function(e){let{children:n,button:i=!0,withDivider:s=!1,exceptionallySetClassName:c}=e,u=t.objectWithoutProperties(e,f);return a.createElement(a.Fragment,null,a.createElement(l.Box,t.objectSpread2(t.objectSpread2({},u),{},{as:"header",paddingLeft:"large",paddingRight:!1===i||null===i?"large":"small",paddingY:"small",className:c}),a.createElement(o.Columns,{space:"large",alignY:"center"},a.createElement(o.Column,{width:"auto"},n),!1===i||null===i?a.createElement("div",{className:p.default.headerContent}):a.createElement(o.Column,{width:"content",exceptionallySetClassName:p.default.buttonContainer,"data-testid":"button-container"},"boolean"==typeof i?a.createElement(C,{"aria-label":"Close modal",autoFocus:!1}):i))),s?a.createElement(r.Divider,null):null)};
2
2
  //# sourceMappingURL=modal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.js","sources":["../../src/modal/modal.tsx"],"sourcesContent":["import * as React from 'react'\nimport classNames from 'classnames'\nimport FocusLock from 'react-focus-lock'\nimport { hideOthers } from 'aria-hidden'\n\nimport { Dialog, DialogOptions, useDialogStore, Portal, PortalOptions } from '@ariakit/react'\n\nimport { CloseIcon } from '../icons/close-icon'\nimport { Column, Columns } from '../columns'\nimport { Inline } from '../inline'\nimport { Divider } from '../divider'\nimport { Box } from '../box'\nimport { Button, ButtonProps } from '../button'\n\nimport styles from './modal.module.css'\n\ntype ModalWidth = 'small' | 'medium' | 'large' | 'xlarge' | 'full'\ntype ModalHeightMode = 'expand' | 'fitContent'\n\n//\n// ModalContext\n//\n\ntype ModalContextValue = {\n onDismiss?(this: void): void\n height: ModalHeightMode\n}\n\nconst ModalContext = React.createContext<ModalContextValue>({\n onDismiss: undefined,\n height: 'fitContent',\n})\n\n//\n// Modal container\n//\n\ntype DivProps = Omit<\n React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLDivElement>, HTMLDivElement>,\n 'className' | 'children' | `aria-label` | `aria-labelledby`\n>\n\nexport type ModalProps = DivProps & {\n /**\n * The content of the modal.\n */\n children: React.ReactNode\n /**\n * Whether the modal is open and visible or not.\n */\n isOpen: boolean\n /**\n * Called when the user triggers closing the modal.\n */\n onDismiss?(): void\n /**\n * A descriptive setting for how wide the modal should aim to be, depending on how much space\n * it has on screen.\n * @default 'medium'\n */\n width?: ModalWidth\n /**\n * A descriptive setting for how tall the modal should aim to be.\n *\n * - 'expand': the modal aims to fill most of the available screen height, leaving only a small\n * padding above and below.\n * - 'fitContent': the modal shrinks to the smallest size that allow it to fit its content.\n *\n * In either case, if content does not fit, the content of the main body is set to scroll\n * (provided you use `ModalBody`) so that the modal never has to strech vertically beyond the\n * viewport boundaries.\n *\n * If you do not use `ModalBody`, the modal still prevents overflow, and you are in charge of\n * the inner layout to ensure scroll, or whatever other strategy you may want.\n */\n height?: ModalHeightMode\n /**\n * Whether to set or not the focus initially to the first focusable element inside the modal.\n */\n autoFocus?: boolean\n /**\n * Controls if the modal is dismissed when pressing \"Escape\".\n */\n hideOnEscape?: DialogOptions['hideOnEscape']\n /**\n * Controls if the modal is dismissed when clicking outside the modal body, on the overlay.\n */\n hideOnInteractOutside?: DialogOptions['hideOnInteractOutside']\n /**\n * An escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n /**\n * An escape hatch in case you need to provide a custom class name to the overlay element.\n */\n exceptionallySetOverlayClassName?: string\n /** Defines a string value that labels the current modal for assistive technologies. */\n 'aria-label'?: string\n /** Identifies the element (or elements) that labels the current modal for assistive technologies. */\n 'aria-labelledby'?: string\n /**\n * An HTML element or a memoized callback function that returns an HTML element to be used as\n * the portal element. By default, the portal element will be a `div` element appended to the\n * `document.body`.\n *\n * @default HTMLDivElement\n *\n * @example\n * const [portal, setPortal] = useState(null);\n * <Portal portalElement={portal} />;\n * <div ref={setPortal} />;\n *\n * @example\n * const getPortalElement = useCallback(() => {\n * const div = document.createElement(\"div\");\n * const portalRoot = document.getElementById(\"portal-root\");\n * portalRoot.appendChild(div);\n * return div;\n * }, []);\n * <Portal portalElement={getPortalElement} />;\n */\n portalElement?: PortalOptions['portalElement']\n}\n\nfunction isNotInternalFrame(element: HTMLElement) {\n return !(element.ownerDocument === document && element.tagName.toLowerCase() === 'iframe')\n}\n\n/**\n * Renders a modal that sits on top of the rest of the content in the entire page.\n *\n * Follows the WAI-ARIA Dialog (Modal) Pattern.\n *\n * @see ModalHeader\n * @see ModalFooter\n * @see ModalBody\n */\nexport function Modal({\n isOpen,\n onDismiss,\n height = 'fitContent',\n width = 'medium',\n exceptionallySetClassName,\n exceptionallySetOverlayClassName,\n autoFocus = true,\n hideOnEscape = true,\n hideOnInteractOutside = true,\n children,\n portalElement,\n onKeyDown,\n ...props\n}: ModalProps) {\n const setOpen = React.useCallback(\n (visible: boolean) => {\n if (!visible) {\n onDismiss?.()\n }\n },\n [onDismiss],\n )\n const store = useDialogStore({ open: isOpen, setOpen })\n\n const contextValue: ModalContextValue = React.useMemo(() => ({ onDismiss, height }), [\n onDismiss,\n height,\n ])\n\n const portalRef = React.useRef<HTMLElement | null>(null)\n const dialogRef = React.useRef<HTMLDivElement | null>(null)\n const backdropRef = React.useRef<HTMLDivElement | null>(null)\n const handleBackdropClick = React.useCallback(\n (event: React.MouseEvent) => {\n if (\n // The focus lock element takes up the same space as the backdrop and is where the event bubbles up from,\n // so instead of checking the backdrop as the event target, we need to make sure it's just above the dialog\n !dialogRef.current?.contains(event.target as Node) &&\n // Events fired from other portals will bubble up to the backdrop, even if it isn't a child in the DOM\n backdropRef.current?.contains(event.target as Node)\n ) {\n event.stopPropagation()\n onDismiss?.()\n }\n },\n [onDismiss],\n )\n\n React.useLayoutEffect(\n function disableAccessibilityTreeOutside() {\n if (!isOpen || !portalRef.current) {\n return\n }\n\n return hideOthers(portalRef.current)\n },\n [isOpen],\n )\n\n const handleKeyDown = React.useCallback(\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n if (\n hideOnEscape &&\n onDismiss != null &&\n event.key === 'Escape' &&\n !event.defaultPrevented\n ) {\n event.stopPropagation()\n onDismiss()\n }\n onKeyDown?.(event)\n },\n [onDismiss, hideOnEscape, onKeyDown],\n )\n\n if (!isOpen) {\n return null\n }\n\n return (\n <Portal portalRef={portalRef} portalElement={portalElement}>\n <Box\n data-testid=\"modal-overlay\"\n data-overlay\n className={classNames(\n styles.overlay,\n styles[height],\n styles[width],\n exceptionallySetOverlayClassName,\n )}\n /**\n * We're using `onPointerDown` instead of `onClick` to prevent\n * the modal from closing when the click starts inside the modal\n * and ends on the backdrop.\n */\n onPointerDown={hideOnInteractOutside ? handleBackdropClick : undefined}\n ref={backdropRef}\n >\n <FocusLock autoFocus={autoFocus} whiteList={isNotInternalFrame} returnFocus={true}>\n <Dialog\n {...props}\n ref={dialogRef}\n as={Box}\n store={store}\n preventBodyScroll\n borderRadius=\"full\"\n background=\"default\"\n display=\"flex\"\n flexDirection=\"column\"\n overflow=\"hidden\"\n height={height === 'expand' ? 'full' : undefined}\n flexGrow={height === 'expand' ? 1 : 0}\n className={[exceptionallySetClassName, styles.container]}\n // Disable focus lock as we set up our own using ReactFocusLock\n modal={false}\n autoFocus={false}\n autoFocusOnShow={false}\n autoFocusOnHide={false}\n // Disable portal and backdrop as we control their markup\n portal={false}\n backdrop={false}\n hideOnInteractOutside={false}\n hideOnEscape={false}\n onKeyDown={handleKeyDown}\n >\n <ModalContext.Provider value={contextValue}>\n {children}\n </ModalContext.Provider>\n </Dialog>\n </FocusLock>\n </Box>\n </Portal>\n )\n}\n\n//\n// ModalCloseButton\n//\n\nexport type ModalCloseButtonProps = Omit<\n ButtonProps,\n | 'type'\n | 'children'\n | 'variant'\n | 'icon'\n | 'startIcon'\n | 'endIcon'\n | 'disabled'\n | 'loading'\n | 'tabIndex'\n | 'width'\n | 'align'\n> & {\n /**\n * The descriptive label of the button.\n */\n 'aria-label': string\n}\n\n/**\n * The close button rendered by ModalHeader. Provided independently so that consumers can customize\n * the button's label.\n *\n * @see ModalHeader\n */\nexport function ModalCloseButton(props: ModalCloseButtonProps) {\n const { onDismiss } = React.useContext(ModalContext)\n const [includeInTabOrder, setIncludeInTabOrder] = React.useState(false)\n const [isMounted, setIsMounted] = React.useState(false)\n\n React.useEffect(\n function skipAutoFocus() {\n if (isMounted) {\n setIncludeInTabOrder(true)\n } else {\n setIsMounted(true)\n }\n },\n [isMounted],\n )\n\n return (\n <Button\n {...props}\n variant=\"quaternary\"\n onClick={onDismiss}\n icon={<CloseIcon />}\n tabIndex={includeInTabOrder ? 0 : -1}\n />\n )\n}\n\n//\n// ModalHeader\n//\n\nexport type ModalHeaderProps = DivProps & {\n /**\n * The content of the header.\n */\n children: React.ReactNode\n /**\n * Allows to provide a custom button element, or to omit the close button if set to false.\n * @see ModalCloseButton\n */\n button?: React.ReactNode | boolean\n /**\n * Whether to render a divider line below the header.\n * @default false\n */\n withDivider?: boolean\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n}\n\n/**\n * Renders a standard modal header area with an optional close button.\n *\n * @see Modal\n * @see ModalFooter\n * @see ModalBody\n */\nexport function ModalHeader({\n children,\n button = true,\n withDivider = false,\n exceptionallySetClassName,\n ...props\n}: ModalHeaderProps) {\n return (\n <>\n <Box\n {...props}\n as=\"header\"\n paddingLeft=\"large\"\n paddingRight={button === false || button === null ? 'large' : 'small'}\n paddingY=\"small\"\n className={exceptionallySetClassName}\n >\n <Columns space=\"large\" alignY=\"center\">\n <Column width=\"auto\">{children}</Column>\n {button === false || button === null ? (\n <div className={styles.headerContent} />\n ) : (\n <Column\n width=\"content\"\n exceptionallySetClassName={styles.buttonContainer}\n data-testid=\"button-container\"\n >\n {typeof button === 'boolean' ? (\n <ModalCloseButton aria-label=\"Close modal\" autoFocus={false} />\n ) : (\n button\n )}\n </Column>\n )}\n </Columns>\n </Box>\n {withDivider ? <Divider /> : null}\n </>\n )\n}\n\n//\n// ModalBody\n//\n\nexport type ModalBodyProps = DivProps & {\n /**\n * The content of the modal body.\n */\n children: React.ReactNode\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n}\n\n/**\n * Renders the body of a modal.\n *\n * Convenient to use alongside ModalHeader and/or ModalFooter as needed. It ensures, among other\n * things, that the contet of the modal body expands or contracts depending on the modal height\n * setting or the size of the content. The body content also automatically scrolls when it's too\n * large to fit the available space.\n *\n * @see Modal\n * @see ModalHeader\n * @see ModalFooter\n */\nexport function ModalBody({ exceptionallySetClassName, children, ...props }: ModalBodyProps) {\n const { height } = React.useContext(ModalContext)\n return (\n <Box\n {...props}\n className={exceptionallySetClassName}\n flexGrow={height === 'expand' ? 1 : 0}\n height={height === 'expand' ? 'full' : undefined}\n overflow=\"auto\"\n >\n <Box padding=\"large\" paddingBottom=\"xxlarge\">\n {children}\n </Box>\n </Box>\n )\n}\n\n//\n// ModalFooter\n//\n\nexport type ModalFooterProps = DivProps & {\n /**\n * The contant of the modal footer.\n */\n children: React.ReactNode\n /**\n * Whether to render a divider line below the footer.\n * @default false\n */\n withDivider?: boolean\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n}\n\n/**\n * Renders a standard modal footer area.\n *\n * @see Modal\n * @see ModalHeader\n * @see ModalBody\n */\nexport function ModalFooter({\n exceptionallySetClassName,\n withDivider = false,\n ...props\n}: ModalFooterProps) {\n return (\n <>\n {withDivider ? <Divider /> : null}\n <Box as=\"footer\" {...props} className={exceptionallySetClassName} padding=\"large\" />\n </>\n )\n}\n\n//\n// ModalActions\n//\n\nexport type ModalActionsProps = ModalFooterProps\n\n/**\n * A specific version of the ModalFooter, tailored to showing an inline list of actions (buttons).\n * @see ModalFooter\n */\nexport function ModalActions({ children, ...props }: ModalActionsProps) {\n return (\n <ModalFooter {...props}>\n <Inline align=\"right\" space=\"large\">\n {children}\n </Inline>\n </ModalFooter>\n )\n}\n"],"names":["ModalContext","React","onDismiss","undefined","height","isNotInternalFrame","element","ownerDocument","document","tagName","toLowerCase","ModalCloseButton","props","includeInTabOrder","setIncludeInTabOrder","isMounted","setIsMounted","Button","variant","onClick","icon","CloseIcon","tabIndex","ModalFooter","exceptionallySetClassName","withDivider","Divider","Box","as","className","padding","isOpen","width","exceptionallySetOverlayClassName","autoFocus","hideOnEscape","hideOnInteractOutside","children","portalElement","onKeyDown","setOpen","visible","store","useDialogStore","open","contextValue","portalRef","dialogRef","backdropRef","handleBackdropClick","event","current","_dialogRef$current","contains","target","_backdropRef$current","stopPropagation","hideOthers","handleKeyDown","key","defaultPrevented","Portal","classNames","styles","overlay","onPointerDown","ref","FocusLock","whiteList","returnFocus","Dialog","preventBodyScroll","borderRadius","background","display","flexDirection","overflow","flexGrow","container","modal","autoFocusOnShow","autoFocusOnHide","portal","backdrop","Provider","value","Inline","align","space","paddingBottom","button","paddingLeft","paddingRight","paddingY","Columns","alignY","Column","headerContent","buttonContainer"],"mappings":"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"}
1
+ {"version":3,"file":"modal.js","sources":["../../src/modal/modal.tsx"],"sourcesContent":["import * as React from 'react'\nimport classNames from 'classnames'\nimport FocusLock from 'react-focus-lock'\nimport { hideOthers } from 'aria-hidden'\n\nimport { Dialog, DialogOptions, useDialogStore, Portal, PortalOptions } from '@ariakit/react'\n\nimport { CloseIcon } from '../icons/close-icon'\nimport { Column, Columns } from '../columns'\nimport { Inline } from '../inline'\nimport { Divider } from '../divider'\nimport { Box } from '../box'\nimport { IconButtonProps, IconButton } from '../button'\n\nimport styles from './modal.module.css'\nimport type { ObfuscatedClassName } from '../utils/common-types'\n\ntype ModalWidth = 'small' | 'medium' | 'large' | 'xlarge' | 'full'\ntype ModalHeightMode = 'expand' | 'fitContent'\n\n//\n// ModalContext\n//\n\ntype ModalContextValue = {\n onDismiss?(this: void): void\n height: ModalHeightMode\n}\n\nconst ModalContext = React.createContext<ModalContextValue>({\n onDismiss: undefined,\n height: 'fitContent',\n})\n\n//\n// Modal container\n//\n\ntype DivProps = Omit<\n React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLDivElement>, HTMLDivElement>,\n 'className' | 'children' | `aria-label` | `aria-labelledby`\n>\n\nexport interface ModalProps extends DivProps, ObfuscatedClassName {\n /**\n * The content of the modal.\n */\n children: React.ReactNode\n /**\n * Whether the modal is open and visible or not.\n */\n isOpen: boolean\n /**\n * Called when the user triggers closing the modal.\n */\n onDismiss?(): void\n /**\n * A descriptive setting for how wide the modal should aim to be, depending on how much space\n * it has on screen.\n * @default 'medium'\n */\n width?: ModalWidth\n /**\n * A descriptive setting for how tall the modal should aim to be.\n *\n * - 'expand': the modal aims to fill most of the available screen height, leaving only a small\n * padding above and below.\n * - 'fitContent': the modal shrinks to the smallest size that allow it to fit its content.\n *\n * In either case, if content does not fit, the content of the main body is set to scroll\n * (provided you use `ModalBody`) so that the modal never has to strech vertically beyond the\n * viewport boundaries.\n *\n * If you do not use `ModalBody`, the modal still prevents overflow, and you are in charge of\n * the inner layout to ensure scroll, or whatever other strategy you may want.\n */\n height?: ModalHeightMode\n\n /**\n * Whether to set or not the focus initially to the first focusable element inside the modal.\n */\n autoFocus?: boolean\n\n /**\n * Controls if the modal is dismissed when pressing \"Escape\".\n */\n hideOnEscape?: DialogOptions['hideOnEscape']\n\n /**\n * Controls if the modal is dismissed when clicking outside the modal body, on the overlay.\n */\n hideOnInteractOutside?: DialogOptions['hideOnInteractOutside']\n\n /**\n * An escape hatch in case you need to provide a custom class name to the overlay element.\n */\n exceptionallySetOverlayClassName?: string\n\n /** Defines a string value that labels the current modal for assistive technologies. */\n 'aria-label'?: string\n\n /** Identifies the element (or elements) that labels the current modal for assistive technologies. */\n 'aria-labelledby'?: string\n\n /**\n * An HTML element or a memoized callback function that returns an HTML element to be used as\n * the portal element. By default, the portal element will be a `div` element appended to the\n * `document.body`.\n *\n * @default HTMLDivElement\n *\n * @example\n * const [portal, setPortal] = useState(null);\n * <Portal portalElement={portal} />;\n * <div ref={setPortal} />;\n *\n * @example\n * const getPortalElement = useCallback(() => {\n * const div = document.createElement(\"div\");\n * const portalRoot = document.getElementById(\"portal-root\");\n * portalRoot.appendChild(div);\n * return div;\n * }, []);\n * <Portal portalElement={getPortalElement} />;\n */\n portalElement?: PortalOptions['portalElement']\n}\n\nfunction isNotInternalFrame(element: HTMLElement) {\n return !(element.ownerDocument === document && element.tagName.toLowerCase() === 'iframe')\n}\n\n/**\n * Renders a modal that sits on top of the rest of the content in the entire page.\n *\n * Follows the WAI-ARIA Dialog (Modal) Pattern.\n *\n * @see ModalHeader\n * @see ModalFooter\n * @see ModalBody\n */\nexport function Modal({\n isOpen,\n onDismiss,\n height = 'fitContent',\n width = 'medium',\n exceptionallySetClassName,\n exceptionallySetOverlayClassName,\n autoFocus = true,\n hideOnEscape = true,\n hideOnInteractOutside = true,\n children,\n portalElement,\n onKeyDown,\n ...props\n}: ModalProps) {\n const setOpen = React.useCallback(\n (visible: boolean) => {\n if (!visible) {\n onDismiss?.()\n }\n },\n [onDismiss],\n )\n const store = useDialogStore({ open: isOpen, setOpen })\n\n const contextValue: ModalContextValue = React.useMemo(() => ({ onDismiss, height }), [\n onDismiss,\n height,\n ])\n\n const portalRef = React.useRef<HTMLElement | null>(null)\n const dialogRef = React.useRef<HTMLDivElement | null>(null)\n const backdropRef = React.useRef<HTMLDivElement | null>(null)\n const handleBackdropClick = React.useCallback(\n (event: React.MouseEvent) => {\n if (\n // The focus lock element takes up the same space as the backdrop and is where the event bubbles up from,\n // so instead of checking the backdrop as the event target, we need to make sure it's just above the dialog\n !dialogRef.current?.contains(event.target as Node) &&\n // Events fired from other portals will bubble up to the backdrop, even if it isn't a child in the DOM\n backdropRef.current?.contains(event.target as Node)\n ) {\n event.stopPropagation()\n onDismiss?.()\n }\n },\n [onDismiss],\n )\n\n React.useLayoutEffect(\n function disableAccessibilityTreeOutside() {\n if (!isOpen || !portalRef.current) {\n return\n }\n\n return hideOthers(portalRef.current)\n },\n [isOpen],\n )\n\n const handleKeyDown = React.useCallback(\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n if (\n hideOnEscape &&\n onDismiss != null &&\n event.key === 'Escape' &&\n !event.defaultPrevented\n ) {\n event.stopPropagation()\n onDismiss()\n }\n onKeyDown?.(event)\n },\n [onDismiss, hideOnEscape, onKeyDown],\n )\n\n if (!isOpen) {\n return null\n }\n\n return (\n <Portal portalRef={portalRef} portalElement={portalElement}>\n <Box\n data-testid=\"modal-overlay\"\n data-overlay\n className={classNames(\n styles.overlay,\n styles[height],\n styles[width],\n exceptionallySetOverlayClassName,\n )}\n /**\n * We're using `onPointerDown` instead of `onClick` to prevent\n * the modal from closing when the click starts inside the modal\n * and ends on the backdrop.\n */\n onPointerDown={hideOnInteractOutside ? handleBackdropClick : undefined}\n ref={backdropRef}\n >\n <FocusLock autoFocus={autoFocus} whiteList={isNotInternalFrame} returnFocus={true}>\n <Dialog\n {...props}\n ref={dialogRef}\n as={Box}\n store={store}\n preventBodyScroll\n borderRadius=\"full\"\n background=\"default\"\n display=\"flex\"\n flexDirection=\"column\"\n overflow=\"hidden\"\n height={height === 'expand' ? 'full' : undefined}\n flexGrow={height === 'expand' ? 1 : 0}\n className={[exceptionallySetClassName, styles.container]}\n // Disable focus lock as we set up our own using ReactFocusLock\n modal={false}\n autoFocus={false}\n autoFocusOnShow={false}\n autoFocusOnHide={false}\n // Disable portal and backdrop as we control their markup\n portal={false}\n backdrop={false}\n hideOnInteractOutside={false}\n hideOnEscape={false}\n onKeyDown={handleKeyDown}\n >\n <ModalContext.Provider value={contextValue}>\n {children}\n </ModalContext.Provider>\n </Dialog>\n </FocusLock>\n </Box>\n </Portal>\n )\n}\n\n//\n// ModalCloseButton\n//\n\nexport type ModalCloseButtonProps = Omit<\n IconButtonProps,\n 'type' | 'variant' | 'icon' | 'disabled' | 'loading' | 'tabIndex' | 'ref'\n> & {\n /**\n * The descriptive label of the button.\n */\n 'aria-label': string\n}\n\n/**\n * The close button rendered by ModalHeader. Provided independently so that consumers can customize\n * the button's label.\n *\n * @see ModalHeader\n */\nexport function ModalCloseButton(props: ModalCloseButtonProps) {\n const { onDismiss } = React.useContext(ModalContext)\n const [includeInTabOrder, setIncludeInTabOrder] = React.useState(false)\n const [isMounted, setIsMounted] = React.useState(false)\n\n React.useEffect(\n function skipAutoFocus() {\n if (isMounted) {\n setIncludeInTabOrder(true)\n } else {\n setIsMounted(true)\n }\n },\n [isMounted],\n )\n\n return (\n <IconButton\n {...props}\n variant=\"quaternary\"\n onClick={onDismiss}\n icon={<CloseIcon />}\n tabIndex={includeInTabOrder ? 0 : -1}\n />\n )\n}\n\n//\n// ModalHeader\n//\n\nexport type ModalHeaderProps = DivProps & {\n /**\n * The content of the header.\n */\n children: React.ReactNode\n\n /**\n * Allows to provide a custom button element, or to omit the close button if set to false.\n * @see ModalCloseButton\n */\n button?: React.ReactNode | boolean\n\n /**\n * Whether to render a divider line below the header.\n * @default false\n */\n withDivider?: boolean\n\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n}\n\n/**\n * Renders a standard modal header area with an optional close button.\n *\n * @see Modal\n * @see ModalFooter\n * @see ModalBody\n */\nexport function ModalHeader({\n children,\n button = true,\n withDivider = false,\n exceptionallySetClassName,\n ...props\n}: ModalHeaderProps) {\n return (\n <>\n <Box\n {...props}\n as=\"header\"\n paddingLeft=\"large\"\n paddingRight={button === false || button === null ? 'large' : 'small'}\n paddingY=\"small\"\n className={exceptionallySetClassName}\n >\n <Columns space=\"large\" alignY=\"center\">\n <Column width=\"auto\">{children}</Column>\n {button === false || button === null ? (\n <div className={styles.headerContent} />\n ) : (\n <Column\n width=\"content\"\n exceptionallySetClassName={styles.buttonContainer}\n data-testid=\"button-container\"\n >\n {typeof button === 'boolean' ? (\n <ModalCloseButton aria-label=\"Close modal\" autoFocus={false} />\n ) : (\n button\n )}\n </Column>\n )}\n </Columns>\n </Box>\n {withDivider ? <Divider /> : null}\n </>\n )\n}\n\n//\n// ModalBody\n//\n\nexport type ModalBodyProps = DivProps & {\n /**\n * The content of the modal body.\n */\n children: React.ReactNode\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n}\n\n/**\n * Renders the body of a modal.\n *\n * Convenient to use alongside ModalHeader and/or ModalFooter as needed. It ensures, among other\n * things, that the contet of the modal body expands or contracts depending on the modal height\n * setting or the size of the content. The body content also automatically scrolls when it's too\n * large to fit the available space.\n *\n * @see Modal\n * @see ModalHeader\n * @see ModalFooter\n */\nexport function ModalBody({ exceptionallySetClassName, children, ...props }: ModalBodyProps) {\n const { height } = React.useContext(ModalContext)\n return (\n <Box\n {...props}\n className={exceptionallySetClassName}\n flexGrow={height === 'expand' ? 1 : 0}\n height={height === 'expand' ? 'full' : undefined}\n overflow=\"auto\"\n >\n <Box padding=\"large\" paddingBottom=\"xxlarge\">\n {children}\n </Box>\n </Box>\n )\n}\n\n//\n// ModalFooter\n//\n\nexport type ModalFooterProps = DivProps & {\n /**\n * The contant of the modal footer.\n */\n children: React.ReactNode\n /**\n * Whether to render a divider line below the footer.\n * @default false\n */\n withDivider?: boolean\n /**\n * A escape hatch in case you need to provide a custom class name to the container element.\n */\n exceptionallySetClassName?: string\n}\n\n/**\n * Renders a standard modal footer area.\n *\n * @see Modal\n * @see ModalHeader\n * @see ModalBody\n */\nexport function ModalFooter({\n exceptionallySetClassName,\n withDivider = false,\n ...props\n}: ModalFooterProps) {\n return (\n <>\n {withDivider ? <Divider /> : null}\n <Box as=\"footer\" {...props} className={exceptionallySetClassName} padding=\"large\" />\n </>\n )\n}\n\n//\n// ModalActions\n//\n\nexport type ModalActionsProps = ModalFooterProps\n\n/**\n * A specific version of the ModalFooter, tailored to showing an inline list of actions (buttons).\n * @see ModalFooter\n */\nexport function ModalActions({ children, ...props }: ModalActionsProps) {\n return (\n <ModalFooter {...props}>\n <Inline align=\"right\" space=\"large\">\n {children}\n </Inline>\n </ModalFooter>\n )\n}\n"],"names":["ModalContext","React","onDismiss","undefined","height","isNotInternalFrame","element","ownerDocument","document","tagName","toLowerCase","ModalCloseButton","props","includeInTabOrder","setIncludeInTabOrder","isMounted","setIsMounted","IconButton","variant","onClick","icon","CloseIcon","tabIndex","ModalFooter","exceptionallySetClassName","withDivider","Divider","Box","as","className","padding","isOpen","width","exceptionallySetOverlayClassName","autoFocus","hideOnEscape","hideOnInteractOutside","children","portalElement","onKeyDown","setOpen","visible","store","useDialogStore","open","contextValue","portalRef","dialogRef","backdropRef","handleBackdropClick","event","current","_dialogRef$current","contains","target","_backdropRef$current","stopPropagation","hideOthers","handleKeyDown","key","defaultPrevented","Portal","classNames","styles","overlay","onPointerDown","ref","FocusLock","whiteList","returnFocus","Dialog","preventBodyScroll","borderRadius","background","display","flexDirection","overflow","flexGrow","container","modal","autoFocusOnShow","autoFocusOnHide","portal","backdrop","Provider","value","Inline","align","space","paddingBottom","button","paddingLeft","paddingRight","paddingY","Columns","alignY","Column","headerContent","buttonContainer"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../_virtual/_rollupPluginBabelHelpers.js"),r=require("react"),t=require("../button/button.js"),o=require("../icons/password-visible-icon.js"),s=require("../icons/password-hidden-icon.js"),i=require("../text-field/text-field.js");const a=["togglePasswordLabel"];exports.PasswordField=r.forwardRef((function(l,n){let{togglePasswordLabel:d="Toggle password visibility"}=l,c=e.objectWithoutProperties(l,a);const[u,b]=r.useState(!1),p=u?o.PasswordVisibleIcon:s.PasswordHiddenIcon;return r.createElement(i.TextField,e.objectSpread2(e.objectSpread2({},c),{},{ref:n,type:u?"text":"password",endSlot:r.createElement(t.Button,{variant:"quaternary",icon:r.createElement(p,{"aria-hidden":!0}),"aria-label":d,onClick:()=>b(e=>!e)})}))}));
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../_virtual/_rollupPluginBabelHelpers.js"),r=require("react"),t=require("../button/button.js"),o=require("../icons/password-visible-icon.js"),s=require("../icons/password-hidden-icon.js"),i=require("../text-field/text-field.js");const a=["togglePasswordLabel"];exports.PasswordField=r.forwardRef((function(l,n){let{togglePasswordLabel:d="Toggle password visibility"}=l,c=e.objectWithoutProperties(l,a);const[u,b]=r.useState(!1),p=u?o.PasswordVisibleIcon:s.PasswordHiddenIcon;return r.createElement(i.TextField,e.objectSpread2(e.objectSpread2({},c),{},{ref:n,type:u?"text":"password",endSlot:r.createElement(t.IconButton,{variant:"quaternary",icon:r.createElement(p,{"aria-hidden":!0}),"aria-label":d,onClick:()=>b(e=>!e)})}))}));
2
2
  //# sourceMappingURL=password-field.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"password-field.js","sources":["../../src/password-field/password-field.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport { PasswordVisibleIcon } from '../icons/password-visible-icon'\nimport { PasswordHiddenIcon } from '../icons/password-hidden-icon'\n\nimport { TextField, TextFieldProps } from '../text-field'\nimport { Button } from '../button'\n\nimport type { BaseFieldVariantProps } from '../base-field'\n\n/**\n * FIXME: This is a workaround for consumers that are using newer versions of React types that no longer have these props.\n * Once we upgrade Reactist to the newest React types, we should be able to remove these.\n */\ntype DeprecatedProps = 'crossOrigin' | 'onPointerEnterCapture' | 'onPointerLeaveCapture'\n\ntype PasswordFieldProps = Omit<TextFieldProps, 'type' | 'startSlot' | 'endSlot' | DeprecatedProps> &\n BaseFieldVariantProps & {\n togglePasswordLabel?: string\n }\n\nconst PasswordField = React.forwardRef<HTMLInputElement, PasswordFieldProps>(function PasswordField(\n { togglePasswordLabel = 'Toggle password visibility', ...props },\n ref,\n) {\n const [isPasswordVisible, setPasswordVisible] = React.useState(false)\n const Icon = isPasswordVisible ? PasswordVisibleIcon : PasswordHiddenIcon\n return (\n <TextField\n {...props}\n ref={ref}\n // @ts-expect-error TextField does not support type=\"password\", so we override the type check here\n type={isPasswordVisible ? 'text' : 'password'}\n endSlot={\n <Button\n variant=\"quaternary\"\n icon={<Icon aria-hidden />}\n aria-label={togglePasswordLabel}\n onClick={() => setPasswordVisible((v) => !v)}\n />\n }\n />\n )\n})\n\nexport { PasswordField }\nexport type { PasswordFieldProps }\n"],"names":["React","ref","togglePasswordLabel","props","isPasswordVisible","setPasswordVisible","Icon","PasswordVisibleIcon","PasswordHiddenIcon","TextField","type","endSlot","Button","variant","icon","onClick","v"],"mappings":"8WAqBsBA,cAAuD,WAEzEC,OADAC,oBAAEA,EAAsB,gCAAiCC,iCAGzD,MAAOC,EAAmBC,GAAsBL,YAAe,GACzDM,EAAOF,EAAoBG,sBAAsBC,qBACvD,OACIR,gBAACS,+CACON,OACJF,IAAKA,EAELS,KAAMN,EAAoB,OAAS,WACnCO,QACIX,gBAACY,UACGC,QAAQ,aACRC,KAAMd,gBAACM,mCACKJ,EACZa,QAAS,IAAMV,EAAoBW,IAAOA"}
1
+ {"version":3,"file":"password-field.js","sources":["../../src/password-field/password-field.tsx"],"sourcesContent":["import * as React from 'react'\n\nimport { PasswordVisibleIcon } from '../icons/password-visible-icon'\nimport { PasswordHiddenIcon } from '../icons/password-hidden-icon'\n\nimport { TextField, TextFieldProps } from '../text-field'\nimport { IconButton } from '../button'\n\nimport type { BaseFieldVariantProps } from '../base-field'\n\n/**\n * FIXME: This is a workaround for consumers that are using newer versions of React types that no longer have these props.\n * Once we upgrade Reactist to the newest React types, we should be able to remove these.\n */\ntype DeprecatedProps = 'crossOrigin' | 'onPointerEnterCapture' | 'onPointerLeaveCapture'\n\ntype PasswordFieldProps = Omit<TextFieldProps, 'type' | 'startSlot' | 'endSlot' | DeprecatedProps> &\n BaseFieldVariantProps & {\n togglePasswordLabel?: string\n }\n\nconst PasswordField = React.forwardRef<HTMLInputElement, PasswordFieldProps>(function PasswordField(\n { togglePasswordLabel = 'Toggle password visibility', ...props },\n ref,\n) {\n const [isPasswordVisible, setPasswordVisible] = React.useState(false)\n const Icon = isPasswordVisible ? PasswordVisibleIcon : PasswordHiddenIcon\n return (\n <TextField\n {...props}\n ref={ref}\n // @ts-expect-error TextField does not support type=\"password\", so we override the type check here\n type={isPasswordVisible ? 'text' : 'password'}\n endSlot={\n <IconButton\n variant=\"quaternary\"\n icon={<Icon aria-hidden />}\n aria-label={togglePasswordLabel}\n onClick={() => setPasswordVisible((v) => !v)}\n />\n }\n />\n )\n})\n\nexport { PasswordField }\nexport type { PasswordFieldProps }\n"],"names":["React","ref","togglePasswordLabel","props","isPasswordVisible","setPasswordVisible","Icon","PasswordVisibleIcon","PasswordHiddenIcon","TextField","type","endSlot","IconButton","variant","icon","onClick","v"],"mappings":"8WAqBsBA,cAAuD,WAEzEC,OADAC,oBAAEA,EAAsB,gCAAiCC,iCAGzD,MAAOC,EAAmBC,GAAsBL,YAAe,GACzDM,EAAOF,EAAoBG,sBAAsBC,qBACvD,OACIR,gBAACS,+CACON,OACJF,IAAKA,EAELS,KAAMN,EAAoB,OAAS,WACnCO,QACIX,gBAACY,cACGC,QAAQ,aACRC,KAAMd,gBAACM,mCACKJ,EACZa,QAAS,IAAMV,EAAoBW,IAAOA"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=require("../_virtual/_rollupPluginBabelHelpers.js"),l=(e=require("react"))&&"object"==typeof e&&"default"in e?e.default:e,n=require("../box/box.js"),r=require("../stack/stack.js"),a=require("../button/button.js"),i=require("../icons/close-icon.js"),o=require("../text/text.js"),s=require("./toast.module.css.js");const c=["message","description","icon","action","onDismiss","dismissLabel"];function u(e){return null!=e&&"object"==typeof e&&"label"in e&&"onClick"in e&&"string"==typeof e.label&&"function"==typeof e.onClick}function m({children:e}){return l.createElement(n.Box,{display:"flex",alignItems:"center",justifyContent:"center",marginX:"-xsmall",marginY:"-medium",className:s.default.slot},e)}exports.StaticToast=l.forwardRef((function(e,d){let{message:f,description:b,icon:p,action:x,onDismiss:j,dismissLabel:E="Close"}=e,g=t.objectWithoutProperties(e,c);return l.createElement(n.Box,t.objectSpread2({ref:d,role:"alert","aria-live":"polite",borderRadius:"full",width:"fitContent",background:"toast",display:"flex",padding:"large",alignItems:"center",className:s.default.toastContainer},g),p?l.createElement(m,null,p):null,l.createElement(n.Box,{flexGrow:1,maxWidth:"small"},b?l.createElement(r.Stack,{space:"small"},l.createElement(o.Text,{weight:"bold"},f," "),l.createElement(o.Text,null,b)):l.createElement(o.Text,null,f)),x?l.createElement(m,null,u(x)?l.createElement(a.Button,{variant:"tertiary",size:"small",onClick:x.onClick},x.label):x):null,j?l.createElement(m,null,l.createElement(a.Button,{variant:"quaternary",size:"small",onClick:j,"aria-label":E,icon:l.createElement(i.CloseIcon,null)})):null)})),exports.isActionObject=u;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=require("../_virtual/_rollupPluginBabelHelpers.js"),l=(e=require("react"))&&"object"==typeof e&&"default"in e?e.default:e,n=require("../box/box.js"),r=require("../stack/stack.js"),a=require("../button/button.js"),i=require("../icons/close-icon.js"),o=require("../text/text.js"),s=require("./toast.module.css.js");const c=["message","description","icon","action","onDismiss","dismissLabel"];function u(e){return null!=e&&"object"==typeof e&&"label"in e&&"onClick"in e&&"string"==typeof e.label&&"function"==typeof e.onClick}function m({children:e}){return l.createElement(n.Box,{display:"flex",alignItems:"center",justifyContent:"center",marginX:"-xsmall",marginY:"-medium",className:s.default.slot},e)}exports.StaticToast=l.forwardRef((function(e,d){let{message:f,description:b,icon:p,action:x,onDismiss:j,dismissLabel:E="Close"}=e,g=t.objectWithoutProperties(e,c);return l.createElement(n.Box,t.objectSpread2({ref:d,role:"alert","aria-live":"polite",borderRadius:"full",width:"fitContent",background:"toast",display:"flex",padding:"large",alignItems:"center",className:s.default.toastContainer},g),p?l.createElement(m,null,p):null,l.createElement(n.Box,{flexGrow:1,maxWidth:"small"},b?l.createElement(r.Stack,{space:"small"},l.createElement(o.Text,{weight:"bold"},f," "),l.createElement(o.Text,null,b)):l.createElement(o.Text,null,f)),x?l.createElement(m,null,u(x)?l.createElement(a.Button,{variant:"tertiary",size:"small",onClick:x.onClick},x.label):x):null,j?l.createElement(m,null,l.createElement(a.IconButton,{variant:"quaternary",size:"small",onClick:j,"aria-label":E,icon:l.createElement(i.CloseIcon,null)})):null)})),exports.isActionObject=u;
2
2
  //# sourceMappingURL=static-toast.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"static-toast.js","sources":["../../src/toast/static-toast.tsx"],"sourcesContent":["import React from 'react'\n\nimport { CloseIcon } from '../icons/close-icon'\nimport { Box } from '../box'\nimport { Button } from '../button'\nimport { Stack } from '../stack'\nimport { Text } from '../text'\n\nimport styles from './toast.module.css'\n\ntype ToastActionObject = {\n label: string\n onClick: () => void\n}\n\ntype StaticToastProps = {\n /**\n * The message shown in the toast.\n */\n message: NonNullable<React.ReactNode>\n\n /**\n * An optional extra description that complements the main message shown in the toast.\n */\n description?: React.ReactNode\n\n /**\n * An icon to be shown in front of the message.\n */\n icon?: React.ReactNode\n\n /**\n * The action to call when the user clicks on the dismiss button. If omitted, the dismiss button\n * does not appear.\n */\n onDismiss?: () => void\n\n /**\n * The label for the button that dismisses the toast.\n */\n dismissLabel?: string\n\n /**\n * What to render in the action slot. Usually a button or link.\n *\n * You can also pass an object that containst the action label, and a function that performs the\n * action. This is used by the toast component to render a button for you.\n *\n * In general, you should prefer the action object most of the time. But it is possible to pass\n * a React element instead, if you need more control over what to render. For instance, you may\n * want to render a link instead of a button.\n *\n * Keep in mind, though, that the default button rendered uses `variant=\"tertiary\"` and\n * `size=\"small\"`. In most cases you should stick to the variants `tertiary` or `primary`, which\n * are the ones that look better in the toast's dark background. And in all cases you should use\n * size `small`.\n */\n action?: React.ReactElement | ToastActionObject\n}\n\n/**\n * A toast that shows a message, and an optional action associated with it.\n *\n * This component is generally not meant to be used directly. Most of the time you'll want to use\n * toasts generated via `useToasts` instead. However, this component is available in case you need\n * to take control of rendering a toast under different circumstances than that of notification-like\n * floating toasts.\n *\n * This component makes no assumptions outwardly about how it is positioned on the screen. That is,\n * it will not be shown floating or fixed to the viewport edges, as toasts normally show up. It only\n * provides the toast look and feel, but you are responsible for positioning it as you want.\n *\n * @see useToasts\n */\nconst StaticToast = React.forwardRef<HTMLDivElement, StaticToastProps>(function Toast(\n { message, description, icon, action, onDismiss, dismissLabel = 'Close', ...props },\n ref,\n) {\n return (\n <Box\n ref={ref}\n role=\"alert\"\n aria-live=\"polite\"\n borderRadius=\"full\"\n width=\"fitContent\"\n background=\"toast\"\n display=\"flex\"\n padding=\"large\"\n alignItems=\"center\"\n className={styles.toastContainer}\n {...props}\n >\n {icon ? <ToastContentSlot>{icon}</ToastContentSlot> : null}\n\n <Box flexGrow={1} maxWidth=\"small\">\n {description ? (\n <Stack space=\"small\">\n <Text weight=\"bold\">{message} </Text>\n <Text>{description}</Text>\n </Stack>\n ) : (\n <Text>{message}</Text>\n )}\n </Box>\n\n {action ? (\n <ToastContentSlot>\n {isActionObject(action) ? (\n <Button variant=\"tertiary\" size=\"small\" onClick={action.onClick}>\n {action.label}\n </Button>\n ) : (\n action\n )}\n </ToastContentSlot>\n ) : null}\n\n {onDismiss ? (\n <ToastContentSlot>\n <Button\n variant=\"quaternary\"\n size=\"small\"\n onClick={onDismiss}\n aria-label={dismissLabel}\n icon={<CloseIcon />}\n />\n </ToastContentSlot>\n ) : null}\n </Box>\n )\n})\n\nfunction isActionObject(action: StaticToastProps['action']): action is ToastActionObject {\n return (\n action != null &&\n typeof action === 'object' &&\n 'label' in action &&\n 'onClick' in action &&\n typeof action.label === 'string' &&\n typeof action.onClick === 'function'\n )\n}\n\nfunction ToastContentSlot({ children }: { children: React.ReactNode }) {\n return (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n marginX=\"-xsmall\"\n marginY=\"-medium\"\n className={styles.slot}\n >\n {children}\n </Box>\n )\n}\n\nexport { StaticToast, isActionObject }\nexport type { StaticToastProps }\n"],"names":["isActionObject","action","label","onClick","ToastContentSlot","children","React","Box","display","alignItems","justifyContent","marginX","marginY","className","styles","slot","forwardRef","ref","message","description","icon","onDismiss","dismissLabel","props","role","borderRadius","width","background","padding","toastContainer","flexGrow","maxWidth","Stack","space","Text","weight","Button","variant","size","CloseIcon"],"mappings":"kdAoIA,SAASA,EAAeC,GACpB,OACc,MAAVA,GACkB,iBAAXA,GACP,UAAWA,GACX,YAAaA,GACW,iBAAjBA,EAAOC,OACY,mBAAnBD,EAAOE,QAItB,SAASC,GAAiBC,SAAEA,IACxB,OACIC,gBAACC,OACGC,QAAQ,OACRC,WAAW,SACXC,eAAe,SACfC,QAAQ,UACRC,QAAQ,UACRC,UAAWC,UAAOC,MAEjBV,uBA/EOC,EAAMU,YAA6C,WAEnEC,OADAC,QAAEA,EAAFC,YAAWA,EAAXC,KAAwBA,EAAxBnB,OAA8BA,EAA9BoB,UAAsCA,EAAtCC,aAAiDA,EAAe,WAAYC,iCAG5E,OACIjB,gBAACC,uBACGU,IAAKA,EACLO,KAAK,oBACK,SACVC,aAAa,OACbC,MAAM,aACNC,WAAW,QACXnB,QAAQ,OACRoB,QAAQ,QACRnB,WAAW,SACXI,UAAWC,UAAOe,gBACdN,GAEHH,EAAOd,gBAACF,OAAkBgB,GAA2B,KAEtDd,gBAACC,OAAIuB,SAAU,EAAGC,SAAS,SACtBZ,EACGb,gBAAC0B,SAAMC,MAAM,SACT3B,gBAAC4B,QAAKC,OAAO,QAAQjB,OACrBZ,gBAAC4B,YAAMf,IAGXb,gBAAC4B,YAAMhB,IAIdjB,EACGK,gBAACF,OACIJ,EAAeC,GACZK,gBAAC8B,UAAOC,QAAQ,WAAWC,KAAK,QAAQnC,QAASF,EAAOE,SACnDF,EAAOC,OAGZD,GAGR,KAEHoB,EACGf,gBAACF,OACGE,gBAAC8B,UACGC,QAAQ,aACRC,KAAK,QACLnC,QAASkB,eACGC,EACZF,KAAMd,gBAACiC,qBAGf"}
1
+ {"version":3,"file":"static-toast.js","sources":["../../src/toast/static-toast.tsx"],"sourcesContent":["import React from 'react'\n\nimport { CloseIcon } from '../icons/close-icon'\nimport { Box } from '../box'\nimport { IconButton, Button } from '../button'\nimport { Stack } from '../stack'\nimport { Text } from '../text'\n\nimport styles from './toast.module.css'\n\ntype ToastActionObject = {\n label: string\n onClick: () => void\n}\n\ntype StaticToastProps = {\n /**\n * The message shown in the toast.\n */\n message: NonNullable<React.ReactNode>\n\n /**\n * An optional extra description that complements the main message shown in the toast.\n */\n description?: React.ReactNode\n\n /**\n * An icon to be shown in front of the message.\n */\n icon?: React.ReactNode\n\n /**\n * The action to call when the user clicks on the dismiss button. If omitted, the dismiss button\n * does not appear.\n */\n onDismiss?: () => void\n\n /**\n * The label for the button that dismisses the toast.\n */\n dismissLabel?: string\n\n /**\n * What to render in the action slot. Usually a button or link.\n *\n * You can also pass an object that containst the action label, and a function that performs the\n * action. This is used by the toast component to render a button for you.\n *\n * In general, you should prefer the action object most of the time. But it is possible to pass\n * a React element instead, if you need more control over what to render. For instance, you may\n * want to render a link instead of a button.\n *\n * Keep in mind, though, that the default button rendered uses `variant=\"tertiary\"` and\n * `size=\"small\"`. In most cases you should stick to the variants `tertiary` or `primary`, which\n * are the ones that look better in the toast's dark background. And in all cases you should use\n * size `small`.\n */\n action?: React.ReactElement | ToastActionObject\n}\n\n/**\n * A toast that shows a message, and an optional action associated with it.\n *\n * This component is generally not meant to be used directly. Most of the time you'll want to use\n * toasts generated via `useToasts` instead. However, this component is available in case you need\n * to take control of rendering a toast under different circumstances than that of notification-like\n * floating toasts.\n *\n * This component makes no assumptions outwardly about how it is positioned on the screen. That is,\n * it will not be shown floating or fixed to the viewport edges, as toasts normally show up. It only\n * provides the toast look and feel, but you are responsible for positioning it as you want.\n *\n * @see useToasts\n */\nconst StaticToast = React.forwardRef<HTMLDivElement, StaticToastProps>(function Toast(\n { message, description, icon, action, onDismiss, dismissLabel = 'Close', ...props },\n ref,\n) {\n return (\n <Box\n ref={ref}\n role=\"alert\"\n aria-live=\"polite\"\n borderRadius=\"full\"\n width=\"fitContent\"\n background=\"toast\"\n display=\"flex\"\n padding=\"large\"\n alignItems=\"center\"\n className={styles.toastContainer}\n {...props}\n >\n {icon ? <ToastContentSlot>{icon}</ToastContentSlot> : null}\n\n <Box flexGrow={1} maxWidth=\"small\">\n {description ? (\n <Stack space=\"small\">\n <Text weight=\"bold\">{message} </Text>\n <Text>{description}</Text>\n </Stack>\n ) : (\n <Text>{message}</Text>\n )}\n </Box>\n\n {action ? (\n <ToastContentSlot>\n {isActionObject(action) ? (\n <Button variant=\"tertiary\" size=\"small\" onClick={action.onClick}>\n {action.label}\n </Button>\n ) : (\n action\n )}\n </ToastContentSlot>\n ) : null}\n\n {onDismiss ? (\n <ToastContentSlot>\n <IconButton\n variant=\"quaternary\"\n size=\"small\"\n onClick={onDismiss}\n aria-label={dismissLabel}\n icon={<CloseIcon />}\n />\n </ToastContentSlot>\n ) : null}\n </Box>\n )\n})\n\nfunction isActionObject(action: StaticToastProps['action']): action is ToastActionObject {\n return (\n action != null &&\n typeof action === 'object' &&\n 'label' in action &&\n 'onClick' in action &&\n typeof action.label === 'string' &&\n typeof action.onClick === 'function'\n )\n}\n\nfunction ToastContentSlot({ children }: { children: React.ReactNode }) {\n return (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n marginX=\"-xsmall\"\n marginY=\"-medium\"\n className={styles.slot}\n >\n {children}\n </Box>\n )\n}\n\nexport { StaticToast, isActionObject }\nexport type { StaticToastProps }\n"],"names":["isActionObject","action","label","onClick","ToastContentSlot","children","React","Box","display","alignItems","justifyContent","marginX","marginY","className","styles","slot","forwardRef","ref","message","description","icon","onDismiss","dismissLabel","props","role","borderRadius","width","background","padding","toastContainer","flexGrow","maxWidth","Stack","space","Text","weight","Button","variant","size","IconButton","CloseIcon"],"mappings":"kdAoIA,SAASA,EAAeC,GACpB,OACc,MAAVA,GACkB,iBAAXA,GACP,UAAWA,GACX,YAAaA,GACW,iBAAjBA,EAAOC,OACY,mBAAnBD,EAAOE,QAItB,SAASC,GAAiBC,SAAEA,IACxB,OACIC,gBAACC,OACGC,QAAQ,OACRC,WAAW,SACXC,eAAe,SACfC,QAAQ,UACRC,QAAQ,UACRC,UAAWC,UAAOC,MAEjBV,uBA/EOC,EAAMU,YAA6C,WAEnEC,OADAC,QAAEA,EAAFC,YAAWA,EAAXC,KAAwBA,EAAxBnB,OAA8BA,EAA9BoB,UAAsCA,EAAtCC,aAAiDA,EAAe,WAAYC,iCAG5E,OACIjB,gBAACC,uBACGU,IAAKA,EACLO,KAAK,oBACK,SACVC,aAAa,OACbC,MAAM,aACNC,WAAW,QACXnB,QAAQ,OACRoB,QAAQ,QACRnB,WAAW,SACXI,UAAWC,UAAOe,gBACdN,GAEHH,EAAOd,gBAACF,OAAkBgB,GAA2B,KAEtDd,gBAACC,OAAIuB,SAAU,EAAGC,SAAS,SACtBZ,EACGb,gBAAC0B,SAAMC,MAAM,SACT3B,gBAAC4B,QAAKC,OAAO,QAAQjB,OACrBZ,gBAAC4B,YAAMf,IAGXb,gBAAC4B,YAAMhB,IAIdjB,EACGK,gBAACF,OACIJ,EAAeC,GACZK,gBAAC8B,UAAOC,QAAQ,WAAWC,KAAK,QAAQnC,QAASF,EAAOE,SACnDF,EAAOC,OAGZD,GAGR,KAEHoB,EACGf,gBAACF,OACGE,gBAACiC,cACGF,QAAQ,aACRC,KAAK,QACLnC,QAASkB,eACGC,EACZF,KAAMd,gBAACkC,qBAGf"}
@@ -20,4 +20,23 @@ export interface OpenInNewTab {
20
20
  target?: never;
21
21
  rel?: never;
22
22
  }
23
+ export declare type ObfuscatedClassName = {
24
+ /**
25
+ * Used internally to set the `className` prop of the main container element for this component.
26
+ *
27
+ * Aside from the different name, the prop behaves the same as the native `className`. The only
28
+ * reason for the name change is to discourage applying custom CSS to the design system
29
+ * components, which are supposed to _eventually_ provide all the styling features we may need.
30
+ *
31
+ * This prop is meant to be used only in certain circumstances, when you really need a escape
32
+ * hatch to apply custom styles to a component. Before reaching for this feature, try harder to
33
+ * see if you can solve your needs with what the design system provides.
34
+ *
35
+ * For instance, instead of applying layout-related styles to a non-layout component, consider
36
+ * wrapping it inside a layout component.
37
+ *
38
+ * @see PolymorphicComponent
39
+ */
40
+ exceptionallySetClassName?: string;
41
+ };
23
42
  export {};
@@ -1,28 +1,10 @@
1
1
  import * as React from 'react';
2
+ import type { ObfuscatedClassName } from './common-types';
2
3
  declare type Merge<P1, P2> = Omit<P1, keyof P2> & P2;
3
4
  declare type EmptyObject = {
4
5
  [K in any]: never;
5
6
  };
6
7
  declare type ObfuscateClassNameMode = 'keepClassName' | 'obfuscateClassName' | 'omitClassName';
7
- declare type ObfuscatedClassName = {
8
- /**
9
- * Used internally to set the `className` prop of the main container element for this component.
10
- *
11
- * Aside from the different name, the prop behaves the same as the native `className`. The only
12
- * reason for the name change is to discourage applying custom CSS to the design system
13
- * components, which are supposed to _eventually_ provide all the styling features we may need.
14
- *
15
- * This prop is meant to be used only in certain circumstances, when you really need a escape
16
- * hatch to apply custom styles to a component. Before reaching for this feature, try harder to
17
- * see if you can solve your needs with what the design system provides.
18
- *
19
- * For instance, instead of applying layout-related styles to a non-layout component, consider
20
- * wrapping it inside a layout component.
21
- *
22
- * @see PolymorphicComponent
23
- */
24
- exceptionallySetClassName?: string;
25
- };
26
8
  /**
27
9
  * If a set of props include the `className` prop, we replace it with a `exceptionallySetClassName`
28
10
  * prop instead.
@@ -1 +1 @@
1
- {"version":3,"file":"polymorphism.js","sources":["../../src/utils/polymorphism.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport * as React from 'react'\n\ntype Merge<P1, P2> = Omit<P1, keyof P2> & P2\n\ntype EmptyObject = {\n [K in any]: never\n}\n\ntype ObfuscateClassNameMode = 'keepClassName' | 'obfuscateClassName' | 'omitClassName'\n\ntype ObfuscatedClassName = {\n /**\n * Used internally to set the `className` prop of the main container element for this component.\n *\n * Aside from the different name, the prop behaves the same as the native `className`. The only\n * reason for the name change is to discourage applying custom CSS to the design system\n * components, which are supposed to _eventually_ provide all the styling features we may need.\n *\n * This prop is meant to be used only in certain circumstances, when you really need a escape\n * hatch to apply custom styles to a component. Before reaching for this feature, try harder to\n * see if you can solve your needs with what the design system provides.\n *\n * For instance, instead of applying layout-related styles to a non-layout component, consider\n * wrapping it inside a layout component.\n *\n * @see PolymorphicComponent\n */\n exceptionallySetClassName?: string\n}\n\n/**\n * If a set of props include the `className` prop, we replace it with a `exceptionallySetClassName`\n * prop instead.\n *\n * This can be customized via the second generic parameter, as there are cases where it may be\n * needed to omit this behaviour and keep the `className`. You can also instruct it to remove the\n * `className` prop while not replacing it with the `exceptionallySetClassName` one.\n *\n * @see ObfuscatedClassName['exceptionallySetClassName'] for details about this prop\n * @see PolymorphicComponent for details about this feature\n */\ntype WithObfuscatedClassName<\n Props,\n ShouldObfuscateClassName extends ObfuscateClassNameMode\n> = 'className' extends keyof Props\n ? ShouldObfuscateClassName extends 'obfuscateClassName'\n ? Omit<Props, 'className'> & ObfuscatedClassName\n : ShouldObfuscateClassName extends 'omitClassName'\n ? Omit<Props, 'className'>\n : ShouldObfuscateClassName extends 'keepClassName'\n ? Props\n : never\n : Props\n\ntype PolymorphicProp<ComponentType extends React.ElementType> = {\n /**\n * Used to instruct this component what React element to render as. It can be both a string\n * representing a HTML tag name, or a React component.\n *\n * When using this prop, the component you apply it to will also recognize in its props types\n * all the props from the component or HTML element you are rendering it as.\n *\n * Some uses for this feature:\n *\n * - Using some of our layout components, while at the same time being able to set them to use\n * semantic HTML elements needed for accessibility purposes (e.g. `nav`, `main`, etc).\n * - Using a design system link component, but have it internally use a client-side router link\n * implemented via a React component (e.g. react-router's `Link`).\n *\n * Keep in mind that not all compositions of this kind may work well, especially when composing\n * with another React component and not with a HTML tag name. In particular, if the components\n * being composed have opposing concerns of clashing features (e.g. they have contradicting\n * styles applied to them) things may not go well. In those cases prefer to nest them instead.\n *\n * @see PolymorphicComponent\n */\n as?: ComponentType\n}\n\n/**\n * Given a component or element type, and a set of additional props, this builds the entire set of\n * props for a polymorphic component.\n *\n * It does three things:\n *\n * 1. it merges the element type props with the `OwnProps`\n * 2. it adds the `as` prop to allow for polymorphism to happen\n * 3. it optionally obfuscates or omits the className prop if present\n *\n * @see PolymorphicProp\n * @see WithObfuscatedClassName\n */\ntype PolymorphicComponentProps<\n ComponentType extends React.ElementType,\n OwnProps,\n ShouldObfuscateClassName extends ObfuscateClassNameMode\n> = Merge<\n WithObfuscatedClassName<React.ComponentProps<ComponentType>, ShouldObfuscateClassName>,\n OwnProps & PolymorphicProp<ComponentType>\n>\n\ntype ElementTagNameMap = HTMLElementTagNameMap &\n Pick<SVGElementTagNameMap, Exclude<keyof SVGElementTagNameMap, keyof HTMLElementTagNameMap>>\n\ntype ElementByTag<TagName extends keyof ElementTagNameMap> = ElementTagNameMap[TagName]\n\ntype ElementByTagOrAny<\n ComponentType extends React.ElementType\n> = ComponentType extends keyof ElementTagNameMap ? ElementByTag<ComponentType> : any\n\n/**\n * The function passed to React.forwardRef, but typed in a way that's prepared for polymorphism via\n * the `as` prop. It also allows to specify if the `className` prop should be obfuscated or omitted.\n *\n * @see PolymorphicComponentProps\n * @see WithObfuscatedClassName\n */\ninterface ForwardRefFunction<\n ComponentType extends React.ElementType,\n OwnProps,\n ShouldObfuscateClassName extends ObfuscateClassNameMode\n> {\n (\n props: PolymorphicComponentProps<ComponentType, OwnProps, ShouldObfuscateClassName>,\n ref:\n | ((instance: ElementByTagOrAny<ComponentType> | null) => void)\n | React.MutableRefObject<ElementByTagOrAny<ComponentType> | null>\n | null,\n ): React.ReactElement | null\n displayName?: string\n}\n\n/**\n * A component that can customize the React element type that it renders (a.k.a. a polymorphic\n * component). This is achieved by passing a prop `as={ElementType}` or `as=\"html-tag-name\"`.\n *\n * It transparently takes care of forwarding refs, and properly sets the ref type depending on the\n * element type.\n *\n * ## Recognizing props based on the polymorphic type\n *\n * The `ComponentType` argument sets the default type for the `as` prop. Whatever the `as` prop\n * component or HTML element is, the type system will automatically allow you to pass props that are\n * not explicitly defined by you, but that are recognized as valid props to be passed to the\n * component you are rendering.\n *\n * For instance, see the following example:\n *\n * ```jsx\n * <Box as=\"label\" htmlFor=\"field-id\">Hello</Box>\n * ```\n *\n * The `htmlFor` prop is exclusive to label elements. If you omit the `as=\"label\"` prop, the type\n * system will consider the `htmlFor` prop to be an error. The same happens if you pass a value of\n * an incorrect type to such prop. For instance, the example below will issue a type error:\n *\n * ```jsx\n * <Box as=\"label\" htmlFor={123}>Hello</Box>\n * ```\n *\n * ## Omitting or obfuscating the `className` prop\n *\n * If a set of props include the `className` prop, we replace it with a `exceptionallySetClassName`\n * prop instead.\n *\n * This is to discourage customizing design system components via custom styling, while still\n * leaving the door open to do it as an escape hatch when the design system still has shortcomings\n * with respect to the product designs we want to achieve.\n *\n * The cumbersome name also serves the purpose of aiding in easily searching for the places in the\n * code where this escape hatch was needed, in order to identify areas where the design system\n * components need to improve to better match our needs.\n *\n * This behaviour can be customized via an optional second generic argument that allows to disable\n * this feature, or to omit the `className` altogether without replacing it with the obfuscated prop\n * name.\n */\ninterface PolymorphicComponent<\n ComponentType extends React.ElementType,\n OwnProps,\n ShouldObfuscateClassName extends ObfuscateClassNameMode = 'obfuscateClassName'\n> {\n <TT extends React.ElementType = ComponentType>(\n props: PolymorphicComponentProps<TT, OwnProps, ShouldObfuscateClassName>,\n ): React.ReactElement | null\n readonly $$typeof: symbol\n defaultProps?: Partial<\n PolymorphicComponentProps<ComponentType, OwnProps, ShouldObfuscateClassName>\n >\n propTypes?: React.WeakValidationMap<\n PolymorphicComponentProps<ComponentType, OwnProps, ShouldObfuscateClassName>\n >\n displayName?: string\n}\n\n/**\n * A wrapper to use React.forwardRef with polymorphic components in a type-safe manner. This is a\n * convenience over merely using React.forwardRef directly, and then manually forcing the resulting\n * value to be typed using `as PolymorphicComponent<…>`.\n *\n * @see PolymorphicComponent for details about what this type does\n */\nfunction polymorphicComponent<\n ComponentType extends React.ElementType = 'div',\n OwnProps = EmptyObject,\n ShouldObfuscateClassName extends ObfuscateClassNameMode = 'obfuscateClassName'\n>(render: ForwardRefFunction<ComponentType, OwnProps, ShouldObfuscateClassName>) {\n return React.forwardRef(render) as PolymorphicComponent<\n ComponentType,\n OwnProps,\n ShouldObfuscateClassName\n >\n}\n\nexport type { PolymorphicComponent, ObfuscatedClassName }\nexport { polymorphicComponent }\n"],"names":["render","React"],"mappings":"wHA4MA,SAIEA,GACE,OAAOC,aAAiBD"}
1
+ {"version":3,"file":"polymorphism.js","sources":["../../src/utils/polymorphism.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport * as React from 'react'\nimport type { ObfuscatedClassName } from './common-types'\n\ntype Merge<P1, P2> = Omit<P1, keyof P2> & P2\n\ntype EmptyObject = {\n [K in any]: never\n}\n\ntype ObfuscateClassNameMode = 'keepClassName' | 'obfuscateClassName' | 'omitClassName'\n\n/**\n * If a set of props include the `className` prop, we replace it with a `exceptionallySetClassName`\n * prop instead.\n *\n * This can be customized via the second generic parameter, as there are cases where it may be\n * needed to omit this behaviour and keep the `className`. You can also instruct it to remove the\n * `className` prop while not replacing it with the `exceptionallySetClassName` one.\n *\n * @see ObfuscatedClassName['exceptionallySetClassName'] for details about this prop\n * @see PolymorphicComponent for details about this feature\n */\ntype WithObfuscatedClassName<\n Props,\n ShouldObfuscateClassName extends ObfuscateClassNameMode\n> = 'className' extends keyof Props\n ? ShouldObfuscateClassName extends 'obfuscateClassName'\n ? Omit<Props, 'className'> & ObfuscatedClassName\n : ShouldObfuscateClassName extends 'omitClassName'\n ? Omit<Props, 'className'>\n : ShouldObfuscateClassName extends 'keepClassName'\n ? Props\n : never\n : Props\n\ntype PolymorphicProp<ComponentType extends React.ElementType> = {\n /**\n * Used to instruct this component what React element to render as. It can be both a string\n * representing a HTML tag name, or a React component.\n *\n * When using this prop, the component you apply it to will also recognize in its props types\n * all the props from the component or HTML element you are rendering it as.\n *\n * Some uses for this feature:\n *\n * - Using some of our layout components, while at the same time being able to set them to use\n * semantic HTML elements needed for accessibility purposes (e.g. `nav`, `main`, etc).\n * - Using a design system link component, but have it internally use a client-side router link\n * implemented via a React component (e.g. react-router's `Link`).\n *\n * Keep in mind that not all compositions of this kind may work well, especially when composing\n * with another React component and not with a HTML tag name. In particular, if the components\n * being composed have opposing concerns of clashing features (e.g. they have contradicting\n * styles applied to them) things may not go well. In those cases prefer to nest them instead.\n *\n * @see PolymorphicComponent\n */\n as?: ComponentType\n}\n\n/**\n * Given a component or element type, and a set of additional props, this builds the entire set of\n * props for a polymorphic component.\n *\n * It does three things:\n *\n * 1. it merges the element type props with the `OwnProps`\n * 2. it adds the `as` prop to allow for polymorphism to happen\n * 3. it optionally obfuscates or omits the className prop if present\n *\n * @see PolymorphicProp\n * @see WithObfuscatedClassName\n */\ntype PolymorphicComponentProps<\n ComponentType extends React.ElementType,\n OwnProps,\n ShouldObfuscateClassName extends ObfuscateClassNameMode\n> = Merge<\n WithObfuscatedClassName<React.ComponentProps<ComponentType>, ShouldObfuscateClassName>,\n OwnProps & PolymorphicProp<ComponentType>\n>\n\ntype ElementTagNameMap = HTMLElementTagNameMap &\n Pick<SVGElementTagNameMap, Exclude<keyof SVGElementTagNameMap, keyof HTMLElementTagNameMap>>\n\ntype ElementByTag<TagName extends keyof ElementTagNameMap> = ElementTagNameMap[TagName]\n\ntype ElementByTagOrAny<\n ComponentType extends React.ElementType\n> = ComponentType extends keyof ElementTagNameMap ? ElementByTag<ComponentType> : any\n\n/**\n * The function passed to React.forwardRef, but typed in a way that's prepared for polymorphism via\n * the `as` prop. It also allows to specify if the `className` prop should be obfuscated or omitted.\n *\n * @see PolymorphicComponentProps\n * @see WithObfuscatedClassName\n */\ninterface ForwardRefFunction<\n ComponentType extends React.ElementType,\n OwnProps,\n ShouldObfuscateClassName extends ObfuscateClassNameMode\n> {\n (\n props: PolymorphicComponentProps<ComponentType, OwnProps, ShouldObfuscateClassName>,\n ref:\n | ((instance: ElementByTagOrAny<ComponentType> | null) => void)\n | React.MutableRefObject<ElementByTagOrAny<ComponentType> | null>\n | null,\n ): React.ReactElement | null\n displayName?: string\n}\n\n/**\n * A component that can customize the React element type that it renders (a.k.a. a polymorphic\n * component). This is achieved by passing a prop `as={ElementType}` or `as=\"html-tag-name\"`.\n *\n * It transparently takes care of forwarding refs, and properly sets the ref type depending on the\n * element type.\n *\n * ## Recognizing props based on the polymorphic type\n *\n * The `ComponentType` argument sets the default type for the `as` prop. Whatever the `as` prop\n * component or HTML element is, the type system will automatically allow you to pass props that are\n * not explicitly defined by you, but that are recognized as valid props to be passed to the\n * component you are rendering.\n *\n * For instance, see the following example:\n *\n * ```jsx\n * <Box as=\"label\" htmlFor=\"field-id\">Hello</Box>\n * ```\n *\n * The `htmlFor` prop is exclusive to label elements. If you omit the `as=\"label\"` prop, the type\n * system will consider the `htmlFor` prop to be an error. The same happens if you pass a value of\n * an incorrect type to such prop. For instance, the example below will issue a type error:\n *\n * ```jsx\n * <Box as=\"label\" htmlFor={123}>Hello</Box>\n * ```\n *\n * ## Omitting or obfuscating the `className` prop\n *\n * If a set of props include the `className` prop, we replace it with a `exceptionallySetClassName`\n * prop instead.\n *\n * This is to discourage customizing design system components via custom styling, while still\n * leaving the door open to do it as an escape hatch when the design system still has shortcomings\n * with respect to the product designs we want to achieve.\n *\n * The cumbersome name also serves the purpose of aiding in easily searching for the places in the\n * code where this escape hatch was needed, in order to identify areas where the design system\n * components need to improve to better match our needs.\n *\n * This behaviour can be customized via an optional second generic argument that allows to disable\n * this feature, or to omit the `className` altogether without replacing it with the obfuscated prop\n * name.\n */\ninterface PolymorphicComponent<\n ComponentType extends React.ElementType,\n OwnProps,\n ShouldObfuscateClassName extends ObfuscateClassNameMode = 'obfuscateClassName'\n> {\n <TT extends React.ElementType = ComponentType>(\n props: PolymorphicComponentProps<TT, OwnProps, ShouldObfuscateClassName>,\n ): React.ReactElement | null\n readonly $$typeof: symbol\n defaultProps?: Partial<\n PolymorphicComponentProps<ComponentType, OwnProps, ShouldObfuscateClassName>\n >\n propTypes?: React.WeakValidationMap<\n PolymorphicComponentProps<ComponentType, OwnProps, ShouldObfuscateClassName>\n >\n displayName?: string\n}\n\n/**\n * A wrapper to use React.forwardRef with polymorphic components in a type-safe manner. This is a\n * convenience over merely using React.forwardRef directly, and then manually forcing the resulting\n * value to be typed using `as PolymorphicComponent<…>`.\n *\n * @see PolymorphicComponent for details about what this type does\n */\nfunction polymorphicComponent<\n ComponentType extends React.ElementType = 'div',\n OwnProps = EmptyObject,\n ShouldObfuscateClassName extends ObfuscateClassNameMode = 'obfuscateClassName'\n>(render: ForwardRefFunction<ComponentType, OwnProps, ShouldObfuscateClassName>) {\n return React.forwardRef(render) as PolymorphicComponent<\n ComponentType,\n OwnProps,\n ShouldObfuscateClassName\n >\n}\n\nexport type { PolymorphicComponent, ObfuscatedClassName }\nexport { polymorphicComponent }\n"],"names":["render","React"],"mappings":"wHAyLA,SAIEA,GACE,OAAOC,aAAiBD"}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "email": "henning@doist.com",
7
7
  "url": "http://doist.com"
8
8
  },
9
- "version": "24.1.5-beta",
9
+ "version": "25.0.0-beta",
10
10
  "license": "MIT",
11
11
  "homepage": "https://github.com/Doist/reactist#readme",
12
12
  "repository": {