@mittwald/flow-react-components 1.3.5 → 1.4.0-next.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 (85) hide show
  1. package/MIGRATION.md +25 -2
  2. package/dist/assets/component-index.json +1 -1
  3. package/dist/assets/doc-properties.json +1 -1
  4. package/dist/css/all-layered.css +1 -1
  5. package/dist/css/all.css +1 -1
  6. package/dist/js/_virtual/_24.locale.mjs +10 -2
  7. package/dist/js/default.mjs +2 -1
  8. package/dist/js/flr-universal.mjs +2 -1
  9. package/dist/js/packages/components/src/components/Action/models/ActionModel.mjs +25 -8
  10. package/dist/js/packages/components/src/components/Action/models/ActionModel.mjs.map +1 -1
  11. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.mjs +0 -1
  12. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.mjs.map +1 -1
  13. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.module.mjs +2 -4
  14. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.module.mjs.map +1 -1
  15. package/dist/js/packages/components/src/components/ContextMenu/ContextMenu.mjs +2 -2
  16. package/dist/js/packages/components/src/components/ContextMenu/ContextMenu.mjs.map +1 -1
  17. package/dist/js/packages/components/src/components/ContextMenu/components/ContextMenuSection/ContextMenuSection.mjs +2 -2
  18. package/dist/js/packages/components/src/components/ContextMenu/components/ContextMenuSection/ContextMenuSection.mjs.map +1 -1
  19. package/dist/js/packages/components/src/components/ContextMenu/lib.mjs +7 -3
  20. package/dist/js/packages/components/src/components/ContextMenu/lib.mjs.map +1 -1
  21. package/dist/js/packages/components/src/components/CopyButton/CopyButton.mjs +4 -3
  22. package/dist/js/packages/components/src/components/CopyButton/CopyButton.mjs.map +1 -1
  23. package/dist/js/packages/components/src/components/Icon/components/icons/IconAIHosting.mjs +19 -0
  24. package/dist/js/packages/components/src/components/Icon/components/icons/IconAIHosting.mjs.map +1 -0
  25. package/dist/js/packages/components/src/components/Image/Image.mjs +2 -2
  26. package/dist/js/packages/components/src/components/Image/Image.mjs.map +1 -1
  27. package/dist/js/packages/components/src/components/Image/Image.module.mjs +3 -1
  28. package/dist/js/packages/components/src/components/Image/Image.module.mjs.map +1 -1
  29. package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/AllFiltersModal.mjs +2 -2
  30. package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/AllFiltersModal.mjs.map +1 -1
  31. package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/FilterAccordionDateRange.mjs +2 -2
  32. package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/FilterAccordionDateRange.mjs.map +1 -1
  33. package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/FilterAccordionRadioGroup.mjs +2 -2
  34. package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/FilterAccordionRadioGroup.mjs.map +1 -1
  35. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.mjs +16 -3
  36. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -1
  37. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.module.mjs +4 -2
  38. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.module.mjs.map +1 -1
  39. package/dist/js/packages/components/src/components/MarkdownEditor/components/AttachmentButton.mjs +47 -0
  40. package/dist/js/packages/components/src/components/MarkdownEditor/components/AttachmentButton.mjs.map +1 -0
  41. package/dist/js/packages/components/src/components/MarkdownEditor/components/Toolbar.mjs +21 -20
  42. package/dist/js/packages/components/src/components/MarkdownEditor/components/Toolbar.mjs.map +1 -1
  43. package/dist/js/packages/components/src/components/MarkdownEditor/components/ToolbarButton.mjs +1 -1
  44. package/dist/js/packages/components/src/components/MarkdownEditor/components/ToolbarButton.mjs.map +1 -1
  45. package/dist/js/packages/components/src/components/MarkdownEditor/lib/fileUpload.mjs +73 -0
  46. package/dist/js/packages/components/src/components/MarkdownEditor/lib/fileUpload.mjs.map +1 -0
  47. package/dist/js/packages/components/src/components/MarkdownEditor/lib/useFileUpload.mjs +141 -0
  48. package/dist/js/packages/components/src/components/MarkdownEditor/lib/useFileUpload.mjs.map +1 -0
  49. package/dist/js/packages/components/src/components/Modal/Modal.mjs +6 -4
  50. package/dist/js/packages/components/src/components/Modal/Modal.mjs.map +1 -1
  51. package/dist/js/packages/components/src/components/OverlayTrigger/OverlayTrigger.mjs +1 -0
  52. package/dist/js/packages/components/src/components/OverlayTrigger/OverlayTrigger.mjs.map +1 -1
  53. package/dist/js/packages/components/src/components/TabNavigation/lib/useCollapsingItems.mjs +1 -2
  54. package/dist/js/packages/components/src/components/TabNavigation/lib/useCollapsingItems.mjs.map +1 -1
  55. package/dist/js/packages/components/src/components/Tabs/lib/useTabIndicator.mjs +2 -3
  56. package/dist/js/packages/components/src/components/Tabs/lib/useTabIndicator.mjs.map +1 -1
  57. package/dist/js/packages/components/src/lib/controller/overlay/OverlayContextProvider.mjs +6 -3
  58. package/dist/js/packages/components/src/lib/controller/overlay/OverlayContextProvider.mjs.map +1 -1
  59. package/dist/js/packages/components/src/lib/controller/overlay/OverlayController.mjs.map +1 -1
  60. package/dist/js/packages/components/src/lib/controller/overlay/context.mjs +1 -1
  61. package/dist/js/packages/components/src/lib/controller/overlay/context.mjs.map +1 -1
  62. package/dist/js/packages/components/src/lib/controller/overlay/useOverlayController.mjs +1 -1
  63. package/dist/js/packages/components/src/lib/controller/overlay/useOverlayController.mjs.map +1 -1
  64. package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs +1 -1
  65. package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs.map +1 -1
  66. package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs +1 -1
  67. package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs.map +1 -1
  68. package/dist/types/components/Action/models/ActionModel.d.ts +12 -4
  69. package/dist/types/components/Action/types.d.ts +9 -2
  70. package/dist/types/components/ContextMenu/lib.d.ts +5 -1
  71. package/dist/types/components/CopyButton/CopyButton.d.ts +5 -0
  72. package/dist/types/components/Icon/components/icons/IconAIHosting.d.ts +4 -0
  73. package/dist/types/components/Icon/components/icons/index.d.ts +1 -0
  74. package/dist/types/components/Image/Image.d.ts +7 -1
  75. package/dist/types/components/MarkdownEditor/MarkdownEditor.d.ts +20 -0
  76. package/dist/types/components/MarkdownEditor/components/AttachmentButton.d.ts +1 -0
  77. package/dist/types/components/MarkdownEditor/components/Toolbar.d.ts +11 -2
  78. package/dist/types/components/MarkdownEditor/components/ToolbarButton.d.ts +8 -2
  79. package/dist/types/components/MarkdownEditor/index.d.ts +1 -1
  80. package/dist/types/components/MarkdownEditor/lib/fileUpload.d.ts +19 -0
  81. package/dist/types/components/MarkdownEditor/lib/useFileUpload.d.ts +1 -0
  82. package/dist/types/lib/controller/overlay/OverlayContextProvider.d.ts +9 -0
  83. package/dist/types/lib/controller/overlay/OverlayController.d.ts +11 -1
  84. package/dist/types/lib/controller/overlay/context.d.ts +19 -2
  85. package/package.json +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.mjs","names":[],"sources":["../../../../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["import { type PropsWithChildren, type ReactNode, Suspense, useId } from \"react\";\nimport styles from \"./Modal.module.scss\";\nimport clsx from \"clsx\";\nimport {\n dynamic,\n type PropsContext,\n PropsContextProvider,\n} from \"@/lib/propsContext\";\nimport { OverlayController } from \"@/lib/controller/overlay\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport { Overlay, type OverlayProps } from \"@/components/Overlay/Overlay\";\nimport { Action } from \"@/components/Action\";\nimport { IconClose } from \"@/components/Icon/components/icons\";\nimport type { PropsWithClassName } from \"@/lib/types/props\";\nimport ButtonView from \"@/views/ButtonView\";\nimport DivView from \"@/views/DivView\";\nimport { OffCanvasSuspenseFallback } from \"@/components/Modal/components/OffCanvasSuspenseFallback\";\nimport { ConfirmUnsavedChangesModal } from \"@/components/Modal/components/ConfirmUnsavedChangesModal/ConfirmUnsavedChangesModal\";\nimport Wrap from \"@/components/Wrap\";\nimport { ClearPropsContext } from \"@/components/ClearPropsContext/ClearPropsContext\";\nimport ClearPropsContextView from \"@/views/ClearPropsContextView\";\nimport { useLocalizedStringFormatter } from \"@/components/TranslationProvider\";\nimport { useVirtualKeyboardVisible } from \"@/lib/hooks/dom/useVirtualKeyboardVisible\";\nimport locales from \"./locales/*.locale.json\";\n\ntype SupportedOverlayProps = Pick<\n OverlayProps,\n \"isOpen\" | \"isDefaultOpen\" | \"onOpen\" | \"onClose\" | \"onOpenChange\"\n>;\n\nexport interface ModalProps\n extends\n PropsWithChildren,\n FlowComponentProps,\n PropsWithClassName,\n SupportedOverlayProps {\n /** The size of the modal. @default \"s\" */\n size?: \"s\" | \"m\" | \"l\";\n /** Whether the modal should be displayed as an off canvas. */\n offCanvas?: boolean;\n /**\n * Whether the off canvas should be displayed on the right or left side of the\n * screen. @default \"right\"\n */\n offCanvasOrientation?: \"left\" | \"right\";\n /** An overlay controller to control the modal state. */\n controller?: OverlayController;\n /**\n * Accepts \"actionConfirm\" to use the modal as a confirmation modal for an\n * action.\n */\n slot?: string;\n /** Whether the modal can be closed by clicking outside of it. */\n isDismissable?: boolean;\n /** Whether the close button should be visible */\n showCloseButton?: boolean;\n /**\n * Whether closing the modal must be confirmed – use it to protect unsaved\n * changes. `false` does not switch off the confirmation of a dirty `Form`\n * inside the modal; set `confirmModalCloseOnUnsavedChanges={false}` on the\n * `Form` for that.\n */\n confirmOnClose?: boolean;\n}\n\nexport const Modal = flowComponent(\"Modal\", (props) => {\n const {\n size = \"s\",\n offCanvas,\n controller,\n children,\n ref,\n className,\n offCanvasOrientation = \"right\",\n showCloseButton,\n ...overlayProps\n } = props;\n\n const stringFormatter = useLocalizedStringFormatter(locales, \"Modal\");\n\n // On mobile the header/footer are docked (sticky) while at rest, but flow\n // normally while the on-screen keyboard is open so the content gets the full\n // available space (see Modal.module.scss). #2423\n const keyboardVisible = useVirtualKeyboardVisible();\n\n const rootClassName = clsx(\n offCanvas ? styles.offCanvas : styles.modal,\n styles[`size-${size}`],\n offCanvasOrientation === \"left\" && styles[\"left\"],\n keyboardVisible && styles.keyboardVisible,\n className,\n );\n\n const generatedId = useId();\n\n const header = (children: ReactNode) => (\n <>\n <DivView className={styles.headerTitle}>{children}</DivView>\n <ClearPropsContext>\n <ClearPropsContextView>\n <Action closeModal={{ bypassConfirmation: true }}>\n <ButtonView\n variant=\"plain\"\n color=\"secondary\"\n aria-label={stringFormatter.format(\"close\")}\n className={clsx(\n styles.closeButton,\n showCloseButton === true\n ? styles.alwaysVisible\n : showCloseButton === false\n ? styles.alwaysHidden\n : undefined,\n )}\n >\n <IconClose />\n </ButtonView>\n </Action>\n </ClearPropsContextView>\n </ClearPropsContext>\n </>\n );\n\n const nestedHeadingLevel = 3;\n\n const nestedHeadingProps: PropsContext = {\n Heading: { level: nestedHeadingLevel },\n Section: {\n Header: { Heading: { level: nestedHeadingLevel } },\n Heading: { level: nestedHeadingLevel },\n hideSeparator: true,\n },\n Header: { Heading: { level: nestedHeadingLevel } },\n };\n\n const propsContext: PropsContext = {\n Content: {\n ...nestedHeadingProps,\n className: styles.content,\n },\n ColumnLayout: {\n ...nestedHeadingProps,\n l: [2, 1],\n m: [1],\n className: styles.columnLayout,\n AccentBox: { className: styles.accentBox, backgroundColor: \"neutral\" },\n wrapWith: <ClearPropsContext />,\n },\n Heading: {\n className: styles.header,\n level: 2,\n children: dynamic((props) => header(props.children)),\n id: generatedId,\n },\n ActionGroup: {\n className: styles.actionGroup,\n spacing: \"m\",\n Action: {\n closeModal: dynamic((props) => {\n if (props.closeModal === undefined) {\n return;\n }\n if (props.closeModal === true) {\n return { bypassConfirmation: true };\n }\n return {\n bypassConfirmation: true,\n ...props.closeModal,\n };\n }),\n closeOverlay: dynamic((props) => {\n if (props.closeOverlay === undefined) {\n return;\n }\n if (\n props.closeOverlay instanceof OverlayController ||\n typeof props.closeOverlay === \"string\"\n ) {\n return {\n bypassConfirmation: true,\n overlay: props.closeOverlay,\n };\n }\n return {\n bypassConfirmation: true,\n ...props.closeOverlay,\n };\n }),\n },\n },\n };\n\n return (\n <Overlay\n className={rootClassName}\n controller={controller}\n ref={ref}\n aria-labelledby={generatedId}\n {...overlayProps}\n >\n <PropsContextProvider props={propsContext}>\n <Wrap if={offCanvas}>\n <Suspense fallback={<OffCanvasSuspenseFallback />}>\n {children}\n </Suspense>\n </Wrap>\n </PropsContextProvider>\n <ConfirmUnsavedChangesModal />\n </Overlay>\n );\n});\n\nexport default Modal;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAkEA,IAAa,QAAQ,cAAc,UAAU,UAAU;CACrD,MAAM,EACJ,OAAO,KACP,WACA,YACA,UACA,KACA,WACA,uBAAuB,SACvB,iBACA,GAAG,iBACD;CAEJ,MAAM,kBAAkB,4BAA4B,kBAAS,OAAO;CAKpE,MAAM,kBAAkB,0BAA0B;CAElD,MAAM,gBAAgB,KACpB,YAAY,qBAAO,YAAY,qBAAO,OACtC,qBAAO,QAAQ,SACf,yBAAyB,UAAU,qBAAO,SAC1C,mBAAmB,qBAAO,iBAC1B,SACF;CAEA,MAAM,cAAc,MAAM;CAE1B,MAAM,UAAU,aACd,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,SAAD;EAAS,WAAW,qBAAO;EAAc;CAAkB,CAAA,GAC3D,oBAAC,mBAAD,EAAA,UACE,oBAAC,uBAAD,EAAA,UACE,oBAAC,QAAD;EAAQ,YAAY,EAAE,oBAAoB,KAAK;EAC7C,UAAA,oBAAC,YAAD;GACE,SAAQ;GACR,OAAM;GACN,cAAY,gBAAgB,OAAO,OAAO;GAC1C,WAAW,KACT,qBAAO,aACP,oBAAoB,OAChB,qBAAO,gBACP,oBAAoB,QAClB,qBAAO,eACP,KAAA,CACR;GAEA,UAAA,oBAAC,WAAD,CAAY,CAAA;EACF,CAAA;CACN,CAAA,EACa,CAAA,EACN,CAAA,CACnB,EAAA,CAAA;CAGJ,MAAM,qBAAqB;CAE3B,MAAM,qBAAmC;EACvC,SAAS,EAAE,OAAO,mBAAmB;EACrC,SAAS;GACP,QAAQ,EAAE,SAAS,EAAE,OAAO,mBAAmB,EAAE;GACjD,SAAS,EAAE,OAAO,mBAAmB;GACrC,eAAe;EACjB;EACA,QAAQ,EAAE,SAAS,EAAE,OAAO,mBAAmB,EAAE;CACnD;CAEA,MAAM,eAA6B;EACjC,SAAS;GACP,GAAG;GACH,WAAW,qBAAO;EACpB;EACA,cAAc;GACZ,GAAG;GACH,GAAG,CAAC,GAAG,CAAC;GACR,GAAG,CAAC,CAAC;GACL,WAAW,qBAAO;GAClB,WAAW;IAAE,WAAW,qBAAO;IAAW,iBAAiB;GAAU;GACrE,UAAU,oBAAC,mBAAD,CAAoB,CAAA;EAChC;EACA,SAAS;GACP,WAAW,qBAAO;GAClB,OAAO;GACP,UAAU,SAAS,UAAU,OAAO,MAAM,QAAQ,CAAC;GACnD,IAAI;EACN;EACA,aAAa;GACX,WAAW,qBAAO;GAClB,SAAS;GACT,QAAQ;IACN,YAAY,SAAS,UAAU;KAC7B,IAAI,MAAM,eAAe,KAAA,GACvB;KAEF,IAAI,MAAM,eAAe,MACvB,OAAO,EAAE,oBAAoB,KAAK;KAEpC,OAAO;MACL,oBAAoB;MACpB,GAAG,MAAM;KACX;IACF,CAAC;IACD,cAAc,SAAS,UAAU;KAC/B,IAAI,MAAM,iBAAiB,KAAA,GACzB;KAEF,IACE,MAAM,wBAAwB,qBAC9B,OAAO,MAAM,iBAAiB,UAE9B,OAAO;MACL,oBAAoB;MACpB,SAAS,MAAM;KACjB;KAEF,OAAO;MACL,oBAAoB;MACpB,GAAG,MAAM;KACX;IACF,CAAC;GACH;EACF;CACF;CAEA,OACE,qBAAC,SAAD;EACE,WAAW;EACC;EACP;EACL,mBAAiB;EACjB,GAAI;EALN,UAAA,CAOE,oBAAC,sBAAD;GAAsB,OAAO;GAC3B,UAAA,oBAAC,MAAD;IAAM,IAAI;IACR,UAAA,oBAAC,UAAD;KAAU,UAAU,oBAAC,2BAAD,CAA4B,CAAA;KAC7C;IACO,CAAA;GACN,CAAA;EACc,CAAA,GACtB,oBAAC,4BAAD,CAA6B,CAAA,CACtB;;AAEb,CAAC"}
1
+ {"version":3,"file":"Modal.mjs","names":[],"sources":["../../../../../../../src/components/Modal/Modal.tsx"],"sourcesContent":["import { type PropsWithChildren, type ReactNode, Suspense, useId } from \"react\";\nimport styles from \"./Modal.module.scss\";\nimport clsx from \"clsx\";\nimport {\n dynamic,\n type PropsContext,\n PropsContextProvider,\n} from \"@/lib/propsContext\";\nimport { OverlayController } from \"@/lib/controller/overlay\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport { Overlay, type OverlayProps } from \"@/components/Overlay/Overlay\";\nimport { Action } from \"@/components/Action\";\nimport { IconClose } from \"@/components/Icon/components/icons\";\nimport type { PropsWithClassName } from \"@/lib/types/props\";\nimport ButtonView from \"@/views/ButtonView\";\nimport DivView from \"@/views/DivView\";\nimport { OffCanvasSuspenseFallback } from \"@/components/Modal/components/OffCanvasSuspenseFallback\";\nimport { ConfirmUnsavedChangesModal } from \"@/components/Modal/components/ConfirmUnsavedChangesModal/ConfirmUnsavedChangesModal\";\nimport Wrap from \"@/components/Wrap\";\nimport { ClearPropsContext } from \"@/components/ClearPropsContext/ClearPropsContext\";\nimport ClearPropsContextView from \"@/views/ClearPropsContextView\";\nimport { useLocalizedStringFormatter } from \"@/components/TranslationProvider\";\nimport { useVirtualKeyboardVisible } from \"@/lib/hooks/dom/useVirtualKeyboardVisible\";\nimport locales from \"./locales/*.locale.json\";\n\ntype SupportedOverlayProps = Pick<\n OverlayProps,\n \"isOpen\" | \"isDefaultOpen\" | \"onOpen\" | \"onClose\" | \"onOpenChange\"\n>;\n\nexport interface ModalProps\n extends\n PropsWithChildren,\n FlowComponentProps,\n PropsWithClassName,\n SupportedOverlayProps {\n /** The size of the modal. @default \"s\" */\n size?: \"s\" | \"m\" | \"l\";\n /** Whether the modal should be displayed as an off canvas. */\n offCanvas?: boolean;\n /**\n * Whether the off canvas should be displayed on the right or left side of the\n * screen. @default \"right\"\n */\n offCanvasOrientation?: \"left\" | \"right\";\n /** An overlay controller to control the modal state. */\n controller?: OverlayController;\n /**\n * Accepts \"actionConfirm\" to use the modal as a confirmation modal for an\n * action.\n */\n slot?: string;\n /** Whether the modal can be closed by clicking outside of it. */\n isDismissable?: boolean;\n /** Whether the close button should be visible */\n showCloseButton?: boolean;\n /**\n * Whether closing the modal must be confirmed – use it to protect unsaved\n * changes. `false` does not switch off the confirmation of a dirty `Form`\n * inside the modal; set `confirmModalCloseOnUnsavedChanges={false}` on the\n * `Form` for that.\n */\n confirmOnClose?: boolean;\n}\n\nexport const Modal = flowComponent(\"Modal\", (props) => {\n const {\n size = \"s\",\n offCanvas,\n controller,\n children,\n ref,\n className,\n offCanvasOrientation = \"right\",\n showCloseButton,\n ...overlayProps\n } = props;\n\n const stringFormatter = useLocalizedStringFormatter(locales, \"Modal\");\n\n // On mobile the header/footer are docked (sticky) while at rest, but flow\n // normally while the on-screen keyboard is open so the content gets the full\n // available space (see Modal.module.scss). #2423\n const keyboardVisible = useVirtualKeyboardVisible();\n\n const rootClassName = clsx(\n offCanvas ? styles.offCanvas : styles.modal,\n styles[`size-${size}`],\n offCanvasOrientation === \"left\" && styles[\"left\"],\n keyboardVisible && styles.keyboardVisible,\n className,\n );\n\n const generatedId = useId();\n\n const header = (children: ReactNode) => (\n <>\n <DivView className={styles.headerTitle}>{children}</DivView>\n <ClearPropsContext>\n <ClearPropsContextView>\n <Action closeModal={{ bypassConfirmation: true }}>\n <ButtonView\n variant=\"plain\"\n color=\"secondary\"\n aria-label={stringFormatter.format(\"close\")}\n className={clsx(\n styles.closeButton,\n showCloseButton === true\n ? styles.alwaysVisible\n : showCloseButton === false\n ? styles.alwaysHidden\n : undefined,\n )}\n >\n <IconClose />\n </ButtonView>\n </Action>\n </ClearPropsContextView>\n </ClearPropsContext>\n </>\n );\n\n const nestedHeadingLevel = 3;\n\n const nestedHeadingProps: PropsContext = {\n Heading: { level: nestedHeadingLevel },\n Section: {\n Header: { Heading: { level: nestedHeadingLevel } },\n Heading: { level: nestedHeadingLevel },\n hideSeparator: true,\n },\n Header: { Heading: { level: nestedHeadingLevel } },\n };\n\n const propsContext: PropsContext = {\n Content: {\n ...nestedHeadingProps,\n className: styles.content,\n },\n ColumnLayout: {\n ...nestedHeadingProps,\n l: [2, 1],\n m: [1],\n className: styles.columnLayout,\n AccentBox: { className: styles.accentBox, backgroundColor: \"neutral\" },\n wrapWith: <ClearPropsContext />,\n },\n Heading: {\n className: styles.header,\n level: 2,\n children: dynamic((props) => header(props.children)),\n id: generatedId,\n },\n ActionGroup: {\n className: styles.actionGroup,\n spacing: \"m\",\n Action: {\n closeModal: dynamic((props) => {\n if (props.closeModal === undefined) {\n return;\n }\n if (props.closeModal === true) {\n return { bypassConfirmation: true };\n }\n return {\n bypassConfirmation: true,\n ...props.closeModal,\n };\n }),\n closeOverlay: dynamic((props) => {\n const { closeOverlay } = props;\n if (closeOverlay === undefined || closeOverlay === false) {\n return closeOverlay;\n }\n // `true` keeps its \"the nearest overlay\" meaning by leaving `overlay`\n // unset – the options object means the same thing.\n if (closeOverlay === true) {\n return { bypassConfirmation: true };\n }\n if (\n closeOverlay instanceof OverlayController ||\n typeof closeOverlay === \"string\"\n ) {\n return {\n bypassConfirmation: true,\n overlay: closeOverlay,\n };\n }\n return {\n bypassConfirmation: true,\n ...closeOverlay,\n };\n }),\n },\n },\n };\n\n return (\n <Overlay\n className={rootClassName}\n controller={controller}\n ref={ref}\n aria-labelledby={generatedId}\n {...overlayProps}\n >\n <PropsContextProvider props={propsContext}>\n <Wrap if={offCanvas}>\n <Suspense fallback={<OffCanvasSuspenseFallback />}>\n {children}\n </Suspense>\n </Wrap>\n </PropsContextProvider>\n <ConfirmUnsavedChangesModal />\n </Overlay>\n );\n});\n\nexport default Modal;\n"],"mappings":"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"}
@@ -31,6 +31,7 @@ var OverlayTrigger = (props) => {
31
31
  return /* @__PURE__ */ jsx(OverlayContextProvider, {
32
32
  type: overlayType,
33
33
  controller: overlayController,
34
+ isOverlayContent: false,
34
35
  children: /* @__PURE__ */ jsx(PropsContextProvider, {
35
36
  props: propsContext,
36
37
  dependencies: [isPending, overlayController],
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayTrigger.mjs","names":[],"sources":["../../../../../../../src/components/OverlayTrigger/OverlayTrigger.tsx"],"sourcesContent":["import type { ComponentType, FC, PropsWithChildren, ReactNode } from \"react\";\nimport { OverlayController } from \"@/lib/controller\";\nimport type { PropsContext } from \"@/lib/propsContext\";\nimport { PropsContextProvider } from \"@/lib/propsContext\";\nimport { useComponentPropsContext } from \"@/lib/propsContext/propsContext\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\nimport OverlayContextProvider from \"@/lib/controller/overlay/OverlayContextProvider\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { useIsPendingWithWait } from \"@/components/Action/hooks/useIsPendingWithWait\";\n\ntype AriaComponentType = ComponentType<{\n isOpen?: boolean;\n children: ReactNode;\n}>;\n\nexport interface OverlayTriggerProps\n extends FlowComponentProps, PropsWithChildren {\n /** Whether the overlay should be open initially. */\n isDefaultOpen?: boolean;\n /** A controller to control the state of the overlay. */\n controller?: OverlayController;\n}\n\ninterface Props extends OverlayTriggerProps {\n overlayType: FlowComponentName;\n component: AriaComponentType;\n}\n\nexport const OverlayTrigger: FC<Props> = (props) => {\n const {\n overlayType,\n isDefaultOpen = false,\n component: AriaOverlayTrigger,\n children,\n controller: controllerFromProps,\n } = props;\n const buttonPropsContext = useComponentPropsContext(\"Button\");\n\n const newOverlayController = OverlayController.useNew({ isDefaultOpen });\n const overlayController = controllerFromProps ?? newOverlayController;\n const isOpen = overlayController.useIsOpen();\n const isContentSuspended = overlayController.useIsContentSuspended();\n const isPending = useIsPendingWithWait(isContentSuspended);\n\n const propsContext: PropsContext = {\n Button: {\n onPress: overlayController.open,\n isPending,\n isDisabled: Boolean(buttonPropsContext?.isDisabled) || isContentSuspended,\n /*\n * The button is the react-aria trigger. react-aria hands the press\n * handling, the trigger ref and `aria-haspopup`/`aria-expanded`/\n * `aria-controls` down through a `PressResponder`, which only reaches its\n * own subtree — so a surrounding props context must not tunnel the button\n * out of the trigger. Such a context has to tunnel the trigger as a whole\n * instead (`overlayTriggersTunneledTo`).\n */\n tunnel: null,\n },\n /*\n * The aria trigger this renders is the host-side identity of every trigger\n * that is not `@flr-generate` (see `overlayTriggersTunneledTo`), so a\n * tunneling props context targets it as well. Here it is already inside the\n * trigger the author wrote — tunneling it again would send the same subtree\n * into the exit twice.\n */\n DialogTrigger: {\n tunnel: null,\n },\n /*\n * The overlay is already placed — this trigger owns it. A surrounding\n * props context that moves or wraps the bare overlay, so that it can be\n * written without a trigger (`Badge`), must not reach this one: it would\n * pull the overlay out of its trigger and add a second trigger button\n * around it.\n */\n [overlayType]: {\n tunnel: null,\n wrapWith: null,\n },\n };\n\n return (\n <OverlayContextProvider type={overlayType} controller={overlayController}>\n <PropsContextProvider\n props={propsContext}\n dependencies={[isPending, overlayController]}\n >\n <AriaOverlayTrigger isOpen={isOpen}>{children}</AriaOverlayTrigger>\n </PropsContextProvider>\n </OverlayContextProvider>\n );\n};\n\nexport default OverlayTrigger;\n"],"mappings":";;;;;;;;;AA4BA,IAAa,kBAA6B,UAAU;CAClD,MAAM,EACJ,aACA,gBAAgB,OAChB,WAAW,oBACX,UACA,YAAY,wBACV;CACJ,MAAM,qBAAqB,yBAAyB,QAAQ;CAE5D,MAAM,uBAAuB,kBAAkB,OAAO,EAAE,cAAc,CAAC;CACvE,MAAM,oBAAoB,uBAAuB;CACjD,MAAM,SAAS,kBAAkB,UAAU;CAC3C,MAAM,qBAAqB,kBAAkB,sBAAsB;CACnE,MAAM,YAAY,qBAAqB,kBAAkB;CAEzD,MAAM,eAA6B;EACjC,QAAQ;GACN,SAAS,kBAAkB;GAC3B;GACA,YAAY,QAAQ,oBAAoB,UAAU,KAAK;GASvD,QAAQ;EACV;EAQA,eAAe,EACb,QAAQ,KACV;GAQC,cAAc;GACb,QAAQ;GACR,UAAU;EACZ;CACF;CAEA,OACE,oBAAC,wBAAD;EAAwB,MAAM;EAAa,YAAY;EACrD,UAAA,oBAAC,sBAAD;GACE,OAAO;GACP,cAAc,CAAC,WAAW,iBAAiB;GAE3C,UAAA,oBAAC,oBAAD;IAA4B;IAAS;GAA6B,CAAA;EAC9C,CAAA;CACA,CAAA;AAE5B"}
1
+ {"version":3,"file":"OverlayTrigger.mjs","names":[],"sources":["../../../../../../../src/components/OverlayTrigger/OverlayTrigger.tsx"],"sourcesContent":["import type { ComponentType, FC, PropsWithChildren, ReactNode } from \"react\";\nimport { OverlayController } from \"@/lib/controller\";\nimport type { PropsContext } from \"@/lib/propsContext\";\nimport { PropsContextProvider } from \"@/lib/propsContext\";\nimport { useComponentPropsContext } from \"@/lib/propsContext/propsContext\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\nimport OverlayContextProvider from \"@/lib/controller/overlay/OverlayContextProvider\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { useIsPendingWithWait } from \"@/components/Action/hooks/useIsPendingWithWait\";\n\ntype AriaComponentType = ComponentType<{\n isOpen?: boolean;\n children: ReactNode;\n}>;\n\nexport interface OverlayTriggerProps\n extends FlowComponentProps, PropsWithChildren {\n /** Whether the overlay should be open initially. */\n isDefaultOpen?: boolean;\n /** A controller to control the state of the overlay. */\n controller?: OverlayController;\n}\n\ninterface Props extends OverlayTriggerProps {\n overlayType: FlowComponentName;\n component: AriaComponentType;\n}\n\nexport const OverlayTrigger: FC<Props> = (props) => {\n const {\n overlayType,\n isDefaultOpen = false,\n component: AriaOverlayTrigger,\n children,\n controller: controllerFromProps,\n } = props;\n const buttonPropsContext = useComponentPropsContext(\"Button\");\n\n const newOverlayController = OverlayController.useNew({ isDefaultOpen });\n const overlayController = controllerFromProps ?? newOverlayController;\n const isOpen = overlayController.useIsOpen();\n const isContentSuspended = overlayController.useIsContentSuspended();\n const isPending = useIsPendingWithWait(isContentSuspended);\n\n const propsContext: PropsContext = {\n Button: {\n onPress: overlayController.open,\n isPending,\n isDisabled: Boolean(buttonPropsContext?.isDisabled) || isContentSuspended,\n /*\n * The button is the react-aria trigger. react-aria hands the press\n * handling, the trigger ref and `aria-haspopup`/`aria-expanded`/\n * `aria-controls` down through a `PressResponder`, which only reaches its\n * own subtree — so a surrounding props context must not tunnel the button\n * out of the trigger. Such a context has to tunnel the trigger as a whole\n * instead (`overlayTriggersTunneledTo`).\n */\n tunnel: null,\n },\n /*\n * The aria trigger this renders is the host-side identity of every trigger\n * that is not `@flr-generate` (see `overlayTriggersTunneledTo`), so a\n * tunneling props context targets it as well. Here it is already inside the\n * trigger the author wrote — tunneling it again would send the same subtree\n * into the exit twice.\n */\n DialogTrigger: {\n tunnel: null,\n },\n /*\n * The overlay is already placed — this trigger owns it. A surrounding\n * props context that moves or wraps the bare overlay, so that it can be\n * written without a trigger (`Badge`), must not reach this one: it would\n * pull the overlay out of its trigger and add a second trigger button\n * around it.\n */\n [overlayType]: {\n tunnel: null,\n wrapWith: null,\n },\n };\n\n return (\n <OverlayContextProvider\n type={overlayType}\n controller={overlayController}\n isOverlayContent={false}\n >\n <PropsContextProvider\n props={propsContext}\n dependencies={[isPending, overlayController]}\n >\n <AriaOverlayTrigger isOpen={isOpen}>{children}</AriaOverlayTrigger>\n </PropsContextProvider>\n </OverlayContextProvider>\n );\n};\n\nexport default OverlayTrigger;\n"],"mappings":";;;;;;;;;AA4BA,IAAa,kBAA6B,UAAU;CAClD,MAAM,EACJ,aACA,gBAAgB,OAChB,WAAW,oBACX,UACA,YAAY,wBACV;CACJ,MAAM,qBAAqB,yBAAyB,QAAQ;CAE5D,MAAM,uBAAuB,kBAAkB,OAAO,EAAE,cAAc,CAAC;CACvE,MAAM,oBAAoB,uBAAuB;CACjD,MAAM,SAAS,kBAAkB,UAAU;CAC3C,MAAM,qBAAqB,kBAAkB,sBAAsB;CACnE,MAAM,YAAY,qBAAqB,kBAAkB;CAEzD,MAAM,eAA6B;EACjC,QAAQ;GACN,SAAS,kBAAkB;GAC3B;GACA,YAAY,QAAQ,oBAAoB,UAAU,KAAK;GASvD,QAAQ;EACV;EAQA,eAAe,EACb,QAAQ,KACV;GAQC,cAAc;GACb,QAAQ;GACR,UAAU;EACZ;CACF;CAEA,OACE,oBAAC,wBAAD;EACE,MAAM;EACN,YAAY;EACZ,kBAAkB;EAElB,UAAA,oBAAC,sBAAD;GACE,OAAO;GACP,cAAc,CAAC,WAAW,iBAAiB;GAE3C,UAAA,oBAAC,oBAAD;IAA4B;IAAS;GAA6B,CAAA;EAC9C,CAAA;CACA,CAAA;AAE5B"}
@@ -28,9 +28,8 @@ var useCollapsingItems = () => {
28
28
  if (!list || !more || !container) return;
29
29
  const items = Array.from(list.children).filter((child) => child instanceof HTMLElement);
30
30
  const containerStyle = window.getComputedStyle(container);
31
- const scale = container.offsetWidth > 0 ? container.getBoundingClientRect().width / container.offsetWidth : 1;
32
31
  const availableWidth = container.clientWidth - (parseFloat(containerStyle.paddingInlineStart) || 0) - (parseFloat(containerStyle.paddingInlineEnd) || 0);
33
- const visibleCount = getVisibleItemCount(items.map((item) => item.getBoundingClientRect().width / scale), availableWidth, more.getBoundingClientRect().width / scale);
32
+ const visibleCount = getVisibleItemCount(items.map((item) => item.getBoundingClientRect().width), availableWidth, more.getBoundingClientRect().width);
34
33
  items.forEach((item, index) => {
35
34
  item.style.visibility = index < visibleCount ? "" : "hidden";
36
35
  });
@@ -1 +1 @@
1
- {"version":3,"file":"useCollapsingItems.mjs","names":[],"sources":["../../../../../../../../src/components/TabNavigation/lib/useCollapsingItems.ts"],"sourcesContent":["import type { RefObject } from \"react\";\nimport { useCallback, useLayoutEffect, useRef, useState } from \"react\";\nimport { createFrameResizeObserver } from \"@/lib/dom/createFrameResizeObserver\";\nimport { getVisibleItemCount } from \"./getVisibleItemCount\";\n\ninterface CollapsingItemsState {\n /** Number of visible items. `null` until the first measurement was done. */\n visibleCount: number | null;\n /** Whether at least one item does not fit and is collapsed. */\n hasOverflow: boolean;\n /** Whether one of the collapsed items contains the current page link. */\n menuHasCurrentItem: boolean;\n}\n\ninterface UseCollapsingItemsReturn extends CollapsingItemsState {\n listRef: RefObject<HTMLUListElement | null>;\n moreRef: RefObject<HTMLDivElement | null>;\n}\n\nconst initialState: CollapsingItemsState = {\n visibleCount: null,\n hasOverflow: false,\n menuHasCurrentItem: false,\n};\n\n/**\n * Observes the items of the list and computes how many of them fit into the\n * available width of the list's parent element. Items that do not fit are\n * hidden via `visibility: hidden` (removes them from the accessibility tree and\n * the tab order while keeping them measurable). The width of the \"more\" element\n * is reserved whenever items are collapsed, so it must always be rendered\n * (visually hidden when there is no overflow).\n */\nexport const useCollapsingItems = (): UseCollapsingItemsReturn => {\n const listRef = useRef<HTMLUListElement>(null);\n const moreRef = useRef<HTMLDivElement>(null);\n\n const [state, setState] = useState(initialState);\n\n const update = useCallback(() => {\n const list = listRef.current;\n const more = moreRef.current;\n const container = list?.parentElement;\n\n if (!list || !more || !container) {\n return;\n }\n\n const items = Array.from(list.children).filter(\n (child): child is HTMLElement => child instanceof HTMLElement,\n );\n\n const containerStyle = window.getComputedStyle(container);\n /*\n * `clientWidth` and a computed padding are layout pixels, while\n * `getBoundingClientRect` below reports rendered ones. Where an ancestor\n * scales the subtree — a `transform`, a CSS `zoom` — comparing the two\n * overstates the room by the scale factor, and the items stay visible\n * instead of collapsing. The container's own two border-box widths give\n * the factor; `clientWidth` would be off by the border.\n */\n const scale =\n container.offsetWidth > 0\n ? container.getBoundingClientRect().width / container.offsetWidth\n : 1;\n\n const availableWidth =\n container.clientWidth -\n (parseFloat(containerStyle.paddingInlineStart) || 0) -\n (parseFloat(containerStyle.paddingInlineEnd) || 0);\n\n const visibleCount = getVisibleItemCount(\n items.map((item) => item.getBoundingClientRect().width / scale),\n availableWidth,\n more.getBoundingClientRect().width / scale,\n );\n\n items.forEach((item, index) => {\n item.style.visibility = index < visibleCount ? \"\" : \"hidden\";\n });\n\n const menuHasCurrentItem = items\n .slice(visibleCount)\n .some(\n (item) =>\n !!item.querySelector('[aria-current]:not([aria-current=\"false\"])'),\n );\n\n setState((previous) => {\n const next: CollapsingItemsState = {\n visibleCount,\n hasOverflow: visibleCount < items.length,\n menuHasCurrentItem,\n };\n\n const isUnchanged =\n previous.visibleCount === next.visibleCount &&\n previous.hasOverflow === next.hasOverflow &&\n previous.menuHasCurrentItem === next.menuHasCurrentItem;\n\n return isUnchanged ? previous : next;\n });\n }, []);\n\n // Runs after every render (no dependency array): the rendered items may\n // have changed, so the observed elements are re-collected and re-measured.\n // `update()` only triggers a re-render when the computed state changed.\n useLayoutEffect(() => {\n const list = listRef.current;\n const more = moreRef.current;\n const container = list?.parentElement;\n\n if (!list || !more || !container) {\n return;\n }\n\n const observer = createFrameResizeObserver(update);\n observer.observe([container, more, ...list.children]);\n\n update();\n\n return () => observer.disconnect();\n });\n\n return { ...state, listRef, moreRef };\n};\n\nexport default useCollapsingItems;\n"],"mappings":";;;;;;AAmBA,IAAM,eAAqC;CACzC,cAAc;CACd,aAAa;CACb,oBAAoB;AACtB;;;;;;;;;AAUA,IAAa,2BAAqD;CAChE,MAAM,UAAU,OAAyB,IAAI;CAC7C,MAAM,UAAU,OAAuB,IAAI;CAE3C,MAAM,CAAC,OAAO,YAAY,SAAS,YAAY;CAE/C,MAAM,SAAS,kBAAkB;EAC/B,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,QAAQ;EACrB,MAAM,YAAY,MAAM;EAExB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,WACrB;EAGF,MAAM,QAAQ,MAAM,KAAK,KAAK,QAAQ,CAAC,CAAC,QACrC,UAAgC,iBAAiB,WACpD;EAEA,MAAM,iBAAiB,OAAO,iBAAiB,SAAS;EASxD,MAAM,QACJ,UAAU,cAAc,IACpB,UAAU,sBAAsB,CAAC,CAAC,QAAQ,UAAU,cACpD;EAEN,MAAM,iBACJ,UAAU,eACT,WAAW,eAAe,kBAAkB,KAAK,MACjD,WAAW,eAAe,gBAAgB,KAAK;EAElD,MAAM,eAAe,oBACnB,MAAM,KAAK,SAAS,KAAK,sBAAsB,CAAC,CAAC,QAAQ,KAAK,GAC9D,gBACA,KAAK,sBAAsB,CAAC,CAAC,QAAQ,KACvC;EAEA,MAAM,SAAS,MAAM,UAAU;GAC7B,KAAK,MAAM,aAAa,QAAQ,eAAe,KAAK;EACtD,CAAC;EAED,MAAM,qBAAqB,MACxB,MAAM,YAAY,CAAC,CACnB,MACE,SACC,CAAC,CAAC,KAAK,cAAc,8CAA4C,CACrE;EAEF,UAAU,aAAa;GACrB,MAAM,OAA6B;IACjC;IACA,aAAa,eAAe,MAAM;IAClC;GACF;GAOA,OAJE,SAAS,iBAAiB,KAAK,gBAC/B,SAAS,gBAAgB,KAAK,eAC9B,SAAS,uBAAuB,KAAK,qBAElB,WAAW;EAClC,CAAC;CACH,GAAG,CAAC,CAAC;CAKL,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,QAAQ;EACrB,MAAM,YAAY,MAAM;EAExB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,WACrB;EAGF,MAAM,WAAW,0BAA0B,MAAM;EACjD,SAAS,QAAQ;GAAC;GAAW;GAAM,GAAG,KAAK;EAAQ,CAAC;EAEpD,OAAO;EAEP,aAAa,SAAS,WAAW;CACnC,CAAC;CAED,OAAO;EAAE,GAAG;EAAO;EAAS;CAAQ;AACtC"}
1
+ {"version":3,"file":"useCollapsingItems.mjs","names":[],"sources":["../../../../../../../../src/components/TabNavigation/lib/useCollapsingItems.ts"],"sourcesContent":["import type { RefObject } from \"react\";\nimport { useCallback, useLayoutEffect, useRef, useState } from \"react\";\nimport { createFrameResizeObserver } from \"@/lib/dom/createFrameResizeObserver\";\nimport { getVisibleItemCount } from \"./getVisibleItemCount\";\n\ninterface CollapsingItemsState {\n /** Number of visible items. `null` until the first measurement was done. */\n visibleCount: number | null;\n /** Whether at least one item does not fit and is collapsed. */\n hasOverflow: boolean;\n /** Whether one of the collapsed items contains the current page link. */\n menuHasCurrentItem: boolean;\n}\n\ninterface UseCollapsingItemsReturn extends CollapsingItemsState {\n listRef: RefObject<HTMLUListElement | null>;\n moreRef: RefObject<HTMLDivElement | null>;\n}\n\nconst initialState: CollapsingItemsState = {\n visibleCount: null,\n hasOverflow: false,\n menuHasCurrentItem: false,\n};\n\n/**\n * Observes the items of the list and computes how many of them fit into the\n * available width of the list's parent element. Items that do not fit are\n * hidden via `visibility: hidden` (removes them from the accessibility tree and\n * the tab order while keeping them measurable). The width of the \"more\" element\n * is reserved whenever items are collapsed, so it must always be rendered\n * (visually hidden when there is no overflow).\n */\nexport const useCollapsingItems = (): UseCollapsingItemsReturn => {\n const listRef = useRef<HTMLUListElement>(null);\n const moreRef = useRef<HTMLDivElement>(null);\n\n const [state, setState] = useState(initialState);\n\n const update = useCallback(() => {\n const list = listRef.current;\n const more = moreRef.current;\n const container = list?.parentElement;\n\n if (!list || !more || !container) {\n return;\n }\n\n const items = Array.from(list.children).filter(\n (child): child is HTMLElement => child instanceof HTMLElement,\n );\n\n const containerStyle = window.getComputedStyle(container);\n const availableWidth =\n container.clientWidth -\n (parseFloat(containerStyle.paddingInlineStart) || 0) -\n (parseFloat(containerStyle.paddingInlineEnd) || 0);\n\n const visibleCount = getVisibleItemCount(\n items.map((item) => item.getBoundingClientRect().width),\n availableWidth,\n more.getBoundingClientRect().width,\n );\n\n items.forEach((item, index) => {\n item.style.visibility = index < visibleCount ? \"\" : \"hidden\";\n });\n\n const menuHasCurrentItem = items\n .slice(visibleCount)\n .some(\n (item) =>\n !!item.querySelector('[aria-current]:not([aria-current=\"false\"])'),\n );\n\n setState((previous) => {\n const next: CollapsingItemsState = {\n visibleCount,\n hasOverflow: visibleCount < items.length,\n menuHasCurrentItem,\n };\n\n const isUnchanged =\n previous.visibleCount === next.visibleCount &&\n previous.hasOverflow === next.hasOverflow &&\n previous.menuHasCurrentItem === next.menuHasCurrentItem;\n\n return isUnchanged ? previous : next;\n });\n }, []);\n\n // Runs after every render (no dependency array): the rendered items may\n // have changed, so the observed elements are re-collected and re-measured.\n // `update()` only triggers a re-render when the computed state changed.\n useLayoutEffect(() => {\n const list = listRef.current;\n const more = moreRef.current;\n const container = list?.parentElement;\n\n if (!list || !more || !container) {\n return;\n }\n\n const observer = createFrameResizeObserver(update);\n observer.observe([container, more, ...list.children]);\n\n update();\n\n return () => observer.disconnect();\n });\n\n return { ...state, listRef, moreRef };\n};\n\nexport default useCollapsingItems;\n"],"mappings":";;;;;;AAmBA,IAAM,eAAqC;CACzC,cAAc;CACd,aAAa;CACb,oBAAoB;AACtB;;;;;;;;;AAUA,IAAa,2BAAqD;CAChE,MAAM,UAAU,OAAyB,IAAI;CAC7C,MAAM,UAAU,OAAuB,IAAI;CAE3C,MAAM,CAAC,OAAO,YAAY,SAAS,YAAY;CAE/C,MAAM,SAAS,kBAAkB;EAC/B,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,QAAQ;EACrB,MAAM,YAAY,MAAM;EAExB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,WACrB;EAGF,MAAM,QAAQ,MAAM,KAAK,KAAK,QAAQ,CAAC,CAAC,QACrC,UAAgC,iBAAiB,WACpD;EAEA,MAAM,iBAAiB,OAAO,iBAAiB,SAAS;EACxD,MAAM,iBACJ,UAAU,eACT,WAAW,eAAe,kBAAkB,KAAK,MACjD,WAAW,eAAe,gBAAgB,KAAK;EAElD,MAAM,eAAe,oBACnB,MAAM,KAAK,SAAS,KAAK,sBAAsB,CAAC,CAAC,KAAK,GACtD,gBACA,KAAK,sBAAsB,CAAC,CAAC,KAC/B;EAEA,MAAM,SAAS,MAAM,UAAU;GAC7B,KAAK,MAAM,aAAa,QAAQ,eAAe,KAAK;EACtD,CAAC;EAED,MAAM,qBAAqB,MACxB,MAAM,YAAY,CAAC,CACnB,MACE,SACC,CAAC,CAAC,KAAK,cAAc,8CAA4C,CACrE;EAEF,UAAU,aAAa;GACrB,MAAM,OAA6B;IACjC;IACA,aAAa,eAAe,MAAM;IAClC;GACF;GAOA,OAJE,SAAS,iBAAiB,KAAK,gBAC/B,SAAS,gBAAgB,KAAK,eAC9B,SAAS,uBAAuB,KAAK,qBAElB,WAAW;EAClC,CAAC;CACH,GAAG,CAAC,CAAC;CAKL,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,QAAQ;EACrB,MAAM,YAAY,MAAM;EAExB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,WACrB;EAGF,MAAM,WAAW,0BAA0B,MAAM;EACjD,SAAS,QAAQ;GAAC;GAAW;GAAM,GAAG,KAAK;EAAQ,CAAC;EAEpD,OAAO;EAEP,aAAa,SAAS,WAAW;CACnC,CAAC;CAED,OAAO;EAAE,GAAG;EAAO;EAAS;CAAQ;AACtC"}
@@ -31,10 +31,9 @@ var useTabIndicator = (isCollapsed) => {
31
31
  }
32
32
  const rootRect = root.getBoundingClientRect();
33
33
  const selectedTabRect = selectedTab.getBoundingClientRect();
34
- const scale = root.offsetWidth > 0 ? rootRect.width / root.offsetWidth : 1;
35
34
  const nextIndicator = {
36
- x: (selectedTabRect.left - rootRect.left) / scale,
37
- width: selectedTabRect.width / scale,
35
+ x: selectedTabRect.left - rootRect.left,
36
+ width: selectedTabRect.width,
38
37
  isAnimated: hasMeasuredRef.current
39
38
  };
40
39
  setIndicator((previousIndicator) => {
@@ -1 +1 @@
1
- {"version":3,"file":"useTabIndicator.mjs","names":[],"sources":["../../../../../../../../src/components/Tabs/lib/useTabIndicator.ts"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport { useLayoutEffect, useRef, useState } from \"react\";\nimport { createFrameResizeObserver } from \"@/lib/dom/createFrameResizeObserver\";\n\ninterface TabIndicatorState {\n x: number;\n width: number;\n isAnimated: boolean;\n}\n\ninterface TabIndicatorStyle extends CSSProperties {\n \"--tab-indicator-x\": string;\n \"--tab-indicator-width\": string;\n}\n\nconst getTabIndicatorStyle = (\n state: TabIndicatorState | undefined,\n): TabIndicatorStyle | undefined =>\n state && {\n \"--tab-indicator-x\": `${state.x}px`,\n \"--tab-indicator-width\": `${state.width}px`,\n };\n\nexport const useTabIndicator = (isCollapsed: boolean) => {\n const rootRef = useRef<HTMLDivElement | null>(null);\n const titlesRef = useRef<HTMLDivElement | null>(null);\n const hasMeasuredRef = useRef(false);\n const [indicator, setIndicator] = useState<TabIndicatorState | undefined>();\n\n const resetIndicator = () => {\n hasMeasuredRef.current = false;\n // React bails out of the re-render when the state is already `undefined`.\n setIndicator(undefined);\n };\n\n useLayoutEffect(() => {\n const root = rootRef.current;\n const titles = titlesRef.current;\n\n if (!root || !titles || isCollapsed) {\n resetIndicator();\n return;\n }\n\n const measureIndicator = () => {\n const selectedTab = titles.querySelector<HTMLElement>(\"[data-selected]\");\n\n if (!selectedTab) {\n resetIndicator();\n return;\n }\n\n const rootRect = root.getBoundingClientRect();\n const selectedTabRect = selectedTab.getBoundingClientRect();\n\n /*\n * `getBoundingClientRect` reports rendered pixels, but the custom\n * properties below are read as lengths inside the same subtree. Where an\n * ancestor scales it — a `transform`, a CSS `zoom` — the two differ, and\n * writing the rendered value back scales it a second time. The root's own\n * rendered and layout width give the factor between them.\n */\n const scale =\n root.offsetWidth > 0 ? rootRect.width / root.offsetWidth : 1;\n\n const nextIndicator: TabIndicatorState = {\n x: (selectedTabRect.left - rootRect.left) / scale,\n width: selectedTabRect.width / scale,\n isAnimated: hasMeasuredRef.current,\n };\n\n setIndicator((previousIndicator) => {\n if (\n previousIndicator &&\n previousIndicator.x === nextIndicator.x &&\n previousIndicator.width === nextIndicator.width &&\n previousIndicator.isAnimated === nextIndicator.isAnimated\n ) {\n return previousIndicator;\n }\n\n return nextIndicator;\n });\n\n hasMeasuredRef.current = true;\n };\n\n measureIndicator();\n\n const observer = createFrameResizeObserver(measureIndicator);\n observer.observe([root, titles]);\n\n return () => observer.disconnect();\n });\n\n return {\n rootRef,\n titlesRef,\n indicatorStyle: getTabIndicatorStyle(indicator),\n isAnimated: indicator?.isAnimated ?? false,\n };\n};\n"],"mappings":";;;;;AAeA,IAAM,wBACJ,UAEA,SAAS;CACP,qBAAqB,GAAG,MAAM,EAAE;CAChC,yBAAyB,GAAG,MAAM,MAAM;AAC1C;AAEF,IAAa,mBAAmB,gBAAyB;CACvD,MAAM,UAAU,OAA8B,IAAI;CAClD,MAAM,YAAY,OAA8B,IAAI;CACpD,MAAM,iBAAiB,OAAO,KAAK;CACnC,MAAM,CAAC,WAAW,gBAAgB,SAAwC;CAE1E,MAAM,uBAAuB;EAC3B,eAAe,UAAU;EAEzB,aAAa,KAAA,CAAS;CACxB;CAEA,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,SAAS,UAAU;EAEzB,IAAI,CAAC,QAAQ,CAAC,UAAU,aAAa;GACnC,eAAe;GACf;EACF;EAEA,MAAM,yBAAyB;GAC7B,MAAM,cAAc,OAAO,cAA2B,iBAAiB;GAEvE,IAAI,CAAC,aAAa;IAChB,eAAe;IACf;GACF;GAEA,MAAM,WAAW,KAAK,sBAAsB;GAC5C,MAAM,kBAAkB,YAAY,sBAAsB;GAS1D,MAAM,QACJ,KAAK,cAAc,IAAI,SAAS,QAAQ,KAAK,cAAc;GAE7D,MAAM,gBAAmC;IACvC,IAAI,gBAAgB,OAAO,SAAS,QAAQ;IAC5C,OAAO,gBAAgB,QAAQ;IAC/B,YAAY,eAAe;GAC7B;GAEA,cAAc,sBAAsB;IAClC,IACE,qBACA,kBAAkB,MAAM,cAAc,KACtC,kBAAkB,UAAU,cAAc,SAC1C,kBAAkB,eAAe,cAAc,YAE/C,OAAO;IAGT,OAAO;GACT,CAAC;GAED,eAAe,UAAU;EAC3B;EAEA,iBAAiB;EAEjB,MAAM,WAAW,0BAA0B,gBAAgB;EAC3D,SAAS,QAAQ,CAAC,MAAM,MAAM,CAAC;EAE/B,aAAa,SAAS,WAAW;CACnC,CAAC;CAED,OAAO;EACL;EACA;EACA,gBAAgB,qBAAqB,SAAS;EAC9C,YAAY,WAAW,cAAc;CACvC;AACF"}
1
+ {"version":3,"file":"useTabIndicator.mjs","names":[],"sources":["../../../../../../../../src/components/Tabs/lib/useTabIndicator.ts"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport { useLayoutEffect, useRef, useState } from \"react\";\nimport { createFrameResizeObserver } from \"@/lib/dom/createFrameResizeObserver\";\n\ninterface TabIndicatorState {\n x: number;\n width: number;\n isAnimated: boolean;\n}\n\ninterface TabIndicatorStyle extends CSSProperties {\n \"--tab-indicator-x\": string;\n \"--tab-indicator-width\": string;\n}\n\nconst getTabIndicatorStyle = (\n state: TabIndicatorState | undefined,\n): TabIndicatorStyle | undefined =>\n state && {\n \"--tab-indicator-x\": `${state.x}px`,\n \"--tab-indicator-width\": `${state.width}px`,\n };\n\nexport const useTabIndicator = (isCollapsed: boolean) => {\n const rootRef = useRef<HTMLDivElement | null>(null);\n const titlesRef = useRef<HTMLDivElement | null>(null);\n const hasMeasuredRef = useRef(false);\n const [indicator, setIndicator] = useState<TabIndicatorState | undefined>();\n\n const resetIndicator = () => {\n hasMeasuredRef.current = false;\n // React bails out of the re-render when the state is already `undefined`.\n setIndicator(undefined);\n };\n\n useLayoutEffect(() => {\n const root = rootRef.current;\n const titles = titlesRef.current;\n\n if (!root || !titles || isCollapsed) {\n resetIndicator();\n return;\n }\n\n const measureIndicator = () => {\n const selectedTab = titles.querySelector<HTMLElement>(\"[data-selected]\");\n\n if (!selectedTab) {\n resetIndicator();\n return;\n }\n\n const rootRect = root.getBoundingClientRect();\n const selectedTabRect = selectedTab.getBoundingClientRect();\n const nextIndicator: TabIndicatorState = {\n x: selectedTabRect.left - rootRect.left,\n width: selectedTabRect.width,\n isAnimated: hasMeasuredRef.current,\n };\n\n setIndicator((previousIndicator) => {\n if (\n previousIndicator &&\n previousIndicator.x === nextIndicator.x &&\n previousIndicator.width === nextIndicator.width &&\n previousIndicator.isAnimated === nextIndicator.isAnimated\n ) {\n return previousIndicator;\n }\n\n return nextIndicator;\n });\n\n hasMeasuredRef.current = true;\n };\n\n measureIndicator();\n\n const observer = createFrameResizeObserver(measureIndicator);\n observer.observe([root, titles]);\n\n return () => observer.disconnect();\n });\n\n return {\n rootRef,\n titlesRef,\n indicatorStyle: getTabIndicatorStyle(indicator),\n isAnimated: indicator?.isAnimated ?? false,\n };\n};\n"],"mappings":";;;;;AAeA,IAAM,wBACJ,UAEA,SAAS;CACP,qBAAqB,GAAG,MAAM,EAAE;CAChC,yBAAyB,GAAG,MAAM,MAAM;AAC1C;AAEF,IAAa,mBAAmB,gBAAyB;CACvD,MAAM,UAAU,OAA8B,IAAI;CAClD,MAAM,YAAY,OAA8B,IAAI;CACpD,MAAM,iBAAiB,OAAO,KAAK;CACnC,MAAM,CAAC,WAAW,gBAAgB,SAAwC;CAE1E,MAAM,uBAAuB;EAC3B,eAAe,UAAU;EAEzB,aAAa,KAAA,CAAS;CACxB;CAEA,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,SAAS,UAAU;EAEzB,IAAI,CAAC,QAAQ,CAAC,UAAU,aAAa;GACnC,eAAe;GACf;EACF;EAEA,MAAM,yBAAyB;GAC7B,MAAM,cAAc,OAAO,cAA2B,iBAAiB;GAEvE,IAAI,CAAC,aAAa;IAChB,eAAe;IACf;GACF;GAEA,MAAM,WAAW,KAAK,sBAAsB;GAC5C,MAAM,kBAAkB,YAAY,sBAAsB;GAC1D,MAAM,gBAAmC;IACvC,GAAG,gBAAgB,OAAO,SAAS;IACnC,OAAO,gBAAgB;IACvB,YAAY,eAAe;GAC7B;GAEA,cAAc,sBAAsB;IAClC,IACE,qBACA,kBAAkB,MAAM,cAAc,KACtC,kBAAkB,UAAU,cAAc,SAC1C,kBAAkB,eAAe,cAAc,YAE/C,OAAO;IAGT,OAAO;GACT,CAAC;GAED,eAAe,UAAU;EAC3B;EAEA,iBAAiB;EAEjB,MAAM,WAAW,0BAA0B,gBAAgB;EAC3D,SAAS,QAAQ,CAAC,MAAM,MAAM,CAAC;EAE/B,aAAa,SAAS,WAAW;CACnC,CAAC;CAED,OAAO;EACL;EACA;EACA,gBAAgB,qBAAqB,SAAS;EAC9C,YAAY,WAAW,cAAc;CACvC;AACF"}
@@ -4,12 +4,15 @@ import { overlayContext, useOverlayContext } from "./context.mjs";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/lib/controller/overlay/OverlayContextProvider.tsx
6
6
  var OverlayContextProvider = (props) => {
7
- const { type, controller, children } = props;
7
+ const { type, controller, isOverlayContent = true, children } = props;
8
8
  const parentContext = useOverlayContext();
9
9
  return /* @__PURE__ */ jsx(overlayContext.Provider, {
10
10
  value: {
11
- ...parentContext,
12
- [type]: controller
11
+ byType: {
12
+ ...parentContext.byType,
13
+ [type]: controller
14
+ },
15
+ nearest: isOverlayContent ? controller : parentContext.nearest
13
16
  },
14
17
  children
15
18
  });
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayContextProvider.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayContextProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport {\n overlayContext,\n useOverlayContext,\n} from \"@/lib/controller/overlay/context\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\nimport type { OverlayController } from \"@/lib/controller\";\n\ninterface Props extends PropsWithChildren {\n type: FlowComponentName;\n controller: OverlayController;\n}\n\nexport const OverlayContextProvider: FC<Props> = (props) => {\n const { type, controller, children } = props;\n const parentContext = useOverlayContext();\n\n return (\n <overlayContext.Provider\n value={{\n ...parentContext,\n [type]: controller,\n }}\n >\n {children}\n </overlayContext.Provider>\n );\n};\n\nexport default OverlayContextProvider;\n"],"mappings":";;;;;AAaA,IAAa,0BAAqC,UAAU;CAC1D,MAAM,EAAE,MAAM,YAAY,aAAa;CACvC,MAAM,gBAAgB,kBAAkB;CAExC,OACE,oBAAC,eAAe,UAAhB;EACE,OAAO;GACL,GAAG;IACF,OAAO;EACV;EAEC;CACsB,CAAA;AAE7B"}
1
+ {"version":3,"file":"OverlayContextProvider.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayContextProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport {\n overlayContext,\n useOverlayContext,\n} from \"@/lib/controller/overlay/context\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\nimport type { OverlayController } from \"@/lib/controller\";\n\ninterface Props extends PropsWithChildren {\n type: FlowComponentName;\n controller: OverlayController;\n /**\n * Whether the children are the overlay's content. Content also registers the\n * controller as the _nearest_ overlay, which is what `closeOverlay` without a\n * name resolves to. Set `false` where the subtree is not inside the overlay –\n * `OverlayTrigger` wraps the trigger too.\n *\n * @default true\n */\n isOverlayContent?: boolean;\n}\n\nexport const OverlayContextProvider: FC<Props> = (props) => {\n const { type, controller, isOverlayContent = true, children } = props;\n const parentContext = useOverlayContext();\n\n return (\n <overlayContext.Provider\n value={{\n byType: {\n ...parentContext.byType,\n [type]: controller,\n },\n nearest: isOverlayContent ? controller : parentContext.nearest,\n }}\n >\n {children}\n </overlayContext.Provider>\n );\n};\n\nexport default OverlayContextProvider;\n"],"mappings":";;;;;AAsBA,IAAa,0BAAqC,UAAU;CAC1D,MAAM,EAAE,MAAM,YAAY,mBAAmB,MAAM,aAAa;CAChE,MAAM,gBAAgB,kBAAkB;CAExC,OACE,oBAAC,eAAe,UAAhB;EACE,OAAO;GACL,QAAQ;IACN,GAAG,cAAc;KAChB,OAAO;GACV;GACA,SAAS,mBAAmB,aAAa,cAAc;EACzD;EAEC;CACsB,CAAA;AAE7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayController.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n runInAction,\n} from \"mobx\";\nimport useSelector from \"@/lib/mobx/useSelector\";\nimport { useStatic } from \"@/lib/hooks/useStatic\";\nimport { useEffect, useRef, type DependencyList } from \"react\";\nimport { useCloseOverlayConfirmationController } from \"@/lib/controller/overlay/useCloseOverlayConfirmationController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport type OverlayOpenHandler = () => unknown;\nexport type OverlayCloseHandler = () => unknown;\nexport type OverlayOpenStateHandler = (isOpen: boolean) => unknown;\ntype AnyOverlayOpenStateHandler =\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler;\n\ntype DisposerFn = () => void;\n\nexport interface CloseOverlayOptions {\n overlay: FlowComponentName | OverlayController;\n bypassConfirmation?: boolean;\n}\n\nexport interface OnOverlayClosedOptions {\n dependencies?: DependencyList;\n}\n\nexport type CloseModalOptions = Omit<CloseOverlayOptions, \"overlay\">;\n\ntype CloseOptions = CloseOverlayOptions | CloseModalOptions;\n\nexport interface OverlayControllerOptions {\n isDefaultOpen?: boolean;\n onOpen?: OverlayOpenHandler;\n onClose?: OverlayCloseHandler;\n onOpenChange?: OverlayOpenStateHandler;\n /**\n * Whether closing the overlay must be confirmed. `undefined` means \"no\n * opinion\": the value is not contributed at all, so other sources (e.g. a\n * `Modal`'s `confirmOnClose` prop or a dirty `Form`) still decide.\n */\n confirmOnClose?: boolean;\n}\n\ntype ConstructorOptions = Pick<\n OverlayControllerOptions,\n \"isDefaultOpen\" | \"confirmOnClose\"\n>;\n\nexport class OverlayController {\n public isOpen = false;\n public isContentSuspended = false;\n private onOpenHandlers = new Set<OverlayOpenHandler>();\n private onCloseHandlers = new Set<OverlayCloseHandler>();\n private onOpenChangeHandlers = new Set<OverlayOpenStateHandler>();\n\n public showConfirmationModal = false;\n public closeIsConfirmed = false;\n private readonly confirmOnCloseFromOptions: boolean;\n /**\n * Every mounted component that has an opinion on close confirmation\n * contributes one entry here – e.g. a `Modal` with a `confirmOnClose` prop\n * and a `Form` tracking its dirty state. Combining them instead of assigning\n * a single flag keeps them from overwriting each other.\n */\n private confirmOnCloseSources = observable.map<object, boolean>();\n /**\n * Active grants that allow closing without a confirmation. Each entry is\n * scoped to an ongoing operation that legitimately closes the overlay – e.g.\n * a `Form` submit – and is dropped again when that operation has finished, so\n * an operation that does _not_ close the overlay leaves the confirmation\n * armed.\n */\n private closeWithoutConfirmationGrants = new Set<object>();\n /**\n * The open state a `setOpen` call is currently applying. Handlers run before\n * `isOpen` is assigned, so a handler that calls `setOpen` again would not be\n * caught by the equality check at the top and would recurse.\n */\n private openStateInFlight: boolean | undefined;\n\n public constructor(options: ConstructorOptions = {}) {\n makeObservable(this, {\n isOpen: observable,\n isContentSuspended: observable,\n showConfirmationModal: observable,\n confirmOnCloseEnabled: computed,\n open: action.bound,\n close: action.bound,\n toggle: action.bound,\n setOpen: action.bound,\n syncOpen: action.bound,\n setIsContentSuspended: action.bound,\n confirmClose: action.bound,\n cancelConfirmation: action.bound,\n });\n const { isDefaultOpen = false, confirmOnClose = false } = options;\n this.isOpen = isDefaultOpen;\n this.confirmOnCloseFromOptions = confirmOnClose;\n }\n\n /** Whether closing this overlay currently requires a confirmation. */\n public get confirmOnCloseEnabled(): boolean {\n if (this.confirmOnCloseSources.size === 0) {\n return this.confirmOnCloseFromOptions;\n }\n return Array.from(this.confirmOnCloseSources.values()).some(Boolean);\n }\n\n public useUpdateOptions(options: OverlayControllerOptions = {}): void {\n const { onOpen, onClose, onOpenChange, confirmOnClose } = options;\n\n this.useOnHandler(onOpen, (h) =>\n this.addOpenStateHandler(h, this.onOpenHandlers),\n );\n this.useOnHandler(onClose, (h) =>\n this.addOpenStateHandler(h, this.onCloseHandlers),\n );\n this.useOnHandler(onOpenChange, (h) =>\n this.addOpenStateHandler(h, this.onOpenChangeHandlers),\n );\n\n this.useConfirmOnCloseSource(confirmOnClose);\n }\n\n /**\n * Registers the calling component as a close confirmation source for as long\n * as it is mounted. `undefined` contributes nothing at all.\n */\n private useConfirmOnCloseSource(confirmOnClose: boolean | undefined): void {\n const source = useStatic((): object => ({}));\n\n useEffect(() => {\n if (confirmOnClose === undefined) {\n this.removeConfirmOnCloseSource(source);\n return;\n }\n this.setConfirmOnCloseSource(source, confirmOnClose);\n return () => this.removeConfirmOnCloseSource(source);\n }, [this, source, confirmOnClose]);\n }\n\n private setConfirmOnCloseSource(source: object, confirmOnClose: boolean) {\n runInAction(() => this.confirmOnCloseSources.set(source, confirmOnClose));\n }\n\n private removeConfirmOnCloseSource(source: object) {\n runInAction(() => this.confirmOnCloseSources.delete(source));\n }\n\n /**\n * Can be used to execute a callback when the Overlay has unmounted – means\n * after any closing animation.\n *\n * NOTICE: This hook only works inside the corresponding Overlay!\n */\n public useOnClosed(\n callback: () => unknown,\n options: OnOverlayClosedOptions = {},\n ) {\n const { dependencies = [] } = options;\n const isOpen = this.useIsOpen();\n const wasOpen = useRef(this.isOpen);\n\n this.useUpdateOptions({\n onOpen: () => {\n wasOpen.current = true;\n },\n });\n\n useEffect(() => {\n return () => {\n if (!isOpen && wasOpen.current) {\n wasOpen.current = false;\n callback();\n }\n };\n }, [isOpen, ...dependencies]);\n }\n\n public static useNew(\n options: OverlayControllerOptions = {},\n ): OverlayController {\n const controller = useStatic(() => new OverlayController(options));\n controller.useUpdateOptions(options);\n return controller;\n }\n\n private addOpenStateHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T,\n handlersSet: Set<T>,\n ): DisposerFn {\n handlersSet.add(handler);\n return () => {\n handlersSet.delete(handler);\n };\n }\n\n private useOnHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T | undefined,\n addHandlerFn: (handler: T) => DisposerFn,\n ) {\n useEffect(\n () => (handler ? addHandlerFn(handler) : undefined),\n [handler, this],\n );\n }\n\n private executeHandlers(\n isOpen: boolean,\n handlers: Set<\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler\n >,\n ): boolean {\n const handlerResult = Array.from(handlers).map((handler) =>\n handler(isOpen),\n );\n return handlerResult.some((result) => result === false);\n }\n\n private executeOnClose(): boolean {\n return this.executeHandlers(false, this.onCloseHandlers);\n }\n\n private executeOnOpen(): boolean {\n return this.executeHandlers(true, this.onOpenHandlers);\n }\n\n private executeOnOpenChange(isOpen: boolean): boolean {\n return this.executeHandlers(isOpen, this.onOpenChangeHandlers);\n }\n\n public addOnClose(handler: OverlayCloseHandler) {\n return this.addOpenStateHandler(handler, this.onCloseHandlers);\n }\n\n public addOnOpen(handler: OverlayOpenHandler) {\n return this.addOpenStateHandler(handler, this.onOpenHandlers);\n }\n\n public addOnOpenChange(handler: OverlayOpenStateHandler) {\n return this.addOpenStateHandler(handler, this.onOpenChangeHandlers);\n }\n\n public open(): void {\n this.setOpen(true);\n }\n\n public close(options?: CloseOptions): void {\n this.setOpen(false, options);\n }\n\n public toggle(): void {\n this.setOpen(!this.isOpen);\n }\n\n public setOpen(toOpen: boolean, options: CloseOptions = {}): void {\n if (this.isOpen === toOpen || this.openStateInFlight === toOpen) {\n return;\n }\n\n this.openStateInFlight = toOpen;\n try {\n this.applyOpenState(toOpen, options);\n } finally {\n this.openStateInFlight = undefined;\n }\n }\n\n /**\n * Sets the open state without running any handler. Use it to mirror a\n * controlled `isOpen` prop, whose change comes from the consumer – notifying\n * them of their own state would echo it back.\n */\n public syncOpen(toOpen: boolean): void {\n this.isOpen = toOpen;\n }\n\n private applyOpenState(toOpen: boolean, options: CloseOptions): void {\n const { bypassConfirmation = false } = options;\n\n if (toOpen === false) {\n // The confirmation is a one-shot permission for exactly this close\n // attempt – consume it here instead of only when a close succeeds, so it\n // cannot survive an aborted close and disarm later attempts.\n const closeIsConfirmed = this.closeIsConfirmed;\n this.closeIsConfirmed = false;\n\n if (\n this.confirmOnCloseEnabled &&\n !closeIsConfirmed &&\n this.closeWithoutConfirmationGrants.size === 0 &&\n !bypassConfirmation\n ) {\n this.showConfirmationModal = true;\n return;\n }\n }\n\n let aborted: boolean;\n if (toOpen) {\n aborted = this.executeOnOpen();\n } else {\n aborted = this.executeOnClose();\n }\n if (!aborted) {\n aborted = this.executeOnOpenChange(toOpen);\n }\n\n if (!aborted) {\n this.isOpen = toOpen;\n }\n }\n\n public setIsContentSuspended(to: boolean): void {\n this.isContentSuspended = to;\n }\n\n public useIsOpen() {\n return useSelector(() => this.isOpen);\n }\n\n public useIsContentSuspended() {\n return useSelector(() => this.isContentSuspended);\n }\n\n public useShowConfirmationModal() {\n return useSelector(() => this.showConfirmationModal);\n }\n\n public useConfirmOnCloseEnabled() {\n return useSelector(() => this.confirmOnCloseEnabled);\n }\n\n public useConfirmationController() {\n return useCloseOverlayConfirmationController(this);\n }\n\n /**\n * Allows closing this overlay without a confirmation until the returned\n * disposer is called. Use it around an operation that may legitimately close\n * the overlay – e.g. a `Form` submit, where a \"discard unsaved changes?\"\n * prompt would be nonsense – and dispose it as soon as that operation has\n * finished. An operation that ends without closing the overlay therefore\n * leaves the confirmation armed (#2775).\n */\n public grantCloseWithoutConfirmation(): DisposerFn {\n const grant = {};\n this.closeWithoutConfirmationGrants.add(grant);\n return () => {\n this.closeWithoutConfirmationGrants.delete(grant);\n };\n }\n\n public confirmClose(): void {\n this.closeIsConfirmed = true;\n this.showConfirmationModal = false;\n }\n\n public cancelConfirmation(): void {\n this.showConfirmationModal = false;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayController.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n runInAction,\n} from \"mobx\";\nimport useSelector from \"@/lib/mobx/useSelector\";\nimport { useStatic } from \"@/lib/hooks/useStatic\";\nimport { useEffect, useRef, type DependencyList } from \"react\";\nimport { useCloseOverlayConfirmationController } from \"@/lib/controller/overlay/useCloseOverlayConfirmationController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport type OverlayOpenHandler = () => unknown;\nexport type OverlayCloseHandler = () => unknown;\nexport type OverlayOpenStateHandler = (isOpen: boolean) => unknown;\ntype AnyOverlayOpenStateHandler =\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler;\n\ntype DisposerFn = () => void;\n\nexport interface CloseOverlayOptions {\n /**\n * The overlay to close. Omitted, the nearest enclosing overlay is closed –\n * the same thing `closeOverlay={true}` means.\n */\n overlay?: FlowComponentName | OverlayController;\n bypassConfirmation?: boolean;\n}\n\nexport interface OnOverlayClosedOptions {\n dependencies?: DependencyList;\n}\n\nexport type CloseModalOptions = Omit<CloseOverlayOptions, \"overlay\">;\n\n/**\n * Every way an action can point at an overlay: by the Flow component name it\n * registers under, by controller, by options, or with `true` – the nearest\n * enclosing overlay, whatever its name.\n */\nexport type OverlayReference =\n FlowComponentName | OverlayController | CloseOverlayOptions | true;\n\ntype CloseOptions = CloseOverlayOptions | CloseModalOptions;\n\nexport interface OverlayControllerOptions {\n isDefaultOpen?: boolean;\n onOpen?: OverlayOpenHandler;\n onClose?: OverlayCloseHandler;\n onOpenChange?: OverlayOpenStateHandler;\n /**\n * Whether closing the overlay must be confirmed. `undefined` means \"no\n * opinion\": the value is not contributed at all, so other sources (e.g. a\n * `Modal`'s `confirmOnClose` prop or a dirty `Form`) still decide.\n */\n confirmOnClose?: boolean;\n}\n\ntype ConstructorOptions = Pick<\n OverlayControllerOptions,\n \"isDefaultOpen\" | \"confirmOnClose\"\n>;\n\nexport class OverlayController {\n public isOpen = false;\n public isContentSuspended = false;\n private onOpenHandlers = new Set<OverlayOpenHandler>();\n private onCloseHandlers = new Set<OverlayCloseHandler>();\n private onOpenChangeHandlers = new Set<OverlayOpenStateHandler>();\n\n public showConfirmationModal = false;\n public closeIsConfirmed = false;\n private readonly confirmOnCloseFromOptions: boolean;\n /**\n * Every mounted component that has an opinion on close confirmation\n * contributes one entry here – e.g. a `Modal` with a `confirmOnClose` prop\n * and a `Form` tracking its dirty state. Combining them instead of assigning\n * a single flag keeps them from overwriting each other.\n */\n private confirmOnCloseSources = observable.map<object, boolean>();\n /**\n * Active grants that allow closing without a confirmation. Each entry is\n * scoped to an ongoing operation that legitimately closes the overlay – e.g.\n * a `Form` submit – and is dropped again when that operation has finished, so\n * an operation that does _not_ close the overlay leaves the confirmation\n * armed.\n */\n private closeWithoutConfirmationGrants = new Set<object>();\n /**\n * The open state a `setOpen` call is currently applying. Handlers run before\n * `isOpen` is assigned, so a handler that calls `setOpen` again would not be\n * caught by the equality check at the top and would recurse.\n */\n private openStateInFlight: boolean | undefined;\n\n public constructor(options: ConstructorOptions = {}) {\n makeObservable(this, {\n isOpen: observable,\n isContentSuspended: observable,\n showConfirmationModal: observable,\n confirmOnCloseEnabled: computed,\n open: action.bound,\n close: action.bound,\n toggle: action.bound,\n setOpen: action.bound,\n syncOpen: action.bound,\n setIsContentSuspended: action.bound,\n confirmClose: action.bound,\n cancelConfirmation: action.bound,\n });\n const { isDefaultOpen = false, confirmOnClose = false } = options;\n this.isOpen = isDefaultOpen;\n this.confirmOnCloseFromOptions = confirmOnClose;\n }\n\n /** Whether closing this overlay currently requires a confirmation. */\n public get confirmOnCloseEnabled(): boolean {\n if (this.confirmOnCloseSources.size === 0) {\n return this.confirmOnCloseFromOptions;\n }\n return Array.from(this.confirmOnCloseSources.values()).some(Boolean);\n }\n\n public useUpdateOptions(options: OverlayControllerOptions = {}): void {\n const { onOpen, onClose, onOpenChange, confirmOnClose } = options;\n\n this.useOnHandler(onOpen, (h) =>\n this.addOpenStateHandler(h, this.onOpenHandlers),\n );\n this.useOnHandler(onClose, (h) =>\n this.addOpenStateHandler(h, this.onCloseHandlers),\n );\n this.useOnHandler(onOpenChange, (h) =>\n this.addOpenStateHandler(h, this.onOpenChangeHandlers),\n );\n\n this.useConfirmOnCloseSource(confirmOnClose);\n }\n\n /**\n * Registers the calling component as a close confirmation source for as long\n * as it is mounted. `undefined` contributes nothing at all.\n */\n private useConfirmOnCloseSource(confirmOnClose: boolean | undefined): void {\n const source = useStatic((): object => ({}));\n\n useEffect(() => {\n if (confirmOnClose === undefined) {\n this.removeConfirmOnCloseSource(source);\n return;\n }\n this.setConfirmOnCloseSource(source, confirmOnClose);\n return () => this.removeConfirmOnCloseSource(source);\n }, [this, source, confirmOnClose]);\n }\n\n private setConfirmOnCloseSource(source: object, confirmOnClose: boolean) {\n runInAction(() => this.confirmOnCloseSources.set(source, confirmOnClose));\n }\n\n private removeConfirmOnCloseSource(source: object) {\n runInAction(() => this.confirmOnCloseSources.delete(source));\n }\n\n /**\n * Can be used to execute a callback when the Overlay has unmounted – means\n * after any closing animation.\n *\n * NOTICE: This hook only works inside the corresponding Overlay!\n */\n public useOnClosed(\n callback: () => unknown,\n options: OnOverlayClosedOptions = {},\n ) {\n const { dependencies = [] } = options;\n const isOpen = this.useIsOpen();\n const wasOpen = useRef(this.isOpen);\n\n this.useUpdateOptions({\n onOpen: () => {\n wasOpen.current = true;\n },\n });\n\n useEffect(() => {\n return () => {\n if (!isOpen && wasOpen.current) {\n wasOpen.current = false;\n callback();\n }\n };\n }, [isOpen, ...dependencies]);\n }\n\n public static useNew(\n options: OverlayControllerOptions = {},\n ): OverlayController {\n const controller = useStatic(() => new OverlayController(options));\n controller.useUpdateOptions(options);\n return controller;\n }\n\n private addOpenStateHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T,\n handlersSet: Set<T>,\n ): DisposerFn {\n handlersSet.add(handler);\n return () => {\n handlersSet.delete(handler);\n };\n }\n\n private useOnHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T | undefined,\n addHandlerFn: (handler: T) => DisposerFn,\n ) {\n useEffect(\n () => (handler ? addHandlerFn(handler) : undefined),\n [handler, this],\n );\n }\n\n private executeHandlers(\n isOpen: boolean,\n handlers: Set<\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler\n >,\n ): boolean {\n const handlerResult = Array.from(handlers).map((handler) =>\n handler(isOpen),\n );\n return handlerResult.some((result) => result === false);\n }\n\n private executeOnClose(): boolean {\n return this.executeHandlers(false, this.onCloseHandlers);\n }\n\n private executeOnOpen(): boolean {\n return this.executeHandlers(true, this.onOpenHandlers);\n }\n\n private executeOnOpenChange(isOpen: boolean): boolean {\n return this.executeHandlers(isOpen, this.onOpenChangeHandlers);\n }\n\n public addOnClose(handler: OverlayCloseHandler) {\n return this.addOpenStateHandler(handler, this.onCloseHandlers);\n }\n\n public addOnOpen(handler: OverlayOpenHandler) {\n return this.addOpenStateHandler(handler, this.onOpenHandlers);\n }\n\n public addOnOpenChange(handler: OverlayOpenStateHandler) {\n return this.addOpenStateHandler(handler, this.onOpenChangeHandlers);\n }\n\n public open(): void {\n this.setOpen(true);\n }\n\n public close(options?: CloseOptions): void {\n this.setOpen(false, options);\n }\n\n public toggle(): void {\n this.setOpen(!this.isOpen);\n }\n\n public setOpen(toOpen: boolean, options: CloseOptions = {}): void {\n if (this.isOpen === toOpen || this.openStateInFlight === toOpen) {\n return;\n }\n\n this.openStateInFlight = toOpen;\n try {\n this.applyOpenState(toOpen, options);\n } finally {\n this.openStateInFlight = undefined;\n }\n }\n\n /**\n * Sets the open state without running any handler. Use it to mirror a\n * controlled `isOpen` prop, whose change comes from the consumer – notifying\n * them of their own state would echo it back.\n */\n public syncOpen(toOpen: boolean): void {\n this.isOpen = toOpen;\n }\n\n private applyOpenState(toOpen: boolean, options: CloseOptions): void {\n const { bypassConfirmation = false } = options;\n\n if (toOpen === false) {\n // The confirmation is a one-shot permission for exactly this close\n // attempt – consume it here instead of only when a close succeeds, so it\n // cannot survive an aborted close and disarm later attempts.\n const closeIsConfirmed = this.closeIsConfirmed;\n this.closeIsConfirmed = false;\n\n if (\n this.confirmOnCloseEnabled &&\n !closeIsConfirmed &&\n this.closeWithoutConfirmationGrants.size === 0 &&\n !bypassConfirmation\n ) {\n this.showConfirmationModal = true;\n return;\n }\n }\n\n let aborted: boolean;\n if (toOpen) {\n aborted = this.executeOnOpen();\n } else {\n aborted = this.executeOnClose();\n }\n if (!aborted) {\n aborted = this.executeOnOpenChange(toOpen);\n }\n\n if (!aborted) {\n this.isOpen = toOpen;\n }\n }\n\n public setIsContentSuspended(to: boolean): void {\n this.isContentSuspended = to;\n }\n\n public useIsOpen() {\n return useSelector(() => this.isOpen);\n }\n\n public useIsContentSuspended() {\n return useSelector(() => this.isContentSuspended);\n }\n\n public useShowConfirmationModal() {\n return useSelector(() => this.showConfirmationModal);\n }\n\n public useConfirmOnCloseEnabled() {\n return useSelector(() => this.confirmOnCloseEnabled);\n }\n\n public useConfirmationController() {\n return useCloseOverlayConfirmationController(this);\n }\n\n /**\n * Allows closing this overlay without a confirmation until the returned\n * disposer is called. Use it around an operation that may legitimately close\n * the overlay – e.g. a `Form` submit, where a \"discard unsaved changes?\"\n * prompt would be nonsense – and dispose it as soon as that operation has\n * finished. An operation that ends without closing the overlay therefore\n * leaves the confirmation armed (#2775).\n */\n public grantCloseWithoutConfirmation(): DisposerFn {\n const grant = {};\n this.closeWithoutConfirmationGrants.add(grant);\n return () => {\n this.closeWithoutConfirmationGrants.delete(grant);\n };\n }\n\n public confirmClose(): void {\n this.closeIsConfirmed = true;\n this.showConfirmationModal = false;\n }\n\n public cancelConfirmation(): void {\n this.showConfirmationModal = false;\n }\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  /* */
3
3
  import { createContext, useContext } from "react";
4
4
  //#region src/lib/controller/overlay/context.ts
5
- var overlayContext = createContext({});
5
+ var overlayContext = createContext({ byType: {} });
6
6
  var useOverlayContext = () => useContext(overlayContext);
7
7
  //#endregion
8
8
  export { overlayContext, useOverlayContext };
@@ -1 +1 @@
1
- {"version":3,"file":"context.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/context.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport type OverlayContext = Partial<\n Record<FlowComponentName, OverlayController | undefined>\n>;\n\nexport const overlayContext = createContext<OverlayContext>({});\n\nexport const useOverlayContext = (): OverlayContext =>\n useContext(overlayContext);\n"],"mappings":";;;;AAQA,IAAa,iBAAiB,cAA8B,CAAC,CAAC;AAE9D,IAAa,0BACX,WAAW,cAAc"}
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/context.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport interface OverlayContext {\n /**\n * The enclosing overlays' controllers, keyed by the Flow component name the\n * providing overlay registers itself under. Innermost wins per name – a\n * `Modal` inside a `Modal` overwrites the `Modal` entry – but the map does\n * not record which of two differently named overlays is the inner one.\n */\n byType: Partial<Record<FlowComponentName, OverlayController | undefined>>;\n /**\n * The controller of the innermost overlay this subtree is the _content_ of,\n * whatever its component name. `undefined` outside any overlay content.\n *\n * Only providers that wrap overlay content set it. `OverlayTrigger` wraps the\n * trigger as well, so it contributes to `byType` only – an `Action` in the\n * trigger button is not inside the overlay it opens.\n */\n nearest?: OverlayController;\n}\n\nexport const overlayContext = createContext<OverlayContext>({ byType: {} });\n\nexport const useOverlayContext = (): OverlayContext =>\n useContext(overlayContext);\n"],"mappings":";;;;AAuBA,IAAa,iBAAiB,cAA8B,EAAE,QAAQ,CAAC,EAAE,CAAC;AAE1E,IAAa,0BACX,WAAW,cAAc"}
@@ -6,7 +6,7 @@ import { useOverlayContext } from "./context.mjs";
6
6
  var useOverlayController = (overlayType, options = {}) => {
7
7
  const { reuseControllerFromContext = true, ...restControllerOptions } = options;
8
8
  const newController = OverlayController.useNew(restControllerOptions);
9
- const controllerFromContext = useOverlayContext()[overlayType];
9
+ const controllerFromContext = useOverlayContext().byType[overlayType];
10
10
  const controller = reuseControllerFromContext && controllerFromContext ? controllerFromContext : newController;
11
11
  if (controller === controllerFromContext) controller.useUpdateOptions(restControllerOptions);
12
12
  return controller;
@@ -1 +1 @@
1
- {"version":3,"file":"useOverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/useOverlayController.ts"],"sourcesContent":["import { useOverlayContext } from \"@/lib/controller/overlay/context\";\nimport type { OverlayControllerOptions } from \"@/lib/controller/overlay/OverlayController\";\nimport { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport interface UseOverlayControllerOptions extends OverlayControllerOptions {\n reuseControllerFromContext?: boolean;\n}\n\nexport const useOverlayController = (\n overlayType: FlowComponentName,\n options: UseOverlayControllerOptions = {},\n): OverlayController => {\n const { reuseControllerFromContext = true, ...restControllerOptions } =\n options;\n\n const newController = OverlayController.useNew(restControllerOptions);\n const controllerFromContext = useOverlayContext()[overlayType];\n\n const controller =\n reuseControllerFromContext && controllerFromContext\n ? controllerFromContext\n : newController;\n\n if (controller === controllerFromContext) {\n controller.useUpdateOptions(restControllerOptions);\n }\n\n return controller;\n};\n"],"mappings":";;;;;AASA,IAAa,wBACX,aACA,UAAuC,CAAC,MAClB;CACtB,MAAM,EAAE,6BAA6B,MAAM,GAAG,0BAC5C;CAEF,MAAM,gBAAgB,kBAAkB,OAAO,qBAAqB;CACpE,MAAM,wBAAwB,kBAAkB,CAAC,CAAC;CAElD,MAAM,aACJ,8BAA8B,wBAC1B,wBACA;CAEN,IAAI,eAAe,uBACjB,WAAW,iBAAiB,qBAAqB;CAGnD,OAAO;AACT"}
1
+ {"version":3,"file":"useOverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/useOverlayController.ts"],"sourcesContent":["import { useOverlayContext } from \"@/lib/controller/overlay/context\";\nimport type { OverlayControllerOptions } from \"@/lib/controller/overlay/OverlayController\";\nimport { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport interface UseOverlayControllerOptions extends OverlayControllerOptions {\n reuseControllerFromContext?: boolean;\n}\n\nexport const useOverlayController = (\n overlayType: FlowComponentName,\n options: UseOverlayControllerOptions = {},\n): OverlayController => {\n const { reuseControllerFromContext = true, ...restControllerOptions } =\n options;\n\n const newController = OverlayController.useNew(restControllerOptions);\n const controllerFromContext = useOverlayContext().byType[overlayType];\n\n const controller =\n reuseControllerFromContext && controllerFromContext\n ? controllerFromContext\n : newController;\n\n if (controller === controllerFromContext) {\n controller.useUpdateOptions(restControllerOptions);\n }\n\n return controller;\n};\n"],"mappings":";;;;;AASA,IAAa,wBACX,aACA,UAAuC,CAAC,MAClB;CACtB,MAAM,EAAE,6BAA6B,MAAM,GAAG,0BAC5C;CAEF,MAAM,gBAAgB,kBAAkB,OAAO,qBAAqB;CACpE,MAAM,wBAAwB,kBAAkB,CAAC,CAAC,OAAO;CAEzD,MAAM,aACJ,8BAA8B,wBAC1B,wBACA;CAEN,IAAI,eAAe,uBACjB,WAAW,iBAAiB,qBAAqB;CAGnD,OAAO;AACT"}
@@ -1099,7 +1099,7 @@ var image = {
1099
1099
  "path": ["image", "border-style"]
1100
1100
  },
1101
1101
  "border-color": {
1102
- "value": "#DCE9F7",
1102
+ "value": "#8FA1B4",
1103
1103
  "path": ["image", "border-color"]
1104
1104
  }
1105
1105
  };