@tamagui/dismissable 1.0.1-beta.117 → 1.0.1-beta.120
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.
- package/dist/cjs/Dismissable.js +10 -11
- package/dist/cjs/Dismissable.js.map +2 -2
- package/dist/cjs/DismissableProps.js.map +1 -1
- package/dist/esm/Dismissable.js +9 -8
- package/dist/esm/Dismissable.js.map +2 -2
- package/dist/jsx/Dismissable.js +9 -8
- package/dist/jsx/Dismissable.js.map +2 -2
- package/package.json +5 -5
- package/src/Dismissable.tsx +8 -13
- package/src/DismissableProps.tsx +5 -0
- package/types/Dismissable.d.ts +1 -3
- package/types/Dismissable.d.ts.map +1 -1
- package/types/DismissableProps.d.ts +1 -0
- package/types/DismissableProps.d.ts.map +1 -1
package/dist/cjs/Dismissable.js
CHANGED
|
@@ -21,10 +21,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
22
|
var Dismissable_exports = {};
|
|
23
23
|
__export(Dismissable_exports, {
|
|
24
|
-
Branch: () => Branch,
|
|
25
24
|
Dismissable: () => Dismissable,
|
|
26
|
-
DismissableBranch: () => DismissableBranch
|
|
27
|
-
Root: () => Root
|
|
25
|
+
DismissableBranch: () => DismissableBranch
|
|
28
26
|
});
|
|
29
27
|
module.exports = __toCommonJS(Dismissable_exports);
|
|
30
28
|
var import_react_use_escape_keydown = require("@radix-ui/react-use-escape-keydown");
|
|
@@ -50,6 +48,7 @@ const DismissableContext = React.createContext({
|
|
|
50
48
|
const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
51
49
|
const {
|
|
52
50
|
disableOutsidePointerEvents = false,
|
|
51
|
+
forceUnmount,
|
|
53
52
|
onEscapeKeyDown,
|
|
54
53
|
onPointerDownOutside,
|
|
55
54
|
onFocusOutside,
|
|
@@ -116,6 +115,8 @@ const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
|
116
115
|
};
|
|
117
116
|
}, [node, disableOutsidePointerEvents, context]);
|
|
118
117
|
React.useEffect(() => {
|
|
118
|
+
if (forceUnmount)
|
|
119
|
+
return;
|
|
119
120
|
return () => {
|
|
120
121
|
if (!node)
|
|
121
122
|
return;
|
|
@@ -123,9 +124,11 @@ const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
|
123
124
|
context.layersWithOutsidePointerEventsDisabled.delete(node);
|
|
124
125
|
dispatchUpdate();
|
|
125
126
|
};
|
|
126
|
-
}, [node, context]);
|
|
127
|
+
}, [node, context, forceUnmount]);
|
|
127
128
|
React.useEffect(() => {
|
|
128
|
-
const handleUpdate = () =>
|
|
129
|
+
const handleUpdate = () => {
|
|
130
|
+
force({});
|
|
131
|
+
};
|
|
129
132
|
document.addEventListener(CONTEXT_UPDATE, handleUpdate);
|
|
130
133
|
return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate);
|
|
131
134
|
}, []);
|
|
@@ -187,7 +190,7 @@ function usePointerDownOutside(onPointerDownOutside) {
|
|
|
187
190
|
}
|
|
188
191
|
isPointerInsideReactTreeRef.current = false;
|
|
189
192
|
};
|
|
190
|
-
const timerId =
|
|
193
|
+
const timerId = setTimeout(() => {
|
|
191
194
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
192
195
|
}, 0);
|
|
193
196
|
return () => {
|
|
@@ -235,13 +238,9 @@ function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
|
|
|
235
238
|
target.dispatchEvent(event);
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
|
-
const Root = Dismissable;
|
|
239
|
-
const Branch = DismissableBranch;
|
|
240
241
|
// Annotate the CommonJS export names for ESM import in node:
|
|
241
242
|
0 && (module.exports = {
|
|
242
|
-
Branch,
|
|
243
243
|
Dismissable,
|
|
244
|
-
DismissableBranch
|
|
245
|
-
Root
|
|
244
|
+
DismissableBranch
|
|
246
245
|
});
|
|
247
246
|
//# sourceMappingURL=Dismissable.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/Dismissable.tsx"],
|
|
4
|
-
"sourcesContent": ["// forked from radix-ui\n// https://github.com/radix-ui/primitives/blob/cfd8dcba5fa6a0e751486af418d05a7b88a7f541/packages/react/dismissable-layer/src/DismissableLayer.tsx#L324\n\nimport { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown'\nimport { useComposedRefs } from '@tamagui/compose-refs'\nimport { composeEventHandlers } from '@tamagui/core'\nimport { useEvent } from '@tamagui/use-event'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { DismissableBranchProps, DismissableProps } from './DismissableProps'\n\nfunction dispatchDiscreteCustomEvent<E extends CustomEvent>(target: E['target'], event: E) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event))\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Dismissable\n * -----------------------------------------------------------------------------------------------*/\n\nconst DISMISSABLE_LAYER_NAME = 'Dismissable'\nconst CONTEXT_UPDATE = 'dismissable.update'\nconst POINTER_DOWN_OUTSIDE = 'dismissable.pointerDownOutside'\nconst FOCUS_OUTSIDE = 'dismissable.focusOutside'\n\nlet originalBodyPointerEvents: string\n\nconst DismissableContext = React.createContext({\n layers: new Set<HTMLDivElement>(),\n layersWithOutsidePointerEventsDisabled: new Set<HTMLDivElement>(),\n branches: new Set<HTMLDivElement>(),\n})\n\nconst Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, forwardedRef) => {\n const {\n disableOutsidePointerEvents = false,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n onDismiss,\n ...layerProps\n } = props\n const context = React.useContext(DismissableContext)\n const [node, setNode] = React.useState<HTMLDivElement | null>(null)\n const [, force] = React.useState({})\n const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node))\n const layers = Array.from(context.layers)\n const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); // prettier-ignore\n const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore\n const index = node ? layers.indexOf(node) : -1\n const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0\n const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex\n\n const pointerDownOutside = usePointerDownOutside((event) => {\n const target = event.target as HTMLDivElement\n const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target))\n if (!isPointerEventsEnabled || isPointerDownOnBranch) return\n onPointerDownOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n const focusOutside = useFocusOutside((event) => {\n const target = event.target as HTMLDivElement\n const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target))\n if (isFocusInBranch) return\n onFocusOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n useEscapeKeydown((event) => {\n const isHighestLayer = index === context.layers.size - 1\n if (!isHighestLayer) return\n onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n })\n\n React.useEffect(() => {\n if (!node) return\n if (disableOutsidePointerEvents) {\n if (context.layersWithOutsidePointerEventsDisabled.size === 0) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n document.body.style.pointerEvents = 'none'\n }\n context.layersWithOutsidePointerEventsDisabled.add(node)\n }\n context.layers.add(node)\n dispatchUpdate()\n return () => {\n if (\n disableOutsidePointerEvents &&\n context.layersWithOutsidePointerEventsDisabled.size === 1\n ) {\n document.body.style.pointerEvents = originalBodyPointerEvents\n }\n }\n }, [node, disableOutsidePointerEvents, context])\n\n /**\n * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect\n * because a change to `disableOutsidePointerEvents` would remove this layer from the stack\n * and add it to the end again so the layering order wouldn't be _creation order_.\n * We only want them to be removed from context stacks when unmounted.\n */\n React.useEffect(() => {\n return () => {\n if (!node) return\n context.layers.delete(node)\n context.layersWithOutsidePointerEventsDisabled.delete(node)\n dispatchUpdate()\n }\n }, [node, context])\n\n React.useEffect(() => {\n const handleUpdate = () => force({})\n document.addEventListener(CONTEXT_UPDATE, handleUpdate)\n return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate)\n }, [])\n\n return (\n <div\n {...layerProps}\n // @ts-ignore\n ref={composedRefs}\n style={{\n display: 'contents',\n pointerEvents: isBodyPointerEventsDisabled\n ? isPointerEventsEnabled\n ? 'auto'\n : 'none'\n : undefined,\n // @ts-ignore\n ...props.style,\n }}\n onFocusCapture={composeEventHandlers(\n // @ts-ignore\n props.onFocusCapture,\n focusOutside.onFocusCapture\n )}\n onBlurCapture={composeEventHandlers(\n // @ts-ignore\n props.onBlurCapture,\n focusOutside.onBlurCapture\n )}\n // @ts-ignore\n onPointerDownCapture={composeEventHandlers(\n // @ts-ignore\n props.onPointerDownCapture,\n pointerDownOutside.onPointerDownCapture\n )}\n />\n )\n})\n\nDismissable.displayName = DISMISSABLE_LAYER_NAME\n\n/* -------------------------------------------------------------------------------------------------\n * DismissableBranch\n * -----------------------------------------------------------------------------------------------*/\n\nconst BRANCH_NAME = 'DismissableBranch'\n\nconst DismissableBranch = React.forwardRef<HTMLDivElement, DismissableBranchProps>(\n (props, forwardedRef) => {\n const context = React.useContext(DismissableContext)\n const ref = React.useRef<HTMLDivElement>(null)\n const composedRefs = useComposedRefs(forwardedRef, ref)\n\n React.useEffect(() => {\n const node = ref.current\n if (node) {\n context.branches.add(node)\n return () => {\n context.branches.delete(node)\n }\n }\n }, [context.branches])\n\n return <div style={{ display: 'contents' }} {...props} ref={composedRefs} />\n }\n)\n\nDismissableBranch.displayName = BRANCH_NAME\n\n/* -----------------------------------------------------------------------------------------------*/\n\nexport type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>\nexport type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>\n\n/**\n * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`\n * to mimic layer dismissing behaviour present in OS.\n * Returns props to pass to the node we want to check for outside events.\n */\nfunction usePointerDownOutside(onPointerDownOutside?: (event: PointerDownOutsideEvent) => void) {\n const handlePointerDownOutside = useEvent(onPointerDownOutside) as EventListener\n const isPointerInsideReactTreeRef = React.useRef(false)\n const handleClickRef = React.useRef(() => {})\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n\n function handleAndDispatchPointerDownOutsideEvent() {\n handleAndDispatchCustomEvent(\n POINTER_DOWN_OUTSIDE,\n handlePointerDownOutside,\n eventDetail,\n { discrete: true }\n )\n }\n\n /**\n * On touch devices, we need to wait for a click event because browsers implement\n * a ~350ms delay between the time the user stops touching the display and when the\n * browser executres events. We need to ensure we don't reactivate pointer-events within\n * this timeframe otherwise the browser may execute events that should have been prevented.\n *\n * Additionally, this also lets us deal automatically with cancellations when a click event\n * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.\n *\n * This is why we also continuously remove the previous listener, because we cannot be\n * certain that it was raised, and therefore cleaned-up.\n */\n if (event.pointerType === 'touch') {\n document.removeEventListener('click', handleClickRef.current)\n handleClickRef.current = handleAndDispatchPointerDownOutsideEvent\n document.addEventListener('click', handleClickRef.current, { once: true })\n } else {\n handleAndDispatchPointerDownOutsideEvent()\n }\n }\n isPointerInsideReactTreeRef.current = false\n }\n /**\n * if this hook executes in a component that mounts via a `pointerdown` event, the event\n * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid\n * this by delaying the event listener registration on the document.\n * This is not React specific, but rather how the DOM works, ie:\n * ```\n * button.addEventListener('pointerdown', () => {\n * console.log('I will log');\n * document.addEventListener('pointerdown', () => {\n * console.log('I will also log');\n * })\n * });\n */\n const timerId = window.setTimeout(() => {\n document.addEventListener('pointerdown', handlePointerDown)\n }, 0)\n return () => {\n window.clearTimeout(timerId)\n document.removeEventListener('pointerdown', handlePointerDown)\n document.removeEventListener('click', handleClickRef.current)\n }\n }, [handlePointerDownOutside])\n\n return {\n // ensures we check React component tree (not just DOM tree)\n onPointerDownCapture: () => (isPointerInsideReactTreeRef.current = true),\n }\n}\n\n/**\n * Listens for when focus happens outside a react subtree.\n * Returns props to pass to the root (node) of the subtree we want to check.\n */\nfunction useFocusOutside(onFocusOutside?: (event: FocusOutsideEvent) => void) {\n const handleFocusOutside = useEvent(onFocusOutside) as EventListener\n const isFocusInsideReactTreeRef = React.useRef(false)\n\n React.useEffect(() => {\n const handleFocus = (event: FocusEvent) => {\n if (event.target && !isFocusInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {\n discrete: false,\n })\n }\n }\n document.addEventListener('focusin', handleFocus)\n return () => document.removeEventListener('focusin', handleFocus)\n }, [handleFocusOutside])\n\n return {\n onFocusCapture: () => (isFocusInsideReactTreeRef.current = true),\n onBlurCapture: () => (isFocusInsideReactTreeRef.current = false),\n }\n}\n\nfunction dispatchUpdate() {\n const event = new CustomEvent(CONTEXT_UPDATE)\n document.dispatchEvent(event)\n}\n\nfunction handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent extends Event>(\n name: string,\n handler: ((event: E) => void) | undefined,\n detail: { originalEvent: OriginalEvent } & (E extends CustomEvent<infer D> ? D : never),\n { discrete }: { discrete: boolean }\n) {\n const target = detail.originalEvent.target\n const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail })\n if (handler) target.addEventListener(name, handler as EventListener, { once: true })\n\n if (discrete) {\n dispatchDiscreteCustomEvent(target, event)\n } else {\n target.dispatchEvent(event)\n }\n}\n\nconst Root = Dismissable\nconst Branch = DismissableBranch\n\nexport {\n Dismissable,\n DismissableBranch,\n //\n Root,\n Branch,\n}\n\nexport type { DismissableProps }\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["// forked from radix-ui\n// https://github.com/radix-ui/primitives/blob/cfd8dcba5fa6a0e751486af418d05a7b88a7f541/packages/react/dismissable-layer/src/DismissableLayer.tsx#L324\n\nimport { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown'\nimport { useComposedRefs } from '@tamagui/compose-refs'\nimport { composeEventHandlers } from '@tamagui/core'\nimport { useEvent } from '@tamagui/use-event'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { DismissableBranchProps, DismissableProps } from './DismissableProps'\n\nfunction dispatchDiscreteCustomEvent<E extends CustomEvent>(target: E['target'], event: E) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event))\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Dismissable\n * -----------------------------------------------------------------------------------------------*/\n\nconst DISMISSABLE_LAYER_NAME = 'Dismissable'\nconst CONTEXT_UPDATE = 'dismissable.update'\nconst POINTER_DOWN_OUTSIDE = 'dismissable.pointerDownOutside'\nconst FOCUS_OUTSIDE = 'dismissable.focusOutside'\n\nlet originalBodyPointerEvents: string\n\nconst DismissableContext = React.createContext({\n layers: new Set<HTMLDivElement>(),\n layersWithOutsidePointerEventsDisabled: new Set<HTMLDivElement>(),\n branches: new Set<HTMLDivElement>(),\n})\n\nconst Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, forwardedRef) => {\n const {\n disableOutsidePointerEvents = false,\n forceUnmount,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n onDismiss,\n ...layerProps\n } = props\n const context = React.useContext(DismissableContext)\n const [node, setNode] = React.useState<HTMLDivElement | null>(null)\n const [, force] = React.useState({})\n const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node))\n const layers = Array.from(context.layers)\n const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); // prettier-ignore\n const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore\n const index = node ? layers.indexOf(node) : -1\n const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0\n const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex\n\n const pointerDownOutside = usePointerDownOutside((event) => {\n const target = event.target as HTMLDivElement\n const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target))\n if (!isPointerEventsEnabled || isPointerDownOnBranch) return\n onPointerDownOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n const focusOutside = useFocusOutside((event) => {\n const target = event.target as HTMLDivElement\n const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target))\n if (isFocusInBranch) return\n onFocusOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n useEscapeKeydown((event) => {\n const isHighestLayer = index === context.layers.size - 1\n if (!isHighestLayer) return\n onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n })\n\n React.useEffect(() => {\n if (!node) return\n if (disableOutsidePointerEvents) {\n if (context.layersWithOutsidePointerEventsDisabled.size === 0) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n document.body.style.pointerEvents = 'none'\n }\n context.layersWithOutsidePointerEventsDisabled.add(node)\n }\n context.layers.add(node)\n dispatchUpdate()\n return () => {\n if (\n disableOutsidePointerEvents &&\n context.layersWithOutsidePointerEventsDisabled.size === 1\n ) {\n document.body.style.pointerEvents = originalBodyPointerEvents\n }\n }\n }, [node, disableOutsidePointerEvents, context])\n\n /**\n * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect\n * because a change to `disableOutsidePointerEvents` would remove this layer from the stack\n * and add it to the end again so the layering order wouldn't be _creation order_.\n * We only want them to be removed from context stacks when unmounted.\n */\n React.useEffect(() => {\n if (forceUnmount) return\n return () => {\n if (!node) return\n context.layers.delete(node)\n context.layersWithOutsidePointerEventsDisabled.delete(node)\n dispatchUpdate()\n }\n }, [node, context, forceUnmount])\n\n React.useEffect(() => {\n const handleUpdate = () => {\n force({})\n }\n document.addEventListener(CONTEXT_UPDATE, handleUpdate)\n return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate)\n }, [])\n\n return (\n <div\n {...layerProps}\n // @ts-ignore\n ref={composedRefs}\n style={{\n display: 'contents',\n pointerEvents: isBodyPointerEventsDisabled\n ? isPointerEventsEnabled\n ? 'auto'\n : 'none'\n : undefined,\n // @ts-ignore\n ...props.style,\n }}\n onFocusCapture={composeEventHandlers(\n // @ts-ignore\n props.onFocusCapture,\n focusOutside.onFocusCapture\n )}\n onBlurCapture={composeEventHandlers(\n // @ts-ignore\n props.onBlurCapture,\n focusOutside.onBlurCapture\n )}\n // @ts-ignore\n onPointerDownCapture={composeEventHandlers(\n // @ts-ignore\n props.onPointerDownCapture,\n pointerDownOutside.onPointerDownCapture\n )}\n />\n )\n})\n\nDismissable.displayName = DISMISSABLE_LAYER_NAME\n\n/* -------------------------------------------------------------------------------------------------\n * DismissableBranch\n * -----------------------------------------------------------------------------------------------*/\n\nconst BRANCH_NAME = 'DismissableBranch'\n\nconst DismissableBranch = React.forwardRef<HTMLDivElement, DismissableBranchProps>(\n (props, forwardedRef) => {\n const context = React.useContext(DismissableContext)\n const ref = React.useRef<HTMLDivElement>(null)\n const composedRefs = useComposedRefs(forwardedRef, ref)\n\n React.useEffect(() => {\n const node = ref.current\n if (node) {\n context.branches.add(node)\n return () => {\n context.branches.delete(node)\n }\n }\n }, [context.branches])\n\n return <div style={{ display: 'contents' }} {...props} ref={composedRefs} />\n }\n)\n\nDismissableBranch.displayName = BRANCH_NAME\n\n/* -----------------------------------------------------------------------------------------------*/\n\nexport type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>\nexport type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>\n\n/**\n * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`\n * to mimic layer dismissing behaviour present in OS.\n * Returns props to pass to the node we want to check for outside events.\n */\nfunction usePointerDownOutside(onPointerDownOutside?: (event: PointerDownOutsideEvent) => void) {\n const handlePointerDownOutside = useEvent(onPointerDownOutside) as EventListener\n const isPointerInsideReactTreeRef = React.useRef(false)\n const handleClickRef = React.useRef(() => {})\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n\n function handleAndDispatchPointerDownOutsideEvent() {\n handleAndDispatchCustomEvent(\n POINTER_DOWN_OUTSIDE,\n handlePointerDownOutside,\n eventDetail,\n { discrete: true }\n )\n }\n\n /**\n * On touch devices, we need to wait for a click event because browsers implement\n * a ~350ms delay between the time the user stops touching the display and when the\n * browser executres events. We need to ensure we don't reactivate pointer-events within\n * this timeframe otherwise the browser may execute events that should have been prevented.\n *\n * Additionally, this also lets us deal automatically with cancellations when a click event\n * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.\n *\n * This is why we also continuously remove the previous listener, because we cannot be\n * certain that it was raised, and therefore cleaned-up.\n */\n if (event.pointerType === 'touch') {\n document.removeEventListener('click', handleClickRef.current)\n handleClickRef.current = handleAndDispatchPointerDownOutsideEvent\n document.addEventListener('click', handleClickRef.current, { once: true })\n } else {\n handleAndDispatchPointerDownOutsideEvent()\n }\n }\n isPointerInsideReactTreeRef.current = false\n }\n /**\n * if this hook executes in a component that mounts via a `pointerdown` event, the event\n * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid\n * this by delaying the event listener registration on the document.\n * This is not React specific, but rather how the DOM works, ie:\n * ```\n * button.addEventListener('pointerdown', () => {\n * console.log('I will log');\n * document.addEventListener('pointerdown', () => {\n * console.log('I will also log');\n * })\n * });\n */\n const timerId = setTimeout(() => {\n document.addEventListener('pointerdown', handlePointerDown)\n }, 0)\n return () => {\n window.clearTimeout(timerId)\n document.removeEventListener('pointerdown', handlePointerDown)\n document.removeEventListener('click', handleClickRef.current)\n }\n }, [handlePointerDownOutside])\n\n return {\n // ensures we check React component tree (not just DOM tree)\n onPointerDownCapture: () => (isPointerInsideReactTreeRef.current = true),\n }\n}\n\n/**\n * Listens for when focus happens outside a react subtree.\n * Returns props to pass to the root (node) of the subtree we want to check.\n */\nfunction useFocusOutside(onFocusOutside?: (event: FocusOutsideEvent) => void) {\n const handleFocusOutside = useEvent(onFocusOutside) as EventListener\n const isFocusInsideReactTreeRef = React.useRef(false)\n\n React.useEffect(() => {\n const handleFocus = (event: FocusEvent) => {\n if (event.target && !isFocusInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {\n discrete: false,\n })\n }\n }\n document.addEventListener('focusin', handleFocus)\n return () => document.removeEventListener('focusin', handleFocus)\n }, [handleFocusOutside])\n\n return {\n onFocusCapture: () => (isFocusInsideReactTreeRef.current = true),\n onBlurCapture: () => (isFocusInsideReactTreeRef.current = false),\n }\n}\n\nfunction dispatchUpdate() {\n const event = new CustomEvent(CONTEXT_UPDATE)\n document.dispatchEvent(event)\n}\n\nfunction handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent extends Event>(\n name: string,\n handler: ((event: E) => void) | undefined,\n detail: { originalEvent: OriginalEvent } & (E extends CustomEvent<infer D> ? D : never),\n { discrete }: { discrete: boolean }\n) {\n const target = detail.originalEvent.target\n const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail })\n if (handler) target.addEventListener(name, handler as EventListener, { once: true })\n\n if (discrete) {\n dispatchDiscreteCustomEvent(target, event)\n } else {\n target.dispatchEvent(event)\n }\n}\n\nexport { Dismissable, DismissableBranch }\n\nexport type { DismissableProps }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/DismissableProps.tsx"],
|
|
4
|
-
"sourcesContent": ["import React from 'react'\n\nimport { FocusOutsideEvent, PointerDownOutsideEvent } from './Dismissable'\n\nexport interface DismissableProps {\n /**\n * When `true`, hover/focus/click interactions will be disabled on elements outside\n * the `Dismissable`. Users will need to click twice on outside elements to\n * interact with them: once to close the `Dismissable`, and again to trigger the element.\n */\n disableOutsidePointerEvents?: boolean\n /**\n * Event handler called when the escape key is down.\n * Can be prevented.\n */\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n /**\n * Event handler called when the a `pointerdown` event happens outside of the `Dismissable`.\n * Can be prevented.\n */\n onPointerDownOutside?: (event: PointerDownOutsideEvent) => void\n /**\n * Event handler called when the focus moves outside of the `Dismissable`.\n * Can be prevented.\n */\n onFocusOutside?: (event: FocusOutsideEvent) => void\n /**\n * Event handler called when an interaction happens outside the `Dismissable`.\n * Specifically, when a `pointerdown` event happens outside or focus moves outside of it.\n * Can be prevented.\n */\n onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void\n /**\n * Handler called when the `Dismissable` should be dismissed\n */\n onDismiss?: () => void\n\n children?: React.ReactNode\n}\n\nexport interface DismissableBranchProps {\n children?: React.ReactNode\n}\n"],
|
|
4
|
+
"sourcesContent": ["import React from 'react'\n\nimport { FocusOutsideEvent, PointerDownOutsideEvent } from './Dismissable'\n\nexport interface DismissableProps {\n /**\n * When `true`, hover/focus/click interactions will be disabled on elements outside\n * the `Dismissable`. Users will need to click twice on outside elements to\n * interact with them: once to close the `Dismissable`, and again to trigger the element.\n */\n disableOutsidePointerEvents?: boolean\n /**\n * Event handler called when the escape key is down.\n * Can be prevented.\n */\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n /**\n * Event handler called when the a `pointerdown` event happens outside of the `Dismissable`.\n * Can be prevented.\n */\n onPointerDownOutside?: (event: PointerDownOutsideEvent) => void\n /**\n * Event handler called when the focus moves outside of the `Dismissable`.\n * Can be prevented.\n */\n onFocusOutside?: (event: FocusOutsideEvent) => void\n /**\n * Event handler called when an interaction happens outside the `Dismissable`.\n * Specifically, when a `pointerdown` event happens outside or focus moves outside of it.\n * Can be prevented.\n */\n onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void\n /**\n * Handler called when the `Dismissable` should be dismissed\n */\n onDismiss?: () => void\n\n /**\n * When using animations on exit, may want to simualte force unmount early\n */\n forceUnmount?: boolean\n\n children?: React.ReactNode\n}\n\nexport interface DismissableBranchProps {\n children?: React.ReactNode\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/esm/Dismissable.js
CHANGED
|
@@ -21,6 +21,7 @@ const DismissableContext = React.createContext({
|
|
|
21
21
|
const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
22
22
|
const {
|
|
23
23
|
disableOutsidePointerEvents = false,
|
|
24
|
+
forceUnmount,
|
|
24
25
|
onEscapeKeyDown,
|
|
25
26
|
onPointerDownOutside,
|
|
26
27
|
onFocusOutside,
|
|
@@ -87,6 +88,8 @@ const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
|
87
88
|
};
|
|
88
89
|
}, [node, disableOutsidePointerEvents, context]);
|
|
89
90
|
React.useEffect(() => {
|
|
91
|
+
if (forceUnmount)
|
|
92
|
+
return;
|
|
90
93
|
return () => {
|
|
91
94
|
if (!node)
|
|
92
95
|
return;
|
|
@@ -94,9 +97,11 @@ const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
|
94
97
|
context.layersWithOutsidePointerEventsDisabled.delete(node);
|
|
95
98
|
dispatchUpdate();
|
|
96
99
|
};
|
|
97
|
-
}, [node, context]);
|
|
100
|
+
}, [node, context, forceUnmount]);
|
|
98
101
|
React.useEffect(() => {
|
|
99
|
-
const handleUpdate = () =>
|
|
102
|
+
const handleUpdate = () => {
|
|
103
|
+
force({});
|
|
104
|
+
};
|
|
100
105
|
document.addEventListener(CONTEXT_UPDATE, handleUpdate);
|
|
101
106
|
return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate);
|
|
102
107
|
}, []);
|
|
@@ -158,7 +163,7 @@ function usePointerDownOutside(onPointerDownOutside) {
|
|
|
158
163
|
}
|
|
159
164
|
isPointerInsideReactTreeRef.current = false;
|
|
160
165
|
};
|
|
161
|
-
const timerId =
|
|
166
|
+
const timerId = setTimeout(() => {
|
|
162
167
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
163
168
|
}, 0);
|
|
164
169
|
return () => {
|
|
@@ -206,12 +211,8 @@ function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
|
|
|
206
211
|
target.dispatchEvent(event);
|
|
207
212
|
}
|
|
208
213
|
}
|
|
209
|
-
const Root = Dismissable;
|
|
210
|
-
const Branch = DismissableBranch;
|
|
211
214
|
export {
|
|
212
|
-
Branch,
|
|
213
215
|
Dismissable,
|
|
214
|
-
DismissableBranch
|
|
215
|
-
Root
|
|
216
|
+
DismissableBranch
|
|
216
217
|
};
|
|
217
218
|
//# sourceMappingURL=Dismissable.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/Dismissable.tsx"],
|
|
4
|
-
"sourcesContent": ["// forked from radix-ui\n// https://github.com/radix-ui/primitives/blob/cfd8dcba5fa6a0e751486af418d05a7b88a7f541/packages/react/dismissable-layer/src/DismissableLayer.tsx#L324\n\nimport { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown'\nimport { useComposedRefs } from '@tamagui/compose-refs'\nimport { composeEventHandlers } from '@tamagui/core'\nimport { useEvent } from '@tamagui/use-event'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { DismissableBranchProps, DismissableProps } from './DismissableProps'\n\nfunction dispatchDiscreteCustomEvent<E extends CustomEvent>(target: E['target'], event: E) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event))\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Dismissable\n * -----------------------------------------------------------------------------------------------*/\n\nconst DISMISSABLE_LAYER_NAME = 'Dismissable'\nconst CONTEXT_UPDATE = 'dismissable.update'\nconst POINTER_DOWN_OUTSIDE = 'dismissable.pointerDownOutside'\nconst FOCUS_OUTSIDE = 'dismissable.focusOutside'\n\nlet originalBodyPointerEvents: string\n\nconst DismissableContext = React.createContext({\n layers: new Set<HTMLDivElement>(),\n layersWithOutsidePointerEventsDisabled: new Set<HTMLDivElement>(),\n branches: new Set<HTMLDivElement>(),\n})\n\nconst Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, forwardedRef) => {\n const {\n disableOutsidePointerEvents = false,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n onDismiss,\n ...layerProps\n } = props\n const context = React.useContext(DismissableContext)\n const [node, setNode] = React.useState<HTMLDivElement | null>(null)\n const [, force] = React.useState({})\n const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node))\n const layers = Array.from(context.layers)\n const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); // prettier-ignore\n const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore\n const index = node ? layers.indexOf(node) : -1\n const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0\n const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex\n\n const pointerDownOutside = usePointerDownOutside((event) => {\n const target = event.target as HTMLDivElement\n const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target))\n if (!isPointerEventsEnabled || isPointerDownOnBranch) return\n onPointerDownOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n const focusOutside = useFocusOutside((event) => {\n const target = event.target as HTMLDivElement\n const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target))\n if (isFocusInBranch) return\n onFocusOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n useEscapeKeydown((event) => {\n const isHighestLayer = index === context.layers.size - 1\n if (!isHighestLayer) return\n onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n })\n\n React.useEffect(() => {\n if (!node) return\n if (disableOutsidePointerEvents) {\n if (context.layersWithOutsidePointerEventsDisabled.size === 0) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n document.body.style.pointerEvents = 'none'\n }\n context.layersWithOutsidePointerEventsDisabled.add(node)\n }\n context.layers.add(node)\n dispatchUpdate()\n return () => {\n if (\n disableOutsidePointerEvents &&\n context.layersWithOutsidePointerEventsDisabled.size === 1\n ) {\n document.body.style.pointerEvents = originalBodyPointerEvents\n }\n }\n }, [node, disableOutsidePointerEvents, context])\n\n /**\n * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect\n * because a change to `disableOutsidePointerEvents` would remove this layer from the stack\n * and add it to the end again so the layering order wouldn't be _creation order_.\n * We only want them to be removed from context stacks when unmounted.\n */\n React.useEffect(() => {\n return () => {\n if (!node) return\n context.layers.delete(node)\n context.layersWithOutsidePointerEventsDisabled.delete(node)\n dispatchUpdate()\n }\n }, [node, context])\n\n React.useEffect(() => {\n const handleUpdate = () => force({})\n document.addEventListener(CONTEXT_UPDATE, handleUpdate)\n return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate)\n }, [])\n\n return (\n <div\n {...layerProps}\n // @ts-ignore\n ref={composedRefs}\n style={{\n display: 'contents',\n pointerEvents: isBodyPointerEventsDisabled\n ? isPointerEventsEnabled\n ? 'auto'\n : 'none'\n : undefined,\n // @ts-ignore\n ...props.style,\n }}\n onFocusCapture={composeEventHandlers(\n // @ts-ignore\n props.onFocusCapture,\n focusOutside.onFocusCapture\n )}\n onBlurCapture={composeEventHandlers(\n // @ts-ignore\n props.onBlurCapture,\n focusOutside.onBlurCapture\n )}\n // @ts-ignore\n onPointerDownCapture={composeEventHandlers(\n // @ts-ignore\n props.onPointerDownCapture,\n pointerDownOutside.onPointerDownCapture\n )}\n />\n )\n})\n\nDismissable.displayName = DISMISSABLE_LAYER_NAME\n\n/* -------------------------------------------------------------------------------------------------\n * DismissableBranch\n * -----------------------------------------------------------------------------------------------*/\n\nconst BRANCH_NAME = 'DismissableBranch'\n\nconst DismissableBranch = React.forwardRef<HTMLDivElement, DismissableBranchProps>(\n (props, forwardedRef) => {\n const context = React.useContext(DismissableContext)\n const ref = React.useRef<HTMLDivElement>(null)\n const composedRefs = useComposedRefs(forwardedRef, ref)\n\n React.useEffect(() => {\n const node = ref.current\n if (node) {\n context.branches.add(node)\n return () => {\n context.branches.delete(node)\n }\n }\n }, [context.branches])\n\n return <div style={{ display: 'contents' }} {...props} ref={composedRefs} />\n }\n)\n\nDismissableBranch.displayName = BRANCH_NAME\n\n/* -----------------------------------------------------------------------------------------------*/\n\nexport type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>\nexport type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>\n\n/**\n * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`\n * to mimic layer dismissing behaviour present in OS.\n * Returns props to pass to the node we want to check for outside events.\n */\nfunction usePointerDownOutside(onPointerDownOutside?: (event: PointerDownOutsideEvent) => void) {\n const handlePointerDownOutside = useEvent(onPointerDownOutside) as EventListener\n const isPointerInsideReactTreeRef = React.useRef(false)\n const handleClickRef = React.useRef(() => {})\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n\n function handleAndDispatchPointerDownOutsideEvent() {\n handleAndDispatchCustomEvent(\n POINTER_DOWN_OUTSIDE,\n handlePointerDownOutside,\n eventDetail,\n { discrete: true }\n )\n }\n\n /**\n * On touch devices, we need to wait for a click event because browsers implement\n * a ~350ms delay between the time the user stops touching the display and when the\n * browser executres events. We need to ensure we don't reactivate pointer-events within\n * this timeframe otherwise the browser may execute events that should have been prevented.\n *\n * Additionally, this also lets us deal automatically with cancellations when a click event\n * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.\n *\n * This is why we also continuously remove the previous listener, because we cannot be\n * certain that it was raised, and therefore cleaned-up.\n */\n if (event.pointerType === 'touch') {\n document.removeEventListener('click', handleClickRef.current)\n handleClickRef.current = handleAndDispatchPointerDownOutsideEvent\n document.addEventListener('click', handleClickRef.current, { once: true })\n } else {\n handleAndDispatchPointerDownOutsideEvent()\n }\n }\n isPointerInsideReactTreeRef.current = false\n }\n /**\n * if this hook executes in a component that mounts via a `pointerdown` event, the event\n * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid\n * this by delaying the event listener registration on the document.\n * This is not React specific, but rather how the DOM works, ie:\n * ```\n * button.addEventListener('pointerdown', () => {\n * console.log('I will log');\n * document.addEventListener('pointerdown', () => {\n * console.log('I will also log');\n * })\n * });\n */\n const timerId = window.setTimeout(() => {\n document.addEventListener('pointerdown', handlePointerDown)\n }, 0)\n return () => {\n window.clearTimeout(timerId)\n document.removeEventListener('pointerdown', handlePointerDown)\n document.removeEventListener('click', handleClickRef.current)\n }\n }, [handlePointerDownOutside])\n\n return {\n // ensures we check React component tree (not just DOM tree)\n onPointerDownCapture: () => (isPointerInsideReactTreeRef.current = true),\n }\n}\n\n/**\n * Listens for when focus happens outside a react subtree.\n * Returns props to pass to the root (node) of the subtree we want to check.\n */\nfunction useFocusOutside(onFocusOutside?: (event: FocusOutsideEvent) => void) {\n const handleFocusOutside = useEvent(onFocusOutside) as EventListener\n const isFocusInsideReactTreeRef = React.useRef(false)\n\n React.useEffect(() => {\n const handleFocus = (event: FocusEvent) => {\n if (event.target && !isFocusInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {\n discrete: false,\n })\n }\n }\n document.addEventListener('focusin', handleFocus)\n return () => document.removeEventListener('focusin', handleFocus)\n }, [handleFocusOutside])\n\n return {\n onFocusCapture: () => (isFocusInsideReactTreeRef.current = true),\n onBlurCapture: () => (isFocusInsideReactTreeRef.current = false),\n }\n}\n\nfunction dispatchUpdate() {\n const event = new CustomEvent(CONTEXT_UPDATE)\n document.dispatchEvent(event)\n}\n\nfunction handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent extends Event>(\n name: string,\n handler: ((event: E) => void) | undefined,\n detail: { originalEvent: OriginalEvent } & (E extends CustomEvent<infer D> ? D : never),\n { discrete }: { discrete: boolean }\n) {\n const target = detail.originalEvent.target\n const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail })\n if (handler) target.addEventListener(name, handler as EventListener, { once: true })\n\n if (discrete) {\n dispatchDiscreteCustomEvent(target, event)\n } else {\n target.dispatchEvent(event)\n }\n}\n\nconst Root = Dismissable\nconst Branch = DismissableBranch\n\nexport {\n Dismissable,\n DismissableBranch,\n //\n Root,\n Branch,\n}\n\nexport type { DismissableProps }\n"],
|
|
5
|
-
"mappings": "AAGA;AACA;AACA;AACA;AACA;AACA;AAIA,qCAA4D,QAAqB,OAAU;AACzF,MAAI;AAAQ,aAAS,UAAU,MAAM,OAAO,cAAc,KAAK,CAAC;AAClE;AAMA,MAAM,yBAAyB;AAC/B,MAAM,iBAAiB;AACvB,MAAM,uBAAuB;AAC7B,MAAM,gBAAgB;AAEtB,IAAI;AAEJ,MAAM,qBAAqB,MAAM,cAAc;AAAA,EAC7C,QAAQ,oBAAI,IAAoB;AAAA,EAChC,wCAAwC,oBAAI,IAAoB;AAAA,EAChE,UAAU,oBAAI,IAAoB;AACpC,CAAC;AAED,MAAM,cAAc,MAAM,WAA6C,CAAC,OAAO,iBAAiB;AAC9F,QAAM;AAAA,IACJ,8BAA8B;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,OACG;AAAA,MACD;AACJ,QAAM,UAAU,MAAM,WAAW,kBAAkB;AACnD,QAAM,CAAC,MAAM,WAAW,MAAM,SAAgC,IAAI;AAClE,QAAM,CAAC,EAAE,SAAS,MAAM,SAAS,CAAC,CAAC;AACnC,QAAM,eAAe,gBAAgB,cAAc,CAAC,UAAS,QAAQ,KAAI,CAAC;AAC1E,QAAM,SAAS,MAAM,KAAK,QAAQ,MAAM;AACxC,QAAM,CAAC,gDAAgD,CAAC,GAAG,QAAQ,sCAAsC,EAAE,MAAM,EAAE;AACnH,QAAM,oDAAoD,OAAO,QAAQ,4CAA4C;AACrH,QAAM,QAAQ,OAAO,OAAO,QAAQ,IAAI,IAAI;AAC5C,QAAM,8BAA8B,QAAQ,uCAAuC,OAAO;AAC1F,QAAM,yBAAyB,SAAS;AAExC,QAAM,qBAAqB,sBAAsB,CAAC,UAAU;AAC1D,UAAM,SAAS,MAAM;AACrB,UAAM,wBAAwB,CAAC,GAAG,QAAQ,QAAQ,EAAE,KAAK,CAAC,WAAW,OAAO,SAAS,MAAM,CAAC;AAC5F,QAAI,CAAC,0BAA0B;AAAuB;AACtD,iEAAuB;AACvB,2DAAoB;AACpB,QAAI,CAAC,MAAM;AAAkB;AAAA,EAC/B,CAAC;AAED,QAAM,eAAe,gBAAgB,CAAC,UAAU;AAC9C,UAAM,SAAS,MAAM;AACrB,UAAM,kBAAkB,CAAC,GAAG,QAAQ,QAAQ,EAAE,KAAK,CAAC,WAAW,OAAO,SAAS,MAAM,CAAC;AACtF,QAAI;AAAiB;AACrB,qDAAiB;AACjB,2DAAoB;AACpB,QAAI,CAAC,MAAM;AAAkB;AAAA,EAC/B,CAAC;AAED,mBAAiB,CAAC,UAAU;AAC1B,UAAM,iBAAiB,UAAU,QAAQ,OAAO,OAAO;AACvD,QAAI,CAAC;AAAgB;AACrB,uDAAkB;AAClB,QAAI,CAAC,MAAM,oBAAoB,WAAW;AACxC,YAAM,eAAe;AACrB,gBAAU;AAAA,IACZ;AAAA,EACF,CAAC;AAED,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC;AAAM;AACX,QAAI,6BAA6B;AAC/B,UAAI,QAAQ,uCAAuC,SAAS,GAAG;AAC7D,oCAA4B,SAAS,KAAK,MAAM;AAChD,iBAAS,KAAK,MAAM,gBAAgB;AAAA,MACtC;AACA,cAAQ,uCAAuC,IAAI,IAAI;AAAA,IACzD;AACA,YAAQ,OAAO,IAAI,IAAI;AACvB,mBAAe;AACf,WAAO,MAAM;AACX,UACE,+BACA,QAAQ,uCAAuC,SAAS,GACxD;AACA,iBAAS,KAAK,MAAM,gBAAgB;AAAA,MACtC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,6BAA6B,OAAO,CAAC;AAQ/C,QAAM,UAAU,MAAM;AACpB,WAAO,MAAM;AACX,UAAI,CAAC;AAAM;AACX,cAAQ,OAAO,OAAO,IAAI;AAC1B,cAAQ,uCAAuC,OAAO,IAAI;AAC1D,qBAAe;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,MAAM,
|
|
4
|
+
"sourcesContent": ["// forked from radix-ui\n// https://github.com/radix-ui/primitives/blob/cfd8dcba5fa6a0e751486af418d05a7b88a7f541/packages/react/dismissable-layer/src/DismissableLayer.tsx#L324\n\nimport { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown'\nimport { useComposedRefs } from '@tamagui/compose-refs'\nimport { composeEventHandlers } from '@tamagui/core'\nimport { useEvent } from '@tamagui/use-event'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { DismissableBranchProps, DismissableProps } from './DismissableProps'\n\nfunction dispatchDiscreteCustomEvent<E extends CustomEvent>(target: E['target'], event: E) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event))\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Dismissable\n * -----------------------------------------------------------------------------------------------*/\n\nconst DISMISSABLE_LAYER_NAME = 'Dismissable'\nconst CONTEXT_UPDATE = 'dismissable.update'\nconst POINTER_DOWN_OUTSIDE = 'dismissable.pointerDownOutside'\nconst FOCUS_OUTSIDE = 'dismissable.focusOutside'\n\nlet originalBodyPointerEvents: string\n\nconst DismissableContext = React.createContext({\n layers: new Set<HTMLDivElement>(),\n layersWithOutsidePointerEventsDisabled: new Set<HTMLDivElement>(),\n branches: new Set<HTMLDivElement>(),\n})\n\nconst Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, forwardedRef) => {\n const {\n disableOutsidePointerEvents = false,\n forceUnmount,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n onDismiss,\n ...layerProps\n } = props\n const context = React.useContext(DismissableContext)\n const [node, setNode] = React.useState<HTMLDivElement | null>(null)\n const [, force] = React.useState({})\n const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node))\n const layers = Array.from(context.layers)\n const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); // prettier-ignore\n const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore\n const index = node ? layers.indexOf(node) : -1\n const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0\n const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex\n\n const pointerDownOutside = usePointerDownOutside((event) => {\n const target = event.target as HTMLDivElement\n const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target))\n if (!isPointerEventsEnabled || isPointerDownOnBranch) return\n onPointerDownOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n const focusOutside = useFocusOutside((event) => {\n const target = event.target as HTMLDivElement\n const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target))\n if (isFocusInBranch) return\n onFocusOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n useEscapeKeydown((event) => {\n const isHighestLayer = index === context.layers.size - 1\n if (!isHighestLayer) return\n onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n })\n\n React.useEffect(() => {\n if (!node) return\n if (disableOutsidePointerEvents) {\n if (context.layersWithOutsidePointerEventsDisabled.size === 0) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n document.body.style.pointerEvents = 'none'\n }\n context.layersWithOutsidePointerEventsDisabled.add(node)\n }\n context.layers.add(node)\n dispatchUpdate()\n return () => {\n if (\n disableOutsidePointerEvents &&\n context.layersWithOutsidePointerEventsDisabled.size === 1\n ) {\n document.body.style.pointerEvents = originalBodyPointerEvents\n }\n }\n }, [node, disableOutsidePointerEvents, context])\n\n /**\n * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect\n * because a change to `disableOutsidePointerEvents` would remove this layer from the stack\n * and add it to the end again so the layering order wouldn't be _creation order_.\n * We only want them to be removed from context stacks when unmounted.\n */\n React.useEffect(() => {\n if (forceUnmount) return\n return () => {\n if (!node) return\n context.layers.delete(node)\n context.layersWithOutsidePointerEventsDisabled.delete(node)\n dispatchUpdate()\n }\n }, [node, context, forceUnmount])\n\n React.useEffect(() => {\n const handleUpdate = () => {\n force({})\n }\n document.addEventListener(CONTEXT_UPDATE, handleUpdate)\n return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate)\n }, [])\n\n return (\n <div\n {...layerProps}\n // @ts-ignore\n ref={composedRefs}\n style={{\n display: 'contents',\n pointerEvents: isBodyPointerEventsDisabled\n ? isPointerEventsEnabled\n ? 'auto'\n : 'none'\n : undefined,\n // @ts-ignore\n ...props.style,\n }}\n onFocusCapture={composeEventHandlers(\n // @ts-ignore\n props.onFocusCapture,\n focusOutside.onFocusCapture\n )}\n onBlurCapture={composeEventHandlers(\n // @ts-ignore\n props.onBlurCapture,\n focusOutside.onBlurCapture\n )}\n // @ts-ignore\n onPointerDownCapture={composeEventHandlers(\n // @ts-ignore\n props.onPointerDownCapture,\n pointerDownOutside.onPointerDownCapture\n )}\n />\n )\n})\n\nDismissable.displayName = DISMISSABLE_LAYER_NAME\n\n/* -------------------------------------------------------------------------------------------------\n * DismissableBranch\n * -----------------------------------------------------------------------------------------------*/\n\nconst BRANCH_NAME = 'DismissableBranch'\n\nconst DismissableBranch = React.forwardRef<HTMLDivElement, DismissableBranchProps>(\n (props, forwardedRef) => {\n const context = React.useContext(DismissableContext)\n const ref = React.useRef<HTMLDivElement>(null)\n const composedRefs = useComposedRefs(forwardedRef, ref)\n\n React.useEffect(() => {\n const node = ref.current\n if (node) {\n context.branches.add(node)\n return () => {\n context.branches.delete(node)\n }\n }\n }, [context.branches])\n\n return <div style={{ display: 'contents' }} {...props} ref={composedRefs} />\n }\n)\n\nDismissableBranch.displayName = BRANCH_NAME\n\n/* -----------------------------------------------------------------------------------------------*/\n\nexport type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>\nexport type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>\n\n/**\n * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`\n * to mimic layer dismissing behaviour present in OS.\n * Returns props to pass to the node we want to check for outside events.\n */\nfunction usePointerDownOutside(onPointerDownOutside?: (event: PointerDownOutsideEvent) => void) {\n const handlePointerDownOutside = useEvent(onPointerDownOutside) as EventListener\n const isPointerInsideReactTreeRef = React.useRef(false)\n const handleClickRef = React.useRef(() => {})\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n\n function handleAndDispatchPointerDownOutsideEvent() {\n handleAndDispatchCustomEvent(\n POINTER_DOWN_OUTSIDE,\n handlePointerDownOutside,\n eventDetail,\n { discrete: true }\n )\n }\n\n /**\n * On touch devices, we need to wait for a click event because browsers implement\n * a ~350ms delay between the time the user stops touching the display and when the\n * browser executres events. We need to ensure we don't reactivate pointer-events within\n * this timeframe otherwise the browser may execute events that should have been prevented.\n *\n * Additionally, this also lets us deal automatically with cancellations when a click event\n * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.\n *\n * This is why we also continuously remove the previous listener, because we cannot be\n * certain that it was raised, and therefore cleaned-up.\n */\n if (event.pointerType === 'touch') {\n document.removeEventListener('click', handleClickRef.current)\n handleClickRef.current = handleAndDispatchPointerDownOutsideEvent\n document.addEventListener('click', handleClickRef.current, { once: true })\n } else {\n handleAndDispatchPointerDownOutsideEvent()\n }\n }\n isPointerInsideReactTreeRef.current = false\n }\n /**\n * if this hook executes in a component that mounts via a `pointerdown` event, the event\n * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid\n * this by delaying the event listener registration on the document.\n * This is not React specific, but rather how the DOM works, ie:\n * ```\n * button.addEventListener('pointerdown', () => {\n * console.log('I will log');\n * document.addEventListener('pointerdown', () => {\n * console.log('I will also log');\n * })\n * });\n */\n const timerId = setTimeout(() => {\n document.addEventListener('pointerdown', handlePointerDown)\n }, 0)\n return () => {\n window.clearTimeout(timerId)\n document.removeEventListener('pointerdown', handlePointerDown)\n document.removeEventListener('click', handleClickRef.current)\n }\n }, [handlePointerDownOutside])\n\n return {\n // ensures we check React component tree (not just DOM tree)\n onPointerDownCapture: () => (isPointerInsideReactTreeRef.current = true),\n }\n}\n\n/**\n * Listens for when focus happens outside a react subtree.\n * Returns props to pass to the root (node) of the subtree we want to check.\n */\nfunction useFocusOutside(onFocusOutside?: (event: FocusOutsideEvent) => void) {\n const handleFocusOutside = useEvent(onFocusOutside) as EventListener\n const isFocusInsideReactTreeRef = React.useRef(false)\n\n React.useEffect(() => {\n const handleFocus = (event: FocusEvent) => {\n if (event.target && !isFocusInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {\n discrete: false,\n })\n }\n }\n document.addEventListener('focusin', handleFocus)\n return () => document.removeEventListener('focusin', handleFocus)\n }, [handleFocusOutside])\n\n return {\n onFocusCapture: () => (isFocusInsideReactTreeRef.current = true),\n onBlurCapture: () => (isFocusInsideReactTreeRef.current = false),\n }\n}\n\nfunction dispatchUpdate() {\n const event = new CustomEvent(CONTEXT_UPDATE)\n document.dispatchEvent(event)\n}\n\nfunction handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent extends Event>(\n name: string,\n handler: ((event: E) => void) | undefined,\n detail: { originalEvent: OriginalEvent } & (E extends CustomEvent<infer D> ? D : never),\n { discrete }: { discrete: boolean }\n) {\n const target = detail.originalEvent.target\n const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail })\n if (handler) target.addEventListener(name, handler as EventListener, { once: true })\n\n if (discrete) {\n dispatchDiscreteCustomEvent(target, event)\n } else {\n target.dispatchEvent(event)\n }\n}\n\nexport { Dismissable, DismissableBranch }\n\nexport type { DismissableProps }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/jsx/Dismissable.js
CHANGED
|
@@ -21,6 +21,7 @@ const DismissableContext = React.createContext({
|
|
|
21
21
|
const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
22
22
|
const {
|
|
23
23
|
disableOutsidePointerEvents = false,
|
|
24
|
+
forceUnmount,
|
|
24
25
|
onEscapeKeyDown,
|
|
25
26
|
onPointerDownOutside,
|
|
26
27
|
onFocusOutside,
|
|
@@ -87,6 +88,8 @@ const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
|
87
88
|
};
|
|
88
89
|
}, [node, disableOutsidePointerEvents, context]);
|
|
89
90
|
React.useEffect(() => {
|
|
91
|
+
if (forceUnmount)
|
|
92
|
+
return;
|
|
90
93
|
return () => {
|
|
91
94
|
if (!node)
|
|
92
95
|
return;
|
|
@@ -94,9 +97,11 @@ const Dismissable = React.forwardRef((props, forwardedRef) => {
|
|
|
94
97
|
context.layersWithOutsidePointerEventsDisabled.delete(node);
|
|
95
98
|
dispatchUpdate();
|
|
96
99
|
};
|
|
97
|
-
}, [node, context]);
|
|
100
|
+
}, [node, context, forceUnmount]);
|
|
98
101
|
React.useEffect(() => {
|
|
99
|
-
const handleUpdate = () =>
|
|
102
|
+
const handleUpdate = () => {
|
|
103
|
+
force({});
|
|
104
|
+
};
|
|
100
105
|
document.addEventListener(CONTEXT_UPDATE, handleUpdate);
|
|
101
106
|
return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate);
|
|
102
107
|
}, []);
|
|
@@ -147,7 +152,7 @@ function usePointerDownOutside(onPointerDownOutside) {
|
|
|
147
152
|
}
|
|
148
153
|
isPointerInsideReactTreeRef.current = false;
|
|
149
154
|
};
|
|
150
|
-
const timerId =
|
|
155
|
+
const timerId = setTimeout(() => {
|
|
151
156
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
152
157
|
}, 0);
|
|
153
158
|
return () => {
|
|
@@ -195,12 +200,8 @@ function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
|
|
|
195
200
|
target.dispatchEvent(event);
|
|
196
201
|
}
|
|
197
202
|
}
|
|
198
|
-
const Root = Dismissable;
|
|
199
|
-
const Branch = DismissableBranch;
|
|
200
203
|
export {
|
|
201
|
-
Branch,
|
|
202
204
|
Dismissable,
|
|
203
|
-
DismissableBranch
|
|
204
|
-
Root
|
|
205
|
+
DismissableBranch
|
|
205
206
|
};
|
|
206
207
|
//# sourceMappingURL=Dismissable.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/Dismissable.tsx"],
|
|
4
|
-
"sourcesContent": ["// forked from radix-ui\n// https://github.com/radix-ui/primitives/blob/cfd8dcba5fa6a0e751486af418d05a7b88a7f541/packages/react/dismissable-layer/src/DismissableLayer.tsx#L324\n\nimport { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown'\nimport { useComposedRefs } from '@tamagui/compose-refs'\nimport { composeEventHandlers } from '@tamagui/core'\nimport { useEvent } from '@tamagui/use-event'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { DismissableBranchProps, DismissableProps } from './DismissableProps'\n\nfunction dispatchDiscreteCustomEvent<E extends CustomEvent>(target: E['target'], event: E) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event))\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Dismissable\n * -----------------------------------------------------------------------------------------------*/\n\nconst DISMISSABLE_LAYER_NAME = 'Dismissable'\nconst CONTEXT_UPDATE = 'dismissable.update'\nconst POINTER_DOWN_OUTSIDE = 'dismissable.pointerDownOutside'\nconst FOCUS_OUTSIDE = 'dismissable.focusOutside'\n\nlet originalBodyPointerEvents: string\n\nconst DismissableContext = React.createContext({\n layers: new Set<HTMLDivElement>(),\n layersWithOutsidePointerEventsDisabled: new Set<HTMLDivElement>(),\n branches: new Set<HTMLDivElement>(),\n})\n\nconst Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, forwardedRef) => {\n const {\n disableOutsidePointerEvents = false,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n onDismiss,\n ...layerProps\n } = props\n const context = React.useContext(DismissableContext)\n const [node, setNode] = React.useState<HTMLDivElement | null>(null)\n const [, force] = React.useState({})\n const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node))\n const layers = Array.from(context.layers)\n const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); // prettier-ignore\n const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore\n const index = node ? layers.indexOf(node) : -1\n const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0\n const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex\n\n const pointerDownOutside = usePointerDownOutside((event) => {\n const target = event.target as HTMLDivElement\n const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target))\n if (!isPointerEventsEnabled || isPointerDownOnBranch) return\n onPointerDownOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n const focusOutside = useFocusOutside((event) => {\n const target = event.target as HTMLDivElement\n const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target))\n if (isFocusInBranch) return\n onFocusOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n useEscapeKeydown((event) => {\n const isHighestLayer = index === context.layers.size - 1\n if (!isHighestLayer) return\n onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n })\n\n React.useEffect(() => {\n if (!node) return\n if (disableOutsidePointerEvents) {\n if (context.layersWithOutsidePointerEventsDisabled.size === 0) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n document.body.style.pointerEvents = 'none'\n }\n context.layersWithOutsidePointerEventsDisabled.add(node)\n }\n context.layers.add(node)\n dispatchUpdate()\n return () => {\n if (\n disableOutsidePointerEvents &&\n context.layersWithOutsidePointerEventsDisabled.size === 1\n ) {\n document.body.style.pointerEvents = originalBodyPointerEvents\n }\n }\n }, [node, disableOutsidePointerEvents, context])\n\n /**\n * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect\n * because a change to `disableOutsidePointerEvents` would remove this layer from the stack\n * and add it to the end again so the layering order wouldn't be _creation order_.\n * We only want them to be removed from context stacks when unmounted.\n */\n React.useEffect(() => {\n return () => {\n if (!node) return\n context.layers.delete(node)\n context.layersWithOutsidePointerEventsDisabled.delete(node)\n dispatchUpdate()\n }\n }, [node, context])\n\n React.useEffect(() => {\n const handleUpdate = () => force({})\n document.addEventListener(CONTEXT_UPDATE, handleUpdate)\n return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate)\n }, [])\n\n return (\n <div\n {...layerProps}\n // @ts-ignore\n ref={composedRefs}\n style={{\n display: 'contents',\n pointerEvents: isBodyPointerEventsDisabled\n ? isPointerEventsEnabled\n ? 'auto'\n : 'none'\n : undefined,\n // @ts-ignore\n ...props.style,\n }}\n onFocusCapture={composeEventHandlers(\n // @ts-ignore\n props.onFocusCapture,\n focusOutside.onFocusCapture\n )}\n onBlurCapture={composeEventHandlers(\n // @ts-ignore\n props.onBlurCapture,\n focusOutside.onBlurCapture\n )}\n // @ts-ignore\n onPointerDownCapture={composeEventHandlers(\n // @ts-ignore\n props.onPointerDownCapture,\n pointerDownOutside.onPointerDownCapture\n )}\n />\n )\n})\n\nDismissable.displayName = DISMISSABLE_LAYER_NAME\n\n/* -------------------------------------------------------------------------------------------------\n * DismissableBranch\n * -----------------------------------------------------------------------------------------------*/\n\nconst BRANCH_NAME = 'DismissableBranch'\n\nconst DismissableBranch = React.forwardRef<HTMLDivElement, DismissableBranchProps>(\n (props, forwardedRef) => {\n const context = React.useContext(DismissableContext)\n const ref = React.useRef<HTMLDivElement>(null)\n const composedRefs = useComposedRefs(forwardedRef, ref)\n\n React.useEffect(() => {\n const node = ref.current\n if (node) {\n context.branches.add(node)\n return () => {\n context.branches.delete(node)\n }\n }\n }, [context.branches])\n\n return <div style={{ display: 'contents' }} {...props} ref={composedRefs} />\n }\n)\n\nDismissableBranch.displayName = BRANCH_NAME\n\n/* -----------------------------------------------------------------------------------------------*/\n\nexport type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>\nexport type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>\n\n/**\n * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`\n * to mimic layer dismissing behaviour present in OS.\n * Returns props to pass to the node we want to check for outside events.\n */\nfunction usePointerDownOutside(onPointerDownOutside?: (event: PointerDownOutsideEvent) => void) {\n const handlePointerDownOutside = useEvent(onPointerDownOutside) as EventListener\n const isPointerInsideReactTreeRef = React.useRef(false)\n const handleClickRef = React.useRef(() => {})\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n\n function handleAndDispatchPointerDownOutsideEvent() {\n handleAndDispatchCustomEvent(\n POINTER_DOWN_OUTSIDE,\n handlePointerDownOutside,\n eventDetail,\n { discrete: true }\n )\n }\n\n /**\n * On touch devices, we need to wait for a click event because browsers implement\n * a ~350ms delay between the time the user stops touching the display and when the\n * browser executres events. We need to ensure we don't reactivate pointer-events within\n * this timeframe otherwise the browser may execute events that should have been prevented.\n *\n * Additionally, this also lets us deal automatically with cancellations when a click event\n * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.\n *\n * This is why we also continuously remove the previous listener, because we cannot be\n * certain that it was raised, and therefore cleaned-up.\n */\n if (event.pointerType === 'touch') {\n document.removeEventListener('click', handleClickRef.current)\n handleClickRef.current = handleAndDispatchPointerDownOutsideEvent\n document.addEventListener('click', handleClickRef.current, { once: true })\n } else {\n handleAndDispatchPointerDownOutsideEvent()\n }\n }\n isPointerInsideReactTreeRef.current = false\n }\n /**\n * if this hook executes in a component that mounts via a `pointerdown` event, the event\n * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid\n * this by delaying the event listener registration on the document.\n * This is not React specific, but rather how the DOM works, ie:\n * ```\n * button.addEventListener('pointerdown', () => {\n * console.log('I will log');\n * document.addEventListener('pointerdown', () => {\n * console.log('I will also log');\n * })\n * });\n */\n const timerId = window.setTimeout(() => {\n document.addEventListener('pointerdown', handlePointerDown)\n }, 0)\n return () => {\n window.clearTimeout(timerId)\n document.removeEventListener('pointerdown', handlePointerDown)\n document.removeEventListener('click', handleClickRef.current)\n }\n }, [handlePointerDownOutside])\n\n return {\n // ensures we check React component tree (not just DOM tree)\n onPointerDownCapture: () => (isPointerInsideReactTreeRef.current = true),\n }\n}\n\n/**\n * Listens for when focus happens outside a react subtree.\n * Returns props to pass to the root (node) of the subtree we want to check.\n */\nfunction useFocusOutside(onFocusOutside?: (event: FocusOutsideEvent) => void) {\n const handleFocusOutside = useEvent(onFocusOutside) as EventListener\n const isFocusInsideReactTreeRef = React.useRef(false)\n\n React.useEffect(() => {\n const handleFocus = (event: FocusEvent) => {\n if (event.target && !isFocusInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {\n discrete: false,\n })\n }\n }\n document.addEventListener('focusin', handleFocus)\n return () => document.removeEventListener('focusin', handleFocus)\n }, [handleFocusOutside])\n\n return {\n onFocusCapture: () => (isFocusInsideReactTreeRef.current = true),\n onBlurCapture: () => (isFocusInsideReactTreeRef.current = false),\n }\n}\n\nfunction dispatchUpdate() {\n const event = new CustomEvent(CONTEXT_UPDATE)\n document.dispatchEvent(event)\n}\n\nfunction handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent extends Event>(\n name: string,\n handler: ((event: E) => void) | undefined,\n detail: { originalEvent: OriginalEvent } & (E extends CustomEvent<infer D> ? D : never),\n { discrete }: { discrete: boolean }\n) {\n const target = detail.originalEvent.target\n const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail })\n if (handler) target.addEventListener(name, handler as EventListener, { once: true })\n\n if (discrete) {\n dispatchDiscreteCustomEvent(target, event)\n } else {\n target.dispatchEvent(event)\n }\n}\n\nconst Root = Dismissable\nconst Branch = DismissableBranch\n\nexport {\n Dismissable,\n DismissableBranch,\n //\n Root,\n Branch,\n}\n\nexport type { DismissableProps }\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["// forked from radix-ui\n// https://github.com/radix-ui/primitives/blob/cfd8dcba5fa6a0e751486af418d05a7b88a7f541/packages/react/dismissable-layer/src/DismissableLayer.tsx#L324\n\nimport { useEscapeKeydown } from '@radix-ui/react-use-escape-keydown'\nimport { useComposedRefs } from '@tamagui/compose-refs'\nimport { composeEventHandlers } from '@tamagui/core'\nimport { useEvent } from '@tamagui/use-event'\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport { DismissableBranchProps, DismissableProps } from './DismissableProps'\n\nfunction dispatchDiscreteCustomEvent<E extends CustomEvent>(target: E['target'], event: E) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event))\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Dismissable\n * -----------------------------------------------------------------------------------------------*/\n\nconst DISMISSABLE_LAYER_NAME = 'Dismissable'\nconst CONTEXT_UPDATE = 'dismissable.update'\nconst POINTER_DOWN_OUTSIDE = 'dismissable.pointerDownOutside'\nconst FOCUS_OUTSIDE = 'dismissable.focusOutside'\n\nlet originalBodyPointerEvents: string\n\nconst DismissableContext = React.createContext({\n layers: new Set<HTMLDivElement>(),\n layersWithOutsidePointerEventsDisabled: new Set<HTMLDivElement>(),\n branches: new Set<HTMLDivElement>(),\n})\n\nconst Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, forwardedRef) => {\n const {\n disableOutsidePointerEvents = false,\n forceUnmount,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n onDismiss,\n ...layerProps\n } = props\n const context = React.useContext(DismissableContext)\n const [node, setNode] = React.useState<HTMLDivElement | null>(null)\n const [, force] = React.useState({})\n const composedRefs = useComposedRefs(forwardedRef, (node) => setNode(node))\n const layers = Array.from(context.layers)\n const [highestLayerWithOutsidePointerEventsDisabled] = [...context.layersWithOutsidePointerEventsDisabled].slice(-1); // prettier-ignore\n const highestLayerWithOutsidePointerEventsDisabledIndex = layers.indexOf(highestLayerWithOutsidePointerEventsDisabled); // prettier-ignore\n const index = node ? layers.indexOf(node) : -1\n const isBodyPointerEventsDisabled = context.layersWithOutsidePointerEventsDisabled.size > 0\n const isPointerEventsEnabled = index >= highestLayerWithOutsidePointerEventsDisabledIndex\n\n const pointerDownOutside = usePointerDownOutside((event) => {\n const target = event.target as HTMLDivElement\n const isPointerDownOnBranch = [...context.branches].some((branch) => branch.contains(target))\n if (!isPointerEventsEnabled || isPointerDownOnBranch) return\n onPointerDownOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n const focusOutside = useFocusOutside((event) => {\n const target = event.target as HTMLDivElement\n const isFocusInBranch = [...context.branches].some((branch) => branch.contains(target))\n if (isFocusInBranch) return\n onFocusOutside?.(event)\n onInteractOutside?.(event)\n if (!event.defaultPrevented) onDismiss?.()\n })\n\n useEscapeKeydown((event) => {\n const isHighestLayer = index === context.layers.size - 1\n if (!isHighestLayer) return\n onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n })\n\n React.useEffect(() => {\n if (!node) return\n if (disableOutsidePointerEvents) {\n if (context.layersWithOutsidePointerEventsDisabled.size === 0) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n document.body.style.pointerEvents = 'none'\n }\n context.layersWithOutsidePointerEventsDisabled.add(node)\n }\n context.layers.add(node)\n dispatchUpdate()\n return () => {\n if (\n disableOutsidePointerEvents &&\n context.layersWithOutsidePointerEventsDisabled.size === 1\n ) {\n document.body.style.pointerEvents = originalBodyPointerEvents\n }\n }\n }, [node, disableOutsidePointerEvents, context])\n\n /**\n * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect\n * because a change to `disableOutsidePointerEvents` would remove this layer from the stack\n * and add it to the end again so the layering order wouldn't be _creation order_.\n * We only want them to be removed from context stacks when unmounted.\n */\n React.useEffect(() => {\n if (forceUnmount) return\n return () => {\n if (!node) return\n context.layers.delete(node)\n context.layersWithOutsidePointerEventsDisabled.delete(node)\n dispatchUpdate()\n }\n }, [node, context, forceUnmount])\n\n React.useEffect(() => {\n const handleUpdate = () => {\n force({})\n }\n document.addEventListener(CONTEXT_UPDATE, handleUpdate)\n return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate)\n }, [])\n\n return (\n <div\n {...layerProps}\n // @ts-ignore\n ref={composedRefs}\n style={{\n display: 'contents',\n pointerEvents: isBodyPointerEventsDisabled\n ? isPointerEventsEnabled\n ? 'auto'\n : 'none'\n : undefined,\n // @ts-ignore\n ...props.style,\n }}\n onFocusCapture={composeEventHandlers(\n // @ts-ignore\n props.onFocusCapture,\n focusOutside.onFocusCapture\n )}\n onBlurCapture={composeEventHandlers(\n // @ts-ignore\n props.onBlurCapture,\n focusOutside.onBlurCapture\n )}\n // @ts-ignore\n onPointerDownCapture={composeEventHandlers(\n // @ts-ignore\n props.onPointerDownCapture,\n pointerDownOutside.onPointerDownCapture\n )}\n />\n )\n})\n\nDismissable.displayName = DISMISSABLE_LAYER_NAME\n\n/* -------------------------------------------------------------------------------------------------\n * DismissableBranch\n * -----------------------------------------------------------------------------------------------*/\n\nconst BRANCH_NAME = 'DismissableBranch'\n\nconst DismissableBranch = React.forwardRef<HTMLDivElement, DismissableBranchProps>(\n (props, forwardedRef) => {\n const context = React.useContext(DismissableContext)\n const ref = React.useRef<HTMLDivElement>(null)\n const composedRefs = useComposedRefs(forwardedRef, ref)\n\n React.useEffect(() => {\n const node = ref.current\n if (node) {\n context.branches.add(node)\n return () => {\n context.branches.delete(node)\n }\n }\n }, [context.branches])\n\n return <div style={{ display: 'contents' }} {...props} ref={composedRefs} />\n }\n)\n\nDismissableBranch.displayName = BRANCH_NAME\n\n/* -----------------------------------------------------------------------------------------------*/\n\nexport type PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>\nexport type FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>\n\n/**\n * Listens for `pointerdown` outside a react subtree. We use `pointerdown` rather than `pointerup`\n * to mimic layer dismissing behaviour present in OS.\n * Returns props to pass to the node we want to check for outside events.\n */\nfunction usePointerDownOutside(onPointerDownOutside?: (event: PointerDownOutsideEvent) => void) {\n const handlePointerDownOutside = useEvent(onPointerDownOutside) as EventListener\n const isPointerInsideReactTreeRef = React.useRef(false)\n const handleClickRef = React.useRef(() => {})\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (event.target && !isPointerInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n\n function handleAndDispatchPointerDownOutsideEvent() {\n handleAndDispatchCustomEvent(\n POINTER_DOWN_OUTSIDE,\n handlePointerDownOutside,\n eventDetail,\n { discrete: true }\n )\n }\n\n /**\n * On touch devices, we need to wait for a click event because browsers implement\n * a ~350ms delay between the time the user stops touching the display and when the\n * browser executres events. We need to ensure we don't reactivate pointer-events within\n * this timeframe otherwise the browser may execute events that should have been prevented.\n *\n * Additionally, this also lets us deal automatically with cancellations when a click event\n * isn't raised because the page was considered scrolled/drag-scrolled, long-pressed, etc.\n *\n * This is why we also continuously remove the previous listener, because we cannot be\n * certain that it was raised, and therefore cleaned-up.\n */\n if (event.pointerType === 'touch') {\n document.removeEventListener('click', handleClickRef.current)\n handleClickRef.current = handleAndDispatchPointerDownOutsideEvent\n document.addEventListener('click', handleClickRef.current, { once: true })\n } else {\n handleAndDispatchPointerDownOutsideEvent()\n }\n }\n isPointerInsideReactTreeRef.current = false\n }\n /**\n * if this hook executes in a component that mounts via a `pointerdown` event, the event\n * would bubble up to the document and trigger a `pointerDownOutside` event. We avoid\n * this by delaying the event listener registration on the document.\n * This is not React specific, but rather how the DOM works, ie:\n * ```\n * button.addEventListener('pointerdown', () => {\n * console.log('I will log');\n * document.addEventListener('pointerdown', () => {\n * console.log('I will also log');\n * })\n * });\n */\n const timerId = setTimeout(() => {\n document.addEventListener('pointerdown', handlePointerDown)\n }, 0)\n return () => {\n window.clearTimeout(timerId)\n document.removeEventListener('pointerdown', handlePointerDown)\n document.removeEventListener('click', handleClickRef.current)\n }\n }, [handlePointerDownOutside])\n\n return {\n // ensures we check React component tree (not just DOM tree)\n onPointerDownCapture: () => (isPointerInsideReactTreeRef.current = true),\n }\n}\n\n/**\n * Listens for when focus happens outside a react subtree.\n * Returns props to pass to the root (node) of the subtree we want to check.\n */\nfunction useFocusOutside(onFocusOutside?: (event: FocusOutsideEvent) => void) {\n const handleFocusOutside = useEvent(onFocusOutside) as EventListener\n const isFocusInsideReactTreeRef = React.useRef(false)\n\n React.useEffect(() => {\n const handleFocus = (event: FocusEvent) => {\n if (event.target && !isFocusInsideReactTreeRef.current) {\n const eventDetail = { originalEvent: event }\n handleAndDispatchCustomEvent(FOCUS_OUTSIDE, handleFocusOutside, eventDetail, {\n discrete: false,\n })\n }\n }\n document.addEventListener('focusin', handleFocus)\n return () => document.removeEventListener('focusin', handleFocus)\n }, [handleFocusOutside])\n\n return {\n onFocusCapture: () => (isFocusInsideReactTreeRef.current = true),\n onBlurCapture: () => (isFocusInsideReactTreeRef.current = false),\n }\n}\n\nfunction dispatchUpdate() {\n const event = new CustomEvent(CONTEXT_UPDATE)\n document.dispatchEvent(event)\n}\n\nfunction handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent extends Event>(\n name: string,\n handler: ((event: E) => void) | undefined,\n detail: { originalEvent: OriginalEvent } & (E extends CustomEvent<infer D> ? D : never),\n { discrete }: { discrete: boolean }\n) {\n const target = detail.originalEvent.target\n const event = new CustomEvent(name, { bubbles: false, cancelable: true, detail })\n if (handler) target.addEventListener(name, handler as EventListener, { once: true })\n\n if (discrete) {\n dispatchDiscreteCustomEvent(target, event)\n } else {\n target.dispatchEvent(event)\n }\n}\n\nexport { Dismissable, DismissableBranch }\n\nexport type { DismissableProps }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/dismissable",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
3
|
+
"version": "1.0.1-beta.120",
|
|
4
4
|
"sideEffects": true,
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"types": "./types/index.d.ts",
|
|
@@ -20,16 +20,16 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@radix-ui/react-use-escape-keydown": "^0.1.0",
|
|
23
|
-
"@tamagui/compose-refs": "^1.0.1-beta.
|
|
24
|
-
"@tamagui/core": "^1.0.1-beta.
|
|
25
|
-
"@tamagui/use-event": "^1.0.1-beta.
|
|
23
|
+
"@tamagui/compose-refs": "^1.0.1-beta.120",
|
|
24
|
+
"@tamagui/core": "^1.0.1-beta.120",
|
|
25
|
+
"@tamagui/use-event": "^1.0.1-beta.120"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "*",
|
|
29
29
|
"react-dom": "*"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@tamagui/build": "^1.0.1-beta.
|
|
32
|
+
"@tamagui/build": "^1.0.1-beta.120",
|
|
33
33
|
"react": "*",
|
|
34
34
|
"react-dom": "*"
|
|
35
35
|
},
|
package/src/Dismissable.tsx
CHANGED
|
@@ -34,6 +34,7 @@ const DismissableContext = React.createContext({
|
|
|
34
34
|
const Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, forwardedRef) => {
|
|
35
35
|
const {
|
|
36
36
|
disableOutsidePointerEvents = false,
|
|
37
|
+
forceUnmount,
|
|
37
38
|
onEscapeKeyDown,
|
|
38
39
|
onPointerDownOutside,
|
|
39
40
|
onFocusOutside,
|
|
@@ -108,16 +109,19 @@ const Dismissable = React.forwardRef<HTMLDivElement, DismissableProps>((props, f
|
|
|
108
109
|
* We only want them to be removed from context stacks when unmounted.
|
|
109
110
|
*/
|
|
110
111
|
React.useEffect(() => {
|
|
112
|
+
if (forceUnmount) return
|
|
111
113
|
return () => {
|
|
112
114
|
if (!node) return
|
|
113
115
|
context.layers.delete(node)
|
|
114
116
|
context.layersWithOutsidePointerEventsDisabled.delete(node)
|
|
115
117
|
dispatchUpdate()
|
|
116
118
|
}
|
|
117
|
-
}, [node, context])
|
|
119
|
+
}, [node, context, forceUnmount])
|
|
118
120
|
|
|
119
121
|
React.useEffect(() => {
|
|
120
|
-
const handleUpdate = () =>
|
|
122
|
+
const handleUpdate = () => {
|
|
123
|
+
force({})
|
|
124
|
+
}
|
|
121
125
|
document.addEventListener(CONTEXT_UPDATE, handleUpdate)
|
|
122
126
|
return () => document.removeEventListener(CONTEXT_UPDATE, handleUpdate)
|
|
123
127
|
}, [])
|
|
@@ -251,7 +255,7 @@ function usePointerDownOutside(onPointerDownOutside?: (event: PointerDownOutside
|
|
|
251
255
|
* })
|
|
252
256
|
* });
|
|
253
257
|
*/
|
|
254
|
-
const timerId =
|
|
258
|
+
const timerId = setTimeout(() => {
|
|
255
259
|
document.addEventListener('pointerdown', handlePointerDown)
|
|
256
260
|
}, 0)
|
|
257
261
|
return () => {
|
|
@@ -316,15 +320,6 @@ function handleAndDispatchCustomEvent<E extends CustomEvent, OriginalEvent exten
|
|
|
316
320
|
}
|
|
317
321
|
}
|
|
318
322
|
|
|
319
|
-
|
|
320
|
-
const Branch = DismissableBranch
|
|
321
|
-
|
|
322
|
-
export {
|
|
323
|
-
Dismissable,
|
|
324
|
-
DismissableBranch,
|
|
325
|
-
//
|
|
326
|
-
Root,
|
|
327
|
-
Branch,
|
|
328
|
-
}
|
|
323
|
+
export { Dismissable, DismissableBranch }
|
|
329
324
|
|
|
330
325
|
export type { DismissableProps }
|
package/src/DismissableProps.tsx
CHANGED
package/types/Dismissable.d.ts
CHANGED
|
@@ -8,8 +8,6 @@ export declare type PointerDownOutsideEvent = CustomEvent<{
|
|
|
8
8
|
export declare type FocusOutsideEvent = CustomEvent<{
|
|
9
9
|
originalEvent: FocusEvent;
|
|
10
10
|
}>;
|
|
11
|
-
|
|
12
|
-
declare const Branch: React.ForwardRefExoticComponent<DismissableBranchProps & React.RefAttributes<HTMLDivElement>>;
|
|
13
|
-
export { Dismissable, DismissableBranch, Root, Branch, };
|
|
11
|
+
export { Dismissable, DismissableBranch };
|
|
14
12
|
export type { DismissableProps };
|
|
15
13
|
//# sourceMappingURL=Dismissable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dismissable.d.ts","sourceRoot":"","sources":["../src/Dismissable.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAuB7E,QAAA,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"Dismissable.d.ts","sourceRoot":"","sources":["../src/Dismissable.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAuB7E,QAAA,MAAM,WAAW,yFAgIf,CAAA;AAUF,QAAA,MAAM,iBAAiB,+FAkBtB,CAAA;AAMD,oBAAY,uBAAuB,GAAG,WAAW,CAAC;IAAE,aAAa,EAAE,YAAY,CAAA;CAAE,CAAC,CAAA;AAClF,oBAAY,iBAAiB,GAAG,WAAW,CAAC;IAAE,aAAa,EAAE,UAAU,CAAA;CAAE,CAAC,CAAA;AA8H1E,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAA;AAEzC,YAAY,EAAE,gBAAgB,EAAE,CAAA"}
|
|
@@ -7,6 +7,7 @@ export interface DismissableProps {
|
|
|
7
7
|
onFocusOutside?: (event: FocusOutsideEvent) => void;
|
|
8
8
|
onInteractOutside?: (event: PointerDownOutsideEvent | FocusOutsideEvent) => void;
|
|
9
9
|
onDismiss?: () => void;
|
|
10
|
+
forceUnmount?: boolean;
|
|
10
11
|
children?: React.ReactNode;
|
|
11
12
|
}
|
|
12
13
|
export interface DismissableBranchProps {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DismissableProps.d.ts","sourceRoot":"","sources":["../src/DismissableProps.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAE1E,MAAM,WAAW,gBAAgB;IAM/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IAKrC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAKhD,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAK/D,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAMnD,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,GAAG,iBAAiB,KAAK,IAAI,CAAA;IAIhF,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IAEtB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B"}
|
|
1
|
+
{"version":3,"file":"DismissableProps.d.ts","sourceRoot":"","sources":["../src/DismissableProps.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAE1E,MAAM,WAAW,gBAAgB;IAM/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IAKrC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAKhD,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAK/D,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAA;IAMnD,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,GAAG,iBAAiB,KAAK,IAAI,CAAA;IAIhF,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IAKtB,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B"}
|