@flipdish/ui-library 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/components/organisms/SidePanel/components/side-panel-content.cjs +15 -0
  2. package/dist/components/organisms/SidePanel/components/side-panel-content.cjs.map +1 -0
  3. package/dist/components/organisms/SidePanel/components/side-panel-content.d.ts +11 -0
  4. package/dist/components/organisms/SidePanel/components/side-panel-content.d.ts.map +1 -0
  5. package/dist/components/organisms/SidePanel/components/side-panel-content.js +13 -0
  6. package/dist/components/organisms/SidePanel/components/side-panel-content.js.map +1 -0
  7. package/dist/components/organisms/SidePanel/components/side-panel-footer.cjs +15 -0
  8. package/dist/components/organisms/SidePanel/components/side-panel-footer.cjs.map +1 -0
  9. package/dist/components/organisms/SidePanel/components/side-panel-footer.d.ts +11 -0
  10. package/dist/components/organisms/SidePanel/components/side-panel-footer.d.ts.map +1 -0
  11. package/dist/components/organisms/SidePanel/components/side-panel-footer.js +13 -0
  12. package/dist/components/organisms/SidePanel/components/side-panel-footer.js.map +1 -0
  13. package/dist/components/organisms/SidePanel/components/side-panel-header.cjs +19 -0
  14. package/dist/components/organisms/SidePanel/components/side-panel-header.cjs.map +1 -0
  15. package/dist/components/organisms/SidePanel/components/side-panel-header.d.ts +15 -0
  16. package/dist/components/organisms/SidePanel/components/side-panel-header.d.ts.map +1 -0
  17. package/dist/components/organisms/SidePanel/components/side-panel-header.js +17 -0
  18. package/dist/components/organisms/SidePanel/components/side-panel-header.js.map +1 -0
  19. package/dist/components/organisms/SidePanel/components/side-panel-region.cjs +42 -0
  20. package/dist/components/organisms/SidePanel/components/side-panel-region.cjs.map +1 -0
  21. package/dist/components/organisms/SidePanel/components/side-panel-region.d.ts +15 -0
  22. package/dist/components/organisms/SidePanel/components/side-panel-region.d.ts.map +1 -0
  23. package/dist/components/organisms/SidePanel/components/side-panel-region.js +39 -0
  24. package/dist/components/organisms/SidePanel/components/side-panel-region.js.map +1 -0
  25. package/dist/components/organisms/SidePanel/hooks/useOpenOnMount.cjs +29 -0
  26. package/dist/components/organisms/SidePanel/hooks/useOpenOnMount.cjs.map +1 -0
  27. package/dist/components/organisms/SidePanel/hooks/useOpenOnMount.d.ts +13 -0
  28. package/dist/components/organisms/SidePanel/hooks/useOpenOnMount.d.ts.map +1 -0
  29. package/dist/components/organisms/SidePanel/hooks/useOpenOnMount.js +27 -0
  30. package/dist/components/organisms/SidePanel/hooks/useOpenOnMount.js.map +1 -0
  31. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.cjs +76 -0
  32. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.cjs.map +1 -0
  33. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.d.ts +22 -0
  34. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.d.ts.map +1 -0
  35. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.js +74 -0
  36. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.js.map +1 -0
  37. package/dist/components/organisms/SidePanel/index.cjs +51 -0
  38. package/dist/components/organisms/SidePanel/index.cjs.map +1 -0
  39. package/dist/components/organisms/SidePanel/index.d.ts +48 -0
  40. package/dist/components/organisms/SidePanel/index.d.ts.map +1 -0
  41. package/dist/components/organisms/SidePanel/index.js +49 -0
  42. package/dist/components/organisms/SidePanel/index.js.map +1 -0
  43. package/dist/components/organisms/SidePanel/providers/page-cover-context.cjs +12 -0
  44. package/dist/components/organisms/SidePanel/providers/page-cover-context.cjs.map +1 -0
  45. package/dist/components/organisms/SidePanel/providers/page-cover-context.d.ts +6 -0
  46. package/dist/components/organisms/SidePanel/providers/page-cover-context.d.ts.map +1 -0
  47. package/dist/components/organisms/SidePanel/providers/page-cover-context.js +10 -0
  48. package/dist/components/organisms/SidePanel/providers/page-cover-context.js.map +1 -0
  49. package/dist/components/organisms/SidePanel/providers/side-panel-context.cjs +9 -0
  50. package/dist/components/organisms/SidePanel/providers/side-panel-context.cjs.map +1 -0
  51. package/dist/components/organisms/SidePanel/providers/side-panel-context.d.ts +8 -0
  52. package/dist/components/organisms/SidePanel/providers/side-panel-context.d.ts.map +1 -0
  53. package/dist/components/organisms/SidePanel/providers/side-panel-context.js +7 -0
  54. package/dist/components/organisms/SidePanel/providers/side-panel-context.js.map +1 -0
  55. package/dist/components/organisms/SidebarNavigation/components/mobile-header.cjs +1 -1
  56. package/dist/components/organisms/SidebarNavigation/components/mobile-header.cjs.map +1 -1
  57. package/dist/components/organisms/SidebarNavigation/components/mobile-header.js +1 -1
  58. package/dist/components/organisms/SidebarNavigation/components/mobile-header.js.map +1 -1
  59. package/dist/components/organisms/SlideoutMenu/index.cjs +9 -3
  60. package/dist/components/organisms/SlideoutMenu/index.cjs.map +1 -1
  61. package/dist/components/organisms/SlideoutMenu/index.d.ts +1 -1
  62. package/dist/components/organisms/SlideoutMenu/index.d.ts.map +1 -1
  63. package/dist/components/organisms/SlideoutMenu/index.js +10 -4
  64. package/dist/components/organisms/SlideoutMenu/index.js.map +1 -1
  65. package/dist/components/templates/AppShell/hooks/usePageCover.cjs +24 -0
  66. package/dist/components/templates/AppShell/hooks/usePageCover.cjs.map +1 -0
  67. package/dist/components/templates/AppShell/hooks/usePageCover.d.ts +14 -0
  68. package/dist/components/templates/AppShell/hooks/usePageCover.d.ts.map +1 -0
  69. package/dist/components/templates/AppShell/hooks/usePageCover.js +22 -0
  70. package/dist/components/templates/AppShell/hooks/usePageCover.js.map +1 -0
  71. package/dist/components/templates/AppShell/index.cjs +13 -7
  72. package/dist/components/templates/AppShell/index.cjs.map +1 -1
  73. package/dist/components/templates/AppShell/index.d.ts +8 -7
  74. package/dist/components/templates/AppShell/index.d.ts.map +1 -1
  75. package/dist/components/templates/AppShell/index.js +13 -7
  76. package/dist/components/templates/AppShell/index.js.map +1 -1
  77. package/dist/hooks/useSidePanel/index.cjs +61 -0
  78. package/dist/hooks/useSidePanel/index.cjs.map +1 -0
  79. package/dist/hooks/useSidePanel/index.d.ts +31 -0
  80. package/dist/hooks/useSidePanel/index.d.ts.map +1 -0
  81. package/dist/hooks/useSidePanel/index.js +59 -0
  82. package/dist/hooks/useSidePanel/index.js.map +1 -0
  83. package/dist/native/components/organisms/SidePanel/index.d.ts +12 -0
  84. package/dist/native/hooks/useSidePanel/index.d.ts +12 -0
  85. package/dist/utilities/__internal__/focusUtils/focus.utils.cjs +12 -0
  86. package/dist/utilities/__internal__/focusUtils/focus.utils.cjs.map +1 -0
  87. package/dist/utilities/__internal__/focusUtils/focus.utils.d.ts +3 -0
  88. package/dist/utilities/__internal__/focusUtils/focus.utils.d.ts.map +1 -0
  89. package/dist/utilities/__internal__/focusUtils/focus.utils.js +10 -0
  90. package/dist/utilities/__internal__/focusUtils/focus.utils.js.map +1 -0
  91. package/dist/utilities/__internal__/webStorageUtils/webStorage.utils.cjs +3 -0
  92. package/dist/utilities/__internal__/webStorageUtils/webStorage.utils.cjs.map +1 -1
  93. package/dist/utilities/__internal__/webStorageUtils/webStorage.utils.d.ts +2 -0
  94. package/dist/utilities/__internal__/webStorageUtils/webStorage.utils.d.ts.map +1 -1
  95. package/dist/utilities/__internal__/webStorageUtils/webStorage.utils.js +3 -1
  96. package/dist/utilities/__internal__/webStorageUtils/webStorage.utils.js.map +1 -1
  97. package/dist/utilities/localStorageUtils/index.cjs +7 -0
  98. package/dist/utilities/localStorageUtils/index.cjs.map +1 -1
  99. package/dist/utilities/localStorageUtils/index.d.ts +2 -0
  100. package/dist/utilities/localStorageUtils/index.d.ts.map +1 -1
  101. package/dist/utilities/localStorageUtils/index.js +8 -2
  102. package/dist/utilities/localStorageUtils/index.js.map +1 -1
  103. package/dist/utilities/localStorageUtils/localStorageUtils.constants.cjs +2 -0
  104. package/dist/utilities/localStorageUtils/localStorageUtils.constants.cjs.map +1 -1
  105. package/dist/utilities/localStorageUtils/localStorageUtils.constants.d.ts +2 -0
  106. package/dist/utilities/localStorageUtils/localStorageUtils.constants.d.ts.map +1 -1
  107. package/dist/utilities/localStorageUtils/localStorageUtils.constants.js +2 -0
  108. package/dist/utilities/localStorageUtils/localStorageUtils.constants.js.map +1 -1
  109. package/package.json +1 -1
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var cx = require('@flipdish/ui-library/utilities/cx');
5
+ var testIdUtils = require('@flipdish/ui-library/utilities/testIdUtils');
6
+
7
+ /** The scrolling body. It takes the height the header and footer leave. */
8
+ const SidePanelContent = ({ className, 'data-testid': dataTestId, ...props }) => {
9
+ const prefix = testIdUtils.useTestIdPrefix();
10
+ return (jsxRuntime.jsx("div", { ...props, "data-testid": dataTestId ?? (prefix ? testIdUtils.joinTestId(prefix, 'content') : undefined), className: cx.cx('flex min-h-0 w-full flex-1 flex-col gap-6 overflow-y-auto px-4 lg:px-6', className) }));
11
+ };
12
+ SidePanelContent.displayName = 'SidePanelContent';
13
+
14
+ exports.SidePanelContent = SidePanelContent;
15
+ //# sourceMappingURL=side-panel-content.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-content.cjs","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-content.tsx"],"sourcesContent":[null],"names":["useTestIdPrefix","_jsx","joinTestId","cx"],"mappings":";;;;;;AAWA;AACO,MAAM,gBAAgB,GAAG,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAyB,KAAI;AAC5G,IAAA,MAAM,MAAM,GAAGA,2BAAe,EAAE;AAEhC,IAAA,QACEC,cAAA,CAAA,KAAA,EAAA,EAAA,GACM,KAAK,EAAA,aAAA,EACI,UAAU,KAAK,MAAM,GAAGC,sBAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC,EAC/E,SAAS,EAAEC,KAAE,CAAC,wEAAwE,EAAE,SAAS,CAAC,EAAA,CAClG;AAEN;AACA,gBAAgB,CAAC,WAAW,GAAG,kBAAkB;;;;"}
@@ -0,0 +1,11 @@
1
+ import type { ComponentPropsWithRef } from 'react';
2
+ export type SidePanelContentProps = ComponentPropsWithRef<'div'> & {
3
+ /** Overrides the content's `data-testid` (defaults to `<root>--content`). */
4
+ 'data-testid'?: string;
5
+ };
6
+ /** The scrolling body. It takes the height the header and footer leave. */
7
+ export declare const SidePanelContent: {
8
+ ({ className, "data-testid": dataTestId, ...props }: SidePanelContentProps): import("react").JSX.Element;
9
+ displayName: string;
10
+ };
11
+ //# sourceMappingURL=side-panel-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-content.d.ts","sourceRoot":"","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-content.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAEnD,MAAM,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,KAAK,CAAC,GAAG;IACjE,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB;yDAAwD,qBAAqB;;CAUzG,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { cx } from '@flipdish/ui-library/utilities/cx';
3
+ import { useTestIdPrefix, joinTestId } from '@flipdish/ui-library/utilities/testIdUtils';
4
+
5
+ /** The scrolling body. It takes the height the header and footer leave. */
6
+ const SidePanelContent = ({ className, 'data-testid': dataTestId, ...props }) => {
7
+ const prefix = useTestIdPrefix();
8
+ return (jsx("div", { ...props, "data-testid": dataTestId ?? (prefix ? joinTestId(prefix, 'content') : undefined), className: cx('flex min-h-0 w-full flex-1 flex-col gap-6 overflow-y-auto px-4 lg:px-6', className) }));
9
+ };
10
+ SidePanelContent.displayName = 'SidePanelContent';
11
+
12
+ export { SidePanelContent };
13
+ //# sourceMappingURL=side-panel-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-content.js","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-content.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;AAWA;AACO,MAAM,gBAAgB,GAAG,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAyB,KAAI;AAC5G,IAAA,MAAM,MAAM,GAAG,eAAe,EAAE;AAEhC,IAAA,QACEA,GAAA,CAAA,KAAA,EAAA,EAAA,GACM,KAAK,EAAA,aAAA,EACI,UAAU,KAAK,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC,EAC/E,SAAS,EAAE,EAAE,CAAC,wEAAwE,EAAE,SAAS,CAAC,EAAA,CAClG;AAEN;AACA,gBAAgB,CAAC,WAAW,GAAG,kBAAkB;;;;"}
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var cx = require('@flipdish/ui-library/utilities/cx');
5
+ var testIdUtils = require('@flipdish/ui-library/utilities/testIdUtils');
6
+
7
+ /** Pinned actions under the content, such as a message input. */
8
+ const SidePanelFooter = ({ className, 'data-testid': dataTestId, ...props }) => {
9
+ const prefix = testIdUtils.useTestIdPrefix();
10
+ return (jsxRuntime.jsx("footer", { ...props, "data-testid": dataTestId ?? (prefix ? testIdUtils.joinTestId(prefix, 'footer') : undefined), className: cx.cx('w-full px-4 pb-4 lg:px-6 lg:pb-5', className) }));
11
+ };
12
+ SidePanelFooter.displayName = 'SidePanelFooter';
13
+
14
+ exports.SidePanelFooter = SidePanelFooter;
15
+ //# sourceMappingURL=side-panel-footer.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-footer.cjs","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-footer.tsx"],"sourcesContent":[null],"names":["useTestIdPrefix","_jsx","joinTestId","cx"],"mappings":";;;;;;AAWA;AACO,MAAM,eAAe,GAAG,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAwB,KAAI;AAC1G,IAAA,MAAM,MAAM,GAAGA,2BAAe,EAAE;AAEhC,IAAA,QACEC,cAAA,CAAA,QAAA,EAAA,EAAA,GACM,KAAK,EAAA,aAAA,EACI,UAAU,KAAK,MAAM,GAAGC,sBAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC,EAC9E,SAAS,EAAEC,KAAE,CAAC,kCAAkC,EAAE,SAAS,CAAC,EAAA,CAC5D;AAEN;AACA,eAAe,CAAC,WAAW,GAAG,iBAAiB;;;;"}
@@ -0,0 +1,11 @@
1
+ import type { ComponentPropsWithRef } from 'react';
2
+ export type SidePanelFooterProps = ComponentPropsWithRef<'footer'> & {
3
+ /** Overrides the footer's `data-testid` (defaults to `<root>--footer`). */
4
+ 'data-testid'?: string;
5
+ };
6
+ /** Pinned actions under the content, such as a message input. */
7
+ export declare const SidePanelFooter: {
8
+ ({ className, "data-testid": dataTestId, ...props }: SidePanelFooterProps): import("react").JSX.Element;
9
+ displayName: string;
10
+ };
11
+ //# sourceMappingURL=side-panel-footer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-footer.d.ts","sourceRoot":"","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-footer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAEnD,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,CAAC,QAAQ,CAAC,GAAG;IACnE,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,eAAe;yDAAwD,oBAAoB;;CAUvG,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { cx } from '@flipdish/ui-library/utilities/cx';
3
+ import { useTestIdPrefix, joinTestId } from '@flipdish/ui-library/utilities/testIdUtils';
4
+
5
+ /** Pinned actions under the content, such as a message input. */
6
+ const SidePanelFooter = ({ className, 'data-testid': dataTestId, ...props }) => {
7
+ const prefix = useTestIdPrefix();
8
+ return (jsx("footer", { ...props, "data-testid": dataTestId ?? (prefix ? joinTestId(prefix, 'footer') : undefined), className: cx('w-full px-4 pb-4 lg:px-6 lg:pb-5', className) }));
9
+ };
10
+ SidePanelFooter.displayName = 'SidePanelFooter';
11
+
12
+ export { SidePanelFooter };
13
+ //# sourceMappingURL=side-panel-footer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-footer.js","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-footer.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;AAWA;AACO,MAAM,eAAe,GAAG,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAwB,KAAI;AAC1G,IAAA,MAAM,MAAM,GAAG,eAAe,EAAE;AAEhC,IAAA,QACEA,GAAA,CAAA,QAAA,EAAA,EAAA,GACM,KAAK,EAAA,aAAA,EACI,UAAU,KAAK,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC,EAC9E,SAAS,EAAE,EAAE,CAAC,kCAAkC,EAAE,SAAS,CAAC,EAAA,CAC5D;AAEN;AACA,eAAe,CAAC,WAAW,GAAG,iBAAiB;;;;"}
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var CloseButton = require('@flipdish/ui-library/components/atoms/CloseButton');
5
+ var cx = require('@flipdish/ui-library/utilities/cx');
6
+ var testIdUtils = require('@flipdish/ui-library/utilities/testIdUtils');
7
+ var React = require('react');
8
+ var sidePanelContext = require('../providers/side-panel-context.cjs');
9
+
10
+ /** Title area with a close button, which closes the panel unless `onClose` is passed. */
11
+ const SidePanelHeader = ({ className, children, onClose, closeLabel, 'data-testid': dataTestId, ...props }) => {
12
+ const panel = React.useContext(sidePanelContext.SidePanelContext);
13
+ const prefix = testIdUtils.useTestIdPrefix();
14
+ return (jsxRuntime.jsxs("header", { ...props, "data-testid": dataTestId ?? (prefix ? testIdUtils.joinTestId(prefix, 'header') : undefined), className: cx.cx('relative w-full px-4 pt-6 pb-8 lg:px-6', className), children: [children, jsxRuntime.jsx(CloseButton.CloseButton, { size: "md", label: closeLabel ?? (panel ? `Close ${panel.label}` : undefined), className: "absolute top-3 right-3 shrink-0", onClick: onClose ?? panel?.close, "data-testid": prefix ? testIdUtils.joinTestId(prefix, 'close') : undefined })] }));
15
+ };
16
+ SidePanelHeader.displayName = 'SidePanelHeader';
17
+
18
+ exports.SidePanelHeader = SidePanelHeader;
19
+ //# sourceMappingURL=side-panel-header.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-header.cjs","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-header.tsx"],"sourcesContent":[null],"names":["useContext","SidePanelContext","useTestIdPrefix","_jsxs","joinTestId","cx","_jsx","CloseButton"],"mappings":";;;;;;;;;AAkBA;MACa,eAAe,GAAG,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAwB,KAAI;AACzI,IAAA,MAAM,KAAK,GAAGA,gBAAU,CAACC,iCAAgB,CAAC;AAC1C,IAAA,MAAM,MAAM,GAAGC,2BAAe,EAAE;AAEhC,IAAA,QACEC,eAAA,CAAA,QAAA,EAAA,EAAA,GACM,KAAK,iBACI,UAAU,KAAK,MAAM,GAAGC,sBAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC,EAC9E,SAAS,EAAEC,KAAE,CAAC,wCAAwC,EAAE,SAAS,CAAC,EAAA,QAAA,EAAA,CAEjE,QAAQ,EACTC,cAAA,CAACC,uBAAW,IACV,IAAI,EAAC,IAAI,EACT,KAAK,EAAE,UAAU,KAAK,KAAK,GAAG,SAAS,KAAK,CAAC,KAAK,CAAA,CAAE,GAAG,SAAS,CAAC,EACjE,SAAS,EAAC,iCAAiC,EAC3C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,KAAK,EAAA,aAAA,EACnB,MAAM,GAAGH,sBAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAA,CAC7D,CAAA,EAAA,CACK;AAEb;AACA,eAAe,CAAC,WAAW,GAAG,iBAAiB;;;;"}
@@ -0,0 +1,15 @@
1
+ import type { ComponentPropsWithRef } from 'react';
2
+ export interface SidePanelHeaderProps extends ComponentPropsWithRef<'header'> {
3
+ /** Runs instead of closing the panel when the close button is pressed. */
4
+ onClose?: () => void;
5
+ /** Accessible name of the close button. Defaults to "Close" followed by the panel's `aria-label`. */
6
+ closeLabel?: string;
7
+ /** Overrides the header's `data-testid` (defaults to `<root>--header`). */
8
+ 'data-testid'?: string;
9
+ }
10
+ /** Title area with a close button, which closes the panel unless `onClose` is passed. */
11
+ export declare const SidePanelHeader: {
12
+ ({ className, children, onClose, closeLabel, "data-testid": dataTestId, ...props }: SidePanelHeaderProps): import("react").JSX.Element;
13
+ displayName: string;
14
+ };
15
+ //# sourceMappingURL=side-panel-header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-header.d.ts","sourceRoot":"","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-header.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB,CAAC,QAAQ,CAAC;IAC3E,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qGAAqG;IACrG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,yFAAyF;AACzF,eAAO,MAAM,eAAe;wFAAuF,oBAAoB;;CAoBtI,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { CloseButton } from '@flipdish/ui-library/components/atoms/CloseButton';
3
+ import { cx } from '@flipdish/ui-library/utilities/cx';
4
+ import { useTestIdPrefix, joinTestId } from '@flipdish/ui-library/utilities/testIdUtils';
5
+ import { useContext } from 'react';
6
+ import { SidePanelContext } from '../providers/side-panel-context.js';
7
+
8
+ /** Title area with a close button, which closes the panel unless `onClose` is passed. */
9
+ const SidePanelHeader = ({ className, children, onClose, closeLabel, 'data-testid': dataTestId, ...props }) => {
10
+ const panel = useContext(SidePanelContext);
11
+ const prefix = useTestIdPrefix();
12
+ return (jsxs("header", { ...props, "data-testid": dataTestId ?? (prefix ? joinTestId(prefix, 'header') : undefined), className: cx('relative w-full px-4 pt-6 pb-8 lg:px-6', className), children: [children, jsx(CloseButton, { size: "md", label: closeLabel ?? (panel ? `Close ${panel.label}` : undefined), className: "absolute top-3 right-3 shrink-0", onClick: onClose ?? panel?.close, "data-testid": prefix ? joinTestId(prefix, 'close') : undefined })] }));
13
+ };
14
+ SidePanelHeader.displayName = 'SidePanelHeader';
15
+
16
+ export { SidePanelHeader };
17
+ //# sourceMappingURL=side-panel-header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-header.js","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-header.tsx"],"sourcesContent":[null],"names":["_jsxs","_jsx"],"mappings":";;;;;;;AAkBA;MACa,eAAe,GAAG,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAwB,KAAI;AACzI,IAAA,MAAM,KAAK,GAAG,UAAU,CAAC,gBAAgB,CAAC;AAC1C,IAAA,MAAM,MAAM,GAAG,eAAe,EAAE;AAEhC,IAAA,QACEA,IAAA,CAAA,QAAA,EAAA,EAAA,GACM,KAAK,iBACI,UAAU,KAAK,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC,EAC9E,SAAS,EAAE,EAAE,CAAC,wCAAwC,EAAE,SAAS,CAAC,EAAA,QAAA,EAAA,CAEjE,QAAQ,EACTC,GAAA,CAAC,WAAW,IACV,IAAI,EAAC,IAAI,EACT,KAAK,EAAE,UAAU,KAAK,KAAK,GAAG,SAAS,KAAK,CAAC,KAAK,CAAA,CAAE,GAAG,SAAS,CAAC,EACjE,SAAS,EAAC,iCAAiC,EAC3C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,KAAK,EAAA,aAAA,EACnB,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAA,CAC7D,CAAA,EAAA,CACK;AAEb;AACA,eAAe,CAAC,WAAW,GAAG,iBAAiB;;;;"}
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var cx = require('@flipdish/ui-library/utilities/cx');
5
+ var react = require('motion/react');
6
+ var React = require('react');
7
+ var usePanelFocus = require('../hooks/usePanelFocus.cjs');
8
+
9
+ /** Width of the panel from `lg` in pixels. Matches `w-100`. Below `lg` the panel is as wide as the page. */
10
+ const SIDE_PANEL_WIDTH = 400;
11
+ const SPRING = { type: 'spring', damping: 26, stiffness: 220, bounce: 0 };
12
+ const DOCKED = {
13
+ closed: { width: 0, x: 0 },
14
+ open: { width: SIDE_PANEL_WIDTH, x: 0 },
15
+ };
16
+ const FULL_PAGE = {
17
+ closed: { width: '100%', x: '100%' },
18
+ open: { width: '100%', x: 0 },
19
+ };
20
+ /** The rendered region. A component of its own so it can tell, while animating out, that it is leaving. */
21
+ const SidePanelRegion = ({ 'aria-label': ariaLabel, children, className, testId, isDesktop, shouldFocusOnMount }) => {
22
+ const panelRef = React.useRef(null);
23
+ const isPresent = react.useIsPresent();
24
+ const shouldReduceMotion = react.useReducedMotion();
25
+ const { onFocusCapture } = usePanelFocus.usePanelFocus({ panelRef, isPresent, isDesktop, shouldFocusOnMount });
26
+ // Crossing the breakpoint while open swaps the layout at once; only opening and closing animate.
27
+ const previousIsDesktop = React.useRef(isDesktop);
28
+ const hasCrossedBreakpoint = previousIsDesktop.current !== isDesktop;
29
+ React.useEffect(() => {
30
+ previousIsDesktop.current = isDesktop;
31
+ }, [isDesktop]);
32
+ const motionStates = isDesktop ? DOCKED : FULL_PAGE;
33
+ return (jsxRuntime.jsx(react.motion.aside, { ref: panelRef, "aria-label": ariaLabel, "data-testid": testId,
34
+ // Focusable by script only, so opening can land on the region without adding a tab stop.
35
+ tabIndex: -1, onFocusCapture: onFocusCapture, initial: motionStates.closed, animate: motionStates.open, exit: motionStates.closed, transition: shouldReduceMotion || hasCrossedBreakpoint ? { duration: 0 } : SPRING,
36
+ // overflow-hidden clips the fixed-width content while the panel's own width animates.
37
+ className: cx.cx('flex h-full min-h-0 shrink-0 overflow-hidden bg-secondary outline-focus-ring focus-visible:outline-2 focus-visible:-outline-offset-2', !isDesktop && 'absolute inset-y-0 right-0 z-10', className), children: jsxRuntime.jsx("div", { className: cx.cx('flex h-full shrink-0 flex-col', isDesktop ? 'w-100 border-l border-secondary' : 'w-full'), children: children }) }));
38
+ };
39
+
40
+ exports.SIDE_PANEL_WIDTH = SIDE_PANEL_WIDTH;
41
+ exports.SidePanelRegion = SidePanelRegion;
42
+ //# sourceMappingURL=side-panel-region.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-region.cjs","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-region.tsx"],"sourcesContent":[null],"names":["useRef","useIsPresent","useReducedMotion","usePanelFocus","useEffect","_jsx","motion","cx"],"mappings":";;;;;;;;AAQA;AACO,MAAM,gBAAgB,GAAG;AAEhC,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAW;AAElF,MAAM,MAAM,GAAG;IACb,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IAC1B,IAAI,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE;CAC/B;AAEV,MAAM,SAAS,GAAG;IAChB,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE;IACpC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE;CACrB;AAWV;MACa,eAAe,GAAG,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAwB,KAAI;AAC/I,IAAA,MAAM,QAAQ,GAAGA,YAAM,CAAc,IAAI,CAAC;AAC1C,IAAA,MAAM,SAAS,GAAGC,kBAAY,EAAE;AAChC,IAAA,MAAM,kBAAkB,GAAGC,sBAAgB,EAAE;AAC7C,IAAA,MAAM,EAAE,cAAc,EAAE,GAAGC,2BAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;;AAGhG,IAAA,MAAM,iBAAiB,GAAGH,YAAM,CAAC,SAAS,CAAC;AAC3C,IAAA,MAAM,oBAAoB,GAAG,iBAAiB,CAAC,OAAO,KAAK,SAAS;IACpEI,eAAS,CAAC,MAAK;AACb,QAAA,iBAAiB,CAAC,OAAO,GAAG,SAAS;AACvC,IAAA,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IAEf,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS;AAEnD,IAAA,QACEC,cAAA,CAACC,YAAM,CAAC,KAAK,EAAA,EACX,GAAG,EAAE,QAAQ,EAAA,YAAA,EACD,SAAS,EAAA,aAAA,EACR,MAAM;;AAEnB,QAAA,QAAQ,EAAE,EAAE,EACZ,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,YAAY,CAAC,MAAM,EAC5B,OAAO,EAAE,YAAY,CAAC,IAAI,EAC1B,IAAI,EAAE,YAAY,CAAC,MAAM,EACzB,UAAU,EAAE,kBAAkB,IAAI,oBAAoB,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,MAAM;;AAEjF,QAAA,SAAS,EAAEC,KAAE,CACX,sIAAsI,EACtI,CAAC,SAAS,IAAI,iCAAiC,EAC/C,SAAS,CACV,EAAA,QAAA,EAGDF,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAEE,KAAE,CAAC,+BAA+B,EAAE,SAAS,GAAG,iCAAiC,GAAG,QAAQ,CAAC,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAO,EAAA,CAClH;AAEnB;;;;;"}
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+ /** Width of the panel from `lg` in pixels. Matches `w-100`. Below `lg` the panel is as wide as the page. */
3
+ export declare const SIDE_PANEL_WIDTH = 400;
4
+ interface SidePanelRegionProps {
5
+ 'aria-label': string;
6
+ children: ReactNode;
7
+ className?: string;
8
+ testId: string;
9
+ isDesktop: boolean;
10
+ shouldFocusOnMount: boolean;
11
+ }
12
+ /** The rendered region. A component of its own so it can tell, while animating out, that it is leaving. */
13
+ export declare const SidePanelRegion: ({ "aria-label": ariaLabel, children, className, testId, isDesktop, shouldFocusOnMount }: SidePanelRegionProps) => import("react").JSX.Element;
14
+ export {};
15
+ //# sourceMappingURL=side-panel-region.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-region.d.ts","sourceRoot":"","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-region.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,4GAA4G;AAC5G,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAcpC,UAAU,oBAAoB;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,2GAA2G;AAC3G,eAAO,MAAM,eAAe,GAAI,yFAAyF,oBAAoB,gCAsC5I,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { cx } from '@flipdish/ui-library/utilities/cx';
3
+ import { useIsPresent, useReducedMotion, motion } from 'motion/react';
4
+ import { useRef, useEffect } from 'react';
5
+ import { usePanelFocus } from '../hooks/usePanelFocus.js';
6
+
7
+ /** Width of the panel from `lg` in pixels. Matches `w-100`. Below `lg` the panel is as wide as the page. */
8
+ const SIDE_PANEL_WIDTH = 400;
9
+ const SPRING = { type: 'spring', damping: 26, stiffness: 220, bounce: 0 };
10
+ const DOCKED = {
11
+ closed: { width: 0, x: 0 },
12
+ open: { width: SIDE_PANEL_WIDTH, x: 0 },
13
+ };
14
+ const FULL_PAGE = {
15
+ closed: { width: '100%', x: '100%' },
16
+ open: { width: '100%', x: 0 },
17
+ };
18
+ /** The rendered region. A component of its own so it can tell, while animating out, that it is leaving. */
19
+ const SidePanelRegion = ({ 'aria-label': ariaLabel, children, className, testId, isDesktop, shouldFocusOnMount }) => {
20
+ const panelRef = useRef(null);
21
+ const isPresent = useIsPresent();
22
+ const shouldReduceMotion = useReducedMotion();
23
+ const { onFocusCapture } = usePanelFocus({ panelRef, isPresent, isDesktop, shouldFocusOnMount });
24
+ // Crossing the breakpoint while open swaps the layout at once; only opening and closing animate.
25
+ const previousIsDesktop = useRef(isDesktop);
26
+ const hasCrossedBreakpoint = previousIsDesktop.current !== isDesktop;
27
+ useEffect(() => {
28
+ previousIsDesktop.current = isDesktop;
29
+ }, [isDesktop]);
30
+ const motionStates = isDesktop ? DOCKED : FULL_PAGE;
31
+ return (jsx(motion.aside, { ref: panelRef, "aria-label": ariaLabel, "data-testid": testId,
32
+ // Focusable by script only, so opening can land on the region without adding a tab stop.
33
+ tabIndex: -1, onFocusCapture: onFocusCapture, initial: motionStates.closed, animate: motionStates.open, exit: motionStates.closed, transition: shouldReduceMotion || hasCrossedBreakpoint ? { duration: 0 } : SPRING,
34
+ // overflow-hidden clips the fixed-width content while the panel's own width animates.
35
+ className: cx('flex h-full min-h-0 shrink-0 overflow-hidden bg-secondary outline-focus-ring focus-visible:outline-2 focus-visible:-outline-offset-2', !isDesktop && 'absolute inset-y-0 right-0 z-10', className), children: jsx("div", { className: cx('flex h-full shrink-0 flex-col', isDesktop ? 'w-100 border-l border-secondary' : 'w-full'), children: children }) }));
36
+ };
37
+
38
+ export { SIDE_PANEL_WIDTH, SidePanelRegion };
39
+ //# sourceMappingURL=side-panel-region.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"side-panel-region.js","sources":["../../../../../src/components/organisms/SidePanel/components/side-panel-region.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;;;AAQA;AACO,MAAM,gBAAgB,GAAG;AAEhC,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAW;AAElF,MAAM,MAAM,GAAG;IACb,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IAC1B,IAAI,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE;CAC/B;AAEV,MAAM,SAAS,GAAG;IAChB,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE;IACpC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE;CACrB;AAWV;MACa,eAAe,GAAG,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAwB,KAAI;AAC/I,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAc,IAAI,CAAC;AAC1C,IAAA,MAAM,SAAS,GAAG,YAAY,EAAE;AAChC,IAAA,MAAM,kBAAkB,GAAG,gBAAgB,EAAE;AAC7C,IAAA,MAAM,EAAE,cAAc,EAAE,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;;AAGhG,IAAA,MAAM,iBAAiB,GAAG,MAAM,CAAC,SAAS,CAAC;AAC3C,IAAA,MAAM,oBAAoB,GAAG,iBAAiB,CAAC,OAAO,KAAK,SAAS;IACpE,SAAS,CAAC,MAAK;AACb,QAAA,iBAAiB,CAAC,OAAO,GAAG,SAAS;AACvC,IAAA,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IAEf,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS;AAEnD,IAAA,QACEA,GAAA,CAAC,MAAM,CAAC,KAAK,EAAA,EACX,GAAG,EAAE,QAAQ,EAAA,YAAA,EACD,SAAS,EAAA,aAAA,EACR,MAAM;;AAEnB,QAAA,QAAQ,EAAE,EAAE,EACZ,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,YAAY,CAAC,MAAM,EAC5B,OAAO,EAAE,YAAY,CAAC,IAAI,EAC1B,IAAI,EAAE,YAAY,CAAC,MAAM,EACzB,UAAU,EAAE,kBAAkB,IAAI,oBAAoB,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,MAAM;;AAEjF,QAAA,SAAS,EAAE,EAAE,CACX,sIAAsI,EACtI,CAAC,SAAS,IAAI,iCAAiC,EAC/C,SAAS,CACV,EAAA,QAAA,EAGDA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,GAAG,iCAAiC,GAAG,QAAQ,CAAC,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAO,EAAA,CAClH;AAEnB;;;;"}
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ const subscribeToNothing = () => () => { };
6
+ /**
7
+ * Tells the panel whether opening should move focus into it. A panel that is already open when the
8
+ * page loads must not pull focus away from the page, and "when the page loads" means the first render
9
+ * that knows the viewport: on the server and while hydrating nothing renders, so state restored right
10
+ * after hydration still counts as open on load.
11
+ *
12
+ * @returns whether the viewport is known yet, and whether an opening panel should take focus
13
+ */
14
+ const useOpenOnMount = (isOpen) => {
15
+ // False on the server and while hydrating, where the viewport is unknown. True at once in a client-only app.
16
+ const canMeasureViewport = React.useSyncExternalStore(subscribeToNothing, () => true, () => false);
17
+ const wasOpenOnMount = React.useRef(null);
18
+ if (canMeasureViewport && wasOpenOnMount.current === null)
19
+ wasOpenOnMount.current = isOpen;
20
+ React.useEffect(() => {
21
+ // Once it has been closed, the next open is the user's doing and takes focus.
22
+ if (canMeasureViewport && !isOpen)
23
+ wasOpenOnMount.current = false;
24
+ }, [canMeasureViewport, isOpen]);
25
+ return { canMeasureViewport, shouldFocusOnMount: !wasOpenOnMount.current };
26
+ };
27
+
28
+ exports.useOpenOnMount = useOpenOnMount;
29
+ //# sourceMappingURL=useOpenOnMount.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOpenOnMount.cjs","sources":["../../../../../src/components/organisms/SidePanel/hooks/useOpenOnMount.ts"],"sourcesContent":[null],"names":["useSyncExternalStore","useRef","useEffect"],"mappings":";;;;AAIA,MAAM,kBAAkB,GAAG,MAAM,MAAK,EAAE,CAAC;AAEzC;;;;;;;AAOG;AACI,MAAM,cAAc,GAAG,CAAC,MAAe,KAAI;;AAEhD,IAAA,MAAM,kBAAkB,GAAGA,0BAAoB,CAC7C,kBAAkB,EAClB,MAAM,IAAI,EACV,MAAM,KAAK,CACZ;AAED,IAAA,MAAM,cAAc,GAAGC,YAAM,CAAiB,IAAI,CAAC;AACnD,IAAA,IAAI,kBAAkB,IAAI,cAAc,CAAC,OAAO,KAAK,IAAI;AAAE,QAAA,cAAc,CAAC,OAAO,GAAG,MAAM;IAC1FC,eAAS,CAAC,MAAK;;QAEb,IAAI,kBAAkB,IAAI,CAAC,MAAM;AAAE,YAAA,cAAc,CAAC,OAAO,GAAG,KAAK;AACnE,IAAA,CAAC,EAAE,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IAEhC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE;AAC5E;;;;"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Tells the panel whether opening should move focus into it. A panel that is already open when the
3
+ * page loads must not pull focus away from the page, and "when the page loads" means the first render
4
+ * that knows the viewport: on the server and while hydrating nothing renders, so state restored right
5
+ * after hydration still counts as open on load.
6
+ *
7
+ * @returns whether the viewport is known yet, and whether an opening panel should take focus
8
+ */
9
+ export declare const useOpenOnMount: (isOpen: boolean) => {
10
+ canMeasureViewport: boolean;
11
+ shouldFocusOnMount: boolean;
12
+ };
13
+ //# sourceMappingURL=useOpenOnMount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOpenOnMount.d.ts","sourceRoot":"","sources":["../../../../../src/components/organisms/SidePanel/hooks/useOpenOnMount.ts"],"names":[],"mappings":"AAMA;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,OAAO;;;CAgB7C,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { useSyncExternalStore, useRef, useEffect } from 'react';
2
+
3
+ const subscribeToNothing = () => () => { };
4
+ /**
5
+ * Tells the panel whether opening should move focus into it. A panel that is already open when the
6
+ * page loads must not pull focus away from the page, and "when the page loads" means the first render
7
+ * that knows the viewport: on the server and while hydrating nothing renders, so state restored right
8
+ * after hydration still counts as open on load.
9
+ *
10
+ * @returns whether the viewport is known yet, and whether an opening panel should take focus
11
+ */
12
+ const useOpenOnMount = (isOpen) => {
13
+ // False on the server and while hydrating, where the viewport is unknown. True at once in a client-only app.
14
+ const canMeasureViewport = useSyncExternalStore(subscribeToNothing, () => true, () => false);
15
+ const wasOpenOnMount = useRef(null);
16
+ if (canMeasureViewport && wasOpenOnMount.current === null)
17
+ wasOpenOnMount.current = isOpen;
18
+ useEffect(() => {
19
+ // Once it has been closed, the next open is the user's doing and takes focus.
20
+ if (canMeasureViewport && !isOpen)
21
+ wasOpenOnMount.current = false;
22
+ }, [canMeasureViewport, isOpen]);
23
+ return { canMeasureViewport, shouldFocusOnMount: !wasOpenOnMount.current };
24
+ };
25
+
26
+ export { useOpenOnMount };
27
+ //# sourceMappingURL=useOpenOnMount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOpenOnMount.js","sources":["../../../../../src/components/organisms/SidePanel/hooks/useOpenOnMount.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAIA,MAAM,kBAAkB,GAAG,MAAM,MAAK,EAAE,CAAC;AAEzC;;;;;;;AAOG;AACI,MAAM,cAAc,GAAG,CAAC,MAAe,KAAI;;AAEhD,IAAA,MAAM,kBAAkB,GAAG,oBAAoB,CAC7C,kBAAkB,EAClB,MAAM,IAAI,EACV,MAAM,KAAK,CACZ;AAED,IAAA,MAAM,cAAc,GAAG,MAAM,CAAiB,IAAI,CAAC;AACnD,IAAA,IAAI,kBAAkB,IAAI,cAAc,CAAC,OAAO,KAAK,IAAI;AAAE,QAAA,cAAc,CAAC,OAAO,GAAG,MAAM;IAC1F,SAAS,CAAC,MAAK;;QAEb,IAAI,kBAAkB,IAAI,CAAC,MAAM;AAAE,YAAA,cAAc,CAAC,OAAO,GAAG,KAAK;AACnE,IAAA,CAAC,EAAE,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IAEhC,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE;AAC5E;;;;"}
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var focus_utils = require('../../../../utilities/__internal__/focusUtils/focus.utils.cjs');
5
+
6
+ /** The element before the panel when it can take focus, such as `AppShell`'s scroll area. */
7
+ const focusableSiblingBefore = (panel) => {
8
+ const sibling = panel.previousElementSibling;
9
+ return sibling instanceof HTMLElement && sibling.tabIndex >= 0 ? sibling : null;
10
+ };
11
+ /**
12
+ * Hands focus into the panel when it opens and back to the control that opened it when it closes,
13
+ * and makes a leaving panel inert. Managed by hand, not with a focus scope: a scope would also
14
+ * reroute Tab at the panel's edges, as a popover does.
15
+ *
16
+ * @returns a capture-phase focus handler to spread onto the panel element
17
+ */
18
+ const usePanelFocus = ({ panelRef, isPresent, isDesktop, shouldFocusOnMount }) => {
19
+ const openerRef = React.useRef(null);
20
+ const previousIsPresent = React.useRef(null);
21
+ const previousIsDesktop = React.useRef(isDesktop);
22
+ // Read while rendering, before the content mounts: an `autoFocus` input takes focus during commit, ahead of any effect.
23
+ const [focusedBeforeMount] = React.useState(focus_utils.getFocusedElement);
24
+ React.useEffect(() => {
25
+ const panel = panelRef.current;
26
+ if (!panel)
27
+ return;
28
+ const previous = previousIsPresent.current;
29
+ previousIsPresent.current = isPresent;
30
+ // Entering covers a fresh open and a reopen that interrupts the close animation.
31
+ const isEntering = isPresent && (previous === false || (previous === null && shouldFocusOnMount));
32
+ const isLeaving = !isPresent && previous === true;
33
+ const focused = focus_utils.getFocusedElement();
34
+ const hasFocusInside = focused !== null && panel.contains(focused);
35
+ // A panel reopened mid-close is still inert from leaving, and an inert element cannot take focus.
36
+ if (isPresent)
37
+ panel.inert = false;
38
+ if (isEntering) {
39
+ // On mount the content may already hold focus, so the opener is what was focused before it. A reopen mid-close finds focus still outside.
40
+ openerRef.current = previous === null ? focusedBeforeMount : focused;
41
+ // Content that focused itself (an `autoFocus` input) keeps focus; otherwise the region takes it.
42
+ // preventScroll: below `lg` the panel starts off-screen, and scrolling it into view would shift the layout.
43
+ if (!hasFocusInside)
44
+ panel.focus({ preventScroll: true });
45
+ }
46
+ // Hand focus back only if it is still in the panel, so a user who has moved on is left alone.
47
+ if (isLeaving && hasFocusInside) {
48
+ const opener = openerRef.current;
49
+ // The opener may have unmounted meanwhile, such as a header button that only renders at one breakpoint.
50
+ (opener?.isConnected ? opener : focusableSiblingBefore(panel))?.focus();
51
+ }
52
+ // A leaving panel must not be reachable while another opens; set last, since inert drops any focus inside it.
53
+ if (!isPresent)
54
+ panel.inert = true;
55
+ }, [panelRef, isPresent, shouldFocusOnMount, focusedBeforeMount]);
56
+ React.useEffect(() => {
57
+ const hasStartedCoveringPage = previousIsDesktop.current && !isDesktop;
58
+ previousIsDesktop.current = isDesktop;
59
+ const panel = panelRef.current;
60
+ const focused = focus_utils.getFocusedElement();
61
+ // The page beside the panel is about to go out of reach, so focus must not be left in it.
62
+ if (hasStartedCoveringPage && panel && focused && !panel.contains(focused) && panel.parentElement?.contains(focused)) {
63
+ panel.focus({ preventScroll: true });
64
+ }
65
+ }, [panelRef, isDesktop]);
66
+ // A panel that was open on load has no opener, so closing hands focus back to wherever it first came in from.
67
+ const onFocusCapture = (event) => {
68
+ const from = event.relatedTarget;
69
+ if (openerRef.current === null && from instanceof HTMLElement && !event.currentTarget.contains(from))
70
+ openerRef.current = from;
71
+ };
72
+ return { onFocusCapture };
73
+ };
74
+
75
+ exports.usePanelFocus = usePanelFocus;
76
+ //# sourceMappingURL=usePanelFocus.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePanelFocus.cjs","sources":["../../../../../src/components/organisms/SidePanel/hooks/usePanelFocus.ts"],"sourcesContent":[null],"names":["useRef","useState","getFocusedElement","useEffect"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { FocusEvent, RefObject } from 'react';
2
+ interface UsePanelFocusOptions {
3
+ panelRef: RefObject<HTMLElement | null>;
4
+ /** From `useIsPresent`: false once the panel is animating out. */
5
+ isPresent: boolean;
6
+ /** Whether the panel is docked beside the page rather than covering it. */
7
+ isDesktop: boolean;
8
+ /** False for a panel that is open on the first render, which must not pull focus away from the page. */
9
+ shouldFocusOnMount: boolean;
10
+ }
11
+ /**
12
+ * Hands focus into the panel when it opens and back to the control that opened it when it closes,
13
+ * and makes a leaving panel inert. Managed by hand, not with a focus scope: a scope would also
14
+ * reroute Tab at the panel's edges, as a popover does.
15
+ *
16
+ * @returns a capture-phase focus handler to spread onto the panel element
17
+ */
18
+ export declare const usePanelFocus: ({ panelRef, isPresent, isDesktop, shouldFocusOnMount }: UsePanelFocusOptions) => {
19
+ onFocusCapture: (event: FocusEvent<HTMLElement>) => void;
20
+ };
21
+ export {};
22
+ //# sourceMappingURL=usePanelFocus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePanelFocus.d.ts","sourceRoot":"","sources":["../../../../../src/components/organisms/SidePanel/hooks/usePanelFocus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWnD,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACxC,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,2EAA2E;IAC3E,SAAS,EAAE,OAAO,CAAC;IACnB,wGAAwG;IACxG,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAI,wDAAwD,oBAAoB;4BAmDzE,UAAU,CAAC,WAAW,CAAC;CAMvD,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { useRef, useState, useEffect } from 'react';
2
+ import { getFocusedElement } from '../../../../utilities/__internal__/focusUtils/focus.utils.js';
3
+
4
+ /** The element before the panel when it can take focus, such as `AppShell`'s scroll area. */
5
+ const focusableSiblingBefore = (panel) => {
6
+ const sibling = panel.previousElementSibling;
7
+ return sibling instanceof HTMLElement && sibling.tabIndex >= 0 ? sibling : null;
8
+ };
9
+ /**
10
+ * Hands focus into the panel when it opens and back to the control that opened it when it closes,
11
+ * and makes a leaving panel inert. Managed by hand, not with a focus scope: a scope would also
12
+ * reroute Tab at the panel's edges, as a popover does.
13
+ *
14
+ * @returns a capture-phase focus handler to spread onto the panel element
15
+ */
16
+ const usePanelFocus = ({ panelRef, isPresent, isDesktop, shouldFocusOnMount }) => {
17
+ const openerRef = useRef(null);
18
+ const previousIsPresent = useRef(null);
19
+ const previousIsDesktop = useRef(isDesktop);
20
+ // Read while rendering, before the content mounts: an `autoFocus` input takes focus during commit, ahead of any effect.
21
+ const [focusedBeforeMount] = useState(getFocusedElement);
22
+ useEffect(() => {
23
+ const panel = panelRef.current;
24
+ if (!panel)
25
+ return;
26
+ const previous = previousIsPresent.current;
27
+ previousIsPresent.current = isPresent;
28
+ // Entering covers a fresh open and a reopen that interrupts the close animation.
29
+ const isEntering = isPresent && (previous === false || (previous === null && shouldFocusOnMount));
30
+ const isLeaving = !isPresent && previous === true;
31
+ const focused = getFocusedElement();
32
+ const hasFocusInside = focused !== null && panel.contains(focused);
33
+ // A panel reopened mid-close is still inert from leaving, and an inert element cannot take focus.
34
+ if (isPresent)
35
+ panel.inert = false;
36
+ if (isEntering) {
37
+ // On mount the content may already hold focus, so the opener is what was focused before it. A reopen mid-close finds focus still outside.
38
+ openerRef.current = previous === null ? focusedBeforeMount : focused;
39
+ // Content that focused itself (an `autoFocus` input) keeps focus; otherwise the region takes it.
40
+ // preventScroll: below `lg` the panel starts off-screen, and scrolling it into view would shift the layout.
41
+ if (!hasFocusInside)
42
+ panel.focus({ preventScroll: true });
43
+ }
44
+ // Hand focus back only if it is still in the panel, so a user who has moved on is left alone.
45
+ if (isLeaving && hasFocusInside) {
46
+ const opener = openerRef.current;
47
+ // The opener may have unmounted meanwhile, such as a header button that only renders at one breakpoint.
48
+ (opener?.isConnected ? opener : focusableSiblingBefore(panel))?.focus();
49
+ }
50
+ // A leaving panel must not be reachable while another opens; set last, since inert drops any focus inside it.
51
+ if (!isPresent)
52
+ panel.inert = true;
53
+ }, [panelRef, isPresent, shouldFocusOnMount, focusedBeforeMount]);
54
+ useEffect(() => {
55
+ const hasStartedCoveringPage = previousIsDesktop.current && !isDesktop;
56
+ previousIsDesktop.current = isDesktop;
57
+ const panel = panelRef.current;
58
+ const focused = getFocusedElement();
59
+ // The page beside the panel is about to go out of reach, so focus must not be left in it.
60
+ if (hasStartedCoveringPage && panel && focused && !panel.contains(focused) && panel.parentElement?.contains(focused)) {
61
+ panel.focus({ preventScroll: true });
62
+ }
63
+ }, [panelRef, isDesktop]);
64
+ // A panel that was open on load has no opener, so closing hands focus back to wherever it first came in from.
65
+ const onFocusCapture = (event) => {
66
+ const from = event.relatedTarget;
67
+ if (openerRef.current === null && from instanceof HTMLElement && !event.currentTarget.contains(from))
68
+ openerRef.current = from;
69
+ };
70
+ return { onFocusCapture };
71
+ };
72
+
73
+ export { usePanelFocus };
74
+ //# sourceMappingURL=usePanelFocus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePanelFocus.js","sources":["../../../../../src/components/organisms/SidePanel/hooks/usePanelFocus.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}