eidos-ui 3.6.0 → 3.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TNBML2MJ.cjs → chunk-HEXAY6DE.cjs} +7 -4
- package/dist/chunk-HEXAY6DE.cjs.map +1 -0
- package/dist/{chunk-3LRT7ZIB.js → chunk-LGDODZHI.js} +7 -4
- package/dist/chunk-LGDODZHI.js.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.css +2 -6
- package/dist/index.js +1 -1
- package/dist/page-layout/index.cjs +2 -2
- package/dist/page-layout/index.d.cts +1 -1
- package/dist/page-layout/index.d.ts +1 -1
- package/dist/page-layout/index.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-3LRT7ZIB.js.map +0 -1
- package/dist/chunk-TNBML2MJ.cjs.map +0 -1
|
@@ -29,11 +29,14 @@ var useScrollRestoration = (key, forwardTo) => {
|
|
|
29
29
|
}, []);
|
|
30
30
|
_react.useEffect.call(void 0, () => {
|
|
31
31
|
const element = node.current;
|
|
32
|
-
if (!element
|
|
33
|
-
const record = () =>
|
|
32
|
+
if (!element) return;
|
|
33
|
+
const record = () => {
|
|
34
|
+
const current = appliedKey.current;
|
|
35
|
+
if (current !== void 0) offsets.current.set(current, element.scrollTop);
|
|
36
|
+
};
|
|
34
37
|
element.addEventListener("scroll", record, { passive: true });
|
|
35
38
|
return () => element.removeEventListener("scroll", record);
|
|
36
|
-
}, [
|
|
39
|
+
}, []);
|
|
37
40
|
_react.useLayoutEffect.call(void 0, () => {
|
|
38
41
|
const element = node.current;
|
|
39
42
|
if (!element || key === void 0 || appliedKey.current === key) return;
|
|
@@ -93,4 +96,4 @@ var PageLayout = ({
|
|
|
93
96
|
|
|
94
97
|
|
|
95
98
|
exports.PageLayout = PageLayout;
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-HEXAY6DE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-HEXAY6DE.cjs","../src/components/PageLayout/useScrollRestoration.ts","../src/components/PageLayout/PageLayout.component.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-HEXAY6DE.cjs","sourcesContent":[null,"import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';\n\n/**\n * Remembers the content region's scroll offset per key, and applies the\n * stored offset whenever the key changes.\n *\n * The key is supplied by the consumer rather than derived here, because only\n * they know what counts as a navigation - this library has no router opinion.\n * That also decides the semantics, exactly as React Router's `getKey` does:\n * a per-path key gives \"this path always reopens where you left it\", while a\n * per-history-entry key gives the browser's own behaviour, where Back\n * restores but a fresh link to the same URL starts at the top.\n *\n * Returns a ref callback for the scroll container, which also forwards the\n * node to the caller's own `contentRef`.\n */\nexport const useScrollRestoration = (\n key: string | number | undefined,\n forwardTo: React.Ref<HTMLElement> | undefined,\n): ((node: HTMLElement | null) => void) => {\n const node = useRef<HTMLElement | null>(null);\n const offsets = useRef(new Map<string | number, number>());\n const appliedKey = useRef(key);\n\n // Held in a ref so the ref callback below can keep a stable identity. A\n // callback ref that changes identity is invoked with `null` and then the\n // node again on every render that changes it, which would detach and\n // reattach the caller's ref for no reason.\n const forwarded = useRef(forwardTo);\n useEffect(() => {\n forwarded.current = forwardTo;\n }, [forwardTo]);\n\n const setNode = useCallback((element: HTMLElement | null) => {\n node.current = element;\n const ref = forwarded.current;\n if (typeof ref === 'function') ref(element);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = element;\n }, []);\n\n // Recorded as it happens rather than when the key changes: by the time a\n // navigation commits, the new page's content is already in the DOM and the\n // browser has clamped `scrollTop` to the new, possibly shorter, height. The\n // outgoing offset is no longer readable at that point.\n //\n // **The key is read from a ref, and the listener is registered once.** Both\n // halves matter. A listener re-subscribed per key closes over the key it was\n // created with, and restoring the incoming page's offset sets `scrollTop`,\n // which makes the browser dispatch a `scroll` event - so the two race:\n //\n // 1. the layout effect below sets `scrollTop` for the incoming key\n // 2. passive effects swap the listener from the outgoing key to it\n // 3. the browser dispatches the scroll event from step 1\n //\n // React flushes passive effects through the scheduler and the browser\n // dispatches `scroll` at its own rendering opportunity, so nothing orders 2\n // before 3. When 3 won, the still-attached *outgoing* listener recorded the\n // incoming page's offset under the outgoing page's key - overwriting a real\n // offset with 0 and losing the position it exists to keep. It passed locally\n // and failed in CI, which is what a race of this shape looks like.\n //\n // Reading `appliedKey` instead means whichever order those steps take, the\n // offset is filed under the key that is actually on screen: the layout effect\n // updates the ref before it touches `scrollTop`.\n useEffect(() => {\n const element = node.current;\n if (!element) return;\n\n const record = () => {\n const current = appliedKey.current;\n if (current !== undefined) offsets.current.set(current, element.scrollTop);\n };\n\n element.addEventListener('scroll', record, { passive: true });\n return () => element.removeEventListener('scroll', record);\n // Registered once, for the same reason: re-subscribing is what created the\n // window where a stale key could be recorded.\n }, []);\n\n // Layout effect so the offset is applied before paint - in a passive effect\n // the new page is visible at the previous page's offset for a frame first.\n // It does not run on the server, which is correct here: there is no scroll\n // position to restore in static markup, and the client applies it on mount.\n useLayoutEffect(() => {\n const element = node.current;\n if (!element || key === undefined || appliedKey.current === key) return;\n\n appliedKey.current = key;\n element.scrollTop = offsets.current.get(key) ?? 0;\n }, [key]);\n\n return setNode;\n};\n","import React from 'react';\nimport type { PageLayoutProps } from './PageLayout.types';\nimport './PageLayout.scss';\nimport { Toolbar } from '../Toolbar';\nimport { Header } from '../Header';\nimport { Footer } from '../Footer';\nimport type { FooterProps } from '../Footer';\nimport { Navigation } from '../Navigation';\nimport { useScrollRestoration } from './useScrollRestoration';\n\nconst defaultFooter: FooterProps = { copyright: `© ${new Date().getFullYear()} Eidos UI` };\n\nexport const PageLayout: React.FC<PageLayoutProps> = ({\n toolbar,\n navigation,\n header,\n footer,\n children,\n className = '',\n // Destructured so they cannot fall into `...rest` and land on the root\n // element, which is not the scroll container.\n contentRef,\n scrollRestorationKey,\n ...rest\n}) => {\n const classes = ['eidos-pagelayout', className].filter(Boolean).join(' ');\n const setContentRef = useScrollRestoration(scrollRestorationKey, contentRef);\n\n return (\n <div className={classes} {...rest}>\n {/* Spread rather than forwarded field by field, so a prop added to\n `Toolbar` reaches `PageLayout` consumers without a second edit\n here - the previous per-field list silently dropped anything it\n didn't know about. `className` is merged last so the layout's own\n grid-area class can't be overwritten by the caller's. */}\n <Toolbar\n {...toolbar}\n className={['eidos-pagelayout__toolbar', toolbar?.className].filter(Boolean).join(' ')}\n />\n <div className=\"eidos-pagelayout__navigation\">\n {navigation && <Navigation {...navigation} />}\n </div>\n {/* A scrollable region containing nothing focusable cannot be scrolled\n by keyboard at all, and a page body is often pure content - a\n report, an article. `tabIndex={0}` makes the region itself focusable\n so arrow keys and Page Up/Down reach it (SC 2.1.1), matching\n `VirtualList` and `Chat`. */}\n <main ref={setContentRef} tabIndex={0} className=\"eidos-pagelayout__content\">\n {header && (\n <Header\n {...header}\n className={['eidos-pagelayout__header', header.className].filter(Boolean).join(' ')}\n />\n )}\n <div className=\"eidos-pagelayout__body\">{children}</div>\n <Footer\n {...(footer ?? defaultFooter)}\n className={['eidos-pagelayout__footer', footer?.className].filter(Boolean).join(' ')}\n />\n </main>\n </div>\n );\n};\n"]}
|
|
@@ -29,11 +29,14 @@ var useScrollRestoration = (key, forwardTo) => {
|
|
|
29
29
|
}, []);
|
|
30
30
|
useEffect(() => {
|
|
31
31
|
const element = node.current;
|
|
32
|
-
if (!element
|
|
33
|
-
const record = () =>
|
|
32
|
+
if (!element) return;
|
|
33
|
+
const record = () => {
|
|
34
|
+
const current = appliedKey.current;
|
|
35
|
+
if (current !== void 0) offsets.current.set(current, element.scrollTop);
|
|
36
|
+
};
|
|
34
37
|
element.addEventListener("scroll", record, { passive: true });
|
|
35
38
|
return () => element.removeEventListener("scroll", record);
|
|
36
|
-
}, [
|
|
39
|
+
}, []);
|
|
37
40
|
useLayoutEffect(() => {
|
|
38
41
|
const element = node.current;
|
|
39
42
|
if (!element || key === void 0 || appliedKey.current === key) return;
|
|
@@ -93,4 +96,4 @@ var PageLayout = ({
|
|
|
93
96
|
export {
|
|
94
97
|
PageLayout
|
|
95
98
|
};
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-LGDODZHI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/PageLayout/useScrollRestoration.ts","../src/components/PageLayout/PageLayout.component.tsx"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';\n\n/**\n * Remembers the content region's scroll offset per key, and applies the\n * stored offset whenever the key changes.\n *\n * The key is supplied by the consumer rather than derived here, because only\n * they know what counts as a navigation - this library has no router opinion.\n * That also decides the semantics, exactly as React Router's `getKey` does:\n * a per-path key gives \"this path always reopens where you left it\", while a\n * per-history-entry key gives the browser's own behaviour, where Back\n * restores but a fresh link to the same URL starts at the top.\n *\n * Returns a ref callback for the scroll container, which also forwards the\n * node to the caller's own `contentRef`.\n */\nexport const useScrollRestoration = (\n key: string | number | undefined,\n forwardTo: React.Ref<HTMLElement> | undefined,\n): ((node: HTMLElement | null) => void) => {\n const node = useRef<HTMLElement | null>(null);\n const offsets = useRef(new Map<string | number, number>());\n const appliedKey = useRef(key);\n\n // Held in a ref so the ref callback below can keep a stable identity. A\n // callback ref that changes identity is invoked with `null` and then the\n // node again on every render that changes it, which would detach and\n // reattach the caller's ref for no reason.\n const forwarded = useRef(forwardTo);\n useEffect(() => {\n forwarded.current = forwardTo;\n }, [forwardTo]);\n\n const setNode = useCallback((element: HTMLElement | null) => {\n node.current = element;\n const ref = forwarded.current;\n if (typeof ref === 'function') ref(element);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = element;\n }, []);\n\n // Recorded as it happens rather than when the key changes: by the time a\n // navigation commits, the new page's content is already in the DOM and the\n // browser has clamped `scrollTop` to the new, possibly shorter, height. The\n // outgoing offset is no longer readable at that point.\n //\n // **The key is read from a ref, and the listener is registered once.** Both\n // halves matter. A listener re-subscribed per key closes over the key it was\n // created with, and restoring the incoming page's offset sets `scrollTop`,\n // which makes the browser dispatch a `scroll` event - so the two race:\n //\n // 1. the layout effect below sets `scrollTop` for the incoming key\n // 2. passive effects swap the listener from the outgoing key to it\n // 3. the browser dispatches the scroll event from step 1\n //\n // React flushes passive effects through the scheduler and the browser\n // dispatches `scroll` at its own rendering opportunity, so nothing orders 2\n // before 3. When 3 won, the still-attached *outgoing* listener recorded the\n // incoming page's offset under the outgoing page's key - overwriting a real\n // offset with 0 and losing the position it exists to keep. It passed locally\n // and failed in CI, which is what a race of this shape looks like.\n //\n // Reading `appliedKey` instead means whichever order those steps take, the\n // offset is filed under the key that is actually on screen: the layout effect\n // updates the ref before it touches `scrollTop`.\n useEffect(() => {\n const element = node.current;\n if (!element) return;\n\n const record = () => {\n const current = appliedKey.current;\n if (current !== undefined) offsets.current.set(current, element.scrollTop);\n };\n\n element.addEventListener('scroll', record, { passive: true });\n return () => element.removeEventListener('scroll', record);\n // Registered once, for the same reason: re-subscribing is what created the\n // window where a stale key could be recorded.\n }, []);\n\n // Layout effect so the offset is applied before paint - in a passive effect\n // the new page is visible at the previous page's offset for a frame first.\n // It does not run on the server, which is correct here: there is no scroll\n // position to restore in static markup, and the client applies it on mount.\n useLayoutEffect(() => {\n const element = node.current;\n if (!element || key === undefined || appliedKey.current === key) return;\n\n appliedKey.current = key;\n element.scrollTop = offsets.current.get(key) ?? 0;\n }, [key]);\n\n return setNode;\n};\n","import React from 'react';\nimport type { PageLayoutProps } from './PageLayout.types';\nimport './PageLayout.scss';\nimport { Toolbar } from '../Toolbar';\nimport { Header } from '../Header';\nimport { Footer } from '../Footer';\nimport type { FooterProps } from '../Footer';\nimport { Navigation } from '../Navigation';\nimport { useScrollRestoration } from './useScrollRestoration';\n\nconst defaultFooter: FooterProps = { copyright: `© ${new Date().getFullYear()} Eidos UI` };\n\nexport const PageLayout: React.FC<PageLayoutProps> = ({\n toolbar,\n navigation,\n header,\n footer,\n children,\n className = '',\n // Destructured so they cannot fall into `...rest` and land on the root\n // element, which is not the scroll container.\n contentRef,\n scrollRestorationKey,\n ...rest\n}) => {\n const classes = ['eidos-pagelayout', className].filter(Boolean).join(' ');\n const setContentRef = useScrollRestoration(scrollRestorationKey, contentRef);\n\n return (\n <div className={classes} {...rest}>\n {/* Spread rather than forwarded field by field, so a prop added to\n `Toolbar` reaches `PageLayout` consumers without a second edit\n here - the previous per-field list silently dropped anything it\n didn't know about. `className` is merged last so the layout's own\n grid-area class can't be overwritten by the caller's. */}\n <Toolbar\n {...toolbar}\n className={['eidos-pagelayout__toolbar', toolbar?.className].filter(Boolean).join(' ')}\n />\n <div className=\"eidos-pagelayout__navigation\">\n {navigation && <Navigation {...navigation} />}\n </div>\n {/* A scrollable region containing nothing focusable cannot be scrolled\n by keyboard at all, and a page body is often pure content - a\n report, an article. `tabIndex={0}` makes the region itself focusable\n so arrow keys and Page Up/Down reach it (SC 2.1.1), matching\n `VirtualList` and `Chat`. */}\n <main ref={setContentRef} tabIndex={0} className=\"eidos-pagelayout__content\">\n {header && (\n <Header\n {...header}\n className={['eidos-pagelayout__header', header.className].filter(Boolean).join(' ')}\n />\n )}\n <div className=\"eidos-pagelayout__body\">{children}</div>\n <Footer\n {...(footer ?? defaultFooter)}\n className={['eidos-pagelayout__footer', footer?.className].filter(Boolean).join(' ')}\n />\n </main>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,aAAa,WAAW,iBAAiB,cAAc;AAgBzD,IAAM,uBAAuB,CAClC,KACA,cACyC;AACzC,QAAM,OAAO,OAA2B,IAAI;AAC5C,QAAM,UAAU,OAAO,oBAAI,IAA6B,CAAC;AACzD,QAAM,aAAa,OAAO,GAAG;AAM7B,QAAM,YAAY,OAAO,SAAS;AAClC,YAAU,MAAM;AACd,cAAU,UAAU;AAAA,EACtB,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,UAAU,YAAY,CAAC,YAAgC;AAC3D,SAAK,UAAU;AACf,UAAM,MAAM,UAAU;AACtB,QAAI,OAAO,QAAQ,WAAY,KAAI,OAAO;AAAA,aACjC,IAAK,CAAC,IAA4C,UAAU;AAAA,EACvE,GAAG,CAAC,CAAC;AA0BL,YAAU,MAAM;AACd,UAAM,UAAU,KAAK;AACrB,QAAI,CAAC,QAAS;AAEd,UAAM,SAAS,MAAM;AACnB,YAAM,UAAU,WAAW;AAC3B,UAAI,YAAY,OAAW,SAAQ,QAAQ,IAAI,SAAS,QAAQ,SAAS;AAAA,IAC3E;AAEA,YAAQ,iBAAiB,UAAU,QAAQ,EAAE,SAAS,KAAK,CAAC;AAC5D,WAAO,MAAM,QAAQ,oBAAoB,UAAU,MAAM;AAAA,EAG3D,GAAG,CAAC,CAAC;AAML,kBAAgB,MAAM;AACpB,UAAM,UAAU,KAAK;AACrB,QAAI,CAAC,WAAW,QAAQ,UAAa,WAAW,YAAY,IAAK;AAEjE,eAAW,UAAU;AACrB,YAAQ,YAAY,QAAQ,QAAQ,IAAI,GAAG,KAAK;AAAA,EAClD,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AACT;;;ACzDM,cAYA,YAZA;AAzBN,IAAM,gBAA6B,EAAE,WAAW,SAAK,oBAAI,KAAK,GAAE,YAAY,CAAC,YAAY;AAElF,IAAM,aAAwC,CAAC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA;AAAA;AAAA,EAGZ;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,QAAM,UAAU,CAAC,oBAAoB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AACxE,QAAM,gBAAgB,qBAAqB,sBAAsB,UAAU;AAE3E,SACE,qBAAC,SAAI,WAAW,SAAU,GAAG,MAM3B;AAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,WAAW,CAAC,6BAA6B,SAAS,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA;AAAA,IACvF;AAAA,IACA,oBAAC,SAAI,WAAU,gCACZ,wBAAc,oBAAC,cAAY,GAAG,YAAY,GAC7C;AAAA,IAMA,qBAAC,UAAK,KAAK,eAAe,UAAU,GAAG,WAAU,6BAC9C;AAAA,gBACC;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ,WAAW,CAAC,4BAA4B,OAAO,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA;AAAA,MACpF;AAAA,MAEF,oBAAC,SAAI,WAAU,0BAA0B,UAAS;AAAA,MAClD;AAAA,QAAC;AAAA;AAAA,UACE,GAAI,UAAU;AAAA,UACf,WAAW,CAAC,4BAA4B,QAAQ,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA;AAAA,MACrF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -56,7 +56,7 @@ var _chunkIXZMKIV5cjs = require('./chunk-IXZMKIV5.cjs');
|
|
|
56
56
|
var _chunkVHO6JPRRcjs = require('./chunk-VHO6JPRR.cjs');
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
var
|
|
59
|
+
var _chunkHEXAY6DEcjs = require('./chunk-HEXAY6DE.cjs');
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
var _chunkJCKGAAPZcjs = require('./chunk-JCKGAAPZ.cjs');
|
|
@@ -301,5 +301,5 @@ require('./chunk-DZUJEN5N.cjs');
|
|
|
301
301
|
|
|
302
302
|
|
|
303
303
|
|
|
304
|
-
exports.Accordion = _chunkEAJGSXEWcjs.Accordion; exports.AccordionItem = _chunkEAJGSXEWcjs.AccordionItem; exports.Alert = _chunk3RWZC6OWcjs.Alert; exports.Avatar = _chunkQ3GNKF74cjs.Avatar; exports.AvatarGroup = _chunkQ3GNKF74cjs.AvatarGroup; exports.Badge = _chunk3ETWFS2Ncjs.Badge; exports.Breadcrumb = _chunk5O73AALPcjs.Breadcrumb; exports.Button = _chunkDA375AI6cjs.Button; exports.ButtonGroup = _chunk2ROKOO22cjs.ButtonGroup; exports.Calendar = _chunk6JHVXWDVcjs.Calendar; exports.Card = _chunkV5RS3JZNcjs.Card; exports.Chat = _chunkX3BVQBXDcjs.Chat; exports.Checkbox = _chunkYJNQLH2Lcjs.Checkbox; exports.Chip = _chunkTTLFY76Jcjs.Chip; exports.ColorPicker = _chunkKBQD4JLKcjs.ColorPicker; exports.Combobox = _chunk4AO5RKV5cjs.Combobox; exports.CommandPalette = _chunk2T7ZMMH5cjs.CommandPalette; exports.CommentThread = _chunkX3BVQBXDcjs.CommentThread; exports.ContextMenu = _chunkHNGFRRVZcjs.ContextMenu; exports.DataGrid = _chunk66UQTF57cjs.DataGrid; exports.DatePicker = _chunk6JHVXWDVcjs.DatePicker; exports.Divider = _chunk366R4GKRcjs.Divider; exports.Drawer = _chunkDU5JKTHKcjs.Drawer; exports.Dropdown = _chunkKIZVY57Hcjs.Dropdown; exports.DropdownProvider = _chunkKIZVY57Hcjs.DropdownProvider; exports.EmptyState = _chunkKV3V2CPHcjs.EmptyState; exports.FONT_ACCEPT = _chunkRJVHR45Icjs.FONT_ACCEPT; exports.FileUpload = _chunkXRVRGRC3cjs.FileUpload; exports.Footer = _chunkPTBBY4ZXcjs.Footer; exports.Header = _chunk3KBBJZHKcjs.Header; exports.IconButton = _chunkDA375AI6cjs.IconButton; exports.IdentityHeader = _chunk3KBBJZHKcjs.IdentityHeader; exports.InlineEdit = _chunkI6M6CVI2cjs.InlineEdit; exports.Input = _chunk7VJCGKVPcjs.Input; exports.Kbd = _chunkKVIL4EP4cjs.Kbd; exports.Menu = _chunkJ76JHN7Jcjs.Menu; exports.MenuPanel = _chunkJ76JHN7Jcjs.MenuPanel; exports.MessageComposer = _chunkX3BVQBXDcjs.MessageComposer; exports.Modal = _chunk4JSTBA4Fcjs.Modal; exports.Navigation = _chunkV4BZWBZTcjs.Navigation; exports.NumberInput = _chunkTC5IC6OPcjs.NumberInput; exports.OTPInput = _chunkVHO6JPRRcjs.OTPInput; exports.PageLayout =
|
|
304
|
+
exports.Accordion = _chunkEAJGSXEWcjs.Accordion; exports.AccordionItem = _chunkEAJGSXEWcjs.AccordionItem; exports.Alert = _chunk3RWZC6OWcjs.Alert; exports.Avatar = _chunkQ3GNKF74cjs.Avatar; exports.AvatarGroup = _chunkQ3GNKF74cjs.AvatarGroup; exports.Badge = _chunk3ETWFS2Ncjs.Badge; exports.Breadcrumb = _chunk5O73AALPcjs.Breadcrumb; exports.Button = _chunkDA375AI6cjs.Button; exports.ButtonGroup = _chunk2ROKOO22cjs.ButtonGroup; exports.Calendar = _chunk6JHVXWDVcjs.Calendar; exports.Card = _chunkV5RS3JZNcjs.Card; exports.Chat = _chunkX3BVQBXDcjs.Chat; exports.Checkbox = _chunkYJNQLH2Lcjs.Checkbox; exports.Chip = _chunkTTLFY76Jcjs.Chip; exports.ColorPicker = _chunkKBQD4JLKcjs.ColorPicker; exports.Combobox = _chunk4AO5RKV5cjs.Combobox; exports.CommandPalette = _chunk2T7ZMMH5cjs.CommandPalette; exports.CommentThread = _chunkX3BVQBXDcjs.CommentThread; exports.ContextMenu = _chunkHNGFRRVZcjs.ContextMenu; exports.DataGrid = _chunk66UQTF57cjs.DataGrid; exports.DatePicker = _chunk6JHVXWDVcjs.DatePicker; exports.Divider = _chunk366R4GKRcjs.Divider; exports.Drawer = _chunkDU5JKTHKcjs.Drawer; exports.Dropdown = _chunkKIZVY57Hcjs.Dropdown; exports.DropdownProvider = _chunkKIZVY57Hcjs.DropdownProvider; exports.EmptyState = _chunkKV3V2CPHcjs.EmptyState; exports.FONT_ACCEPT = _chunkRJVHR45Icjs.FONT_ACCEPT; exports.FileUpload = _chunkXRVRGRC3cjs.FileUpload; exports.Footer = _chunkPTBBY4ZXcjs.Footer; exports.Header = _chunk3KBBJZHKcjs.Header; exports.IconButton = _chunkDA375AI6cjs.IconButton; exports.IdentityHeader = _chunk3KBBJZHKcjs.IdentityHeader; exports.InlineEdit = _chunkI6M6CVI2cjs.InlineEdit; exports.Input = _chunk7VJCGKVPcjs.Input; exports.Kbd = _chunkKVIL4EP4cjs.Kbd; exports.Menu = _chunkJ76JHN7Jcjs.Menu; exports.MenuPanel = _chunkJ76JHN7Jcjs.MenuPanel; exports.MessageComposer = _chunkX3BVQBXDcjs.MessageComposer; exports.Modal = _chunk4JSTBA4Fcjs.Modal; exports.Navigation = _chunkV4BZWBZTcjs.Navigation; exports.NumberInput = _chunkTC5IC6OPcjs.NumberInput; exports.OTPInput = _chunkVHO6JPRRcjs.OTPInput; exports.PageLayout = _chunkHEXAY6DEcjs.PageLayout; exports.Pagination = _chunkKREHT4AQcjs.Pagination; exports.Pill = _chunkEQ6BNPTLcjs.Pill; exports.Popover = _chunkVQGLVBPLcjs.Popover; exports.Progress = _chunkV2S6XWIQcjs.Progress; exports.Radio = _chunkKPMIIGHHcjs.Radio; exports.RadioGroup = _chunkKPMIIGHHcjs.RadioGroup; exports.SegmentedControl = _chunkJPYJQ4TFcjs.SegmentedControl; exports.Select = _chunkXZLSHEHEcjs.Select; exports.Skeleton = _chunkIGFR5TEScjs.Skeleton; exports.Slider = _chunkOZZHOEN5cjs.Slider; exports.SnackbarContainer = _chunkXERBOFYZcjs.SnackbarContainer; exports.SnackbarProvider = _chunkXERBOFYZcjs.SnackbarProvider; exports.Spinner = _chunkTROYIUDHcjs.Spinner; exports.SplitButton = _chunkLQXFXXMJcjs.SplitButton; exports.Stepper = _chunkHFZ5FKRGcjs.Stepper; exports.Switch = _chunkIXZMKIV5cjs.Switch; exports.Tab = _chunkNOQF7UQ5cjs.Tab; exports.TabPanel = _chunkNOQF7UQ5cjs.TabPanel; exports.Table = _chunk3ZRFOKDMcjs.Table; exports.TableFiltersDropdown = _chunkPMSENLOAcjs.TableFiltersDropdown; exports.Tabs = _chunkNOQF7UQ5cjs.Tabs; exports.TagInput = _chunkZMRINZIOcjs.TagInput; exports.Textarea = _chunk7BFODYNLcjs.Textarea; exports.ThemeEditor = _chunk36JFXFM2cjs.ThemeEditor; exports.ThemeProvider = _chunkRJVHR45Icjs.ThemeProvider; exports.TimeInput = _chunk6JHVXWDVcjs.TimeInput; exports.Timeline = _chunkZMDZGL5Acjs.Timeline; exports.Toolbar = _chunkJCKGAAPZcjs.Toolbar; exports.Tooltip = _chunkBEOECPVJcjs.Tooltip; exports.TreeView = _chunkXKQMEVODcjs.TreeView; exports.VirtualList = _chunkRUDXHT76cjs.VirtualList; exports.defaultTheme = _chunkRJVHR45Icjs.defaultTheme; exports.familyNameFromFile = _chunkRJVHR45Icjs.familyNameFromFile; exports.isFontAvailable = _chunkRJVHR45Icjs.isFontAvailable; exports.isFontStackAvailable = _chunkRJVHR45Icjs.isFontStackAvailable; exports.registerFontFace = _chunkRJVHR45Icjs.registerFontFace; exports.registerFontFile = _chunkRJVHR45Icjs.registerFontFile; exports.renderIcon = _chunk35LGEPLPcjs.renderIcon; exports.toFontStack = _chunkRJVHR45Icjs.toFontStack; exports.useDropdownContext = _chunkKIZVY57Hcjs.useDropdownContext; exports.useSnackbar = _chunkXERBOFYZcjs.useSnackbar; exports.useSnackbarContext = _chunkXERBOFYZcjs.useSnackbarContext; exports.useTheme = _chunkRJVHR45Icjs.useTheme;
|
|
305
305
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.css
CHANGED
|
@@ -2903,9 +2903,11 @@ kbd.eidos-cmd-kbd {
|
|
|
2903
2903
|
border: 1px solid var(--gray-200);
|
|
2904
2904
|
border-radius: var(--border-radius-md);
|
|
2905
2905
|
background: var(--white);
|
|
2906
|
+
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
2906
2907
|
}
|
|
2907
2908
|
.eidos-message-composer:focus-within {
|
|
2908
2909
|
border-color: var(--primary-color);
|
|
2910
|
+
box-shadow: 0 0 0 2px var(--white), 0 0 0 4px var(--primary-color);
|
|
2909
2911
|
}
|
|
2910
2912
|
|
|
2911
2913
|
.eidos-composer-reply-hint {
|
|
@@ -2957,12 +2959,6 @@ kbd.eidos-cmd-kbd {
|
|
|
2957
2959
|
.eidos-composer-input {
|
|
2958
2960
|
width: 100%;
|
|
2959
2961
|
resize: none;
|
|
2960
|
-
}
|
|
2961
|
-
.eidos-composer-input:focus-visible {
|
|
2962
|
-
box-shadow: inset 0 0 0 2px var(--primary-color);
|
|
2963
|
-
border-radius: var(--border-radius-sm);
|
|
2964
|
-
}
|
|
2965
|
-
.eidos-composer-input {
|
|
2966
2962
|
font-size: var(--font-size-sm);
|
|
2967
2963
|
color: var(--dark-color);
|
|
2968
2964
|
line-height: 1.55;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkHEXAY6DEcjs = require('../chunk-HEXAY6DE.cjs');
|
|
4
4
|
require('../chunk-JCKGAAPZ.cjs');
|
|
5
5
|
require('../chunk-3KBBJZHK.cjs');
|
|
6
6
|
require('../chunk-VQGLVBPL.cjs');
|
|
@@ -21,5 +21,5 @@ require('../chunk-35LGEPLP.cjs');
|
|
|
21
21
|
require('../chunk-DZUJEN5N.cjs');
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
exports.PageLayout =
|
|
24
|
+
exports.PageLayout = _chunkHEXAY6DEcjs.PageLayout;
|
|
25
25
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -44,7 +44,7 @@ interface PageLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
44
44
|
*
|
|
45
45
|
* Omit it to leave the scroll position alone entirely.
|
|
46
46
|
*/
|
|
47
|
-
scrollRestorationKey?: string;
|
|
47
|
+
scrollRestorationKey?: string | number;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
declare const PageLayout: React__default.FC<PageLayoutProps>;
|
|
@@ -44,7 +44,7 @@ interface PageLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
44
44
|
*
|
|
45
45
|
* Omit it to leave the scroll position alone entirely.
|
|
46
46
|
*/
|
|
47
|
-
scrollRestorationKey?: string;
|
|
47
|
+
scrollRestorationKey?: string | number;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
declare const PageLayout: React__default.FC<PageLayoutProps>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eidos-ui",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.2",
|
|
4
4
|
"description": "A modern React component library with TypeScript and SCSS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"postversion": "git push --follow-tags",
|
|
59
59
|
"release:needed": "node scripts/release-needed.js",
|
|
60
60
|
"check:docs": "node scripts/check-docs.js",
|
|
61
|
+
"check:story-docs": "node scripts/check-story-docs.js",
|
|
61
62
|
"release:preflight": "node scripts/preflight-release.js && npm run lint && npm run typecheck && npm run prettier:check && npm run build"
|
|
62
63
|
},
|
|
63
64
|
"keywords": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/PageLayout/useScrollRestoration.ts","../src/components/PageLayout/PageLayout.component.tsx"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';\n\n/**\n * Remembers the content region's scroll offset per key, and applies the\n * stored offset whenever the key changes.\n *\n * The key is supplied by the consumer rather than derived here, because only\n * they know what counts as a navigation - this library has no router opinion.\n * That also decides the semantics, exactly as React Router's `getKey` does:\n * a per-path key gives \"this path always reopens where you left it\", while a\n * per-history-entry key gives the browser's own behaviour, where Back\n * restores but a fresh link to the same URL starts at the top.\n *\n * Returns a ref callback for the scroll container, which also forwards the\n * node to the caller's own `contentRef`.\n */\nexport const useScrollRestoration = (\n key: string | undefined,\n forwardTo: React.Ref<HTMLElement> | undefined,\n): ((node: HTMLElement | null) => void) => {\n const node = useRef<HTMLElement | null>(null);\n const offsets = useRef(new Map<string, number>());\n const appliedKey = useRef(key);\n\n // Held in a ref so the ref callback below can keep a stable identity. A\n // callback ref that changes identity is invoked with `null` and then the\n // node again on every render that changes it, which would detach and\n // reattach the caller's ref for no reason.\n const forwarded = useRef(forwardTo);\n useEffect(() => {\n forwarded.current = forwardTo;\n }, [forwardTo]);\n\n const setNode = useCallback((element: HTMLElement | null) => {\n node.current = element;\n const ref = forwarded.current;\n if (typeof ref === 'function') ref(element);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = element;\n }, []);\n\n // Recorded as it happens rather than when the key changes: by the time a\n // navigation commits, the new page's content is already in the DOM and the\n // browser has clamped `scrollTop` to the new, possibly shorter, height. The\n // outgoing offset is no longer readable at that point.\n useEffect(() => {\n const element = node.current;\n if (!element || key === undefined) return;\n\n const record = () => offsets.current.set(key, element.scrollTop);\n element.addEventListener('scroll', record, { passive: true });\n return () => element.removeEventListener('scroll', record);\n }, [key]);\n\n // Layout effect so the offset is applied before paint - in a passive effect\n // the new page is visible at the previous page's offset for a frame first.\n // It does not run on the server, which is correct here: there is no scroll\n // position to restore in static markup, and the client applies it on mount.\n useLayoutEffect(() => {\n const element = node.current;\n if (!element || key === undefined || appliedKey.current === key) return;\n\n appliedKey.current = key;\n element.scrollTop = offsets.current.get(key) ?? 0;\n }, [key]);\n\n return setNode;\n};\n","import React from 'react';\nimport type { PageLayoutProps } from './PageLayout.types';\nimport './PageLayout.scss';\nimport { Toolbar } from '../Toolbar';\nimport { Header } from '../Header';\nimport { Footer } from '../Footer';\nimport type { FooterProps } from '../Footer';\nimport { Navigation } from '../Navigation';\nimport { useScrollRestoration } from './useScrollRestoration';\n\nconst defaultFooter: FooterProps = { copyright: `© ${new Date().getFullYear()} Eidos UI` };\n\nexport const PageLayout: React.FC<PageLayoutProps> = ({\n toolbar,\n navigation,\n header,\n footer,\n children,\n className = '',\n // Destructured so they cannot fall into `...rest` and land on the root\n // element, which is not the scroll container.\n contentRef,\n scrollRestorationKey,\n ...rest\n}) => {\n const classes = ['eidos-pagelayout', className].filter(Boolean).join(' ');\n const setContentRef = useScrollRestoration(scrollRestorationKey, contentRef);\n\n return (\n <div className={classes} {...rest}>\n {/* Spread rather than forwarded field by field, so a prop added to\n `Toolbar` reaches `PageLayout` consumers without a second edit\n here - the previous per-field list silently dropped anything it\n didn't know about. `className` is merged last so the layout's own\n grid-area class can't be overwritten by the caller's. */}\n <Toolbar\n {...toolbar}\n className={['eidos-pagelayout__toolbar', toolbar?.className].filter(Boolean).join(' ')}\n />\n <div className=\"eidos-pagelayout__navigation\">\n {navigation && <Navigation {...navigation} />}\n </div>\n {/* A scrollable region containing nothing focusable cannot be scrolled\n by keyboard at all, and a page body is often pure content - a\n report, an article. `tabIndex={0}` makes the region itself focusable\n so arrow keys and Page Up/Down reach it (SC 2.1.1), matching\n `VirtualList` and `Chat`. */}\n <main ref={setContentRef} tabIndex={0} className=\"eidos-pagelayout__content\">\n {header && (\n <Header\n {...header}\n className={['eidos-pagelayout__header', header.className].filter(Boolean).join(' ')}\n />\n )}\n <div className=\"eidos-pagelayout__body\">{children}</div>\n <Footer\n {...(footer ?? defaultFooter)}\n className={['eidos-pagelayout__footer', footer?.className].filter(Boolean).join(' ')}\n />\n </main>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,aAAa,WAAW,iBAAiB,cAAc;AAgBzD,IAAM,uBAAuB,CAClC,KACA,cACyC;AACzC,QAAM,OAAO,OAA2B,IAAI;AAC5C,QAAM,UAAU,OAAO,oBAAI,IAAoB,CAAC;AAChD,QAAM,aAAa,OAAO,GAAG;AAM7B,QAAM,YAAY,OAAO,SAAS;AAClC,YAAU,MAAM;AACd,cAAU,UAAU;AAAA,EACtB,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,UAAU,YAAY,CAAC,YAAgC;AAC3D,SAAK,UAAU;AACf,UAAM,MAAM,UAAU;AACtB,QAAI,OAAO,QAAQ,WAAY,KAAI,OAAO;AAAA,aACjC,IAAK,CAAC,IAA4C,UAAU;AAAA,EACvE,GAAG,CAAC,CAAC;AAML,YAAU,MAAM;AACd,UAAM,UAAU,KAAK;AACrB,QAAI,CAAC,WAAW,QAAQ,OAAW;AAEnC,UAAM,SAAS,MAAM,QAAQ,QAAQ,IAAI,KAAK,QAAQ,SAAS;AAC/D,YAAQ,iBAAiB,UAAU,QAAQ,EAAE,SAAS,KAAK,CAAC;AAC5D,WAAO,MAAM,QAAQ,oBAAoB,UAAU,MAAM;AAAA,EAC3D,GAAG,CAAC,GAAG,CAAC;AAMR,kBAAgB,MAAM;AACpB,UAAM,UAAU,KAAK;AACrB,QAAI,CAAC,WAAW,QAAQ,UAAa,WAAW,YAAY,IAAK;AAEjE,eAAW,UAAU;AACrB,YAAQ,YAAY,QAAQ,QAAQ,IAAI,GAAG,KAAK;AAAA,EAClD,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AACT;;;AC/BM,cAYA,YAZA;AAzBN,IAAM,gBAA6B,EAAE,WAAW,SAAK,oBAAI,KAAK,GAAE,YAAY,CAAC,YAAY;AAElF,IAAM,aAAwC,CAAC;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA;AAAA;AAAA,EAGZ;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,QAAM,UAAU,CAAC,oBAAoB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AACxE,QAAM,gBAAgB,qBAAqB,sBAAsB,UAAU;AAE3E,SACE,qBAAC,SAAI,WAAW,SAAU,GAAG,MAM3B;AAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,WAAW,CAAC,6BAA6B,SAAS,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA;AAAA,IACvF;AAAA,IACA,oBAAC,SAAI,WAAU,gCACZ,wBAAc,oBAAC,cAAY,GAAG,YAAY,GAC7C;AAAA,IAMA,qBAAC,UAAK,KAAK,eAAe,UAAU,GAAG,WAAU,6BAC9C;AAAA,gBACC;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ,WAAW,CAAC,4BAA4B,OAAO,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA;AAAA,MACpF;AAAA,MAEF,oBAAC,SAAI,WAAU,0BAA0B,UAAS;AAAA,MAClD;AAAA,QAAC;AAAA;AAAA,UACE,GAAI,UAAU;AAAA,UACf,WAAW,CAAC,4BAA4B,QAAQ,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA;AAAA,MACrF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-TNBML2MJ.cjs","../src/components/PageLayout/useScrollRestoration.ts","../src/components/PageLayout/PageLayout.component.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-TNBML2MJ.cjs","sourcesContent":[null,"import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';\n\n/**\n * Remembers the content region's scroll offset per key, and applies the\n * stored offset whenever the key changes.\n *\n * The key is supplied by the consumer rather than derived here, because only\n * they know what counts as a navigation - this library has no router opinion.\n * That also decides the semantics, exactly as React Router's `getKey` does:\n * a per-path key gives \"this path always reopens where you left it\", while a\n * per-history-entry key gives the browser's own behaviour, where Back\n * restores but a fresh link to the same URL starts at the top.\n *\n * Returns a ref callback for the scroll container, which also forwards the\n * node to the caller's own `contentRef`.\n */\nexport const useScrollRestoration = (\n key: string | undefined,\n forwardTo: React.Ref<HTMLElement> | undefined,\n): ((node: HTMLElement | null) => void) => {\n const node = useRef<HTMLElement | null>(null);\n const offsets = useRef(new Map<string, number>());\n const appliedKey = useRef(key);\n\n // Held in a ref so the ref callback below can keep a stable identity. A\n // callback ref that changes identity is invoked with `null` and then the\n // node again on every render that changes it, which would detach and\n // reattach the caller's ref for no reason.\n const forwarded = useRef(forwardTo);\n useEffect(() => {\n forwarded.current = forwardTo;\n }, [forwardTo]);\n\n const setNode = useCallback((element: HTMLElement | null) => {\n node.current = element;\n const ref = forwarded.current;\n if (typeof ref === 'function') ref(element);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = element;\n }, []);\n\n // Recorded as it happens rather than when the key changes: by the time a\n // navigation commits, the new page's content is already in the DOM and the\n // browser has clamped `scrollTop` to the new, possibly shorter, height. The\n // outgoing offset is no longer readable at that point.\n useEffect(() => {\n const element = node.current;\n if (!element || key === undefined) return;\n\n const record = () => offsets.current.set(key, element.scrollTop);\n element.addEventListener('scroll', record, { passive: true });\n return () => element.removeEventListener('scroll', record);\n }, [key]);\n\n // Layout effect so the offset is applied before paint - in a passive effect\n // the new page is visible at the previous page's offset for a frame first.\n // It does not run on the server, which is correct here: there is no scroll\n // position to restore in static markup, and the client applies it on mount.\n useLayoutEffect(() => {\n const element = node.current;\n if (!element || key === undefined || appliedKey.current === key) return;\n\n appliedKey.current = key;\n element.scrollTop = offsets.current.get(key) ?? 0;\n }, [key]);\n\n return setNode;\n};\n","import React from 'react';\nimport type { PageLayoutProps } from './PageLayout.types';\nimport './PageLayout.scss';\nimport { Toolbar } from '../Toolbar';\nimport { Header } from '../Header';\nimport { Footer } from '../Footer';\nimport type { FooterProps } from '../Footer';\nimport { Navigation } from '../Navigation';\nimport { useScrollRestoration } from './useScrollRestoration';\n\nconst defaultFooter: FooterProps = { copyright: `© ${new Date().getFullYear()} Eidos UI` };\n\nexport const PageLayout: React.FC<PageLayoutProps> = ({\n toolbar,\n navigation,\n header,\n footer,\n children,\n className = '',\n // Destructured so they cannot fall into `...rest` and land on the root\n // element, which is not the scroll container.\n contentRef,\n scrollRestorationKey,\n ...rest\n}) => {\n const classes = ['eidos-pagelayout', className].filter(Boolean).join(' ');\n const setContentRef = useScrollRestoration(scrollRestorationKey, contentRef);\n\n return (\n <div className={classes} {...rest}>\n {/* Spread rather than forwarded field by field, so a prop added to\n `Toolbar` reaches `PageLayout` consumers without a second edit\n here - the previous per-field list silently dropped anything it\n didn't know about. `className` is merged last so the layout's own\n grid-area class can't be overwritten by the caller's. */}\n <Toolbar\n {...toolbar}\n className={['eidos-pagelayout__toolbar', toolbar?.className].filter(Boolean).join(' ')}\n />\n <div className=\"eidos-pagelayout__navigation\">\n {navigation && <Navigation {...navigation} />}\n </div>\n {/* A scrollable region containing nothing focusable cannot be scrolled\n by keyboard at all, and a page body is often pure content - a\n report, an article. `tabIndex={0}` makes the region itself focusable\n so arrow keys and Page Up/Down reach it (SC 2.1.1), matching\n `VirtualList` and `Chat`. */}\n <main ref={setContentRef} tabIndex={0} className=\"eidos-pagelayout__content\">\n {header && (\n <Header\n {...header}\n className={['eidos-pagelayout__header', header.className].filter(Boolean).join(' ')}\n />\n )}\n <div className=\"eidos-pagelayout__body\">{children}</div>\n <Footer\n {...(footer ?? defaultFooter)}\n className={['eidos-pagelayout__footer', footer?.className].filter(Boolean).join(' ')}\n />\n </main>\n </div>\n );\n};\n"]}
|