@gnome-ui/react 1.45.2 → 1.46.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 (31) hide show
  1. package/dist/components/AboutDialog/AboutDialog.cjs +1 -1
  2. package/dist/components/AboutDialog/AboutDialog.cjs.map +1 -1
  3. package/dist/components/AboutDialog/AboutDialog.js +105 -106
  4. package/dist/components/AboutDialog/AboutDialog.js.map +1 -1
  5. package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
  6. package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
  7. package/dist/components/BottomSheet/BottomSheet.js +36 -36
  8. package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
  9. package/dist/components/Dialog/Dialog.cjs +1 -1
  10. package/dist/components/Dialog/Dialog.cjs.map +1 -1
  11. package/dist/components/Dialog/Dialog.js +50 -51
  12. package/dist/components/Dialog/Dialog.js.map +1 -1
  13. package/dist/components/Dialog/dialogUtils.cjs +1 -1
  14. package/dist/components/Dialog/dialogUtils.cjs.map +1 -1
  15. package/dist/components/Dialog/dialogUtils.d.ts +6 -0
  16. package/dist/components/Dialog/dialogUtils.js +11 -2
  17. package/dist/components/Dialog/dialogUtils.js.map +1 -1
  18. package/dist/components/Dropdown/Dropdown.cjs +1 -1
  19. package/dist/components/Dropdown/Dropdown.cjs.map +1 -1
  20. package/dist/components/Dropdown/Dropdown.js +88 -84
  21. package/dist/components/Dropdown/Dropdown.js.map +1 -1
  22. package/dist/components/PasswordEntryRow/PasswordEntryRow.cjs +1 -1
  23. package/dist/components/PasswordEntryRow/PasswordEntryRow.cjs.map +1 -1
  24. package/dist/components/PasswordEntryRow/PasswordEntryRow.d.ts +1 -1
  25. package/dist/components/PasswordEntryRow/PasswordEntryRow.js +10 -9
  26. package/dist/components/PasswordEntryRow/PasswordEntryRow.js.map +1 -1
  27. package/dist/components/ShortcutsDialog/ShortcutsDialog.cjs +1 -1
  28. package/dist/components/ShortcutsDialog/ShortcutsDialog.cjs.map +1 -1
  29. package/dist/components/ShortcutsDialog/ShortcutsDialog.js +74 -74
  30. package/dist/components/ShortcutsDialog/ShortcutsDialog.js.map +1 -1
  31. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- const e=require("../Dialog/dialogUtils.cjs"),t=require("./AboutDialog.module.css.cjs");let n=require("react"),r=require("react-dom"),i=require("react/jsx-runtime");var a={details:`Details`,credits:`Credits`,legal:`Legal`},o=({open:o,onClose:s,applicationName:c,applicationIcon:l,version:u,comments:d,developerName:f,website:p,websiteLabel:m,developers:h,designers:g,artists:_,copyright:v,licenseType:y,licenseText:b,links:x})=>{let S=(0,n.useRef)(null),C=(0,n.useId)(),w=(0,n.useRef)(null),T=e.useVisualViewport(),[E,D]=(0,n.useState)(`details`);(0,n.useEffect)(()=>{o?(w.current=document.activeElement,(S.current?.querySelector(e.FOCUSABLE))?.focus()):(w.current?.focus(),D(`details`))},[o]);let O=(0,n.useCallback)(t=>{if(t.key===`Escape`){t.preventDefault(),s?.();return}e.trapFocus(t,S)},[s]);if(!o)return null;let k=[`details`,!!(h?.length||g?.length||_?.length)&&`credits`,!!(v||y||b)&&`legal`].filter(Boolean),A=(0,i.jsx)(`div`,{className:t.default.backdrop,style:T,onClick:s,"aria-hidden":`true`,children:(0,i.jsxs)(`div`,{ref:S,role:`dialog`,"aria-modal":`true`,"aria-labelledby":C,className:t.default.dialog,onKeyDown:O,onClick:e=>e.stopPropagation(),children:[(0,i.jsxs)(`div`,{className:t.default.header,children:[l&&(0,i.jsx)(`div`,{className:t.default.icon,children:l}),(0,i.jsx)(`div`,{id:C,className:t.default.appName,children:c}),u&&(0,i.jsx)(`div`,{className:t.default.version,children:u})]}),k.length>1&&(0,i.jsx)(`div`,{className:t.default.tabBar,role:`tablist`,children:k.map(e=>(0,i.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":E===e,className:[t.default.tabBtn,E===e?t.default.tabBtnActive:null].filter(Boolean).join(` `),onClick:()=>D(e),children:a[e]},e))}),(0,i.jsxs)(`div`,{className:t.default.tabContent,children:[E===`details`&&(0,i.jsxs)(`div`,{className:t.default.section,children:[d&&(0,i.jsx)(`p`,{className:t.default.comments,children:d}),(f||p||x?.length)&&(0,i.jsxs)(`dl`,{className:t.default.infoList,children:[f&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`dt`,{className:t.default.infoLabel,children:`Developer`}),(0,i.jsx)(`dd`,{className:t.default.infoValue,children:f})]}),p&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`dt`,{className:t.default.infoLabel,children:`Website`}),(0,i.jsx)(`dd`,{className:t.default.infoValue,children:(0,i.jsx)(`a`,{href:p,target:`_blank`,rel:`noopener noreferrer`,className:t.default.link,children:m??p})})]}),x?.map(e=>(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`dt`,{className:t.default.infoLabel,children:e.label},`${e.label}-dt`),(0,i.jsx)(`dd`,{className:t.default.infoValue,children:(0,i.jsx)(`a`,{href:e.url,target:`_blank`,rel:`noopener noreferrer`,className:t.default.link,children:e.url})},`${e.label}-dd`)]}))]})]}),E===`credits`&&(0,i.jsx)(`div`,{className:t.default.section,children:[{heading:`Developers`,list:h},{heading:`Designers`,list:g},{heading:`Artists`,list:_}].filter(e=>e.list?.length).map(({heading:e,list:n})=>(0,i.jsxs)(`div`,{className:t.default.creditGroup,children:[(0,i.jsx)(`h4`,{className:t.default.creditTitle,children:e}),(0,i.jsx)(`ul`,{className:t.default.creditList,children:n?.map(e=>(0,i.jsx)(`li`,{className:t.default.creditItem,children:e},e))})]},e))}),E===`legal`&&(0,i.jsxs)(`div`,{className:t.default.section,children:[v&&(0,i.jsx)(`p`,{className:t.default.copyright,children:v}),y&&(0,i.jsx)(`p`,{className:t.default.licenseType,children:y}),b&&(0,i.jsx)(`pre`,{className:t.default.licenseText,children:b})]})]}),(0,i.jsx)(`div`,{className:t.default.footer,children:(0,i.jsx)(`button`,{type:`button`,className:[t.default.btn,t.default.btnDefault].join(` `),onClick:s,children:`Close`})})]})});return typeof document>`u`?A:(0,r.createPortal)(A,document.body)};exports.AboutDialog=o;
1
+ const e=require("../Dialog/dialogUtils.cjs"),t=require("./AboutDialog.module.css.cjs");let n=require("react"),r=require("react-dom"),i=require("react/jsx-runtime");var a={details:`Details`,credits:`Credits`,legal:`Legal`},o=({open:o,onClose:s,applicationName:c,applicationIcon:l,version:u,comments:d,developerName:f,website:p,websiteLabel:m,developers:h,designers:g,artists:_,copyright:v,licenseType:y,licenseText:b,links:x})=>{let S=(0,n.useRef)(null),C=(0,n.useId)(),w=(0,n.useRef)(null),T=e.useVisualViewport(),[E,D]=(0,n.useState)(`details`);e.useBodyScrollLock(o),(0,n.useEffect)(()=>{o?(w.current=document.activeElement,(S.current?.querySelector(e.FOCUSABLE))?.focus()):(w.current?.focus(),D(`details`))},[o]);let O=(0,n.useCallback)(t=>{if(t.key===`Escape`){t.preventDefault(),s?.();return}e.trapFocus(t,S)},[s]);if(!o)return null;let k=[`details`,!!(h?.length||g?.length||_?.length)&&`credits`,!!(v||y||b)&&`legal`].filter(Boolean),A=(0,i.jsx)(`div`,{className:t.default.backdrop,style:T,onClick:s,children:(0,i.jsxs)(`div`,{ref:S,role:`dialog`,"aria-modal":`true`,"aria-labelledby":C,className:t.default.dialog,onKeyDown:O,onClick:e=>e.stopPropagation(),children:[(0,i.jsxs)(`div`,{className:t.default.header,children:[l&&(0,i.jsx)(`div`,{className:t.default.icon,children:l}),(0,i.jsx)(`div`,{id:C,className:t.default.appName,children:c}),u&&(0,i.jsx)(`div`,{className:t.default.version,children:u})]}),k.length>1&&(0,i.jsx)(`div`,{className:t.default.tabBar,role:`tablist`,children:k.map(e=>(0,i.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":E===e,className:[t.default.tabBtn,E===e?t.default.tabBtnActive:null].filter(Boolean).join(` `),onClick:()=>D(e),children:a[e]},e))}),(0,i.jsxs)(`div`,{className:t.default.tabContent,children:[E===`details`&&(0,i.jsxs)(`div`,{className:t.default.section,children:[d&&(0,i.jsx)(`p`,{className:t.default.comments,children:d}),(f||p||x?.length)&&(0,i.jsxs)(`dl`,{className:t.default.infoList,children:[f&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`dt`,{className:t.default.infoLabel,children:`Developer`}),(0,i.jsx)(`dd`,{className:t.default.infoValue,children:f})]}),p&&(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`dt`,{className:t.default.infoLabel,children:`Website`}),(0,i.jsx)(`dd`,{className:t.default.infoValue,children:(0,i.jsx)(`a`,{href:p,target:`_blank`,rel:`noopener noreferrer`,className:t.default.link,children:m??p})})]}),x?.map(e=>(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`dt`,{className:t.default.infoLabel,children:e.label},`${e.label}-dt`),(0,i.jsx)(`dd`,{className:t.default.infoValue,children:(0,i.jsx)(`a`,{href:e.url,target:`_blank`,rel:`noopener noreferrer`,className:t.default.link,children:e.url})},`${e.label}-dd`)]}))]})]}),E===`credits`&&(0,i.jsx)(`div`,{className:t.default.section,children:[{heading:`Developers`,list:h},{heading:`Designers`,list:g},{heading:`Artists`,list:_}].filter(e=>e.list?.length).map(({heading:e,list:n})=>(0,i.jsxs)(`div`,{className:t.default.creditGroup,children:[(0,i.jsx)(`h4`,{className:t.default.creditTitle,children:e}),(0,i.jsx)(`ul`,{className:t.default.creditList,children:n?.map(e=>(0,i.jsx)(`li`,{className:t.default.creditItem,children:e},e))})]},e))}),E===`legal`&&(0,i.jsxs)(`div`,{className:t.default.section,children:[v&&(0,i.jsx)(`p`,{className:t.default.copyright,children:v}),y&&(0,i.jsx)(`p`,{className:t.default.licenseType,children:y}),b&&(0,i.jsx)(`pre`,{className:t.default.licenseText,children:b})]})]}),(0,i.jsx)(`div`,{className:t.default.footer,children:(0,i.jsx)(`button`,{type:`button`,className:[t.default.btn,t.default.btnDefault].join(` `),onClick:s,children:`Close`})})]})});return typeof document>`u`?A:(0,r.createPortal)(A,document.body)};exports.AboutDialog=o;
2
2
  //# sourceMappingURL=AboutDialog.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"AboutDialog.cjs","names":[],"sources":["../../../src/components/AboutDialog/AboutDialog.tsx"],"sourcesContent":["import {\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { FOCUSABLE, trapFocus, useVisualViewport } from '../Dialog/dialogUtils';\n\nimport styles from './AboutDialog.module.css';\n\nexport interface AboutDialogLink {\n label: string;\n url: string;\n}\n\nexport interface AboutDialogProps {\n /** Whether the dialog is visible. */\n open: boolean;\n /** Called on Escape or close button click. */\n onClose?: () => void;\n /** Application name. */\n applicationName: string;\n /** Icon rendered above the app name. */\n applicationIcon?: ReactNode;\n /** Version string (e.g. `\"1.0.0\"`). */\n version?: string;\n /** One-sentence description. */\n comments?: string;\n /** Developer or organisation name. */\n developerName?: string;\n /** Application website URL. */\n website?: string;\n /** Label for the website link. Defaults to the URL. */\n websiteLabel?: string;\n /** Developer names shown in the Credits tab. */\n developers?: string[];\n /** Designer names shown in the Credits tab. */\n designers?: string[];\n /** Artist names shown in the Credits tab. */\n artists?: string[];\n /** Copyright notice (e.g. `\"© 2024 Jane Smith\"`). */\n copyright?: string;\n /** SPDX identifier or short name (e.g. `\"GPL-3.0\"`). */\n licenseType?: string;\n /** Full license text shown in the Legal tab. */\n licenseText?: string;\n /** Extra links shown in the Details section. */\n links?: AboutDialogLink[];\n}\n\ntype AboutTab = 'details' | 'credits' | 'legal';\nconst ABOUT_TAB_LABEL: Record<AboutTab, string> = {\n details: 'Details',\n credits: 'Credits',\n legal: 'Legal',\n};\n\n/**\n * Standard app info dialog with details, credits, and legal tabs.\n * Mirrors `AdwAboutDialog`.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.AboutDialog.html\n */\nexport const AboutDialog = ({\n open,\n onClose,\n applicationName,\n applicationIcon,\n version,\n comments,\n developerName,\n website,\n websiteLabel,\n developers,\n designers,\n artists,\n copyright,\n licenseType,\n licenseText,\n links,\n}: AboutDialogProps) => {\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n const viewportStyle = useVisualViewport();\n const [activeTab, setActiveTab] = useState<AboutTab>('details');\n\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = dialogRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n setActiveTab('details');\n }\n }, [open]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n trapFocus(e, dialogRef);\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const hasCredits = !!(developers?.length || designers?.length || artists?.length);\n const hasLegal = !!(copyright || licenseType || licenseText);\n const tabs = (\n ['details', hasCredits && 'credits', hasLegal && 'legal'] as (AboutTab | false)[]\n ).filter(Boolean) as AboutTab[];\n\n const node = (\n <div className={styles.backdrop} style={viewportStyle} onClick={onClose} aria-hidden=\"true\">\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n className={styles.dialog}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={styles.header}>\n {applicationIcon && <div className={styles.icon}>{applicationIcon}</div>}\n <div id={titleId} className={styles.appName}>\n {applicationName}\n </div>\n {version && <div className={styles.version}>{version}</div>}\n </div>\n\n {tabs.length > 1 && (\n <div className={styles.tabBar} role=\"tablist\">\n {tabs.map((t) => (\n <button\n key={t}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === t}\n className={[styles.tabBtn, activeTab === t ? styles.tabBtnActive : null]\n .filter(Boolean)\n .join(' ')}\n onClick={() => setActiveTab(t)}\n >\n {ABOUT_TAB_LABEL[t]}\n </button>\n ))}\n </div>\n )}\n\n <div className={styles.tabContent}>\n {activeTab === 'details' && (\n <div className={styles.section}>\n {comments && <p className={styles.comments}>{comments}</p>}\n {(developerName || website || links?.length) && (\n <dl className={styles.infoList}>\n {developerName && (\n <>\n <dt className={styles.infoLabel}>Developer</dt>\n <dd className={styles.infoValue}>{developerName}</dd>\n </>\n )}\n {website && (\n <>\n <dt className={styles.infoLabel}>Website</dt>\n <dd className={styles.infoValue}>\n <a\n href={website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {websiteLabel ?? website}\n </a>\n </dd>\n </>\n )}\n {links?.map((l) => (\n <>\n <dt key={`${l.label}-dt`} className={styles.infoLabel}>\n {l.label}\n </dt>\n <dd key={`${l.label}-dd`} className={styles.infoValue}>\n <a\n href={l.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {l.url}\n </a>\n </dd>\n </>\n ))}\n </dl>\n )}\n </div>\n )}\n\n {activeTab === 'credits' && (\n <div className={styles.section}>\n {[\n { heading: 'Developers', list: developers },\n { heading: 'Designers', list: designers },\n { heading: 'Artists', list: artists },\n ]\n .filter((g) => g.list?.length)\n .map(({ heading, list }) => (\n <div key={heading} className={styles.creditGroup}>\n <h4 className={styles.creditTitle}>{heading}</h4>\n <ul className={styles.creditList}>\n {list?.map((name) => (\n <li key={name} className={styles.creditItem}>\n {name}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n )}\n\n {activeTab === 'legal' && (\n <div className={styles.section}>\n {copyright && <p className={styles.copyright}>{copyright}</p>}\n {licenseType && <p className={styles.licenseType}>{licenseType}</p>}\n {licenseText && <pre className={styles.licenseText}>{licenseText}</pre>}\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button\n type=\"button\"\n className={[styles.btn, styles.btnDefault].join(' ')}\n onClick={onClose}\n >\n Close\n </button>\n </div>\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AboutDialog.cjs","names":[],"sources":["../../../src/components/AboutDialog/AboutDialog.tsx"],"sourcesContent":["import {\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { FOCUSABLE, trapFocus, useBodyScrollLock, useVisualViewport } from '../Dialog/dialogUtils';\n\nimport styles from './AboutDialog.module.css';\n\nexport interface AboutDialogLink {\n label: string;\n url: string;\n}\n\nexport interface AboutDialogProps {\n /** Whether the dialog is visible. */\n open: boolean;\n /** Called on Escape or close button click. */\n onClose?: () => void;\n /** Application name. */\n applicationName: string;\n /** Icon rendered above the app name. */\n applicationIcon?: ReactNode;\n /** Version string (e.g. `\"1.0.0\"`). */\n version?: string;\n /** One-sentence description. */\n comments?: string;\n /** Developer or organisation name. */\n developerName?: string;\n /** Application website URL. */\n website?: string;\n /** Label for the website link. Defaults to the URL. */\n websiteLabel?: string;\n /** Developer names shown in the Credits tab. */\n developers?: string[];\n /** Designer names shown in the Credits tab. */\n designers?: string[];\n /** Artist names shown in the Credits tab. */\n artists?: string[];\n /** Copyright notice (e.g. `\"© 2024 Jane Smith\"`). */\n copyright?: string;\n /** SPDX identifier or short name (e.g. `\"GPL-3.0\"`). */\n licenseType?: string;\n /** Full license text shown in the Legal tab. */\n licenseText?: string;\n /** Extra links shown in the Details section. */\n links?: AboutDialogLink[];\n}\n\ntype AboutTab = 'details' | 'credits' | 'legal';\nconst ABOUT_TAB_LABEL: Record<AboutTab, string> = {\n details: 'Details',\n credits: 'Credits',\n legal: 'Legal',\n};\n\n/**\n * Standard app info dialog with details, credits, and legal tabs.\n * Mirrors `AdwAboutDialog`.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.AboutDialog.html\n */\nexport const AboutDialog = ({\n open,\n onClose,\n applicationName,\n applicationIcon,\n version,\n comments,\n developerName,\n website,\n websiteLabel,\n developers,\n designers,\n artists,\n copyright,\n licenseType,\n licenseText,\n links,\n}: AboutDialogProps) => {\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n const viewportStyle = useVisualViewport();\n const [activeTab, setActiveTab] = useState<AboutTab>('details');\n\n useBodyScrollLock(open);\n\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = dialogRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n setActiveTab('details');\n }\n }, [open]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n trapFocus(e, dialogRef);\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const hasCredits = !!(developers?.length || designers?.length || artists?.length);\n const hasLegal = !!(copyright || licenseType || licenseText);\n const tabs = (\n ['details', hasCredits && 'credits', hasLegal && 'legal'] as (AboutTab | false)[]\n ).filter(Boolean) as AboutTab[];\n\n const node = (\n <div className={styles.backdrop} style={viewportStyle} onClick={onClose}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n className={styles.dialog}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={styles.header}>\n {applicationIcon && <div className={styles.icon}>{applicationIcon}</div>}\n <div id={titleId} className={styles.appName}>\n {applicationName}\n </div>\n {version && <div className={styles.version}>{version}</div>}\n </div>\n\n {tabs.length > 1 && (\n <div className={styles.tabBar} role=\"tablist\">\n {tabs.map((t) => (\n <button\n key={t}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === t}\n className={[styles.tabBtn, activeTab === t ? styles.tabBtnActive : null]\n .filter(Boolean)\n .join(' ')}\n onClick={() => setActiveTab(t)}\n >\n {ABOUT_TAB_LABEL[t]}\n </button>\n ))}\n </div>\n )}\n\n <div className={styles.tabContent}>\n {activeTab === 'details' && (\n <div className={styles.section}>\n {comments && <p className={styles.comments}>{comments}</p>}\n {(developerName || website || links?.length) && (\n <dl className={styles.infoList}>\n {developerName && (\n <>\n <dt className={styles.infoLabel}>Developer</dt>\n <dd className={styles.infoValue}>{developerName}</dd>\n </>\n )}\n {website && (\n <>\n <dt className={styles.infoLabel}>Website</dt>\n <dd className={styles.infoValue}>\n <a\n href={website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {websiteLabel ?? website}\n </a>\n </dd>\n </>\n )}\n {links?.map((l) => (\n <>\n <dt key={`${l.label}-dt`} className={styles.infoLabel}>\n {l.label}\n </dt>\n <dd key={`${l.label}-dd`} className={styles.infoValue}>\n <a\n href={l.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {l.url}\n </a>\n </dd>\n </>\n ))}\n </dl>\n )}\n </div>\n )}\n\n {activeTab === 'credits' && (\n <div className={styles.section}>\n {[\n { heading: 'Developers', list: developers },\n { heading: 'Designers', list: designers },\n { heading: 'Artists', list: artists },\n ]\n .filter((g) => g.list?.length)\n .map(({ heading, list }) => (\n <div key={heading} className={styles.creditGroup}>\n <h4 className={styles.creditTitle}>{heading}</h4>\n <ul className={styles.creditList}>\n {list?.map((name) => (\n <li key={name} className={styles.creditItem}>\n {name}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n )}\n\n {activeTab === 'legal' && (\n <div className={styles.section}>\n {copyright && <p className={styles.copyright}>{copyright}</p>}\n {licenseType && <p className={styles.licenseType}>{licenseType}</p>}\n {licenseText && <pre className={styles.licenseText}>{licenseText}</pre>}\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button\n type=\"button\"\n className={[styles.btn, styles.btnDefault].join(' ')}\n onClick={onClose}\n >\n Close\n </button>\n </div>\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"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"}
@@ -1,184 +1,183 @@
1
- import { FOCUSABLE as e, trapFocus as t, useVisualViewport as n } from "../Dialog/dialogUtils.js";
2
- import r from "./AboutDialog.module.css.js";
3
- import { useCallback as i, useEffect as a, useId as o, useRef as s, useState as c } from "react";
4
- import { createPortal as l } from "react-dom";
5
- import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
1
+ import { FOCUSABLE as e, trapFocus as t, useBodyScrollLock as n, useVisualViewport as r } from "../Dialog/dialogUtils.js";
2
+ import i from "./AboutDialog.module.css.js";
3
+ import { useCallback as a, useEffect as o, useId as s, useRef as c, useState as l } from "react";
4
+ import { createPortal as u } from "react-dom";
5
+ import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
6
6
  //#region src/components/AboutDialog/AboutDialog.tsx
7
- var p = {
7
+ var m = {
8
8
  details: "Details",
9
9
  credits: "Credits",
10
10
  legal: "Legal"
11
- }, m = ({ open: m, onClose: h, applicationName: g, applicationIcon: _, version: v, comments: y, developerName: b, website: x, websiteLabel: S, developers: C, designers: w, artists: T, copyright: E, licenseType: D, licenseText: O, links: k }) => {
12
- let A = s(null), j = o(), M = s(null), N = n(), [P, F] = c("details");
13
- a(() => {
14
- m ? (M.current = document.activeElement, (A.current?.querySelector(e))?.focus()) : (M.current?.focus(), F("details"));
15
- }, [m]);
16
- let I = i((e) => {
11
+ }, h = ({ open: h, onClose: g, applicationName: _, applicationIcon: v, version: y, comments: b, developerName: x, website: S, websiteLabel: C, developers: w, designers: T, artists: E, copyright: D, licenseType: O, licenseText: k, links: A }) => {
12
+ let j = c(null), M = s(), N = c(null), P = r(), [F, I] = l("details");
13
+ n(h), o(() => {
14
+ h ? (N.current = document.activeElement, (j.current?.querySelector(e))?.focus()) : (N.current?.focus(), I("details"));
15
+ }, [h]);
16
+ let L = a((e) => {
17
17
  if (e.key === "Escape") {
18
- e.preventDefault(), h?.();
18
+ e.preventDefault(), g?.();
19
19
  return;
20
20
  }
21
- t(e, A);
22
- }, [h]);
23
- if (!m) return null;
24
- let L = [
21
+ t(e, j);
22
+ }, [g]);
23
+ if (!h) return null;
24
+ let R = [
25
25
  "details",
26
- !!(C?.length || w?.length || T?.length) && "credits",
27
- !!(E || D || O) && "legal"
28
- ].filter(Boolean), R = /* @__PURE__ */ d("div", {
29
- className: r.backdrop,
30
- style: N,
31
- onClick: h,
32
- "aria-hidden": "true",
33
- children: /* @__PURE__ */ f("div", {
34
- ref: A,
26
+ !!(w?.length || T?.length || E?.length) && "credits",
27
+ !!(D || O || k) && "legal"
28
+ ].filter(Boolean), z = /* @__PURE__ */ f("div", {
29
+ className: i.backdrop,
30
+ style: P,
31
+ onClick: g,
32
+ children: /* @__PURE__ */ p("div", {
33
+ ref: j,
35
34
  role: "dialog",
36
35
  "aria-modal": "true",
37
- "aria-labelledby": j,
38
- className: r.dialog,
39
- onKeyDown: I,
36
+ "aria-labelledby": M,
37
+ className: i.dialog,
38
+ onKeyDown: L,
40
39
  onClick: (e) => e.stopPropagation(),
41
40
  children: [
42
- /* @__PURE__ */ f("div", {
43
- className: r.header,
41
+ /* @__PURE__ */ p("div", {
42
+ className: i.header,
44
43
  children: [
45
- _ && /* @__PURE__ */ d("div", {
46
- className: r.icon,
47
- children: _
44
+ v && /* @__PURE__ */ f("div", {
45
+ className: i.icon,
46
+ children: v
48
47
  }),
49
- /* @__PURE__ */ d("div", {
50
- id: j,
51
- className: r.appName,
52
- children: g
48
+ /* @__PURE__ */ f("div", {
49
+ id: M,
50
+ className: i.appName,
51
+ children: _
53
52
  }),
54
- v && /* @__PURE__ */ d("div", {
55
- className: r.version,
56
- children: v
53
+ y && /* @__PURE__ */ f("div", {
54
+ className: i.version,
55
+ children: y
57
56
  })
58
57
  ]
59
58
  }),
60
- L.length > 1 && /* @__PURE__ */ d("div", {
61
- className: r.tabBar,
59
+ R.length > 1 && /* @__PURE__ */ f("div", {
60
+ className: i.tabBar,
62
61
  role: "tablist",
63
- children: L.map((e) => /* @__PURE__ */ d("button", {
62
+ children: R.map((e) => /* @__PURE__ */ f("button", {
64
63
  type: "button",
65
64
  role: "tab",
66
- "aria-selected": P === e,
67
- className: [r.tabBtn, P === e ? r.tabBtnActive : null].filter(Boolean).join(" "),
68
- onClick: () => F(e),
69
- children: p[e]
65
+ "aria-selected": F === e,
66
+ className: [i.tabBtn, F === e ? i.tabBtnActive : null].filter(Boolean).join(" "),
67
+ onClick: () => I(e),
68
+ children: m[e]
70
69
  }, e))
71
70
  }),
72
- /* @__PURE__ */ f("div", {
73
- className: r.tabContent,
71
+ /* @__PURE__ */ p("div", {
72
+ className: i.tabContent,
74
73
  children: [
75
- P === "details" && /* @__PURE__ */ f("div", {
76
- className: r.section,
77
- children: [y && /* @__PURE__ */ d("p", {
78
- className: r.comments,
79
- children: y
80
- }), (b || x || k?.length) && /* @__PURE__ */ f("dl", {
81
- className: r.infoList,
74
+ F === "details" && /* @__PURE__ */ p("div", {
75
+ className: i.section,
76
+ children: [b && /* @__PURE__ */ f("p", {
77
+ className: i.comments,
78
+ children: b
79
+ }), (x || S || A?.length) && /* @__PURE__ */ p("dl", {
80
+ className: i.infoList,
82
81
  children: [
83
- b && /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("dt", {
84
- className: r.infoLabel,
82
+ x && /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("dt", {
83
+ className: i.infoLabel,
85
84
  children: "Developer"
86
- }), /* @__PURE__ */ d("dd", {
87
- className: r.infoValue,
88
- children: b
85
+ }), /* @__PURE__ */ f("dd", {
86
+ className: i.infoValue,
87
+ children: x
89
88
  })] }),
90
- x && /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("dt", {
91
- className: r.infoLabel,
89
+ S && /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("dt", {
90
+ className: i.infoLabel,
92
91
  children: "Website"
93
- }), /* @__PURE__ */ d("dd", {
94
- className: r.infoValue,
95
- children: /* @__PURE__ */ d("a", {
96
- href: x,
92
+ }), /* @__PURE__ */ f("dd", {
93
+ className: i.infoValue,
94
+ children: /* @__PURE__ */ f("a", {
95
+ href: S,
97
96
  target: "_blank",
98
97
  rel: "noopener noreferrer",
99
- className: r.link,
100
- children: S ?? x
98
+ className: i.link,
99
+ children: C ?? S
101
100
  })
102
101
  })] }),
103
- k?.map((e) => /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("dt", {
104
- className: r.infoLabel,
102
+ A?.map((e) => /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f("dt", {
103
+ className: i.infoLabel,
105
104
  children: e.label
106
- }, `${e.label}-dt`), /* @__PURE__ */ d("dd", {
107
- className: r.infoValue,
108
- children: /* @__PURE__ */ d("a", {
105
+ }, `${e.label}-dt`), /* @__PURE__ */ f("dd", {
106
+ className: i.infoValue,
107
+ children: /* @__PURE__ */ f("a", {
109
108
  href: e.url,
110
109
  target: "_blank",
111
110
  rel: "noopener noreferrer",
112
- className: r.link,
111
+ className: i.link,
113
112
  children: e.url
114
113
  })
115
114
  }, `${e.label}-dd`)] }))
116
115
  ]
117
116
  })]
118
117
  }),
119
- P === "credits" && /* @__PURE__ */ d("div", {
120
- className: r.section,
118
+ F === "credits" && /* @__PURE__ */ f("div", {
119
+ className: i.section,
121
120
  children: [
122
121
  {
123
122
  heading: "Developers",
124
- list: C
123
+ list: w
125
124
  },
126
125
  {
127
126
  heading: "Designers",
128
- list: w
127
+ list: T
129
128
  },
130
129
  {
131
130
  heading: "Artists",
132
- list: T
131
+ list: E
133
132
  }
134
- ].filter((e) => e.list?.length).map(({ heading: e, list: t }) => /* @__PURE__ */ f("div", {
135
- className: r.creditGroup,
136
- children: [/* @__PURE__ */ d("h4", {
137
- className: r.creditTitle,
133
+ ].filter((e) => e.list?.length).map(({ heading: e, list: t }) => /* @__PURE__ */ p("div", {
134
+ className: i.creditGroup,
135
+ children: [/* @__PURE__ */ f("h4", {
136
+ className: i.creditTitle,
138
137
  children: e
139
- }), /* @__PURE__ */ d("ul", {
140
- className: r.creditList,
141
- children: t?.map((e) => /* @__PURE__ */ d("li", {
142
- className: r.creditItem,
138
+ }), /* @__PURE__ */ f("ul", {
139
+ className: i.creditList,
140
+ children: t?.map((e) => /* @__PURE__ */ f("li", {
141
+ className: i.creditItem,
143
142
  children: e
144
143
  }, e))
145
144
  })]
146
145
  }, e))
147
146
  }),
148
- P === "legal" && /* @__PURE__ */ f("div", {
149
- className: r.section,
147
+ F === "legal" && /* @__PURE__ */ p("div", {
148
+ className: i.section,
150
149
  children: [
151
- E && /* @__PURE__ */ d("p", {
152
- className: r.copyright,
153
- children: E
154
- }),
155
- D && /* @__PURE__ */ d("p", {
156
- className: r.licenseType,
150
+ D && /* @__PURE__ */ f("p", {
151
+ className: i.copyright,
157
152
  children: D
158
153
  }),
159
- O && /* @__PURE__ */ d("pre", {
160
- className: r.licenseText,
154
+ O && /* @__PURE__ */ f("p", {
155
+ className: i.licenseType,
161
156
  children: O
157
+ }),
158
+ k && /* @__PURE__ */ f("pre", {
159
+ className: i.licenseText,
160
+ children: k
162
161
  })
163
162
  ]
164
163
  })
165
164
  ]
166
165
  }),
167
- /* @__PURE__ */ d("div", {
168
- className: r.footer,
169
- children: /* @__PURE__ */ d("button", {
166
+ /* @__PURE__ */ f("div", {
167
+ className: i.footer,
168
+ children: /* @__PURE__ */ f("button", {
170
169
  type: "button",
171
- className: [r.btn, r.btnDefault].join(" "),
172
- onClick: h,
170
+ className: [i.btn, i.btnDefault].join(" "),
171
+ onClick: g,
173
172
  children: "Close"
174
173
  })
175
174
  })
176
175
  ]
177
176
  })
178
177
  });
179
- return typeof document > "u" ? R : l(R, document.body);
178
+ return typeof document > "u" ? z : u(z, document.body);
180
179
  };
181
180
  //#endregion
182
- export { m as AboutDialog };
181
+ export { h as AboutDialog };
183
182
 
184
183
  //# sourceMappingURL=AboutDialog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AboutDialog.js","names":[],"sources":["../../../src/components/AboutDialog/AboutDialog.tsx"],"sourcesContent":["import {\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { FOCUSABLE, trapFocus, useVisualViewport } from '../Dialog/dialogUtils';\n\nimport styles from './AboutDialog.module.css';\n\nexport interface AboutDialogLink {\n label: string;\n url: string;\n}\n\nexport interface AboutDialogProps {\n /** Whether the dialog is visible. */\n open: boolean;\n /** Called on Escape or close button click. */\n onClose?: () => void;\n /** Application name. */\n applicationName: string;\n /** Icon rendered above the app name. */\n applicationIcon?: ReactNode;\n /** Version string (e.g. `\"1.0.0\"`). */\n version?: string;\n /** One-sentence description. */\n comments?: string;\n /** Developer or organisation name. */\n developerName?: string;\n /** Application website URL. */\n website?: string;\n /** Label for the website link. Defaults to the URL. */\n websiteLabel?: string;\n /** Developer names shown in the Credits tab. */\n developers?: string[];\n /** Designer names shown in the Credits tab. */\n designers?: string[];\n /** Artist names shown in the Credits tab. */\n artists?: string[];\n /** Copyright notice (e.g. `\"© 2024 Jane Smith\"`). */\n copyright?: string;\n /** SPDX identifier or short name (e.g. `\"GPL-3.0\"`). */\n licenseType?: string;\n /** Full license text shown in the Legal tab. */\n licenseText?: string;\n /** Extra links shown in the Details section. */\n links?: AboutDialogLink[];\n}\n\ntype AboutTab = 'details' | 'credits' | 'legal';\nconst ABOUT_TAB_LABEL: Record<AboutTab, string> = {\n details: 'Details',\n credits: 'Credits',\n legal: 'Legal',\n};\n\n/**\n * Standard app info dialog with details, credits, and legal tabs.\n * Mirrors `AdwAboutDialog`.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.AboutDialog.html\n */\nexport const AboutDialog = ({\n open,\n onClose,\n applicationName,\n applicationIcon,\n version,\n comments,\n developerName,\n website,\n websiteLabel,\n developers,\n designers,\n artists,\n copyright,\n licenseType,\n licenseText,\n links,\n}: AboutDialogProps) => {\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n const viewportStyle = useVisualViewport();\n const [activeTab, setActiveTab] = useState<AboutTab>('details');\n\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = dialogRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n setActiveTab('details');\n }\n }, [open]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n trapFocus(e, dialogRef);\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const hasCredits = !!(developers?.length || designers?.length || artists?.length);\n const hasLegal = !!(copyright || licenseType || licenseText);\n const tabs = (\n ['details', hasCredits && 'credits', hasLegal && 'legal'] as (AboutTab | false)[]\n ).filter(Boolean) as AboutTab[];\n\n const node = (\n <div className={styles.backdrop} style={viewportStyle} onClick={onClose} aria-hidden=\"true\">\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n className={styles.dialog}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={styles.header}>\n {applicationIcon && <div className={styles.icon}>{applicationIcon}</div>}\n <div id={titleId} className={styles.appName}>\n {applicationName}\n </div>\n {version && <div className={styles.version}>{version}</div>}\n </div>\n\n {tabs.length > 1 && (\n <div className={styles.tabBar} role=\"tablist\">\n {tabs.map((t) => (\n <button\n key={t}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === t}\n className={[styles.tabBtn, activeTab === t ? styles.tabBtnActive : null]\n .filter(Boolean)\n .join(' ')}\n onClick={() => setActiveTab(t)}\n >\n {ABOUT_TAB_LABEL[t]}\n </button>\n ))}\n </div>\n )}\n\n <div className={styles.tabContent}>\n {activeTab === 'details' && (\n <div className={styles.section}>\n {comments && <p className={styles.comments}>{comments}</p>}\n {(developerName || website || links?.length) && (\n <dl className={styles.infoList}>\n {developerName && (\n <>\n <dt className={styles.infoLabel}>Developer</dt>\n <dd className={styles.infoValue}>{developerName}</dd>\n </>\n )}\n {website && (\n <>\n <dt className={styles.infoLabel}>Website</dt>\n <dd className={styles.infoValue}>\n <a\n href={website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {websiteLabel ?? website}\n </a>\n </dd>\n </>\n )}\n {links?.map((l) => (\n <>\n <dt key={`${l.label}-dt`} className={styles.infoLabel}>\n {l.label}\n </dt>\n <dd key={`${l.label}-dd`} className={styles.infoValue}>\n <a\n href={l.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {l.url}\n </a>\n </dd>\n </>\n ))}\n </dl>\n )}\n </div>\n )}\n\n {activeTab === 'credits' && (\n <div className={styles.section}>\n {[\n { heading: 'Developers', list: developers },\n { heading: 'Designers', list: designers },\n { heading: 'Artists', list: artists },\n ]\n .filter((g) => g.list?.length)\n .map(({ heading, list }) => (\n <div key={heading} className={styles.creditGroup}>\n <h4 className={styles.creditTitle}>{heading}</h4>\n <ul className={styles.creditList}>\n {list?.map((name) => (\n <li key={name} className={styles.creditItem}>\n {name}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n )}\n\n {activeTab === 'legal' && (\n <div className={styles.section}>\n {copyright && <p className={styles.copyright}>{copyright}</p>}\n {licenseType && <p className={styles.licenseType}>{licenseType}</p>}\n {licenseText && <pre className={styles.licenseText}>{licenseText}</pre>}\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button\n type=\"button\"\n className={[styles.btn, styles.btnDefault].join(' ')}\n onClick={onClose}\n >\n Close\n </button>\n </div>\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AboutDialog.js","names":[],"sources":["../../../src/components/AboutDialog/AboutDialog.tsx"],"sourcesContent":["import {\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { FOCUSABLE, trapFocus, useBodyScrollLock, useVisualViewport } from '../Dialog/dialogUtils';\n\nimport styles from './AboutDialog.module.css';\n\nexport interface AboutDialogLink {\n label: string;\n url: string;\n}\n\nexport interface AboutDialogProps {\n /** Whether the dialog is visible. */\n open: boolean;\n /** Called on Escape or close button click. */\n onClose?: () => void;\n /** Application name. */\n applicationName: string;\n /** Icon rendered above the app name. */\n applicationIcon?: ReactNode;\n /** Version string (e.g. `\"1.0.0\"`). */\n version?: string;\n /** One-sentence description. */\n comments?: string;\n /** Developer or organisation name. */\n developerName?: string;\n /** Application website URL. */\n website?: string;\n /** Label for the website link. Defaults to the URL. */\n websiteLabel?: string;\n /** Developer names shown in the Credits tab. */\n developers?: string[];\n /** Designer names shown in the Credits tab. */\n designers?: string[];\n /** Artist names shown in the Credits tab. */\n artists?: string[];\n /** Copyright notice (e.g. `\"© 2024 Jane Smith\"`). */\n copyright?: string;\n /** SPDX identifier or short name (e.g. `\"GPL-3.0\"`). */\n licenseType?: string;\n /** Full license text shown in the Legal tab. */\n licenseText?: string;\n /** Extra links shown in the Details section. */\n links?: AboutDialogLink[];\n}\n\ntype AboutTab = 'details' | 'credits' | 'legal';\nconst ABOUT_TAB_LABEL: Record<AboutTab, string> = {\n details: 'Details',\n credits: 'Credits',\n legal: 'Legal',\n};\n\n/**\n * Standard app info dialog with details, credits, and legal tabs.\n * Mirrors `AdwAboutDialog`.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.AboutDialog.html\n */\nexport const AboutDialog = ({\n open,\n onClose,\n applicationName,\n applicationIcon,\n version,\n comments,\n developerName,\n website,\n websiteLabel,\n developers,\n designers,\n artists,\n copyright,\n licenseType,\n licenseText,\n links,\n}: AboutDialogProps) => {\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n const viewportStyle = useVisualViewport();\n const [activeTab, setActiveTab] = useState<AboutTab>('details');\n\n useBodyScrollLock(open);\n\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = dialogRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n setActiveTab('details');\n }\n }, [open]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n trapFocus(e, dialogRef);\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const hasCredits = !!(developers?.length || designers?.length || artists?.length);\n const hasLegal = !!(copyright || licenseType || licenseText);\n const tabs = (\n ['details', hasCredits && 'credits', hasLegal && 'legal'] as (AboutTab | false)[]\n ).filter(Boolean) as AboutTab[];\n\n const node = (\n <div className={styles.backdrop} style={viewportStyle} onClick={onClose}>\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n className={styles.dialog}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={styles.header}>\n {applicationIcon && <div className={styles.icon}>{applicationIcon}</div>}\n <div id={titleId} className={styles.appName}>\n {applicationName}\n </div>\n {version && <div className={styles.version}>{version}</div>}\n </div>\n\n {tabs.length > 1 && (\n <div className={styles.tabBar} role=\"tablist\">\n {tabs.map((t) => (\n <button\n key={t}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === t}\n className={[styles.tabBtn, activeTab === t ? styles.tabBtnActive : null]\n .filter(Boolean)\n .join(' ')}\n onClick={() => setActiveTab(t)}\n >\n {ABOUT_TAB_LABEL[t]}\n </button>\n ))}\n </div>\n )}\n\n <div className={styles.tabContent}>\n {activeTab === 'details' && (\n <div className={styles.section}>\n {comments && <p className={styles.comments}>{comments}</p>}\n {(developerName || website || links?.length) && (\n <dl className={styles.infoList}>\n {developerName && (\n <>\n <dt className={styles.infoLabel}>Developer</dt>\n <dd className={styles.infoValue}>{developerName}</dd>\n </>\n )}\n {website && (\n <>\n <dt className={styles.infoLabel}>Website</dt>\n <dd className={styles.infoValue}>\n <a\n href={website}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {websiteLabel ?? website}\n </a>\n </dd>\n </>\n )}\n {links?.map((l) => (\n <>\n <dt key={`${l.label}-dt`} className={styles.infoLabel}>\n {l.label}\n </dt>\n <dd key={`${l.label}-dd`} className={styles.infoValue}>\n <a\n href={l.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={styles.link}\n >\n {l.url}\n </a>\n </dd>\n </>\n ))}\n </dl>\n )}\n </div>\n )}\n\n {activeTab === 'credits' && (\n <div className={styles.section}>\n {[\n { heading: 'Developers', list: developers },\n { heading: 'Designers', list: designers },\n { heading: 'Artists', list: artists },\n ]\n .filter((g) => g.list?.length)\n .map(({ heading, list }) => (\n <div key={heading} className={styles.creditGroup}>\n <h4 className={styles.creditTitle}>{heading}</h4>\n <ul className={styles.creditList}>\n {list?.map((name) => (\n <li key={name} className={styles.creditItem}>\n {name}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n )}\n\n {activeTab === 'legal' && (\n <div className={styles.section}>\n {copyright && <p className={styles.copyright}>{copyright}</p>}\n {licenseType && <p className={styles.licenseType}>{licenseType}</p>}\n {licenseText && <pre className={styles.licenseText}>{licenseText}</pre>}\n </div>\n )}\n </div>\n\n <div className={styles.footer}>\n <button\n type=\"button\"\n className={[styles.btn, styles.btnDefault].join(' ')}\n onClick={onClose}\n >\n Close\n </button>\n </div>\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("./BottomSheet.module.css.cjs");let t=require("react"),n=require("react-dom"),r=require("react/jsx-runtime");var i=`button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])`,a=({open:a,title:o,children:s,onClose:c,closeOnBackdrop:l=!0,className:u,...d})=>{let f=(0,t.useRef)(null),p=(0,t.useId)(),m=(0,t.useRef)(null);(0,t.useEffect)(()=>{a?(m.current=document.activeElement,(f.current?.querySelector(i))?.focus()):m.current?.focus()},[a]);let h=(0,t.useCallback)(e=>{if(e.key===`Escape`){e.preventDefault(),c?.();return}if(e.key!==`Tab`)return;let t=Array.from(f.current?.querySelectorAll(i)??[]);if(t.length===0)return;let n=t[0],r=t[t.length-1];e.shiftKey?document.activeElement===n&&(e.preventDefault(),r.focus()):document.activeElement===r&&(e.preventDefault(),n.focus())},[c]);if(!a)return null;let g=(0,r.jsx)(`div`,{className:e.default.backdrop,onClick:l?c:void 0,"aria-hidden":`true`,children:(0,r.jsxs)(`div`,{ref:f,role:`dialog`,"aria-modal":`true`,"aria-labelledby":o?p:void 0,className:[e.default.sheet,u].filter(Boolean).join(` `),onKeyDown:h,onClick:e=>e.stopPropagation(),...d,children:[(0,r.jsx)(`div`,{className:e.default.handle,"aria-hidden":`true`,children:(0,r.jsx)(`div`,{className:e.default.handleBar})}),o&&(0,r.jsx)(`div`,{id:p,className:e.default.title,children:o}),s&&(0,r.jsx)(`div`,{className:e.default.content,children:s})]})});return typeof document>`u`?g:(0,n.createPortal)(g,document.body)};exports.BottomSheet=a;
1
+ const e=require("../Dialog/dialogUtils.cjs"),t=require("./BottomSheet.module.css.cjs");let n=require("react"),r=require("react-dom"),i=require("react/jsx-runtime");var a=`button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])`,o=({open:o,title:s,children:c,onClose:l,closeOnBackdrop:u=!0,className:d,...f})=>{let p=(0,n.useRef)(null),m=(0,n.useId)(),h=(0,n.useRef)(null);e.useBodyScrollLock(o),(0,n.useEffect)(()=>{o?(h.current=document.activeElement,(p.current?.querySelector(a))?.focus()):h.current?.focus()},[o]);let g=(0,n.useCallback)(e=>{if(e.key===`Escape`){e.preventDefault(),l?.();return}if(e.key!==`Tab`)return;let t=Array.from(p.current?.querySelectorAll(a)??[]);if(t.length===0)return;let n=t[0],r=t[t.length-1];e.shiftKey?document.activeElement===n&&(e.preventDefault(),r.focus()):document.activeElement===r&&(e.preventDefault(),n.focus())},[l]);if(!o)return null;let _=(0,i.jsx)(`div`,{className:t.default.backdrop,onClick:u?l:void 0,children:(0,i.jsxs)(`div`,{ref:p,role:`dialog`,"aria-modal":`true`,"aria-labelledby":s?m:void 0,className:[t.default.sheet,d].filter(Boolean).join(` `),onKeyDown:g,onClick:e=>e.stopPropagation(),...f,children:[(0,i.jsx)(`div`,{className:t.default.handle,"aria-hidden":`true`,children:(0,i.jsx)(`div`,{className:t.default.handleBar})}),s&&(0,i.jsx)(`div`,{id:m,className:t.default.title,children:s}),c&&(0,i.jsx)(`div`,{className:t.default.content,children:c})]})});return typeof document>`u`?_:(0,r.createPortal)(_,document.body)};exports.BottomSheet=o;
2
2
  //# sourceMappingURL=BottomSheet.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BottomSheet.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape or backdrop click). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape or backdrop click.\n * The handle bar is decorative — drag-to-close is not implemented.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const node = (\n <div\n className={styles.backdrop}\n onClick={closeOnBackdrop ? onClose : undefined}\n aria-hidden=\"true\"\n >\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[styles.sheet, className].filter(Boolean).join(' ')}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar */}\n <div className={styles.handle} aria-hidden=\"true\">\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"6HAcA,IAAM,EACJ,2IA4BW,GAAe,CAC1B,OACA,QACA,WACA,UACA,kBAAkB,GAClB,YACA,GAAG,KACmB,CACtB,IAAM,GAAA,EAAA,EAAA,QAAkC,IAAI,EACtC,GAAA,EAAA,EAAA,OAAgB,EAChB,GAAA,EAAA,EAAA,QAA2C,IAAI,GAGrD,EAAA,EAAA,eAAgB,CACV,GACF,EAAkB,QAAU,SAAS,eAC1B,EAAS,SAAS,cAA2B,CAAS,IAE7D,MAAM,GAEV,EAAmB,SAAgC,MAAM,CAE7D,EAAG,CAAC,CAAI,CAAC,EAGT,IAAM,GAAA,EAAA,EAAA,aACH,GAAqC,CACpC,GAAI,EAAE,MAAQ,SAAU,CACtB,EAAE,eAAe,EACjB,IAAU,EAEV,MACF,CAEA,GAAI,EAAE,MAAQ,MACZ,OAGF,IAAM,EAAY,MAAM,KACtB,EAAS,SAAS,iBAA8B,CAAS,GAAK,CAAC,CACjE,EAEA,GAAI,EAAU,SAAW,EACvB,OAGF,IAAM,EAAQ,EAAU,GAClB,EAAO,EAAU,EAAU,OAAS,GAEtC,EAAE,SACA,SAAS,gBAAkB,IAC7B,EAAE,eAAe,EACjB,EAAK,MAAM,GAGT,SAAS,gBAAkB,IAC7B,EAAE,eAAe,EACjB,EAAM,MAAM,EAGlB,EACA,CAAC,CAAO,CACV,EAEA,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,GACJ,EAAA,EAAA,KAAC,MAAD,CACE,UAAW,EAAA,QAAO,SAClB,QAAS,EAAkB,EAAU,IAAA,GACrC,cAAY,iBAEZ,EAAA,EAAA,MAAC,MAAD,CACE,IAAK,EACL,KAAK,SACL,aAAW,OACX,kBAAiB,EAAQ,EAAU,IAAA,GACnC,UAAW,CAAC,EAAA,QAAO,MAAO,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAC7D,UAAW,EACX,QAAU,GAAM,EAAE,gBAAgB,EAClC,GAAI,WARN,EAWE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAQ,cAAY,iBACzC,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,SAAY,CAAA,CAChC,CAAA,EAGJ,IACC,EAAA,EAAA,KAAC,MAAD,CAAK,GAAI,EAAS,UAAW,EAAA,QAAO,eACjC,CACE,CAAA,EAIN,IAAY,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,UAAc,CAAA,CACzD,GACF,CAAA,EAOP,OAJI,OAAO,SAAa,IACf,GAGT,EAAA,EAAA,cAAoB,EAAM,SAAS,IAAI,CACzC"}
1
+ {"version":3,"file":"BottomSheet.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { useBodyScrollLock } from '../Dialog/dialogUtils';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape or backdrop click). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape or backdrop click.\n * The handle bar is decorative — drag-to-close is not implemented.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n useBodyScrollLock(open);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const node = (\n <div className={styles.backdrop} onClick={closeOnBackdrop ? onClose : undefined}>\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[styles.sheet, className].filter(Boolean).join(' ')}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar */}\n <div className={styles.handle} aria-hidden=\"true\">\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"oKAgBA,IAAM,EACJ,2IA4BW,GAAe,CAC1B,OACA,QACA,WACA,UACA,kBAAkB,GAClB,YACA,GAAG,KACmB,CACtB,IAAM,GAAA,EAAA,EAAA,QAAkC,IAAI,EACtC,GAAA,EAAA,EAAA,OAAgB,EAChB,GAAA,EAAA,EAAA,QAA2C,IAAI,EAErD,EAAA,kBAAkB,CAAI,GAGtB,EAAA,EAAA,eAAgB,CACV,GACF,EAAkB,QAAU,SAAS,eAC1B,EAAS,SAAS,cAA2B,CAAS,IAE7D,MAAM,GAEV,EAAmB,SAAgC,MAAM,CAE7D,EAAG,CAAC,CAAI,CAAC,EAGT,IAAM,GAAA,EAAA,EAAA,aACH,GAAqC,CACpC,GAAI,EAAE,MAAQ,SAAU,CACtB,EAAE,eAAe,EACjB,IAAU,EAEV,MACF,CAEA,GAAI,EAAE,MAAQ,MACZ,OAGF,IAAM,EAAY,MAAM,KACtB,EAAS,SAAS,iBAA8B,CAAS,GAAK,CAAC,CACjE,EAEA,GAAI,EAAU,SAAW,EACvB,OAGF,IAAM,EAAQ,EAAU,GAClB,EAAO,EAAU,EAAU,OAAS,GAEtC,EAAE,SACA,SAAS,gBAAkB,IAC7B,EAAE,eAAe,EACjB,EAAK,MAAM,GAGT,SAAS,gBAAkB,IAC7B,EAAE,eAAe,EACjB,EAAM,MAAM,EAGlB,EACA,CAAC,CAAO,CACV,EAEA,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,GACJ,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,SAAU,QAAS,EAAkB,EAAU,IAAA,aACpE,EAAA,EAAA,MAAC,MAAD,CACE,IAAK,EACL,KAAK,SACL,aAAW,OACX,kBAAiB,EAAQ,EAAU,IAAA,GACnC,UAAW,CAAC,EAAA,QAAO,MAAO,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAC7D,UAAW,EACX,QAAU,GAAM,EAAE,gBAAgB,EAClC,GAAI,WARN,EAWE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAQ,cAAY,iBACzC,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,SAAY,CAAA,CAChC,CAAA,EAGJ,IACC,EAAA,EAAA,KAAC,MAAD,CAAK,GAAI,EAAS,UAAW,EAAA,QAAO,eACjC,CACE,CAAA,EAIN,IAAY,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,UAAc,CAAA,CACzD,GACF,CAAA,EAOP,OAJI,OAAO,SAAa,IACf,GAGT,EAAA,EAAA,cAAoB,EAAM,SAAS,IAAI,CACzC"}
@@ -1,59 +1,59 @@
1
- import e from "./BottomSheet.module.css.js";
2
- import { useCallback as t, useEffect as n, useId as r, useRef as i } from "react";
3
- import { createPortal as a } from "react-dom";
4
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
1
+ import { useBodyScrollLock as e } from "../Dialog/dialogUtils.js";
2
+ import t from "./BottomSheet.module.css.js";
3
+ import { useCallback as n, useEffect as r, useId as i, useRef as a } from "react";
4
+ import { createPortal as o } from "react-dom";
5
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
5
6
  //#region src/components/BottomSheet/BottomSheet.tsx
6
- var c = "button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])", l = ({ open: l, title: u, children: d, onClose: f, closeOnBackdrop: p = !0, className: m, ...h }) => {
7
- let g = i(null), _ = r(), v = i(null);
8
- n(() => {
9
- l ? (v.current = document.activeElement, (g.current?.querySelector(c))?.focus()) : v.current?.focus();
10
- }, [l]);
11
- let y = t((e) => {
7
+ var l = "button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])", u = ({ open: u, title: d, children: f, onClose: p, closeOnBackdrop: m = !0, className: h, ...g }) => {
8
+ let _ = a(null), v = i(), y = a(null);
9
+ e(u), r(() => {
10
+ u ? (y.current = document.activeElement, (_.current?.querySelector(l))?.focus()) : y.current?.focus();
11
+ }, [u]);
12
+ let b = n((e) => {
12
13
  if (e.key === "Escape") {
13
- e.preventDefault(), f?.();
14
+ e.preventDefault(), p?.();
14
15
  return;
15
16
  }
16
17
  if (e.key !== "Tab") return;
17
- let t = Array.from(g.current?.querySelectorAll(c) ?? []);
18
+ let t = Array.from(_.current?.querySelectorAll(l) ?? []);
18
19
  if (t.length === 0) return;
19
20
  let n = t[0], r = t[t.length - 1];
20
21
  e.shiftKey ? document.activeElement === n && (e.preventDefault(), r.focus()) : document.activeElement === r && (e.preventDefault(), n.focus());
21
- }, [f]);
22
- if (!l) return null;
23
- let b = /* @__PURE__ */ o("div", {
24
- className: e.backdrop,
25
- onClick: p ? f : void 0,
26
- "aria-hidden": "true",
27
- children: /* @__PURE__ */ s("div", {
28
- ref: g,
22
+ }, [p]);
23
+ if (!u) return null;
24
+ let x = /* @__PURE__ */ s("div", {
25
+ className: t.backdrop,
26
+ onClick: m ? p : void 0,
27
+ children: /* @__PURE__ */ c("div", {
28
+ ref: _,
29
29
  role: "dialog",
30
30
  "aria-modal": "true",
31
- "aria-labelledby": u ? _ : void 0,
32
- className: [e.sheet, m].filter(Boolean).join(" "),
33
- onKeyDown: y,
31
+ "aria-labelledby": d ? v : void 0,
32
+ className: [t.sheet, h].filter(Boolean).join(" "),
33
+ onKeyDown: b,
34
34
  onClick: (e) => e.stopPropagation(),
35
- ...h,
35
+ ...g,
36
36
  children: [
37
- /* @__PURE__ */ o("div", {
38
- className: e.handle,
37
+ /* @__PURE__ */ s("div", {
38
+ className: t.handle,
39
39
  "aria-hidden": "true",
40
- children: /* @__PURE__ */ o("div", { className: e.handleBar })
40
+ children: /* @__PURE__ */ s("div", { className: t.handleBar })
41
41
  }),
42
- u && /* @__PURE__ */ o("div", {
43
- id: _,
44
- className: e.title,
45
- children: u
46
- }),
47
- d && /* @__PURE__ */ o("div", {
48
- className: e.content,
42
+ d && /* @__PURE__ */ s("div", {
43
+ id: v,
44
+ className: t.title,
49
45
  children: d
46
+ }),
47
+ f && /* @__PURE__ */ s("div", {
48
+ className: t.content,
49
+ children: f
50
50
  })
51
51
  ]
52
52
  })
53
53
  });
54
- return typeof document > "u" ? b : a(b, document.body);
54
+ return typeof document > "u" ? x : o(x, document.body);
55
55
  };
56
56
  //#endregion
57
- export { l as BottomSheet };
57
+ export { u as BottomSheet };
58
58
 
59
59
  //# sourceMappingURL=BottomSheet.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BottomSheet.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape or backdrop click). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape or backdrop click.\n * The handle bar is decorative — drag-to-close is not implemented.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const node = (\n <div\n className={styles.backdrop}\n onClick={closeOnBackdrop ? onClose : undefined}\n aria-hidden=\"true\"\n >\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[styles.sheet, className].filter(Boolean).join(' ')}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar */}\n <div className={styles.handle} aria-hidden=\"true\">\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":";;;;;AAcA,IAAM,IACJ,8IA4BW,KAAe,EAC1B,SACA,UACA,aACA,YACA,qBAAkB,IAClB,cACA,GAAG,QACmB;CACtB,IAAM,IAAW,EAAuB,IAAI,GACtC,IAAU,EAAM,GAChB,IAAoB,EAAuB,IAAI;CAGrD,QAAgB;EACd,AAAI,KACF,EAAkB,UAAU,SAAS,gBAC1B,EAAS,SAAS,cAA2B,CAAS,IAE7D,MAAM,KAEV,EAAmB,SAAgC,MAAM;CAE7D,GAAG,CAAC,CAAI,CAAC;CAGT,IAAM,IAAgB,GACnB,MAAqC;EACpC,IAAI,EAAE,QAAQ,UAAU;GAEtB,AADA,EAAE,eAAe,GACjB,IAAU;GAEV;EACF;EAEA,IAAI,EAAE,QAAQ,OACZ;EAGF,IAAM,IAAY,MAAM,KACtB,EAAS,SAAS,iBAA8B,CAAS,KAAK,CAAC,CACjE;EAEA,IAAI,EAAU,WAAW,GACvB;EAGF,IAAM,IAAQ,EAAU,IAClB,IAAO,EAAU,EAAU,SAAS;EAE1C,AAAI,EAAE,WACA,SAAS,kBAAkB,MAC7B,EAAE,eAAe,GACjB,EAAK,MAAM,KAGT,SAAS,kBAAkB,MAC7B,EAAE,eAAe,GACjB,EAAM,MAAM;CAGlB,GACA,CAAC,CAAO,CACV;CAEA,IAAI,CAAC,GACH,OAAO;CAGT,IAAM,IACJ,kBAAC,OAAD;EACE,WAAW,EAAO;EAClB,SAAS,IAAkB,IAAU,KAAA;EACrC,eAAY;YAEZ,kBAAC,OAAD;GACE,KAAK;GACL,MAAK;GACL,cAAW;GACX,mBAAiB,IAAQ,IAAU,KAAA;GACnC,WAAW,CAAC,EAAO,OAAO,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;GAC7D,WAAW;GACX,UAAU,MAAM,EAAE,gBAAgB;GAClC,GAAI;aARN;IAWE,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAQ,eAAY;eACzC,kBAAC,OAAD,EAAK,WAAW,EAAO,UAAY,CAAA;IAChC,CAAA;IAGJ,KACC,kBAAC,OAAD;KAAK,IAAI;KAAS,WAAW,EAAO;eACjC;IACE,CAAA;IAIN,KAAY,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAU;IAAc,CAAA;GACzD;;CACF,CAAA;CAOP,OAJI,OAAO,WAAa,MACf,IAGF,EAAa,GAAM,SAAS,IAAI;AACzC"}
1
+ {"version":3,"file":"BottomSheet.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { useBodyScrollLock } from '../Dialog/dialogUtils';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape or backdrop click). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape or backdrop click.\n * The handle bar is decorative — drag-to-close is not implemented.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n useBodyScrollLock(open);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const node = (\n <div className={styles.backdrop} onClick={closeOnBackdrop ? onClose : undefined}>\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[styles.sheet, className].filter(Boolean).join(' ')}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar */}\n <div className={styles.handle} aria-hidden=\"true\">\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":";;;;;;AAgBA,IAAM,IACJ,8IA4BW,KAAe,EAC1B,SACA,UACA,aACA,YACA,qBAAkB,IAClB,cACA,GAAG,QACmB;CACtB,IAAM,IAAW,EAAuB,IAAI,GACtC,IAAU,EAAM,GAChB,IAAoB,EAAuB,IAAI;CAKrD,AAHA,EAAkB,CAAI,GAGtB,QAAgB;EACd,AAAI,KACF,EAAkB,UAAU,SAAS,gBAC1B,EAAS,SAAS,cAA2B,CAAS,IAE7D,MAAM,KAEV,EAAmB,SAAgC,MAAM;CAE7D,GAAG,CAAC,CAAI,CAAC;CAGT,IAAM,IAAgB,GACnB,MAAqC;EACpC,IAAI,EAAE,QAAQ,UAAU;GAEtB,AADA,EAAE,eAAe,GACjB,IAAU;GAEV;EACF;EAEA,IAAI,EAAE,QAAQ,OACZ;EAGF,IAAM,IAAY,MAAM,KACtB,EAAS,SAAS,iBAA8B,CAAS,KAAK,CAAC,CACjE;EAEA,IAAI,EAAU,WAAW,GACvB;EAGF,IAAM,IAAQ,EAAU,IAClB,IAAO,EAAU,EAAU,SAAS;EAE1C,AAAI,EAAE,WACA,SAAS,kBAAkB,MAC7B,EAAE,eAAe,GACjB,EAAK,MAAM,KAGT,SAAS,kBAAkB,MAC7B,EAAE,eAAe,GACjB,EAAM,MAAM;CAGlB,GACA,CAAC,CAAO,CACV;CAEA,IAAI,CAAC,GACH,OAAO;CAGT,IAAM,IACJ,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAU,SAAS,IAAkB,IAAU,KAAA;YACpE,kBAAC,OAAD;GACE,KAAK;GACL,MAAK;GACL,cAAW;GACX,mBAAiB,IAAQ,IAAU,KAAA;GACnC,WAAW,CAAC,EAAO,OAAO,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;GAC7D,WAAW;GACX,UAAU,MAAM,EAAE,gBAAgB;GAClC,GAAI;aARN;IAWE,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAQ,eAAY;eACzC,kBAAC,OAAD,EAAK,WAAW,EAAO,UAAY,CAAA;IAChC,CAAA;IAGJ,KACC,kBAAC,OAAD;KAAK,IAAI;KAAS,WAAW,EAAO;eACjC;IACE,CAAA;IAIN,KAAY,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAU;IAAc,CAAA;GACzD;;CACF,CAAA;CAOP,OAJI,OAAO,WAAa,MACf,IAGF,EAAa,GAAM,SAAS,IAAI;AACzC"}