@elliemae/ds-banner 3.80.0-next.36 → 3.80.0-next.39

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.
@@ -42,6 +42,7 @@ var import_ds_system = require("@elliemae/ds-system");
42
42
  var import_DSBannerContent = require("./DSBannerContent.js");
43
43
  var import_LiveRegionCorrectlyImplemented = require("./LiveRegionCorrectlyImplemented.js");
44
44
  var import_constants = require("./constants/index.js");
45
+ var import_useBannerContainer = require("./useBannerContainer.js");
45
46
  var import_usePageNotice = require("./usePageNotice.js");
46
47
  var import_react_desc_prop_types = require("./react-desc-prop-types.js");
47
48
  var import_styles = require("./styles.js");
@@ -77,19 +78,9 @@ const DSBanner = (props) => {
77
78
  if (CustomBody) return colsWithCustomBody;
78
79
  return isSmall ? outOfTheBoxColsSmallLayout : outOfTheBoxCols;
79
80
  }, [CustomBody, isSmall]);
80
- const handleActionRefForContainer = (0, import_react.useCallback)(
81
- (containerNode) => {
82
- if (containerNode && actionRef && actionRef.current) {
83
- actionRef.current.focusOnWrapper = () => {
84
- if (containerNode) {
85
- setTimeout(() => {
86
- containerNode?.focus();
87
- }, 300);
88
- }
89
- };
90
- }
91
- },
92
- [actionRef]
81
+ const { handleActionRefForContainer, isContainerRendered, containerExitProps, liveRegionKey } = (0, import_useBannerContainer.useBannerContainer)(
82
+ isOpen,
83
+ actionRef
93
84
  );
94
85
  const { baseId, contentIds, pageNoticeNameProps } = (0, import_usePageNotice.usePageNotice)(propsWithDefaults, props, globalAttrs);
95
86
  const handleOnKeyDownToClose = (0, import_react.useCallback)(
@@ -115,7 +106,7 @@ const DSBanner = (props) => {
115
106
  (0, import_react.useEffect)(() => {
116
107
  if (isOpen && getIsLiveRegion(withLiveRegionAnnouncement)) read();
117
108
  }, [isOpen, withLiveRegionAnnouncement, read]);
118
- if (!isOpen)
109
+ if (!isContainerRendered)
119
110
  return getIsLiveRegion(withLiveRegionAnnouncement) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
120
111
  import_LiveRegionCorrectlyImplemented.LiveRegionCorrectlyImplemented,
121
112
  {
@@ -134,10 +125,12 @@ const DSBanner = (props) => {
134
125
  innerRef: handleActionRefForContainer,
135
126
  tabIndex: -1,
136
127
  role: isPageNotice ? "region" : void 0,
128
+ $isExpanded: isOpen,
137
129
  ...pageNoticeNameProps,
138
130
  ...containerProps,
139
131
  ...globalAttrs,
140
132
  ...xstyledAttrs,
133
+ ...containerExitProps,
141
134
  ...ownerPropsConfig,
142
135
  children: [
143
136
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styles.StyledBannerLayout, { ...ownerPropsConfig, $type: type, children: [
@@ -175,7 +168,8 @@ const DSBanner = (props) => {
175
168
  announcementType: withLiveRegionAnnouncement,
176
169
  ownerPropsConfig,
177
170
  globalAttrs
178
- }
171
+ },
172
+ liveRegionKey
179
173
  ) : null
180
174
  ]
181
175
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/DSBanner.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["import { CloseX } from '@elliemae/ds-icons';\nimport {\n describe,\n useGetGlobalAttributes,\n useGetXstyledProps,\n useMemoMergePropsWithDefault,\n useOwnerProps,\n} from '@elliemae/ds-props-helpers';\nimport React, { useCallback, useEffect, useMemo } from 'react';\nimport { useGetLayoutMode } from '@elliemae/ds-system';\nimport { DSBannerContent } from './DSBannerContent.js';\nimport { LiveRegionCorrectlyImplemented } from './LiveRegionCorrectlyImplemented.js';\nimport { DSBannerDatatestid, DSBannerName } from './constants/index.js';\nimport { usePageNotice } from './usePageNotice.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { defaultProps, DSBannerPropTypesSchema } from './react-desc-prop-types.js';\nimport { StyledBannerContainer, StyledBannerLayout, StyledCloseButton, StyledInnerContainer } from './styles.js';\n\nconst outOfTheBoxCols = ['auto', '1fr'];\nconst outOfTheBoxColsSmallLayout = ['auto', '1fr'];\nconst colsWithCustomBody = ['1fr', 'auto'];\n\nconst getIsLiveRegion = (type: string) => type === 'polite' || type === 'assertive';\n\nconst DSBanner: React.ComponentType<DSBannerT.Props> = (props) => {\n const propsWithDefaults = useMemoMergePropsWithDefault<DSBannerT.InternalProps>(props, defaultProps);\n\n const {\n type,\n isOpen,\n onClose,\n label,\n body,\n closeBtnRef,\n CustomBody,\n actionLink,\n showCloseButton,\n containerProps,\n actionRef,\n withLiveRegionAnnouncement,\n isPageNotice,\n bannerId,\n ...rest\n } = propsWithDefaults;\n // eslint-disable-next-line no-unused-vars\n const { height: globalHeight, ...globalAttrs } = useGetGlobalAttributes(rest);\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n const xstyledAttrs = useGetXstyledProps(rest);\n\n const layoutMode = useGetLayoutMode();\n const isSmall = layoutMode === 's' || layoutMode === 'xs';\n const innerContainerCols = useMemo(() => {\n if (CustomBody) return colsWithCustomBody;\n return isSmall ? outOfTheBoxColsSmallLayout : outOfTheBoxCols;\n }, [CustomBody, isSmall]);\n\n const handleActionRefForContainer = useCallback<React.RefCallback<HTMLDivElement>>(\n (containerNode) => {\n if (containerNode && actionRef && actionRef.current) {\n actionRef.current.focusOnWrapper = () => {\n if (containerNode) {\n setTimeout(() => {\n containerNode?.focus();\n }, 300);\n }\n };\n }\n },\n [actionRef],\n );\n\n const { baseId, contentIds, pageNoticeNameProps } = usePageNotice(propsWithDefaults, props, globalAttrs);\n\n const handleOnKeyDownToClose = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n }\n },\n [onClose],\n );\n\n const liveRegionRef = React.useRef<HTMLDivElement>(null);\n const isOpenRef = React.useRef(isOpen);\n isOpenRef.current = isOpen;\n const textToAnnounceRef = React.useRef(`${label} ${body}`);\n textToAnnounceRef.current = `${label} ${body}`;\n const read = React.useCallback(() => {\n if (liveRegionRef.current) {\n if (isOpenRef.current) liveRegionRef.current.textContent = textToAnnounceRef.current;\n else liveRegionRef.current.textContent = '';\n }\n }, []);\n\n useEffect(() => {\n if (isOpen && getIsLiveRegion(withLiveRegionAnnouncement)) read();\n }, [isOpen, withLiveRegionAnnouncement, read]);\n\n // this used to \"try\" to animate the banner closing\n // in reality the closing animation has never actually worked (the banner just disappears, due to using \"&&\" instead of \"||\" in the logic)\n // given that it has never worked, and the complexity it adds to the code, we are officially removing the closing animation for now\n // if there is a future need for it, we can re-visit adding it back in.\n if (!isOpen)\n return getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null;\n\n return (\n <StyledBannerContainer\n onKeyDown={handleOnKeyDownToClose}\n data-testid={DSBannerDatatestid.CONTAINER}\n innerRef={handleActionRefForContainer}\n tabIndex={-1}\n role={isPageNotice ? 'region' : undefined}\n {...pageNoticeNameProps}\n {...containerProps}\n {...globalAttrs}\n {...xstyledAttrs}\n {...ownerPropsConfig}\n >\n <StyledBannerLayout {...ownerPropsConfig} $type={type}>\n <StyledInnerContainer\n cols={innerContainerCols}\n data-type={type}\n data-testid={DSBannerDatatestid.INNER_CONTAINER}\n role={withLiveRegionAnnouncement === 'alert' ? 'alert' : undefined}\n id={baseId}\n {...ownerPropsConfig}\n >\n {!CustomBody ? <DSBannerContent propsWithDefaults={propsWithDefaults} {...contentIds} /> : <CustomBody />}\n </StyledInnerContainer>\n {!CustomBody && showCloseButton ? (\n <StyledCloseButton\n data-testid={DSBannerDatatestid.CLOSE_BUTTON}\n buttonType=\"icon\"\n innerRef={closeBtnRef}\n onClick={onClose}\n aria-label=\"Visually dismiss the banner\"\n aria-describedby={baseId}\n {...ownerPropsConfig}\n >\n <CloseX width={12} height={12} />\n </StyledCloseButton>\n ) : null}\n </StyledBannerLayout>\n {getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null}\n </StyledBannerContainer>\n );\n};\n\nDSBanner.displayName = DSBannerName;\nconst DSBannerWithSchema = describe(DSBanner);\nDSBannerWithSchema.propTypes = DSBannerPropTypesSchema;\n\nexport default DSBanner;\nexport { DSBanner, DSBannerWithSchema };\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { CloseX } from '@elliemae/ds-icons';\nimport {\n describe,\n useGetGlobalAttributes,\n useGetXstyledProps,\n useMemoMergePropsWithDefault,\n useOwnerProps,\n} from '@elliemae/ds-props-helpers';\nimport React, { useCallback, useEffect, useMemo } from 'react';\nimport { useGetLayoutMode } from '@elliemae/ds-system';\nimport { DSBannerContent } from './DSBannerContent.js';\nimport { LiveRegionCorrectlyImplemented } from './LiveRegionCorrectlyImplemented.js';\nimport { DSBannerDatatestid, DSBannerName } from './constants/index.js';\nimport { useBannerContainer } from './useBannerContainer.js';\nimport { usePageNotice } from './usePageNotice.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { defaultProps, DSBannerPropTypesSchema } from './react-desc-prop-types.js';\nimport { StyledBannerContainer, StyledBannerLayout, StyledCloseButton, StyledInnerContainer } from './styles.js';\n\nconst outOfTheBoxCols = ['auto', '1fr'];\nconst outOfTheBoxColsSmallLayout = ['auto', '1fr'];\nconst colsWithCustomBody = ['1fr', 'auto'];\n\nconst getIsLiveRegion = (type: string) => type === 'polite' || type === 'assertive';\n\nconst DSBanner: React.ComponentType<DSBannerT.Props> = (props) => {\n const propsWithDefaults = useMemoMergePropsWithDefault<DSBannerT.InternalProps>(props, defaultProps);\n\n const {\n type,\n isOpen,\n onClose,\n label,\n body,\n closeBtnRef,\n CustomBody,\n actionLink,\n showCloseButton,\n containerProps,\n actionRef,\n withLiveRegionAnnouncement,\n isPageNotice,\n bannerId,\n ...rest\n } = propsWithDefaults;\n // eslint-disable-next-line no-unused-vars\n const { height: globalHeight, ...globalAttrs } = useGetGlobalAttributes(rest);\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n const xstyledAttrs = useGetXstyledProps(rest);\n\n const layoutMode = useGetLayoutMode();\n const isSmall = layoutMode === 's' || layoutMode === 'xs';\n const innerContainerCols = useMemo(() => {\n if (CustomBody) return colsWithCustomBody;\n return isSmall ? outOfTheBoxColsSmallLayout : outOfTheBoxCols;\n }, [CustomBody, isSmall]);\n\n const { handleActionRefForContainer, isContainerRendered, containerExitProps, liveRegionKey } = useBannerContainer(\n isOpen,\n actionRef,\n );\n\n const { baseId, contentIds, pageNoticeNameProps } = usePageNotice(propsWithDefaults, props, globalAttrs);\n\n const handleOnKeyDownToClose = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n }\n },\n [onClose],\n );\n\n const liveRegionRef = React.useRef<HTMLDivElement>(null);\n const isOpenRef = React.useRef(isOpen);\n isOpenRef.current = isOpen;\n const textToAnnounceRef = React.useRef(`${label} ${body}`);\n textToAnnounceRef.current = `${label} ${body}`;\n const read = React.useCallback(() => {\n if (liveRegionRef.current) {\n if (isOpenRef.current) liveRegionRef.current.textContent = textToAnnounceRef.current;\n else liveRegionRef.current.textContent = '';\n }\n }, []);\n\n useEffect(() => {\n if (isOpen && getIsLiveRegion(withLiveRegionAnnouncement)) read();\n }, [isOpen, withLiveRegionAnnouncement, read]);\n\n // the container stays mounted while it slides up after closing (see useBannerExitAnimation)\n if (!isContainerRendered)\n return getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null;\n\n return (\n <StyledBannerContainer\n onKeyDown={handleOnKeyDownToClose}\n data-testid={DSBannerDatatestid.CONTAINER}\n innerRef={handleActionRefForContainer}\n tabIndex={-1}\n role={isPageNotice ? 'region' : undefined}\n $isExpanded={isOpen}\n {...pageNoticeNameProps}\n {...containerProps}\n {...globalAttrs}\n {...xstyledAttrs}\n {...containerExitProps}\n {...ownerPropsConfig}\n >\n <StyledBannerLayout {...ownerPropsConfig} $type={type}>\n <StyledInnerContainer\n cols={innerContainerCols}\n data-type={type}\n data-testid={DSBannerDatatestid.INNER_CONTAINER}\n role={withLiveRegionAnnouncement === 'alert' ? 'alert' : undefined}\n id={baseId}\n {...ownerPropsConfig}\n >\n {!CustomBody ? <DSBannerContent propsWithDefaults={propsWithDefaults} {...contentIds} /> : <CustomBody />}\n </StyledInnerContainer>\n {!CustomBody && showCloseButton ? (\n <StyledCloseButton\n data-testid={DSBannerDatatestid.CLOSE_BUTTON}\n buttonType=\"icon\"\n innerRef={closeBtnRef}\n onClick={onClose}\n aria-label=\"Visually dismiss the banner\"\n aria-describedby={baseId}\n {...ownerPropsConfig}\n >\n <CloseX width={12} height={12} />\n </StyledCloseButton>\n ) : null}\n </StyledBannerLayout>\n {getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n key={liveRegionKey}\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null}\n </StyledBannerContainer>\n );\n};\n\nDSBanner.displayName = DSBannerName;\nconst DSBannerWithSchema = describe(DSBanner);\nDSBannerWithSchema.propTypes = DSBannerPropTypesSchema;\n\nexport default DSBanner;\nexport { DSBanner, DSBannerWithSchema };\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": "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",
6
6
  "names": ["React"]
7
7
  }
@@ -77,28 +77,26 @@ const DSBannerContent = (props) => {
77
77
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
78
78
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styles.StyledIconContainer, { "data-testid": import_constants.DSBannerDatatestid.ICON_CONTAINER, ...ownerPropsConfig, children: icons[type] }),
79
79
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styles.StyledBody, { ...ownerPropsConfig, children: [
80
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styles.StyledTitle, { id: titleId, variant: import_ds_typography.TYPOGRAPHY_VARIANTS.H5_STRONG, ...ownerPropsConfig, children: label }),
81
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styles.StyledSubTitle, { id: bodyId, variant: import_ds_typography.TYPOGRAPHY_VARIANTS.B1, ...ownerPropsConfig, children: [
82
- body,
83
- actionLink && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
84
- !body ? "" : " ",
85
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
86
- import_styles.StyledActionLink,
87
- {
88
- "data-testid": import_constants.DSBannerDatatestid.ACTION_LINK,
89
- onClick: actionLink.onClick,
90
- href: actionLink.href,
91
- innerRef: handleActionRefForLink,
92
- onKeyDown: handleOnKeyDown,
93
- tabIndex: 0,
94
- isBodyEmpty: !body,
95
- title: actionLink.label,
96
- ...ownerPropsConfig,
97
- children: actionLink.label
98
- }
99
- )
100
- ] })
101
- ] })
80
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styles.StyledTitle, { id: titleId, variant: import_ds_typography.TYPOGRAPHY_VARIANTS.H5_STRONG, component: "span", ...ownerPropsConfig, children: label }),
81
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styles.StyledSubTitle, { id: bodyId, variant: import_ds_typography.TYPOGRAPHY_VARIANTS.B1, ...ownerPropsConfig, children: body }),
82
+ actionLink && // its own element (a sibling of the description, not inline in it): the spacing is CSS, not literal spaces.
83
+ // the DSTypography link variant gives the size + DSTypography-root class, the underline/weight pending UX are in styles.tsx
84
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
85
+ import_styles.StyledActionLink,
86
+ {
87
+ variant: import_ds_typography.TYPOGRAPHY_VARIANTS.LINK_SML_TITLE,
88
+ "data-testid": import_constants.DSBannerDatatestid.ACTION_LINK,
89
+ onClick: actionLink.onClick,
90
+ href: actionLink.href,
91
+ innerRef: handleActionRefForLink,
92
+ onKeyDown: handleOnKeyDown,
93
+ tabIndex: 0,
94
+ isBodyEmpty: !body,
95
+ title: actionLink.label,
96
+ ...ownerPropsConfig,
97
+ children: actionLink.label
98
+ }
99
+ )
102
100
  ] })
103
101
  ] });
104
102
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/DSBannerContent.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable max-lines */\nimport { AlertsDetailFill, InfoFill, SuccessFill, WarningSquare } from '@elliemae/ds-icons';\nimport { useOwnerProps } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport React, { useCallback } from 'react';\nimport { DSBannerDatatestid } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { StyledActionLink, StyledIconContainer, StyledSubTitle, StyledTitle, StyledBody } from './styles.js';\n\nexport const icons: Record<string, JSX.Element> = {\n success: <SuccessFill color={['success', '900']} width=\"20px\" height=\"20px\" />,\n info: <InfoFill color={['brand-primary', '600']} width=\"20px\" height=\"20px\" />,\n danger: <AlertsDetailFill color={['danger', '900']} width=\"20px\" height=\"20px\" />,\n warning: <WarningSquare color={['warning', '900']} width=\"20px\" height=\"20px\" />,\n};\n\ninterface DSBannerContentProps {\n propsWithDefaults: DSBannerT.InternalProps;\n titleId?: string;\n bodyId?: string;\n}\n\nexport const DSBannerContent: React.ComponentType<DSBannerContentProps> = (props) => {\n const {\n propsWithDefaults,\n titleId,\n bodyId,\n propsWithDefaults: { type, label, body, actionLink, actionRef },\n } = props;\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n\n const linkRef = React.useRef<HTMLAnchorElement>(null) as React.MutableRefObject<HTMLAnchorElement>;\n\n const handleActionRefForLink = useCallback<React.RefCallback<HTMLAnchorElement>>(\n (linkNode) => {\n if (linkNode) {\n linkRef.current = linkNode;\n if (actionRef && actionRef.current) {\n actionRef.current.focusOnLink = () => {\n linkNode?.focus?.();\n };\n }\n }\n },\n [actionRef],\n );\n\n const handleOnKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (linkRef.current) linkRef.current.click();\n }\n }, []);\n\n return (\n <>\n <StyledIconContainer data-testid={DSBannerDatatestid.ICON_CONTAINER} {...ownerPropsConfig}>\n {icons[type]}\n </StyledIconContainer>\n <StyledBody {...ownerPropsConfig}>\n <StyledTitle id={titleId} variant={TYPOGRAPHY_VARIANTS.H5_STRONG} {...ownerPropsConfig}>\n {label}\n </StyledTitle>\n <StyledSubTitle id={bodyId} variant={TYPOGRAPHY_VARIANTS.B1} {...ownerPropsConfig}>\n {body}\n {actionLink && (\n <>\n {/* This way of handling the space is making use of the browser default\n white-space clamping, avoiding lots of JS code. */}\n {!body ? '' : ' '}\n <StyledActionLink\n data-testid={DSBannerDatatestid.ACTION_LINK}\n onClick={actionLink.onClick}\n href={actionLink.href}\n innerRef={handleActionRefForLink}\n onKeyDown={handleOnKeyDown}\n tabIndex={0}\n isBodyEmpty={!body}\n title={actionLink.label}\n {...ownerPropsConfig}\n >\n {actionLink.label}\n </StyledActionLink>\n </>\n )}\n </StyledSubTitle>\n </StyledBody>\n </>\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADUZ;AATX,sBAAuE;AACvE,8BAA8B;AAC9B,2BAAoC;AACpC,mBAAmC;AACnC,uBAAmC;AAEnC,oBAA+F;AAExF,MAAM,QAAqC;AAAA,EAChD,SAAS,4CAAC,+BAAY,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,MAAM,4CAAC,4BAAS,OAAO,CAAC,iBAAiB,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,QAAQ,4CAAC,oCAAiB,OAAO,CAAC,UAAU,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC/E,SAAS,4CAAC,iCAAc,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAChF;AAQO,MAAM,kBAA6D,CAAC,UAAU;AACnF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,EAAE,MAAM,OAAO,MAAM,YAAY,UAAU;AAAA,EAChE,IAAI;AACJ,QAAM,uBAAmB,uCAAc,mBAAmB,EAAE,GAAG,MAAM,CAAC;AAEtE,QAAM,UAAU,aAAAA,QAAM,OAA0B,IAAI;AAEpD,QAAM,6BAAyB;AAAA,IAC7B,CAAC,aAAa;AACZ,UAAI,UAAU;AACZ,gBAAQ,UAAU;AAClB,YAAI,aAAa,UAAU,SAAS;AAClC,oBAAU,QAAQ,cAAc,MAAM;AACpC,sBAAU,QAAQ;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,sBAAkB,0BAAY,CAAC,MAA2B;AAC9D,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,eAAe;AACjB,UAAI,QAAQ,QAAS,SAAQ,QAAQ,MAAM;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,4EACE;AAAA,gDAAC,qCAAoB,eAAa,oCAAmB,gBAAiB,GAAG,kBACtE,gBAAM,IAAI,GACb;AAAA,IACA,6CAAC,4BAAY,GAAG,kBACd;AAAA,kDAAC,6BAAY,IAAI,SAAS,SAAS,yCAAoB,WAAY,GAAG,kBACnE,iBACH;AAAA,MACA,6CAAC,gCAAe,IAAI,QAAQ,SAAS,yCAAoB,IAAK,GAAG,kBAC9D;AAAA;AAAA,QACA,cACC,4EAGG;AAAA,WAAC,OAAO,KAAK;AAAA,UACd;AAAA,YAAC;AAAA;AAAA,cACC,eAAa,oCAAmB;AAAA,cAChC,SAAS,WAAW;AAAA,cACpB,MAAM,WAAW;AAAA,cACjB,UAAU;AAAA,cACV,WAAW;AAAA,cACX,UAAU;AAAA,cACV,aAAa,CAAC;AAAA,cACd,OAAO,WAAW;AAAA,cACjB,GAAG;AAAA,cAEH,qBAAW;AAAA;AAAA,UACd;AAAA,WACF;AAAA,SAEJ;AAAA,OACF;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["/* eslint-disable max-lines */\nimport { AlertsDetailFill, InfoFill, SuccessFill, WarningSquare } from '@elliemae/ds-icons';\nimport { useOwnerProps } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport React, { useCallback } from 'react';\nimport { DSBannerDatatestid } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { StyledActionLink, StyledIconContainer, StyledSubTitle, StyledTitle, StyledBody } from './styles.js';\n\nexport const icons: Record<string, JSX.Element> = {\n success: <SuccessFill color={['success', '900']} width=\"20px\" height=\"20px\" />,\n info: <InfoFill color={['brand-primary', '600']} width=\"20px\" height=\"20px\" />,\n danger: <AlertsDetailFill color={['danger', '900']} width=\"20px\" height=\"20px\" />,\n warning: <WarningSquare color={['warning', '900']} width=\"20px\" height=\"20px\" />,\n};\n\ninterface DSBannerContentProps {\n propsWithDefaults: DSBannerT.InternalProps;\n titleId?: string;\n bodyId?: string;\n}\n\nexport const DSBannerContent: React.ComponentType<DSBannerContentProps> = (props) => {\n const {\n propsWithDefaults,\n titleId,\n bodyId,\n propsWithDefaults: { type, label, body, actionLink, actionRef },\n } = props;\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n\n const linkRef = React.useRef<HTMLElement>(null) as React.MutableRefObject<HTMLElement>;\n\n const handleActionRefForLink = useCallback<React.RefCallback<HTMLElement>>(\n (linkNode) => {\n if (linkNode) {\n linkRef.current = linkNode;\n if (actionRef && actionRef.current) {\n actionRef.current.focusOnLink = () => {\n linkNode?.focus?.();\n };\n }\n }\n },\n [actionRef],\n );\n\n const handleOnKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (linkRef.current) linkRef.current.click();\n }\n }, []);\n\n return (\n <>\n <StyledIconContainer data-testid={DSBannerDatatestid.ICON_CONTAINER} {...ownerPropsConfig}>\n {icons[type]}\n </StyledIconContainer>\n <StyledBody {...ownerPropsConfig}>\n {/* h5-strong look, but a span: the title must not inject a heading into the host page outline.\n `component` (not `as`): on a styled(DSTypography) wrapper `as` would replace DSTypography itself. */}\n <StyledTitle id={titleId} variant={TYPOGRAPHY_VARIANTS.H5_STRONG} component=\"span\" {...ownerPropsConfig}>\n {label}\n </StyledTitle>\n <StyledSubTitle id={bodyId} variant={TYPOGRAPHY_VARIANTS.B1} {...ownerPropsConfig}>\n {body}\n </StyledSubTitle>\n {actionLink && (\n // its own element (a sibling of the description, not inline in it): the spacing is CSS, not literal spaces.\n // the DSTypography link variant gives the size + DSTypography-root class, the underline/weight pending UX are in styles.tsx\n <StyledActionLink\n variant={TYPOGRAPHY_VARIANTS.LINK_SML_TITLE}\n data-testid={DSBannerDatatestid.ACTION_LINK}\n onClick={actionLink.onClick}\n href={actionLink.href}\n innerRef={handleActionRefForLink}\n onKeyDown={handleOnKeyDown}\n tabIndex={0}\n isBodyEmpty={!body}\n title={actionLink.label}\n {...ownerPropsConfig}\n >\n {actionLink.label}\n </StyledActionLink>\n )}\n </StyledBody>\n </>\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADUZ;AATX,sBAAuE;AACvE,8BAA8B;AAC9B,2BAAoC;AACpC,mBAAmC;AACnC,uBAAmC;AAEnC,oBAA+F;AAExF,MAAM,QAAqC;AAAA,EAChD,SAAS,4CAAC,+BAAY,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,MAAM,4CAAC,4BAAS,OAAO,CAAC,iBAAiB,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,QAAQ,4CAAC,oCAAiB,OAAO,CAAC,UAAU,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC/E,SAAS,4CAAC,iCAAc,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAChF;AAQO,MAAM,kBAA6D,CAAC,UAAU;AACnF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,EAAE,MAAM,OAAO,MAAM,YAAY,UAAU;AAAA,EAChE,IAAI;AACJ,QAAM,uBAAmB,uCAAc,mBAAmB,EAAE,GAAG,MAAM,CAAC;AAEtE,QAAM,UAAU,aAAAA,QAAM,OAAoB,IAAI;AAE9C,QAAM,6BAAyB;AAAA,IAC7B,CAAC,aAAa;AACZ,UAAI,UAAU;AACZ,gBAAQ,UAAU;AAClB,YAAI,aAAa,UAAU,SAAS;AAClC,oBAAU,QAAQ,cAAc,MAAM;AACpC,sBAAU,QAAQ;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,sBAAkB,0BAAY,CAAC,MAA2B;AAC9D,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,eAAe;AACjB,UAAI,QAAQ,QAAS,SAAQ,QAAQ,MAAM;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,4EACE;AAAA,gDAAC,qCAAoB,eAAa,oCAAmB,gBAAiB,GAAG,kBACtE,gBAAM,IAAI,GACb;AAAA,IACA,6CAAC,4BAAY,GAAG,kBAGd;AAAA,kDAAC,6BAAY,IAAI,SAAS,SAAS,yCAAoB,WAAW,WAAU,QAAQ,GAAG,kBACpF,iBACH;AAAA,MACA,4CAAC,gCAAe,IAAI,QAAQ,SAAS,yCAAoB,IAAK,GAAG,kBAC9D,gBACH;AAAA,MACC;AAAA;AAAA,MAGC;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,yCAAoB;AAAA,UAC7B,eAAa,oCAAmB;AAAA,UAChC,SAAS,WAAW;AAAA,UACpB,MAAM,WAAW;AAAA,UACjB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,UAAU;AAAA,UACV,aAAa,CAAC;AAAA,UACd,OAAO,WAAW;AAAA,UACjB,GAAG;AAAA,UAEH,qBAAW;AAAA;AAAA,MACd;AAAA,OAEJ;AAAA,KACF;AAEJ;",
6
6
  "names": ["React"]
7
7
  }
@@ -29,6 +29,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  var constants_exports = {};
30
30
  __export(constants_exports, {
31
31
  BANNER_BODY_ID: () => BANNER_BODY_ID,
32
+ BANNER_SLIDE_DURATION_MS: () => BANNER_SLIDE_DURATION_MS,
32
33
  BANNER_TYPES: () => BANNER_TYPES,
33
34
  DSBannerDatatestid: () => DSBannerDatatestid,
34
35
  DSBannerName: () => DSBannerName,
@@ -44,6 +45,7 @@ const BANNER_TYPES = {
44
45
  WARNING: "warning",
45
46
  DANGER: "danger"
46
47
  };
48
+ const BANNER_SLIDE_DURATION_MS = 500;
47
49
  const BANNER_BODY_ID = "ds-banner-body";
48
50
  const DSBannerSlots = {
49
51
  CONTAINER: "container",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/constants/index.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["import { slotObjectToDataTestIds } from '@elliemae/ds-system';\n\nexport const DSBannerName = 'DSBanner';\nexport const BANNER_TYPES = {\n INFO: 'info',\n SUCCESS: 'success',\n WARNING: 'warning',\n DANGER: 'danger',\n} as const;\n\n/**\n * @deprecated legacy export, no longer rendered or used by the component (PUI-19089).\n * The body used to render with this fixed id, which duplicated across banners. The body id is now\n * `<bannerId>-body`, where `bannerId` is generated per instance or provided through the `bannerId` prop.\n * Kept only so imports of the old constant keep resolving.\n */\nexport const BANNER_BODY_ID = 'ds-banner-body';\n\n// previously this was the exported data-testid object\n// the one marked as // ok are the one that works with the slots convention and works with the slotObjectToDataTestIds function\n// the rest are not compatible and needs manual handling\n// export const DSBannerDatatestid = {\n// CONTAINER: 'ds-banner-container', // ok\n// CUSTOM_CONTAINER: 'ds-banner-custom-container', // ok\n// ACTION_LINK: 'ds-banner-action-link', // ok\n// CLOSE_BUTTON: 'ds-banner-close-button', // ok\n// // From here down are not compatible with the slotObjectToDataTestIds function.\n// INNER_CONTAINER: 'ds-banner',\n// ICON_CONTAINER: 'ds-banner-icon',\n// // from here they were not present but they had an asigned Slot.\n// // TITLE\n// // SUBTITLE\n// };\n\n// we are naming this with the ${component_name}_slots convention to namespace & avoid errors on duplicate exports variables in aggregators\n\nexport const DSBannerSlots = {\n CONTAINER: 'container',\n INNER_CONTAINER: 'inner-container',\n // reserved slot: declared but never rendered. It is part of the public surface (DSBannerDatatestid, dsBannerCustomContainer slot prop)\n // and pinned by DSBanner.data-testid.test.js, so removing it is a breaking change. See KNOWN_INTENTIONAL_DEVIATIONS.md\n CUSTOM_CONTAINER: 'custom-container',\n BODY: 'body',\n TITLE: 'title',\n SUBTITLE: 'subtitle',\n ICON_CONTAINER: 'icon-container',\n ACTION_LINK: 'action-link',\n CLOSE_BUTTON: 'close-button',\n LAYOUT: 'layout',\n LIVE_REGION_PORTAL: 'live-region-portal',\n} as const;\n\n// we are naming this with the ${component_name}_data_testid convention to namespace & avoid errors on duplicate exports variables in aggregators\nexport const DSBannerDatatestid = {\n ...(slotObjectToDataTestIds(DSBannerName, DSBannerSlots) as Record<keyof typeof DSBannerSlots, string>),\n // handling the rest of the data-testids that are not compatible with the slotObjectToDataTestIds function manually to avoid breaking changes\n INNER_CONTAINER: 'ds-banner',\n ICON_CONTAINER: 'ds-banner-icon',\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,uBAAwC;AAEjC,MAAM,eAAe;AACrB,MAAM,eAAe;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV;AAQO,MAAM,iBAAiB;AAoBvB,MAAM,gBAAgB;AAAA,EAC3B,WAAW;AAAA,EACX,iBAAiB;AAAA;AAAA;AAAA,EAGjB,kBAAkB;AAAA,EAClB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,oBAAoB;AACtB;AAGO,MAAM,qBAAqB;AAAA,EAChC,OAAI,0CAAwB,cAAc,aAAa;AAAA;AAAA,EAEvD,iBAAiB;AAAA,EACjB,gBAAgB;AAClB;",
4
+ "sourcesContent": ["import { slotObjectToDataTestIds } from '@elliemae/ds-system';\n\nexport const DSBannerName = 'DSBanner';\nexport const BANNER_TYPES = {\n INFO: 'info',\n SUCCESS: 'success',\n WARNING: 'warning',\n DANGER: 'danger',\n} as const;\n\n// duration of the slide down (open) and slide up (close) of the banner, defined by the Banner spec v2 \"Motion and Animation\"\nexport const BANNER_SLIDE_DURATION_MS = 500;\n\n/**\n * @deprecated legacy export, no longer rendered or used by the component (PUI-19089).\n * The body used to render with this fixed id, which duplicated across banners. The body id is now\n * `<bannerId>-body`, where `bannerId` is generated per instance or provided through the `bannerId` prop.\n * Kept only so imports of the old constant keep resolving.\n */\nexport const BANNER_BODY_ID = 'ds-banner-body';\n\n// previously this was the exported data-testid object\n// the one marked as // ok are the one that works with the slots convention and works with the slotObjectToDataTestIds function\n// the rest are not compatible and needs manual handling\n// export const DSBannerDatatestid = {\n// CONTAINER: 'ds-banner-container', // ok\n// CUSTOM_CONTAINER: 'ds-banner-custom-container', // ok\n// ACTION_LINK: 'ds-banner-action-link', // ok\n// CLOSE_BUTTON: 'ds-banner-close-button', // ok\n// // From here down are not compatible with the slotObjectToDataTestIds function.\n// INNER_CONTAINER: 'ds-banner',\n// ICON_CONTAINER: 'ds-banner-icon',\n// // from here they were not present but they had an asigned Slot.\n// // TITLE\n// // SUBTITLE\n// };\n\n// we are naming this with the ${component_name}_slots convention to namespace & avoid errors on duplicate exports variables in aggregators\n\nexport const DSBannerSlots = {\n CONTAINER: 'container',\n INNER_CONTAINER: 'inner-container',\n // reserved slot: declared but never rendered. It is part of the public surface (DSBannerDatatestid, dsBannerCustomContainer slot prop)\n // and pinned by DSBanner.data-testid.test.js, so removing it is a breaking change. See KNOWN_INTENTIONAL_DEVIATIONS.md\n CUSTOM_CONTAINER: 'custom-container',\n BODY: 'body',\n TITLE: 'title',\n SUBTITLE: 'subtitle',\n ICON_CONTAINER: 'icon-container',\n ACTION_LINK: 'action-link',\n CLOSE_BUTTON: 'close-button',\n LAYOUT: 'layout',\n LIVE_REGION_PORTAL: 'live-region-portal',\n} as const;\n\n// we are naming this with the ${component_name}_data_testid convention to namespace & avoid errors on duplicate exports variables in aggregators\nexport const DSBannerDatatestid = {\n ...(slotObjectToDataTestIds(DSBannerName, DSBannerSlots) as Record<keyof typeof DSBannerSlots, string>),\n // handling the rest of the data-testids that are not compatible with the slotObjectToDataTestIds function manually to avoid breaking changes\n INNER_CONTAINER: 'ds-banner',\n ICON_CONTAINER: 'ds-banner-icon',\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,uBAAwC;AAEjC,MAAM,eAAe;AACrB,MAAM,eAAe;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV;AAGO,MAAM,2BAA2B;AAQjC,MAAM,iBAAiB;AAoBvB,MAAM,gBAAgB;AAAA,EAC3B,WAAW;AAAA,EACX,iBAAiB;AAAA;AAAA;AAAA,EAGjB,kBAAkB;AAAA,EAClB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,oBAAoB;AACtB;AAGO,MAAM,qBAAqB;AAAA,EAChC,OAAI,0CAAwB,cAAc,aAAa;AAAA;AAAA,EAEvD,iBAAiB;AAAA,EACjB,gBAAgB;AAClB;",
6
6
  "names": []
7
7
  }
@@ -50,11 +50,26 @@ const StyledBannerContainer = (0, import_ds_system.styled)("div", {
50
50
  name: import_constants.DSBannerName,
51
51
  slot: import_constants.DSBannerSlots.CONTAINER
52
52
  })`
53
- min-height: 59px;
53
+ display: grid;
54
+ grid-template-columns: minmax(0, 1fr);
55
+ height: fit-content;
56
+ grid-template-rows: ${({ $isExpanded = true }) => $isExpanded ? "minmax(0, 1fr)" : "minmax(0, 0fr)"};
57
+ min-height: ${({ $isExpanded = true }) => $isExpanded ? "59px" : "0px"};
54
58
  overflow: hidden;
55
- transition: all 0.5s ease-in;
59
+ transition:
60
+ grid-template-rows ${import_constants.BANNER_SLIDE_DURATION_MS}ms ease-in,
61
+ min-height ${import_constants.BANNER_SLIDE_DURATION_MS}ms ease-in;
56
62
  @starting-style {
57
- max-height: 0px;
63
+ grid-template-rows: minmax(0, 0fr);
64
+ min-height: 0px;
65
+ }
66
+ & > * {
67
+ align-self: start;
68
+ min-height: 0;
69
+ overflow: hidden;
70
+ }
71
+ @media (prefers-reduced-motion: reduce) {
72
+ transition: none;
58
73
  }
59
74
  ${import_ds_system.xStyledCommonProps}
60
75
  `;
@@ -104,11 +119,18 @@ const StyledIconContainer = (0, import_ds_system.styled)("div", {
104
119
  margin-left: ${({ theme }) => theme.space.xs};
105
120
  min-width: 0px;
106
121
  `;
122
+ const isSmallLayout = ({ theme }) => ["s", "xs"].includes(theme.layoutMode);
107
123
  const StyledBody = (0, import_ds_system.styled)("div", { name: import_constants.DSBannerName, slot: import_constants.DSBannerSlots.BODY })`
124
+ display: grid;
125
+ grid-template-columns: ${(props) => isSmallLayout(props) ? "minmax(0, 1fr)" : "minmax(0, max-content) auto"};
126
+ justify-content: start;
108
127
  padding-top: 9px;
109
- padding-bottom: 9px;
128
+ & > :nth-child(-n + 2) {
129
+ grid-column: 1;
130
+ }
110
131
  `;
111
132
  const StyledTitle = (0, import_ds_system.styled)(import_ds_typography.DSTypography, { name: import_constants.DSBannerName, slot: import_constants.DSBannerSlots.TITLE })`
133
+ display: block;
112
134
  color: neutral-700;
113
135
  overflow-wrap: break-word;
114
136
  white-space: pre-wrap;
@@ -119,27 +141,38 @@ const StyledSubTitle = (0, import_ds_system.styled)(import_ds_typography.DSTypog
119
141
  overflow-wrap: break-word;
120
142
  white-space: pre-wrap;
121
143
  min-width: 0px;
122
- ${({ theme }) => {
123
- if (["s", "xs"].includes(theme.layoutMode)) {
124
- return `
125
- grid-column: 1 / -1;
126
- `;
127
- }
128
- return "";
129
- }}
144
+ padding-bottom: 9px;
130
145
  `;
131
- const StyledActionLink = (0, import_ds_system.styled)("a", {
146
+ const StyledActionLink = (0, import_ds_system.styled)(import_ds_typography.DSTypography, {
132
147
  name: import_constants.DSBannerName,
133
148
  slot: import_constants.DSBannerSlots.ACTION_LINK
134
149
  })`
135
- display: inline-block;
136
- text-decoration: none;
137
- line-height: inherit;
138
- font-size: inherit;
139
- font-weight: ${({ theme }) => theme.fontWeights.regular};
140
- color: brand-600;
141
150
  min-width: 0px;
142
151
  position: relative;
152
+ margin-bottom: 9px;
153
+ ${(props) => isSmallLayout(props) ? `
154
+ justify-self: start;
155
+ ` : `
156
+ grid-column: 2;
157
+ grid-row: ${props.isBodyEmpty ? 1 : 2};
158
+ align-self: end;
159
+ align-self: last baseline;
160
+ margin-left: 16px;
161
+ `}
162
+ /* Typography and underline of the action link (PUI-19233).
163
+ Size comes from the link-sml-title variant (set in DSBannerContent). The rest is the Link "inline text" styling:
164
+ idle underline + brand-600, hover no underline + brand-800 (decided: the link is underlined at rest).
165
+ PENDING UX CONFIRMATION: only font-weight (400 vs the variant's weight; the spec names a variant that does not
166
+ exist) and line-height (the description's, the variant's 24px would make the banner taller and misalign the
167
+ baselines). Adjusting them once UX answers should only touch those two declarations. */
168
+ font-weight: ${({ theme }) => theme.fontWeights.regular};
169
+ line-height: 1.278;
170
+ text-decoration: underline;
171
+ color: brand-600;
172
+ &:hover {
173
+ text-decoration: none;
174
+ color: brand-800;
175
+ }
143
176
  &:focus {
144
177
  outline: none;
145
178
  &:after {
@@ -160,7 +193,8 @@ const StyledCloseButton = (0, import_ds_system.styled)(import_ds_button_v2.DSBut
160
193
  name: import_constants.DSBannerName,
161
194
  slot: import_constants.DSBannerSlots.CLOSE_BUTTON
162
195
  })`
163
- margin: 5px;
196
+ margin-top: 4px;
197
+ margin-left: 8px;
164
198
  `;
165
199
  const StyledLiveRegionPortal = (0, import_ds_system.styled)("div", {
166
200
  name: import_constants.DSBannerName,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/styles.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["import { DSButtonV2 } from '@elliemae/ds-button-v2';\nimport { Grid } from '@elliemae/ds-grid';\nimport type { ColorProps, LayoutProps, SizingProps, SpaceProps } from '@elliemae/ds-system';\nimport { styled, xStyledCommonProps } from '@elliemae/ds-system';\nimport { DSTypography } from '@elliemae/ds-typography';\nimport { BANNER_TYPES, DSBannerName, DSBannerSlots } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\n\ninterface StyledBannerContainerT extends SizingProps, LayoutProps, SpaceProps, ColorProps {}\nexport const StyledBannerContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.CONTAINER,\n})<StyledBannerContainerT>`\n min-height: 59px;\n overflow: hidden;\n transition: all 0.5s ease-in;\n @starting-style {\n max-height: 0px;\n }\n ${xStyledCommonProps}\n`;\n\ninterface StyledInnerContainerT {}\nexport const StyledInnerContainer = styled(Grid, {\n name: DSBannerName,\n slot: DSBannerSlots.INNER_CONTAINER,\n})<StyledInnerContainerT>`\n padding-right: 4px;\n width: 100%;\n min-width: 0;\n`;\n\nconst handleBorderColor = (\n type: DSBannerT.BannerTypesT,\n { colors }: { colors: Record<string, Record<string, string>> },\n): string => {\n switch (type) {\n case BANNER_TYPES.SUCCESS:\n return colors.success[900];\n case BANNER_TYPES.INFO:\n return colors.brand[600];\n case BANNER_TYPES.WARNING:\n return colors.warning[900];\n case BANNER_TYPES.DANGER:\n return colors.danger[900];\n default:\n return 'should_not_happen';\n }\n};\ninterface StyledBannerLayoutT {\n $type: DSBannerT.BannerTypesT;\n}\nexport const StyledBannerLayout = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LAYOUT,\n})<StyledBannerLayoutT>`\n display: flex;\n width: 100%;\n align-items: flex-start;\n justify-content: space-between;\n background-color: neutral-000;\n border-bottom: 5px solid ${({ $type, theme }) => handleBorderColor($type, theme)};\n & > :first-child {\n flex: 1;\n min-width: 0;\n }\n`;\n\nexport const StyledIconContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.ICON_CONTAINER,\n})`\n padding-top: 8px;\n margin-right: ${({ theme }) => theme.space.xxs};\n margin-left: ${({ theme }) => theme.space.xs};\n min-width: 0px;\n`;\n\nexport const StyledBody = styled('div', { name: DSBannerName, slot: DSBannerSlots.BODY })`\n padding-top: 9px;\n padding-bottom: 9px;\n`;\n\nexport const StyledTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.TITLE })`\n color: neutral-700;\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n`;\n\nexport const StyledSubTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.SUBTITLE })`\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n ${({ theme }) => {\n if (['s', 'xs'].includes(theme.layoutMode!)) {\n return `\n grid-column: 1 / -1;\n `;\n }\n return '';\n }}\n`;\n\ninterface StyledActionLinkT {\n isBodyEmpty: boolean;\n}\nexport const StyledActionLink = styled('a', {\n name: DSBannerName,\n slot: DSBannerSlots.ACTION_LINK,\n})<StyledActionLinkT>`\n display: inline-block;\n text-decoration: none;\n line-height: inherit;\n font-size: inherit;\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n color: brand-600;\n min-width: 0px;\n position: relative;\n &:focus {\n outline: none;\n &:after {\n position: absolute;\n content: '';\n top: -2px;\n left: -2px;\n right: -2px;\n bottom: -2px;\n border-radius: 2px;\n border: 2px solid brand-700;\n box-shadow: 0 0 0 1px brand-700;\n pointer-events: none;\n }\n }\n`;\nexport const StyledCloseButton = styled(DSButtonV2, {\n name: DSBannerName,\n slot: DSBannerSlots.CLOSE_BUTTON,\n})`\n margin: 5px;\n`;\n\nexport const StyledLiveRegionPortal = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LIVE_REGION_PORTAL,\n})`\n clip: rect(0 0 0 0);\n position: absolute;\n`;\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,0BAA2B;AAC3B,qBAAqB;AAErB,uBAA2C;AAC3C,2BAA6B;AAC7B,uBAA0D;AAInD,MAAM,4BAAwB,yBAAO,OAAO;AAAA,EACjD,MAAM;AAAA,EACN,MAAM,+BAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOG,mCAAkB;AAAA;AAIf,MAAM,2BAAuB,yBAAO,qBAAM;AAAA,EAC/C,MAAM;AAAA,EACN,MAAM,+BAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAMD,MAAM,oBAAoB,CACxB,MACA,EAAE,OAAO,MACE;AACX,UAAQ,MAAM;AAAA,IACZ,KAAK,8BAAa;AAChB,aAAO,OAAO,QAAQ,GAAG;AAAA,IAC3B,KAAK,8BAAa;AAChB,aAAO,OAAO,MAAM,GAAG;AAAA,IACzB,KAAK,8BAAa;AAChB,aAAO,OAAO,QAAQ,GAAG;AAAA,IAC3B,KAAK,8BAAa;AAChB,aAAO,OAAO,OAAO,GAAG;AAAA,IAC1B;AACE,aAAO;AAAA,EACX;AACF;AAIO,MAAM,yBAAqB,yBAAO,OAAO;AAAA,EAC9C,MAAM;AAAA,EACN,MAAM,+BAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAM4B,CAAC,EAAE,OAAO,MAAM,MAAM,kBAAkB,OAAO,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAO3E,MAAM,0BAAsB,yBAAO,OAAO;AAAA,EAC/C,MAAM;AAAA,EACN,MAAM,+BAAc;AACtB,CAAC;AAAA;AAAA,kBAEiB,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,GAAG;AAAA,iBAC/B,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,EAAE;AAAA;AAAA;AAIvC,MAAM,iBAAa,yBAAO,OAAO,EAAE,MAAM,+BAAc,MAAM,+BAAc,KAAK,CAAC;AAAA;AAAA;AAAA;AAKjF,MAAM,kBAAc,yBAAO,mCAAc,EAAE,MAAM,+BAAc,MAAM,+BAAc,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAO1F,MAAM,qBAAiB,yBAAO,mCAAc,EAAE,MAAM,+BAAc,MAAM,+BAAc,SAAS,CAAC;AAAA,iBACtF,CAAC,EAAE,MAAM,MAAM,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA,IAIrD,CAAC,EAAE,MAAM,MAAM;AACf,MAAI,CAAC,KAAK,IAAI,EAAE,SAAS,MAAM,UAAW,GAAG;AAC3C,WAAO;AAAA;AAAA;AAAA,EAGT;AACA,SAAO;AACT,CAAC;AAAA;AAMI,MAAM,uBAAmB,yBAAO,KAAK;AAAA,EAC1C,MAAM;AAAA,EACN,MAAM,+BAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,iBAKgB,CAAC,EAAE,MAAM,MAAM,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBlD,MAAM,wBAAoB,yBAAO,gCAAY;AAAA,EAClD,MAAM;AAAA,EACN,MAAM,+BAAc;AACtB,CAAC;AAAA;AAAA;AAIM,MAAM,6BAAyB,yBAAO,OAAO;AAAA,EAClD,MAAM;AAAA,EACN,MAAM,+BAAc;AACtB,CAAC;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import { DSButtonV2 } from '@elliemae/ds-button-v2';\nimport { Grid } from '@elliemae/ds-grid';\nimport type { ColorProps, LayoutProps, SizingProps, SpaceProps } from '@elliemae/ds-system';\nimport { styled, xStyledCommonProps } from '@elliemae/ds-system';\nimport { DSTypography } from '@elliemae/ds-typography';\nimport { BANNER_SLIDE_DURATION_MS, BANNER_TYPES, DSBannerName, DSBannerSlots } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\n\ninterface StyledBannerContainerT extends SizingProps, LayoutProps, SpaceProps, ColorProps {\n $isExpanded?: boolean;\n}\n// The slide animates the height of an intrinsically sized (auto height) element, which css can not interpolate with\n// \"height\" or \"max-height\" (auto/none are not interpolable, and min-height would clamp the collapsed state anyway).\n// Instead the single child (the layout, the live region lives in a portal) is the item of a one track grid whose row goes\n// from 0fr to 1fr: the row is always sized from the content so it follows wrapping, small layouts and text resize.\n// The tracks are minmax(0, Xfr) and not plain Xfr because the item has a border (the type color line): a plain 0fr track\n// can not be smaller than the item's border box, so it would collapse to 5px instead of 0.\n// The open slide is css only (@starting-style, the container mounts expanded), the close slide needs the container to\n// still be mounted when $isExpanded turns false, which is handled by useBannerExitAnimation.\nexport const StyledBannerContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.CONTAINER,\n})<StyledBannerContainerT>`\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n height: fit-content;\n grid-template-rows: ${({ $isExpanded = true }) => ($isExpanded ? 'minmax(0, 1fr)' : 'minmax(0, 0fr)')};\n min-height: ${({ $isExpanded = true }) => ($isExpanded ? '59px' : '0px')};\n overflow: hidden;\n transition:\n grid-template-rows ${BANNER_SLIDE_DURATION_MS}ms ease-in,\n min-height ${BANNER_SLIDE_DURATION_MS}ms ease-in;\n @starting-style {\n grid-template-rows: minmax(0, 0fr);\n min-height: 0px;\n }\n & > * {\n align-self: start;\n min-height: 0;\n overflow: hidden;\n }\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n ${xStyledCommonProps}\n`;\n\ninterface StyledInnerContainerT {}\nexport const StyledInnerContainer = styled(Grid, {\n name: DSBannerName,\n slot: DSBannerSlots.INNER_CONTAINER,\n})<StyledInnerContainerT>`\n padding-right: 4px;\n width: 100%;\n min-width: 0;\n`;\n\nconst handleBorderColor = (\n type: DSBannerT.BannerTypesT,\n { colors }: { colors: Record<string, Record<string, string>> },\n): string => {\n switch (type) {\n case BANNER_TYPES.SUCCESS:\n return colors.success[900];\n case BANNER_TYPES.INFO:\n return colors.brand[600];\n case BANNER_TYPES.WARNING:\n return colors.warning[900];\n case BANNER_TYPES.DANGER:\n return colors.danger[900];\n default:\n return 'should_not_happen';\n }\n};\ninterface StyledBannerLayoutT {\n $type: DSBannerT.BannerTypesT;\n}\nexport const StyledBannerLayout = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LAYOUT,\n})<StyledBannerLayoutT>`\n display: flex;\n width: 100%;\n align-items: flex-start;\n justify-content: space-between;\n background-color: neutral-000;\n border-bottom: 5px solid ${({ $type, theme }) => handleBorderColor($type, theme)};\n & > :first-child {\n flex: 1;\n min-width: 0;\n }\n`;\n\nexport const StyledIconContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.ICON_CONTAINER,\n})`\n padding-top: 8px;\n margin-right: ${({ theme }) => theme.space.xxs};\n margin-left: ${({ theme }) => theme.space.xs};\n min-width: 0px;\n`;\n\nconst isSmallLayout = ({ theme }: { theme: { layoutMode?: string } }) => ['s', 'xs'].includes(theme.layoutMode!);\n\n// title, description and action link are the 3 children (in this order). Default layouts: the title and the description\n// share the first column and the action link is its own cell right after the text (the first column grows with the\n// text up to the free space, the link keeps its own width). Small layouts: a single column, the link goes on its own\n// row below the description.\nexport const StyledBody = styled('div', { name: DSBannerName, slot: DSBannerSlots.BODY })`\n display: grid;\n grid-template-columns: ${(props) => (isSmallLayout(props) ? 'minmax(0, 1fr)' : 'minmax(0, max-content) auto')};\n justify-content: start;\n padding-top: 9px;\n & > :nth-child(-n + 2) {\n grid-column: 1;\n }\n`;\n\nexport const StyledTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.TITLE })`\n display: block;\n color: neutral-700;\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n`;\n\n// the description carries the bottom spacing of the content area (Spec v2)\nexport const StyledSubTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.SUBTITLE })`\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n padding-bottom: 9px;\n`;\n\ninterface StyledActionLinkT {\n isBodyEmpty: boolean;\n}\n// its own cell of the StyledBody grid (never inline in the description), nested in DSTypography (link-sml-title variant).\nexport const StyledActionLink = styled(DSTypography, {\n name: DSBannerName,\n slot: DSBannerSlots.ACTION_LINK,\n})<StyledActionLinkT>`\n min-width: 0px;\n position: relative;\n margin-bottom: 9px;\n ${(props) =>\n isSmallLayout(props)\n ? `\n justify-self: start;\n `\n : `\n grid-column: 2;\n grid-row: ${props.isBodyEmpty ? 1 : 2};\n align-self: end;\n align-self: last baseline;\n margin-left: 16px;\n `}\n /* Typography and underline of the action link (PUI-19233).\n Size comes from the link-sml-title variant (set in DSBannerContent). The rest is the Link \"inline text\" styling:\n idle underline + brand-600, hover no underline + brand-800 (decided: the link is underlined at rest).\n PENDING UX CONFIRMATION: only font-weight (400 vs the variant's weight; the spec names a variant that does not\n exist) and line-height (the description's, the variant's 24px would make the banner taller and misalign the\n baselines). Adjusting them once UX answers should only touch those two declarations. */\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n line-height: 1.278;\n text-decoration: underline;\n color: brand-600;\n &:hover {\n text-decoration: none;\n color: brand-800;\n }\n &:focus {\n outline: none;\n &:after {\n position: absolute;\n content: '';\n top: -2px;\n left: -2px;\n right: -2px;\n bottom: -2px;\n border-radius: 2px;\n border: 2px solid brand-700;\n box-shadow: 0 0 0 1px brand-700;\n pointer-events: none;\n }\n }\n`;\nexport const StyledCloseButton = styled(DSButtonV2, {\n name: DSBannerName,\n slot: DSBannerSlots.CLOSE_BUTTON,\n})`\n margin-top: 4px;\n margin-left: 8px;\n`;\n\nexport const StyledLiveRegionPortal = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LIVE_REGION_PORTAL,\n})`\n clip: rect(0 0 0 0);\n position: absolute;\n`;\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var useBannerContainer_exports = {};
30
+ __export(useBannerContainer_exports, {
31
+ useBannerContainer: () => useBannerContainer
32
+ });
33
+ module.exports = __toCommonJS(useBannerContainer_exports);
34
+ var React = __toESM(require("react"));
35
+ var import_react = require("react");
36
+ var import_useBannerExitAnimation = require("./useBannerExitAnimation.js");
37
+ const useBannerContainer = (isOpen, actionRef) => {
38
+ const exitAnimation = (0, import_useBannerExitAnimation.useBannerExitAnimation)(isOpen);
39
+ const handleActionRefForContainer = (0, import_react.useCallback)(
40
+ (containerNode) => {
41
+ if (containerNode && actionRef && actionRef.current) {
42
+ actionRef.current.focusOnWrapper = () => {
43
+ if (containerNode) {
44
+ setTimeout(() => {
45
+ containerNode?.focus();
46
+ }, 300);
47
+ }
48
+ };
49
+ }
50
+ },
51
+ [actionRef]
52
+ );
53
+ return { handleActionRefForContainer, ...exitAnimation };
54
+ };
55
+ //# sourceMappingURL=useBannerContainer.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/useBannerContainer.ts", "../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import type React from 'react';\nimport { useCallback } from 'react';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { useBannerExitAnimation } from './useBannerExitAnimation.js';\n\n// everything the container needs from its lifecycle: the actionRef.focusOnWrapper hookup and the exit animation\nexport const useBannerContainer = (isOpen: boolean, actionRef: DSBannerT.InternalProps['actionRef']) => {\n const exitAnimation = useBannerExitAnimation(isOpen);\n\n const handleActionRefForContainer = useCallback<React.RefCallback<HTMLDivElement>>(\n (containerNode) => {\n if (containerNode && actionRef && actionRef.current) {\n actionRef.current.focusOnWrapper = () => {\n if (containerNode) {\n setTimeout(() => {\n containerNode?.focus();\n }, 300);\n }\n };\n }\n },\n [actionRef],\n );\n\n return { handleActionRefForContainer, ...exitAnimation };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAA4B;AAE5B,oCAAuC;AAGhC,MAAM,qBAAqB,CAAC,QAAiB,cAAoD;AACtG,QAAM,oBAAgB,sDAAuB,MAAM;AAEnD,QAAM,kCAA8B;AAAA,IAClC,CAAC,kBAAkB;AACjB,UAAI,iBAAiB,aAAa,UAAU,SAAS;AACnD,kBAAU,QAAQ,iBAAiB,MAAM;AACvC,cAAI,eAAe;AACjB,uBAAW,MAAM;AACf,6BAAe,MAAM;AAAA,YACvB,GAAG,GAAG;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,SAAO,EAAE,6BAA6B,GAAG,cAAc;AACzD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var useBannerExitAnimation_exports = {};
30
+ __export(useBannerExitAnimation_exports, {
31
+ useBannerExitAnimation: () => useBannerExitAnimation
32
+ });
33
+ module.exports = __toCommonJS(useBannerExitAnimation_exports);
34
+ var React = __toESM(require("react"));
35
+ var import_react = require("react");
36
+ var import_constants = require("./constants/index.js");
37
+ const EXIT_FALLBACK_MS = import_constants.BANNER_SLIDE_DURATION_MS + 100;
38
+ const SLIDE_PROPERTY = "grid-template-rows";
39
+ const prefersReducedMotion = () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
40
+ const useBannerExitAnimation = (isOpen) => {
41
+ const [wasOpen, setWasOpen] = (0, import_react.useState)(isOpen);
42
+ const [isExiting, setIsExiting] = (0, import_react.useState)(false);
43
+ if (wasOpen !== isOpen) {
44
+ setWasOpen(isOpen);
45
+ setIsExiting(wasOpen && !isOpen && !prefersReducedMotion());
46
+ }
47
+ (0, import_react.useEffect)(() => {
48
+ if (!isExiting) return void 0;
49
+ const timeoutId = setTimeout(() => setIsExiting(false), EXIT_FALLBACK_MS);
50
+ return () => clearTimeout(timeoutId);
51
+ }, [isExiting]);
52
+ const handleTransitionEnd = (0, import_react.useCallback)((e) => {
53
+ if (e.target === e.currentTarget && e.propertyName === SLIDE_PROPERTY) setIsExiting(false);
54
+ }, []);
55
+ const containerExitProps = (0, import_react.useMemo)(
56
+ () => isExiting ? { inert: "", "aria-hidden": true, onTransitionEnd: handleTransitionEnd } : {},
57
+ [isExiting, handleTransitionEnd]
58
+ );
59
+ return {
60
+ isContainerRendered: isOpen || isExiting,
61
+ containerExitProps,
62
+ // the live region does not wait for the slide: it remounts (empty) in the same commit that closes the banner
63
+ liveRegionKey: isOpen ? "open" : "closing"
64
+ };
65
+ };
66
+ //# sourceMappingURL=useBannerExitAnimation.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/useBannerExitAnimation.ts", "../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import type React from 'react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { BANNER_SLIDE_DURATION_MS } from './constants/index.js';\n\n// the css transition is the source of truth for the exit, the timer is the safety net for the cases in which\n// \"transitionend\" never fires (jsdom, display none ancestor, consumer overriding the transition, interrupted transitions)\nconst EXIT_FALLBACK_MS = BANNER_SLIDE_DURATION_MS + 100;\nconst SLIDE_PROPERTY = 'grid-template-rows';\n\nconst prefersReducedMotion = () =>\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\ntype ExitProps = React.HTMLAttributes<HTMLDivElement> & { inert?: string };\n\n/**\n * Keeps the banner container mounted while it slides up after `isOpen` turns false.\n * Opening needs no state: the container mounts expanded and the css `@starting-style` slides it down.\n * With `prefers-reduced-motion: reduce` there is no exit phase, the banner is removed right away like it always was.\n */\nexport const useBannerExitAnimation = (isOpen: boolean) => {\n const [wasOpen, setWasOpen] = useState(isOpen);\n const [isExiting, setIsExiting] = useState(false);\n\n // derived during render (not in an effect): the container must still be there in the very commit that closes it,\n // otherwise there is no frame in which the transition can run. Re-opening mid exit cancels the exit.\n if (wasOpen !== isOpen) {\n setWasOpen(isOpen);\n setIsExiting(wasOpen && !isOpen && !prefersReducedMotion());\n }\n\n // synchronizes with an external system (the timers of the browser) while exiting\n // the cleanup runs on re-open, on unmount and when the exit finishes, so the timer can not fire after any of them\n useEffect(() => {\n if (!isExiting) return undefined;\n const timeoutId = setTimeout(() => setIsExiting(false), EXIT_FALLBACK_MS);\n return () => clearTimeout(timeoutId);\n }, [isExiting]);\n\n const handleTransitionEnd = useCallback((e: React.TransitionEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget && e.propertyName === SLIDE_PROPERTY) setIsExiting(false);\n }, []);\n\n // while sliding up the banner is already closed for everyone: no focus, no pointer, out of the a11y tree\n const containerExitProps = useMemo<ExitProps>(\n () => (isExiting ? { inert: '', 'aria-hidden': true, onTransitionEnd: handleTransitionEnd } : {}),\n [isExiting, handleTransitionEnd],\n );\n\n return {\n isContainerRendered: isOpen || isExiting,\n containerExitProps,\n // the live region does not wait for the slide: it remounts (empty) in the same commit that closes the banner\n liveRegionKey: isOpen ? 'open' : 'closing',\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,mBAA0D;AAC1D,uBAAyC;AAIzC,MAAM,mBAAmB,4CAA2B;AACpD,MAAM,iBAAiB;AAEvB,MAAM,uBAAuB,MAC3B,OAAO,WAAW,eAClB,OAAO,OAAO,eAAe,cAC7B,OAAO,WAAW,kCAAkC,EAAE;AASjD,MAAM,yBAAyB,CAAC,WAAoB;AACzD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,MAAM;AAC7C,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAIhD,MAAI,YAAY,QAAQ;AACtB,eAAW,MAAM;AACjB,iBAAa,WAAW,CAAC,UAAU,CAAC,qBAAqB,CAAC;AAAA,EAC5D;AAIA,8BAAU,MAAM;AACd,QAAI,CAAC,UAAW,QAAO;AACvB,UAAM,YAAY,WAAW,MAAM,aAAa,KAAK,GAAG,gBAAgB;AACxE,WAAO,MAAM,aAAa,SAAS;AAAA,EACrC,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,0BAAsB,0BAAY,CAAC,MAA6C;AACpF,QAAI,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,eAAgB,cAAa,KAAK;AAAA,EAC3F,GAAG,CAAC,CAAC;AAGL,QAAM,yBAAqB;AAAA,IACzB,MAAO,YAAY,EAAE,OAAO,IAAI,eAAe,MAAM,iBAAiB,oBAAoB,IAAI,CAAC;AAAA,IAC/F,CAAC,WAAW,mBAAmB;AAAA,EACjC;AAEA,SAAO;AAAA,IACL,qBAAqB,UAAU;AAAA,IAC/B;AAAA;AAAA,IAEA,eAAe,SAAS,SAAS;AAAA,EACnC;AACF;",
6
+ "names": []
7
+ }
@@ -13,6 +13,7 @@ import { useGetLayoutMode } from "@elliemae/ds-system";
13
13
  import { DSBannerContent } from "./DSBannerContent.js";
14
14
  import { LiveRegionCorrectlyImplemented } from "./LiveRegionCorrectlyImplemented.js";
15
15
  import { DSBannerDatatestid, DSBannerName } from "./constants/index.js";
16
+ import { useBannerContainer } from "./useBannerContainer.js";
16
17
  import { usePageNotice } from "./usePageNotice.js";
17
18
  import { defaultProps, DSBannerPropTypesSchema } from "./react-desc-prop-types.js";
18
19
  import { StyledBannerContainer, StyledBannerLayout, StyledCloseButton, StyledInnerContainer } from "./styles.js";
@@ -48,19 +49,9 @@ const DSBanner = (props) => {
48
49
  if (CustomBody) return colsWithCustomBody;
49
50
  return isSmall ? outOfTheBoxColsSmallLayout : outOfTheBoxCols;
50
51
  }, [CustomBody, isSmall]);
51
- const handleActionRefForContainer = useCallback(
52
- (containerNode) => {
53
- if (containerNode && actionRef && actionRef.current) {
54
- actionRef.current.focusOnWrapper = () => {
55
- if (containerNode) {
56
- setTimeout(() => {
57
- containerNode?.focus();
58
- }, 300);
59
- }
60
- };
61
- }
62
- },
63
- [actionRef]
52
+ const { handleActionRefForContainer, isContainerRendered, containerExitProps, liveRegionKey } = useBannerContainer(
53
+ isOpen,
54
+ actionRef
64
55
  );
65
56
  const { baseId, contentIds, pageNoticeNameProps } = usePageNotice(propsWithDefaults, props, globalAttrs);
66
57
  const handleOnKeyDownToClose = useCallback(
@@ -86,7 +77,7 @@ const DSBanner = (props) => {
86
77
  useEffect(() => {
87
78
  if (isOpen && getIsLiveRegion(withLiveRegionAnnouncement)) read();
88
79
  }, [isOpen, withLiveRegionAnnouncement, read]);
89
- if (!isOpen)
80
+ if (!isContainerRendered)
90
81
  return getIsLiveRegion(withLiveRegionAnnouncement) ? /* @__PURE__ */ jsx(
91
82
  LiveRegionCorrectlyImplemented,
92
83
  {
@@ -105,10 +96,12 @@ const DSBanner = (props) => {
105
96
  innerRef: handleActionRefForContainer,
106
97
  tabIndex: -1,
107
98
  role: isPageNotice ? "region" : void 0,
99
+ $isExpanded: isOpen,
108
100
  ...pageNoticeNameProps,
109
101
  ...containerProps,
110
102
  ...globalAttrs,
111
103
  ...xstyledAttrs,
104
+ ...containerExitProps,
112
105
  ...ownerPropsConfig,
113
106
  children: [
114
107
  /* @__PURE__ */ jsxs(StyledBannerLayout, { ...ownerPropsConfig, $type: type, children: [
@@ -146,7 +139,8 @@ const DSBanner = (props) => {
146
139
  announcementType: withLiveRegionAnnouncement,
147
140
  ownerPropsConfig,
148
141
  globalAttrs
149
- }
142
+ },
143
+ liveRegionKey
150
144
  ) : null
151
145
  ]
152
146
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/DSBanner.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { CloseX } from '@elliemae/ds-icons';\nimport {\n describe,\n useGetGlobalAttributes,\n useGetXstyledProps,\n useMemoMergePropsWithDefault,\n useOwnerProps,\n} from '@elliemae/ds-props-helpers';\nimport React, { useCallback, useEffect, useMemo } from 'react';\nimport { useGetLayoutMode } from '@elliemae/ds-system';\nimport { DSBannerContent } from './DSBannerContent.js';\nimport { LiveRegionCorrectlyImplemented } from './LiveRegionCorrectlyImplemented.js';\nimport { DSBannerDatatestid, DSBannerName } from './constants/index.js';\nimport { usePageNotice } from './usePageNotice.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { defaultProps, DSBannerPropTypesSchema } from './react-desc-prop-types.js';\nimport { StyledBannerContainer, StyledBannerLayout, StyledCloseButton, StyledInnerContainer } from './styles.js';\n\nconst outOfTheBoxCols = ['auto', '1fr'];\nconst outOfTheBoxColsSmallLayout = ['auto', '1fr'];\nconst colsWithCustomBody = ['1fr', 'auto'];\n\nconst getIsLiveRegion = (type: string) => type === 'polite' || type === 'assertive';\n\nconst DSBanner: React.ComponentType<DSBannerT.Props> = (props) => {\n const propsWithDefaults = useMemoMergePropsWithDefault<DSBannerT.InternalProps>(props, defaultProps);\n\n const {\n type,\n isOpen,\n onClose,\n label,\n body,\n closeBtnRef,\n CustomBody,\n actionLink,\n showCloseButton,\n containerProps,\n actionRef,\n withLiveRegionAnnouncement,\n isPageNotice,\n bannerId,\n ...rest\n } = propsWithDefaults;\n // eslint-disable-next-line no-unused-vars\n const { height: globalHeight, ...globalAttrs } = useGetGlobalAttributes(rest);\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n const xstyledAttrs = useGetXstyledProps(rest);\n\n const layoutMode = useGetLayoutMode();\n const isSmall = layoutMode === 's' || layoutMode === 'xs';\n const innerContainerCols = useMemo(() => {\n if (CustomBody) return colsWithCustomBody;\n return isSmall ? outOfTheBoxColsSmallLayout : outOfTheBoxCols;\n }, [CustomBody, isSmall]);\n\n const handleActionRefForContainer = useCallback<React.RefCallback<HTMLDivElement>>(\n (containerNode) => {\n if (containerNode && actionRef && actionRef.current) {\n actionRef.current.focusOnWrapper = () => {\n if (containerNode) {\n setTimeout(() => {\n containerNode?.focus();\n }, 300);\n }\n };\n }\n },\n [actionRef],\n );\n\n const { baseId, contentIds, pageNoticeNameProps } = usePageNotice(propsWithDefaults, props, globalAttrs);\n\n const handleOnKeyDownToClose = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n }\n },\n [onClose],\n );\n\n const liveRegionRef = React.useRef<HTMLDivElement>(null);\n const isOpenRef = React.useRef(isOpen);\n isOpenRef.current = isOpen;\n const textToAnnounceRef = React.useRef(`${label} ${body}`);\n textToAnnounceRef.current = `${label} ${body}`;\n const read = React.useCallback(() => {\n if (liveRegionRef.current) {\n if (isOpenRef.current) liveRegionRef.current.textContent = textToAnnounceRef.current;\n else liveRegionRef.current.textContent = '';\n }\n }, []);\n\n useEffect(() => {\n if (isOpen && getIsLiveRegion(withLiveRegionAnnouncement)) read();\n }, [isOpen, withLiveRegionAnnouncement, read]);\n\n // this used to \"try\" to animate the banner closing\n // in reality the closing animation has never actually worked (the banner just disappears, due to using \"&&\" instead of \"||\" in the logic)\n // given that it has never worked, and the complexity it adds to the code, we are officially removing the closing animation for now\n // if there is a future need for it, we can re-visit adding it back in.\n if (!isOpen)\n return getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null;\n\n return (\n <StyledBannerContainer\n onKeyDown={handleOnKeyDownToClose}\n data-testid={DSBannerDatatestid.CONTAINER}\n innerRef={handleActionRefForContainer}\n tabIndex={-1}\n role={isPageNotice ? 'region' : undefined}\n {...pageNoticeNameProps}\n {...containerProps}\n {...globalAttrs}\n {...xstyledAttrs}\n {...ownerPropsConfig}\n >\n <StyledBannerLayout {...ownerPropsConfig} $type={type}>\n <StyledInnerContainer\n cols={innerContainerCols}\n data-type={type}\n data-testid={DSBannerDatatestid.INNER_CONTAINER}\n role={withLiveRegionAnnouncement === 'alert' ? 'alert' : undefined}\n id={baseId}\n {...ownerPropsConfig}\n >\n {!CustomBody ? <DSBannerContent propsWithDefaults={propsWithDefaults} {...contentIds} /> : <CustomBody />}\n </StyledInnerContainer>\n {!CustomBody && showCloseButton ? (\n <StyledCloseButton\n data-testid={DSBannerDatatestid.CLOSE_BUTTON}\n buttonType=\"icon\"\n innerRef={closeBtnRef}\n onClick={onClose}\n aria-label=\"Visually dismiss the banner\"\n aria-describedby={baseId}\n {...ownerPropsConfig}\n >\n <CloseX width={12} height={12} />\n </StyledCloseButton>\n ) : null}\n </StyledBannerLayout>\n {getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null}\n </StyledBannerContainer>\n );\n};\n\nDSBanner.displayName = DSBannerName;\nconst DSBannerWithSchema = describe(DSBanner);\nDSBannerWithSchema.propTypes = DSBannerPropTypesSchema;\n\nexport default DSBanner;\nexport { DSBanner, DSBannerWithSchema };\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { CloseX } from '@elliemae/ds-icons';\nimport {\n describe,\n useGetGlobalAttributes,\n useGetXstyledProps,\n useMemoMergePropsWithDefault,\n useOwnerProps,\n} from '@elliemae/ds-props-helpers';\nimport React, { useCallback, useEffect, useMemo } from 'react';\nimport { useGetLayoutMode } from '@elliemae/ds-system';\nimport { DSBannerContent } from './DSBannerContent.js';\nimport { LiveRegionCorrectlyImplemented } from './LiveRegionCorrectlyImplemented.js';\nimport { DSBannerDatatestid, DSBannerName } from './constants/index.js';\nimport { useBannerContainer } from './useBannerContainer.js';\nimport { usePageNotice } from './usePageNotice.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { defaultProps, DSBannerPropTypesSchema } from './react-desc-prop-types.js';\nimport { StyledBannerContainer, StyledBannerLayout, StyledCloseButton, StyledInnerContainer } from './styles.js';\n\nconst outOfTheBoxCols = ['auto', '1fr'];\nconst outOfTheBoxColsSmallLayout = ['auto', '1fr'];\nconst colsWithCustomBody = ['1fr', 'auto'];\n\nconst getIsLiveRegion = (type: string) => type === 'polite' || type === 'assertive';\n\nconst DSBanner: React.ComponentType<DSBannerT.Props> = (props) => {\n const propsWithDefaults = useMemoMergePropsWithDefault<DSBannerT.InternalProps>(props, defaultProps);\n\n const {\n type,\n isOpen,\n onClose,\n label,\n body,\n closeBtnRef,\n CustomBody,\n actionLink,\n showCloseButton,\n containerProps,\n actionRef,\n withLiveRegionAnnouncement,\n isPageNotice,\n bannerId,\n ...rest\n } = propsWithDefaults;\n // eslint-disable-next-line no-unused-vars\n const { height: globalHeight, ...globalAttrs } = useGetGlobalAttributes(rest);\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n const xstyledAttrs = useGetXstyledProps(rest);\n\n const layoutMode = useGetLayoutMode();\n const isSmall = layoutMode === 's' || layoutMode === 'xs';\n const innerContainerCols = useMemo(() => {\n if (CustomBody) return colsWithCustomBody;\n return isSmall ? outOfTheBoxColsSmallLayout : outOfTheBoxCols;\n }, [CustomBody, isSmall]);\n\n const { handleActionRefForContainer, isContainerRendered, containerExitProps, liveRegionKey } = useBannerContainer(\n isOpen,\n actionRef,\n );\n\n const { baseId, contentIds, pageNoticeNameProps } = usePageNotice(propsWithDefaults, props, globalAttrs);\n\n const handleOnKeyDownToClose = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n }\n },\n [onClose],\n );\n\n const liveRegionRef = React.useRef<HTMLDivElement>(null);\n const isOpenRef = React.useRef(isOpen);\n isOpenRef.current = isOpen;\n const textToAnnounceRef = React.useRef(`${label} ${body}`);\n textToAnnounceRef.current = `${label} ${body}`;\n const read = React.useCallback(() => {\n if (liveRegionRef.current) {\n if (isOpenRef.current) liveRegionRef.current.textContent = textToAnnounceRef.current;\n else liveRegionRef.current.textContent = '';\n }\n }, []);\n\n useEffect(() => {\n if (isOpen && getIsLiveRegion(withLiveRegionAnnouncement)) read();\n }, [isOpen, withLiveRegionAnnouncement, read]);\n\n // the container stays mounted while it slides up after closing (see useBannerExitAnimation)\n if (!isContainerRendered)\n return getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null;\n\n return (\n <StyledBannerContainer\n onKeyDown={handleOnKeyDownToClose}\n data-testid={DSBannerDatatestid.CONTAINER}\n innerRef={handleActionRefForContainer}\n tabIndex={-1}\n role={isPageNotice ? 'region' : undefined}\n $isExpanded={isOpen}\n {...pageNoticeNameProps}\n {...containerProps}\n {...globalAttrs}\n {...xstyledAttrs}\n {...containerExitProps}\n {...ownerPropsConfig}\n >\n <StyledBannerLayout {...ownerPropsConfig} $type={type}>\n <StyledInnerContainer\n cols={innerContainerCols}\n data-type={type}\n data-testid={DSBannerDatatestid.INNER_CONTAINER}\n role={withLiveRegionAnnouncement === 'alert' ? 'alert' : undefined}\n id={baseId}\n {...ownerPropsConfig}\n >\n {!CustomBody ? <DSBannerContent propsWithDefaults={propsWithDefaults} {...contentIds} /> : <CustomBody />}\n </StyledInnerContainer>\n {!CustomBody && showCloseButton ? (\n <StyledCloseButton\n data-testid={DSBannerDatatestid.CLOSE_BUTTON}\n buttonType=\"icon\"\n innerRef={closeBtnRef}\n onClick={onClose}\n aria-label=\"Visually dismiss the banner\"\n aria-describedby={baseId}\n {...ownerPropsConfig}\n >\n <CloseX width={12} height={12} />\n </StyledCloseButton>\n ) : null}\n </StyledBannerLayout>\n {getIsLiveRegion(withLiveRegionAnnouncement) ? (\n <LiveRegionCorrectlyImplemented\n key={liveRegionKey}\n id={`${baseId}-live-region`}\n innerRef={liveRegionRef}\n announcementType={withLiveRegionAnnouncement}\n ownerPropsConfig={ownerPropsConfig}\n globalAttrs={globalAttrs}\n />\n ) : null}\n </StyledBannerContainer>\n );\n};\n\nDSBanner.displayName = DSBannerName;\nconst DSBannerWithSchema = describe(DSBanner);\nDSBannerWithSchema.propTypes = DSBannerPropTypesSchema;\n\nexport default DSBanner;\nexport { DSBanner, DSBannerWithSchema };\n"],
5
+ "mappings": "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",
6
6
  "names": ["React"]
7
7
  }
@@ -43,28 +43,26 @@ const DSBannerContent = (props) => {
43
43
  return /* @__PURE__ */ jsxs(Fragment, { children: [
44
44
  /* @__PURE__ */ jsx(StyledIconContainer, { "data-testid": DSBannerDatatestid.ICON_CONTAINER, ...ownerPropsConfig, children: icons[type] }),
45
45
  /* @__PURE__ */ jsxs(StyledBody, { ...ownerPropsConfig, children: [
46
- /* @__PURE__ */ jsx(StyledTitle, { id: titleId, variant: TYPOGRAPHY_VARIANTS.H5_STRONG, ...ownerPropsConfig, children: label }),
47
- /* @__PURE__ */ jsxs(StyledSubTitle, { id: bodyId, variant: TYPOGRAPHY_VARIANTS.B1, ...ownerPropsConfig, children: [
48
- body,
49
- actionLink && /* @__PURE__ */ jsxs(Fragment, { children: [
50
- !body ? "" : " ",
51
- /* @__PURE__ */ jsx(
52
- StyledActionLink,
53
- {
54
- "data-testid": DSBannerDatatestid.ACTION_LINK,
55
- onClick: actionLink.onClick,
56
- href: actionLink.href,
57
- innerRef: handleActionRefForLink,
58
- onKeyDown: handleOnKeyDown,
59
- tabIndex: 0,
60
- isBodyEmpty: !body,
61
- title: actionLink.label,
62
- ...ownerPropsConfig,
63
- children: actionLink.label
64
- }
65
- )
66
- ] })
67
- ] })
46
+ /* @__PURE__ */ jsx(StyledTitle, { id: titleId, variant: TYPOGRAPHY_VARIANTS.H5_STRONG, component: "span", ...ownerPropsConfig, children: label }),
47
+ /* @__PURE__ */ jsx(StyledSubTitle, { id: bodyId, variant: TYPOGRAPHY_VARIANTS.B1, ...ownerPropsConfig, children: body }),
48
+ actionLink && // its own element (a sibling of the description, not inline in it): the spacing is CSS, not literal spaces.
49
+ // the DSTypography link variant gives the size + DSTypography-root class, the underline/weight pending UX are in styles.tsx
50
+ /* @__PURE__ */ jsx(
51
+ StyledActionLink,
52
+ {
53
+ variant: TYPOGRAPHY_VARIANTS.LINK_SML_TITLE,
54
+ "data-testid": DSBannerDatatestid.ACTION_LINK,
55
+ onClick: actionLink.onClick,
56
+ href: actionLink.href,
57
+ innerRef: handleActionRefForLink,
58
+ onKeyDown: handleOnKeyDown,
59
+ tabIndex: 0,
60
+ isBodyEmpty: !body,
61
+ title: actionLink.label,
62
+ ...ownerPropsConfig,
63
+ children: actionLink.label
64
+ }
65
+ )
68
66
  ] })
69
67
  ] });
70
68
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/DSBannerContent.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-lines */\nimport { AlertsDetailFill, InfoFill, SuccessFill, WarningSquare } from '@elliemae/ds-icons';\nimport { useOwnerProps } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport React, { useCallback } from 'react';\nimport { DSBannerDatatestid } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { StyledActionLink, StyledIconContainer, StyledSubTitle, StyledTitle, StyledBody } from './styles.js';\n\nexport const icons: Record<string, JSX.Element> = {\n success: <SuccessFill color={['success', '900']} width=\"20px\" height=\"20px\" />,\n info: <InfoFill color={['brand-primary', '600']} width=\"20px\" height=\"20px\" />,\n danger: <AlertsDetailFill color={['danger', '900']} width=\"20px\" height=\"20px\" />,\n warning: <WarningSquare color={['warning', '900']} width=\"20px\" height=\"20px\" />,\n};\n\ninterface DSBannerContentProps {\n propsWithDefaults: DSBannerT.InternalProps;\n titleId?: string;\n bodyId?: string;\n}\n\nexport const DSBannerContent: React.ComponentType<DSBannerContentProps> = (props) => {\n const {\n propsWithDefaults,\n titleId,\n bodyId,\n propsWithDefaults: { type, label, body, actionLink, actionRef },\n } = props;\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n\n const linkRef = React.useRef<HTMLAnchorElement>(null) as React.MutableRefObject<HTMLAnchorElement>;\n\n const handleActionRefForLink = useCallback<React.RefCallback<HTMLAnchorElement>>(\n (linkNode) => {\n if (linkNode) {\n linkRef.current = linkNode;\n if (actionRef && actionRef.current) {\n actionRef.current.focusOnLink = () => {\n linkNode?.focus?.();\n };\n }\n }\n },\n [actionRef],\n );\n\n const handleOnKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (linkRef.current) linkRef.current.click();\n }\n }, []);\n\n return (\n <>\n <StyledIconContainer data-testid={DSBannerDatatestid.ICON_CONTAINER} {...ownerPropsConfig}>\n {icons[type]}\n </StyledIconContainer>\n <StyledBody {...ownerPropsConfig}>\n <StyledTitle id={titleId} variant={TYPOGRAPHY_VARIANTS.H5_STRONG} {...ownerPropsConfig}>\n {label}\n </StyledTitle>\n <StyledSubTitle id={bodyId} variant={TYPOGRAPHY_VARIANTS.B1} {...ownerPropsConfig}>\n {body}\n {actionLink && (\n <>\n {/* This way of handling the space is making use of the browser default\n white-space clamping, avoiding lots of JS code. */}\n {!body ? '' : ' '}\n <StyledActionLink\n data-testid={DSBannerDatatestid.ACTION_LINK}\n onClick={actionLink.onClick}\n href={actionLink.href}\n innerRef={handleActionRefForLink}\n onKeyDown={handleOnKeyDown}\n tabIndex={0}\n isBodyEmpty={!body}\n title={actionLink.label}\n {...ownerPropsConfig}\n >\n {actionLink.label}\n </StyledActionLink>\n </>\n )}\n </StyledSubTitle>\n </StyledBody>\n </>\n );\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACUZ,SAwDC,UAxDD,KAwDC,YAxDD;AATX,SAAS,kBAAkB,UAAU,aAAa,qBAAqB;AACvE,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,OAAOA,UAAS,mBAAmB;AACnC,SAAS,0BAA0B;AAEnC,SAAS,kBAAkB,qBAAqB,gBAAgB,aAAa,kBAAkB;AAExF,MAAM,QAAqC;AAAA,EAChD,SAAS,oBAAC,eAAY,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,MAAM,oBAAC,YAAS,OAAO,CAAC,iBAAiB,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,QAAQ,oBAAC,oBAAiB,OAAO,CAAC,UAAU,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC/E,SAAS,oBAAC,iBAAc,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAChF;AAQO,MAAM,kBAA6D,CAAC,UAAU;AACnF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,EAAE,MAAM,OAAO,MAAM,YAAY,UAAU;AAAA,EAChE,IAAI;AACJ,QAAM,mBAAmB,cAAc,mBAAmB,EAAE,GAAG,MAAM,CAAC;AAEtE,QAAM,UAAUA,OAAM,OAA0B,IAAI;AAEpD,QAAM,yBAAyB;AAAA,IAC7B,CAAC,aAAa;AACZ,UAAI,UAAU;AACZ,gBAAQ,UAAU;AAClB,YAAI,aAAa,UAAU,SAAS;AAClC,oBAAU,QAAQ,cAAc,MAAM;AACpC,sBAAU,QAAQ;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,kBAAkB,YAAY,CAAC,MAA2B;AAC9D,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,eAAe;AACjB,UAAI,QAAQ,QAAS,SAAQ,QAAQ,MAAM;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,iCACE;AAAA,wBAAC,uBAAoB,eAAa,mBAAmB,gBAAiB,GAAG,kBACtE,gBAAM,IAAI,GACb;AAAA,IACA,qBAAC,cAAY,GAAG,kBACd;AAAA,0BAAC,eAAY,IAAI,SAAS,SAAS,oBAAoB,WAAY,GAAG,kBACnE,iBACH;AAAA,MACA,qBAAC,kBAAe,IAAI,QAAQ,SAAS,oBAAoB,IAAK,GAAG,kBAC9D;AAAA;AAAA,QACA,cACC,iCAGG;AAAA,WAAC,OAAO,KAAK;AAAA,UACd;AAAA,YAAC;AAAA;AAAA,cACC,eAAa,mBAAmB;AAAA,cAChC,SAAS,WAAW;AAAA,cACpB,MAAM,WAAW;AAAA,cACjB,UAAU;AAAA,cACV,WAAW;AAAA,cACX,UAAU;AAAA,cACV,aAAa,CAAC;AAAA,cACd,OAAO,WAAW;AAAA,cACjB,GAAG;AAAA,cAEH,qBAAW;AAAA;AAAA,UACd;AAAA,WACF;AAAA,SAEJ;AAAA,OACF;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-lines */\nimport { AlertsDetailFill, InfoFill, SuccessFill, WarningSquare } from '@elliemae/ds-icons';\nimport { useOwnerProps } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport React, { useCallback } from 'react';\nimport { DSBannerDatatestid } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { StyledActionLink, StyledIconContainer, StyledSubTitle, StyledTitle, StyledBody } from './styles.js';\n\nexport const icons: Record<string, JSX.Element> = {\n success: <SuccessFill color={['success', '900']} width=\"20px\" height=\"20px\" />,\n info: <InfoFill color={['brand-primary', '600']} width=\"20px\" height=\"20px\" />,\n danger: <AlertsDetailFill color={['danger', '900']} width=\"20px\" height=\"20px\" />,\n warning: <WarningSquare color={['warning', '900']} width=\"20px\" height=\"20px\" />,\n};\n\ninterface DSBannerContentProps {\n propsWithDefaults: DSBannerT.InternalProps;\n titleId?: string;\n bodyId?: string;\n}\n\nexport const DSBannerContent: React.ComponentType<DSBannerContentProps> = (props) => {\n const {\n propsWithDefaults,\n titleId,\n bodyId,\n propsWithDefaults: { type, label, body, actionLink, actionRef },\n } = props;\n const ownerPropsConfig = useOwnerProps(propsWithDefaults, { ...props });\n\n const linkRef = React.useRef<HTMLElement>(null) as React.MutableRefObject<HTMLElement>;\n\n const handleActionRefForLink = useCallback<React.RefCallback<HTMLElement>>(\n (linkNode) => {\n if (linkNode) {\n linkRef.current = linkNode;\n if (actionRef && actionRef.current) {\n actionRef.current.focusOnLink = () => {\n linkNode?.focus?.();\n };\n }\n }\n },\n [actionRef],\n );\n\n const handleOnKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n if (linkRef.current) linkRef.current.click();\n }\n }, []);\n\n return (\n <>\n <StyledIconContainer data-testid={DSBannerDatatestid.ICON_CONTAINER} {...ownerPropsConfig}>\n {icons[type]}\n </StyledIconContainer>\n <StyledBody {...ownerPropsConfig}>\n {/* h5-strong look, but a span: the title must not inject a heading into the host page outline.\n `component` (not `as`): on a styled(DSTypography) wrapper `as` would replace DSTypography itself. */}\n <StyledTitle id={titleId} variant={TYPOGRAPHY_VARIANTS.H5_STRONG} component=\"span\" {...ownerPropsConfig}>\n {label}\n </StyledTitle>\n <StyledSubTitle id={bodyId} variant={TYPOGRAPHY_VARIANTS.B1} {...ownerPropsConfig}>\n {body}\n </StyledSubTitle>\n {actionLink && (\n // its own element (a sibling of the description, not inline in it): the spacing is CSS, not literal spaces.\n // the DSTypography link variant gives the size + DSTypography-root class, the underline/weight pending UX are in styles.tsx\n <StyledActionLink\n variant={TYPOGRAPHY_VARIANTS.LINK_SML_TITLE}\n data-testid={DSBannerDatatestid.ACTION_LINK}\n onClick={actionLink.onClick}\n href={actionLink.href}\n innerRef={handleActionRefForLink}\n onKeyDown={handleOnKeyDown}\n tabIndex={0}\n isBodyEmpty={!body}\n title={actionLink.label}\n {...ownerPropsConfig}\n >\n {actionLink.label}\n </StyledActionLink>\n )}\n </StyledBody>\n </>\n );\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACUZ,SA6CP,UA7CO,KAiDL,YAjDK;AATX,SAAS,kBAAkB,UAAU,aAAa,qBAAqB;AACvE,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,OAAOA,UAAS,mBAAmB;AACnC,SAAS,0BAA0B;AAEnC,SAAS,kBAAkB,qBAAqB,gBAAgB,aAAa,kBAAkB;AAExF,MAAM,QAAqC;AAAA,EAChD,SAAS,oBAAC,eAAY,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,MAAM,oBAAC,YAAS,OAAO,CAAC,iBAAiB,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC5E,QAAQ,oBAAC,oBAAiB,OAAO,CAAC,UAAU,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAAA,EAC/E,SAAS,oBAAC,iBAAc,OAAO,CAAC,WAAW,KAAK,GAAG,OAAM,QAAO,QAAO,QAAO;AAChF;AAQO,MAAM,kBAA6D,CAAC,UAAU;AACnF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,EAAE,MAAM,OAAO,MAAM,YAAY,UAAU;AAAA,EAChE,IAAI;AACJ,QAAM,mBAAmB,cAAc,mBAAmB,EAAE,GAAG,MAAM,CAAC;AAEtE,QAAM,UAAUA,OAAM,OAAoB,IAAI;AAE9C,QAAM,yBAAyB;AAAA,IAC7B,CAAC,aAAa;AACZ,UAAI,UAAU;AACZ,gBAAQ,UAAU;AAClB,YAAI,aAAa,UAAU,SAAS;AAClC,oBAAU,QAAQ,cAAc,MAAM;AACpC,sBAAU,QAAQ;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,kBAAkB,YAAY,CAAC,MAA2B;AAC9D,QAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,eAAe;AACjB,UAAI,QAAQ,QAAS,SAAQ,QAAQ,MAAM;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,iCACE;AAAA,wBAAC,uBAAoB,eAAa,mBAAmB,gBAAiB,GAAG,kBACtE,gBAAM,IAAI,GACb;AAAA,IACA,qBAAC,cAAY,GAAG,kBAGd;AAAA,0BAAC,eAAY,IAAI,SAAS,SAAS,oBAAoB,WAAW,WAAU,QAAQ,GAAG,kBACpF,iBACH;AAAA,MACA,oBAAC,kBAAe,IAAI,QAAQ,SAAS,oBAAoB,IAAK,GAAG,kBAC9D,gBACH;AAAA,MACC;AAAA;AAAA,MAGC;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,oBAAoB;AAAA,UAC7B,eAAa,mBAAmB;AAAA,UAChC,SAAS,WAAW;AAAA,UACpB,MAAM,WAAW;AAAA,UACjB,UAAU;AAAA,UACV,WAAW;AAAA,UACX,UAAU;AAAA,UACV,aAAa,CAAC;AAAA,UACd,OAAO,WAAW;AAAA,UACjB,GAAG;AAAA,UAEH,qBAAW;AAAA;AAAA,MACd;AAAA,OAEJ;AAAA,KACF;AAEJ;",
6
6
  "names": ["React"]
7
7
  }
@@ -7,6 +7,7 @@ const BANNER_TYPES = {
7
7
  WARNING: "warning",
8
8
  DANGER: "danger"
9
9
  };
10
+ const BANNER_SLIDE_DURATION_MS = 500;
10
11
  const BANNER_BODY_ID = "ds-banner-body";
11
12
  const DSBannerSlots = {
12
13
  CONTAINER: "container",
@@ -31,6 +32,7 @@ const DSBannerDatatestid = {
31
32
  };
32
33
  export {
33
34
  BANNER_BODY_ID,
35
+ BANNER_SLIDE_DURATION_MS,
34
36
  BANNER_TYPES,
35
37
  DSBannerDatatestid,
36
38
  DSBannerName,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/constants/index.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { slotObjectToDataTestIds } from '@elliemae/ds-system';\n\nexport const DSBannerName = 'DSBanner';\nexport const BANNER_TYPES = {\n INFO: 'info',\n SUCCESS: 'success',\n WARNING: 'warning',\n DANGER: 'danger',\n} as const;\n\n/**\n * @deprecated legacy export, no longer rendered or used by the component (PUI-19089).\n * The body used to render with this fixed id, which duplicated across banners. The body id is now\n * `<bannerId>-body`, where `bannerId` is generated per instance or provided through the `bannerId` prop.\n * Kept only so imports of the old constant keep resolving.\n */\nexport const BANNER_BODY_ID = 'ds-banner-body';\n\n// previously this was the exported data-testid object\n// the one marked as // ok are the one that works with the slots convention and works with the slotObjectToDataTestIds function\n// the rest are not compatible and needs manual handling\n// export const DSBannerDatatestid = {\n// CONTAINER: 'ds-banner-container', // ok\n// CUSTOM_CONTAINER: 'ds-banner-custom-container', // ok\n// ACTION_LINK: 'ds-banner-action-link', // ok\n// CLOSE_BUTTON: 'ds-banner-close-button', // ok\n// // From here down are not compatible with the slotObjectToDataTestIds function.\n// INNER_CONTAINER: 'ds-banner',\n// ICON_CONTAINER: 'ds-banner-icon',\n// // from here they were not present but they had an asigned Slot.\n// // TITLE\n// // SUBTITLE\n// };\n\n// we are naming this with the ${component_name}_slots convention to namespace & avoid errors on duplicate exports variables in aggregators\n\nexport const DSBannerSlots = {\n CONTAINER: 'container',\n INNER_CONTAINER: 'inner-container',\n // reserved slot: declared but never rendered. It is part of the public surface (DSBannerDatatestid, dsBannerCustomContainer slot prop)\n // and pinned by DSBanner.data-testid.test.js, so removing it is a breaking change. See KNOWN_INTENTIONAL_DEVIATIONS.md\n CUSTOM_CONTAINER: 'custom-container',\n BODY: 'body',\n TITLE: 'title',\n SUBTITLE: 'subtitle',\n ICON_CONTAINER: 'icon-container',\n ACTION_LINK: 'action-link',\n CLOSE_BUTTON: 'close-button',\n LAYOUT: 'layout',\n LIVE_REGION_PORTAL: 'live-region-portal',\n} as const;\n\n// we are naming this with the ${component_name}_data_testid convention to namespace & avoid errors on duplicate exports variables in aggregators\nexport const DSBannerDatatestid = {\n ...(slotObjectToDataTestIds(DSBannerName, DSBannerSlots) as Record<keyof typeof DSBannerSlots, string>),\n // handling the rest of the data-testids that are not compatible with the slotObjectToDataTestIds function manually to avoid breaking changes\n INNER_CONTAINER: 'ds-banner',\n ICON_CONTAINER: 'ds-banner-icon',\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,+BAA+B;AAEjC,MAAM,eAAe;AACrB,MAAM,eAAe;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV;AAQO,MAAM,iBAAiB;AAoBvB,MAAM,gBAAgB;AAAA,EAC3B,WAAW;AAAA,EACX,iBAAiB;AAAA;AAAA;AAAA,EAGjB,kBAAkB;AAAA,EAClB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,oBAAoB;AACtB;AAGO,MAAM,qBAAqB;AAAA,EAChC,GAAI,wBAAwB,cAAc,aAAa;AAAA;AAAA,EAEvD,iBAAiB;AAAA,EACjB,gBAAgB;AAClB;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { slotObjectToDataTestIds } from '@elliemae/ds-system';\n\nexport const DSBannerName = 'DSBanner';\nexport const BANNER_TYPES = {\n INFO: 'info',\n SUCCESS: 'success',\n WARNING: 'warning',\n DANGER: 'danger',\n} as const;\n\n// duration of the slide down (open) and slide up (close) of the banner, defined by the Banner spec v2 \"Motion and Animation\"\nexport const BANNER_SLIDE_DURATION_MS = 500;\n\n/**\n * @deprecated legacy export, no longer rendered or used by the component (PUI-19089).\n * The body used to render with this fixed id, which duplicated across banners. The body id is now\n * `<bannerId>-body`, where `bannerId` is generated per instance or provided through the `bannerId` prop.\n * Kept only so imports of the old constant keep resolving.\n */\nexport const BANNER_BODY_ID = 'ds-banner-body';\n\n// previously this was the exported data-testid object\n// the one marked as // ok are the one that works with the slots convention and works with the slotObjectToDataTestIds function\n// the rest are not compatible and needs manual handling\n// export const DSBannerDatatestid = {\n// CONTAINER: 'ds-banner-container', // ok\n// CUSTOM_CONTAINER: 'ds-banner-custom-container', // ok\n// ACTION_LINK: 'ds-banner-action-link', // ok\n// CLOSE_BUTTON: 'ds-banner-close-button', // ok\n// // From here down are not compatible with the slotObjectToDataTestIds function.\n// INNER_CONTAINER: 'ds-banner',\n// ICON_CONTAINER: 'ds-banner-icon',\n// // from here they were not present but they had an asigned Slot.\n// // TITLE\n// // SUBTITLE\n// };\n\n// we are naming this with the ${component_name}_slots convention to namespace & avoid errors on duplicate exports variables in aggregators\n\nexport const DSBannerSlots = {\n CONTAINER: 'container',\n INNER_CONTAINER: 'inner-container',\n // reserved slot: declared but never rendered. It is part of the public surface (DSBannerDatatestid, dsBannerCustomContainer slot prop)\n // and pinned by DSBanner.data-testid.test.js, so removing it is a breaking change. See KNOWN_INTENTIONAL_DEVIATIONS.md\n CUSTOM_CONTAINER: 'custom-container',\n BODY: 'body',\n TITLE: 'title',\n SUBTITLE: 'subtitle',\n ICON_CONTAINER: 'icon-container',\n ACTION_LINK: 'action-link',\n CLOSE_BUTTON: 'close-button',\n LAYOUT: 'layout',\n LIVE_REGION_PORTAL: 'live-region-portal',\n} as const;\n\n// we are naming this with the ${component_name}_data_testid convention to namespace & avoid errors on duplicate exports variables in aggregators\nexport const DSBannerDatatestid = {\n ...(slotObjectToDataTestIds(DSBannerName, DSBannerSlots) as Record<keyof typeof DSBannerSlots, string>),\n // handling the rest of the data-testids that are not compatible with the slotObjectToDataTestIds function manually to avoid breaking changes\n INNER_CONTAINER: 'ds-banner',\n ICON_CONTAINER: 'ds-banner-icon',\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,+BAA+B;AAEjC,MAAM,eAAe;AACrB,MAAM,eAAe;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV;AAGO,MAAM,2BAA2B;AAQjC,MAAM,iBAAiB;AAoBvB,MAAM,gBAAgB;AAAA,EAC3B,WAAW;AAAA,EACX,iBAAiB;AAAA;AAAA;AAAA,EAGjB,kBAAkB;AAAA,EAClB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,oBAAoB;AACtB;AAGO,MAAM,qBAAqB;AAAA,EAChC,GAAI,wBAAwB,cAAc,aAAa;AAAA;AAAA,EAEvD,iBAAiB;AAAA,EACjB,gBAAgB;AAClB;",
6
6
  "names": []
7
7
  }
@@ -3,16 +3,31 @@ import { DSButtonV2 } from "@elliemae/ds-button-v2";
3
3
  import { Grid } from "@elliemae/ds-grid";
4
4
  import { styled, xStyledCommonProps } from "@elliemae/ds-system";
5
5
  import { DSTypography } from "@elliemae/ds-typography";
6
- import { BANNER_TYPES, DSBannerName, DSBannerSlots } from "./constants/index.js";
6
+ import { BANNER_SLIDE_DURATION_MS, BANNER_TYPES, DSBannerName, DSBannerSlots } from "./constants/index.js";
7
7
  const StyledBannerContainer = styled("div", {
8
8
  name: DSBannerName,
9
9
  slot: DSBannerSlots.CONTAINER
10
10
  })`
11
- min-height: 59px;
11
+ display: grid;
12
+ grid-template-columns: minmax(0, 1fr);
13
+ height: fit-content;
14
+ grid-template-rows: ${({ $isExpanded = true }) => $isExpanded ? "minmax(0, 1fr)" : "minmax(0, 0fr)"};
15
+ min-height: ${({ $isExpanded = true }) => $isExpanded ? "59px" : "0px"};
12
16
  overflow: hidden;
13
- transition: all 0.5s ease-in;
17
+ transition:
18
+ grid-template-rows ${BANNER_SLIDE_DURATION_MS}ms ease-in,
19
+ min-height ${BANNER_SLIDE_DURATION_MS}ms ease-in;
14
20
  @starting-style {
15
- max-height: 0px;
21
+ grid-template-rows: minmax(0, 0fr);
22
+ min-height: 0px;
23
+ }
24
+ & > * {
25
+ align-self: start;
26
+ min-height: 0;
27
+ overflow: hidden;
28
+ }
29
+ @media (prefers-reduced-motion: reduce) {
30
+ transition: none;
16
31
  }
17
32
  ${xStyledCommonProps}
18
33
  `;
@@ -62,11 +77,18 @@ const StyledIconContainer = styled("div", {
62
77
  margin-left: ${({ theme }) => theme.space.xs};
63
78
  min-width: 0px;
64
79
  `;
80
+ const isSmallLayout = ({ theme }) => ["s", "xs"].includes(theme.layoutMode);
65
81
  const StyledBody = styled("div", { name: DSBannerName, slot: DSBannerSlots.BODY })`
82
+ display: grid;
83
+ grid-template-columns: ${(props) => isSmallLayout(props) ? "minmax(0, 1fr)" : "minmax(0, max-content) auto"};
84
+ justify-content: start;
66
85
  padding-top: 9px;
67
- padding-bottom: 9px;
86
+ & > :nth-child(-n + 2) {
87
+ grid-column: 1;
88
+ }
68
89
  `;
69
90
  const StyledTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.TITLE })`
91
+ display: block;
70
92
  color: neutral-700;
71
93
  overflow-wrap: break-word;
72
94
  white-space: pre-wrap;
@@ -77,27 +99,38 @@ const StyledSubTitle = styled(DSTypography, { name: DSBannerName, slot: DSBanner
77
99
  overflow-wrap: break-word;
78
100
  white-space: pre-wrap;
79
101
  min-width: 0px;
80
- ${({ theme }) => {
81
- if (["s", "xs"].includes(theme.layoutMode)) {
82
- return `
83
- grid-column: 1 / -1;
84
- `;
85
- }
86
- return "";
87
- }}
102
+ padding-bottom: 9px;
88
103
  `;
89
- const StyledActionLink = styled("a", {
104
+ const StyledActionLink = styled(DSTypography, {
90
105
  name: DSBannerName,
91
106
  slot: DSBannerSlots.ACTION_LINK
92
107
  })`
93
- display: inline-block;
94
- text-decoration: none;
95
- line-height: inherit;
96
- font-size: inherit;
97
- font-weight: ${({ theme }) => theme.fontWeights.regular};
98
- color: brand-600;
99
108
  min-width: 0px;
100
109
  position: relative;
110
+ margin-bottom: 9px;
111
+ ${(props) => isSmallLayout(props) ? `
112
+ justify-self: start;
113
+ ` : `
114
+ grid-column: 2;
115
+ grid-row: ${props.isBodyEmpty ? 1 : 2};
116
+ align-self: end;
117
+ align-self: last baseline;
118
+ margin-left: 16px;
119
+ `}
120
+ /* Typography and underline of the action link (PUI-19233).
121
+ Size comes from the link-sml-title variant (set in DSBannerContent). The rest is the Link "inline text" styling:
122
+ idle underline + brand-600, hover no underline + brand-800 (decided: the link is underlined at rest).
123
+ PENDING UX CONFIRMATION: only font-weight (400 vs the variant's weight; the spec names a variant that does not
124
+ exist) and line-height (the description's, the variant's 24px would make the banner taller and misalign the
125
+ baselines). Adjusting them once UX answers should only touch those two declarations. */
126
+ font-weight: ${({ theme }) => theme.fontWeights.regular};
127
+ line-height: 1.278;
128
+ text-decoration: underline;
129
+ color: brand-600;
130
+ &:hover {
131
+ text-decoration: none;
132
+ color: brand-800;
133
+ }
101
134
  &:focus {
102
135
  outline: none;
103
136
  &:after {
@@ -118,7 +151,8 @@ const StyledCloseButton = styled(DSButtonV2, {
118
151
  name: DSBannerName,
119
152
  slot: DSBannerSlots.CLOSE_BUTTON
120
153
  })`
121
- margin: 5px;
154
+ margin-top: 4px;
155
+ margin-left: 8px;
122
156
  `;
123
157
  const StyledLiveRegionPortal = styled("div", {
124
158
  name: DSBannerName,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/styles.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { DSButtonV2 } from '@elliemae/ds-button-v2';\nimport { Grid } from '@elliemae/ds-grid';\nimport type { ColorProps, LayoutProps, SizingProps, SpaceProps } from '@elliemae/ds-system';\nimport { styled, xStyledCommonProps } from '@elliemae/ds-system';\nimport { DSTypography } from '@elliemae/ds-typography';\nimport { BANNER_TYPES, DSBannerName, DSBannerSlots } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\n\ninterface StyledBannerContainerT extends SizingProps, LayoutProps, SpaceProps, ColorProps {}\nexport const StyledBannerContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.CONTAINER,\n})<StyledBannerContainerT>`\n min-height: 59px;\n overflow: hidden;\n transition: all 0.5s ease-in;\n @starting-style {\n max-height: 0px;\n }\n ${xStyledCommonProps}\n`;\n\ninterface StyledInnerContainerT {}\nexport const StyledInnerContainer = styled(Grid, {\n name: DSBannerName,\n slot: DSBannerSlots.INNER_CONTAINER,\n})<StyledInnerContainerT>`\n padding-right: 4px;\n width: 100%;\n min-width: 0;\n`;\n\nconst handleBorderColor = (\n type: DSBannerT.BannerTypesT,\n { colors }: { colors: Record<string, Record<string, string>> },\n): string => {\n switch (type) {\n case BANNER_TYPES.SUCCESS:\n return colors.success[900];\n case BANNER_TYPES.INFO:\n return colors.brand[600];\n case BANNER_TYPES.WARNING:\n return colors.warning[900];\n case BANNER_TYPES.DANGER:\n return colors.danger[900];\n default:\n return 'should_not_happen';\n }\n};\ninterface StyledBannerLayoutT {\n $type: DSBannerT.BannerTypesT;\n}\nexport const StyledBannerLayout = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LAYOUT,\n})<StyledBannerLayoutT>`\n display: flex;\n width: 100%;\n align-items: flex-start;\n justify-content: space-between;\n background-color: neutral-000;\n border-bottom: 5px solid ${({ $type, theme }) => handleBorderColor($type, theme)};\n & > :first-child {\n flex: 1;\n min-width: 0;\n }\n`;\n\nexport const StyledIconContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.ICON_CONTAINER,\n})`\n padding-top: 8px;\n margin-right: ${({ theme }) => theme.space.xxs};\n margin-left: ${({ theme }) => theme.space.xs};\n min-width: 0px;\n`;\n\nexport const StyledBody = styled('div', { name: DSBannerName, slot: DSBannerSlots.BODY })`\n padding-top: 9px;\n padding-bottom: 9px;\n`;\n\nexport const StyledTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.TITLE })`\n color: neutral-700;\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n`;\n\nexport const StyledSubTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.SUBTITLE })`\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n ${({ theme }) => {\n if (['s', 'xs'].includes(theme.layoutMode!)) {\n return `\n grid-column: 1 / -1;\n `;\n }\n return '';\n }}\n`;\n\ninterface StyledActionLinkT {\n isBodyEmpty: boolean;\n}\nexport const StyledActionLink = styled('a', {\n name: DSBannerName,\n slot: DSBannerSlots.ACTION_LINK,\n})<StyledActionLinkT>`\n display: inline-block;\n text-decoration: none;\n line-height: inherit;\n font-size: inherit;\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n color: brand-600;\n min-width: 0px;\n position: relative;\n &:focus {\n outline: none;\n &:after {\n position: absolute;\n content: '';\n top: -2px;\n left: -2px;\n right: -2px;\n bottom: -2px;\n border-radius: 2px;\n border: 2px solid brand-700;\n box-shadow: 0 0 0 1px brand-700;\n pointer-events: none;\n }\n }\n`;\nexport const StyledCloseButton = styled(DSButtonV2, {\n name: DSBannerName,\n slot: DSBannerSlots.CLOSE_BUTTON,\n})`\n margin: 5px;\n`;\n\nexport const StyledLiveRegionPortal = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LIVE_REGION_PORTAL,\n})`\n clip: rect(0 0 0 0);\n position: absolute;\n`;\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AAErB,SAAS,QAAQ,0BAA0B;AAC3C,SAAS,oBAAoB;AAC7B,SAAS,cAAc,cAAc,qBAAqB;AAInD,MAAM,wBAAwB,OAAO,OAAO;AAAA,EACjD,MAAM;AAAA,EACN,MAAM,cAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOG,kBAAkB;AAAA;AAIf,MAAM,uBAAuB,OAAO,MAAM;AAAA,EAC/C,MAAM;AAAA,EACN,MAAM,cAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAMD,MAAM,oBAAoB,CACxB,MACA,EAAE,OAAO,MACE;AACX,UAAQ,MAAM;AAAA,IACZ,KAAK,aAAa;AAChB,aAAO,OAAO,QAAQ,GAAG;AAAA,IAC3B,KAAK,aAAa;AAChB,aAAO,OAAO,MAAM,GAAG;AAAA,IACzB,KAAK,aAAa;AAChB,aAAO,OAAO,QAAQ,GAAG;AAAA,IAC3B,KAAK,aAAa;AAChB,aAAO,OAAO,OAAO,GAAG;AAAA,IAC1B;AACE,aAAO;AAAA,EACX;AACF;AAIO,MAAM,qBAAqB,OAAO,OAAO;AAAA,EAC9C,MAAM;AAAA,EACN,MAAM,cAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAM4B,CAAC,EAAE,OAAO,MAAM,MAAM,kBAAkB,OAAO,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAO3E,MAAM,sBAAsB,OAAO,OAAO;AAAA,EAC/C,MAAM;AAAA,EACN,MAAM,cAAc;AACtB,CAAC;AAAA;AAAA,kBAEiB,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,GAAG;AAAA,iBAC/B,CAAC,EAAE,MAAM,MAAM,MAAM,MAAM,EAAE;AAAA;AAAA;AAIvC,MAAM,aAAa,OAAO,OAAO,EAAE,MAAM,cAAc,MAAM,cAAc,KAAK,CAAC;AAAA;AAAA;AAAA;AAKjF,MAAM,cAAc,OAAO,cAAc,EAAE,MAAM,cAAc,MAAM,cAAc,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAO1F,MAAM,iBAAiB,OAAO,cAAc,EAAE,MAAM,cAAc,MAAM,cAAc,SAAS,CAAC;AAAA,iBACtF,CAAC,EAAE,MAAM,MAAM,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA,IAIrD,CAAC,EAAE,MAAM,MAAM;AACf,MAAI,CAAC,KAAK,IAAI,EAAE,SAAS,MAAM,UAAW,GAAG;AAC3C,WAAO;AAAA;AAAA;AAAA,EAGT;AACA,SAAO;AACT,CAAC;AAAA;AAMI,MAAM,mBAAmB,OAAO,KAAK;AAAA,EAC1C,MAAM;AAAA,EACN,MAAM,cAAc;AACtB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,iBAKgB,CAAC,EAAE,MAAM,MAAM,MAAM,YAAY,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBlD,MAAM,oBAAoB,OAAO,YAAY;AAAA,EAClD,MAAM;AAAA,EACN,MAAM,cAAc;AACtB,CAAC;AAAA;AAAA;AAIM,MAAM,yBAAyB,OAAO,OAAO;AAAA,EAClD,MAAM;AAAA,EACN,MAAM,cAAc;AACtB,CAAC;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { DSButtonV2 } from '@elliemae/ds-button-v2';\nimport { Grid } from '@elliemae/ds-grid';\nimport type { ColorProps, LayoutProps, SizingProps, SpaceProps } from '@elliemae/ds-system';\nimport { styled, xStyledCommonProps } from '@elliemae/ds-system';\nimport { DSTypography } from '@elliemae/ds-typography';\nimport { BANNER_SLIDE_DURATION_MS, BANNER_TYPES, DSBannerName, DSBannerSlots } from './constants/index.js';\nimport type { DSBannerT } from './react-desc-prop-types.js';\n\ninterface StyledBannerContainerT extends SizingProps, LayoutProps, SpaceProps, ColorProps {\n $isExpanded?: boolean;\n}\n// The slide animates the height of an intrinsically sized (auto height) element, which css can not interpolate with\n// \"height\" or \"max-height\" (auto/none are not interpolable, and min-height would clamp the collapsed state anyway).\n// Instead the single child (the layout, the live region lives in a portal) is the item of a one track grid whose row goes\n// from 0fr to 1fr: the row is always sized from the content so it follows wrapping, small layouts and text resize.\n// The tracks are minmax(0, Xfr) and not plain Xfr because the item has a border (the type color line): a plain 0fr track\n// can not be smaller than the item's border box, so it would collapse to 5px instead of 0.\n// The open slide is css only (@starting-style, the container mounts expanded), the close slide needs the container to\n// still be mounted when $isExpanded turns false, which is handled by useBannerExitAnimation.\nexport const StyledBannerContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.CONTAINER,\n})<StyledBannerContainerT>`\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n height: fit-content;\n grid-template-rows: ${({ $isExpanded = true }) => ($isExpanded ? 'minmax(0, 1fr)' : 'minmax(0, 0fr)')};\n min-height: ${({ $isExpanded = true }) => ($isExpanded ? '59px' : '0px')};\n overflow: hidden;\n transition:\n grid-template-rows ${BANNER_SLIDE_DURATION_MS}ms ease-in,\n min-height ${BANNER_SLIDE_DURATION_MS}ms ease-in;\n @starting-style {\n grid-template-rows: minmax(0, 0fr);\n min-height: 0px;\n }\n & > * {\n align-self: start;\n min-height: 0;\n overflow: hidden;\n }\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n ${xStyledCommonProps}\n`;\n\ninterface StyledInnerContainerT {}\nexport const StyledInnerContainer = styled(Grid, {\n name: DSBannerName,\n slot: DSBannerSlots.INNER_CONTAINER,\n})<StyledInnerContainerT>`\n padding-right: 4px;\n width: 100%;\n min-width: 0;\n`;\n\nconst handleBorderColor = (\n type: DSBannerT.BannerTypesT,\n { colors }: { colors: Record<string, Record<string, string>> },\n): string => {\n switch (type) {\n case BANNER_TYPES.SUCCESS:\n return colors.success[900];\n case BANNER_TYPES.INFO:\n return colors.brand[600];\n case BANNER_TYPES.WARNING:\n return colors.warning[900];\n case BANNER_TYPES.DANGER:\n return colors.danger[900];\n default:\n return 'should_not_happen';\n }\n};\ninterface StyledBannerLayoutT {\n $type: DSBannerT.BannerTypesT;\n}\nexport const StyledBannerLayout = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LAYOUT,\n})<StyledBannerLayoutT>`\n display: flex;\n width: 100%;\n align-items: flex-start;\n justify-content: space-between;\n background-color: neutral-000;\n border-bottom: 5px solid ${({ $type, theme }) => handleBorderColor($type, theme)};\n & > :first-child {\n flex: 1;\n min-width: 0;\n }\n`;\n\nexport const StyledIconContainer = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.ICON_CONTAINER,\n})`\n padding-top: 8px;\n margin-right: ${({ theme }) => theme.space.xxs};\n margin-left: ${({ theme }) => theme.space.xs};\n min-width: 0px;\n`;\n\nconst isSmallLayout = ({ theme }: { theme: { layoutMode?: string } }) => ['s', 'xs'].includes(theme.layoutMode!);\n\n// title, description and action link are the 3 children (in this order). Default layouts: the title and the description\n// share the first column and the action link is its own cell right after the text (the first column grows with the\n// text up to the free space, the link keeps its own width). Small layouts: a single column, the link goes on its own\n// row below the description.\nexport const StyledBody = styled('div', { name: DSBannerName, slot: DSBannerSlots.BODY })`\n display: grid;\n grid-template-columns: ${(props) => (isSmallLayout(props) ? 'minmax(0, 1fr)' : 'minmax(0, max-content) auto')};\n justify-content: start;\n padding-top: 9px;\n & > :nth-child(-n + 2) {\n grid-column: 1;\n }\n`;\n\nexport const StyledTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.TITLE })`\n display: block;\n color: neutral-700;\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n`;\n\n// the description carries the bottom spacing of the content area (Spec v2)\nexport const StyledSubTitle = styled(DSTypography, { name: DSBannerName, slot: DSBannerSlots.SUBTITLE })`\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n overflow-wrap: break-word;\n white-space: pre-wrap;\n min-width: 0px;\n padding-bottom: 9px;\n`;\n\ninterface StyledActionLinkT {\n isBodyEmpty: boolean;\n}\n// its own cell of the StyledBody grid (never inline in the description), nested in DSTypography (link-sml-title variant).\nexport const StyledActionLink = styled(DSTypography, {\n name: DSBannerName,\n slot: DSBannerSlots.ACTION_LINK,\n})<StyledActionLinkT>`\n min-width: 0px;\n position: relative;\n margin-bottom: 9px;\n ${(props) =>\n isSmallLayout(props)\n ? `\n justify-self: start;\n `\n : `\n grid-column: 2;\n grid-row: ${props.isBodyEmpty ? 1 : 2};\n align-self: end;\n align-self: last baseline;\n margin-left: 16px;\n `}\n /* Typography and underline of the action link (PUI-19233).\n Size comes from the link-sml-title variant (set in DSBannerContent). The rest is the Link \"inline text\" styling:\n idle underline + brand-600, hover no underline + brand-800 (decided: the link is underlined at rest).\n PENDING UX CONFIRMATION: only font-weight (400 vs the variant's weight; the spec names a variant that does not\n exist) and line-height (the description's, the variant's 24px would make the banner taller and misalign the\n baselines). Adjusting them once UX answers should only touch those two declarations. */\n font-weight: ${({ theme }) => theme.fontWeights.regular};\n line-height: 1.278;\n text-decoration: underline;\n color: brand-600;\n &:hover {\n text-decoration: none;\n color: brand-800;\n }\n &:focus {\n outline: none;\n &:after {\n position: absolute;\n content: '';\n top: -2px;\n left: -2px;\n right: -2px;\n bottom: -2px;\n border-radius: 2px;\n border: 2px solid brand-700;\n box-shadow: 0 0 0 1px brand-700;\n pointer-events: none;\n }\n }\n`;\nexport const StyledCloseButton = styled(DSButtonV2, {\n name: DSBannerName,\n slot: DSBannerSlots.CLOSE_BUTTON,\n})`\n margin-top: 4px;\n margin-left: 8px;\n`;\n\nexport const StyledLiveRegionPortal = styled('div', {\n name: DSBannerName,\n slot: DSBannerSlots.LIVE_REGION_PORTAL,\n})`\n clip: rect(0 0 0 0);\n position: absolute;\n`;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,25 @@
1
+ import * as React from "react";
2
+ import { useCallback } from "react";
3
+ import { useBannerExitAnimation } from "./useBannerExitAnimation.js";
4
+ const useBannerContainer = (isOpen, actionRef) => {
5
+ const exitAnimation = useBannerExitAnimation(isOpen);
6
+ const handleActionRefForContainer = useCallback(
7
+ (containerNode) => {
8
+ if (containerNode && actionRef && actionRef.current) {
9
+ actionRef.current.focusOnWrapper = () => {
10
+ if (containerNode) {
11
+ setTimeout(() => {
12
+ containerNode?.focus();
13
+ }, 300);
14
+ }
15
+ };
16
+ }
17
+ },
18
+ [actionRef]
19
+ );
20
+ return { handleActionRefForContainer, ...exitAnimation };
21
+ };
22
+ export {
23
+ useBannerContainer
24
+ };
25
+ //# sourceMappingURL=useBannerContainer.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/useBannerContainer.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type React from 'react';\nimport { useCallback } from 'react';\nimport type { DSBannerT } from './react-desc-prop-types.js';\nimport { useBannerExitAnimation } from './useBannerExitAnimation.js';\n\n// everything the container needs from its lifecycle: the actionRef.focusOnWrapper hookup and the exit animation\nexport const useBannerContainer = (isOpen: boolean, actionRef: DSBannerT.InternalProps['actionRef']) => {\n const exitAnimation = useBannerExitAnimation(isOpen);\n\n const handleActionRefForContainer = useCallback<React.RefCallback<HTMLDivElement>>(\n (containerNode) => {\n if (containerNode && actionRef && actionRef.current) {\n actionRef.current.focusOnWrapper = () => {\n if (containerNode) {\n setTimeout(() => {\n containerNode?.focus();\n }, 300);\n }\n };\n }\n },\n [actionRef],\n );\n\n return { handleActionRefForContainer, ...exitAnimation };\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,mBAAmB;AAE5B,SAAS,8BAA8B;AAGhC,MAAM,qBAAqB,CAAC,QAAiB,cAAoD;AACtG,QAAM,gBAAgB,uBAAuB,MAAM;AAEnD,QAAM,8BAA8B;AAAA,IAClC,CAAC,kBAAkB;AACjB,UAAI,iBAAiB,aAAa,UAAU,SAAS;AACnD,kBAAU,QAAQ,iBAAiB,MAAM;AACvC,cAAI,eAAe;AACjB,uBAAW,MAAM;AACf,6BAAe,MAAM;AAAA,YACvB,GAAG,GAAG;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,SAAO,EAAE,6BAA6B,GAAG,cAAc;AACzD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,36 @@
1
+ import * as React from "react";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { BANNER_SLIDE_DURATION_MS } from "./constants/index.js";
4
+ const EXIT_FALLBACK_MS = BANNER_SLIDE_DURATION_MS + 100;
5
+ const SLIDE_PROPERTY = "grid-template-rows";
6
+ const prefersReducedMotion = () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
7
+ const useBannerExitAnimation = (isOpen) => {
8
+ const [wasOpen, setWasOpen] = useState(isOpen);
9
+ const [isExiting, setIsExiting] = useState(false);
10
+ if (wasOpen !== isOpen) {
11
+ setWasOpen(isOpen);
12
+ setIsExiting(wasOpen && !isOpen && !prefersReducedMotion());
13
+ }
14
+ useEffect(() => {
15
+ if (!isExiting) return void 0;
16
+ const timeoutId = setTimeout(() => setIsExiting(false), EXIT_FALLBACK_MS);
17
+ return () => clearTimeout(timeoutId);
18
+ }, [isExiting]);
19
+ const handleTransitionEnd = useCallback((e) => {
20
+ if (e.target === e.currentTarget && e.propertyName === SLIDE_PROPERTY) setIsExiting(false);
21
+ }, []);
22
+ const containerExitProps = useMemo(
23
+ () => isExiting ? { inert: "", "aria-hidden": true, onTransitionEnd: handleTransitionEnd } : {},
24
+ [isExiting, handleTransitionEnd]
25
+ );
26
+ return {
27
+ isContainerRendered: isOpen || isExiting,
28
+ containerExitProps,
29
+ // the live region does not wait for the slide: it remounts (empty) in the same commit that closes the banner
30
+ liveRegionKey: isOpen ? "open" : "closing"
31
+ };
32
+ };
33
+ export {
34
+ useBannerExitAnimation
35
+ };
36
+ //# sourceMappingURL=useBannerExitAnimation.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/useBannerExitAnimation.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type React from 'react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { BANNER_SLIDE_DURATION_MS } from './constants/index.js';\n\n// the css transition is the source of truth for the exit, the timer is the safety net for the cases in which\n// \"transitionend\" never fires (jsdom, display none ancestor, consumer overriding the transition, interrupted transitions)\nconst EXIT_FALLBACK_MS = BANNER_SLIDE_DURATION_MS + 100;\nconst SLIDE_PROPERTY = 'grid-template-rows';\n\nconst prefersReducedMotion = () =>\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\ntype ExitProps = React.HTMLAttributes<HTMLDivElement> & { inert?: string };\n\n/**\n * Keeps the banner container mounted while it slides up after `isOpen` turns false.\n * Opening needs no state: the container mounts expanded and the css `@starting-style` slides it down.\n * With `prefers-reduced-motion: reduce` there is no exit phase, the banner is removed right away like it always was.\n */\nexport const useBannerExitAnimation = (isOpen: boolean) => {\n const [wasOpen, setWasOpen] = useState(isOpen);\n const [isExiting, setIsExiting] = useState(false);\n\n // derived during render (not in an effect): the container must still be there in the very commit that closes it,\n // otherwise there is no frame in which the transition can run. Re-opening mid exit cancels the exit.\n if (wasOpen !== isOpen) {\n setWasOpen(isOpen);\n setIsExiting(wasOpen && !isOpen && !prefersReducedMotion());\n }\n\n // synchronizes with an external system (the timers of the browser) while exiting\n // the cleanup runs on re-open, on unmount and when the exit finishes, so the timer can not fire after any of them\n useEffect(() => {\n if (!isExiting) return undefined;\n const timeoutId = setTimeout(() => setIsExiting(false), EXIT_FALLBACK_MS);\n return () => clearTimeout(timeoutId);\n }, [isExiting]);\n\n const handleTransitionEnd = useCallback((e: React.TransitionEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget && e.propertyName === SLIDE_PROPERTY) setIsExiting(false);\n }, []);\n\n // while sliding up the banner is already closed for everyone: no focus, no pointer, out of the a11y tree\n const containerExitProps = useMemo<ExitProps>(\n () => (isExiting ? { inert: '', 'aria-hidden': true, onTransitionEnd: handleTransitionEnd } : {}),\n [isExiting, handleTransitionEnd],\n );\n\n return {\n isContainerRendered: isOpen || isExiting,\n containerExitProps,\n // the live region does not wait for the slide: it remounts (empty) in the same commit that closes the banner\n liveRegionKey: isOpen ? 'open' : 'closing',\n };\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,aAAa,WAAW,SAAS,gBAAgB;AAC1D,SAAS,gCAAgC;AAIzC,MAAM,mBAAmB,2BAA2B;AACpD,MAAM,iBAAiB;AAEvB,MAAM,uBAAuB,MAC3B,OAAO,WAAW,eAClB,OAAO,OAAO,eAAe,cAC7B,OAAO,WAAW,kCAAkC,EAAE;AASjD,MAAM,yBAAyB,CAAC,WAAoB;AACzD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,MAAM;AAC7C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAIhD,MAAI,YAAY,QAAQ;AACtB,eAAW,MAAM;AACjB,iBAAa,WAAW,CAAC,UAAU,CAAC,qBAAqB,CAAC;AAAA,EAC5D;AAIA,YAAU,MAAM;AACd,QAAI,CAAC,UAAW,QAAO;AACvB,UAAM,YAAY,WAAW,MAAM,aAAa,KAAK,GAAG,gBAAgB;AACxE,WAAO,MAAM,aAAa,SAAS;AAAA,EACrC,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,sBAAsB,YAAY,CAAC,MAA6C;AACpF,QAAI,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,eAAgB,cAAa,KAAK;AAAA,EAC3F,GAAG,CAAC,CAAC;AAGL,QAAM,qBAAqB;AAAA,IACzB,MAAO,YAAY,EAAE,OAAO,IAAI,eAAe,MAAM,iBAAiB,oBAAoB,IAAI,CAAC;AAAA,IAC/F,CAAC,WAAW,mBAAmB;AAAA,EACjC;AAEA,SAAO;AAAA,IACL,qBAAqB,UAAU;AAAA,IAC/B;AAAA;AAAA,IAEA,eAAe,SAAS,SAAS;AAAA,EACnC;AACF;",
6
+ "names": []
7
+ }
@@ -5,6 +5,7 @@ export declare const BANNER_TYPES: {
5
5
  readonly WARNING: "warning";
6
6
  readonly DANGER: "danger";
7
7
  };
8
+ export declare const BANNER_SLIDE_DURATION_MS = 500;
8
9
  /**
9
10
  * @deprecated legacy export, no longer rendered or used by the component (PUI-19089).
10
11
  * The body used to render with this fixed id, which duplicated across banners. The body id is now
@@ -1,6 +1,7 @@
1
1
  import type { ColorProps, LayoutProps, SizingProps, SpaceProps } from '@elliemae/ds-system';
2
2
  import type { DSBannerT } from './react-desc-prop-types.js';
3
3
  interface StyledBannerContainerT extends SizingProps, LayoutProps, SpaceProps, ColorProps {
4
+ $isExpanded?: boolean;
4
5
  }
5
6
  export declare const StyledBannerContainer: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, StyledBannerContainerT & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
6
7
  interface StyledInnerContainerT {
@@ -17,7 +18,7 @@ export declare const StyledSubTitle: import("styled-components").StyledComponent
17
18
  interface StyledActionLinkT {
18
19
  isBodyEmpty: boolean;
19
20
  }
20
- export declare const StyledActionLink: import("styled-components").StyledComponent<"a", import("@elliemae/ds-system").Theme, StyledActionLinkT & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"a">, never>;
21
+ export declare const StyledActionLink: import("styled-components").StyledComponent<import("react").FC<import("@elliemae/ds-typography").DSTypographyT.Props>, import("@elliemae/ds-system").Theme, StyledActionLinkT & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<import("react").FC<import("@elliemae/ds-typography").DSTypographyT.Props>>, never>;
21
22
  export declare const StyledCloseButton: import("styled-components").StyledComponent<import("react").ComponentType<import("@elliemae/ds-button-v2").DSButtonV2T.Props>, import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<import("react").ComponentType<import("@elliemae/ds-button-v2").DSButtonV2T.Props>>, never>;
22
23
  export declare const StyledLiveRegionPortal: import("styled-components").StyledComponent<"div", import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"div">, never>;
23
24
  export {};
@@ -0,0 +1,10 @@
1
+ import type React from 'react';
2
+ import type { DSBannerT } from './react-desc-prop-types.js';
3
+ export declare const useBannerContainer: (isOpen: boolean, actionRef: DSBannerT.InternalProps["actionRef"]) => {
4
+ isContainerRendered: boolean;
5
+ containerExitProps: React.HTMLAttributes<HTMLDivElement> & {
6
+ inert?: string;
7
+ };
8
+ liveRegionKey: string;
9
+ handleActionRefForContainer: (instance: HTMLDivElement | null) => void | React.DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof React.DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES];
10
+ };
@@ -0,0 +1,15 @@
1
+ import type React from 'react';
2
+ type ExitProps = React.HTMLAttributes<HTMLDivElement> & {
3
+ inert?: string;
4
+ };
5
+ /**
6
+ * Keeps the banner container mounted while it slides up after `isOpen` turns false.
7
+ * Opening needs no state: the container mounts expanded and the css `@starting-style` slides it down.
8
+ * With `prefers-reduced-motion: reduce` there is no exit phase, the banner is removed right away like it always was.
9
+ */
10
+ export declare const useBannerExitAnimation: (isOpen: boolean) => {
11
+ isContainerRendered: boolean;
12
+ containerExitProps: ExitProps;
13
+ liveRegionKey: string;
14
+ };
15
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliemae/ds-banner",
3
- "version": "3.80.0-next.36",
3
+ "version": "3.80.0-next.39",
4
4
  "license": "MIT",
5
5
  "description": "ICE MT - Dimsum - Banner",
6
6
  "files": [
@@ -36,18 +36,18 @@
36
36
  "indent": 4
37
37
  },
38
38
  "dependencies": {
39
- "@elliemae/ds-button-v2": "3.80.0-next.36",
40
- "@elliemae/ds-grid": "3.80.0-next.36",
41
- "@elliemae/ds-icons": "3.80.0-next.36",
42
- "@elliemae/ds-props-helpers": "3.80.0-next.36",
43
- "@elliemae/ds-system": "3.80.0-next.36",
44
- "@elliemae/ds-typescript-helpers": "3.80.0-next.36",
45
- "@elliemae/ds-typography": "3.80.0-next.36",
39
+ "@elliemae/ds-button-v2": "3.80.0-next.39",
40
+ "@elliemae/ds-grid": "3.80.0-next.39",
41
+ "@elliemae/ds-icons": "3.80.0-next.39",
42
+ "@elliemae/ds-props-helpers": "3.80.0-next.39",
43
+ "@elliemae/ds-system": "3.80.0-next.39",
44
+ "@elliemae/ds-typescript-helpers": "3.80.0-next.39",
45
+ "@elliemae/ds-typography": "3.80.0-next.39",
46
46
  "uid": "^2.0.2"
47
47
  },
48
48
  "devDependencies": {
49
- "@elliemae/ds-monorepo-devops": "3.80.0-next.36",
50
- "@elliemae/ds-test-utils": "3.80.0-next.36",
49
+ "@elliemae/ds-monorepo-devops": "3.80.0-next.39",
50
+ "@elliemae/ds-test-utils": "3.80.0-next.39",
51
51
  "jest": "^30.0.0",
52
52
  "styled-components": "~5.3.11"
53
53
  },