@mittwald/flow-react-components 1.3.0-next.1 → 1.3.0-next.10

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 (57) hide show
  1. package/AGENTS.md +14 -0
  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/default.mjs +2 -1
  7. package/dist/js/flr-universal.mjs +2 -1
  8. package/dist/js/packages/components/src/components/Action/models/ActionModel.mjs +25 -8
  9. package/dist/js/packages/components/src/components/Action/models/ActionModel.mjs.map +1 -1
  10. package/dist/js/packages/components/src/components/CartesianChart/CartesianChart.mjs +6 -2
  11. package/dist/js/packages/components/src/components/CartesianChart/CartesianChart.mjs.map +1 -1
  12. package/dist/js/packages/components/src/components/CartesianChart/components/Area/Area.mjs +3 -1
  13. package/dist/js/packages/components/src/components/CartesianChart/components/Area/Area.mjs.map +1 -1
  14. package/dist/js/packages/components/src/components/CartesianChart/components/Bar/Bar.mjs +12 -3
  15. package/dist/js/packages/components/src/components/CartesianChart/components/Bar/Bar.mjs.map +1 -1
  16. package/dist/js/packages/components/src/components/CartesianChart/context.mjs +4 -1
  17. package/dist/js/packages/components/src/components/CartesianChart/context.mjs.map +1 -1
  18. package/dist/js/packages/components/src/components/CartesianChart/hooks/useScopedStackId.mjs +16 -0
  19. package/dist/js/packages/components/src/components/CartesianChart/hooks/useScopedStackId.mjs.map +1 -0
  20. package/dist/js/packages/components/src/components/Combine/Combine.mjs +4 -1
  21. package/dist/js/packages/components/src/components/Combine/Combine.mjs.map +1 -1
  22. package/dist/js/packages/components/src/components/Combine/Combine.module.mjs.map +1 -1
  23. package/dist/js/packages/components/src/components/ContextMenu/ContextMenu.mjs +2 -2
  24. package/dist/js/packages/components/src/components/ContextMenu/ContextMenu.mjs.map +1 -1
  25. package/dist/js/packages/components/src/components/ContextMenu/components/ContextMenuSection/ContextMenuSection.mjs +2 -2
  26. package/dist/js/packages/components/src/components/ContextMenu/components/ContextMenuSection/ContextMenuSection.mjs.map +1 -1
  27. package/dist/js/packages/components/src/components/ContextMenu/lib.mjs +7 -3
  28. package/dist/js/packages/components/src/components/ContextMenu/lib.mjs.map +1 -1
  29. package/dist/js/packages/components/src/components/Icon/components/icons/IconAIHosting.mjs +19 -0
  30. package/dist/js/packages/components/src/components/Icon/components/icons/IconAIHosting.mjs.map +1 -0
  31. package/dist/js/packages/components/src/components/Modal/Modal.mjs +6 -4
  32. package/dist/js/packages/components/src/components/Modal/Modal.mjs.map +1 -1
  33. package/dist/js/packages/components/src/components/OverlayTrigger/OverlayTrigger.mjs +1 -0
  34. package/dist/js/packages/components/src/components/OverlayTrigger/OverlayTrigger.mjs.map +1 -1
  35. package/dist/js/packages/components/src/components/Popover/components/NonModalPopoverContent/NonModalPopoverContent.mjs +19 -11
  36. package/dist/js/packages/components/src/components/Popover/components/NonModalPopoverContent/NonModalPopoverContent.mjs.map +1 -1
  37. package/dist/js/packages/components/src/components/TextArea/TextArea.mjs +14 -13
  38. package/dist/js/packages/components/src/components/TextArea/TextArea.mjs.map +1 -1
  39. package/dist/js/packages/components/src/components/Tooltip/Tooltip.module.mjs.map +1 -1
  40. package/dist/js/packages/components/src/lib/controller/overlay/OverlayContextProvider.mjs +6 -3
  41. package/dist/js/packages/components/src/lib/controller/overlay/OverlayContextProvider.mjs.map +1 -1
  42. package/dist/js/packages/components/src/lib/controller/overlay/OverlayController.mjs.map +1 -1
  43. package/dist/js/packages/components/src/lib/controller/overlay/context.mjs +1 -1
  44. package/dist/js/packages/components/src/lib/controller/overlay/context.mjs.map +1 -1
  45. package/dist/js/packages/components/src/lib/controller/overlay/useOverlayController.mjs +1 -1
  46. package/dist/js/packages/components/src/lib/controller/overlay/useOverlayController.mjs.map +1 -1
  47. package/dist/types/components/Action/models/ActionModel.d.ts +12 -4
  48. package/dist/types/components/Action/types.d.ts +9 -2
  49. package/dist/types/components/CartesianChart/context.d.ts +6 -0
  50. package/dist/types/components/CartesianChart/hooks/useScopedStackId.d.ts +6 -0
  51. package/dist/types/components/ContextMenu/lib.d.ts +5 -1
  52. package/dist/types/components/Icon/components/icons/IconAIHosting.d.ts +4 -0
  53. package/dist/types/components/Icon/components/icons/index.d.ts +1 -0
  54. package/dist/types/lib/controller/overlay/OverlayContextProvider.d.ts +9 -0
  55. package/dist/types/lib/controller/overlay/OverlayController.d.ts +11 -1
  56. package/dist/types/lib/controller/overlay/context.d.ts +19 -2
  57. 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.\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":";;;;;;;;;;;;;;;;;;;;;;;;AAgEA,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.\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"}
@@ -4,9 +4,10 @@ import Popover_module_default from "../../Popover.module.mjs";
4
4
  import { popoverViewportPadding } from "../../viewportPadding.mjs";
5
5
  import { popoverWidthStyle } from "../../widthStyle.mjs";
6
6
  import clsx from "clsx";
7
- import { useEffect, useId, useRef, useState } from "react";
7
+ import { useEffect, useId, useRef } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { useObjectRef, useOverlayPosition } from "react-aria";
9
+ import { useEnterAnimation, useExitAnimation } from "@react-aria/utils";
10
+ import { useObjectRef as useObjectRef$1, useOverlayPosition } from "react-aria";
10
11
  //#region src/components/Popover/components/NonModalPopoverContent/NonModalPopoverContent.tsx
11
12
  var useRepositionWhenAnchorMoves = (anchorRef, isOpen, updatePosition) => {
12
13
  useEffect(() => {
@@ -22,7 +23,19 @@ var useRepositionWhenAnchorMoves = (anchorRef, isOpen, updatePosition) => {
22
23
  ]);
23
24
  };
24
25
  var NonModalPopoverContent = (props) => {
25
- const { children, className, withTip, isOpen = false, width, id, onOpenChange, ref, triggerRef, placement: requestedPlacement, offset, crossOffset, maxHeight: ignoredMaxHeight, shouldFlip, shouldUpdatePosition, arrowBoundaryOffset, boundaryElement, ...rest } = props;
26
+ const { isOpen = false, ref, ...rest } = props;
27
+ const overlayRef = useObjectRef$1(ref);
28
+ const isExiting = useExitAnimation(overlayRef, isOpen);
29
+ if (!isOpen && !isExiting) return null;
30
+ return /* @__PURE__ */ jsx(NonModalPopoverContentInner, {
31
+ ...rest,
32
+ overlayRef,
33
+ isOpen,
34
+ isExiting
35
+ });
36
+ };
37
+ var NonModalPopoverContentInner = (props) => {
38
+ const { children, className, withTip, isOpen = false, isExiting, width, id, onOpenChange, overlayRef, triggerRef, placement: requestedPlacement, offset, crossOffset, maxHeight: ignoredMaxHeight, shouldFlip, shouldUpdatePosition, arrowBoundaryOffset, boundaryElement, ...rest } = props;
26
39
  const positionProps = {
27
40
  placement: requestedPlacement,
28
41
  offset,
@@ -32,9 +45,7 @@ var NonModalPopoverContent = (props) => {
32
45
  arrowBoundaryOffset,
33
46
  boundaryElement
34
47
  };
35
- const overlayRef = useObjectRef(ref);
36
48
  const arrowRef = useRef(null);
37
- const [isEntering, setIsEntering] = useState(true);
38
49
  const detailsId = useId();
39
50
  const { overlayProps, arrowProps, placement, updatePosition } = useOverlayPosition({
40
51
  ...positionProps,
@@ -46,6 +57,8 @@ var NonModalPopoverContent = (props) => {
46
57
  containerPadding: popoverViewportPadding
47
58
  });
48
59
  useRepositionWhenAnchorMoves(triggerRef, isOpen, updatePosition);
60
+ const isPositioned = placement !== null;
61
+ const isEntering = useEnterAnimation(overlayRef, isPositioned);
49
62
  useEffect(() => {
50
63
  const trigger = triggerRef.current;
51
64
  if (!isOpen || !trigger) return;
@@ -68,11 +81,6 @@ var NonModalPopoverContent = (props) => {
68
81
  document.addEventListener("keydown", closeOnEscape);
69
82
  return () => document.removeEventListener("keydown", closeOnEscape);
70
83
  }, [isOpen, onOpenChange]);
71
- useEffect(() => {
72
- if (!isOpen) setIsEntering(true);
73
- }, [isOpen]);
74
- if (!isOpen) return null;
75
- const isPositioned = placement !== null;
76
84
  return /* @__PURE__ */ jsxs("div", {
77
85
  ...rest,
78
86
  ...overlayProps,
@@ -81,7 +89,7 @@ var NonModalPopoverContent = (props) => {
81
89
  className: clsx(className, Popover_module_default["non-modal"]),
82
90
  "data-placement": placement ?? void 0,
83
91
  "data-entering": isEntering || void 0,
84
- onAnimationEnd: () => setIsEntering(false),
92
+ "data-exiting": isExiting || void 0,
85
93
  style: {
86
94
  ...overlayProps.style,
87
95
  zIndex: void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"NonModalPopoverContent.mjs","names":[],"sources":["../../../../../../../../../src/components/Popover/components/NonModalPopoverContent/NonModalPopoverContent.tsx"],"sourcesContent":["import type { FC, PropsWithChildren, Ref, RefObject } from \"react\";\nimport { useEffect, useId, useRef, useState } from \"react\";\nimport clsx from \"clsx\";\nimport { useObjectRef, useOverlayPosition } from \"react-aria\";\nimport type { Placement } from \"react-aria\";\nimport styles from \"../../Popover.module.scss\";\nimport type { PropsWithClassName } from \"@/lib/types/props\";\nimport { popoverViewportPadding } from \"../../viewportPadding\";\nimport { popoverWidthStyle } from \"../../widthStyle\";\n\nexport interface NonModalPopoverContentProps\n extends PropsWithChildren, PropsWithClassName {\n withTip?: boolean;\n isOpen?: boolean;\n width?: string | number;\n placement?: Placement;\n offset?: number;\n crossOffset?: number;\n /** Swallowed on purpose — the stylesheet overrides `max-height` here. */\n maxHeight?: number;\n shouldFlip?: boolean;\n shouldUpdatePosition?: boolean;\n arrowBoundaryOffset?: number;\n boundaryElement?: Element;\n /** The id react-aria's trigger points its `aria-controls` at. */\n id?: string;\n onOpenChange: (isOpen: boolean) => void;\n ref?: Ref<HTMLElement>;\n triggerRef: RefObject<Element | null>;\n}\n\n/*\n * `useOverlayPosition` recalculates when the window resizes, when a scroll\n * container scrolls, and when the anchor or the popover changes *size*. It never\n * notices the anchor merely *moving*, because a popover normally opens on a user\n * interaction, long after the page settled.\n *\n * This one opens itself, so it places itself into a page that is still filling\n * in — and anything appearing above the anchor then pushes the anchor out from\n * under it. Remotely that is the normal case, not an edge case: the host\n * materializes the page in pieces as they arrive over the connection.\n *\n * Observing the ancestors covers it. In block layout an element moves because\n * something around it changed size, and a resized ancestor is the one signal\n * every such reflow has in common. What it does not catch is an ancestor of\n * fixed height rearranging inside — rare, and the next scroll or resize\n * corrects it.\n */\nconst useRepositionWhenAnchorMoves = (\n anchorRef: RefObject<Element | null>,\n isOpen: boolean,\n updatePosition: () => void,\n): void => {\n useEffect(() => {\n // Read inside the effect. A coach mark that is open from its first render\n // renders before the anchor's ref is attached, and a ref filling in does not\n // re-render anything — so reading during render would see `null`, bail, and\n // leave nothing observing.\n const anchor = anchorRef.current;\n\n if (!isOpen || !anchor) {\n return;\n }\n\n const observer = new ResizeObserver(updatePosition);\n\n for (\n let element = anchor.parentElement;\n element;\n element = element.parentElement\n ) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [anchorRef, isOpen, updatePosition]);\n};\n\n/*\n * The non-modal popover deliberately skips react-aria's `usePopover`, which is\n * what a popover normally builds on. That hook couples three things Flow does\n * not want here: it locks page scrolling, it hides the rest of the page from\n * assistive tech, and — the reason this component exists — it closes the\n * popover on the first scroll, with no way to opt out.\n *\n * What is left is `useOverlayPosition` for the anchoring, public react-aria API.\n * The popover therefore tracks its trigger while the page scrolls, and its\n * content stays plain content: no role, no label, no focus of its own.\n *\n * It is not portalled either. A popover that is announced by nothing has to be\n * findable where it belongs, and a portal to the end of `<body>` puts it behind\n * the whole page in reading order — so it renders where it was written, right\n * next to what it points at. Being absolutely positioned it still takes no\n * space; what it does inherit is its surroundings, so an ancestor that clips\n * (`overflow: hidden`) or a stacking context can cut it off.\n */\nexport const NonModalPopoverContent: FC<NonModalPopoverContentProps> = (\n props,\n) => {\n const {\n children,\n className,\n withTip,\n isOpen = false,\n width,\n id,\n onOpenChange,\n ref,\n triggerRef,\n // Named one by one so that everything left over is a DOM prop and reaches\n // the element. Funnelling the rest into the positioning instead drops\n // `aria-*`, `data-*` and the like, which `Aria.Popover` forwards on the\n // modal path.\n placement: requestedPlacement,\n offset,\n crossOffset,\n maxHeight: ignoredMaxHeight,\n shouldFlip,\n shouldUpdatePosition,\n arrowBoundaryOffset,\n boundaryElement,\n ...rest\n } = props;\n\n void ignoredMaxHeight;\n\n const positionProps = {\n placement: requestedPlacement,\n offset,\n crossOffset,\n shouldFlip,\n shouldUpdatePosition,\n arrowBoundaryOffset,\n boundaryElement,\n };\n\n const overlayRef = useObjectRef(ref as Ref<HTMLDivElement>);\n const arrowRef = useRef<HTMLDivElement>(null);\n const [isEntering, setIsEntering] = useState(true);\n const detailsId = useId();\n\n const { overlayProps, arrowProps, placement, updatePosition } =\n useOverlayPosition({\n ...positionProps,\n targetRef: triggerRef,\n overlayRef,\n arrowRef,\n isOpen,\n offset: positionProps.offset ?? 8,\n containerPadding: popoverViewportPadding,\n });\n\n useRepositionWhenAnchorMoves(triggerRef, isOpen, updatePosition);\n\n /*\n * Nothing announces this popover, so the trigger points at it: `aria-details`\n * tells assistive tech that there is related content and offers a way over to\n * it — unlike `aria-describedby`, which would flatten the popover into a\n * string and put its buttons out of reach.\n *\n * Set on the trigger element itself, because that element belongs to whoever\n * rendered it. Whatever it carried before is restored on the way out.\n */\n useEffect(() => {\n const trigger = triggerRef.current;\n\n if (!isOpen || !trigger) {\n return;\n }\n\n const previous = trigger.getAttribute(\"aria-details\");\n trigger.setAttribute(\n \"aria-details\",\n previous ? `${previous} ${detailsId}` : detailsId,\n );\n\n return () => {\n if (previous === null) {\n trigger.removeAttribute(\"aria-details\");\n } else {\n trigger.setAttribute(\"aria-details\", previous);\n }\n };\n }, [isOpen, triggerRef, detailsId]);\n\n // Escape closes it. react-aria would do this through `useOverlay`, which is\n // part of the machinery this component leaves out.\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const closeOnEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onOpenChange(false);\n }\n };\n\n document.addEventListener(\"keydown\", closeOnEscape);\n return () => document.removeEventListener(\"keydown\", closeOnEscape);\n }, [isOpen, onOpenChange]);\n\n useEffect(() => {\n if (!isOpen) {\n setIsEntering(true);\n }\n }, [isOpen]);\n\n if (!isOpen) {\n return null;\n }\n\n /*\n * Until it has a placement, `useOverlayPosition` parks the popover in the top\n * left corner (`position: fixed; top: 0; left: 0`) — it has not measured the\n * anchor yet. Rendered on a server that corner is what ships, and the popover\n * sits there until hydration measures; an anchor given by id is resolved a\n * frame later still. Either way it is visibly in the wrong place first and\n * jumps to the anchor after, so keep it out of sight until it knows where it\n * belongs. It stays in the DOM, which is what its place in the reading order\n * and `aria-details` depend on.\n */\n const isPositioned = placement !== null;\n\n return (\n <div\n {...rest}\n {...overlayProps}\n id={id}\n ref={overlayRef}\n className={clsx(className, styles[\"non-modal\"])}\n data-placement={placement ?? undefined}\n data-entering={isEntering || undefined}\n onAnimationEnd={() => setIsEntering(false)}\n style={{\n ...overlayProps.style,\n /*\n * Two things `useOverlayPosition` adds for an overlay portalled to the\n * end of `<body>` and pinned to the viewport. This one renders where it\n * stands and scrolls with the page, so both are wrong here.\n *\n * `z-index: 100000` would put it in front of the whole application — it\n * scrolled over the docs site's sticky header. Claiming no stacking\n * level leaves that to the page: it still covers the ordinary content\n * around it, and app chrome that sets a `z-index` keeps its place above.\n *\n * The `max-height` it caps the overlay at is wrong here for the same\n * reason, but it is written straight onto the element and has to be\n * undone in CSS — see `.non-modal` in Popover.module.scss.\n */\n zIndex: undefined,\n ...popoverWidthStyle(width),\n ...(isPositioned ? {} : { visibility: \"hidden\" }),\n }}\n >\n {withTip && (\n <div\n {...arrowProps}\n ref={arrowRef}\n className={styles.tip}\n data-placement={placement ?? undefined}\n style={{\n // What <Aria.OverlayArrow /> contributes on top of `arrowProps`:\n // it lifts the tip out of the flow and centres it on the anchor.\n position: \"absolute\",\n transform:\n placement === \"top\" || placement === \"bottom\"\n ? \"translateX(-50%)\"\n : \"translateY(-50%)\",\n // `arrowProps.style` carries the offset along the popover's edge and\n // leaves the other axis `undefined` — which still overwrites. So the\n // edge the tip sits on is set last: spread first, it silently lost\n // `top: 100%` and the tip jumped to the popover's top edge, pointing\n // away from an anchor that was below it.\n ...arrowProps.style,\n ...(placement ? { [placement]: \"100%\" } : {}),\n }}\n >\n <svg width={16} height={16} viewBox=\"0 0 16 16\">\n <path d=\"M0 0 L8 8 L16 0\" />\n </svg>\n </div>\n )}\n <div className={styles.content} id={detailsId}>\n {children}\n </div>\n </div>\n );\n};\n\nexport default NonModalPopoverContent;\n"],"mappings":";;;;;;;;;;AAgDA,IAAM,gCACJ,WACA,QACA,mBACS;CACT,gBAAgB;EAKd,MAAM,SAAS,UAAU;EAEzB,IAAI,CAAC,UAAU,CAAC,QACd;EAGF,MAAM,WAAW,IAAI,eAAe,cAAc;EAElD,KACE,IAAI,UAAU,OAAO,eACrB,SACA,UAAU,QAAQ,eAElB,SAAS,QAAQ,OAAO;EAG1B,aAAa,SAAS,WAAW;CACnC,GAAG;EAAC;EAAW;EAAQ;CAAc,CAAC;AACxC;AAoBA,IAAa,0BACX,UACG;CACH,MAAM,EACJ,UACA,WACA,SACA,SAAS,OACT,OACA,IACA,cACA,KACA,YAKA,WAAW,oBACX,QACA,aACA,WAAW,kBACX,YACA,sBACA,qBACA,iBACA,GAAG,SACD;CAIJ,MAAM,gBAAgB;EACpB,WAAW;EACX;EACA;EACA;EACA;EACA;EACA;CACF;CAEA,MAAM,aAAa,aAAa,GAA0B;CAC1D,MAAM,WAAW,OAAuB,IAAI;CAC5C,MAAM,CAAC,YAAY,iBAAiB,SAAS,IAAI;CACjD,MAAM,YAAY,MAAM;CAExB,MAAM,EAAE,cAAc,YAAY,WAAW,mBAC3C,mBAAmB;EACjB,GAAG;EACH,WAAW;EACX;EACA;EACA;EACA,QAAQ,cAAc,UAAU;EAChC,kBAAkB;CACpB,CAAC;CAEH,6BAA6B,YAAY,QAAQ,cAAc;CAW/D,gBAAgB;EACd,MAAM,UAAU,WAAW;EAE3B,IAAI,CAAC,UAAU,CAAC,SACd;EAGF,MAAM,WAAW,QAAQ,aAAa,cAAc;EACpD,QAAQ,aACN,gBACA,WAAW,GAAG,SAAS,GAAG,cAAc,SAC1C;EAEA,aAAa;GACX,IAAI,aAAa,MACf,QAAQ,gBAAgB,cAAc;QAEtC,QAAQ,aAAa,gBAAgB,QAAQ;EAEjD;CACF,GAAG;EAAC;EAAQ;EAAY;CAAS,CAAC;CAIlC,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,iBAAiB,UAAyB;GAC9C,IAAI,MAAM,QAAQ,UAChB,aAAa,KAAK;EAEtB;EAEA,SAAS,iBAAiB,WAAW,aAAa;EAClD,aAAa,SAAS,oBAAoB,WAAW,aAAa;CACpE,GAAG,CAAC,QAAQ,YAAY,CAAC;CAEzB,gBAAgB;EACd,IAAI,CAAC,QACH,cAAc,IAAI;CAEtB,GAAG,CAAC,MAAM,CAAC;CAEX,IAAI,CAAC,QACH,OAAO;CAaT,MAAM,eAAe,cAAc;CAEnC,OACE,qBAAC,OAAD;EACE,GAAI;EACJ,GAAI;EACA;EACJ,KAAK;EACL,WAAW,KAAK,WAAW,uBAAO,YAAY;EAC9C,kBAAgB,aAAa,KAAA;EAC7B,iBAAe,cAAc,KAAA;EAC7B,sBAAsB,cAAc,KAAK;EACzC,OAAO;GACL,GAAG,aAAa;GAehB,QAAQ,KAAA;GACR,GAAG,kBAAkB,KAAK;GAC1B,GAAI,eAAe,CAAC,IAAI,EAAE,YAAY,SAAS;EACjD;EA5BF,UAAA,CA8BG,WACC,oBAAC,OAAD;GACE,GAAI;GACJ,KAAK;GACL,WAAW,uBAAO;GAClB,kBAAgB,aAAa,KAAA;GAC7B,OAAO;IAGL,UAAU;IACV,WACE,cAAc,SAAS,cAAc,WACjC,qBACA;IAMN,GAAG,WAAW;IACd,GAAI,YAAY,GAAG,YAAY,OAAO,IAAI,CAAC;GAC7C;GAEA,UAAA,oBAAC,OAAD;IAAK,OAAO;IAAI,QAAQ;IAAI,SAAQ;IAClC,UAAA,oBAAC,QAAD,EAAM,GAAE,kBAAmB,CAAA;GACxB,CAAA;EACF,CAAA,GAEP,oBAAC,OAAD;GAAK,WAAW,uBAAO;GAAS,IAAI;GACjC;EACE,CAAA,CACF;;AAET"}
1
+ {"version":3,"file":"NonModalPopoverContent.mjs","names":[],"sources":["../../../../../../../../../src/components/Popover/components/NonModalPopoverContent/NonModalPopoverContent.tsx"],"sourcesContent":["import type { FC, PropsWithChildren, Ref, RefObject } from \"react\";\nimport { useEffect, useId, useRef } from \"react\";\nimport clsx from \"clsx\";\nimport { useObjectRef, useOverlayPosition } from \"react-aria\";\nimport type { Placement } from \"react-aria\";\nimport { useEnterAnimation, useExitAnimation } from \"@react-aria/utils\";\nimport styles from \"../../Popover.module.scss\";\nimport type { PropsWithClassName } from \"@/lib/types/props\";\nimport { popoverViewportPadding } from \"../../viewportPadding\";\nimport { popoverWidthStyle } from \"../../widthStyle\";\n\nexport interface NonModalPopoverContentProps\n extends PropsWithChildren, PropsWithClassName {\n withTip?: boolean;\n isOpen?: boolean;\n width?: string | number;\n placement?: Placement;\n offset?: number;\n crossOffset?: number;\n /** Swallowed on purpose — the stylesheet overrides `max-height` here. */\n maxHeight?: number;\n shouldFlip?: boolean;\n shouldUpdatePosition?: boolean;\n arrowBoundaryOffset?: number;\n boundaryElement?: Element;\n /** The id react-aria's trigger points its `aria-controls` at. */\n id?: string;\n onOpenChange: (isOpen: boolean) => void;\n ref?: Ref<HTMLElement>;\n triggerRef: RefObject<Element | null>;\n}\n\ninterface NonModalPopoverContentInnerProps extends Omit<\n NonModalPopoverContentProps,\n \"ref\"\n> {\n overlayRef: RefObject<HTMLDivElement | null>;\n isExiting: boolean;\n}\n\n/*\n * `useOverlayPosition` recalculates when the window resizes, when a scroll\n * container scrolls, and when the anchor or the popover changes *size*. It never\n * notices the anchor merely *moving*, because a popover normally opens on a user\n * interaction, long after the page settled.\n *\n * This one opens itself, so it places itself into a page that is still filling\n * in — and anything appearing above the anchor then pushes the anchor out from\n * under it. Remotely that is the normal case, not an edge case: the host\n * materializes the page in pieces as they arrive over the connection.\n *\n * Observing the ancestors covers it. In block layout an element moves because\n * something around it changed size, and a resized ancestor is the one signal\n * every such reflow has in common. What it does not catch is an ancestor of\n * fixed height rearranging inside — rare, and the next scroll or resize\n * corrects it.\n */\nconst useRepositionWhenAnchorMoves = (\n anchorRef: RefObject<Element | null>,\n isOpen: boolean,\n updatePosition: () => void,\n): void => {\n useEffect(() => {\n // Read inside the effect. A coach mark that is open from its first render\n // renders before the anchor's ref is attached, and a ref filling in does not\n // re-render anything — so reading during render would see `null`, bail, and\n // leave nothing observing.\n const anchor = anchorRef.current;\n\n if (!isOpen || !anchor) {\n return;\n }\n\n const observer = new ResizeObserver(updatePosition);\n\n for (\n let element = anchor.parentElement;\n element;\n element = element.parentElement\n ) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [anchorRef, isOpen, updatePosition]);\n};\n\n/*\n * The non-modal popover deliberately skips react-aria's `usePopover`, which is\n * what a popover normally builds on. That hook couples three things Flow does\n * not want here: it locks page scrolling, it hides the rest of the page from\n * assistive tech, and — the reason this component exists — it closes the\n * popover on the first scroll, with no way to opt out.\n *\n * What is left is `useOverlayPosition` for the anchoring, public react-aria API.\n * The popover therefore tracks its trigger while the page scrolls, and its\n * content stays plain content: no role, no label, no focus of its own.\n *\n * It is not portalled either. A popover that is announced by nothing has to be\n * findable where it belongs, and a portal to the end of `<body>` puts it behind\n * the whole page in reading order — so it renders where it was written, right\n * next to what it points at. Being absolutely positioned it still takes no\n * space; what it does inherit is its surroundings, so an ancestor that clips\n * (`overflow: hidden`) or a stacking context can cut it off.\n *\n * Mounting is split across two components for the same reason `Aria.Popover`\n * splits it: the closing animation has to outlive `isOpen`, so the element that\n * plays it cannot be unmounted by the render that closes it. This outer half\n * keeps the ref and the mount decision and survives across open and closed; the\n * inner half holds the positioning and remounts on every open, which is what\n * resets the entry animation.\n */\nexport const NonModalPopoverContent: FC<NonModalPopoverContentProps> = (\n props,\n) => {\n const { isOpen = false, ref, ...rest } = props;\n\n const overlayRef = useObjectRef(ref as Ref<HTMLDivElement>);\n\n const isExiting = useExitAnimation(overlayRef, isOpen);\n\n if (!isOpen && !isExiting) {\n return null;\n }\n\n return (\n <NonModalPopoverContentInner\n {...rest}\n overlayRef={overlayRef}\n isOpen={isOpen}\n isExiting={isExiting}\n />\n );\n};\n\nconst NonModalPopoverContentInner: FC<NonModalPopoverContentInnerProps> = (\n props,\n) => {\n const {\n children,\n className,\n withTip,\n isOpen = false,\n isExiting,\n width,\n id,\n onOpenChange,\n overlayRef,\n triggerRef,\n // Named one by one so that everything left over is a DOM prop and reaches\n // the element. Funnelling the rest into the positioning instead drops\n // `aria-*`, `data-*` and the like, which `Aria.Popover` forwards on the\n // modal path.\n placement: requestedPlacement,\n offset,\n crossOffset,\n maxHeight: ignoredMaxHeight,\n shouldFlip,\n shouldUpdatePosition,\n arrowBoundaryOffset,\n boundaryElement,\n ...rest\n } = props;\n\n void ignoredMaxHeight;\n\n const positionProps = {\n placement: requestedPlacement,\n offset,\n crossOffset,\n shouldFlip,\n shouldUpdatePosition,\n arrowBoundaryOffset,\n boundaryElement,\n };\n\n const arrowRef = useRef<HTMLDivElement>(null);\n const detailsId = useId();\n\n const { overlayProps, arrowProps, placement, updatePosition } =\n useOverlayPosition({\n ...positionProps,\n targetRef: triggerRef,\n overlayRef,\n arrowRef,\n isOpen,\n offset: positionProps.offset ?? 8,\n containerPadding: popoverViewportPadding,\n });\n\n useRepositionWhenAnchorMoves(triggerRef, isOpen, updatePosition);\n\n /*\n * Until it has a placement, `useOverlayPosition` parks the popover in the top\n * left corner (`position: fixed; top: 0; left: 0`) — it has not measured the\n * anchor yet. Rendered on a server that corner is what ships, and the popover\n * sits there until hydration measures; an anchor given by id is resolved a\n * frame later still. Either way it is visibly in the wrong place first and\n * jumps to the anchor after, so keep it out of sight until it knows where it\n * belongs. It stays in the DOM, which is what its place in the reading order\n * and `aria-details` depend on.\n */\n const isPositioned = placement !== null;\n\n // Held back until the popover knows where it belongs — an entry animation\n // that plays while the popover is still hidden is one the user never sees.\n const isEntering = useEnterAnimation(overlayRef, isPositioned);\n\n /*\n * Nothing announces this popover, so the trigger points at it: `aria-details`\n * tells assistive tech that there is related content and offers a way over to\n * it — unlike `aria-describedby`, which would flatten the popover into a\n * string and put its buttons out of reach.\n *\n * Set on the trigger element itself, because that element belongs to whoever\n * rendered it. Whatever it carried before is restored on the way out.\n */\n useEffect(() => {\n const trigger = triggerRef.current;\n\n if (!isOpen || !trigger) {\n return;\n }\n\n const previous = trigger.getAttribute(\"aria-details\");\n trigger.setAttribute(\n \"aria-details\",\n previous ? `${previous} ${detailsId}` : detailsId,\n );\n\n return () => {\n if (previous === null) {\n trigger.removeAttribute(\"aria-details\");\n } else {\n trigger.setAttribute(\"aria-details\", previous);\n }\n };\n }, [isOpen, triggerRef, detailsId]);\n\n // Escape closes it. react-aria would do this through `useOverlay`, which is\n // part of the machinery this component leaves out.\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const closeOnEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onOpenChange(false);\n }\n };\n\n document.addEventListener(\"keydown\", closeOnEscape);\n return () => document.removeEventListener(\"keydown\", closeOnEscape);\n }, [isOpen, onOpenChange]);\n\n return (\n <div\n {...rest}\n {...overlayProps}\n id={id}\n ref={overlayRef}\n className={clsx(className, styles[\"non-modal\"])}\n data-placement={placement ?? undefined}\n data-entering={isEntering || undefined}\n data-exiting={isExiting || undefined}\n style={{\n ...overlayProps.style,\n /*\n * Two things `useOverlayPosition` adds for an overlay portalled to the\n * end of `<body>` and pinned to the viewport. This one renders where it\n * stands and scrolls with the page, so both are wrong here.\n *\n * `z-index: 100000` would put it in front of the whole application — it\n * scrolled over the docs site's sticky header. Claiming no stacking\n * level leaves that to the page: it still covers the ordinary content\n * around it, and app chrome that sets a `z-index` keeps its place above.\n *\n * The `max-height` it caps the overlay at is wrong here for the same\n * reason, but it is written straight onto the element and has to be\n * undone in CSS — see `.non-modal` in Popover.module.scss.\n */\n zIndex: undefined,\n ...popoverWidthStyle(width),\n ...(isPositioned ? {} : { visibility: \"hidden\" }),\n }}\n >\n {withTip && (\n <div\n {...arrowProps}\n ref={arrowRef}\n className={styles.tip}\n data-placement={placement ?? undefined}\n style={{\n // What <Aria.OverlayArrow /> contributes on top of `arrowProps`:\n // it lifts the tip out of the flow and centres it on the anchor.\n position: \"absolute\",\n transform:\n placement === \"top\" || placement === \"bottom\"\n ? \"translateX(-50%)\"\n : \"translateY(-50%)\",\n // `arrowProps.style` carries the offset along the popover's edge and\n // leaves the other axis `undefined` — which still overwrites. So the\n // edge the tip sits on is set last: spread first, it silently lost\n // `top: 100%` and the tip jumped to the popover's top edge, pointing\n // away from an anchor that was below it.\n ...arrowProps.style,\n ...(placement ? { [placement]: \"100%\" } : {}),\n }}\n >\n <svg width={16} height={16} viewBox=\"0 0 16 16\">\n <path d=\"M0 0 L8 8 L16 0\" />\n </svg>\n </div>\n )}\n <div className={styles.content} id={detailsId}>\n {children}\n </div>\n </div>\n );\n};\n\nexport default NonModalPopoverContent;\n"],"mappings":"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"}
@@ -10,7 +10,7 @@ import { FieldDescription } from "../FieldDescription/FieldDescription.mjs";
10
10
  import TextArea_module_default from "./TextArea.module.mjs";
11
11
  import __locale_default from "../../../../../_virtual/_23.locale.mjs";
12
12
  import clsx from "clsx";
13
- import { useEffect, useState } from "react";
13
+ import { useEffect, useLayoutEffect, useState } from "react";
14
14
  import { jsx, jsxs } from "react/jsx-runtime";
15
15
  import { useObjectRef } from "@react-aria/utils";
16
16
  import * as Aria from "react-aria-components";
@@ -18,8 +18,7 @@ import * as Aria from "react-aria-components";
18
18
  /** @flr-generate all */
19
19
  var TextArea = flowComponent("TextArea", (props) => {
20
20
  const warnDeprecation = useWarnDeprecation();
21
- const { children, placeholder, rows = 5, autoResizeMaxRows = rows, ref, allowVerticalResize, allowHorizontalResize, showCharacterCount, className, onChange, isReadOnly, ...rest } = useControlledHostValueProps(props, "");
22
- const [charactersCount, setCharactersCount] = useState(props.defaultValue?.length ?? props.value?.length ?? 0);
21
+ const { children, placeholder, rows = 5, autoResizeMaxRows = rows, ref, allowVerticalResize, allowHorizontalResize, showCharacterCount, className, onChange, isReadOnly, value, ...rest } = useControlledHostValueProps(props, "");
23
22
  if (allowHorizontalResize !== void 0) warnDeprecation("The 'allowHorizontalResize' prop is deprecated and will be removed in a future release. Use 'allowResize' instead.");
24
23
  if (allowVerticalResize !== void 0) warnDeprecation("The 'allowVerticalResize' prop is deprecated and will be removed in a future release. Use 'allowResize' instead.");
25
24
  const { FieldErrorView, FieldErrorCaptureContext, fieldPropsContext, fieldProps } = useFieldComponent(props, "TextArea");
@@ -30,11 +29,10 @@ var TextArea = flowComponent("TextArea", (props) => {
30
29
  const inputClassName = clsx(TextArea_module_default.input, typeof allowResize === "boolean" && allowResize ? TextArea_module_default.resize : null, allowResize === "horizontal" ? TextArea_module_default.horizontalResize : allowResize === "vertical" ? TextArea_module_default.verticalResize : null);
31
30
  const handleChange = (v) => {
32
31
  if (isReadOnly) return;
33
- if (showCharacterCount) setCharactersCount(v.length);
34
32
  if (onChange) onChange(v);
35
33
  };
36
34
  const charactersCountDescription = useLocalizedStringFormatter(__locale_default, "TextArea").format("characters", {
37
- count: charactersCount,
35
+ count: value.length,
38
36
  maxCount: props.maxLength ?? 0
39
37
  });
40
38
  const localRef = useObjectRef(ref);
@@ -71,16 +69,20 @@ var TextArea = flowComponent("TextArea", (props) => {
71
69
  window.removeEventListener("mouseup", handleMouseUp);
72
70
  };
73
71
  }, [resized]);
74
- const updateHeight = () => {
75
- if (localRef.current && autoResizable && !verticallyResizable) {
76
- localRef.current.style.height = "0px";
77
- const scrollHeight = localRef.current.scrollHeight;
78
- localRef.current.style.height = scrollHeight + 2 + "px";
79
- }
80
- };
72
+ useLayoutEffect(() => {
73
+ const textArea = localRef.current;
74
+ if (!textArea || !autoResizable || verticallyResizable) return;
75
+ textArea.style.height = "0px";
76
+ textArea.style.height = `${textArea.scrollHeight + 2}px`;
77
+ }, [
78
+ value,
79
+ autoResizable,
80
+ verticallyResizable
81
+ ]);
81
82
  return /* @__PURE__ */ jsx(Aria.TextField, {
82
83
  ...rest,
83
84
  ...fieldProps,
85
+ value,
84
86
  className: rootClassName,
85
87
  onChange: handleChange,
86
88
  children: /* @__PURE__ */ jsxs(PropsContextProvider, {
@@ -95,7 +97,6 @@ var TextArea = flowComponent("TextArea", (props) => {
95
97
  placeholder,
96
98
  className: inputClassName,
97
99
  ref: localRef,
98
- onChange: updateHeight,
99
100
  style: {
100
101
  caretColor: isReadOnly ? "transparent" : void 0,
101
102
  minHeight: getHeight(rows),
@@ -1 +1 @@
1
- {"version":3,"file":"TextArea.mjs","names":[],"sources":["../../../../../../../src/components/TextArea/TextArea.tsx"],"sourcesContent":["import * as Aria from \"react-aria-components\";\nimport styles from \"./TextArea.module.scss\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport { useObjectRef } from \"@react-aria/utils\";\nimport { useFieldComponent } from \"@/lib/hooks/useFieldComponent\";\nimport { PropsContextProvider } from \"@/lib/propsContext\";\nimport clsx from \"clsx\";\nimport { type PropsWithChildren, useEffect, useState } from \"react\";\nimport { useControlledHostValueProps } from \"@/lib/remote/useControlledHostValueProps\";\nimport { useLocalizedStringFormatter } from \"@/components/TranslationProvider/useLocalizedStringFormatter\";\nimport locales from \"./locales/*.locale.json\";\nimport { FieldDescription } from \"@/components/FieldDescription\";\nimport { useWarnDeprecation } from \"@/components/DeprecationWarningProvider\";\n\nexport interface TextAreaProps\n extends\n PropsWithChildren<Omit<Aria.TextFieldProps, \"children\">>,\n Pick<Aria.TextAreaProps, \"placeholder\" | \"rows\" | \"aria-hidden\">,\n FlowComponentProps<HTMLTextAreaElement> {\n /** Whether a character count should be displayed inside the field description. */\n showCharacterCount?: boolean;\n /**\n * Whether the text area should grow if its content gets longer than its\n * initial height.\n */\n autoResizeMaxRows?: number;\n /** Allows the user to manually resize the textArea horizontally. */\n allowResize?: boolean | \"horizontal\" | \"vertical\";\n /** @deprecated Use `allowResize` instead. */\n allowHorizontalResize?: boolean;\n /** @deprecated Use `allowResize` instead. */\n allowVerticalResize?: boolean;\n}\n\n/** @flr-generate all */\nexport const TextArea = flowComponent(\"TextArea\", (props) => {\n const warnDeprecation = useWarnDeprecation();\n const {\n children,\n placeholder,\n rows = 5,\n autoResizeMaxRows = rows,\n ref,\n allowVerticalResize,\n allowHorizontalResize,\n showCharacterCount,\n className,\n onChange,\n isReadOnly,\n ...rest\n } = useControlledHostValueProps(props, \"\");\n\n const [charactersCount, setCharactersCount] = useState(\n props.defaultValue?.length ?? props.value?.length ?? 0,\n );\n\n if (allowHorizontalResize !== undefined) {\n warnDeprecation(\n \"The 'allowHorizontalResize' prop is deprecated and will be removed in a future release. Use 'allowResize' instead.\",\n );\n }\n if (allowVerticalResize !== undefined) {\n warnDeprecation(\n \"The 'allowVerticalResize' prop is deprecated and will be removed in a future release. Use 'allowResize' instead.\",\n );\n }\n\n const {\n FieldErrorView,\n FieldErrorCaptureContext,\n fieldPropsContext,\n fieldProps,\n } = useFieldComponent(props, \"TextArea\");\n\n let { allowResize } = props;\n if (allowVerticalResize) {\n allowResize = \"vertical\";\n } else if (allowHorizontalResize) {\n allowResize = \"horizontal\";\n }\n\n const rootClassName = clsx(fieldProps.className, className);\n\n const inputClassName = clsx(\n styles.input,\n typeof allowResize === \"boolean\" && allowResize ? styles.resize : null,\n allowResize === \"horizontal\"\n ? styles.horizontalResize\n : allowResize === \"vertical\"\n ? styles.verticalResize\n : null,\n );\n\n const handleChange = (v: string) => {\n if (isReadOnly) {\n return;\n }\n\n if (showCharacterCount) {\n setCharactersCount(v.length);\n }\n if (onChange) {\n onChange(v);\n }\n };\n\n const translation = useLocalizedStringFormatter(locales, \"TextArea\");\n\n const charactersCountDescription = translation.format(\"characters\", {\n count: charactersCount,\n maxCount: props.maxLength ?? 0,\n });\n\n const localRef = useObjectRef(ref);\n\n const getHeight = (rows: number) => {\n return `calc(var(--line-height-m) * ${rows} + (var(--form-control--padding-y) * 2))`;\n };\n\n const [resized, setResized] = useState(false);\n\n const autoResizable = rows !== autoResizeMaxRows;\n\n const verticallyResizable =\n allowResize && (!autoResizable || (autoResizable && resized));\n\n useEffect(() => {\n const textarea = localRef.current;\n if (!textarea) return;\n\n const startHeight = textarea.offsetHeight;\n let tracking = false;\n\n const handleMouseDown = () => {\n tracking = true;\n };\n\n const handleMouseMove = () => {\n if (!tracking || resized) return;\n\n const currentHeight = textarea.offsetHeight;\n\n if (currentHeight !== startHeight) {\n setResized(true);\n tracking = false;\n }\n };\n\n const handleMouseUp = () => {\n tracking = false;\n };\n\n window.addEventListener(\"mousedown\", handleMouseDown);\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n window.removeEventListener(\"mousedown\", handleMouseDown);\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [resized]);\n\n const updateHeight = () => {\n if (localRef.current && autoResizable && !verticallyResizable) {\n // https://stackoverflow.com/a/60795884\n localRef.current.style.height = \"0px\";\n const scrollHeight = localRef.current.scrollHeight;\n // + 2 to add border height\n localRef.current.style.height = scrollHeight + 2 + \"px\";\n }\n };\n\n return (\n <Aria.TextField\n {...rest}\n {...fieldProps}\n className={rootClassName}\n onChange={handleChange}\n >\n <PropsContextProvider props={fieldPropsContext}>\n <FieldErrorCaptureContext>{children}</FieldErrorCaptureContext>\n <Aria.TextArea\n rows={rows}\n {...(isReadOnly ? { \"data-readonly\": true } : {})}\n aria-readonly={isReadOnly}\n aria-hidden={props[\"aria-hidden\"]}\n placeholder={placeholder}\n className={inputClassName}\n ref={localRef}\n onChange={updateHeight}\n style={{\n caretColor: isReadOnly ? \"transparent\" : undefined,\n minHeight: getHeight(rows),\n maxHeight: verticallyResizable\n ? undefined\n : getHeight(autoResizeMaxRows),\n }}\n />\n {showCharacterCount && (\n <FieldDescription>{charactersCountDescription}</FieldDescription>\n )}\n <FieldErrorView />\n </PropsContextProvider>\n </Aria.TextField>\n );\n});\n\nexport default TextArea;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TextArea.mjs","names":[],"sources":["../../../../../../../src/components/TextArea/TextArea.tsx"],"sourcesContent":["import * as Aria from \"react-aria-components\";\nimport styles from \"./TextArea.module.scss\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport { useObjectRef } from \"@react-aria/utils\";\nimport { useFieldComponent } from \"@/lib/hooks/useFieldComponent\";\nimport { PropsContextProvider } from \"@/lib/propsContext\";\nimport clsx from \"clsx\";\nimport {\n type PropsWithChildren,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { useControlledHostValueProps } from \"@/lib/remote/useControlledHostValueProps\";\nimport { useLocalizedStringFormatter } from \"@/components/TranslationProvider/useLocalizedStringFormatter\";\nimport locales from \"./locales/*.locale.json\";\nimport { FieldDescription } from \"@/components/FieldDescription\";\nimport { useWarnDeprecation } from \"@/components/DeprecationWarningProvider\";\n\nexport interface TextAreaProps\n extends\n PropsWithChildren<Omit<Aria.TextFieldProps, \"children\">>,\n Pick<Aria.TextAreaProps, \"placeholder\" | \"rows\" | \"aria-hidden\">,\n FlowComponentProps<HTMLTextAreaElement> {\n /** Whether a character count should be displayed inside the field description. */\n showCharacterCount?: boolean;\n /**\n * Whether the text area should grow if its content gets longer than its\n * initial height.\n */\n autoResizeMaxRows?: number;\n /** Allows the user to manually resize the textArea horizontally. */\n allowResize?: boolean | \"horizontal\" | \"vertical\";\n /** @deprecated Use `allowResize` instead. */\n allowHorizontalResize?: boolean;\n /** @deprecated Use `allowResize` instead. */\n allowVerticalResize?: boolean;\n}\n\n/** @flr-generate all */\nexport const TextArea = flowComponent(\"TextArea\", (props) => {\n const warnDeprecation = useWarnDeprecation();\n const {\n children,\n placeholder,\n rows = 5,\n autoResizeMaxRows = rows,\n ref,\n allowVerticalResize,\n allowHorizontalResize,\n showCharacterCount,\n className,\n onChange,\n isReadOnly,\n value,\n ...rest\n } = useControlledHostValueProps(props, \"\");\n\n if (allowHorizontalResize !== undefined) {\n warnDeprecation(\n \"The 'allowHorizontalResize' prop is deprecated and will be removed in a future release. Use 'allowResize' instead.\",\n );\n }\n if (allowVerticalResize !== undefined) {\n warnDeprecation(\n \"The 'allowVerticalResize' prop is deprecated and will be removed in a future release. Use 'allowResize' instead.\",\n );\n }\n\n const {\n FieldErrorView,\n FieldErrorCaptureContext,\n fieldPropsContext,\n fieldProps,\n } = useFieldComponent(props, \"TextArea\");\n\n let { allowResize } = props;\n if (allowVerticalResize) {\n allowResize = \"vertical\";\n } else if (allowHorizontalResize) {\n allowResize = \"horizontal\";\n }\n\n const rootClassName = clsx(fieldProps.className, className);\n\n const inputClassName = clsx(\n styles.input,\n typeof allowResize === \"boolean\" && allowResize ? styles.resize : null,\n allowResize === \"horizontal\"\n ? styles.horizontalResize\n : allowResize === \"vertical\"\n ? styles.verticalResize\n : null,\n );\n\n const handleChange = (v: string) => {\n if (isReadOnly) {\n return;\n }\n\n if (onChange) {\n onChange(v);\n }\n };\n\n const translation = useLocalizedStringFormatter(locales, \"TextArea\");\n\n // Derived, so that a value the field never saw typed is counted as well.\n const charactersCountDescription = translation.format(\"characters\", {\n count: value.length,\n maxCount: props.maxLength ?? 0,\n });\n\n const localRef = useObjectRef(ref);\n\n const getHeight = (rows: number) => {\n return `calc(var(--line-height-m) * ${rows} + (var(--form-control--padding-y) * 2))`;\n };\n\n const [resized, setResized] = useState(false);\n\n const autoResizable = rows !== autoResizeMaxRows;\n\n const verticallyResizable =\n allowResize && (!autoResizable || (autoResizable && resized));\n\n useEffect(() => {\n const textarea = localRef.current;\n if (!textarea) return;\n\n const startHeight = textarea.offsetHeight;\n let tracking = false;\n\n const handleMouseDown = () => {\n tracking = true;\n };\n\n const handleMouseMove = () => {\n if (!tracking || resized) return;\n\n const currentHeight = textarea.offsetHeight;\n\n if (currentHeight !== startHeight) {\n setResized(true);\n tracking = false;\n }\n };\n\n const handleMouseUp = () => {\n tracking = false;\n };\n\n window.addEventListener(\"mousedown\", handleMouseDown);\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n window.removeEventListener(\"mousedown\", handleMouseDown);\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [resized]);\n\n /*\n * The height depends on the rendered content, so it cannot be a style. It is\n * synced to the value instead of to the `change` event, because a value the\n * field never saw typed — an initial value, or a draft loaded into a\n * controlled field — has to resize it just the same.\n */\n useLayoutEffect(() => {\n const textArea = localRef.current;\n if (!textArea || !autoResizable || verticallyResizable) {\n return;\n }\n // https://stackoverflow.com/a/60795884\n textArea.style.height = \"0px\";\n // + 2 to add border height\n textArea.style.height = `${textArea.scrollHeight + 2}px`;\n }, [value, autoResizable, verticallyResizable]);\n\n return (\n <Aria.TextField\n {...rest}\n {...fieldProps}\n value={value}\n className={rootClassName}\n onChange={handleChange}\n >\n <PropsContextProvider props={fieldPropsContext}>\n <FieldErrorCaptureContext>{children}</FieldErrorCaptureContext>\n <Aria.TextArea\n rows={rows}\n {...(isReadOnly ? { \"data-readonly\": true } : {})}\n aria-readonly={isReadOnly}\n aria-hidden={props[\"aria-hidden\"]}\n placeholder={placeholder}\n className={inputClassName}\n ref={localRef}\n style={{\n caretColor: isReadOnly ? \"transparent\" : undefined,\n minHeight: getHeight(rows),\n maxHeight: verticallyResizable\n ? undefined\n : getHeight(autoResizeMaxRows),\n }}\n />\n {showCharacterCount && (\n <FieldDescription>{charactersCountDescription}</FieldDescription>\n )}\n <FieldErrorView />\n </PropsContextProvider>\n </Aria.TextField>\n );\n});\n\nexport default TextArea;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.module.mjs","names":[],"sources":["../../../../../../../src/components/Tooltip/Tooltip.module.scss"],"sourcesContent":[".tooltip {\n border-radius: var(--tooltip--corner-radius);\n background-color: var(--tooltip--background-color);\n color: var(--tooltip--color);\n font-size: var(--tooltip--font-size);\n padding-block: var(--tooltip--padding-y);\n padding-inline: var(--tooltip--padding-x);\n max-width: var(--tooltip--max-width);\n transform: translate3d(0, 0, 0);\n box-shadow: var(--tooltip--box-shadow);\n\n --translate-origin-length: var(--tooltip--tooltip-to-trigger-spacing) / 2;\n\n /* Placement */\n &[data-placement=\"top\"] {\n margin-bottom: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateY(var(--translate-origin-length));\n }\n\n &[data-placement=\"bottom\"] {\n margin-top: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateY(var(--translate-origin-length) * -1);\n\n .tip svg {\n transform: rotate(180deg);\n }\n }\n\n &[data-placement=\"right\"] {\n margin-inline-start: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateX(var(--translate-origin-length) * -1);\n\n .tip svg {\n transform: rotate(90deg);\n }\n }\n\n &[data-placement=\"left\"] {\n margin-inline-end: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateX(var(--translate-origin-length));\n\n .tip svg {\n transform: rotate(-90deg);\n }\n }\n\n /* Animation */\n\n &[data-entering] {\n animation: slide 200ms;\n }\n\n &[data-exiting] {\n animation: slide 200ms reverse ease-in;\n }\n\n .tip {\n width: var(--tooltip--tip-size);\n height: var(--tooltip--tip-size);\n\n svg {\n display: block;\n fill: var(--tooltip--background-color);\n }\n }\n}\n\n@keyframes slide {\n from {\n transform: var(--translate-origin);\n opacity: 0;\n }\n\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Tooltip.module.mjs","names":[],"sources":["../../../../../../../src/components/Tooltip/Tooltip.module.scss"],"sourcesContent":[".tooltip {\n border-radius: var(--tooltip--corner-radius);\n background-color: var(--tooltip--background-color);\n color: var(--tooltip--color);\n font-size: var(--tooltip--font-size);\n padding-block: var(--tooltip--padding-y);\n padding-inline: var(--tooltip--padding-x);\n max-width: var(--tooltip--max-width);\n transform: translate3d(0, 0, 0);\n box-shadow: var(--tooltip--box-shadow);\n\n --translate-origin-length: var(--tooltip--tooltip-to-trigger-spacing) / 2;\n\n /**\n * React Aria sets `data-placement` once it has computed a position, and\n * renders the overlay at `top: 0; left: 0` of the viewport until then. It\n * skips computing one when the tooltip mounts for its exit animation alone –\n * swapping quickly between neighbouring triggers does that – and never\n * retries afterwards, so such a tooltip stays parked in the corner for its\n * whole lifetime. Keep it out of sight instead. `visibility` rather than\n * `display`, so the overlay stays measurable for the positioning pass.\n */\n &:not([data-placement]) {\n visibility: hidden;\n }\n\n /* Placement */\n &[data-placement=\"top\"] {\n margin-bottom: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateY(var(--translate-origin-length));\n }\n\n &[data-placement=\"bottom\"] {\n margin-top: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateY(var(--translate-origin-length) * -1);\n\n .tip svg {\n transform: rotate(180deg);\n }\n }\n\n &[data-placement=\"right\"] {\n margin-inline-start: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateX(var(--translate-origin-length) * -1);\n\n .tip svg {\n transform: rotate(90deg);\n }\n }\n\n &[data-placement=\"left\"] {\n margin-inline-end: var(--tooltip--tooltip-to-trigger-spacing);\n\n --translate-origin: translateX(var(--translate-origin-length));\n\n .tip svg {\n transform: rotate(-90deg);\n }\n }\n\n /* Animation */\n\n &[data-entering] {\n animation: slide 200ms;\n }\n\n &[data-exiting] {\n animation: slide 200ms reverse ease-in;\n }\n\n .tip {\n width: var(--tooltip--tip-size);\n height: var(--tooltip--tip-size);\n\n svg {\n display: block;\n fill: var(--tooltip--background-color);\n }\n }\n}\n\n@keyframes slide {\n from {\n transform: var(--translate-origin);\n opacity: 0;\n }\n\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n"],"mappings":""}
@@ -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":";;;;;;;;AAoDA,IAAa,oBAAb,MAAa,kBAAkB;CAC7B,SAAgB;CAChB,qBAA4B;CAC5B,iCAAyB,IAAI,IAAwB;CACrD,kCAA0B,IAAI,IAAyB;CACvD,uCAA+B,IAAI,IAA6B;CAEhE,wBAA+B;CAC/B,mBAA0B;CAC1B;;;;;;;CAOA,wBAAgC,WAAW,IAAqB;;;;;;;;CAQhE,iDAAyC,IAAI,IAAY;;;;;;CAMzD;CAEA,YAAmB,UAA8B,CAAC,GAAG;EACnD,eAAe,MAAM;GACnB,QAAQ;GACR,oBAAoB;GACpB,uBAAuB;GACvB,uBAAuB;GACvB,MAAM,OAAO;GACb,OAAO,OAAO;GACd,QAAQ,OAAO;GACf,SAAS,OAAO;GAChB,UAAU,OAAO;GACjB,uBAAuB,OAAO;GAC9B,cAAc,OAAO;GACrB,oBAAoB,OAAO;EAC7B,CAAC;EACD,MAAM,EAAE,gBAAgB,OAAO,iBAAiB,UAAU;EAC1D,KAAK,SAAS;EACd,KAAK,4BAA4B;CACnC;;CAGA,IAAW,wBAAiC;EAC1C,IAAI,KAAK,sBAAsB,SAAS,GACtC,OAAO,KAAK;EAEd,OAAO,MAAM,KAAK,KAAK,sBAAsB,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO;CACrE;CAEA,iBAAwB,UAAoC,CAAC,GAAS;EACpE,MAAM,EAAE,QAAQ,SAAS,cAAc,mBAAmB;EAE1D,KAAK,aAAa,SAAS,MACzB,KAAK,oBAAoB,GAAG,KAAK,cAAc,CACjD;EACA,KAAK,aAAa,UAAU,MAC1B,KAAK,oBAAoB,GAAG,KAAK,eAAe,CAClD;EACA,KAAK,aAAa,eAAe,MAC/B,KAAK,oBAAoB,GAAG,KAAK,oBAAoB,CACvD;EAEA,KAAK,wBAAwB,cAAc;CAC7C;;;;;CAMA,wBAAgC,gBAA2C;EACzE,MAAM,SAAS,iBAAyB,CAAC,EAAE;EAE3C,gBAAgB;GACd,IAAI,mBAAmB,KAAA,GAAW;IAChC,KAAK,2BAA2B,MAAM;IACtC;GACF;GACA,KAAK,wBAAwB,QAAQ,cAAc;GACnD,aAAa,KAAK,2BAA2B,MAAM;EACrD,GAAG;GAAC;GAAM;GAAQ;EAAc,CAAC;CACnC;CAEA,wBAAgC,QAAgB,gBAAyB;EACvE,kBAAkB,KAAK,sBAAsB,IAAI,QAAQ,cAAc,CAAC;CAC1E;CAEA,2BAAmC,QAAgB;EACjD,kBAAkB,KAAK,sBAAsB,OAAO,MAAM,CAAC;CAC7D;;;;;;;CAQA,YACE,UACA,UAAkC,CAAC,GACnC;EACA,MAAM,EAAE,eAAe,CAAC,MAAM;EAC9B,MAAM,SAAS,KAAK,UAAU;EAC9B,MAAM,UAAU,OAAO,KAAK,MAAM;EAElC,KAAK,iBAAiB,EACpB,cAAc;GACZ,QAAQ,UAAU;EACpB,EACF,CAAC;EAED,gBAAgB;GACd,aAAa;IACX,IAAI,CAAC,UAAU,QAAQ,SAAS;KAC9B,QAAQ,UAAU;KAClB,SAAS;IACX;GACF;EACF,GAAG,CAAC,QAAQ,GAAG,YAAY,CAAC;CAC9B;CAEA,OAAc,OACZ,UAAoC,CAAC,GAClB;EACnB,MAAM,aAAa,gBAAgB,IAAI,kBAAkB,OAAO,CAAC;EACjE,WAAW,iBAAiB,OAAO;EACnC,OAAO;CACT;CAEA,oBACE,SACA,aACY;EACZ,YAAY,IAAI,OAAO;EACvB,aAAa;GACX,YAAY,OAAO,OAAO;EAC5B;CACF;CAEA,aACE,SACA,cACA;EACA,gBACS,UAAU,aAAa,OAAO,IAAI,KAAA,GACzC,CAAC,SAAS,IAAI,CAChB;CACF;CAEA,gBACE,QACA,UAGS;EAIT,OAHsB,MAAM,KAAK,QAAQ,CAAC,CAAC,KAAK,YAC9C,QAAQ,MAAM,CAET,CAAA,CAAc,MAAM,WAAW,WAAW,KAAK;CACxD;CAEA,iBAAkC;EAChC,OAAO,KAAK,gBAAgB,OAAO,KAAK,eAAe;CACzD;CAEA,gBAAiC;EAC/B,OAAO,KAAK,gBAAgB,MAAM,KAAK,cAAc;CACvD;CAEA,oBAA4B,QAA0B;EACpD,OAAO,KAAK,gBAAgB,QAAQ,KAAK,oBAAoB;CAC/D;CAEA,WAAkB,SAA8B;EAC9C,OAAO,KAAK,oBAAoB,SAAS,KAAK,eAAe;CAC/D;CAEA,UAAiB,SAA6B;EAC5C,OAAO,KAAK,oBAAoB,SAAS,KAAK,cAAc;CAC9D;CAEA,gBAAuB,SAAkC;EACvD,OAAO,KAAK,oBAAoB,SAAS,KAAK,oBAAoB;CACpE;CAEA,OAAoB;EAClB,KAAK,QAAQ,IAAI;CACnB;CAEA,MAAa,SAA8B;EACzC,KAAK,QAAQ,OAAO,OAAO;CAC7B;CAEA,SAAsB;EACpB,KAAK,QAAQ,CAAC,KAAK,MAAM;CAC3B;CAEA,QAAe,QAAiB,UAAwB,CAAC,GAAS;EAChE,IAAI,KAAK,WAAW,UAAU,KAAK,sBAAsB,QACvD;EAGF,KAAK,oBAAoB;EACzB,IAAI;GACF,KAAK,eAAe,QAAQ,OAAO;EACrC,UAAU;GACR,KAAK,oBAAoB,KAAA;EAC3B;CACF;;;;;;CAOA,SAAgB,QAAuB;EACrC,KAAK,SAAS;CAChB;CAEA,eAAuB,QAAiB,SAA6B;EACnE,MAAM,EAAE,qBAAqB,UAAU;EAEvC,IAAI,WAAW,OAAO;GAIpB,MAAM,mBAAmB,KAAK;GAC9B,KAAK,mBAAmB;GAExB,IACE,KAAK,yBACL,CAAC,oBACD,KAAK,+BAA+B,SAAS,KAC7C,CAAC,oBACD;IACA,KAAK,wBAAwB;IAC7B;GACF;EACF;EAEA,IAAI;EACJ,IAAI,QACF,UAAU,KAAK,cAAc;OAE7B,UAAU,KAAK,eAAe;EAEhC,IAAI,CAAC,SACH,UAAU,KAAK,oBAAoB,MAAM;EAG3C,IAAI,CAAC,SACH,KAAK,SAAS;CAElB;CAEA,sBAA6B,IAAmB;EAC9C,KAAK,qBAAqB;CAC5B;CAEA,YAAmB;EACjB,OAAO,kBAAkB,KAAK,MAAM;CACtC;CAEA,wBAA+B;EAC7B,OAAO,kBAAkB,KAAK,kBAAkB;CAClD;CAEA,2BAAkC;EAChC,OAAO,kBAAkB,KAAK,qBAAqB;CACrD;CAEA,2BAAkC;EAChC,OAAO,kBAAkB,KAAK,qBAAqB;CACrD;CAEA,4BAAmC;EACjC,OAAO,sCAAsC,IAAI;CACnD;;;;;;;;;CAUA,gCAAmD;EACjD,MAAM,QAAQ,CAAC;EACf,KAAK,+BAA+B,IAAI,KAAK;EAC7C,aAAa;GACX,KAAK,+BAA+B,OAAO,KAAK;EAClD;CACF;CAEA,eAA4B;EAC1B,KAAK,mBAAmB;EACxB,KAAK,wBAAwB;CAC/B;CAEA,qBAAkC;EAChC,KAAK,wBAAwB;CAC/B;AACF"}
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"}
@@ -2,8 +2,7 @@ import { OverlayController } from '../../../lib/controller';
2
2
  import { ActionProps } from '../types';
3
3
  import { ActionState } from './ActionState';
4
4
  import { OverlayContext } from '../../../lib/controller/overlay/context';
5
- import { FlowComponentName } from '../../propTypes';
6
- import { CloseModalOptions, CloseOverlayOptions } from '../../../lib/controller/overlay/OverlayController';
5
+ import { OverlayReference } from '../../../lib/controller/overlay/OverlayController';
7
6
  interface InitObject {
8
7
  actionProps: ActionProps;
9
8
  parentAction?: ActionModel;
@@ -23,8 +22,17 @@ export declare class ActionModel {
23
22
  static useNew(actionProps: ActionProps, init?: Partial<InitObject>): ActionModel;
24
23
  static use(): ActionModel;
25
24
  static useConfirmationAction(): ActionModel;
26
- getOverlayController(from: FlowComponentName | OverlayController | CloseOverlayOptions | CloseModalOptions): OverlayController | undefined;
27
- static getCloseOverlayOptions: (options?: OverlayController | FlowComponentName | CloseOverlayOptions | CloseModalOptions | true) => CloseModalOptions | undefined;
25
+ /**
26
+ * Resolves an overlay reference against this action's overlay context.
27
+ *
28
+ * Returns `undefined` unless the action carries one of the overlay props –
29
+ * `Action` relies on that to tell whether it owns a surrounding `Modal`'s
30
+ * controller.
31
+ */
32
+ getOverlayController(from: OverlayReference): OverlayController | undefined;
33
+ private get hasOverlayProps();
34
+ private resolveOverlayReference;
35
+ static getCloseOverlayOptions: (options?: OverlayReference) => import('../../../lib/controller/overlay/OverlayController').CloseOverlayOptions | undefined;
28
36
  execute: (...args: unknown[]) => void;
29
37
  }
30
38
  export {};
@@ -16,8 +16,15 @@ export interface ActionProps extends PropsWithChildren, FlowComponentProps {
16
16
  * components share one action state.
17
17
  */
18
18
  actionModel?: ActionModel;
19
- /** The overlay to close when the action is triggered. */
20
- closeOverlay?: FlowComponentName | OverlayController | CloseOverlayOptions;
19
+ /**
20
+ * The overlay to close when the action is triggered. `true` closes the
21
+ * nearest enclosing overlay, whichever component it is — a name still wins,
22
+ * so `closeOverlay="Modal"` inside a `Popover` closes the outer modal.
23
+ *
24
+ * There is no `openOverlay={true}` counterpart: the nearest overlay is the
25
+ * one this action renders inside, so it is open by definition.
26
+ */
27
+ closeOverlay?: boolean | FlowComponentName | OverlayController | CloseOverlayOptions;
21
28
  /** The overlay to open when the action is triggered. */
22
29
  openOverlay?: FlowComponentName | OverlayController;
23
30
  /** The overlay to open or close when the action is triggered. */
@@ -1,6 +1,12 @@
1
1
  import { CartesianChartLayout } from './types';
2
2
  interface CartesianChartContext {
3
3
  layout: CartesianChartLayout;
4
+ /**
5
+ * Prefix that scopes a stack ID to this chart. Recharts derives DOM IDs from
6
+ * the stack ID, so two charts on one page sharing a stack ID would otherwise
7
+ * share their clip paths.
8
+ */
9
+ stackIdPrefix: string;
4
10
  }
5
11
  export declare const useCartesianChartContext: () => CartesianChartContext;
6
12
  export declare const CartesianChartContextProvider: import('react').Provider<CartesianChartContext>;
@@ -0,0 +1,6 @@
1
+ import { StackId } from 'recharts/types/util/ChartUtils';
2
+ /**
3
+ * Scopes a stack ID to the surrounding chart, so that charts on the same page
4
+ * using the same stack ID do not share the DOM IDs Recharts derives from it.
5
+ */
6
+ export declare const useScopedStackId: (stackId: StackId | undefined) => string | undefined;
@@ -1,4 +1,8 @@
1
1
  export type ContextMenuSelectionMode = "single" | "multiple" | "navigation" | "switch";
2
2
  export declare const getAriaSelectionMode: (selectionMode?: ContextMenuSelectionMode) => "single" | "multiple" | "none" | undefined;
3
3
  export declare const getMenuItemSelectionVariant: (selectionMode?: ContextMenuSelectionMode) => "switch" | "navigation" | "control" | undefined;
4
- export declare const getCloseOverlayType: (selectionMode?: ContextMenuSelectionMode) => "ContextMenu" | undefined;
4
+ /**
5
+ * Whether selecting an item closes the menu. A mode that collects several
6
+ * selections keeps it open.
7
+ */
8
+ export declare const closesOnSelect: (selectionMode?: ContextMenuSelectionMode) => selectionMode is "single" | "navigation" | undefined;
@@ -0,0 +1,4 @@
1
+ import { ComponentProps, FC } from 'react';
2
+ import { Icon } from '../..';
3
+ export declare const IconAIHosting: FC<Omit<ComponentProps<typeof Icon>, "children">>;
4
+ export default IconAIHosting;