@mittwald/flow-react-components 1.3.4 → 1.4.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/MIGRATION.md +25 -2
  2. package/dist/assets/component-index.json +1 -1
  3. package/dist/assets/doc-properties.json +1 -1
  4. package/dist/css/all-layered.css +1 -1
  5. package/dist/css/all.css +1 -1
  6. package/dist/js/_virtual/_24.locale.mjs +10 -2
  7. package/dist/js/default.mjs +2 -1
  8. package/dist/js/flr-universal.mjs +2 -1
  9. package/dist/js/packages/components/src/components/Action/models/ActionModel.mjs +25 -8
  10. package/dist/js/packages/components/src/components/Action/models/ActionModel.mjs.map +1 -1
  11. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.mjs +0 -1
  12. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.mjs.map +1 -1
  13. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.module.mjs +2 -4
  14. package/dist/js/packages/components/src/components/CheckboxButton/CheckboxButton.module.mjs.map +1 -1
  15. package/dist/js/packages/components/src/components/ContextMenu/ContextMenu.mjs +2 -2
  16. package/dist/js/packages/components/src/components/ContextMenu/ContextMenu.mjs.map +1 -1
  17. package/dist/js/packages/components/src/components/ContextMenu/components/ContextMenuSection/ContextMenuSection.mjs +2 -2
  18. package/dist/js/packages/components/src/components/ContextMenu/components/ContextMenuSection/ContextMenuSection.mjs.map +1 -1
  19. package/dist/js/packages/components/src/components/ContextMenu/lib.mjs +7 -3
  20. package/dist/js/packages/components/src/components/ContextMenu/lib.mjs.map +1 -1
  21. package/dist/js/packages/components/src/components/CopyButton/CopyButton.mjs +4 -3
  22. package/dist/js/packages/components/src/components/CopyButton/CopyButton.mjs.map +1 -1
  23. package/dist/js/packages/components/src/components/Icon/components/icons/IconAIHosting.mjs +19 -0
  24. package/dist/js/packages/components/src/components/Icon/components/icons/IconAIHosting.mjs.map +1 -0
  25. package/dist/js/packages/components/src/components/Image/Image.mjs +2 -2
  26. package/dist/js/packages/components/src/components/Image/Image.mjs.map +1 -1
  27. package/dist/js/packages/components/src/components/Image/Image.module.mjs +3 -1
  28. package/dist/js/packages/components/src/components/Image/Image.module.mjs.map +1 -1
  29. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.mjs +16 -3
  30. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -1
  31. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.module.mjs +4 -2
  32. package/dist/js/packages/components/src/components/MarkdownEditor/MarkdownEditor.module.mjs.map +1 -1
  33. package/dist/js/packages/components/src/components/MarkdownEditor/components/AttachmentButton.mjs +47 -0
  34. package/dist/js/packages/components/src/components/MarkdownEditor/components/AttachmentButton.mjs.map +1 -0
  35. package/dist/js/packages/components/src/components/MarkdownEditor/components/Toolbar.mjs +21 -20
  36. package/dist/js/packages/components/src/components/MarkdownEditor/components/Toolbar.mjs.map +1 -1
  37. package/dist/js/packages/components/src/components/MarkdownEditor/components/ToolbarButton.mjs +1 -1
  38. package/dist/js/packages/components/src/components/MarkdownEditor/components/ToolbarButton.mjs.map +1 -1
  39. package/dist/js/packages/components/src/components/MarkdownEditor/lib/fileUpload.mjs +73 -0
  40. package/dist/js/packages/components/src/components/MarkdownEditor/lib/fileUpload.mjs.map +1 -0
  41. package/dist/js/packages/components/src/components/MarkdownEditor/lib/useFileUpload.mjs +141 -0
  42. package/dist/js/packages/components/src/components/MarkdownEditor/lib/useFileUpload.mjs.map +1 -0
  43. package/dist/js/packages/components/src/components/Modal/Modal.mjs +6 -4
  44. package/dist/js/packages/components/src/components/Modal/Modal.mjs.map +1 -1
  45. package/dist/js/packages/components/src/components/OverlayTrigger/OverlayTrigger.mjs +1 -0
  46. package/dist/js/packages/components/src/components/OverlayTrigger/OverlayTrigger.mjs.map +1 -1
  47. package/dist/js/packages/components/src/components/TabNavigation/lib/useCollapsingItems.mjs +1 -2
  48. package/dist/js/packages/components/src/components/TabNavigation/lib/useCollapsingItems.mjs.map +1 -1
  49. package/dist/js/packages/components/src/components/Tabs/lib/useTabIndicator.mjs +2 -3
  50. package/dist/js/packages/components/src/components/Tabs/lib/useTabIndicator.mjs.map +1 -1
  51. package/dist/js/packages/components/src/lib/controller/overlay/OverlayContextProvider.mjs +6 -3
  52. package/dist/js/packages/components/src/lib/controller/overlay/OverlayContextProvider.mjs.map +1 -1
  53. package/dist/js/packages/components/src/lib/controller/overlay/OverlayController.mjs.map +1 -1
  54. package/dist/js/packages/components/src/lib/controller/overlay/context.mjs +1 -1
  55. package/dist/js/packages/components/src/lib/controller/overlay/context.mjs.map +1 -1
  56. package/dist/js/packages/components/src/lib/controller/overlay/useOverlayController.mjs +1 -1
  57. package/dist/js/packages/components/src/lib/controller/overlay/useOverlayController.mjs.map +1 -1
  58. package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs +1 -1
  59. package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs.map +1 -1
  60. package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs +1 -1
  61. package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs.map +1 -1
  62. package/dist/types/components/Action/models/ActionModel.d.ts +12 -4
  63. package/dist/types/components/Action/types.d.ts +9 -2
  64. package/dist/types/components/ContextMenu/lib.d.ts +5 -1
  65. package/dist/types/components/CopyButton/CopyButton.d.ts +5 -0
  66. package/dist/types/components/Icon/components/icons/IconAIHosting.d.ts +4 -0
  67. package/dist/types/components/Icon/components/icons/index.d.ts +1 -0
  68. package/dist/types/components/Image/Image.d.ts +7 -1
  69. package/dist/types/components/MarkdownEditor/MarkdownEditor.d.ts +20 -0
  70. package/dist/types/components/MarkdownEditor/components/AttachmentButton.d.ts +1 -0
  71. package/dist/types/components/MarkdownEditor/components/Toolbar.d.ts +11 -2
  72. package/dist/types/components/MarkdownEditor/components/ToolbarButton.d.ts +8 -2
  73. package/dist/types/components/MarkdownEditor/index.d.ts +1 -1
  74. package/dist/types/components/MarkdownEditor/lib/fileUpload.d.ts +19 -0
  75. package/dist/types/components/MarkdownEditor/lib/useFileUpload.d.ts +1 -0
  76. package/dist/types/lib/controller/overlay/OverlayContextProvider.d.ts +9 -0
  77. package/dist/types/lib/controller/overlay/OverlayController.d.ts +11 -1
  78. package/dist/types/lib/controller/overlay/context.d.ts +19 -2
  79. package/package.json +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"useTabIndicator.mjs","names":[],"sources":["../../../../../../../../src/components/Tabs/lib/useTabIndicator.ts"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport { useLayoutEffect, useRef, useState } from \"react\";\nimport { createFrameResizeObserver } from \"@/lib/dom/createFrameResizeObserver\";\n\ninterface TabIndicatorState {\n x: number;\n width: number;\n isAnimated: boolean;\n}\n\ninterface TabIndicatorStyle extends CSSProperties {\n \"--tab-indicator-x\": string;\n \"--tab-indicator-width\": string;\n}\n\nconst getTabIndicatorStyle = (\n state: TabIndicatorState | undefined,\n): TabIndicatorStyle | undefined =>\n state && {\n \"--tab-indicator-x\": `${state.x}px`,\n \"--tab-indicator-width\": `${state.width}px`,\n };\n\nexport const useTabIndicator = (isCollapsed: boolean) => {\n const rootRef = useRef<HTMLDivElement | null>(null);\n const titlesRef = useRef<HTMLDivElement | null>(null);\n const hasMeasuredRef = useRef(false);\n const [indicator, setIndicator] = useState<TabIndicatorState | undefined>();\n\n const resetIndicator = () => {\n hasMeasuredRef.current = false;\n // React bails out of the re-render when the state is already `undefined`.\n setIndicator(undefined);\n };\n\n useLayoutEffect(() => {\n const root = rootRef.current;\n const titles = titlesRef.current;\n\n if (!root || !titles || isCollapsed) {\n resetIndicator();\n return;\n }\n\n const measureIndicator = () => {\n const selectedTab = titles.querySelector<HTMLElement>(\"[data-selected]\");\n\n if (!selectedTab) {\n resetIndicator();\n return;\n }\n\n const rootRect = root.getBoundingClientRect();\n const selectedTabRect = selectedTab.getBoundingClientRect();\n\n /*\n * `getBoundingClientRect` reports rendered pixels, but the custom\n * properties below are read as lengths inside the same subtree. Where an\n * ancestor scales it — a `transform`, a CSS `zoom` — the two differ, and\n * writing the rendered value back scales it a second time. The root's own\n * rendered and layout width give the factor between them.\n */\n const scale =\n root.offsetWidth > 0 ? rootRect.width / root.offsetWidth : 1;\n\n const nextIndicator: TabIndicatorState = {\n x: (selectedTabRect.left - rootRect.left) / scale,\n width: selectedTabRect.width / scale,\n isAnimated: hasMeasuredRef.current,\n };\n\n setIndicator((previousIndicator) => {\n if (\n previousIndicator &&\n previousIndicator.x === nextIndicator.x &&\n previousIndicator.width === nextIndicator.width &&\n previousIndicator.isAnimated === nextIndicator.isAnimated\n ) {\n return previousIndicator;\n }\n\n return nextIndicator;\n });\n\n hasMeasuredRef.current = true;\n };\n\n measureIndicator();\n\n const observer = createFrameResizeObserver(measureIndicator);\n observer.observe([root, titles]);\n\n return () => observer.disconnect();\n });\n\n return {\n rootRef,\n titlesRef,\n indicatorStyle: getTabIndicatorStyle(indicator),\n isAnimated: indicator?.isAnimated ?? false,\n };\n};\n"],"mappings":";;;;;AAeA,IAAM,wBACJ,UAEA,SAAS;CACP,qBAAqB,GAAG,MAAM,EAAE;CAChC,yBAAyB,GAAG,MAAM,MAAM;AAC1C;AAEF,IAAa,mBAAmB,gBAAyB;CACvD,MAAM,UAAU,OAA8B,IAAI;CAClD,MAAM,YAAY,OAA8B,IAAI;CACpD,MAAM,iBAAiB,OAAO,KAAK;CACnC,MAAM,CAAC,WAAW,gBAAgB,SAAwC;CAE1E,MAAM,uBAAuB;EAC3B,eAAe,UAAU;EAEzB,aAAa,KAAA,CAAS;CACxB;CAEA,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,SAAS,UAAU;EAEzB,IAAI,CAAC,QAAQ,CAAC,UAAU,aAAa;GACnC,eAAe;GACf;EACF;EAEA,MAAM,yBAAyB;GAC7B,MAAM,cAAc,OAAO,cAA2B,iBAAiB;GAEvE,IAAI,CAAC,aAAa;IAChB,eAAe;IACf;GACF;GAEA,MAAM,WAAW,KAAK,sBAAsB;GAC5C,MAAM,kBAAkB,YAAY,sBAAsB;GAS1D,MAAM,QACJ,KAAK,cAAc,IAAI,SAAS,QAAQ,KAAK,cAAc;GAE7D,MAAM,gBAAmC;IACvC,IAAI,gBAAgB,OAAO,SAAS,QAAQ;IAC5C,OAAO,gBAAgB,QAAQ;IAC/B,YAAY,eAAe;GAC7B;GAEA,cAAc,sBAAsB;IAClC,IACE,qBACA,kBAAkB,MAAM,cAAc,KACtC,kBAAkB,UAAU,cAAc,SAC1C,kBAAkB,eAAe,cAAc,YAE/C,OAAO;IAGT,OAAO;GACT,CAAC;GAED,eAAe,UAAU;EAC3B;EAEA,iBAAiB;EAEjB,MAAM,WAAW,0BAA0B,gBAAgB;EAC3D,SAAS,QAAQ,CAAC,MAAM,MAAM,CAAC;EAE/B,aAAa,SAAS,WAAW;CACnC,CAAC;CAED,OAAO;EACL;EACA;EACA,gBAAgB,qBAAqB,SAAS;EAC9C,YAAY,WAAW,cAAc;CACvC;AACF"}
1
+ {"version":3,"file":"useTabIndicator.mjs","names":[],"sources":["../../../../../../../../src/components/Tabs/lib/useTabIndicator.ts"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport { useLayoutEffect, useRef, useState } from \"react\";\nimport { createFrameResizeObserver } from \"@/lib/dom/createFrameResizeObserver\";\n\ninterface TabIndicatorState {\n x: number;\n width: number;\n isAnimated: boolean;\n}\n\ninterface TabIndicatorStyle extends CSSProperties {\n \"--tab-indicator-x\": string;\n \"--tab-indicator-width\": string;\n}\n\nconst getTabIndicatorStyle = (\n state: TabIndicatorState | undefined,\n): TabIndicatorStyle | undefined =>\n state && {\n \"--tab-indicator-x\": `${state.x}px`,\n \"--tab-indicator-width\": `${state.width}px`,\n };\n\nexport const useTabIndicator = (isCollapsed: boolean) => {\n const rootRef = useRef<HTMLDivElement | null>(null);\n const titlesRef = useRef<HTMLDivElement | null>(null);\n const hasMeasuredRef = useRef(false);\n const [indicator, setIndicator] = useState<TabIndicatorState | undefined>();\n\n const resetIndicator = () => {\n hasMeasuredRef.current = false;\n // React bails out of the re-render when the state is already `undefined`.\n setIndicator(undefined);\n };\n\n useLayoutEffect(() => {\n const root = rootRef.current;\n const titles = titlesRef.current;\n\n if (!root || !titles || isCollapsed) {\n resetIndicator();\n return;\n }\n\n const measureIndicator = () => {\n const selectedTab = titles.querySelector<HTMLElement>(\"[data-selected]\");\n\n if (!selectedTab) {\n resetIndicator();\n return;\n }\n\n const rootRect = root.getBoundingClientRect();\n const selectedTabRect = selectedTab.getBoundingClientRect();\n const nextIndicator: TabIndicatorState = {\n x: selectedTabRect.left - rootRect.left,\n width: selectedTabRect.width,\n isAnimated: hasMeasuredRef.current,\n };\n\n setIndicator((previousIndicator) => {\n if (\n previousIndicator &&\n previousIndicator.x === nextIndicator.x &&\n previousIndicator.width === nextIndicator.width &&\n previousIndicator.isAnimated === nextIndicator.isAnimated\n ) {\n return previousIndicator;\n }\n\n return nextIndicator;\n });\n\n hasMeasuredRef.current = true;\n };\n\n measureIndicator();\n\n const observer = createFrameResizeObserver(measureIndicator);\n observer.observe([root, titles]);\n\n return () => observer.disconnect();\n });\n\n return {\n rootRef,\n titlesRef,\n indicatorStyle: getTabIndicatorStyle(indicator),\n isAnimated: indicator?.isAnimated ?? false,\n };\n};\n"],"mappings":";;;;;AAeA,IAAM,wBACJ,UAEA,SAAS;CACP,qBAAqB,GAAG,MAAM,EAAE;CAChC,yBAAyB,GAAG,MAAM,MAAM;AAC1C;AAEF,IAAa,mBAAmB,gBAAyB;CACvD,MAAM,UAAU,OAA8B,IAAI;CAClD,MAAM,YAAY,OAA8B,IAAI;CACpD,MAAM,iBAAiB,OAAO,KAAK;CACnC,MAAM,CAAC,WAAW,gBAAgB,SAAwC;CAE1E,MAAM,uBAAuB;EAC3B,eAAe,UAAU;EAEzB,aAAa,KAAA,CAAS;CACxB;CAEA,sBAAsB;EACpB,MAAM,OAAO,QAAQ;EACrB,MAAM,SAAS,UAAU;EAEzB,IAAI,CAAC,QAAQ,CAAC,UAAU,aAAa;GACnC,eAAe;GACf;EACF;EAEA,MAAM,yBAAyB;GAC7B,MAAM,cAAc,OAAO,cAA2B,iBAAiB;GAEvE,IAAI,CAAC,aAAa;IAChB,eAAe;IACf;GACF;GAEA,MAAM,WAAW,KAAK,sBAAsB;GAC5C,MAAM,kBAAkB,YAAY,sBAAsB;GAC1D,MAAM,gBAAmC;IACvC,GAAG,gBAAgB,OAAO,SAAS;IACnC,OAAO,gBAAgB;IACvB,YAAY,eAAe;GAC7B;GAEA,cAAc,sBAAsB;IAClC,IACE,qBACA,kBAAkB,MAAM,cAAc,KACtC,kBAAkB,UAAU,cAAc,SAC1C,kBAAkB,eAAe,cAAc,YAE/C,OAAO;IAGT,OAAO;GACT,CAAC;GAED,eAAe,UAAU;EAC3B;EAEA,iBAAiB;EAEjB,MAAM,WAAW,0BAA0B,gBAAgB;EAC3D,SAAS,QAAQ,CAAC,MAAM,MAAM,CAAC;EAE/B,aAAa,SAAS,WAAW;CACnC,CAAC;CAED,OAAO;EACL;EACA;EACA,gBAAgB,qBAAqB,SAAS;EAC9C,YAAY,WAAW,cAAc;CACvC;AACF"}
@@ -4,12 +4,15 @@ import { overlayContext, useOverlayContext } from "./context.mjs";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/lib/controller/overlay/OverlayContextProvider.tsx
6
6
  var OverlayContextProvider = (props) => {
7
- const { type, controller, children } = props;
7
+ const { type, controller, isOverlayContent = true, children } = props;
8
8
  const parentContext = useOverlayContext();
9
9
  return /* @__PURE__ */ jsx(overlayContext.Provider, {
10
10
  value: {
11
- ...parentContext,
12
- [type]: controller
11
+ byType: {
12
+ ...parentContext.byType,
13
+ [type]: controller
14
+ },
15
+ nearest: isOverlayContent ? controller : parentContext.nearest
13
16
  },
14
17
  children
15
18
  });
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayContextProvider.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayContextProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport {\n overlayContext,\n useOverlayContext,\n} from \"@/lib/controller/overlay/context\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\nimport type { OverlayController } from \"@/lib/controller\";\n\ninterface Props extends PropsWithChildren {\n type: FlowComponentName;\n controller: OverlayController;\n}\n\nexport const OverlayContextProvider: FC<Props> = (props) => {\n const { type, controller, children } = props;\n const parentContext = useOverlayContext();\n\n return (\n <overlayContext.Provider\n value={{\n ...parentContext,\n [type]: controller,\n }}\n >\n {children}\n </overlayContext.Provider>\n );\n};\n\nexport default OverlayContextProvider;\n"],"mappings":";;;;;AAaA,IAAa,0BAAqC,UAAU;CAC1D,MAAM,EAAE,MAAM,YAAY,aAAa;CACvC,MAAM,gBAAgB,kBAAkB;CAExC,OACE,oBAAC,eAAe,UAAhB;EACE,OAAO;GACL,GAAG;IACF,OAAO;EACV;EAEC;CACsB,CAAA;AAE7B"}
1
+ {"version":3,"file":"OverlayContextProvider.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayContextProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport {\n overlayContext,\n useOverlayContext,\n} from \"@/lib/controller/overlay/context\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\nimport type { OverlayController } from \"@/lib/controller\";\n\ninterface Props extends PropsWithChildren {\n type: FlowComponentName;\n controller: OverlayController;\n /**\n * Whether the children are the overlay's content. Content also registers the\n * controller as the _nearest_ overlay, which is what `closeOverlay` without a\n * name resolves to. Set `false` where the subtree is not inside the overlay –\n * `OverlayTrigger` wraps the trigger too.\n *\n * @default true\n */\n isOverlayContent?: boolean;\n}\n\nexport const OverlayContextProvider: FC<Props> = (props) => {\n const { type, controller, isOverlayContent = true, children } = props;\n const parentContext = useOverlayContext();\n\n return (\n <overlayContext.Provider\n value={{\n byType: {\n ...parentContext.byType,\n [type]: controller,\n },\n nearest: isOverlayContent ? controller : parentContext.nearest,\n }}\n >\n {children}\n </overlayContext.Provider>\n );\n};\n\nexport default OverlayContextProvider;\n"],"mappings":";;;;;AAsBA,IAAa,0BAAqC,UAAU;CAC1D,MAAM,EAAE,MAAM,YAAY,mBAAmB,MAAM,aAAa;CAChE,MAAM,gBAAgB,kBAAkB;CAExC,OACE,oBAAC,eAAe,UAAhB;EACE,OAAO;GACL,QAAQ;IACN,GAAG,cAAc;KAChB,OAAO;GACV;GACA,SAAS,mBAAmB,aAAa,cAAc;EACzD;EAEC;CACsB,CAAA;AAE7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayController.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n runInAction,\n} from \"mobx\";\nimport useSelector from \"@/lib/mobx/useSelector\";\nimport { useStatic } from \"@/lib/hooks/useStatic\";\nimport { useEffect, useRef, type DependencyList } from \"react\";\nimport { useCloseOverlayConfirmationController } from \"@/lib/controller/overlay/useCloseOverlayConfirmationController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport type OverlayOpenHandler = () => unknown;\nexport type OverlayCloseHandler = () => unknown;\nexport type OverlayOpenStateHandler = (isOpen: boolean) => unknown;\ntype AnyOverlayOpenStateHandler =\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler;\n\ntype DisposerFn = () => void;\n\nexport interface CloseOverlayOptions {\n overlay: FlowComponentName | OverlayController;\n bypassConfirmation?: boolean;\n}\n\nexport interface OnOverlayClosedOptions {\n dependencies?: DependencyList;\n}\n\nexport type CloseModalOptions = Omit<CloseOverlayOptions, \"overlay\">;\n\ntype CloseOptions = CloseOverlayOptions | CloseModalOptions;\n\nexport interface OverlayControllerOptions {\n isDefaultOpen?: boolean;\n onOpen?: OverlayOpenHandler;\n onClose?: OverlayCloseHandler;\n onOpenChange?: OverlayOpenStateHandler;\n /**\n * Whether closing the overlay must be confirmed. `undefined` means \"no\n * opinion\": the value is not contributed at all, so other sources (e.g. a\n * `Modal`'s `confirmOnClose` prop or a dirty `Form`) still decide.\n */\n confirmOnClose?: boolean;\n}\n\ntype ConstructorOptions = Pick<\n OverlayControllerOptions,\n \"isDefaultOpen\" | \"confirmOnClose\"\n>;\n\nexport class OverlayController {\n public isOpen = false;\n public isContentSuspended = false;\n private onOpenHandlers = new Set<OverlayOpenHandler>();\n private onCloseHandlers = new Set<OverlayCloseHandler>();\n private onOpenChangeHandlers = new Set<OverlayOpenStateHandler>();\n\n public showConfirmationModal = false;\n public closeIsConfirmed = false;\n private readonly confirmOnCloseFromOptions: boolean;\n /**\n * Every mounted component that has an opinion on close confirmation\n * contributes one entry here – e.g. a `Modal` with a `confirmOnClose` prop\n * and a `Form` tracking its dirty state. Combining them instead of assigning\n * a single flag keeps them from overwriting each other.\n */\n private confirmOnCloseSources = observable.map<object, boolean>();\n /**\n * Active grants that allow closing without a confirmation. Each entry is\n * scoped to an ongoing operation that legitimately closes the overlay – e.g.\n * a `Form` submit – and is dropped again when that operation has finished, so\n * an operation that does _not_ close the overlay leaves the confirmation\n * armed.\n */\n private closeWithoutConfirmationGrants = new Set<object>();\n /**\n * The open state a `setOpen` call is currently applying. Handlers run before\n * `isOpen` is assigned, so a handler that calls `setOpen` again would not be\n * caught by the equality check at the top and would recurse.\n */\n private openStateInFlight: boolean | undefined;\n\n public constructor(options: ConstructorOptions = {}) {\n makeObservable(this, {\n isOpen: observable,\n isContentSuspended: observable,\n showConfirmationModal: observable,\n confirmOnCloseEnabled: computed,\n open: action.bound,\n close: action.bound,\n toggle: action.bound,\n setOpen: action.bound,\n syncOpen: action.bound,\n setIsContentSuspended: action.bound,\n confirmClose: action.bound,\n cancelConfirmation: action.bound,\n });\n const { isDefaultOpen = false, confirmOnClose = false } = options;\n this.isOpen = isDefaultOpen;\n this.confirmOnCloseFromOptions = confirmOnClose;\n }\n\n /** Whether closing this overlay currently requires a confirmation. */\n public get confirmOnCloseEnabled(): boolean {\n if (this.confirmOnCloseSources.size === 0) {\n return this.confirmOnCloseFromOptions;\n }\n return Array.from(this.confirmOnCloseSources.values()).some(Boolean);\n }\n\n public useUpdateOptions(options: OverlayControllerOptions = {}): void {\n const { onOpen, onClose, onOpenChange, confirmOnClose } = options;\n\n this.useOnHandler(onOpen, (h) =>\n this.addOpenStateHandler(h, this.onOpenHandlers),\n );\n this.useOnHandler(onClose, (h) =>\n this.addOpenStateHandler(h, this.onCloseHandlers),\n );\n this.useOnHandler(onOpenChange, (h) =>\n this.addOpenStateHandler(h, this.onOpenChangeHandlers),\n );\n\n this.useConfirmOnCloseSource(confirmOnClose);\n }\n\n /**\n * Registers the calling component as a close confirmation source for as long\n * as it is mounted. `undefined` contributes nothing at all.\n */\n private useConfirmOnCloseSource(confirmOnClose: boolean | undefined): void {\n const source = useStatic((): object => ({}));\n\n useEffect(() => {\n if (confirmOnClose === undefined) {\n this.removeConfirmOnCloseSource(source);\n return;\n }\n this.setConfirmOnCloseSource(source, confirmOnClose);\n return () => this.removeConfirmOnCloseSource(source);\n }, [this, source, confirmOnClose]);\n }\n\n private setConfirmOnCloseSource(source: object, confirmOnClose: boolean) {\n runInAction(() => this.confirmOnCloseSources.set(source, confirmOnClose));\n }\n\n private removeConfirmOnCloseSource(source: object) {\n runInAction(() => this.confirmOnCloseSources.delete(source));\n }\n\n /**\n * Can be used to execute a callback when the Overlay has unmounted – means\n * after any closing animation.\n *\n * NOTICE: This hook only works inside the corresponding Overlay!\n */\n public useOnClosed(\n callback: () => unknown,\n options: OnOverlayClosedOptions = {},\n ) {\n const { dependencies = [] } = options;\n const isOpen = this.useIsOpen();\n const wasOpen = useRef(this.isOpen);\n\n this.useUpdateOptions({\n onOpen: () => {\n wasOpen.current = true;\n },\n });\n\n useEffect(() => {\n return () => {\n if (!isOpen && wasOpen.current) {\n wasOpen.current = false;\n callback();\n }\n };\n }, [isOpen, ...dependencies]);\n }\n\n public static useNew(\n options: OverlayControllerOptions = {},\n ): OverlayController {\n const controller = useStatic(() => new OverlayController(options));\n controller.useUpdateOptions(options);\n return controller;\n }\n\n private addOpenStateHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T,\n handlersSet: Set<T>,\n ): DisposerFn {\n handlersSet.add(handler);\n return () => {\n handlersSet.delete(handler);\n };\n }\n\n private useOnHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T | undefined,\n addHandlerFn: (handler: T) => DisposerFn,\n ) {\n useEffect(\n () => (handler ? addHandlerFn(handler) : undefined),\n [handler, this],\n );\n }\n\n private executeHandlers(\n isOpen: boolean,\n handlers: Set<\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler\n >,\n ): boolean {\n const handlerResult = Array.from(handlers).map((handler) =>\n handler(isOpen),\n );\n return handlerResult.some((result) => result === false);\n }\n\n private executeOnClose(): boolean {\n return this.executeHandlers(false, this.onCloseHandlers);\n }\n\n private executeOnOpen(): boolean {\n return this.executeHandlers(true, this.onOpenHandlers);\n }\n\n private executeOnOpenChange(isOpen: boolean): boolean {\n return this.executeHandlers(isOpen, this.onOpenChangeHandlers);\n }\n\n public addOnClose(handler: OverlayCloseHandler) {\n return this.addOpenStateHandler(handler, this.onCloseHandlers);\n }\n\n public addOnOpen(handler: OverlayOpenHandler) {\n return this.addOpenStateHandler(handler, this.onOpenHandlers);\n }\n\n public addOnOpenChange(handler: OverlayOpenStateHandler) {\n return this.addOpenStateHandler(handler, this.onOpenChangeHandlers);\n }\n\n public open(): void {\n this.setOpen(true);\n }\n\n public close(options?: CloseOptions): void {\n this.setOpen(false, options);\n }\n\n public toggle(): void {\n this.setOpen(!this.isOpen);\n }\n\n public setOpen(toOpen: boolean, options: CloseOptions = {}): void {\n if (this.isOpen === toOpen || this.openStateInFlight === toOpen) {\n return;\n }\n\n this.openStateInFlight = toOpen;\n try {\n this.applyOpenState(toOpen, options);\n } finally {\n this.openStateInFlight = undefined;\n }\n }\n\n /**\n * Sets the open state without running any handler. Use it to mirror a\n * controlled `isOpen` prop, whose change comes from the consumer – notifying\n * them of their own state would echo it back.\n */\n public syncOpen(toOpen: boolean): void {\n this.isOpen = toOpen;\n }\n\n private applyOpenState(toOpen: boolean, options: CloseOptions): void {\n const { bypassConfirmation = false } = options;\n\n if (toOpen === false) {\n // The confirmation is a one-shot permission for exactly this close\n // attempt – consume it here instead of only when a close succeeds, so it\n // cannot survive an aborted close and disarm later attempts.\n const closeIsConfirmed = this.closeIsConfirmed;\n this.closeIsConfirmed = false;\n\n if (\n this.confirmOnCloseEnabled &&\n !closeIsConfirmed &&\n this.closeWithoutConfirmationGrants.size === 0 &&\n !bypassConfirmation\n ) {\n this.showConfirmationModal = true;\n return;\n }\n }\n\n let aborted: boolean;\n if (toOpen) {\n aborted = this.executeOnOpen();\n } else {\n aborted = this.executeOnClose();\n }\n if (!aborted) {\n aborted = this.executeOnOpenChange(toOpen);\n }\n\n if (!aborted) {\n this.isOpen = toOpen;\n }\n }\n\n public setIsContentSuspended(to: boolean): void {\n this.isContentSuspended = to;\n }\n\n public useIsOpen() {\n return useSelector(() => this.isOpen);\n }\n\n public useIsContentSuspended() {\n return useSelector(() => this.isContentSuspended);\n }\n\n public useShowConfirmationModal() {\n return useSelector(() => this.showConfirmationModal);\n }\n\n public useConfirmOnCloseEnabled() {\n return useSelector(() => this.confirmOnCloseEnabled);\n }\n\n public useConfirmationController() {\n return useCloseOverlayConfirmationController(this);\n }\n\n /**\n * Allows closing this overlay without a confirmation until the returned\n * disposer is called. Use it around an operation that may legitimately close\n * the overlay – e.g. a `Form` submit, where a \"discard unsaved changes?\"\n * prompt would be nonsense – and dispose it as soon as that operation has\n * finished. An operation that ends without closing the overlay therefore\n * leaves the confirmation armed (#2775).\n */\n public grantCloseWithoutConfirmation(): DisposerFn {\n const grant = {};\n this.closeWithoutConfirmationGrants.add(grant);\n return () => {\n this.closeWithoutConfirmationGrants.delete(grant);\n };\n }\n\n public confirmClose(): void {\n this.closeIsConfirmed = true;\n this.showConfirmationModal = false;\n }\n\n public cancelConfirmation(): void {\n this.showConfirmationModal = false;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/OverlayController.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n runInAction,\n} from \"mobx\";\nimport useSelector from \"@/lib/mobx/useSelector\";\nimport { useStatic } from \"@/lib/hooks/useStatic\";\nimport { useEffect, useRef, type DependencyList } from \"react\";\nimport { useCloseOverlayConfirmationController } from \"@/lib/controller/overlay/useCloseOverlayConfirmationController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport type OverlayOpenHandler = () => unknown;\nexport type OverlayCloseHandler = () => unknown;\nexport type OverlayOpenStateHandler = (isOpen: boolean) => unknown;\ntype AnyOverlayOpenStateHandler =\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler;\n\ntype DisposerFn = () => void;\n\nexport interface CloseOverlayOptions {\n /**\n * The overlay to close. Omitted, the nearest enclosing overlay is closed –\n * the same thing `closeOverlay={true}` means.\n */\n overlay?: FlowComponentName | OverlayController;\n bypassConfirmation?: boolean;\n}\n\nexport interface OnOverlayClosedOptions {\n dependencies?: DependencyList;\n}\n\nexport type CloseModalOptions = Omit<CloseOverlayOptions, \"overlay\">;\n\n/**\n * Every way an action can point at an overlay: by the Flow component name it\n * registers under, by controller, by options, or with `true` – the nearest\n * enclosing overlay, whatever its name.\n */\nexport type OverlayReference =\n FlowComponentName | OverlayController | CloseOverlayOptions | true;\n\ntype CloseOptions = CloseOverlayOptions | CloseModalOptions;\n\nexport interface OverlayControllerOptions {\n isDefaultOpen?: boolean;\n onOpen?: OverlayOpenHandler;\n onClose?: OverlayCloseHandler;\n onOpenChange?: OverlayOpenStateHandler;\n /**\n * Whether closing the overlay must be confirmed. `undefined` means \"no\n * opinion\": the value is not contributed at all, so other sources (e.g. a\n * `Modal`'s `confirmOnClose` prop or a dirty `Form`) still decide.\n */\n confirmOnClose?: boolean;\n}\n\ntype ConstructorOptions = Pick<\n OverlayControllerOptions,\n \"isDefaultOpen\" | \"confirmOnClose\"\n>;\n\nexport class OverlayController {\n public isOpen = false;\n public isContentSuspended = false;\n private onOpenHandlers = new Set<OverlayOpenHandler>();\n private onCloseHandlers = new Set<OverlayCloseHandler>();\n private onOpenChangeHandlers = new Set<OverlayOpenStateHandler>();\n\n public showConfirmationModal = false;\n public closeIsConfirmed = false;\n private readonly confirmOnCloseFromOptions: boolean;\n /**\n * Every mounted component that has an opinion on close confirmation\n * contributes one entry here – e.g. a `Modal` with a `confirmOnClose` prop\n * and a `Form` tracking its dirty state. Combining them instead of assigning\n * a single flag keeps them from overwriting each other.\n */\n private confirmOnCloseSources = observable.map<object, boolean>();\n /**\n * Active grants that allow closing without a confirmation. Each entry is\n * scoped to an ongoing operation that legitimately closes the overlay – e.g.\n * a `Form` submit – and is dropped again when that operation has finished, so\n * an operation that does _not_ close the overlay leaves the confirmation\n * armed.\n */\n private closeWithoutConfirmationGrants = new Set<object>();\n /**\n * The open state a `setOpen` call is currently applying. Handlers run before\n * `isOpen` is assigned, so a handler that calls `setOpen` again would not be\n * caught by the equality check at the top and would recurse.\n */\n private openStateInFlight: boolean | undefined;\n\n public constructor(options: ConstructorOptions = {}) {\n makeObservable(this, {\n isOpen: observable,\n isContentSuspended: observable,\n showConfirmationModal: observable,\n confirmOnCloseEnabled: computed,\n open: action.bound,\n close: action.bound,\n toggle: action.bound,\n setOpen: action.bound,\n syncOpen: action.bound,\n setIsContentSuspended: action.bound,\n confirmClose: action.bound,\n cancelConfirmation: action.bound,\n });\n const { isDefaultOpen = false, confirmOnClose = false } = options;\n this.isOpen = isDefaultOpen;\n this.confirmOnCloseFromOptions = confirmOnClose;\n }\n\n /** Whether closing this overlay currently requires a confirmation. */\n public get confirmOnCloseEnabled(): boolean {\n if (this.confirmOnCloseSources.size === 0) {\n return this.confirmOnCloseFromOptions;\n }\n return Array.from(this.confirmOnCloseSources.values()).some(Boolean);\n }\n\n public useUpdateOptions(options: OverlayControllerOptions = {}): void {\n const { onOpen, onClose, onOpenChange, confirmOnClose } = options;\n\n this.useOnHandler(onOpen, (h) =>\n this.addOpenStateHandler(h, this.onOpenHandlers),\n );\n this.useOnHandler(onClose, (h) =>\n this.addOpenStateHandler(h, this.onCloseHandlers),\n );\n this.useOnHandler(onOpenChange, (h) =>\n this.addOpenStateHandler(h, this.onOpenChangeHandlers),\n );\n\n this.useConfirmOnCloseSource(confirmOnClose);\n }\n\n /**\n * Registers the calling component as a close confirmation source for as long\n * as it is mounted. `undefined` contributes nothing at all.\n */\n private useConfirmOnCloseSource(confirmOnClose: boolean | undefined): void {\n const source = useStatic((): object => ({}));\n\n useEffect(() => {\n if (confirmOnClose === undefined) {\n this.removeConfirmOnCloseSource(source);\n return;\n }\n this.setConfirmOnCloseSource(source, confirmOnClose);\n return () => this.removeConfirmOnCloseSource(source);\n }, [this, source, confirmOnClose]);\n }\n\n private setConfirmOnCloseSource(source: object, confirmOnClose: boolean) {\n runInAction(() => this.confirmOnCloseSources.set(source, confirmOnClose));\n }\n\n private removeConfirmOnCloseSource(source: object) {\n runInAction(() => this.confirmOnCloseSources.delete(source));\n }\n\n /**\n * Can be used to execute a callback when the Overlay has unmounted – means\n * after any closing animation.\n *\n * NOTICE: This hook only works inside the corresponding Overlay!\n */\n public useOnClosed(\n callback: () => unknown,\n options: OnOverlayClosedOptions = {},\n ) {\n const { dependencies = [] } = options;\n const isOpen = this.useIsOpen();\n const wasOpen = useRef(this.isOpen);\n\n this.useUpdateOptions({\n onOpen: () => {\n wasOpen.current = true;\n },\n });\n\n useEffect(() => {\n return () => {\n if (!isOpen && wasOpen.current) {\n wasOpen.current = false;\n callback();\n }\n };\n }, [isOpen, ...dependencies]);\n }\n\n public static useNew(\n options: OverlayControllerOptions = {},\n ): OverlayController {\n const controller = useStatic(() => new OverlayController(options));\n controller.useUpdateOptions(options);\n return controller;\n }\n\n private addOpenStateHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T,\n handlersSet: Set<T>,\n ): DisposerFn {\n handlersSet.add(handler);\n return () => {\n handlersSet.delete(handler);\n };\n }\n\n private useOnHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T | undefined,\n addHandlerFn: (handler: T) => DisposerFn,\n ) {\n useEffect(\n () => (handler ? addHandlerFn(handler) : undefined),\n [handler, this],\n );\n }\n\n private executeHandlers(\n isOpen: boolean,\n handlers: Set<\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler\n >,\n ): boolean {\n const handlerResult = Array.from(handlers).map((handler) =>\n handler(isOpen),\n );\n return handlerResult.some((result) => result === false);\n }\n\n private executeOnClose(): boolean {\n return this.executeHandlers(false, this.onCloseHandlers);\n }\n\n private executeOnOpen(): boolean {\n return this.executeHandlers(true, this.onOpenHandlers);\n }\n\n private executeOnOpenChange(isOpen: boolean): boolean {\n return this.executeHandlers(isOpen, this.onOpenChangeHandlers);\n }\n\n public addOnClose(handler: OverlayCloseHandler) {\n return this.addOpenStateHandler(handler, this.onCloseHandlers);\n }\n\n public addOnOpen(handler: OverlayOpenHandler) {\n return this.addOpenStateHandler(handler, this.onOpenHandlers);\n }\n\n public addOnOpenChange(handler: OverlayOpenStateHandler) {\n return this.addOpenStateHandler(handler, this.onOpenChangeHandlers);\n }\n\n public open(): void {\n this.setOpen(true);\n }\n\n public close(options?: CloseOptions): void {\n this.setOpen(false, options);\n }\n\n public toggle(): void {\n this.setOpen(!this.isOpen);\n }\n\n public setOpen(toOpen: boolean, options: CloseOptions = {}): void {\n if (this.isOpen === toOpen || this.openStateInFlight === toOpen) {\n return;\n }\n\n this.openStateInFlight = toOpen;\n try {\n this.applyOpenState(toOpen, options);\n } finally {\n this.openStateInFlight = undefined;\n }\n }\n\n /**\n * Sets the open state without running any handler. Use it to mirror a\n * controlled `isOpen` prop, whose change comes from the consumer – notifying\n * them of their own state would echo it back.\n */\n public syncOpen(toOpen: boolean): void {\n this.isOpen = toOpen;\n }\n\n private applyOpenState(toOpen: boolean, options: CloseOptions): void {\n const { bypassConfirmation = false } = options;\n\n if (toOpen === false) {\n // The confirmation is a one-shot permission for exactly this close\n // attempt – consume it here instead of only when a close succeeds, so it\n // cannot survive an aborted close and disarm later attempts.\n const closeIsConfirmed = this.closeIsConfirmed;\n this.closeIsConfirmed = false;\n\n if (\n this.confirmOnCloseEnabled &&\n !closeIsConfirmed &&\n this.closeWithoutConfirmationGrants.size === 0 &&\n !bypassConfirmation\n ) {\n this.showConfirmationModal = true;\n return;\n }\n }\n\n let aborted: boolean;\n if (toOpen) {\n aborted = this.executeOnOpen();\n } else {\n aborted = this.executeOnClose();\n }\n if (!aborted) {\n aborted = this.executeOnOpenChange(toOpen);\n }\n\n if (!aborted) {\n this.isOpen = toOpen;\n }\n }\n\n public setIsContentSuspended(to: boolean): void {\n this.isContentSuspended = to;\n }\n\n public useIsOpen() {\n return useSelector(() => this.isOpen);\n }\n\n public useIsContentSuspended() {\n return useSelector(() => this.isContentSuspended);\n }\n\n public useShowConfirmationModal() {\n return useSelector(() => this.showConfirmationModal);\n }\n\n public useConfirmOnCloseEnabled() {\n return useSelector(() => this.confirmOnCloseEnabled);\n }\n\n public useConfirmationController() {\n return useCloseOverlayConfirmationController(this);\n }\n\n /**\n * Allows closing this overlay without a confirmation until the returned\n * disposer is called. Use it around an operation that may legitimately close\n * the overlay – e.g. a `Form` submit, where a \"discard unsaved changes?\"\n * prompt would be nonsense – and dispose it as soon as that operation has\n * finished. An operation that ends without closing the overlay therefore\n * leaves the confirmation armed (#2775).\n */\n public grantCloseWithoutConfirmation(): DisposerFn {\n const grant = {};\n this.closeWithoutConfirmationGrants.add(grant);\n return () => {\n this.closeWithoutConfirmationGrants.delete(grant);\n };\n }\n\n public confirmClose(): void {\n this.closeIsConfirmed = true;\n this.showConfirmationModal = false;\n }\n\n public cancelConfirmation(): void {\n this.showConfirmationModal = false;\n }\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  /* */
3
3
  import { createContext, useContext } from "react";
4
4
  //#region src/lib/controller/overlay/context.ts
5
- var overlayContext = createContext({});
5
+ var overlayContext = createContext({ byType: {} });
6
6
  var useOverlayContext = () => useContext(overlayContext);
7
7
  //#endregion
8
8
  export { overlayContext, useOverlayContext };
@@ -1 +1 @@
1
- {"version":3,"file":"context.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/context.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport type OverlayContext = Partial<\n Record<FlowComponentName, OverlayController | undefined>\n>;\n\nexport const overlayContext = createContext<OverlayContext>({});\n\nexport const useOverlayContext = (): OverlayContext =>\n useContext(overlayContext);\n"],"mappings":";;;;AAQA,IAAa,iBAAiB,cAA8B,CAAC,CAAC;AAE9D,IAAa,0BACX,WAAW,cAAc"}
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/context.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport interface OverlayContext {\n /**\n * The enclosing overlays' controllers, keyed by the Flow component name the\n * providing overlay registers itself under. Innermost wins per name – a\n * `Modal` inside a `Modal` overwrites the `Modal` entry – but the map does\n * not record which of two differently named overlays is the inner one.\n */\n byType: Partial<Record<FlowComponentName, OverlayController | undefined>>;\n /**\n * The controller of the innermost overlay this subtree is the _content_ of,\n * whatever its component name. `undefined` outside any overlay content.\n *\n * Only providers that wrap overlay content set it. `OverlayTrigger` wraps the\n * trigger as well, so it contributes to `byType` only – an `Action` in the\n * trigger button is not inside the overlay it opens.\n */\n nearest?: OverlayController;\n}\n\nexport const overlayContext = createContext<OverlayContext>({ byType: {} });\n\nexport const useOverlayContext = (): OverlayContext =>\n useContext(overlayContext);\n"],"mappings":";;;;AAuBA,IAAa,iBAAiB,cAA8B,EAAE,QAAQ,CAAC,EAAE,CAAC;AAE1E,IAAa,0BACX,WAAW,cAAc"}
@@ -6,7 +6,7 @@ import { useOverlayContext } from "./context.mjs";
6
6
  var useOverlayController = (overlayType, options = {}) => {
7
7
  const { reuseControllerFromContext = true, ...restControllerOptions } = options;
8
8
  const newController = OverlayController.useNew(restControllerOptions);
9
- const controllerFromContext = useOverlayContext()[overlayType];
9
+ const controllerFromContext = useOverlayContext().byType[overlayType];
10
10
  const controller = reuseControllerFromContext && controllerFromContext ? controllerFromContext : newController;
11
11
  if (controller === controllerFromContext) controller.useUpdateOptions(restControllerOptions);
12
12
  return controller;
@@ -1 +1 @@
1
- {"version":3,"file":"useOverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/useOverlayController.ts"],"sourcesContent":["import { useOverlayContext } from \"@/lib/controller/overlay/context\";\nimport type { OverlayControllerOptions } from \"@/lib/controller/overlay/OverlayController\";\nimport { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport interface UseOverlayControllerOptions extends OverlayControllerOptions {\n reuseControllerFromContext?: boolean;\n}\n\nexport const useOverlayController = (\n overlayType: FlowComponentName,\n options: UseOverlayControllerOptions = {},\n): OverlayController => {\n const { reuseControllerFromContext = true, ...restControllerOptions } =\n options;\n\n const newController = OverlayController.useNew(restControllerOptions);\n const controllerFromContext = useOverlayContext()[overlayType];\n\n const controller =\n reuseControllerFromContext && controllerFromContext\n ? controllerFromContext\n : newController;\n\n if (controller === controllerFromContext) {\n controller.useUpdateOptions(restControllerOptions);\n }\n\n return controller;\n};\n"],"mappings":";;;;;AASA,IAAa,wBACX,aACA,UAAuC,CAAC,MAClB;CACtB,MAAM,EAAE,6BAA6B,MAAM,GAAG,0BAC5C;CAEF,MAAM,gBAAgB,kBAAkB,OAAO,qBAAqB;CACpE,MAAM,wBAAwB,kBAAkB,CAAC,CAAC;CAElD,MAAM,aACJ,8BAA8B,wBAC1B,wBACA;CAEN,IAAI,eAAe,uBACjB,WAAW,iBAAiB,qBAAqB;CAGnD,OAAO;AACT"}
1
+ {"version":3,"file":"useOverlayController.mjs","names":[],"sources":["../../../../../../../../src/lib/controller/overlay/useOverlayController.ts"],"sourcesContent":["import { useOverlayContext } from \"@/lib/controller/overlay/context\";\nimport type { OverlayControllerOptions } from \"@/lib/controller/overlay/OverlayController\";\nimport { OverlayController } from \"@/lib/controller/overlay/OverlayController\";\nimport type { FlowComponentName } from \"@/components/propTypes\";\n\nexport interface UseOverlayControllerOptions extends OverlayControllerOptions {\n reuseControllerFromContext?: boolean;\n}\n\nexport const useOverlayController = (\n overlayType: FlowComponentName,\n options: UseOverlayControllerOptions = {},\n): OverlayController => {\n const { reuseControllerFromContext = true, ...restControllerOptions } =\n options;\n\n const newController = OverlayController.useNew(restControllerOptions);\n const controllerFromContext = useOverlayContext().byType[overlayType];\n\n const controller =\n reuseControllerFromContext && controllerFromContext\n ? controllerFromContext\n : newController;\n\n if (controller === controllerFromContext) {\n controller.useUpdateOptions(restControllerOptions);\n }\n\n return controller;\n};\n"],"mappings":";;;;;AASA,IAAa,wBACX,aACA,UAAuC,CAAC,MAClB;CACtB,MAAM,EAAE,6BAA6B,MAAM,GAAG,0BAC5C;CAEF,MAAM,gBAAgB,kBAAkB,OAAO,qBAAqB;CACpE,MAAM,wBAAwB,kBAAkB,CAAC,CAAC,OAAO;CAEzD,MAAM,aACJ,8BAA8B,wBAC1B,wBACA;CAEN,IAAI,eAAe,uBACjB,WAAW,iBAAiB,qBAAqB;CAGnD,OAAO;AACT"}
@@ -1099,7 +1099,7 @@ var image = {
1099
1099
  "path": ["image", "border-style"]
1100
1100
  },
1101
1101
  "border-color": {
1102
- "value": "#DCE9F7",
1102
+ "value": "#8FA1B4",
1103
1103
  "path": ["image", "border-color"]
1104
1104
  }
1105
1105
  };