@mittwald/flow-react-components 1.6.0-next.37 → 1.6.0-next.39

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 (28) hide show
  1. package/dist/assets/component-index.json +1 -1
  2. package/dist/assets/doc-properties.json +1 -1
  3. package/dist/js/packages/components/src/components/Action/models/ActionState.mjs +2 -2
  4. package/dist/js/packages/components/src/components/Calendar/components/RangeCalendar/helpers/useCalendarDateRangePresets.mjs +1 -1
  5. package/dist/js/packages/components/src/components/Link/Link.mjs.map +1 -1
  6. package/dist/js/packages/components/src/components/List/model/ListViewMode.mjs +2 -2
  7. package/dist/js/packages/components/src/components/List/model/ReactTable.mjs +2 -2
  8. package/dist/js/packages/components/src/components/List/model/loading/IncrementalLoaderState.mjs +2 -2
  9. package/dist/js/packages/components/src/components/Table/components/TableCell/TableCell.mjs +5 -12
  10. package/dist/js/packages/components/src/components/Table/components/TableCell/TableCell.mjs.map +1 -1
  11. package/dist/js/packages/components/src/components/Table/components/TableColumn/TableColumn.mjs +4 -2
  12. package/dist/js/packages/components/src/components/Table/components/TableColumn/TableColumn.mjs.map +1 -1
  13. package/dist/js/packages/components/src/components/Table/components/TableHeader/TableHeader.mjs +7 -1
  14. package/dist/js/packages/components/src/components/Table/components/TableHeader/TableHeader.mjs.map +1 -1
  15. package/dist/js/packages/components/src/components/Table/components/TableHeader/context.mjs +14 -0
  16. package/dist/js/packages/components/src/components/Table/components/TableHeader/context.mjs.map +1 -0
  17. package/dist/js/packages/components/src/lib/controller/overlay/OverlayController.mjs +10 -158
  18. package/dist/js/packages/components/src/lib/controller/overlay/OverlayController.mjs.map +1 -1
  19. package/dist/js/packages/components-base/src/index.mjs +2 -1
  20. package/dist/js/packages/components-base/src/overlay/OverlayState.mjs +178 -0
  21. package/dist/js/packages/components-base/src/overlay/OverlayState.mjs.map +1 -0
  22. package/dist/types/_bundled/flow-components-base/index.d.ts +1 -0
  23. package/dist/types/_bundled/flow-components-base/overlay/OverlayState.d.ts +90 -0
  24. package/dist/types/components/Link/Link.d.ts +1 -1
  25. package/dist/types/components/Table/components/TableCell/TableCell.d.ts +4 -1
  26. package/dist/types/components/Table/components/TableHeader/context.d.ts +6 -0
  27. package/dist/types/lib/controller/overlay/OverlayController.d.ts +8 -74
  28. package/package.json +10 -10
@@ -1,9 +1,9 @@
1
1
  "use client"
2
2
  /* */
3
- import useSelector from "../../../lib/mobx/useSelector.mjs";
4
- import { useStatic } from "../../../lib/hooks/useStatic.mjs";
5
3
  import { ActionState as ActionState$1, actionStateDurations } from "../../../../../components-base/src/action/ActionState.mjs";
6
4
  import "../../../../../components-base/src/index.mjs";
5
+ import useSelector from "../../../lib/mobx/useSelector.mjs";
6
+ import { useStatic } from "../../../lib/hooks/useStatic.mjs";
7
7
  //#region src/components/Action/models/ActionState.ts
8
8
  var duration = actionStateDurations;
9
9
  /**
@@ -4,9 +4,9 @@ import { useLocalizedStringFormatter } from "../../../../TranslationProvider/use
4
4
  import __locale_default from "../../../../../../../../_virtual/_7.locale.mjs";
5
5
  import { useContext, useMemo } from "react";
6
6
  import { RangeCalendarStateContext } from "react-aria-components";
7
- import invariant from "invariant";
8
7
  import { CalendarDate, toCalendarDate } from "@internationalized/date";
9
8
  import { DateTime } from "luxon";
9
+ import invariant from "invariant";
10
10
  //#region src/components/Calendar/components/RangeCalendar/helpers/useCalendarDateRangePresets.ts
11
11
  var clampCalendarDate = (date, minDate, maxDate) => {
12
12
  if (minDate && date.compare(minDate) < 0) return minDate;
@@ -1 +1 @@
1
- {"version":3,"file":"Link.mjs","names":["styles","_Fragment","_jsx"],"sources":["../../../../../../../src/components/Link/Link.tsx"],"sourcesContent":["import type {\n ComponentProps,\n ComponentType,\n CSSProperties,\n MouseEvent,\n PropsWithChildren,\n} from \"react\";\nimport { useContext } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport { dynamic, type PropsContext } from \"@/lib/propsContext\";\nimport { PropsContextProvider } from \"@/lib/propsContext\";\nimport styles from \"./Link.module.scss\";\nimport clsx from \"clsx\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport {\n type AlphaColor,\n isAlphaColor,\n type PropsWithClassName,\n} from \"@/lib/types/props\";\nimport { linkContext } from \"@/components/Link/context\";\nimport { LinkIcon } from \"@/components/Link/components/LinkIcon\";\nimport { handleLinkClick, useRouter } from \"@react-aria/utils\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\nimport { SkeletonTextContent } from \"@/components/SkeletonMode/components/SkeletonTextContent\";\nimport { useSkeletonMode } from \"@/components/SkeletonMode/skeletonModeContext\";\nimport { hasContent } from \"@/components/SkeletonMode/lib/hasContent\";\nimport { containsTextChild } from \"@/lib/react/remote\";\n\nexport interface LinkProps\n extends\n PropsWithChildren<Omit<Aria.LinkProps, \"children\" | \"slot\" | \"className\">>,\n FlowComponentProps<HTMLAnchorElement>,\n PropsWithClassName {\n /** Whether the link should be styled for being displayed inside a text. */\n inline?: boolean;\n /** An alternative link component. */\n linkComponent?: ComponentType<Omit<ComponentProps<\"a\">, \"ref\">>;\n /** The color of the link. @default \"default\" */\n color?: \"default\" | AlphaColor;\n /** Marks the link as the currently active one, e.g. in a navigation. */\n \"aria-current\"?: string;\n /**\n * The name of the slot the link is placed in. In action groups: `primary` (at\n * the end), `secondary` (before the primary action) or `abort` (at the\n * start).\n */\n slot?: string;\n /** The whiteSpace css value of the element. */\n whiteSpace?: CSSProperties[\"whiteSpace\"];\n /** The size of the element. @default \"m\" */\n size?: \"s\" | \"m\";\n /** @internal */\n unstyled?: boolean;\n}\n\n/** @flr-generate all */\nexport const Link = flowComponent(\"Link\", (props) => {\n const {\n children,\n className,\n inline,\n linkComponent: linkComponentFromProps,\n color = \"default\",\n unstyled = false,\n \"aria-current\": ariaCurrent,\n ref,\n slot: ignoredSlotProp,\n style,\n whiteSpace,\n size = \"m\",\n onClickCapture: onClickCaptureFromProps,\n target,\n download,\n ...rest\n } = props;\n\n const { linkComponent: linkComponentFromContext } = useContext(linkContext);\n const isSkeleton = useSkeletonMode();\n const Link = linkComponentFromProps\n ? (linkComponentFromProps as typeof Aria.Link)\n : props.href && linkComponentFromContext\n ? (linkComponentFromContext as typeof Aria.Link)\n : Aria.Link;\n\n const router = useRouter();\n\n /**\n * An interactive child (e.g. a Button) stops click propagation via React\n * Aria's `usePress`, so the anchor's own `onClick` never runs and navigation\n * falls back to a full page load. Handling it in the capture phase (top-down,\n * before the child) keeps navigation client-side. Only needed for React\n * Aria's `<a>`; custom link components handle navigation themselves.\n */\n const handleClickCapture =\n Link === Aria.Link && props.href\n ? (event: MouseEvent<HTMLAnchorElement>) => {\n onClickCaptureFromProps?.(event);\n if (event.target !== event.currentTarget) {\n handleLinkClick(event, router, props.href, props.routerOptions);\n }\n }\n : onClickCaptureFromProps;\n\n const rootClassName = unstyled\n ? className\n : clsx(\n styles.link,\n inline && styles.inline,\n isAlphaColor(color) && styles[color],\n size === \"s\" && styles[\"size-s\"],\n className,\n );\n\n const propsContext: PropsContext = {\n Icon: {\n tunnel: {\n component: \"Link\",\n id: \"icon\",\n },\n className: styles.icon,\n size: \"s\",\n },\n AlertText: {\n className: styles.alertText,\n },\n AccentBox: { className: styles.accentBox },\n LayoutCard: { className: styles.layoutCard },\n Button: {\n elementType: \"span\",\n className: styles.button,\n size: props.size,\n color: props.color === \"default\" ? undefined : props.color,\n isDisabled: props.isDisabled,\n children: dynamic((buttonProps) => (\n <>\n {buttonProps.children}\n <LinkIcon download={download} target={target} unstyled={unstyled} />\n </>\n )),\n },\n };\n\n const unsupportedTypingsLinkProps = ariaCurrent\n ? ({\n \"aria-current\": true,\n } as Record<string, unknown>)\n : {};\n\n /* Without text of its own — a Link styled as a Button, a Link around a\n LayoutCard — the content follows its own skeleton rules instead of\n becoming a text bar. */\n const hasOnlyElements = hasContent(children) && !containsTextChild(children);\n\n const textBars = (\n <SkeletonTextContent defaultWidth=\"6em\">{children}</SkeletonTextContent>\n );\n\n const content = (\n <PropsContextProvider props={propsContext}>\n {hasOnlyElements ? children : textBars}\n <LinkIcon\n withZeroWidthJoiner\n unstyled={unstyled}\n target={target}\n download={download}\n >\n <UiComponentTunnelExit id={\"icon\"} component={\"Link\"} />\n </LinkIcon>\n </PropsContextProvider>\n );\n\n /* react-aria's Link drops `inert`, and a skeleton needs no anchor. */\n if (isSkeleton) {\n return (\n <span className={rootClassName} style={{ ...style, whiteSpace }} inert>\n {content}\n </span>\n );\n }\n\n return (\n <Link\n {...unsupportedTypingsLinkProps}\n {...rest}\n target={target}\n download={download}\n onClickCapture={handleClickCapture}\n className={rootClassName}\n ref={ref}\n style={{ ...style, whiteSpace }}\n >\n {content}\n </Link>\n );\n});\n\nexport default Link;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAyDA,IAAa,OAAO,cAAc,SAAS,UAAU;CACnD,MAAM,EACJ,UACA,WACA,QACA,eAAe,wBACf,QAAQ,WACR,WAAW,OACX,gBAAgB,aAChB,KACA,MAAM,iBACN,OACA,YACA,OAAO,KACP,gBAAgB,yBAChB,QACA,UACA,GAAG,SACD;CAEJ,MAAM,EAAE,eAAe,6BAA6B,WAAW,WAAW;CAC1E,MAAM,aAAa,gBAAgB;CACnC,MAAM,OAAO,yBACR,yBACD,MAAM,QAAQ,2BACX,2BACD,KAAK;CAEX,MAAM,SAAS,UAAU;;;;;;;;CASzB,MAAM,qBACJ,SAAS,KAAK,QAAQ,MAAM,QACvB,UAAyC;EACxC,0BAA0B,KAAK;EAC/B,IAAI,MAAM,WAAW,MAAM,eACzB,gBAAgB,OAAO,QAAQ,MAAM,MAAM,MAAM,aAAa;CAElE,IACA;CAEN,MAAM,gBAAgB,WAClB,YACA,KACEA,oBAAO,MACP,UAAUA,oBAAO,QACjB,aAAa,KAAK,KAAKA,oBAAO,QAC9B,SAAS,OAAOA,oBAAO,WACvB,SACF;CAEJ,MAAM,eAA6B;EACjC,MAAM;GACJ,QAAQ;IACN,WAAW;IACX,IAAI;GACN;GACA,WAAWA,oBAAO;GAClB,MAAM;EACR;EACA,WAAW,EACT,WAAWA,oBAAO,UACpB;EACA,WAAW,EAAE,WAAWA,oBAAO,UAAU;EACzC,YAAY,EAAE,WAAWA,oBAAO,WAAW;EAC3C,QAAQ;GACN,aAAa;GACb,WAAWA,oBAAO;GAClB,MAAM,MAAM;GACZ,OAAO,MAAM,UAAU,YAAY,KAAA,IAAY,MAAM;GACrD,YAAY,MAAM;GAClB,UAAU,SAAS,gBACjB,qBAAAC,YAAA,EAAA,UAAA,CACG,YAAY,UACb,oBAAC,UAAD;IAAoB;IAAkB;IAAkB;GAAW,CAAA,CACnE,EAAA,CAAA,CACH;EACH;CACF;CAEA,MAAM,8BAA8B,cAC/B,EACC,gBAAgB,KAClB,IACA,CAAC;CAKL,MAAM,kBAAkB,WAAW,QAAQ,KAAK,CAAC,kBAAkB,QAAQ;CAM3E,MAAM,UACJ,qBAAC,sBAAD;EAAsB,OAAO;EAA7B,UAAA,CACG,kBAAkB,WALrBC,oBAAC,qBAAD;GAAqB,cAAa;GAAO;EAA8B,CAKvC,GAC9B,oBAAC,UAAD;GACE,qBAAA;GACU;GACF;GACE;GAEV,UAAA,oBAAC,uBAAD;IAAuB,IAAI;IAAQ,WAAW;GAAS,CAAA;EAC/C,CAAA,CACU;;CAIxB,IAAI,YACF,OACE,oBAAC,QAAD;EAAM,WAAW;EAAe,OAAO;GAAE,GAAG;GAAO;EAAW;EAAG,OAAA;EAC9D,UAAA;CACG,CAAA;CAIV,OACE,oBAAC,MAAD;EACE,GAAI;EACJ,GAAI;EACI;EACE;EACV,gBAAgB;EAChB,WAAW;EACN;EACL,OAAO;GAAE,GAAG;GAAO;EAAW;EAE7B,UAAA;CACG,CAAA;AAEV,CAAC"}
1
+ {"version":3,"file":"Link.mjs","names":["styles","_Fragment","_jsx"],"sources":["../../../../../../../src/components/Link/Link.tsx"],"sourcesContent":["import type {\n ComponentProps,\n ComponentType,\n CSSProperties,\n MouseEvent,\n PropsWithChildren,\n} from \"react\";\nimport { useContext } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport { dynamic, type PropsContext } from \"@/lib/propsContext\";\nimport { PropsContextProvider } from \"@/lib/propsContext\";\nimport styles from \"./Link.module.scss\";\nimport clsx from \"clsx\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport {\n type AlphaColor,\n isAlphaColor,\n type PropsWithClassName,\n} from \"@/lib/types/props\";\nimport { linkContext } from \"@/components/Link/context\";\nimport { LinkIcon } from \"@/components/Link/components/LinkIcon\";\nimport { handleLinkClick, useRouter } from \"@react-aria/utils\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\nimport { SkeletonTextContent } from \"@/components/SkeletonMode/components/SkeletonTextContent\";\nimport { useSkeletonMode } from \"@/components/SkeletonMode/skeletonModeContext\";\nimport { hasContent } from \"@/components/SkeletonMode/lib/hasContent\";\nimport { containsTextChild } from \"@/lib/react/remote\";\n\nexport interface LinkProps\n extends\n PropsWithChildren<\n Omit<Aria.LinkProps, \"children\" | \"slot\" | \"className\" | \"aria-current\">\n >,\n FlowComponentProps<HTMLAnchorElement>,\n PropsWithClassName {\n /** Whether the link should be styled for being displayed inside a text. */\n inline?: boolean;\n /** An alternative link component. */\n linkComponent?: ComponentType<Omit<ComponentProps<\"a\">, \"ref\">>;\n /** The color of the link. @default \"default\" */\n color?: \"default\" | AlphaColor;\n /** Marks the link as the currently active one, e.g. in a navigation. */\n \"aria-current\"?: string;\n /**\n * The name of the slot the link is placed in. In action groups: `primary` (at\n * the end), `secondary` (before the primary action) or `abort` (at the\n * start).\n */\n slot?: string;\n /** The whiteSpace css value of the element. */\n whiteSpace?: CSSProperties[\"whiteSpace\"];\n /** The size of the element. @default \"m\" */\n size?: \"s\" | \"m\";\n /** @internal */\n unstyled?: boolean;\n}\n\n/** @flr-generate all */\nexport const Link = flowComponent(\"Link\", (props) => {\n const {\n children,\n className,\n inline,\n linkComponent: linkComponentFromProps,\n color = \"default\",\n unstyled = false,\n \"aria-current\": ariaCurrent,\n ref,\n slot: ignoredSlotProp,\n style,\n whiteSpace,\n size = \"m\",\n onClickCapture: onClickCaptureFromProps,\n target,\n download,\n ...rest\n } = props;\n\n const { linkComponent: linkComponentFromContext } = useContext(linkContext);\n const isSkeleton = useSkeletonMode();\n const Link = linkComponentFromProps\n ? (linkComponentFromProps as typeof Aria.Link)\n : props.href && linkComponentFromContext\n ? (linkComponentFromContext as typeof Aria.Link)\n : Aria.Link;\n\n const router = useRouter();\n\n /**\n * An interactive child (e.g. a Button) stops click propagation via React\n * Aria's `usePress`, so the anchor's own `onClick` never runs and navigation\n * falls back to a full page load. Handling it in the capture phase (top-down,\n * before the child) keeps navigation client-side. Only needed for React\n * Aria's `<a>`; custom link components handle navigation themselves.\n */\n const handleClickCapture =\n Link === Aria.Link && props.href\n ? (event: MouseEvent<HTMLAnchorElement>) => {\n onClickCaptureFromProps?.(event);\n if (event.target !== event.currentTarget) {\n handleLinkClick(event, router, props.href, props.routerOptions);\n }\n }\n : onClickCaptureFromProps;\n\n const rootClassName = unstyled\n ? className\n : clsx(\n styles.link,\n inline && styles.inline,\n isAlphaColor(color) && styles[color],\n size === \"s\" && styles[\"size-s\"],\n className,\n );\n\n const propsContext: PropsContext = {\n Icon: {\n tunnel: {\n component: \"Link\",\n id: \"icon\",\n },\n className: styles.icon,\n size: \"s\",\n },\n AlertText: {\n className: styles.alertText,\n },\n AccentBox: { className: styles.accentBox },\n LayoutCard: { className: styles.layoutCard },\n Button: {\n elementType: \"span\",\n className: styles.button,\n size: props.size,\n color: props.color === \"default\" ? undefined : props.color,\n isDisabled: props.isDisabled,\n children: dynamic((buttonProps) => (\n <>\n {buttonProps.children}\n <LinkIcon download={download} target={target} unstyled={unstyled} />\n </>\n )),\n },\n };\n\n const unsupportedTypingsLinkProps = ariaCurrent\n ? ({\n \"aria-current\": true,\n } as Record<string, unknown>)\n : {};\n\n /* Without text of its own — a Link styled as a Button, a Link around a\n LayoutCard — the content follows its own skeleton rules instead of\n becoming a text bar. */\n const hasOnlyElements = hasContent(children) && !containsTextChild(children);\n\n const textBars = (\n <SkeletonTextContent defaultWidth=\"6em\">{children}</SkeletonTextContent>\n );\n\n const content = (\n <PropsContextProvider props={propsContext}>\n {hasOnlyElements ? children : textBars}\n <LinkIcon\n withZeroWidthJoiner\n unstyled={unstyled}\n target={target}\n download={download}\n >\n <UiComponentTunnelExit id={\"icon\"} component={\"Link\"} />\n </LinkIcon>\n </PropsContextProvider>\n );\n\n /* react-aria's Link drops `inert`, and a skeleton needs no anchor. */\n if (isSkeleton) {\n return (\n <span className={rootClassName} style={{ ...style, whiteSpace }} inert>\n {content}\n </span>\n );\n }\n\n return (\n <Link\n {...unsupportedTypingsLinkProps}\n {...rest}\n target={target}\n download={download}\n onClickCapture={handleClickCapture}\n className={rootClassName}\n ref={ref}\n style={{ ...style, whiteSpace }}\n >\n {content}\n </Link>\n );\n});\n\nexport default Link;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2DA,IAAa,OAAO,cAAc,SAAS,UAAU;CACnD,MAAM,EACJ,UACA,WACA,QACA,eAAe,wBACf,QAAQ,WACR,WAAW,OACX,gBAAgB,aAChB,KACA,MAAM,iBACN,OACA,YACA,OAAO,KACP,gBAAgB,yBAChB,QACA,UACA,GAAG,SACD;CAEJ,MAAM,EAAE,eAAe,6BAA6B,WAAW,WAAW;CAC1E,MAAM,aAAa,gBAAgB;CACnC,MAAM,OAAO,yBACR,yBACD,MAAM,QAAQ,2BACX,2BACD,KAAK;CAEX,MAAM,SAAS,UAAU;;;;;;;;CASzB,MAAM,qBACJ,SAAS,KAAK,QAAQ,MAAM,QACvB,UAAyC;EACxC,0BAA0B,KAAK;EAC/B,IAAI,MAAM,WAAW,MAAM,eACzB,gBAAgB,OAAO,QAAQ,MAAM,MAAM,MAAM,aAAa;CAElE,IACA;CAEN,MAAM,gBAAgB,WAClB,YACA,KACEA,oBAAO,MACP,UAAUA,oBAAO,QACjB,aAAa,KAAK,KAAKA,oBAAO,QAC9B,SAAS,OAAOA,oBAAO,WACvB,SACF;CAEJ,MAAM,eAA6B;EACjC,MAAM;GACJ,QAAQ;IACN,WAAW;IACX,IAAI;GACN;GACA,WAAWA,oBAAO;GAClB,MAAM;EACR;EACA,WAAW,EACT,WAAWA,oBAAO,UACpB;EACA,WAAW,EAAE,WAAWA,oBAAO,UAAU;EACzC,YAAY,EAAE,WAAWA,oBAAO,WAAW;EAC3C,QAAQ;GACN,aAAa;GACb,WAAWA,oBAAO;GAClB,MAAM,MAAM;GACZ,OAAO,MAAM,UAAU,YAAY,KAAA,IAAY,MAAM;GACrD,YAAY,MAAM;GAClB,UAAU,SAAS,gBACjB,qBAAAC,YAAA,EAAA,UAAA,CACG,YAAY,UACb,oBAAC,UAAD;IAAoB;IAAkB;IAAkB;GAAW,CAAA,CACnE,EAAA,CAAA,CACH;EACH;CACF;CAEA,MAAM,8BAA8B,cAC/B,EACC,gBAAgB,KAClB,IACA,CAAC;CAKL,MAAM,kBAAkB,WAAW,QAAQ,KAAK,CAAC,kBAAkB,QAAQ;CAM3E,MAAM,UACJ,qBAAC,sBAAD;EAAsB,OAAO;EAA7B,UAAA,CACG,kBAAkB,WALrBC,oBAAC,qBAAD;GAAqB,cAAa;GAAO;EAA8B,CAKvC,GAC9B,oBAAC,UAAD;GACE,qBAAA;GACU;GACF;GACE;GAEV,UAAA,oBAAC,uBAAD;IAAuB,IAAI;IAAQ,WAAW;GAAS,CAAA;EAC/C,CAAA,CACU;;CAIxB,IAAI,YACF,OACE,oBAAC,QAAD;EAAM,WAAW;EAAe,OAAO;GAAE,GAAG;GAAO;EAAW;EAAG,OAAA;EAC9D,UAAA;CACG,CAAA;CAIV,OACE,oBAAC,MAAD;EACE,GAAI;EACJ,GAAI;EACI;EACE;EACV,gBAAgB;EAChB,WAAW;EACN;EACL,OAAO;GAAE,GAAG;GAAO;EAAW;EAE7B,UAAA;CACG,CAAA;AAEV,CAAC"}
@@ -1,9 +1,9 @@
1
1
  "use client"
2
2
  /* */
3
- import useSelector from "../../../lib/mobx/useSelector.mjs";
4
- import { useStatic } from "../../../lib/hooks/useStatic.mjs";
5
3
  import { ListViewMode as ListViewMode$1 } from "../../../../../components-base/src/list/viewMode/ListViewMode.mjs";
6
4
  import "../../../../../components-base/src/index.mjs";
5
+ import useSelector from "../../../lib/mobx/useSelector.mjs";
6
+ import { useStatic } from "../../../lib/hooks/useStatic.mjs";
7
7
  //#region src/components/List/model/ListViewMode.ts
8
8
  /**
9
9
  * React's view of the list's layout mode.
@@ -1,11 +1,11 @@
1
1
  "use client"
2
2
  /* */
3
- import useSelector from "../../../lib/mobx/useSelector.mjs";
4
- import { useStatic } from "../../../lib/hooks/useStatic.mjs";
5
3
  import { getListColumn } from "../../../../../components-base/src/list/ListModelContext.mjs";
6
4
  import { mergeHiddenSorting } from "../../../../../components-base/src/list/sorting/ListSorting.mjs";
7
5
  import { ListTable } from "../../../../../components-base/src/list/table/ListTable.mjs";
8
6
  import "../../../../../components-base/src/index.mjs";
7
+ import useSelector from "../../../lib/mobx/useSelector.mjs";
8
+ import { useStatic } from "../../../lib/hooks/useStatic.mjs";
9
9
  import { Filter } from "./filter/Filter.mjs";
10
10
  import { useEffect, useEffectEvent, useState } from "react";
11
11
  import { getCoreRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel } from "@tanstack/table-core";
@@ -1,9 +1,9 @@
1
1
  "use client"
2
2
  /* */
3
- import useSelector from "../../../../lib/mobx/useSelector.mjs";
4
- import { useStatic } from "../../../../lib/hooks/useStatic.mjs";
5
3
  import { ListLoaderState } from "../../../../../../components-base/src/list/loading/ListLoaderState.mjs";
6
4
  import "../../../../../../components-base/src/index.mjs";
5
+ import useSelector from "../../../../lib/mobx/useSelector.mjs";
6
+ import { useStatic } from "../../../../lib/hooks/useStatic.mjs";
7
7
  //#region src/components/List/model/loading/IncrementalLoaderState.ts
8
8
  /**
9
9
  * React's view of the list's loading state.
@@ -3,7 +3,6 @@
3
3
  import { SkeletonText } from "../../../SkeletonText/SkeletonText.mjs";
4
4
  import { SkeletonRawText } from "../../../SkeletonMode/components/SkeletonRawText/SkeletonRawText.mjs";
5
5
  import Table_module_default from "../../Table.module.mjs";
6
- import { TableColumn } from "../TableColumn/TableColumn.mjs";
7
6
  import clsx from "clsx";
8
7
  import { Suspense } from "react";
9
8
  import { jsx } from "react/jsx-runtime";
@@ -12,20 +11,14 @@ import * as Aria from "react-aria-components";
12
11
  /** @flr-generate all */
13
12
  var TableCell = (props) => {
14
13
  const { children, className, rowHeader, horizontalAlign = "start", ...rest } = props;
15
- const rootClassName = clsx(Table_module_default.cell, horizontalAlign !== "start" && Table_module_default[`horizontal-align-${horizontalAlign}`], className);
16
- const content = /* @__PURE__ */ jsx(Suspense, {
17
- fallback: /* @__PURE__ */ jsx(SkeletonText, { width: "100px" }),
18
- children: /* @__PURE__ */ jsx(SkeletonRawText, { children })
19
- });
20
- if (rowHeader) return /* @__PURE__ */ jsx(TableColumn, {
21
- className: rootClassName,
22
- ...rest,
23
- children: content
24
- });
14
+ const rootClassName = clsx(Table_module_default.cell, rowHeader && Table_module_default.column, horizontalAlign !== "start" && Table_module_default[`horizontal-align-${horizontalAlign}`], className);
25
15
  return /* @__PURE__ */ jsx(Aria.Cell, {
26
16
  className: rootClassName,
27
17
  ...rest,
28
- children: content
18
+ children: /* @__PURE__ */ jsx(Suspense, {
19
+ fallback: /* @__PURE__ */ jsx(SkeletonText, { width: "100px" }),
20
+ children: /* @__PURE__ */ jsx(SkeletonRawText, { children })
21
+ })
29
22
  });
30
23
  };
31
24
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"TableCell.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/Table/components/TableCell/TableCell.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport { Suspense } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"../../Table.module.scss\";\nimport { SkeletonText } from \"@/components/SkeletonText\";\nimport { TableColumn } from \"@/components/Table/components/TableColumn/TableColumn\";\nimport { SkeletonRawText } from \"@/components/SkeletonMode/components/SkeletonRawText\";\n\nexport interface TableCellProps\n extends\n Omit<Aria.CellProps, \"children\" | \"style\" | \"render\">,\n PropsWithChildren {\n /** Use cell as row header */\n rowHeader?: boolean;\n /** Horizontal alignment of the cell content @default \"start\" */\n horizontalAlign?: \"start\" | \"center\" | \"end\";\n}\n\n/** @flr-generate all */\nexport const TableCell: FC<TableCellProps> = (props) => {\n const {\n children,\n className,\n rowHeader,\n horizontalAlign = \"start\",\n ...rest\n } = props;\n\n const rootClassName = clsx(\n styles.cell,\n horizontalAlign !== \"start\" &&\n styles[`horizontal-align-${horizontalAlign}`],\n className,\n );\n\n const content = (\n <Suspense fallback={<SkeletonText width=\"100px\" />}>\n <SkeletonRawText>{children}</SkeletonRawText>\n </Suspense>\n );\n\n if (rowHeader) {\n return (\n <TableColumn className={rootClassName} {...rest}>\n {content}\n </TableColumn>\n );\n }\n\n return (\n <Aria.Cell className={rootClassName} {...rest}>\n {content}\n </Aria.Cell>\n );\n};\n\nexport default TableCell;\n"],"mappings":";;;;;;;;;;;;AAoBA,IAAa,aAAiC,UAAU;CACtD,MAAM,EACJ,UACA,WACA,WACA,kBAAkB,SAClB,GAAG,SACD;CAEJ,MAAM,gBAAgB,KACpBA,qBAAO,MACP,oBAAoB,WAClBA,qBAAO,oBAAoB,oBAC7B,SACF;CAEA,MAAM,UACJ,oBAAC,UAAD;EAAU,UAAU,oBAAC,cAAD,EAAc,OAAM,QAAS,CAAA;EAC/C,UAAA,oBAAC,iBAAD,EAAkB,SAA0B,CAAA;CACpC,CAAA;CAGZ,IAAI,WACF,OACE,oBAAC,aAAD;EAAa,WAAW;EAAe,GAAI;EACxC,UAAA;CACU,CAAA;CAIjB,OACE,oBAAC,KAAK,MAAN;EAAW,WAAW;EAAe,GAAI;EACtC,UAAA;CACQ,CAAA;AAEf"}
1
+ {"version":3,"file":"TableCell.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/Table/components/TableCell/TableCell.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport { Suspense } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"../../Table.module.scss\";\nimport { SkeletonText } from \"@/components/SkeletonText\";\nimport { SkeletonRawText } from \"@/components/SkeletonMode/components/SkeletonRawText\";\n\nexport interface TableCellProps\n extends\n Omit<Aria.CellProps, \"children\" | \"style\" | \"render\">,\n PropsWithChildren {\n /**\n * Styles the cell as a row header. Its semantics come from the column: the\n * first column, or the one with `isRowHeader`.\n */\n rowHeader?: boolean;\n /** Horizontal alignment of the cell content @default \"start\" */\n horizontalAlign?: \"start\" | \"center\" | \"end\";\n}\n\n/** @flr-generate all */\nexport const TableCell: FC<TableCellProps> = (props) => {\n const {\n children,\n className,\n rowHeader,\n horizontalAlign = \"start\",\n ...rest\n } = props;\n\n const rootClassName = clsx(\n styles.cell,\n rowHeader && styles.column,\n horizontalAlign !== \"start\" &&\n styles[`horizontal-align-${horizontalAlign}`],\n className,\n );\n\n return (\n <Aria.Cell className={rootClassName} {...rest}>\n <Suspense fallback={<SkeletonText width=\"100px\" />}>\n <SkeletonRawText>{children}</SkeletonRawText>\n </Suspense>\n </Aria.Cell>\n );\n};\n\nexport default TableCell;\n"],"mappings":";;;;;;;;;;;AAsBA,IAAa,aAAiC,UAAU;CACtD,MAAM,EACJ,UACA,WACA,WACA,kBAAkB,SAClB,GAAG,SACD;CAEJ,MAAM,gBAAgB,KACpBA,qBAAO,MACP,aAAaA,qBAAO,QACpB,oBAAoB,WAClBA,qBAAO,oBAAoB,oBAC7B,SACF;CAEA,OACE,oBAAC,KAAK,MAAN;EAAW,WAAW;EAAe,GAAI;EACvC,UAAA,oBAAC,UAAD;GAAU,UAAU,oBAAC,cAAD,EAAc,OAAM,QAAS,CAAA;GAC/C,UAAA,oBAAC,iBAAD,EAAkB,SAA0B,CAAA;EACpC,CAAA;CACD,CAAA;AAEf"}
@@ -3,17 +3,19 @@
3
3
  import { PropsContextProvider } from "../../../../lib/propsContext/components/PropsContextProvider.mjs";
4
4
  import { SkeletonRawText } from "../../../SkeletonMode/components/SkeletonRawText/SkeletonRawText.mjs";
5
5
  import Table_module_default from "../../Table.module.mjs";
6
+ import { useIsFirstColumn } from "../TableHeader/context.mjs";
6
7
  import clsx from "clsx";
7
8
  import { jsx } from "react/jsx-runtime";
8
9
  import * as Aria from "react-aria-components";
9
10
  //#region src/components/Table/components/TableColumn/TableColumn.tsx
10
11
  /** @flr-generate all */
11
12
  var TableColumn = (props) => {
12
- const { children, className, horizontalAlign = "start", width, minWidth, ...rest } = props;
13
+ const { children, className, horizontalAlign = "start", width, minWidth, isRowHeader, ...rest } = props;
14
+ const isFirstColumn = useIsFirstColumn();
13
15
  const rootClassName = clsx(Table_module_default.column, horizontalAlign !== "start" && Table_module_default[`horizontal-align-${horizontalAlign}`], className);
14
16
  const propsContext = { Checkbox: { slot: null } };
15
17
  return /* @__PURE__ */ jsx(Aria.Column, {
16
- isRowHeader: true,
18
+ isRowHeader: isRowHeader ?? isFirstColumn ?? true,
17
19
  className: rootClassName,
18
20
  ...rest,
19
21
  style: {
@@ -1 +1 @@
1
- {"version":3,"file":"TableColumn.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/Table/components/TableColumn/TableColumn.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"../../Table.module.scss\";\nimport { type PropsContext, PropsContextProvider } from \"@/lib/propsContext\";\nimport { SkeletonRawText } from \"@/components/SkeletonMode/components/SkeletonRawText\";\n\nexport interface TableColumnProps\n extends\n Omit<\n Aria.ColumnProps,\n \"children\" | \"width\" | \"minWidth\" | \"maxWidth\" | \"style\"\n >,\n PropsWithChildren {\n /** Horizontal alignment of the cell content @default \"start\" */\n horizontalAlign?: \"start\" | \"center\" | \"end\";\n /** The width of the column. */\n width?: number | string;\n /** The minimum width of the column. */\n minWidth?: number | string;\n}\n\n/** @flr-generate all */\nexport const TableColumn: FC<TableColumnProps> = (props) => {\n const {\n children,\n className,\n horizontalAlign = \"start\",\n width,\n minWidth,\n ...rest\n } = props;\n const rootClassName = clsx(\n styles.column,\n horizontalAlign !== \"start\" &&\n styles[`horizontal-align-${horizontalAlign}`],\n className,\n );\n\n const propsContext: PropsContext = { Checkbox: { slot: null } };\n\n return (\n <Aria.Column\n isRowHeader\n className={rootClassName}\n {...rest}\n style={{ width, minWidth }}\n >\n <PropsContextProvider props={propsContext}>\n <SkeletonRawText>{children}</SkeletonRawText>\n </PropsContextProvider>\n </Aria.Column>\n );\n};\n\nexport default TableColumn;\n"],"mappings":";;;;;;;;;;AAuBA,IAAa,eAAqC,UAAU;CAC1D,MAAM,EACJ,UACA,WACA,kBAAkB,SAClB,OACA,UACA,GAAG,SACD;CACJ,MAAM,gBAAgB,KACpBA,qBAAO,QACP,oBAAoB,WAClBA,qBAAO,oBAAoB,oBAC7B,SACF;CAEA,MAAM,eAA6B,EAAE,UAAU,EAAE,MAAM,KAAK,EAAE;CAE9D,OACE,oBAAC,KAAK,QAAN;EACE,aAAA;EACA,WAAW;EACX,GAAI;EACJ,OAAO;GAAE;GAAO;EAAS;EAEzB,UAAA,oBAAC,sBAAD;GAAsB,OAAO;GAC3B,UAAA,oBAAC,iBAAD,EAAkB,SAA0B,CAAA;EACxB,CAAA;CACX,CAAA;AAEjB"}
1
+ {"version":3,"file":"TableColumn.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/Table/components/TableColumn/TableColumn.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"../../Table.module.scss\";\nimport { type PropsContext, PropsContextProvider } from \"@/lib/propsContext\";\nimport { SkeletonRawText } from \"@/components/SkeletonMode/components/SkeletonRawText\";\nimport { useIsFirstColumn } from \"@/components/Table/components/TableHeader/context\";\n\nexport interface TableColumnProps\n extends\n Omit<\n Aria.ColumnProps,\n \"children\" | \"width\" | \"minWidth\" | \"maxWidth\" | \"style\"\n >,\n PropsWithChildren {\n /** Horizontal alignment of the cell content @default \"start\" */\n horizontalAlign?: \"start\" | \"center\" | \"end\";\n /** The width of the column. */\n width?: number | string;\n /** The minimum width of the column. */\n minWidth?: number | string;\n}\n\n/** @flr-generate all */\nexport const TableColumn: FC<TableColumnProps> = (props) => {\n const {\n children,\n className,\n horizontalAlign = \"start\",\n width,\n minWidth,\n isRowHeader,\n ...rest\n } = props;\n const isFirstColumn = useIsFirstColumn();\n\n const rootClassName = clsx(\n styles.column,\n horizontalAlign !== \"start\" &&\n styles[`horizontal-align-${horizontalAlign}`],\n className,\n );\n\n const propsContext: PropsContext = { Checkbox: { slot: null } };\n\n return (\n <Aria.Column\n isRowHeader={isRowHeader ?? isFirstColumn ?? true}\n className={rootClassName}\n {...rest}\n style={{ width, minWidth }}\n >\n <PropsContextProvider props={propsContext}>\n <SkeletonRawText>{children}</SkeletonRawText>\n </PropsContextProvider>\n </Aria.Column>\n );\n};\n\nexport default TableColumn;\n"],"mappings":";;;;;;;;;;;AAwBA,IAAa,eAAqC,UAAU;CAC1D,MAAM,EACJ,UACA,WACA,kBAAkB,SAClB,OACA,UACA,aACA,GAAG,SACD;CACJ,MAAM,gBAAgB,iBAAiB;CAEvC,MAAM,gBAAgB,KACpBA,qBAAO,QACP,oBAAoB,WAClBA,qBAAO,oBAAoB,oBAC7B,SACF;CAEA,MAAM,eAA6B,EAAE,UAAU,EAAE,MAAM,KAAK,EAAE;CAE9D,OACE,oBAAC,KAAK,QAAN;EACE,aAAa,eAAe,iBAAiB;EAC7C,WAAW;EACX,GAAI;EACJ,OAAO;GAAE;GAAO;EAAS;EAEzB,UAAA,oBAAC,sBAAD;GAAsB,OAAO;GAC3B,UAAA,oBAAC,iBAAD,EAAkB,SAA0B,CAAA;EACxB,CAAA;CACX,CAAA;AAEjB"}
@@ -1,7 +1,9 @@
1
1
  "use client"
2
2
  /* */
3
3
  import Table_module_default from "../../Table.module.mjs";
4
+ import { IsFirstColumnContext } from "./context.mjs";
4
5
  import clsx from "clsx";
6
+ import { Children } from "react";
5
7
  import { jsx } from "react/jsx-runtime";
6
8
  import * as Aria from "react-aria-components";
7
9
  //#region src/components/Table/components/TableHeader/TableHeader.tsx
@@ -9,10 +11,14 @@ import * as Aria from "react-aria-components";
9
11
  var TableHeader = (props) => {
10
12
  const { children, className, ...rest } = props;
11
13
  const rootClassName = clsx(Table_module_default.header, className);
14
+ const columns = typeof children === "function" ? children : Children.toArray(children).map((column, index) => /* @__PURE__ */ jsx(IsFirstColumnContext, {
15
+ value: index === 0,
16
+ children: column
17
+ }, index));
12
18
  return /* @__PURE__ */ jsx(Aria.TableHeader, {
13
19
  className: rootClassName,
14
20
  ...rest,
15
- children
21
+ children: columns
16
22
  });
17
23
  };
18
24
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"TableHeader.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/Table/components/TableHeader/TableHeader.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"../../Table.module.scss\";\n\nexport type TableHeaderProps = Aria.TableHeaderProps<never>;\n\n/** @flr-generate all */\nexport const TableHeader: FC<TableHeaderProps> = (props) => {\n const { children, className, ...rest } = props;\n\n const rootClassName = clsx(styles.header, className);\n\n return (\n <Aria.TableHeader className={rootClassName} {...rest}>\n {children}\n </Aria.TableHeader>\n );\n};\n\nexport default TableHeader;\n"],"mappings":";;;;;;;;AAQA,IAAa,eAAqC,UAAU;CAC1D,MAAM,EAAE,UAAU,WAAW,GAAG,SAAS;CAEzC,MAAM,gBAAgB,KAAKA,qBAAO,QAAQ,SAAS;CAEnD,OACE,oBAAC,KAAK,aAAN;EAAkB,WAAW;EAAe,GAAI;EAC7C;CACe,CAAA;AAEtB"}
1
+ {"version":3,"file":"TableHeader.mjs","names":["styles"],"sources":["../../../../../../../../../src/components/Table/components/TableHeader/TableHeader.tsx"],"sourcesContent":["import { Children, type FC } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"../../Table.module.scss\";\nimport { IsFirstColumnContext } from \"./context\";\n\nexport type TableHeaderProps = Aria.TableHeaderProps<never>;\n\n/** @flr-generate all */\nexport const TableHeader: FC<TableHeaderProps> = (props) => {\n const { children, className, ...rest } = props;\n\n const rootClassName = clsx(styles.header, className);\n\n // Assumes the first child renders a column; a wrapper that renders nothing\n // leaves the table without row header column, and react-aria throws.\n const columns =\n typeof children === \"function\"\n ? children\n : Children.toArray(children).map((column, index) => (\n <IsFirstColumnContext key={index} value={index === 0}>\n {column}\n </IsFirstColumnContext>\n ));\n\n return (\n <Aria.TableHeader className={rootClassName} {...rest}>\n {columns}\n </Aria.TableHeader>\n );\n};\n\nexport default TableHeader;\n"],"mappings":";;;;;;;;;;AASA,IAAa,eAAqC,UAAU;CAC1D,MAAM,EAAE,UAAU,WAAW,GAAG,SAAS;CAEzC,MAAM,gBAAgB,KAAKA,qBAAO,QAAQ,SAAS;CAInD,MAAM,UACJ,OAAO,aAAa,aAChB,WACA,SAAS,QAAQ,QAAQ,CAAC,CAAC,KAAK,QAAQ,UACtC,oBAAC,sBAAD;EAAkC,OAAO,UAAU;EAChD,UAAA;CACmB,GAFK,KAEL,CACvB;CAEP,OACE,oBAAC,KAAK,aAAN;EAAkB,WAAW;EAAe,GAAI;EAC7C,UAAA;CACe,CAAA;AAEtB"}
@@ -0,0 +1,14 @@
1
+ "use client"
2
+ /* */
3
+ import { createContext, useContext } from "react";
4
+ //#region src/components/Table/components/TableHeader/context.ts
5
+ /**
6
+ * Whether a column is the first of its `TableHeader`. Undefined outside a
7
+ * header that can tell, e.g. with dynamic `columns`.
8
+ */
9
+ var IsFirstColumnContext = createContext(void 0);
10
+ var useIsFirstColumn = () => useContext(IsFirstColumnContext);
11
+ //#endregion
12
+ export { IsFirstColumnContext, useIsFirstColumn };
13
+
14
+ //# sourceMappingURL=context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.mjs","names":[],"sources":["../../../../../../../../../src/components/Table/components/TableHeader/context.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\n\n/**\n * Whether a column is the first of its `TableHeader`. Undefined outside a\n * header that can tell, e.g. with dynamic `columns`.\n */\nexport const IsFirstColumnContext = createContext<boolean | undefined>(\n undefined,\n);\n\nexport const useIsFirstColumn = () => useContext(IsFirstColumnContext);\n"],"mappings":";;;;;;;;AAMA,IAAa,uBAAuB,cAClC,KAAA,CACF;AAEA,IAAa,yBAAyB,WAAW,oBAAoB"}
@@ -1,70 +1,22 @@
1
1
  "use client"
2
2
  /* */
3
+ import { OverlayState } from "../../../../../components-base/src/overlay/OverlayState.mjs";
4
+ import "../../../../../components-base/src/index.mjs";
3
5
  import useSelector from "../../mobx/useSelector.mjs";
4
6
  import { useStatic } from "../../hooks/useStatic.mjs";
5
7
  import { useCloseOverlayConfirmationController } from "./useCloseOverlayConfirmationController.mjs";
6
8
  import { useEffect, useRef } from "react";
7
- import { action, computed, makeObservable, observable, runInAction } from "mobx";
8
9
  //#region src/lib/controller/overlay/OverlayController.ts
9
- var OverlayController = class OverlayController {
10
- isOpen = false;
11
- isContentSuspended = false;
12
- onOpenHandlers = /* @__PURE__ */ new Set();
13
- onCloseHandlers = /* @__PURE__ */ new Set();
14
- onOpenChangeHandlers = /* @__PURE__ */ new Set();
15
- showConfirmationModal = false;
16
- closeIsConfirmed = false;
17
- confirmOnCloseFromOptions;
18
- /**
19
- * Every mounted component that has an opinion on close confirmation
20
- * contributes one entry here – e.g. a `Modal` with a `confirmOnClose` prop
21
- * and a `Form` tracking its dirty state. Combining them instead of assigning
22
- * a single flag keeps them from overwriting each other.
23
- */
24
- confirmOnCloseSources = observable.map();
25
- /**
26
- * Active grants that allow closing without a confirmation. Each entry is
27
- * scoped to an ongoing operation that legitimately closes the overlay – e.g.
28
- * a `Form` submit – and is dropped again when that operation has finished, so
29
- * an operation that does _not_ close the overlay leaves the confirmation
30
- * armed.
31
- */
32
- closeWithoutConfirmationGrants = /* @__PURE__ */ new Set();
33
- /**
34
- * The open state a `setOpen` call is currently applying. Handlers run before
35
- * `isOpen` is assigned, so a handler that calls `setOpen` again would not be
36
- * caught by the equality check at the top and would recurse.
37
- */
38
- openStateInFlight;
39
- constructor(options = {}) {
40
- makeObservable(this, {
41
- isOpen: observable,
42
- isContentSuspended: observable,
43
- showConfirmationModal: observable,
44
- confirmOnCloseEnabled: computed,
45
- open: action.bound,
46
- close: action.bound,
47
- toggle: action.bound,
48
- setOpen: action.bound,
49
- syncOpen: action.bound,
50
- setIsContentSuspended: action.bound,
51
- confirmClose: action.bound,
52
- cancelConfirmation: action.bound
53
- });
54
- const { isDefaultOpen = false, confirmOnClose = false } = options;
55
- this.isOpen = isDefaultOpen;
56
- this.confirmOnCloseFromOptions = confirmOnClose;
57
- }
58
- /** Whether closing this overlay currently requires a confirmation. */
59
- get confirmOnCloseEnabled() {
60
- if (this.confirmOnCloseSources.size === 0) return this.confirmOnCloseFromOptions;
61
- return Array.from(this.confirmOnCloseSources.values()).some(Boolean);
62
- }
10
+ /**
11
+ * The state is `OverlayState` from `@mittwald/flow-components-base`, shared
12
+ * with every remote binding; this adds the hooks.
13
+ */
14
+ var OverlayController = class OverlayController extends OverlayState {
63
15
  useUpdateOptions(options = {}) {
64
16
  const { onOpen, onClose, onOpenChange, confirmOnClose } = options;
65
- this.useOnHandler(onOpen, (h) => this.addOpenStateHandler(h, this.onOpenHandlers));
66
- this.useOnHandler(onClose, (h) => this.addOpenStateHandler(h, this.onCloseHandlers));
67
- this.useOnHandler(onOpenChange, (h) => this.addOpenStateHandler(h, this.onOpenChangeHandlers));
17
+ this.useOnHandler(onOpen, (h) => this.addOnOpen(h));
18
+ this.useOnHandler(onClose, (h) => this.addOnClose(h));
19
+ this.useOnHandler(onOpenChange, (h) => this.addOnOpenChange(h));
68
20
  this.useConfirmOnCloseSource(confirmOnClose);
69
21
  }
70
22
  /**
@@ -86,12 +38,6 @@ var OverlayController = class OverlayController {
86
38
  confirmOnClose
87
39
  ]);
88
40
  }
89
- setConfirmOnCloseSource(source, confirmOnClose) {
90
- runInAction(() => this.confirmOnCloseSources.set(source, confirmOnClose));
91
- }
92
- removeConfirmOnCloseSource(source) {
93
- runInAction(() => this.confirmOnCloseSources.delete(source));
94
- }
95
41
  /**
96
42
  * Can be used to execute a callback when the Overlay has unmounted – means
97
43
  * after any closing animation.
@@ -119,81 +65,9 @@ var OverlayController = class OverlayController {
119
65
  controller.useUpdateOptions(options);
120
66
  return controller;
121
67
  }
122
- addOpenStateHandler(handler, handlersSet) {
123
- handlersSet.add(handler);
124
- return () => {
125
- handlersSet.delete(handler);
126
- };
127
- }
128
68
  useOnHandler(handler, addHandlerFn) {
129
69
  useEffect(() => handler ? addHandlerFn(handler) : void 0, [handler, this]);
130
70
  }
131
- executeHandlers(isOpen, handlers) {
132
- return Array.from(handlers).map((handler) => handler(isOpen)).some((result) => result === false);
133
- }
134
- executeOnClose() {
135
- return this.executeHandlers(false, this.onCloseHandlers);
136
- }
137
- executeOnOpen() {
138
- return this.executeHandlers(true, this.onOpenHandlers);
139
- }
140
- executeOnOpenChange(isOpen) {
141
- return this.executeHandlers(isOpen, this.onOpenChangeHandlers);
142
- }
143
- addOnClose(handler) {
144
- return this.addOpenStateHandler(handler, this.onCloseHandlers);
145
- }
146
- addOnOpen(handler) {
147
- return this.addOpenStateHandler(handler, this.onOpenHandlers);
148
- }
149
- addOnOpenChange(handler) {
150
- return this.addOpenStateHandler(handler, this.onOpenChangeHandlers);
151
- }
152
- open() {
153
- this.setOpen(true);
154
- }
155
- close(options) {
156
- this.setOpen(false, options);
157
- }
158
- toggle() {
159
- this.setOpen(!this.isOpen);
160
- }
161
- setOpen(toOpen, options = {}) {
162
- if (this.isOpen === toOpen || this.openStateInFlight === toOpen) return;
163
- this.openStateInFlight = toOpen;
164
- try {
165
- this.applyOpenState(toOpen, options);
166
- } finally {
167
- this.openStateInFlight = void 0;
168
- }
169
- }
170
- /**
171
- * Sets the open state without running any handler. Use it to mirror a
172
- * controlled `isOpen` prop, whose change comes from the consumer – notifying
173
- * them of their own state would echo it back.
174
- */
175
- syncOpen(toOpen) {
176
- this.isOpen = toOpen;
177
- }
178
- applyOpenState(toOpen, options) {
179
- const { bypassConfirmation = false } = options;
180
- if (toOpen === false) {
181
- const closeIsConfirmed = this.closeIsConfirmed;
182
- this.closeIsConfirmed = false;
183
- if (this.confirmOnCloseEnabled && !closeIsConfirmed && this.closeWithoutConfirmationGrants.size === 0 && !bypassConfirmation) {
184
- this.showConfirmationModal = true;
185
- return;
186
- }
187
- }
188
- let aborted;
189
- if (toOpen) aborted = this.executeOnOpen();
190
- else aborted = this.executeOnClose();
191
- if (!aborted) aborted = this.executeOnOpenChange(toOpen);
192
- if (!aborted) this.isOpen = toOpen;
193
- }
194
- setIsContentSuspended(to) {
195
- this.isContentSuspended = to;
196
- }
197
71
  useIsOpen() {
198
72
  return useSelector(() => this.isOpen);
199
73
  }
@@ -209,28 +83,6 @@ var OverlayController = class OverlayController {
209
83
  useConfirmationController() {
210
84
  return useCloseOverlayConfirmationController(this);
211
85
  }
212
- /**
213
- * Allows closing this overlay without a confirmation until the returned
214
- * disposer is called. Use it around an operation that may legitimately close
215
- * the overlay – e.g. a `Form` submit, where a "discard unsaved changes?"
216
- * prompt would be nonsense – and dispose it as soon as that operation has
217
- * finished. An operation that ends without closing the overlay therefore
218
- * leaves the confirmation armed (#2775).
219
- */
220
- grantCloseWithoutConfirmation() {
221
- const grant = {};
222
- this.closeWithoutConfirmationGrants.add(grant);
223
- return () => {
224
- this.closeWithoutConfirmationGrants.delete(grant);
225
- };
226
- }
227
- confirmClose() {
228
- this.closeIsConfirmed = true;
229
- this.showConfirmationModal = false;
230
- }
231
- cancelConfirmation() {
232
- this.showConfirmationModal = false;
233
- }
234
86
  };
235
87
  //#endregion
236
88
  export { OverlayController };
@@ -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 /**\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":";;;;;;;;AAgEA,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 OverlayState,\n type AnyOverlayOpenStateHandler,\n type DisposerFn,\n type OverlayCloseHandler,\n type OverlayCloseOptions,\n type OverlayOpenHandler,\n type OverlayOpenStateHandler,\n} from \"@mittwald/flow-components-base\";\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 {\n OverlayCloseHandler,\n OverlayOpenHandler,\n OverlayOpenStateHandler,\n} from \"@mittwald/flow-components-base\";\n\nexport interface CloseOverlayOptions extends OverlayCloseOptions {\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}\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\n/**\n * The state is `OverlayState` from `@mittwald/flow-components-base`, shared\n * with every remote binding; this adds the hooks.\n */\nexport class OverlayController extends OverlayState<CloseOptions> {\n public useUpdateOptions(options: OverlayControllerOptions = {}): void {\n const { onOpen, onClose, onOpenChange, confirmOnClose } = options;\n\n this.useOnHandler(onOpen, (h) => this.addOnOpen(h));\n this.useOnHandler(onClose, (h) => this.addOnClose(h));\n this.useOnHandler(onOpenChange, (h) => this.addOnOpenChange(h));\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 /**\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 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 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"],"mappings":";;;;;;;;;;;;;AA8DA,IAAa,oBAAb,MAAa,0BAA0B,aAA2B;CAChE,iBAAwB,UAAoC,CAAC,GAAS;EACpE,MAAM,EAAE,QAAQ,SAAS,cAAc,mBAAmB;EAE1D,KAAK,aAAa,SAAS,MAAM,KAAK,UAAU,CAAC,CAAC;EAClD,KAAK,aAAa,UAAU,MAAM,KAAK,WAAW,CAAC,CAAC;EACpD,KAAK,aAAa,eAAe,MAAM,KAAK,gBAAgB,CAAC,CAAC;EAE9D,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;;;;;;;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,aACE,SACA,cACA;EACA,gBACS,UAAU,aAAa,OAAO,IAAI,KAAA,GACzC,CAAC,SAAS,IAAI,CAChB;CACF;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;AACF"}
@@ -17,4 +17,5 @@ import { ListSearch } from "./list/search/ListSearch.mjs";
17
17
  import { ListSorting, mergeHiddenSorting } from "./list/sorting/ListSorting.mjs";
18
18
  import { ListTable } from "./list/table/ListTable.mjs";
19
19
  import { ListViewMode } from "./list/viewMode/ListViewMode.mjs";
20
- export { ActionState, ListBatchesController, ListDateRangeFilter, ListFilter, ListItemCollection, ListLoaderState, ListSearch, ListSorting, ListTable, ListViewMode, actionStateDurations, formatListDateRange, getListColumn, getListDataLoaderOptions, getListDateTimeRangeUpdate, isListDateTimeRangeEndBeforeStart, listDateTimeRangeFieldsFromValue, mergeHiddenSorting, resolveListDateRange, toListCalendarDate, toListTime };
20
+ import { OverlayState } from "./overlay/OverlayState.mjs";
21
+ export { ActionState, ListBatchesController, ListDateRangeFilter, ListFilter, ListItemCollection, ListLoaderState, ListSearch, ListSorting, ListTable, ListViewMode, OverlayState, actionStateDurations, formatListDateRange, getListColumn, getListDataLoaderOptions, getListDateTimeRangeUpdate, isListDateTimeRangeEndBeforeStart, listDateTimeRangeFieldsFromValue, mergeHiddenSorting, resolveListDateRange, toListCalendarDate, toListTime };