@khanacademy/wonder-blocks-floating 0.0.0-PR2846-20251117162554 → 0.0.0-PR2846-20251118170823

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @khanacademy/wonder-blocks-floating
2
2
 
3
- ## 0.0.0-PR2846-20251117162554
3
+ ## 0.0.0-PR2846-20251118170823
4
4
 
5
5
  ### Minor Changes
6
6
 
@@ -79,22 +79,43 @@ type FloatingProps = {
79
79
  */
80
80
  portal?: boolean;
81
81
  /**
82
- * Whether to use the FocusManager component to manage the focus of the
83
- * floating element.
82
+ * When enabled, user can hide the floating element by pressing the `esc`
83
+ * key or clicking/tapping outside of it.
84
84
  * @default false
85
85
  */
86
- useFocusManager?: boolean;
86
+ dismissEnabled?: boolean;
87
+ };
88
+ type FocusManagerProps = {
87
89
  /**
88
- * The element that will receive focus when the floating element is opened.
90
+ * Whether to enable the FocusManager component to manage the focus of the
91
+ * floating element.
92
+ *
93
+ * When enabled, the focus will continue flowing from the reference element
94
+ * to the floating element and back to the reference element when the
95
+ * floating element is closed.
96
+ *
97
+ * This should be enabled in most cases, but it can be disabled if you want
98
+ * to handle the focus manually or use it in a non-interactive context (e.g.
99
+ * tooltips).
100
+ *
101
+ * @default true
89
102
  */
90
- initialFocusRef?: React.RefObject<HTMLElement>;
103
+ focusManagerEnabled?: true;
91
104
  /**
92
- * When enabled, user can hide the floating element by pressing the `esc`
93
- * key or clicking/tapping outside of it.
94
- * @default false
105
+ * The element that will receive focus when the floating element is opened.
106
+ *
107
+ * This is useful when you want to set the initial focus to an element
108
+ * inside the floating element when it is opened.
109
+ *
110
+ * If not provided, the first focusable element inside the floating element
111
+ * will receive focus when it is opened.
95
112
  */
96
- dismissEnabled?: boolean;
113
+ initialFocusRef?: React.RefObject<HTMLElement>;
114
+ } | {
115
+ focusManagerEnabled: false | undefined;
116
+ initialFocusRef?: never;
97
117
  };
118
+ type Props = FloatingProps & FocusManagerProps;
98
119
  /**
99
120
  * A component that uses the Floating UI library to position a floating element
100
121
  * relative to a reference element.
@@ -112,5 +133,5 @@ type FloatingProps = {
112
133
  * </Floating>
113
134
  * ```
114
135
  */
115
- export default function Floating({ content, children, placement, open, onOpenChange, portal, strategy, testId, useFocusManager, initialFocusRef, dismissEnabled, hide: hideProp, offset: offsetProp, flip: flipProp, shift: shiftProp, showArrow, }: FloatingProps): React.JSX.Element;
136
+ export default function Floating({ content, children, placement, open, onOpenChange, portal, strategy, testId, focusManagerEnabled, initialFocusRef, dismissEnabled, hide: hideProp, offset: offsetProp, flip: flipProp, shift: shiftProp, showArrow, }: Props): React.JSX.Element;
116
137
  export {};
@@ -3,10 +3,10 @@ import { FloatingRootContext } from "@floating-ui/react";
3
3
  /**
4
4
  * Renders the floating element with the focus manager if enabled.
5
5
  */
6
- export declare function FocusManager({ context, dismissEnabled, useFocusManager, initialFocusRef, children, }: {
6
+ export declare function FocusManager({ context, dismissEnabled, focusManagerEnabled, initialFocusRef, children, }: {
7
7
  context: FloatingRootContext;
8
8
  dismissEnabled: boolean;
9
- useFocusManager: boolean;
9
+ focusManagerEnabled: boolean;
10
10
  initialFocusRef: React.RefObject<HTMLElement> | undefined;
11
11
  children: React.JSX.Element;
12
12
  }): React.JSX.Element;
package/dist/es/index.js CHANGED
@@ -15,8 +15,8 @@ function maybeGetNextAncestorModalLauncherPortal(element){let candidateElement=e
15
15
 
16
16
  function Portal({portal,children,reference}){if(portal){const modalHost=maybeGetPortalMountedModalHostElement(reference)||document.body;return jsx(FloatingPortal,{root:modalHost,children:children})}return children}
17
17
 
18
- function FocusManager({context,dismissEnabled,useFocusManager,initialFocusRef,children}){if(!useFocusManager){return children}return jsx(FloatingFocusManager,{context:context,modal:false,initialFocus:initialFocusRef,closeOnFocusOut:false,visuallyHiddenDismiss:dismissEnabled,children:children})}
18
+ function FocusManager({context,dismissEnabled,focusManagerEnabled,initialFocusRef,children}){return jsx(FloatingFocusManager,{disabled:!focusManagerEnabled,context:context,modal:false,initialFocus:initialFocusRef,closeOnFocusOut:false,visuallyHiddenDismiss:dismissEnabled,children:children})}
19
19
 
20
- const StyledDiv=addStyle("div");const SHIFT_PADDING=12;function Floating({content,children,placement="top",open=false,onOpenChange,portal=true,strategy="absolute",testId,useFocusManager=false,initialFocusRef,dismissEnabled=false,hide:hideProp=true,offset:offsetProp=20,flip:flipProp=true,shift:shiftProp=true,showArrow=true}){const arrowRef=React.useRef(null);const prevOpenRef=React.useRef(open??false);const{elements,refs,floatingStyles,context,middlewareData}=useFloating({open,onOpenChange,placement,strategy,whileElementsMounted:autoUpdate,middleware:[offset({mainAxis:offsetProp}),flipProp?flip():undefined,shiftProp?shift({padding:SHIFT_PADDING,crossAxis:true}):undefined,showArrow?arrow({element:arrowRef}):undefined,hideProp?hide():undefined]});const dismiss=useDismiss(context,{enabled:dismissEnabled});const{getReferenceProps,getFloatingProps}=useInteractions([dismiss]);React.useEffect(()=>{if(prevOpenRef.current!==open){onOpenChange?.(open);prevOpenRef.current=open;}},[onOpenChange,open]);const trigger=React.useMemo(()=>{return React.cloneElement(children,{ref:refs.setReference,...getReferenceProps()})},[children,refs.setReference,getReferenceProps]);return jsxs(Fragment,{children:[trigger,open&&elements.reference&&jsx(Portal,{portal:portal,reference:elements.reference,children:jsx(FocusManager,{useFocusManager:useFocusManager,context:context,dismissEnabled:dismissEnabled,initialFocusRef:initialFocusRef,children:jsxs(StyledDiv,{"data-testid":testId,"data-placement":placement,ref:refs.setFloating,style:[styles.floating,floatingStyles,{visibility:middlewareData.hide?.referenceHidden?"hidden":"visible"}],...getFloatingProps(),children:[content,showArrow&&jsx(Arrow,{ref:arrowRef,context:context})]})})})]})}const styles=StyleSheet.create({floating:{background:semanticColor.core.background.base.default,border:`solid ${border.width.thin} ${semanticColor.core.border.neutral.subtle}`,borderRadius:border.radius.radius_040,maxInlineSize:472,minBlockSize:ARROW_SIZE_INLINE,boxShadow:boxShadow.mid,justifyContent:"center"}});
20
+ const StyledDiv=addStyle("div");const SHIFT_PADDING=12;function Floating({content,children,placement="top",open=false,onOpenChange,portal=true,strategy="absolute",testId,focusManagerEnabled=true,initialFocusRef,dismissEnabled=false,hide:hideProp=true,offset:offsetProp=20,flip:flipProp=true,shift:shiftProp=true,showArrow=true}){const arrowRef=React.useRef(null);const prevOpenRef=React.useRef(open??false);const{elements,refs,floatingStyles,context,middlewareData}=useFloating({open,onOpenChange,placement,strategy,whileElementsMounted:autoUpdate,middleware:[offset({mainAxis:offsetProp}),flipProp?flip():undefined,shiftProp?shift({padding:SHIFT_PADDING,crossAxis:true}):undefined,showArrow?arrow({element:arrowRef}):undefined,hideProp?hide():undefined]});const dismiss=useDismiss(context,{enabled:dismissEnabled});const{getReferenceProps,getFloatingProps}=useInteractions([dismiss]);React.useEffect(()=>{if(prevOpenRef.current!==open){onOpenChange?.(open);prevOpenRef.current=open;}},[onOpenChange,open]);const trigger=React.useMemo(()=>{return React.cloneElement(children,{ref:refs.setReference,...getReferenceProps()})},[children,refs.setReference,getReferenceProps]);return jsxs(Fragment,{children:[trigger,open&&elements.reference&&jsx(Portal,{portal:portal,reference:elements.reference,children:jsx(FocusManager,{focusManagerEnabled:focusManagerEnabled,context:context,dismissEnabled:dismissEnabled,initialFocusRef:initialFocusRef,children:jsxs(StyledDiv,{"data-testid":testId,"data-placement":placement,ref:refs.setFloating,style:[styles.floating,floatingStyles,{visibility:middlewareData.hide?.referenceHidden?"hidden":"visible"}],...getFloatingProps(),children:[content,showArrow&&jsx(Arrow,{ref:arrowRef,context:context})]})})})]})}const styles=StyleSheet.create({floating:{background:semanticColor.core.background.base.default,border:`solid ${border.width.thin} ${semanticColor.core.border.neutral.subtle}`,borderRadius:border.radius.radius_040,maxInlineSize:472,minBlockSize:ARROW_SIZE_INLINE,boxShadow:boxShadow.mid,justifyContent:"center",outline:"none"}});
21
21
 
22
22
  export { Floating };
package/dist/index.js CHANGED
@@ -38,8 +38,8 @@ function maybeGetNextAncestorModalLauncherPortal(element){let candidateElement=e
38
38
 
39
39
  function Portal({portal,children,reference}){if(portal){const modalHost=maybeGetPortalMountedModalHostElement(reference)||document.body;return jsxRuntime.jsx(react.FloatingPortal,{root:modalHost,children:children})}return children}
40
40
 
41
- function FocusManager({context,dismissEnabled,useFocusManager,initialFocusRef,children}){if(!useFocusManager){return children}return jsxRuntime.jsx(react.FloatingFocusManager,{context:context,modal:false,initialFocus:initialFocusRef,closeOnFocusOut:false,visuallyHiddenDismiss:dismissEnabled,children:children})}
41
+ function FocusManager({context,dismissEnabled,focusManagerEnabled,initialFocusRef,children}){return jsxRuntime.jsx(react.FloatingFocusManager,{disabled:!focusManagerEnabled,context:context,modal:false,initialFocus:initialFocusRef,closeOnFocusOut:false,visuallyHiddenDismiss:dismissEnabled,children:children})}
42
42
 
43
- const StyledDiv=addStyle("div");const SHIFT_PADDING=12;function Floating({content,children,placement="top",open=false,onOpenChange,portal=true,strategy="absolute",testId,useFocusManager=false,initialFocusRef,dismissEnabled=false,hide:hideProp=true,offset:offsetProp=20,flip:flipProp=true,shift:shiftProp=true,showArrow=true}){const arrowRef=React__namespace.useRef(null);const prevOpenRef=React__namespace.useRef(open??false);const{elements,refs,floatingStyles,context,middlewareData}=react.useFloating({open,onOpenChange,placement,strategy,whileElementsMounted:react.autoUpdate,middleware:[react.offset({mainAxis:offsetProp}),flipProp?react.flip():undefined,shiftProp?react.shift({padding:SHIFT_PADDING,crossAxis:true}):undefined,showArrow?react.arrow({element:arrowRef}):undefined,hideProp?react.hide():undefined]});const dismiss=react.useDismiss(context,{enabled:dismissEnabled});const{getReferenceProps,getFloatingProps}=react.useInteractions([dismiss]);React__namespace.useEffect(()=>{if(prevOpenRef.current!==open){onOpenChange?.(open);prevOpenRef.current=open;}},[onOpenChange,open]);const trigger=React__namespace.useMemo(()=>{return React__namespace.cloneElement(children,{ref:refs.setReference,...getReferenceProps()})},[children,refs.setReference,getReferenceProps]);return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[trigger,open&&elements.reference&&jsxRuntime.jsx(Portal,{portal:portal,reference:elements.reference,children:jsxRuntime.jsx(FocusManager,{useFocusManager:useFocusManager,context:context,dismissEnabled:dismissEnabled,initialFocusRef:initialFocusRef,children:jsxRuntime.jsxs(StyledDiv,{"data-testid":testId,"data-placement":placement,ref:refs.setFloating,style:[styles.floating,floatingStyles,{visibility:middlewareData.hide?.referenceHidden?"hidden":"visible"}],...getFloatingProps(),children:[content,showArrow&&jsxRuntime.jsx(Arrow,{ref:arrowRef,context:context})]})})})]})}const styles=aphrodite.StyleSheet.create({floating:{background:wonderBlocksTokens.semanticColor.core.background.base.default,border:`solid ${wonderBlocksTokens.border.width.thin} ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,borderRadius:wonderBlocksTokens.border.radius.radius_040,maxInlineSize:472,minBlockSize:ARROW_SIZE_INLINE,boxShadow:wonderBlocksTokens.boxShadow.mid,justifyContent:"center"}});
43
+ const StyledDiv=addStyle("div");const SHIFT_PADDING=12;function Floating({content,children,placement="top",open=false,onOpenChange,portal=true,strategy="absolute",testId,focusManagerEnabled=true,initialFocusRef,dismissEnabled=false,hide:hideProp=true,offset:offsetProp=20,flip:flipProp=true,shift:shiftProp=true,showArrow=true}){const arrowRef=React__namespace.useRef(null);const prevOpenRef=React__namespace.useRef(open??false);const{elements,refs,floatingStyles,context,middlewareData}=react.useFloating({open,onOpenChange,placement,strategy,whileElementsMounted:react.autoUpdate,middleware:[react.offset({mainAxis:offsetProp}),flipProp?react.flip():undefined,shiftProp?react.shift({padding:SHIFT_PADDING,crossAxis:true}):undefined,showArrow?react.arrow({element:arrowRef}):undefined,hideProp?react.hide():undefined]});const dismiss=react.useDismiss(context,{enabled:dismissEnabled});const{getReferenceProps,getFloatingProps}=react.useInteractions([dismiss]);React__namespace.useEffect(()=>{if(prevOpenRef.current!==open){onOpenChange?.(open);prevOpenRef.current=open;}},[onOpenChange,open]);const trigger=React__namespace.useMemo(()=>{return React__namespace.cloneElement(children,{ref:refs.setReference,...getReferenceProps()})},[children,refs.setReference,getReferenceProps]);return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[trigger,open&&elements.reference&&jsxRuntime.jsx(Portal,{portal:portal,reference:elements.reference,children:jsxRuntime.jsx(FocusManager,{focusManagerEnabled:focusManagerEnabled,context:context,dismissEnabled:dismissEnabled,initialFocusRef:initialFocusRef,children:jsxRuntime.jsxs(StyledDiv,{"data-testid":testId,"data-placement":placement,ref:refs.setFloating,style:[styles.floating,floatingStyles,{visibility:middlewareData.hide?.referenceHidden?"hidden":"visible"}],...getFloatingProps(),children:[content,showArrow&&jsxRuntime.jsx(Arrow,{ref:arrowRef,context:context})]})})})]})}const styles=aphrodite.StyleSheet.create({floating:{background:wonderBlocksTokens.semanticColor.core.background.base.default,border:`solid ${wonderBlocksTokens.border.width.thin} ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,borderRadius:wonderBlocksTokens.border.radius.radius_040,maxInlineSize:472,minBlockSize:ARROW_SIZE_INLINE,boxShadow:wonderBlocksTokens.boxShadow.mid,justifyContent:"center",outline:"none"}});
44
44
 
45
45
  exports.Floating = Floating;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "A package that provides support for floating UI components in our UIs, including portal and focus management support.",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "0.0.0-PR2846-20251117162554",
6
+ "version": "0.0.0-PR2846-20251118170823",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -27,8 +27,8 @@
27
27
  "react": "18.2.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@khanacademy/wonder-blocks-modal": "8.5.5",
31
- "@khanacademy/wb-dev-build-settings": "3.2.0"
30
+ "@khanacademy/wb-dev-build-settings": "3.2.0",
31
+ "@khanacademy/wonder-blocks-modal": "8.5.5"
32
32
  },
33
33
  "scripts": {
34
34
  "test": "echo \"Error: no test specified\" && exit 1"