@sproutsocial/seeds-react-popout 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/Popout.tsx
2
2
  import * as React from "react";
3
3
  import { useState, useEffect, useRef, useCallback, useMemo } from "react";
4
- import { useTransition, animated } from "react-spring";
4
+ import { useTransition, animated } from "@react-spring/web";
5
5
  import FocusLock from "react-focus-lock";
6
6
  import { Popper } from "react-popper";
7
7
  import { MOTION_DURATION_FAST } from "@sproutsocial/seeds-motion/dist/seeds-motion-unitless";
@@ -19,6 +19,7 @@ var TargetWrapper = styled.div`
19
19
  `;
20
20
 
21
21
  // src/Popout.tsx
22
+ import { jsx, jsxs } from "react/jsx-runtime";
22
23
  var doesRefContainEventTarget = (ref, event) => {
23
24
  return ref.current && event.target instanceof Node && ref.current.contains(event.target);
24
25
  };
@@ -33,7 +34,10 @@ var transitionConfig = {
33
34
  opacity: 0
34
35
  },
35
36
  config: {
36
- duration: MOTION_DURATION_FAST * 1e3
37
+ duration: (
38
+ // skip animation in test environment
39
+ process.env.NODE_ENV === "test" ? 0 : MOTION_DURATION_FAST * 1e3
40
+ )
37
41
  }
38
42
  };
39
43
  function Popout({
@@ -65,12 +69,11 @@ function Popout({
65
69
  const isControlled = typeof isOpen === "boolean";
66
70
  const isShown = isControlled ? isOpen : isInternalShown;
67
71
  const setIsShown = useMemo(
68
- () => isControlled && setIsOpen ? setIsOpen : (nextIsShown) => setIsInternalShown(nextIsShown),
72
+ () => isControlled && setIsOpen ? setIsOpen : setIsInternalShown,
69
73
  [isControlled, setIsOpen]
70
74
  );
71
75
  const targetRef = useRef();
72
76
  const popoutRef = useRef();
73
- const isFirstRender = useRef(true);
74
77
  const scheduleUpdateCallback = useRef(() => {
75
78
  });
76
79
  useMutationObserver(
@@ -114,26 +117,19 @@ function Popout({
114
117
  };
115
118
  }
116
119
  }, [isShown, setIsShown]);
117
- useEffect(
118
- () => {
119
- if (isFirstRender.current) {
120
- isFirstRender.current = false;
121
- return;
122
- }
123
- if (!onOpen && !onClose) {
124
- return;
125
- }
126
- if (isShown && onOpen) {
127
- onOpen();
128
- }
129
- if (!isShown && onClose) {
130
- onClose();
131
- }
132
- },
133
- // eslint-disable-next-line
134
- [isShown]
135
- );
136
- const transitions = useTransition(isShown, null, transitionConfig);
120
+ const callbackStateRef = useRef({ calledFor: isShown });
121
+ useEffect(() => {
122
+ if (callbackStateRef.current.calledFor === isShown) {
123
+ return;
124
+ }
125
+ callbackStateRef.current.calledFor = isShown;
126
+ if (isShown) {
127
+ onOpen?.();
128
+ } else {
129
+ onClose?.();
130
+ }
131
+ }, [isShown, onOpen, onClose]);
132
+ const transition = useTransition(isShown, transitionConfig);
137
133
  const ariaProps = useMemo(
138
134
  () => disableWrapperAria ? {} : {
139
135
  "aria-expanded": isShown,
@@ -153,77 +149,82 @@ function Popout({
153
149
  setShouldRenderPopout(true);
154
150
  }
155
151
  };
156
- return /* @__PURE__ */ React.createElement(React.Fragment, null, typeof children === "function" ? children({
157
- ref: childrenRef,
158
- toggle,
159
- show,
160
- hide,
161
- ariaProps
162
- }) : /* @__PURE__ */ React.createElement(TargetWrapper, { ...qa, id, ...rest, ref: childrenRef }, React.cloneElement(children, {
163
- ...ariaProps,
164
- ...!isControlled ? {
165
- onClick: toggle
166
- } : void 0
167
- })), shouldRenderPopout && !isInvalidContent && transitions.map(
168
- ({ item, key, props }) => item && /* @__PURE__ */ React.createElement(PopoutComponentWrapper, { key }, /* @__PURE__ */ React.createElement(
169
- Popper,
170
- {
171
- referenceElement: targetRef.current,
172
- placement,
173
- modifiers: {
174
- preventOverflow: {
175
- boundariesElement: "viewport"
176
- }
177
- },
178
- ...popperProps
179
- },
180
- ({
181
- ref,
182
- style,
183
- placement: placement2,
184
- outOfBoundaries,
185
- scheduleUpdate
186
- }) => {
187
- const interceptRef = (el) => {
188
- popoutRef.current = el;
189
- ref(el);
190
- };
191
- scheduleUpdateCallback.current = scheduleUpdate;
192
- scheduleUpdateRef(scheduleUpdate);
193
- return /* @__PURE__ */ React.createElement(
194
- "div",
195
- {
196
- ref: interceptRef,
197
- style: {
198
- ...style,
199
- zIndex,
200
- width: fullWidth && targetRef.current ? targetRef.current.offsetWidth : "initial"
201
- },
202
- "data-placement": placement2,
203
- "data-qa-popout": "",
204
- "data-qa-popout-isopen": isOpen === true,
205
- color,
206
- ...rest
152
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
153
+ typeof children === "function" ? children({
154
+ ref: childrenRef,
155
+ toggle,
156
+ show,
157
+ hide,
158
+ ariaProps
159
+ }) : /* @__PURE__ */ jsx(TargetWrapper, { ...qa, id, ...rest, ref: childrenRef, children: React.cloneElement(children, {
160
+ ...ariaProps,
161
+ ...!isControlled ? {
162
+ onClick: toggle
163
+ } : void 0
164
+ }) }),
165
+ shouldRenderPopout && !isInvalidContent && transition(
166
+ (transitionStyle, isVisible, transition2) => isVisible && /* @__PURE__ */ jsx(PopoutComponentWrapper, { children: /* @__PURE__ */ jsx(
167
+ Popper,
168
+ {
169
+ referenceElement: targetRef.current,
170
+ placement,
171
+ modifiers: {
172
+ preventOverflow: {
173
+ boundariesElement: "viewport"
174
+ }
207
175
  },
208
- item && !outOfBoundaries && /* @__PURE__ */ React.createElement(animated.div, { style: props }, /* @__PURE__ */ React.createElement(
209
- FocusLock,
210
- {
211
- autoFocus,
212
- returnFocus,
213
- disabled: !focusOnContent,
214
- ...restFocusLockProps
215
- },
216
- typeof content === "function" && content({
217
- hide
218
- }),
219
- typeof content !== "function" && content
220
- ))
221
- );
222
- }
223
- ))
224
- ));
176
+ ...popperProps,
177
+ children: ({
178
+ ref,
179
+ style,
180
+ placement: placement2,
181
+ outOfBoundaries,
182
+ scheduleUpdate
183
+ }) => {
184
+ const interceptRef = (el) => {
185
+ popoutRef.current = el;
186
+ ref(el);
187
+ };
188
+ scheduleUpdateCallback.current = scheduleUpdate;
189
+ scheduleUpdateRef(scheduleUpdate);
190
+ return /* @__PURE__ */ jsx(
191
+ "div",
192
+ {
193
+ ref: interceptRef,
194
+ style: {
195
+ ...style,
196
+ zIndex,
197
+ width: fullWidth && targetRef.current ? targetRef.current.offsetWidth : "initial"
198
+ },
199
+ "data-placement": placement2,
200
+ "data-qa-popout": "",
201
+ "data-qa-popout-isopen": isOpen === true,
202
+ color,
203
+ ...rest,
204
+ children: isVisible && !outOfBoundaries && /* @__PURE__ */ jsx(animated.div, { style: transitionStyle, children: /* @__PURE__ */ jsxs(
205
+ FocusLock,
206
+ {
207
+ autoFocus,
208
+ returnFocus,
209
+ disabled: !focusOnContent,
210
+ ...restFocusLockProps,
211
+ children: [
212
+ typeof content === "function" && content({
213
+ hide
214
+ }),
215
+ typeof content !== "function" && content
216
+ ]
217
+ }
218
+ ) })
219
+ }
220
+ );
221
+ }
222
+ }
223
+ ) }, transition2.key)
224
+ )
225
+ ] });
225
226
  }
226
- var PopoutContent = ({ children, ...rest }) => /* @__PURE__ */ React.createElement(
227
+ var PopoutContent = ({ children, ...rest }) => /* @__PURE__ */ jsx(
227
228
  Box,
228
229
  {
229
230
  bg: "container.background.base",
@@ -234,14 +235,17 @@ var PopoutContent = ({ children, ...rest }) => /* @__PURE__ */ React.createEleme
234
235
  boxShadow: "medium",
235
236
  p: 400,
236
237
  m: 300,
237
- ...rest
238
- },
239
- children
238
+ ...rest,
239
+ children
240
+ }
240
241
  );
241
242
  PopoutContent.displayName = "Popout.Content";
242
243
  Popout.Content = PopoutContent;
243
244
  var Popout_default = Popout;
244
245
 
246
+ // src/PopoutTypes.ts
247
+ import "react";
248
+
245
249
  // src/index.ts
246
250
  var src_default = Popout_default;
247
251
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Popout.tsx","../../src/styles.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useState, useEffect, useRef, useCallback, useMemo } from \"react\";\nimport { useTransition, animated } from \"react-spring\";\nimport FocusLock from \"react-focus-lock\";\nimport { Popper } from \"react-popper\";\nimport { MOTION_DURATION_FAST } from \"@sproutsocial/seeds-motion/dist/seeds-motion-unitless\";\nimport { useMutationObserver } from \"@sproutsocial/seeds-react-hooks\";\nimport Portal from \"@sproutsocial/seeds-react-portal\";\nimport Box, { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport { TargetWrapper } from \"./styles\";\nimport type { TypePopoutProps, EnumPlacements } from \"./PopoutTypes\";\n\nexport const placements: { [key: string]: EnumPlacements } = {\n auto: \"auto\",\n\n top: \"top\",\n right: \"right\",\n bottom: \"bottom\",\n left: \"left\",\n\n \"top-start\": \"top-start\",\n \"right-start\": \"right-start\",\n \"bottom-start\": \"bottom-start\",\n \"left-start\": \"left-start\",\n\n \"top-end\": \"top-end\",\n \"right-end\": \"right-end\",\n \"bottom-end\": \"bottom-end\",\n \"left-end\": \"left-end\",\n};\n\nconst doesRefContainEventTarget = (ref, event) => {\n return (\n ref.current &&\n event.target instanceof Node &&\n ref.current.contains(event.target)\n );\n};\n\n// Transition definitions for fading in and out\nconst transitionConfig = {\n from: {\n opacity: 0,\n },\n enter: {\n opacity: 1,\n },\n leave: {\n opacity: 0,\n },\n config: {\n duration: MOTION_DURATION_FAST * 1000,\n },\n};\n\nexport function Popout({\n isOpen,\n setIsOpen,\n content,\n children,\n placement = \"auto\",\n fullWidth = false,\n zIndex = 7,\n focusOnContent = true,\n onOpen,\n onClose,\n qa = {},\n popperProps,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n scheduleUpdateRef = () => {},\n appendToBody = true,\n focusLockProps = {},\n color,\n \"aria-haspopup\": ariaHasPopup,\n disableWrapperAria = false,\n id,\n ...rest\n}: TypePopoutProps) {\n const PopoutComponentWrapper = appendToBody ? Portal : React.Fragment;\n const [isInternalShown, setIsInternalShown] = useState<boolean>(false);\n const isControlled = typeof isOpen === \"boolean\";\n const isShown = isControlled ? isOpen : isInternalShown;\n\n const setIsShown = useMemo(\n () =>\n isControlled && setIsOpen\n ? setIsOpen\n : (nextIsShown) => setIsInternalShown(nextIsShown),\n [isControlled, setIsOpen]\n );\n\n const targetRef = useRef<HTMLDivElement>();\n const popoutRef = useRef<HTMLDivElement>();\n const isFirstRender = useRef(true);\n\n // This callback will automatically trigger a recalculation of the popout position if the content is changed\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n const scheduleUpdateCallback = useRef(() => {});\n\n useMutationObserver(\n popoutRef.current ?? null,\n {\n childList: true,\n characterData: true,\n subtree: true,\n },\n scheduleUpdateCallback.current\n );\n\n const {\n autoFocus = true,\n returnFocus = true,\n ...restFocusLockProps\n } = focusLockProps;\n\n const isInvalidContent = content === null || content === undefined;\n\n // Callbacks for showing, hiding, and toggling visibility of the popout\n // (Not used when isOpen is passed explicitly)\n const show = useCallback(() => setIsShown(true), [setIsShown]);\n const hide = useCallback(() => setIsShown(false), [setIsShown]);\n const toggle = useCallback(() => setIsShown(!isShown), [isShown, setIsShown]);\n\n useEffect(() => {\n const documentBody = document.body;\n\n if (isShown && documentBody) {\n // Callback passed to a click handler attached to document.body,\n // allowing user to close the popout by clicking outside\n const bodyClick = (e: MouseEvent): void => {\n if (\n doesRefContainEventTarget(targetRef, e) ||\n doesRefContainEventTarget(popoutRef, e)\n ) {\n return;\n }\n\n setIsShown(false, e);\n };\n\n // Callback for allowing user to close by keying \"esc\"\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n // stop propagation to avoid interacting with other components when popout is shown\n // ie if we have a popout shown in a modal and hit esc, we don't want to close both the popout and modal\n e.stopPropagation();\n setIsShown(false, e);\n }\n };\n\n documentBody.addEventListener(\"click\", bodyClick, { capture: true });\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n return () => {\n documentBody.removeEventListener(\"click\", bodyClick, { capture: true });\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n };\n }\n }, [isShown, setIsShown]);\n\n // Manage onOpen and onClose callbacks\n useEffect(\n () => {\n // Don't fire onClose on the first render\n if (isFirstRender.current) {\n isFirstRender.current = false;\n return;\n }\n\n if (!onOpen && !onClose) {\n return;\n }\n\n if (isShown && onOpen) {\n onOpen();\n }\n\n if (!isShown && onClose) {\n onClose();\n }\n },\n // eslint-disable-next-line\n [isShown]\n );\n\n const transitions = useTransition(isShown, null, transitionConfig);\n // WAI-Aria properties for the popout trigger, disabled if necessary\n const ariaProps = useMemo(\n () =>\n disableWrapperAria\n ? {}\n : {\n \"aria-expanded\": isShown,\n \"aria-haspopup\": ariaHasPopup ? ariaHasPopup : true,\n },\n [isShown, ariaHasPopup, disableWrapperAria]\n );\n\n // In cases where a controlled popout is used (e.g. props.isOpen is true), we need\n // to wait for the targetRef to receive a value before rendering the popout. Otherwise,\n // the Popout component renders, but doesn't know how to position itself due the\n // `refereElement` property being undefined.\n const [shouldRenderPopout, setShouldRenderPopout] = useState<boolean>( // Only trigger this shouldRenderPopout logic when using a controlled component.\n // The reason for that is because controlled components may render the popout\n // immediately before the targetRef has a value set to it.\n !isControlled\n );\n\n const childrenRef = (el) => {\n targetRef.current = el;\n\n if (targetRef.current) {\n setShouldRenderPopout(true);\n }\n };\n\n return (\n <React.Fragment>\n {typeof children === \"function\" ? (\n children({\n ref: childrenRef,\n toggle,\n show,\n hide,\n ariaProps,\n })\n ) : (\n <TargetWrapper {...qa} id={id} {...rest} ref={childrenRef}>\n {React.cloneElement(children, {\n ...ariaProps,\n ...(!isControlled\n ? {\n onClick: toggle,\n }\n : undefined),\n })}\n </TargetWrapper>\n )}\n {shouldRenderPopout &&\n !isInvalidContent &&\n transitions.map(\n ({ item, key, props }) =>\n item && (\n <PopoutComponentWrapper key={key}>\n <Popper\n referenceElement={targetRef.current}\n placement={placement}\n modifiers={{\n preventOverflow: {\n boundariesElement: \"viewport\",\n },\n }}\n {...popperProps}\n >\n {({\n ref,\n style,\n placement,\n outOfBoundaries,\n scheduleUpdate,\n }) => {\n const interceptRef = (el) => {\n popoutRef.current = el;\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n ref(el);\n };\n\n scheduleUpdateCallback.current = scheduleUpdate;\n scheduleUpdateRef(scheduleUpdate);\n\n return (\n <div\n ref={interceptRef}\n style={{\n ...style,\n zIndex,\n width:\n fullWidth && targetRef.current\n ? targetRef.current.offsetWidth\n : \"initial\",\n }}\n data-placement={placement}\n data-qa-popout=\"\"\n data-qa-popout-isopen={isOpen === true}\n // TODO: fix this type since `color` should be valid here. TS can't resolve the correct type.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n color={color}\n {...rest}\n >\n {item && !outOfBoundaries && (\n <animated.div style={props}>\n <FocusLock\n autoFocus={autoFocus}\n returnFocus={returnFocus}\n disabled={!focusOnContent}\n {...restFocusLockProps}\n >\n {typeof content === \"function\" &&\n content({\n hide,\n })}\n {typeof content !== \"function\" && content}\n </FocusLock>\n </animated.div>\n )}\n </div>\n );\n }}\n </Popper>\n </PopoutComponentWrapper>\n )\n )}\n </React.Fragment>\n );\n}\n\nconst PopoutContent = ({ children, ...rest }: TypeBoxProps) => (\n <Box\n bg=\"container.background.base\"\n color=\"text.body\"\n border={500}\n borderColor=\"container.border.base\"\n borderRadius=\"outer\"\n boxShadow=\"medium\"\n p={400}\n m={300}\n {...rest}\n >\n {children}\n </Box>\n);\n\nPopoutContent.displayName = \"Popout.Content\";\nPopout.Content = PopoutContent;\n\nexport default Popout;\n","import styled from \"styled-components\";\nimport { COMMON, LAYOUT } from \"@sproutsocial/seeds-react-system-props\";\n\nexport const TargetWrapper = styled.div`\n display: inline-block;\n ${COMMON}\n ${LAYOUT}\n`;\n","import Popout from \"./Popout\";\n\nexport default Popout;\nexport { Popout };\nexport * from \"./PopoutTypes\";\n"],"mappings":"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","names":["placement"]}
1
+ {"version":3,"sources":["../../src/Popout.tsx","../../src/styles.ts","../../src/PopoutTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useState, useEffect, useRef, useCallback, useMemo } from \"react\";\nimport { useTransition, animated } from \"@react-spring/web\";\nimport FocusLock from \"react-focus-lock\";\nimport { Popper } from \"react-popper\";\nimport { MOTION_DURATION_FAST } from \"@sproutsocial/seeds-motion/dist/seeds-motion-unitless\";\nimport { useMutationObserver } from \"@sproutsocial/seeds-react-hooks\";\nimport Portal from \"@sproutsocial/seeds-react-portal\";\nimport Box, { type TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport { TargetWrapper } from \"./styles\";\nimport type { TypePopoutProps } from \"./PopoutTypes\";\n\nconst doesRefContainEventTarget = (\n ref: React.MutableRefObject<HTMLDivElement | undefined>,\n event: MouseEvent\n) => {\n return (\n ref.current &&\n event.target instanceof Node &&\n ref.current.contains(event.target)\n );\n};\n\n// Transition definitions for fading in and out\nconst transitionConfig = {\n from: {\n opacity: 0,\n },\n enter: {\n opacity: 1,\n },\n leave: {\n opacity: 0,\n },\n config: {\n duration:\n // skip animation in test environment\n process.env.NODE_ENV === \"test\" ? 0 : MOTION_DURATION_FAST * 1000,\n },\n};\n\nexport function Popout({\n isOpen,\n setIsOpen,\n content,\n children,\n placement = \"auto\",\n fullWidth = false,\n zIndex = 7,\n focusOnContent = true,\n onOpen,\n onClose,\n qa = {},\n popperProps,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n scheduleUpdateRef = () => {},\n appendToBody = true,\n focusLockProps = {},\n color,\n \"aria-haspopup\": ariaHasPopup,\n disableWrapperAria = false,\n id,\n ...rest\n}: TypePopoutProps) {\n const PopoutComponentWrapper = appendToBody ? Portal : React.Fragment;\n const [isInternalShown, setIsInternalShown] = useState<boolean>(false);\n const isControlled = typeof isOpen === \"boolean\";\n const isShown = isControlled ? isOpen : isInternalShown;\n\n const setIsShown = useMemo(\n () => (isControlled && setIsOpen ? setIsOpen : setIsInternalShown),\n [isControlled, setIsOpen]\n );\n\n const targetRef = useRef<HTMLElement | any>();\n const popoutRef = useRef<HTMLDivElement>();\n\n // This callback will automatically trigger a recalculation of the popout position if the content is changed\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n const scheduleUpdateCallback = useRef(() => {});\n\n useMutationObserver(\n popoutRef.current ?? null,\n {\n childList: true,\n characterData: true,\n subtree: true,\n },\n scheduleUpdateCallback.current\n );\n\n const {\n autoFocus = true,\n returnFocus = true,\n ...restFocusLockProps\n } = focusLockProps;\n\n const isInvalidContent = content === null || content === undefined;\n\n // Callbacks for showing, hiding, and toggling visibility of the popout\n // (Not used when isOpen is passed explicitly)\n const show = useCallback(() => setIsShown(true), [setIsShown]);\n const hide = useCallback(() => setIsShown(false), [setIsShown]);\n const toggle = useCallback(() => setIsShown(!isShown), [isShown, setIsShown]);\n\n useEffect(() => {\n const documentBody = document.body;\n\n if (isShown && documentBody) {\n // Callback passed to a click handler attached to document.body,\n // allowing user to close the popout by clicking outside\n const bodyClick = (e: MouseEvent): void => {\n if (\n doesRefContainEventTarget(targetRef, e) ||\n doesRefContainEventTarget(popoutRef, e)\n ) {\n return;\n }\n\n setIsShown(false, e);\n };\n\n // Callback for allowing user to close by keying \"esc\"\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n // stop propagation to avoid interacting with other components when popout is shown\n // ie if we have a popout shown in a modal and hit esc, we don't want to close both the popout and modal\n e.stopPropagation();\n setIsShown(false, e);\n }\n };\n\n documentBody.addEventListener(\"click\", bodyClick, { capture: true });\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n return () => {\n documentBody.removeEventListener(\"click\", bodyClick, { capture: true });\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n };\n }\n }, [isShown, setIsShown]);\n\n const callbackStateRef = useRef({ calledFor: isShown });\n useEffect(() => {\n if (callbackStateRef.current.calledFor === isShown) {\n return;\n }\n\n callbackStateRef.current.calledFor = isShown;\n if (isShown) {\n onOpen?.();\n } else {\n onClose?.();\n }\n }, [isShown, onOpen, onClose]);\n\n const transition = useTransition(isShown, transitionConfig);\n // WAI-Aria properties for the popout trigger, disabled if necessary\n const ariaProps = useMemo(\n () =>\n disableWrapperAria\n ? {}\n : {\n \"aria-expanded\": isShown,\n \"aria-haspopup\": ariaHasPopup ? ariaHasPopup : true,\n },\n [isShown, ariaHasPopup, disableWrapperAria]\n );\n\n // In cases where a controlled popout is used (e.g. props.isOpen is true), we need\n // to wait for the targetRef to receive a value before rendering the popout. Otherwise,\n // the Popout component renders, but doesn't know how to position itself due the\n // `refereElement` property being undefined.\n const [shouldRenderPopout, setShouldRenderPopout] = useState<boolean>( // Only trigger this shouldRenderPopout logic when using a controlled component.\n // The reason for that is because controlled components may render the popout\n // immediately before the targetRef has a value set to it.\n !isControlled\n );\n\n const childrenRef = (el: React.ElementRef<any> | HTMLElement) => {\n targetRef.current = el;\n\n if (targetRef.current) {\n setShouldRenderPopout(true);\n }\n };\n\n return (\n <React.Fragment>\n {typeof children === \"function\" ? (\n children({\n ref: childrenRef,\n toggle,\n show,\n hide,\n ariaProps,\n })\n ) : (\n <TargetWrapper {...qa} id={id} {...rest} ref={childrenRef}>\n {React.cloneElement(children, {\n ...ariaProps,\n ...(!isControlled\n ? {\n onClick: toggle,\n }\n : undefined),\n })}\n </TargetWrapper>\n )}\n {shouldRenderPopout &&\n !isInvalidContent &&\n transition(\n (transitionStyle, isVisible, transition) =>\n isVisible && (\n <PopoutComponentWrapper key={transition.key}>\n <Popper\n referenceElement={targetRef.current}\n placement={placement}\n modifiers={{\n preventOverflow: {\n boundariesElement: \"viewport\",\n },\n }}\n {...popperProps}\n >\n {({\n ref,\n style,\n placement,\n outOfBoundaries,\n scheduleUpdate,\n }) => {\n const interceptRef = (el: HTMLDivElement | undefined) => {\n popoutRef.current = el;\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n ref(el);\n };\n\n scheduleUpdateCallback.current = scheduleUpdate;\n scheduleUpdateRef(scheduleUpdate);\n\n return (\n <div\n ref={interceptRef}\n style={{\n ...style,\n zIndex,\n width:\n fullWidth && targetRef.current\n ? targetRef.current.offsetWidth\n : \"initial\",\n }}\n data-placement={placement}\n data-qa-popout=\"\"\n data-qa-popout-isopen={isOpen === true}\n // TODO: fix this type since `color` should be valid here. TS can't resolve the correct type.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n color={color}\n {...rest}\n >\n {isVisible && !outOfBoundaries && (\n <animated.div style={transitionStyle}>\n <FocusLock\n autoFocus={autoFocus}\n returnFocus={returnFocus}\n disabled={!focusOnContent}\n {...restFocusLockProps}\n >\n {typeof content === \"function\" &&\n content({\n hide,\n })}\n {typeof content !== \"function\" && content}\n </FocusLock>\n </animated.div>\n )}\n </div>\n );\n }}\n </Popper>\n </PopoutComponentWrapper>\n )\n )}\n </React.Fragment>\n );\n}\n\nconst PopoutContent = ({ children, ...rest }: TypeBoxProps) => (\n <Box\n bg=\"container.background.base\"\n color=\"text.body\"\n border={500}\n borderColor=\"container.border.base\"\n borderRadius=\"outer\"\n boxShadow=\"medium\"\n p={400}\n m={300}\n {...rest}\n >\n {children}\n </Box>\n);\n\nPopoutContent.displayName = \"Popout.Content\";\nPopout.Content = PopoutContent;\n\nexport default Popout;\n","import styled from \"styled-components\";\nimport { COMMON, LAYOUT } from \"@sproutsocial/seeds-react-system-props\";\n\nexport const TargetWrapper = styled.div`\n display: inline-block;\n ${COMMON}\n ${LAYOUT}\n`;\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport * as React from \"react\";\nimport type { PopperProps } from \"react-popper\";\nimport type {\n TypeSystemCommonProps,\n TypeSystemLayoutProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\n\nexport type EnumPlacements = Exclude<PopperProps[\"placement\"], undefined>;\n\nexport interface TypeFocusLockProps {\n disabled?: boolean;\n returnFocus?:\n | boolean\n | {\n preventScroll?: boolean;\n };\n persistentFocus?: boolean;\n autoFocus?: boolean;\n noFocusGuards?: boolean | \"tail\";\n group?: string;\n className?: string;\n onActivation?: (node: HTMLElement) => void;\n onDeactivation?: (node: HTMLElement) => void;\n as?: TypeStyledComponentsCommonProps[\"as\"];\n lockProps?: any;\n ref?: any;\n whiteList?: (activeElement: HTMLElement) => boolean;\n shards?: Array<any>;\n children?: React.ReactNode;\n}\n\nexport interface TypePopoutProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n TypeSystemLayoutProps,\n Omit<\n React.ComponentPropsWithoutRef<\"div\">,\n \"color\" | \"children\" | \"content\"\n > {\n /**\n * Whether Popout should automatically add aria-attributes to its wrapped elements\n */\n disableWrapperAria?: boolean;\n /**\n * Is the popout open? This prop is optional. By using it, you will lose some automatic handling of the logic for opening and closing the popout.\n */\n isOpen?: boolean;\n\n /**\n * If you use the isOpen prop you will need to pass a handler to change the state of the popout\n */\n setIsOpen?: (isOpen: boolean, event?: MouseEvent | KeyboardEvent) => void;\n\n /**\n * The content to be shown in the popout. If there is no content, just the children are rendered\n */\n content:\n | (React.ReactElement<any> | null | undefined)\n | (\n | ((opts: { hide: () => void }) => React.ReactElement<any>)\n | null\n | undefined\n );\n\n /**\n * The content that the popout should be attached to\n */\n children:\n | React.ReactElement<any>\n | ((opts: {\n ref: (arg0: React.ElementRef<any> | HTMLElement) => void;\n toggle: () => void;\n show: () => void;\n hide: () => void;\n ariaProps: Record<string, any>;\n }) => React.ReactNode);\n\n /** How the popped-out content should be placed, in relationship to the children */\n placement?: EnumPlacements;\n\n /**\n * Should the popped-out content inherit its width from the children?\n * This is useful for typeaheads and other places where a popout needs to match the width of a given element.\n */\n fullWidth?: boolean;\n\n /**\n * When the popout has opened, should we focus on its content?\n * Focus will be brought inside by looking for elements with [autofocus] first, [tabindex] second and buttons/links/other natively-focusable elements last.\n * Upon closing the popout, focus will be returned to the popout's target.\n * If nothing within your popout's content is focusable, this prop will do nothing.\n */\n focusOnContent?: boolean;\n qa?: Record<string, string>;\n zIndex?: number;\n\n /**\n * Override react-popper per the API documentation here: https://github.com/FezVrasta/react-popper#api-documentation\n */\n popperProps?: Partial<PopperProps>;\n onClose?: () => void;\n onOpen?: () => void;\n\n /**\n * And optional callback to receive the scheduleUpdate function.\n * Use the function to recalculate the popout position in relation to the contents.\n */\n scheduleUpdateRef?: (arg0: () => void) => void;\n\n /**\n * Mount the popout at the bottom of the DOM (using React.Portal) instead of inside the current DOM tree\n */\n appendToBody?: boolean;\n\n /**\n * Override `FocusLock` props, see the API documentation for more details: https://github.com/theKashey/react-focus-lock#api\n */\n focusLockProps?: TypeFocusLockProps;\n}\n","import Popout from \"./Popout\";\n\nexport default Popout;\nexport { Popout };\nexport * from \"./PopoutTypes\";\n"],"mappings":"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","names":["transition","placement"]}
package/dist/index.d.mts CHANGED
@@ -1,9 +1,10 @@
1
- import * as React from 'react';
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { TypeBoxProps } from '@sproutsocial/seeds-react-box';
3
+ import * as React from 'react';
3
4
  import { PopperProps } from 'react-popper';
4
5
  import { TypeStyledComponentsCommonProps, TypeSystemCommonProps, TypeSystemLayoutProps } from '@sproutsocial/seeds-react-system-props';
5
6
 
6
- type EnumPlacements = "auto" | "top" | "right" | "bottom" | "left" | "top-start" | "right-start" | "bottom-start" | "left-start" | "top-end" | "right-end" | "bottom-end" | "left-end";
7
+ type EnumPlacements = Exclude<PopperProps["placement"], undefined>;
7
8
  interface TypeFocusLockProps {
8
9
  disabled?: boolean;
9
10
  returnFocus?: boolean | {
@@ -89,10 +90,10 @@ interface TypePopoutProps extends TypeStyledComponentsCommonProps, TypeSystemCom
89
90
  focusLockProps?: TypeFocusLockProps;
90
91
  }
91
92
 
92
- declare function Popout({ isOpen, setIsOpen, content, children, placement, fullWidth, zIndex, focusOnContent, onOpen, onClose, qa, popperProps, scheduleUpdateRef, appendToBody, focusLockProps, color, "aria-haspopup": ariaHasPopup, disableWrapperAria, id, ...rest }: TypePopoutProps): React.JSX.Element;
93
+ declare function Popout({ isOpen, setIsOpen, content, children, placement, fullWidth, zIndex, focusOnContent, onOpen, onClose, qa, popperProps, scheduleUpdateRef, appendToBody, focusLockProps, color, "aria-haspopup": ariaHasPopup, disableWrapperAria, id, ...rest }: TypePopoutProps): react_jsx_runtime.JSX.Element;
93
94
  declare namespace Popout {
94
95
  var Content: {
95
- ({ children, ...rest }: TypeBoxProps): React.JSX.Element;
96
+ ({ children, ...rest }: TypeBoxProps): react_jsx_runtime.JSX.Element;
96
97
  displayName: string;
97
98
  };
98
99
  }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import * as React from 'react';
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { TypeBoxProps } from '@sproutsocial/seeds-react-box';
3
+ import * as React from 'react';
3
4
  import { PopperProps } from 'react-popper';
4
5
  import { TypeStyledComponentsCommonProps, TypeSystemCommonProps, TypeSystemLayoutProps } from '@sproutsocial/seeds-react-system-props';
5
6
 
6
- type EnumPlacements = "auto" | "top" | "right" | "bottom" | "left" | "top-start" | "right-start" | "bottom-start" | "left-start" | "top-end" | "right-end" | "bottom-end" | "left-end";
7
+ type EnumPlacements = Exclude<PopperProps["placement"], undefined>;
7
8
  interface TypeFocusLockProps {
8
9
  disabled?: boolean;
9
10
  returnFocus?: boolean | {
@@ -89,10 +90,10 @@ interface TypePopoutProps extends TypeStyledComponentsCommonProps, TypeSystemCom
89
90
  focusLockProps?: TypeFocusLockProps;
90
91
  }
91
92
 
92
- declare function Popout({ isOpen, setIsOpen, content, children, placement, fullWidth, zIndex, focusOnContent, onOpen, onClose, qa, popperProps, scheduleUpdateRef, appendToBody, focusLockProps, color, "aria-haspopup": ariaHasPopup, disableWrapperAria, id, ...rest }: TypePopoutProps): React.JSX.Element;
93
+ declare function Popout({ isOpen, setIsOpen, content, children, placement, fullWidth, zIndex, focusOnContent, onOpen, onClose, qa, popperProps, scheduleUpdateRef, appendToBody, focusLockProps, color, "aria-haspopup": ariaHasPopup, disableWrapperAria, id, ...rest }: TypePopoutProps): react_jsx_runtime.JSX.Element;
93
94
  declare namespace Popout {
94
95
  var Content: {
95
- ({ children, ...rest }: TypeBoxProps): React.JSX.Element;
96
+ ({ children, ...rest }: TypeBoxProps): react_jsx_runtime.JSX.Element;
96
97
  displayName: string;
97
98
  };
98
99
  }
package/dist/index.js CHANGED
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(src_exports);
38
38
  // src/Popout.tsx
39
39
  var React = __toESM(require("react"));
40
40
  var import_react = require("react");
41
- var import_react_spring = require("react-spring");
41
+ var import_web = require("@react-spring/web");
42
42
  var import_react_focus_lock = __toESM(require("react-focus-lock"));
43
43
  var import_react_popper = require("react-popper");
44
44
  var import_seeds_motion_unitless = require("@sproutsocial/seeds-motion/dist/seeds-motion-unitless");
@@ -56,6 +56,7 @@ var TargetWrapper = import_styled_components.default.div`
56
56
  `;
57
57
 
58
58
  // src/Popout.tsx
59
+ var import_jsx_runtime = require("react/jsx-runtime");
59
60
  var doesRefContainEventTarget = (ref, event) => {
60
61
  return ref.current && event.target instanceof Node && ref.current.contains(event.target);
61
62
  };
@@ -70,7 +71,10 @@ var transitionConfig = {
70
71
  opacity: 0
71
72
  },
72
73
  config: {
73
- duration: import_seeds_motion_unitless.MOTION_DURATION_FAST * 1e3
74
+ duration: (
75
+ // skip animation in test environment
76
+ process.env.NODE_ENV === "test" ? 0 : import_seeds_motion_unitless.MOTION_DURATION_FAST * 1e3
77
+ )
74
78
  }
75
79
  };
76
80
  function Popout({
@@ -102,12 +106,11 @@ function Popout({
102
106
  const isControlled = typeof isOpen === "boolean";
103
107
  const isShown = isControlled ? isOpen : isInternalShown;
104
108
  const setIsShown = (0, import_react.useMemo)(
105
- () => isControlled && setIsOpen ? setIsOpen : (nextIsShown) => setIsInternalShown(nextIsShown),
109
+ () => isControlled && setIsOpen ? setIsOpen : setIsInternalShown,
106
110
  [isControlled, setIsOpen]
107
111
  );
108
112
  const targetRef = (0, import_react.useRef)();
109
113
  const popoutRef = (0, import_react.useRef)();
110
- const isFirstRender = (0, import_react.useRef)(true);
111
114
  const scheduleUpdateCallback = (0, import_react.useRef)(() => {
112
115
  });
113
116
  (0, import_seeds_react_hooks.useMutationObserver)(
@@ -151,26 +154,19 @@ function Popout({
151
154
  };
152
155
  }
153
156
  }, [isShown, setIsShown]);
154
- (0, import_react.useEffect)(
155
- () => {
156
- if (isFirstRender.current) {
157
- isFirstRender.current = false;
158
- return;
159
- }
160
- if (!onOpen && !onClose) {
161
- return;
162
- }
163
- if (isShown && onOpen) {
164
- onOpen();
165
- }
166
- if (!isShown && onClose) {
167
- onClose();
168
- }
169
- },
170
- // eslint-disable-next-line
171
- [isShown]
172
- );
173
- const transitions = (0, import_react_spring.useTransition)(isShown, null, transitionConfig);
157
+ const callbackStateRef = (0, import_react.useRef)({ calledFor: isShown });
158
+ (0, import_react.useEffect)(() => {
159
+ if (callbackStateRef.current.calledFor === isShown) {
160
+ return;
161
+ }
162
+ callbackStateRef.current.calledFor = isShown;
163
+ if (isShown) {
164
+ onOpen?.();
165
+ } else {
166
+ onClose?.();
167
+ }
168
+ }, [isShown, onOpen, onClose]);
169
+ const transition = (0, import_web.useTransition)(isShown, transitionConfig);
174
170
  const ariaProps = (0, import_react.useMemo)(
175
171
  () => disableWrapperAria ? {} : {
176
172
  "aria-expanded": isShown,
@@ -190,77 +186,82 @@ function Popout({
190
186
  setShouldRenderPopout(true);
191
187
  }
192
188
  };
193
- return /* @__PURE__ */ React.createElement(React.Fragment, null, typeof children === "function" ? children({
194
- ref: childrenRef,
195
- toggle,
196
- show,
197
- hide,
198
- ariaProps
199
- }) : /* @__PURE__ */ React.createElement(TargetWrapper, { ...qa, id, ...rest, ref: childrenRef }, React.cloneElement(children, {
200
- ...ariaProps,
201
- ...!isControlled ? {
202
- onClick: toggle
203
- } : void 0
204
- })), shouldRenderPopout && !isInvalidContent && transitions.map(
205
- ({ item, key, props }) => item && /* @__PURE__ */ React.createElement(PopoutComponentWrapper, { key }, /* @__PURE__ */ React.createElement(
206
- import_react_popper.Popper,
207
- {
208
- referenceElement: targetRef.current,
209
- placement,
210
- modifiers: {
211
- preventOverflow: {
212
- boundariesElement: "viewport"
213
- }
214
- },
215
- ...popperProps
216
- },
217
- ({
218
- ref,
219
- style,
220
- placement: placement2,
221
- outOfBoundaries,
222
- scheduleUpdate
223
- }) => {
224
- const interceptRef = (el) => {
225
- popoutRef.current = el;
226
- ref(el);
227
- };
228
- scheduleUpdateCallback.current = scheduleUpdate;
229
- scheduleUpdateRef(scheduleUpdate);
230
- return /* @__PURE__ */ React.createElement(
231
- "div",
232
- {
233
- ref: interceptRef,
234
- style: {
235
- ...style,
236
- zIndex,
237
- width: fullWidth && targetRef.current ? targetRef.current.offsetWidth : "initial"
238
- },
239
- "data-placement": placement2,
240
- "data-qa-popout": "",
241
- "data-qa-popout-isopen": isOpen === true,
242
- color,
243
- ...rest
189
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(React.Fragment, { children: [
190
+ typeof children === "function" ? children({
191
+ ref: childrenRef,
192
+ toggle,
193
+ show,
194
+ hide,
195
+ ariaProps
196
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TargetWrapper, { ...qa, id, ...rest, ref: childrenRef, children: React.cloneElement(children, {
197
+ ...ariaProps,
198
+ ...!isControlled ? {
199
+ onClick: toggle
200
+ } : void 0
201
+ }) }),
202
+ shouldRenderPopout && !isInvalidContent && transition(
203
+ (transitionStyle, isVisible, transition2) => isVisible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopoutComponentWrapper, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
204
+ import_react_popper.Popper,
205
+ {
206
+ referenceElement: targetRef.current,
207
+ placement,
208
+ modifiers: {
209
+ preventOverflow: {
210
+ boundariesElement: "viewport"
211
+ }
244
212
  },
245
- item && !outOfBoundaries && /* @__PURE__ */ React.createElement(import_react_spring.animated.div, { style: props }, /* @__PURE__ */ React.createElement(
246
- import_react_focus_lock.default,
247
- {
248
- autoFocus,
249
- returnFocus,
250
- disabled: !focusOnContent,
251
- ...restFocusLockProps
252
- },
253
- typeof content === "function" && content({
254
- hide
255
- }),
256
- typeof content !== "function" && content
257
- ))
258
- );
259
- }
260
- ))
261
- ));
213
+ ...popperProps,
214
+ children: ({
215
+ ref,
216
+ style,
217
+ placement: placement2,
218
+ outOfBoundaries,
219
+ scheduleUpdate
220
+ }) => {
221
+ const interceptRef = (el) => {
222
+ popoutRef.current = el;
223
+ ref(el);
224
+ };
225
+ scheduleUpdateCallback.current = scheduleUpdate;
226
+ scheduleUpdateRef(scheduleUpdate);
227
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
228
+ "div",
229
+ {
230
+ ref: interceptRef,
231
+ style: {
232
+ ...style,
233
+ zIndex,
234
+ width: fullWidth && targetRef.current ? targetRef.current.offsetWidth : "initial"
235
+ },
236
+ "data-placement": placement2,
237
+ "data-qa-popout": "",
238
+ "data-qa-popout-isopen": isOpen === true,
239
+ color,
240
+ ...rest,
241
+ children: isVisible && !outOfBoundaries && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_web.animated.div, { style: transitionStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
242
+ import_react_focus_lock.default,
243
+ {
244
+ autoFocus,
245
+ returnFocus,
246
+ disabled: !focusOnContent,
247
+ ...restFocusLockProps,
248
+ children: [
249
+ typeof content === "function" && content({
250
+ hide
251
+ }),
252
+ typeof content !== "function" && content
253
+ ]
254
+ }
255
+ ) })
256
+ }
257
+ );
258
+ }
259
+ }
260
+ ) }, transition2.key)
261
+ )
262
+ ] });
262
263
  }
263
- var PopoutContent = ({ children, ...rest }) => /* @__PURE__ */ React.createElement(
264
+ var PopoutContent = ({ children, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
264
265
  import_seeds_react_box.default,
265
266
  {
266
267
  bg: "container.background.base",
@@ -271,14 +272,17 @@ var PopoutContent = ({ children, ...rest }) => /* @__PURE__ */ React.createEleme
271
272
  boxShadow: "medium",
272
273
  p: 400,
273
274
  m: 300,
274
- ...rest
275
- },
276
- children
275
+ ...rest,
276
+ children
277
+ }
277
278
  );
278
279
  PopoutContent.displayName = "Popout.Content";
279
280
  Popout.Content = PopoutContent;
280
281
  var Popout_default = Popout;
281
282
 
283
+ // src/PopoutTypes.ts
284
+ var React2 = require("react");
285
+
282
286
  // src/index.ts
283
287
  var src_default = Popout_default;
284
288
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Popout.tsx","../src/styles.ts"],"sourcesContent":["import Popout from \"./Popout\";\n\nexport default Popout;\nexport { Popout };\nexport * from \"./PopoutTypes\";\n","import * as React from \"react\";\nimport { useState, useEffect, useRef, useCallback, useMemo } from \"react\";\nimport { useTransition, animated } from \"react-spring\";\nimport FocusLock from \"react-focus-lock\";\nimport { Popper } from \"react-popper\";\nimport { MOTION_DURATION_FAST } from \"@sproutsocial/seeds-motion/dist/seeds-motion-unitless\";\nimport { useMutationObserver } from \"@sproutsocial/seeds-react-hooks\";\nimport Portal from \"@sproutsocial/seeds-react-portal\";\nimport Box, { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport { TargetWrapper } from \"./styles\";\nimport type { TypePopoutProps, EnumPlacements } from \"./PopoutTypes\";\n\nexport const placements: { [key: string]: EnumPlacements } = {\n auto: \"auto\",\n\n top: \"top\",\n right: \"right\",\n bottom: \"bottom\",\n left: \"left\",\n\n \"top-start\": \"top-start\",\n \"right-start\": \"right-start\",\n \"bottom-start\": \"bottom-start\",\n \"left-start\": \"left-start\",\n\n \"top-end\": \"top-end\",\n \"right-end\": \"right-end\",\n \"bottom-end\": \"bottom-end\",\n \"left-end\": \"left-end\",\n};\n\nconst doesRefContainEventTarget = (ref, event) => {\n return (\n ref.current &&\n event.target instanceof Node &&\n ref.current.contains(event.target)\n );\n};\n\n// Transition definitions for fading in and out\nconst transitionConfig = {\n from: {\n opacity: 0,\n },\n enter: {\n opacity: 1,\n },\n leave: {\n opacity: 0,\n },\n config: {\n duration: MOTION_DURATION_FAST * 1000,\n },\n};\n\nexport function Popout({\n isOpen,\n setIsOpen,\n content,\n children,\n placement = \"auto\",\n fullWidth = false,\n zIndex = 7,\n focusOnContent = true,\n onOpen,\n onClose,\n qa = {},\n popperProps,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n scheduleUpdateRef = () => {},\n appendToBody = true,\n focusLockProps = {},\n color,\n \"aria-haspopup\": ariaHasPopup,\n disableWrapperAria = false,\n id,\n ...rest\n}: TypePopoutProps) {\n const PopoutComponentWrapper = appendToBody ? Portal : React.Fragment;\n const [isInternalShown, setIsInternalShown] = useState<boolean>(false);\n const isControlled = typeof isOpen === \"boolean\";\n const isShown = isControlled ? isOpen : isInternalShown;\n\n const setIsShown = useMemo(\n () =>\n isControlled && setIsOpen\n ? setIsOpen\n : (nextIsShown) => setIsInternalShown(nextIsShown),\n [isControlled, setIsOpen]\n );\n\n const targetRef = useRef<HTMLDivElement>();\n const popoutRef = useRef<HTMLDivElement>();\n const isFirstRender = useRef(true);\n\n // This callback will automatically trigger a recalculation of the popout position if the content is changed\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n const scheduleUpdateCallback = useRef(() => {});\n\n useMutationObserver(\n popoutRef.current ?? null,\n {\n childList: true,\n characterData: true,\n subtree: true,\n },\n scheduleUpdateCallback.current\n );\n\n const {\n autoFocus = true,\n returnFocus = true,\n ...restFocusLockProps\n } = focusLockProps;\n\n const isInvalidContent = content === null || content === undefined;\n\n // Callbacks for showing, hiding, and toggling visibility of the popout\n // (Not used when isOpen is passed explicitly)\n const show = useCallback(() => setIsShown(true), [setIsShown]);\n const hide = useCallback(() => setIsShown(false), [setIsShown]);\n const toggle = useCallback(() => setIsShown(!isShown), [isShown, setIsShown]);\n\n useEffect(() => {\n const documentBody = document.body;\n\n if (isShown && documentBody) {\n // Callback passed to a click handler attached to document.body,\n // allowing user to close the popout by clicking outside\n const bodyClick = (e: MouseEvent): void => {\n if (\n doesRefContainEventTarget(targetRef, e) ||\n doesRefContainEventTarget(popoutRef, e)\n ) {\n return;\n }\n\n setIsShown(false, e);\n };\n\n // Callback for allowing user to close by keying \"esc\"\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n // stop propagation to avoid interacting with other components when popout is shown\n // ie if we have a popout shown in a modal and hit esc, we don't want to close both the popout and modal\n e.stopPropagation();\n setIsShown(false, e);\n }\n };\n\n documentBody.addEventListener(\"click\", bodyClick, { capture: true });\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n return () => {\n documentBody.removeEventListener(\"click\", bodyClick, { capture: true });\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n };\n }\n }, [isShown, setIsShown]);\n\n // Manage onOpen and onClose callbacks\n useEffect(\n () => {\n // Don't fire onClose on the first render\n if (isFirstRender.current) {\n isFirstRender.current = false;\n return;\n }\n\n if (!onOpen && !onClose) {\n return;\n }\n\n if (isShown && onOpen) {\n onOpen();\n }\n\n if (!isShown && onClose) {\n onClose();\n }\n },\n // eslint-disable-next-line\n [isShown]\n );\n\n const transitions = useTransition(isShown, null, transitionConfig);\n // WAI-Aria properties for the popout trigger, disabled if necessary\n const ariaProps = useMemo(\n () =>\n disableWrapperAria\n ? {}\n : {\n \"aria-expanded\": isShown,\n \"aria-haspopup\": ariaHasPopup ? ariaHasPopup : true,\n },\n [isShown, ariaHasPopup, disableWrapperAria]\n );\n\n // In cases where a controlled popout is used (e.g. props.isOpen is true), we need\n // to wait for the targetRef to receive a value before rendering the popout. Otherwise,\n // the Popout component renders, but doesn't know how to position itself due the\n // `refereElement` property being undefined.\n const [shouldRenderPopout, setShouldRenderPopout] = useState<boolean>( // Only trigger this shouldRenderPopout logic when using a controlled component.\n // The reason for that is because controlled components may render the popout\n // immediately before the targetRef has a value set to it.\n !isControlled\n );\n\n const childrenRef = (el) => {\n targetRef.current = el;\n\n if (targetRef.current) {\n setShouldRenderPopout(true);\n }\n };\n\n return (\n <React.Fragment>\n {typeof children === \"function\" ? (\n children({\n ref: childrenRef,\n toggle,\n show,\n hide,\n ariaProps,\n })\n ) : (\n <TargetWrapper {...qa} id={id} {...rest} ref={childrenRef}>\n {React.cloneElement(children, {\n ...ariaProps,\n ...(!isControlled\n ? {\n onClick: toggle,\n }\n : undefined),\n })}\n </TargetWrapper>\n )}\n {shouldRenderPopout &&\n !isInvalidContent &&\n transitions.map(\n ({ item, key, props }) =>\n item && (\n <PopoutComponentWrapper key={key}>\n <Popper\n referenceElement={targetRef.current}\n placement={placement}\n modifiers={{\n preventOverflow: {\n boundariesElement: \"viewport\",\n },\n }}\n {...popperProps}\n >\n {({\n ref,\n style,\n placement,\n outOfBoundaries,\n scheduleUpdate,\n }) => {\n const interceptRef = (el) => {\n popoutRef.current = el;\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n ref(el);\n };\n\n scheduleUpdateCallback.current = scheduleUpdate;\n scheduleUpdateRef(scheduleUpdate);\n\n return (\n <div\n ref={interceptRef}\n style={{\n ...style,\n zIndex,\n width:\n fullWidth && targetRef.current\n ? targetRef.current.offsetWidth\n : \"initial\",\n }}\n data-placement={placement}\n data-qa-popout=\"\"\n data-qa-popout-isopen={isOpen === true}\n // TODO: fix this type since `color` should be valid here. TS can't resolve the correct type.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n color={color}\n {...rest}\n >\n {item && !outOfBoundaries && (\n <animated.div style={props}>\n <FocusLock\n autoFocus={autoFocus}\n returnFocus={returnFocus}\n disabled={!focusOnContent}\n {...restFocusLockProps}\n >\n {typeof content === \"function\" &&\n content({\n hide,\n })}\n {typeof content !== \"function\" && content}\n </FocusLock>\n </animated.div>\n )}\n </div>\n );\n }}\n </Popper>\n </PopoutComponentWrapper>\n )\n )}\n </React.Fragment>\n );\n}\n\nconst PopoutContent = ({ children, ...rest }: TypeBoxProps) => (\n <Box\n bg=\"container.background.base\"\n color=\"text.body\"\n border={500}\n borderColor=\"container.border.base\"\n borderRadius=\"outer\"\n boxShadow=\"medium\"\n p={400}\n m={300}\n {...rest}\n >\n {children}\n </Box>\n);\n\nPopoutContent.displayName = \"Popout.Content\";\nPopout.Content = PopoutContent;\n\nexport default Popout;\n","import styled from \"styled-components\";\nimport { COMMON, LAYOUT } from \"@sproutsocial/seeds-react-system-props\";\n\nexport const TargetWrapper = styled.div`\n display: inline-block;\n ${COMMON}\n ${LAYOUT}\n`;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AACvB,mBAAkE;AAClE,0BAAwC;AACxC,8BAAsB;AACtB,0BAAuB;AACvB,mCAAqC;AACrC,+BAAoC;AACpC,gCAAmB;AACnB,6BAAkC;;;ACRlC,+BAAmB;AACnB,sCAA+B;AAExB,IAAM,gBAAgB,yBAAAA,QAAO;AAAA;AAAA,IAEhC,sCAAM;AAAA,IACN,sCAAM;AAAA;;;ADyBV,IAAM,4BAA4B,CAAC,KAAK,UAAU;AAChD,SACE,IAAI,WACJ,MAAM,kBAAkB,QACxB,IAAI,QAAQ,SAAS,MAAM,MAAM;AAErC;AAGA,IAAM,mBAAmB;AAAA,EACvB,MAAM;AAAA,IACJ,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,UAAU,oDAAuB;AAAA,EACnC;AACF;AAEO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA,KAAK,CAAC;AAAA,EACN;AAAA;AAAA,EAEA,oBAAoB,MAAM;AAAA,EAAC;AAAA,EAC3B,eAAe;AAAA,EACf,iBAAiB,CAAC;AAAA,EAClB;AAAA,EACA,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB;AAAA,EACA,GAAG;AACL,GAAoB;AAClB,QAAM,yBAAyB,eAAe,0BAAAC,UAAe;AAC7D,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAAkB,KAAK;AACrE,QAAM,eAAe,OAAO,WAAW;AACvC,QAAM,UAAU,eAAe,SAAS;AAExC,QAAM,iBAAa;AAAA,IACjB,MACE,gBAAgB,YACZ,YACA,CAAC,gBAAgB,mBAAmB,WAAW;AAAA,IACrD,CAAC,cAAc,SAAS;AAAA,EAC1B;AAEA,QAAM,gBAAY,qBAAuB;AACzC,QAAM,gBAAY,qBAAuB;AACzC,QAAM,oBAAgB,qBAAO,IAAI;AAIjC,QAAM,6BAAyB,qBAAO,MAAM;AAAA,EAAC,CAAC;AAE9C;AAAA,IACE,UAAU,WAAW;AAAA,IACrB;AAAA,MACE,WAAW;AAAA,MACX,eAAe;AAAA,MACf,SAAS;AAAA,IACX;AAAA,IACA,uBAAuB;AAAA,EACzB;AAEA,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,mBAAmB,YAAY,QAAQ,YAAY;AAIzD,QAAM,WAAO,0BAAY,MAAM,WAAW,IAAI,GAAG,CAAC,UAAU,CAAC;AAC7D,QAAM,WAAO,0BAAY,MAAM,WAAW,KAAK,GAAG,CAAC,UAAU,CAAC;AAC9D,QAAM,aAAS,0BAAY,MAAM,WAAW,CAAC,OAAO,GAAG,CAAC,SAAS,UAAU,CAAC;AAE5E,8BAAU,MAAM;AACd,UAAM,eAAe,SAAS;AAE9B,QAAI,WAAW,cAAc;AAG3B,YAAM,YAAY,CAAC,MAAwB;AACzC,YACE,0BAA0B,WAAW,CAAC,KACtC,0BAA0B,WAAW,CAAC,GACtC;AACA;AAAA,QACF;AAEA,mBAAW,OAAO,CAAC;AAAA,MACrB;AAGA,YAAM,QAAQ,CAAC,MAA2B;AAExC,YAAI,CAAC,UAAU,KAAK,EAAE,SAAS,EAAE,GAAG,GAAG;AAGrC,YAAE,gBAAgB;AAClB,qBAAW,OAAO,CAAC;AAAA,QACrB;AAAA,MACF;AAEA,mBAAa,iBAAiB,SAAS,WAAW,EAAE,SAAS,KAAK,CAAC;AACnE,mBAAa,iBAAiB,WAAW,OAAO,EAAE,SAAS,KAAK,CAAC;AACjE,aAAO,MAAM;AACX,qBAAa,oBAAoB,SAAS,WAAW,EAAE,SAAS,KAAK,CAAC;AACtE,qBAAa,oBAAoB,WAAW,OAAO,EAAE,SAAS,KAAK,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,UAAU,CAAC;AAGxB;AAAA,IACE,MAAM;AAEJ,UAAI,cAAc,SAAS;AACzB,sBAAc,UAAU;AACxB;AAAA,MACF;AAEA,UAAI,CAAC,UAAU,CAAC,SAAS;AACvB;AAAA,MACF;AAEA,UAAI,WAAW,QAAQ;AACrB,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,WAAW,SAAS;AACvB,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA;AAAA,IAEA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,kBAAc,mCAAc,SAAS,MAAM,gBAAgB;AAEjE,QAAM,gBAAY;AAAA,IAChB,MACE,qBACI,CAAC,IACD;AAAA,MACE,iBAAiB;AAAA,MACjB,iBAAiB,eAAe,eAAe;AAAA,IACjD;AAAA,IACN,CAAC,SAAS,cAAc,kBAAkB;AAAA,EAC5C;AAMA,QAAM,CAAC,oBAAoB,qBAAqB,QAAI;AAAA;AAAA;AAAA;AAAA,IAGlD,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,CAAC,OAAO;AAC1B,cAAU,UAAU;AAEpB,QAAI,UAAU,SAAS;AACrB,4BAAsB,IAAI;AAAA,IAC5B;AAAA,EACF;AAEA,SACE,oCAAO,gBAAN,MACE,OAAO,aAAa,aACnB,SAAS;AAAA,IACP,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC,IAED,oCAAC,iBAAe,GAAG,IAAI,IAAS,GAAG,MAAM,KAAK,eACrC,mBAAa,UAAU;AAAA,IAC5B,GAAG;AAAA,IACH,GAAI,CAAC,eACD;AAAA,MACE,SAAS;AAAA,IACX,IACA;AAAA,EACN,CAAC,CACH,GAED,sBACC,CAAC,oBACD,YAAY;AAAA,IACV,CAAC,EAAE,MAAM,KAAK,MAAM,MAClB,QACE,oCAAC,0BAAuB,OACtB;AAAA,MAAC;AAAA;AAAA,QACC,kBAAkB,UAAU;AAAA,QAC5B;AAAA,QACA,WAAW;AAAA,UACT,iBAAiB;AAAA,YACf,mBAAmB;AAAA,UACrB;AAAA,QACF;AAAA,QACC,GAAG;AAAA;AAAA,MAEH,CAAC;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAAC;AAAA,QACA;AAAA,QACA;AAAA,MACF,MAAM;AACJ,cAAM,eAAe,CAAC,OAAO;AAC3B,oBAAU,UAAU;AAGpB,cAAI,EAAE;AAAA,QACR;AAEA,+BAAuB,UAAU;AACjC,0BAAkB,cAAc;AAEhC,eACE;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,OAAO;AAAA,cACL,GAAG;AAAA,cACH;AAAA,cACA,OACE,aAAa,UAAU,UACnB,UAAU,QAAQ,cAClB;AAAA,YACR;AAAA,YACA,kBAAgBA;AAAA,YAChB,kBAAe;AAAA,YACf,yBAAuB,WAAW;AAAA,YAIlC;AAAA,YACC,GAAG;AAAA;AAAA,UAEH,QAAQ,CAAC,mBACR,oCAAC,6BAAS,KAAT,EAAa,OAAO,SACnB;AAAA,YAAC,wBAAAC;AAAA,YAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA,UAAU,CAAC;AAAA,cACV,GAAG;AAAA;AAAA,YAEH,OAAO,YAAY,cAClB,QAAQ;AAAA,cACN;AAAA,YACF,CAAC;AAAA,YACF,OAAO,YAAY,cAAc;AAAA,UACpC,CACF;AAAA,QAEJ;AAAA,MAEJ;AAAA,IACF,CACF;AAAA,EAEN,CACJ;AAEJ;AAEA,IAAM,gBAAgB,CAAC,EAAE,UAAU,GAAG,KAAK,MACzC;AAAA,EAAC,uBAAAC;AAAA,EAAA;AAAA,IACC,IAAG;AAAA,IACH,OAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAY;AAAA,IACZ,cAAa;AAAA,IACb,WAAU;AAAA,IACV,GAAG;AAAA,IACH,GAAG;AAAA,IACF,GAAG;AAAA;AAAA,EAEH;AACH;AAGF,cAAc,cAAc;AAC5B,OAAO,UAAU;AAEjB,IAAO,iBAAQ;;;AD/Uf,IAAO,cAAQ;","names":["styled","Portal","placement","FocusLock","Box"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Popout.tsx","../src/styles.ts","../src/PopoutTypes.ts"],"sourcesContent":["import Popout from \"./Popout\";\n\nexport default Popout;\nexport { Popout };\nexport * from \"./PopoutTypes\";\n","import * as React from \"react\";\nimport { useState, useEffect, useRef, useCallback, useMemo } from \"react\";\nimport { useTransition, animated } from \"@react-spring/web\";\nimport FocusLock from \"react-focus-lock\";\nimport { Popper } from \"react-popper\";\nimport { MOTION_DURATION_FAST } from \"@sproutsocial/seeds-motion/dist/seeds-motion-unitless\";\nimport { useMutationObserver } from \"@sproutsocial/seeds-react-hooks\";\nimport Portal from \"@sproutsocial/seeds-react-portal\";\nimport Box, { type TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport { TargetWrapper } from \"./styles\";\nimport type { TypePopoutProps } from \"./PopoutTypes\";\n\nconst doesRefContainEventTarget = (\n ref: React.MutableRefObject<HTMLDivElement | undefined>,\n event: MouseEvent\n) => {\n return (\n ref.current &&\n event.target instanceof Node &&\n ref.current.contains(event.target)\n );\n};\n\n// Transition definitions for fading in and out\nconst transitionConfig = {\n from: {\n opacity: 0,\n },\n enter: {\n opacity: 1,\n },\n leave: {\n opacity: 0,\n },\n config: {\n duration:\n // skip animation in test environment\n process.env.NODE_ENV === \"test\" ? 0 : MOTION_DURATION_FAST * 1000,\n },\n};\n\nexport function Popout({\n isOpen,\n setIsOpen,\n content,\n children,\n placement = \"auto\",\n fullWidth = false,\n zIndex = 7,\n focusOnContent = true,\n onOpen,\n onClose,\n qa = {},\n popperProps,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n scheduleUpdateRef = () => {},\n appendToBody = true,\n focusLockProps = {},\n color,\n \"aria-haspopup\": ariaHasPopup,\n disableWrapperAria = false,\n id,\n ...rest\n}: TypePopoutProps) {\n const PopoutComponentWrapper = appendToBody ? Portal : React.Fragment;\n const [isInternalShown, setIsInternalShown] = useState<boolean>(false);\n const isControlled = typeof isOpen === \"boolean\";\n const isShown = isControlled ? isOpen : isInternalShown;\n\n const setIsShown = useMemo(\n () => (isControlled && setIsOpen ? setIsOpen : setIsInternalShown),\n [isControlled, setIsOpen]\n );\n\n const targetRef = useRef<HTMLElement | any>();\n const popoutRef = useRef<HTMLDivElement>();\n\n // This callback will automatically trigger a recalculation of the popout position if the content is changed\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n const scheduleUpdateCallback = useRef(() => {});\n\n useMutationObserver(\n popoutRef.current ?? null,\n {\n childList: true,\n characterData: true,\n subtree: true,\n },\n scheduleUpdateCallback.current\n );\n\n const {\n autoFocus = true,\n returnFocus = true,\n ...restFocusLockProps\n } = focusLockProps;\n\n const isInvalidContent = content === null || content === undefined;\n\n // Callbacks for showing, hiding, and toggling visibility of the popout\n // (Not used when isOpen is passed explicitly)\n const show = useCallback(() => setIsShown(true), [setIsShown]);\n const hide = useCallback(() => setIsShown(false), [setIsShown]);\n const toggle = useCallback(() => setIsShown(!isShown), [isShown, setIsShown]);\n\n useEffect(() => {\n const documentBody = document.body;\n\n if (isShown && documentBody) {\n // Callback passed to a click handler attached to document.body,\n // allowing user to close the popout by clicking outside\n const bodyClick = (e: MouseEvent): void => {\n if (\n doesRefContainEventTarget(targetRef, e) ||\n doesRefContainEventTarget(popoutRef, e)\n ) {\n return;\n }\n\n setIsShown(false, e);\n };\n\n // Callback for allowing user to close by keying \"esc\"\n const onEsc = (e: KeyboardEvent): void => {\n // older browsers use \"Esc\"\n if ([\"Escape\", \"Esc\"].includes(e.key)) {\n // stop propagation to avoid interacting with other components when popout is shown\n // ie if we have a popout shown in a modal and hit esc, we don't want to close both the popout and modal\n e.stopPropagation();\n setIsShown(false, e);\n }\n };\n\n documentBody.addEventListener(\"click\", bodyClick, { capture: true });\n documentBody.addEventListener(\"keydown\", onEsc, { capture: true });\n return () => {\n documentBody.removeEventListener(\"click\", bodyClick, { capture: true });\n documentBody.removeEventListener(\"keydown\", onEsc, { capture: true });\n };\n }\n }, [isShown, setIsShown]);\n\n const callbackStateRef = useRef({ calledFor: isShown });\n useEffect(() => {\n if (callbackStateRef.current.calledFor === isShown) {\n return;\n }\n\n callbackStateRef.current.calledFor = isShown;\n if (isShown) {\n onOpen?.();\n } else {\n onClose?.();\n }\n }, [isShown, onOpen, onClose]);\n\n const transition = useTransition(isShown, transitionConfig);\n // WAI-Aria properties for the popout trigger, disabled if necessary\n const ariaProps = useMemo(\n () =>\n disableWrapperAria\n ? {}\n : {\n \"aria-expanded\": isShown,\n \"aria-haspopup\": ariaHasPopup ? ariaHasPopup : true,\n },\n [isShown, ariaHasPopup, disableWrapperAria]\n );\n\n // In cases where a controlled popout is used (e.g. props.isOpen is true), we need\n // to wait for the targetRef to receive a value before rendering the popout. Otherwise,\n // the Popout component renders, but doesn't know how to position itself due the\n // `refereElement` property being undefined.\n const [shouldRenderPopout, setShouldRenderPopout] = useState<boolean>( // Only trigger this shouldRenderPopout logic when using a controlled component.\n // The reason for that is because controlled components may render the popout\n // immediately before the targetRef has a value set to it.\n !isControlled\n );\n\n const childrenRef = (el: React.ElementRef<any> | HTMLElement) => {\n targetRef.current = el;\n\n if (targetRef.current) {\n setShouldRenderPopout(true);\n }\n };\n\n return (\n <React.Fragment>\n {typeof children === \"function\" ? (\n children({\n ref: childrenRef,\n toggle,\n show,\n hide,\n ariaProps,\n })\n ) : (\n <TargetWrapper {...qa} id={id} {...rest} ref={childrenRef}>\n {React.cloneElement(children, {\n ...ariaProps,\n ...(!isControlled\n ? {\n onClick: toggle,\n }\n : undefined),\n })}\n </TargetWrapper>\n )}\n {shouldRenderPopout &&\n !isInvalidContent &&\n transition(\n (transitionStyle, isVisible, transition) =>\n isVisible && (\n <PopoutComponentWrapper key={transition.key}>\n <Popper\n referenceElement={targetRef.current}\n placement={placement}\n modifiers={{\n preventOverflow: {\n boundariesElement: \"viewport\",\n },\n }}\n {...popperProps}\n >\n {({\n ref,\n style,\n placement,\n outOfBoundaries,\n scheduleUpdate,\n }) => {\n const interceptRef = (el: HTMLDivElement | undefined) => {\n popoutRef.current = el;\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n ref(el);\n };\n\n scheduleUpdateCallback.current = scheduleUpdate;\n scheduleUpdateRef(scheduleUpdate);\n\n return (\n <div\n ref={interceptRef}\n style={{\n ...style,\n zIndex,\n width:\n fullWidth && targetRef.current\n ? targetRef.current.offsetWidth\n : \"initial\",\n }}\n data-placement={placement}\n data-qa-popout=\"\"\n data-qa-popout-isopen={isOpen === true}\n // TODO: fix this type since `color` should be valid here. TS can't resolve the correct type.\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n color={color}\n {...rest}\n >\n {isVisible && !outOfBoundaries && (\n <animated.div style={transitionStyle}>\n <FocusLock\n autoFocus={autoFocus}\n returnFocus={returnFocus}\n disabled={!focusOnContent}\n {...restFocusLockProps}\n >\n {typeof content === \"function\" &&\n content({\n hide,\n })}\n {typeof content !== \"function\" && content}\n </FocusLock>\n </animated.div>\n )}\n </div>\n );\n }}\n </Popper>\n </PopoutComponentWrapper>\n )\n )}\n </React.Fragment>\n );\n}\n\nconst PopoutContent = ({ children, ...rest }: TypeBoxProps) => (\n <Box\n bg=\"container.background.base\"\n color=\"text.body\"\n border={500}\n borderColor=\"container.border.base\"\n borderRadius=\"outer\"\n boxShadow=\"medium\"\n p={400}\n m={300}\n {...rest}\n >\n {children}\n </Box>\n);\n\nPopoutContent.displayName = \"Popout.Content\";\nPopout.Content = PopoutContent;\n\nexport default Popout;\n","import styled from \"styled-components\";\nimport { COMMON, LAYOUT } from \"@sproutsocial/seeds-react-system-props\";\n\nexport const TargetWrapper = styled.div`\n display: inline-block;\n ${COMMON}\n ${LAYOUT}\n`;\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport * as React from \"react\";\nimport type { PopperProps } from \"react-popper\";\nimport type {\n TypeSystemCommonProps,\n TypeSystemLayoutProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\n\nexport type EnumPlacements = Exclude<PopperProps[\"placement\"], undefined>;\n\nexport interface TypeFocusLockProps {\n disabled?: boolean;\n returnFocus?:\n | boolean\n | {\n preventScroll?: boolean;\n };\n persistentFocus?: boolean;\n autoFocus?: boolean;\n noFocusGuards?: boolean | \"tail\";\n group?: string;\n className?: string;\n onActivation?: (node: HTMLElement) => void;\n onDeactivation?: (node: HTMLElement) => void;\n as?: TypeStyledComponentsCommonProps[\"as\"];\n lockProps?: any;\n ref?: any;\n whiteList?: (activeElement: HTMLElement) => boolean;\n shards?: Array<any>;\n children?: React.ReactNode;\n}\n\nexport interface TypePopoutProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n TypeSystemLayoutProps,\n Omit<\n React.ComponentPropsWithoutRef<\"div\">,\n \"color\" | \"children\" | \"content\"\n > {\n /**\n * Whether Popout should automatically add aria-attributes to its wrapped elements\n */\n disableWrapperAria?: boolean;\n /**\n * Is the popout open? This prop is optional. By using it, you will lose some automatic handling of the logic for opening and closing the popout.\n */\n isOpen?: boolean;\n\n /**\n * If you use the isOpen prop you will need to pass a handler to change the state of the popout\n */\n setIsOpen?: (isOpen: boolean, event?: MouseEvent | KeyboardEvent) => void;\n\n /**\n * The content to be shown in the popout. If there is no content, just the children are rendered\n */\n content:\n | (React.ReactElement<any> | null | undefined)\n | (\n | ((opts: { hide: () => void }) => React.ReactElement<any>)\n | null\n | undefined\n );\n\n /**\n * The content that the popout should be attached to\n */\n children:\n | React.ReactElement<any>\n | ((opts: {\n ref: (arg0: React.ElementRef<any> | HTMLElement) => void;\n toggle: () => void;\n show: () => void;\n hide: () => void;\n ariaProps: Record<string, any>;\n }) => React.ReactNode);\n\n /** How the popped-out content should be placed, in relationship to the children */\n placement?: EnumPlacements;\n\n /**\n * Should the popped-out content inherit its width from the children?\n * This is useful for typeaheads and other places where a popout needs to match the width of a given element.\n */\n fullWidth?: boolean;\n\n /**\n * When the popout has opened, should we focus on its content?\n * Focus will be brought inside by looking for elements with [autofocus] first, [tabindex] second and buttons/links/other natively-focusable elements last.\n * Upon closing the popout, focus will be returned to the popout's target.\n * If nothing within your popout's content is focusable, this prop will do nothing.\n */\n focusOnContent?: boolean;\n qa?: Record<string, string>;\n zIndex?: number;\n\n /**\n * Override react-popper per the API documentation here: https://github.com/FezVrasta/react-popper#api-documentation\n */\n popperProps?: Partial<PopperProps>;\n onClose?: () => void;\n onOpen?: () => void;\n\n /**\n * And optional callback to receive the scheduleUpdate function.\n * Use the function to recalculate the popout position in relation to the contents.\n */\n scheduleUpdateRef?: (arg0: () => void) => void;\n\n /**\n * Mount the popout at the bottom of the DOM (using React.Portal) instead of inside the current DOM tree\n */\n appendToBody?: boolean;\n\n /**\n * Override `FocusLock` props, see the API documentation for more details: https://github.com/theKashey/react-focus-lock#api\n */\n focusLockProps?: TypeFocusLockProps;\n}\n"],"mappings":"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","names":["styled","Portal","transition","placement","FocusLock","Box","React"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-popout",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Seeds React Popout",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
@@ -26,7 +26,7 @@
26
26
  "@sproutsocial/seeds-react-system-props": "^2.2.0",
27
27
  "react-focus-lock": "^2.0.3",
28
28
  "react-popper": "^1.3.11",
29
- "react-spring": "^8.0.25"
29
+ "@react-spring/web": "^9.0.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/react": "^18.0.0",
@@ -34,7 +34,9 @@
34
34
  "@sproutsocial/eslint-config-seeds": "*",
35
35
  "react": "^18.0.0",
36
36
  "styled-components": "^5.2.3",
37
- "typescript": "^5.1.6"
37
+ "typescript": "^5.6.2",
38
+ "@sproutsocial/seeds-tsconfig": "*",
39
+ "tsup": "^8.0.2"
38
40
  },
39
41
  "peerDependencies": {
40
42
  "styled-components": "^5.2.3"