@khanacademy/wonder-blocks-dropdown 10.14.1 → 11.0.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/.turbo/turbo-build$colon$css.log +1 -1
- package/CHANGELOG.md +24 -0
- package/dist/components/action-item.d.ts +37 -8
- package/dist/components/option-item.d.ts +36 -8
- package/dist/components/separator-item.d.ts +7 -1
- package/dist/es/index.js +9 -9
- package/dist/hooks/use-listbox.d.ts +56 -17
- package/dist/index.js +10 -10
- package/package.json +2 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @khanacademy/wonder-blocks-dropdown@
|
|
2
|
+
> @khanacademy/wonder-blocks-dropdown@11.0.0 build:css /home/runner/work/wonder-blocks/wonder-blocks/packages/wonder-blocks-dropdown
|
|
3
3
|
> pnpm exec wonder-blocks-tokens .
|
|
4
4
|
|
|
5
5
|
CSS variables generated successfully in: /home/runner/work/wonder-blocks/wonder-blocks/packages/wonder-blocks-dropdown/dist/css
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-dropdown
|
|
2
2
|
|
|
3
|
+
## 11.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 4e011ea: `OptionItem` and `ActionItem` now forward their `ref` to the item's root DOM element (the underlying `DetailCell`: a `<button>`, or an `<a>` for an `ActionItem` with `href`) instead of exposing the component instance.
|
|
8
|
+
|
|
9
|
+
Breaking changes:
|
|
10
|
+
|
|
11
|
+
- `ref.current` on an `OptionItem` or `ActionItem` is now an `HTMLElement`, not a class instance. Code that called instance methods (e.g. `handleClick`) or read `props` from the instance must use the element instead. Code that passed the instance to `ReactDOM.findDOMNode` can use `ref.current` directly.
|
|
12
|
+
- `OptionItem` and `ActionItem` are no longer classes: they can't be extended, used with `instanceof`, or used as an instance type (e.g. `React.RefObject<OptionItem>`), and they no longer have a `defaultProps` static.
|
|
13
|
+
- `OptionItem.isClassOf`, `ActionItem.isClassOf` and `SeparatorItem.isClassOf` are renamed to `isComponentOf`, matching `ModalContent.isComponentOf` and `ModalFooter.isComponentOf`. They work the same way.
|
|
14
|
+
- `DropdownCore` now focuses items using the element from their ref instead of `ReactDOM.findDOMNode`. A custom component passed as a `SingleSelect`, `MultiSelect` or `ActionMenu` item must forward its ref to a DOM element to receive keyboard focus; a class component that doesn't is skipped.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [4e011ea]
|
|
19
|
+
- @khanacademy/wonder-blocks-cell@6.4.0
|
|
20
|
+
|
|
21
|
+
## 10.14.2
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 8739d20: Remove the unused `@khanacademy/wonder-blocks-pill` dependency.
|
|
26
|
+
|
|
3
27
|
## 10.14.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
2
|
+
import type { PropsFor, StyleType } from "@khanacademy/wonder-blocks-core";
|
|
3
3
|
import type { CellProps } from "../util/types";
|
|
4
4
|
type ActionProps = {
|
|
5
5
|
/**
|
|
@@ -103,15 +103,44 @@ type DefaultProps = {
|
|
|
103
103
|
indent: ActionProps["indent"];
|
|
104
104
|
role: ActionProps["role"];
|
|
105
105
|
};
|
|
106
|
+
type ActionItemInnerProps = ActionProps & {
|
|
107
|
+
/**
|
|
108
|
+
* The ref passed to `ActionItem`, forwarded to the root DOM element of
|
|
109
|
+
* the item (the `DetailCell`).
|
|
110
|
+
*/
|
|
111
|
+
forwardedRef?: React.Ref<HTMLElement>;
|
|
112
|
+
};
|
|
106
113
|
/**
|
|
107
|
-
* The
|
|
108
|
-
*
|
|
109
|
-
* ActionMenu.
|
|
114
|
+
* The class implementation of `ActionItem`. It's wrapped by the exported
|
|
115
|
+
* `ActionItem` so that refs are forwarded to the root DOM element.
|
|
110
116
|
*/
|
|
111
|
-
|
|
112
|
-
static isClassOf(instance: React.ReactElement<any>): boolean;
|
|
117
|
+
declare class ActionItemInner extends React.Component<ActionItemInnerProps> {
|
|
113
118
|
static defaultProps: DefaultProps;
|
|
114
|
-
static __IS_ACTION_ITEM__: boolean;
|
|
115
119
|
render(): React.ReactNode;
|
|
116
120
|
}
|
|
117
|
-
|
|
121
|
+
type ActionItemProps = Omit<PropsFor<typeof ActionItemInner>, "forwardedRef">;
|
|
122
|
+
/**
|
|
123
|
+
* Check whether the given element is an `ActionItem` element.
|
|
124
|
+
*
|
|
125
|
+
* @param instance The value to check, e.g. a child of a dropdown.
|
|
126
|
+
* @returns `true` if the element's type is `ActionItem`.
|
|
127
|
+
*/
|
|
128
|
+
declare const isComponentOf: (instance: unknown) => boolean;
|
|
129
|
+
/**
|
|
130
|
+
* The type of `ActionItem`: a ref-forwarding component plus the statics that
|
|
131
|
+
* parents use to recognise its elements.
|
|
132
|
+
*/
|
|
133
|
+
type ActionItemComponent = React.ForwardRefExoticComponent<ActionItemProps & React.RefAttributes<HTMLElement>> & {
|
|
134
|
+
isComponentOf: typeof isComponentOf;
|
|
135
|
+
__IS_ACTION_ITEM__: true;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* The action item trigger actions, such as navigating to a different page or
|
|
139
|
+
* opening a modal. Supply the href and/or onClick props. Used as a child of
|
|
140
|
+
* ActionMenu.
|
|
141
|
+
*
|
|
142
|
+
* The ref is forwarded to the root DOM element of the item (an `<a>` when
|
|
143
|
+
* `href` is set, otherwise a `<button>`).
|
|
144
|
+
*/
|
|
145
|
+
declare const ActionItem: ActionItemComponent;
|
|
146
|
+
export default ActionItem;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { AriaProps, StyleType } from "@khanacademy/wonder-blocks-core";
|
|
2
|
+
import type { AriaProps, PropsFor, StyleType } from "@khanacademy/wonder-blocks-core";
|
|
3
3
|
import Check from "./check";
|
|
4
4
|
import Checkbox from "./checkbox";
|
|
5
5
|
import { CellProps, OptionLabel } from "../util/types";
|
|
@@ -115,17 +115,45 @@ type DefaultProps = {
|
|
|
115
115
|
role: OptionProps["role"];
|
|
116
116
|
selected: OptionProps["selected"];
|
|
117
117
|
};
|
|
118
|
+
type OptionItemInnerProps = OptionProps & {
|
|
119
|
+
/**
|
|
120
|
+
* The ref passed to `OptionItem`, forwarded to the root DOM element of
|
|
121
|
+
* the item (the `DetailCell`).
|
|
122
|
+
*/
|
|
123
|
+
forwardedRef?: React.Ref<HTMLElement>;
|
|
124
|
+
};
|
|
118
125
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* MultiSelect.
|
|
126
|
+
* The class implementation of `OptionItem`. It's wrapped by the exported
|
|
127
|
+
* `OptionItem` so that refs are forwarded to the root DOM element.
|
|
122
128
|
*/
|
|
123
|
-
|
|
124
|
-
static isClassOf(instance: React.ReactElement<any>): boolean;
|
|
129
|
+
declare class OptionItemInner extends React.Component<OptionItemInnerProps> {
|
|
125
130
|
static defaultProps: DefaultProps;
|
|
126
|
-
static __IS_OPTION_ITEM__: boolean;
|
|
127
131
|
getCheckComponent(): typeof Check | typeof Checkbox;
|
|
128
132
|
handleClick: () => void;
|
|
129
133
|
render(): React.ReactNode;
|
|
130
134
|
}
|
|
131
|
-
|
|
135
|
+
type OptionItemProps = Omit<PropsFor<typeof OptionItemInner>, "forwardedRef">;
|
|
136
|
+
/**
|
|
137
|
+
* Check whether the given element is an `OptionItem` element.
|
|
138
|
+
*
|
|
139
|
+
* @param instance The value to check, e.g. a child of a dropdown.
|
|
140
|
+
* @returns `true` if the element's type is `OptionItem`.
|
|
141
|
+
*/
|
|
142
|
+
declare const isComponentOf: (instance: unknown) => boolean;
|
|
143
|
+
/**
|
|
144
|
+
* The type of `OptionItem`: a ref-forwarding component plus the statics that
|
|
145
|
+
* parents use to recognise its elements.
|
|
146
|
+
*/
|
|
147
|
+
type OptionItemComponent = React.ForwardRefExoticComponent<OptionItemProps & React.RefAttributes<HTMLElement>> & {
|
|
148
|
+
isComponentOf: typeof isComponentOf;
|
|
149
|
+
__IS_OPTION_ITEM__: true;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* For option items that can be selected in a dropdown, selection denoted either
|
|
153
|
+
* with a check ✔️ or a checkbox ☑️. Use as children in SingleSelect or
|
|
154
|
+
* MultiSelect.
|
|
155
|
+
*
|
|
156
|
+
* The ref is forwarded to the root DOM element of the item.
|
|
157
|
+
*/
|
|
158
|
+
declare const OptionItem: OptionItemComponent;
|
|
159
|
+
export default OptionItem;
|
|
@@ -11,7 +11,13 @@ export default class SeparatorItem extends React.Component<{
|
|
|
11
11
|
*/
|
|
12
12
|
style?: StyleType;
|
|
13
13
|
}> {
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Check whether the given value is a `SeparatorItem` element.
|
|
16
|
+
*
|
|
17
|
+
* @param instance The value to check, e.g. a child of a dropdown.
|
|
18
|
+
* @returns `true` if the value is an element whose type is `SeparatorItem`.
|
|
19
|
+
*/
|
|
20
|
+
static isComponentOf(instance: unknown): boolean;
|
|
15
21
|
static __IS_SEPARATOR_ITEM__: boolean;
|
|
16
22
|
render(): React.ReactNode;
|
|
17
23
|
}
|
package/dist/es/index.js
CHANGED
|
@@ -10,10 +10,10 @@ import { View, useLatestRef, useOnMountEffect, keys, addStyle, Id } from '@khana
|
|
|
10
10
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
11
11
|
import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
|
|
12
12
|
import { ClickableBehavior } from '@khanacademy/wonder-blocks-clickable';
|
|
13
|
-
import * as ReactDOM from 'react-dom';
|
|
14
13
|
import SearchField from '@khanacademy/wonder-blocks-search-field';
|
|
15
14
|
import { withActionScheduler, useActionScheduler } from '@khanacademy/wonder-blocks-timing';
|
|
16
15
|
import { useWonderBlocksI18n } from '@khanacademy/wonder-blocks-config';
|
|
16
|
+
import * as ReactDOM from 'react-dom';
|
|
17
17
|
import { VariableSizeList } from 'react-window';
|
|
18
18
|
import { Popper } from 'react-popper';
|
|
19
19
|
import { maybeGetPortalMountedModalHostElement } from '@khanacademy/wonder-blocks-modal';
|
|
@@ -32,23 +32,23 @@ var themeDefault = {listbox:{border:{radius:border.radius.radius_040},layout:{pa
|
|
|
32
32
|
|
|
33
33
|
var theme = mapValuesToCssVars(themeDefault,"--wb-c-dropdown-");
|
|
34
34
|
|
|
35
|
-
class
|
|
35
|
+
class ActionItemInner extends React.Component{render(){const{disabled,horizontalRule,href,target,indent,label,lang,leftAccessory,rightAccessory,onClick,role,style,subtitle1,subtitle2,testId,active,"aria-label":ariaLabel,forwardedRef}=this.props;const defaultStyle=[styles$c.wrapper,style];const labelComponent=typeof label==="string"?jsx(BodyText,{tag:"div",lang:lang,style:styles$c.label,children:label}):React.cloneElement(label,{lang,style:styles$c.label,...label.props});return jsx(DetailCell,{disabled:disabled,horizontalRule:horizontalRule,leftAccessory:leftAccessory,rightAccessory:rightAccessory,styles:{root:[defaultStyle,styles$c.shared,indent&&styles$c.indent]},role:role,testId:testId,subtitle1:subtitle1,title:labelComponent,subtitle2:subtitle2,href:href,target:target,onClick:onClick,active:active,"aria-label":ariaLabel,ref:forwardedRef})}}ActionItemInner.defaultProps={disabled:false,horizontalRule:"none",indent:false,role:"menuitem"};const isComponentOf$1=instance=>{if(typeof instance!=="object"||instance===null){return false}const type="type"in instance?instance.type:undefined;return typeof type==="object"&&type!==null&&"__IS_ACTION_ITEM__"in type&&type.__IS_ACTION_ITEM__===true};const ActionItem=React.forwardRef(function ActionItem(props,ref){return jsx(ActionItemInner,{...props,forwardedRef:ref})});ActionItem.isComponentOf=isComponentOf$1;ActionItem.__IS_ACTION_ITEM__=true;const styles$c=StyleSheet.create({wrapper:{minBlockSize:DROPDOWN_ITEM_HEIGHT,touchAction:"manipulation",":focus":{borderRadius:theme.item.border.radius.default,outline:focusStyles.focus[":focus-visible"].outline,outlineOffset:`calc(${border.width.medium} * -1)`,boxShadow:`inset 0 0 0 calc(${border.width.medium}*2) ${semanticColor.focus.inner}`,[":after"]:{content:"unset"}}},shared:{minBlockSize:DROPDOWN_ITEM_HEIGHT,paddingBlock:theme.item.layout.padding.block},label:{fontWeight:theme.item.font.weight,lineHeight:sizing.size_200,whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},indent:{paddingInlineStart:sizing.size_320}});
|
|
36
36
|
|
|
37
37
|
const Check=function(props){const{selected,disabled}=props;const iconColor=disabled?semanticColor.core.foreground.disabled.strong:semanticColor.core.foreground.instructive.default;return jsx(PhosphorIcon,{color:iconColor,icon:checkIcon,size:"small",style:[styles$b.bounds,!selected&&styles$b.hide]})};const styles$b=StyleSheet.create({bounds:{alignSelf:"center",height:sizing.size_160,minBlockSize:sizing.size_160,minInlineSize:sizing.size_160},hide:{visibility:"hidden"}});
|
|
38
38
|
|
|
39
39
|
const Checkbox=function(props){const{disabled,selected}=props;return jsx(View,{className:"checkbox",style:[styles$a.checkbox,selected&&!disabled&&styles$a.selected,disabled&&styles$a.disabledCheckbox],children:selected&&jsx(PhosphorIcon,{icon:checkIcon,size:"small",className:"check",style:[{width:sizing.size_120,height:sizing.size_120,margin:sizing.size_020},disabled&&selected&&styles$a.disabledCheckFormatting]})})};const checkboxTokens={color:{default:{border:semanticColor.input.default.border,background:semanticColor.input.default.background},disabled:{border:semanticColor.input.disabled.border,background:semanticColor.input.disabled.background},selected:{background:semanticColor.input.checked.background,foreground:semanticColor.input.checked.foreground}}};const styles$a=StyleSheet.create({checkbox:{alignSelf:"center",minBlockSize:sizing.size_160,minInlineSize:sizing.size_160,height:sizing.size_160,background:checkboxTokens.color.default.background,borderRadius:3,borderWidth:border.width.thin,borderStyle:"solid",borderColor:checkboxTokens.color.default.border},selected:{borderWidth:0,background:checkboxTokens.color.selected.background,color:checkboxTokens.color.selected.foreground},disabledCheckbox:{borderColor:checkboxTokens.color.disabled.border,backgroundColor:checkboxTokens.color.disabled.background},disabledCheckFormatting:{position:"absolute",insetBlockStart:-1,insetInlineStart:-1}});
|
|
40
40
|
|
|
41
|
-
class
|
|
41
|
+
class OptionItemInner extends React.Component{getCheckComponent(){if(this.props.variant==="check"){return Check}else {return Checkbox}}render(){const{disabled,focused,label,selected,testId,leftAccessory,horizontalRule,parentComponent,rightAccessory,style,subtitle1,subtitle2,value,onClick,onToggle,variant,role,forwardedRef,...sharedProps}=this.props;const CheckComponent=this.getCheckComponent();const defaultStyle=[styles$9.optionItem,style];const listboxStyles=[styles$9.listboxOptionItem,focused&&styles$9.listboxOptionItemFocused];const selectStyles=[styles$9.selectOptionItem];return jsx(DetailCell,{disabled:disabled,horizontalRule:horizontalRule,styles:{root:[defaultStyle,parentComponent==="listbox"?listboxStyles:selectStyles]},"aria-selected":selected?"true":"false",role:role,testId:testId,leftAccessory:jsx(Fragment,{children:leftAccessory?jsxs(View,{style:{flexDirection:"row",gap:sizing.size_080},children:[jsx(CheckComponent,{disabled:disabled,selected:selected}),leftAccessory]}):jsx(CheckComponent,{disabled:disabled,selected:selected})}),rightAccessory:rightAccessory,subtitle1:subtitle1,title:jsx(BodyText,{tag:"div",style:styles$9.label,children:label}),subtitle2:subtitle2,onClick:this.handleClick,tabIndex:parentComponent==="listbox"?-1:undefined,...sharedProps,ref:forwardedRef})}constructor(...args){super(...args),this.handleClick=()=>{const{onClick,onToggle,value}=this.props;onToggle(value);if(onClick){onClick();}};}}OptionItemInner.defaultProps={disabled:false,focused:false,horizontalRule:"none",onToggle:()=>void 0,role:"option",selected:false};const isComponentOf=instance=>{if(typeof instance!=="object"||instance===null){return false}const type="type"in instance?instance.type:undefined;return typeof type==="object"&&type!==null&&"__IS_OPTION_ITEM__"in type&&type.__IS_OPTION_ITEM__===true};const OptionItem=React.forwardRef(function OptionItem(props,ref){return jsx(OptionItemInner,{...props,forwardedRef:ref})});OptionItem.isComponentOf=isComponentOf;OptionItem.__IS_OPTION_ITEM__=true;const focusedStyle={borderRadius:theme.item.border.radius.default,outline:focusStyles.focus[":focus-visible"].outline,outlineOffset:`calc(${border.width.medium} * -1)`,boxShadow:`inset 0 0 0 calc(${border.width.medium}*2) ${semanticColor.focus.inner}`};const resetFocusStyle={outline:"none",boxShadow:"none"};const styles$9=StyleSheet.create({optionItem:{paddingBlock:theme.item.layout.padding.block,paddingInlineStart:theme.item.layout.padding.inlineStart,paddingInlineEnd:theme.item.layout.padding.inlineEnd,whiteSpace:"nowrap",minBlockSize:sizing.size_400,":active":{borderRadius:theme.item.border.radius.press},[":is([aria-disabled=true])"]:{":focus":resetFocusStyle}},listboxOptionItem:{":focus-visible":resetFocusStyle},listboxOptionItemFocused:{...focusedStyle,":focus-visible":focusedStyle},selectOptionItem:{":focus":focusedStyle},label:{fontWeight:theme.item.font.weight,lineHeight:sizing.size_200,whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},hide:{visibility:"hidden"}});
|
|
42
42
|
|
|
43
|
-
class SeparatorItem extends React.Component{static
|
|
43
|
+
class SeparatorItem extends React.Component{static isComponentOf(instance){if(typeof instance!=="object"||instance===null){return false}const type="type"in instance?instance.type:undefined;return typeof type==="function"&&"__IS_SEPARATOR_ITEM__"in type&&type.__IS_SEPARATOR_ITEM__===true}render(){return jsx(View,{style:[styles$8.separator,this.props.style],"aria-hidden":"true"})}}SeparatorItem.__IS_SEPARATOR_ITEM__=true;const styles$8=StyleSheet.create({separator:{borderBlockStart:`${border.width.thin} solid ${semanticColor.core.border.neutral.subtle}`,height:1,minBlockSize:1,marginBlock:sizing.size_040}});
|
|
44
44
|
|
|
45
45
|
const DropdownOpener=React.forwardRef((props,ref)=>{const{disabled=false,readOnly=false,testId,text,opened,"aria-controls":ariaControls,"aria-haspopup":ariaHasPopUp,"aria-required":ariaRequired,"aria-label":ariaLabel,id,role,onBlur,onClick,children,error}=props;const renderAnchorChildren=(eventState,clickableChildrenProps)=>{const renderedChildren=children({...eventState,text,opened});const childrenProps=renderedChildren.props;const childrenTestId=childrenProps?.testId||childrenProps?.["data-testid"];const renderedAriaLabel=childrenProps["aria-label"]??ariaLabel;return React.cloneElement(renderedChildren,{...clickableChildrenProps,ref,"aria-label":renderedAriaLabel??undefined,"aria-invalid":error,disabled,"aria-controls":ariaControls,role,id,"aria-expanded":opened?"true":"false","aria-haspopup":ariaHasPopUp,"aria-required":ariaRequired,"aria-disabled":readOnly||disabled||undefined,onClick:childrenProps.onClick?e=>{childrenProps.onClick(e);clickableChildrenProps.onClick(e);}:clickableChildrenProps.onClick,"data-testid":childrenTestId||testId,onBlur:onBlur?e=>{onBlur(e);clickableChildrenProps.onBlur(e);}:clickableChildrenProps.onBlur})};return jsx(ClickableBehavior,{onClick:onClick,disabled:disabled||readOnly,tabIndex:0,children:(eventState,handlers)=>renderAnchorChildren(eventState,handlers)})});DropdownOpener.displayName="DropdownOpener";
|
|
46
46
|
|
|
47
|
-
class DropdownVirtualizedItem extends React.Component{render(){const{data,index,style}=this.props;const item=data[index];if(SeparatorItem.
|
|
47
|
+
class DropdownVirtualizedItem extends React.Component{render(){const{data,index,style}=this.props;const item=data[index];if(SeparatorItem.isComponentOf(item.component)){return React.cloneElement(item.component,{style})}else {const{component,populatedProps,onClick,role,ref}=item;return React.cloneElement(component,{style,...populatedProps,key:index,onClick,ref:item.focusable&&ref,role})}}}
|
|
48
48
|
|
|
49
|
-
function getDropdownMenuHeight(items,initialHeight=0){return items.slice(0,MAX_VISIBLE_ITEMS).reduce((sum,item)=>{if(SeparatorItem.
|
|
49
|
+
function getDropdownMenuHeight(items,initialHeight=0){return items.slice(0,MAX_VISIBLE_ITEMS).reduce((sum,item)=>{if(SeparatorItem.isComponentOf(item.component)){return sum+SEPARATOR_ITEM_HEIGHT}else {return sum+DROPDOWN_ITEM_HEIGHT}},initialHeight)}
|
|
50
50
|
|
|
51
|
-
class DropdownCoreVirtualized extends React.Component{componentDidMount(){const{schedule}=this.props;schedule.animationFrame(()=>{this.setWidth();});}componentDidUpdate(prevProps){const{data,listRef}=this.props;if(prevProps.data.length!==data.length){this.setHeight();if(listRef&&listRef.current){listRef.current.resetAfterIndex(1);}}}setWidth(){const rootNode=ReactDOM.findDOMNode(this);const parentNode=rootNode?.parentElement;if(parentNode){const width=parentNode.getBoundingClientRect().width;this.setState({width});}}setHeight(){const height=getDropdownMenuHeight(this.props.data);this.setState({height});}renderInitialItems(){const{data}=this.props;const allComponents=data.map(e=>e.component);const longestItems=React.Children.toArray(allComponents).filter(Boolean).sort((a,b)=>{if(b.props.label&&a.props.label){return b.props.label.length-a.props.label.length}return -1}).slice(0,MAX_VISIBLE_ITEMS);return longestItems.map(item=>React.cloneElement(item,{style:{visibility:"hidden"}}))}renderVirtualizedList(width,height){const{data,listRef}=this.props;return jsx(VariableSizeList,{height:height,itemCount:data.length,itemSize:this.getItemSize,itemData:data,style:{overflowX:"hidden"},width:width,overscanCount:5,ref:listRef,children:DropdownVirtualizedItem})}render(){const{width,height}=this.state;if(width==null){return this.renderInitialItems()}else {return this.renderVirtualizedList(width,height)}}constructor(props){super(props),this.getItemSize=index=>{const item=this.props.data[index];if(SeparatorItem.
|
|
51
|
+
class DropdownCoreVirtualized extends React.Component{componentDidMount(){const{schedule}=this.props;schedule.animationFrame(()=>{this.setWidth();});}componentDidUpdate(prevProps){const{data,listRef}=this.props;if(prevProps.data.length!==data.length){this.setHeight();if(listRef&&listRef.current){listRef.current.resetAfterIndex(1);}}}setWidth(){const rootNode=ReactDOM.findDOMNode(this);const parentNode=rootNode?.parentElement;if(parentNode){const width=parentNode.getBoundingClientRect().width;this.setState({width});}}setHeight(){const height=getDropdownMenuHeight(this.props.data);this.setState({height});}renderInitialItems(){const{data}=this.props;const allComponents=data.map(e=>e.component);const longestItems=React.Children.toArray(allComponents).filter(Boolean).sort((a,b)=>{if(b.props.label&&a.props.label){return b.props.label.length-a.props.label.length}return -1}).slice(0,MAX_VISIBLE_ITEMS);return longestItems.map(item=>React.cloneElement(item,{style:{visibility:"hidden"}}))}renderVirtualizedList(width,height){const{data,listRef}=this.props;return jsx(VariableSizeList,{height:height,itemCount:data.length,itemSize:this.getItemSize,itemData:data,style:{overflowX:"hidden"},width:width,overscanCount:5,ref:listRef,children:DropdownVirtualizedItem})}render(){const{width,height}=this.state;if(width==null){return this.renderInitialItems()}else {return this.renderVirtualizedList(width,height)}}constructor(props){super(props),this.getItemSize=index=>{const item=this.props.data[index];if(SeparatorItem.isComponentOf(item.component)){return SEPARATOR_ITEM_HEIGHT}else {return DROPDOWN_ITEM_HEIGHT}};this.state={height:getDropdownMenuHeight(props.data),width:props.width};}}var DropdownCoreVirtualized$1 = withActionScheduler(DropdownCoreVirtualized);
|
|
52
52
|
|
|
53
53
|
function modifyMaxHeight({state,options}){const overflow=detectOverflow(state,options);const{y}=state.modifiersData.preventOverflow||{x:0,y:0};const{height}=state.rects.popper;const[basePlacement]=state.placement.split("-");const heightProp=basePlacement==="top"?"top":"bottom";const maxHeight=height-overflow[heightProp]-y;state.styles.popper={...state.styles.popper,maxHeight:`${maxHeight}px`,["--popper-max-height"]:`${maxHeight}px`};}const maxHeightModifier={name:"maxHeight",enabled:true,phase:"main",options:{padding:DROPDOWN_ITEM_HEIGHT},requiresIfExists:["offset","preventOverflow","flip"],fn:modifyMaxHeight};
|
|
54
54
|
|
|
@@ -56,11 +56,11 @@ const modifiers=[{name:"preventOverflow",options:{rootBoundary:"viewport",altAxi
|
|
|
56
56
|
|
|
57
57
|
function getStringForKey(key){if(key.length===1||!/^[A-Z]/i.test(key)){return key}return ""}function debounce(callback,wait){let timeout;return function executedFunction(...args){const later=()=>{clearTimeout(timeout);callback(...args);};clearTimeout(timeout);timeout=setTimeout(later,wait);}}function isString(x){return typeof x==="string"}function getLabel(props){if(isString(props.label)){return props.label}if(isString(props.labelAsText)){return props.labelAsText}return ""}function getSelectOpenerLabel(showOpenerLabelAsText,props){if(showOpenerLabelAsText){return getLabel(props)}return props.label}function getListboxLabelProps({ariaLabel,ariaLabelledBy,openerElement}){const openerLabel=getOpenerLabel(openerElement);const labelId=ariaLabelledBy||openerLabel?.id;if(labelId){return {"aria-labelledby":labelId}}const label=openerLabel?.textContent||ariaLabel;return label?{"aria-label":label}:{}}function getOpenerLabel(openerElement){if(!openerElement||!("labels"in openerElement)){return undefined}return openerElement.labels?.[0]}
|
|
58
58
|
|
|
59
|
-
const VIRTUALIZE_THRESHOLD=125;const sameItemsFocusable=(prevItems,currentItems)=>{if(prevItems.length!==currentItems.length){return false}for(let i=0;i<prevItems.length;i++){if(prevItems[i].focusable!==currentItems[i].focusable){return false}}return true};const createItemRefs=items=>{const itemRefs=[];for(let i=0;i<items.length;i++){if(items[i].focusable){const ref=React.createRef();itemRefs.push({ref,originalIndex:i});}}return itemRefs};const DropdownCore=props=>{const{strings}=useWonderBlocksI18n();const{"aria-invalid":ariaInvalid,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,"aria-required":ariaRequired,alignment="left",autoFocus=true,className,disabled,dropdownStyle,enableTypeAhead=true,id,initialFocusedIndex,isFilterable,items,labels,onOpenChanged,onSearchTextChanged,open,opener,openerElement,role,searchText,selectionType="single",style}=props;const schedule=useActionScheduler();const openRef=useLatestRef(open);const onOpenChangedRef=useLatestRef(onOpenChanged);const rootRef=React.useRef(null);const popperElementRef=React.useRef(undefined);const virtualizedListRef=React.useRef(null);const searchFieldRef=React.useRef(null);const textSuggestionRef=React.useRef("");const committedItemsRef=React.useRef({itemRefs:[],prevItems:items});const{itemRefs:prevItemRefs,prevItems}=committedItemsRef.current;const shouldCreateItemRefs=prevItemRefs.length===0&&open||!sameItemsFocusable(prevItems,items);const derivedItems=shouldCreateItemRefs?{itemRefs:createItemRefs(items),sameItemsFocusable:false}:{itemRefs:prevItemRefs,sameItemsFocusable:true};const itemRefsRef=React.useRef(derivedItems.itemRefs);React.useEffect(()=>{committedItemsRef.current={itemRefs:derivedItems.itemRefs,prevItems:items};itemRefsRef.current=derivedItems.itemRefs;});const hasSearchField=React.useCallback(()=>{return !!isFilterable},[isFilterable]);const isSearchFieldFocused=React.useCallback(()=>{return hasSearchField()&&document.activeElement===searchFieldRef.current},[hasSearchField]);const focusSearchField=React.useCallback(()=>{if(searchFieldRef.current){searchFieldRef.current.focus();}},[]);const focusedIndexRef=React.useRef(-1);const focusedOriginalIndexRef=React.useRef(-1);const itemsClickedRef=React.useRef(false);const resetFocusedIndex=React.useCallback(()=>{if(typeof initialFocusedIndex!=="undefined"){focusedIndexRef.current=initialFocusedIndex;}else {if(hasSearchField()&&!isSearchFieldFocused()){return focusSearchField()}focusedIndexRef.current=0;}},[focusSearchField,hasSearchField,initialFocusedIndex,isSearchFieldFocused]);const initializedRef=React.useRef(false);if(!initializedRef.current){initializedRef.current=true;resetFocusedIndex();}const shouldVirtualizeList=React.useCallback(()=>{return items.length>VIRTUALIZE_THRESHOLD},[items]);const focusCurrentItem=React.useCallback(onFocus=>{const focusedItemRef=itemRefsRef.current[focusedIndexRef.current];if(!focusedItemRef){return}const{current:virtualizedList}=virtualizedListRef;if(virtualizedList){virtualizedList.scrollToItem(focusedItemRef.originalIndex);}const focusNode=()=>{if(!openRef.current){return}const currentFocusedItemRef=itemRefsRef.current[focusedIndexRef.current];const node=ReactDOM.findDOMNode(currentFocusedItemRef.ref.current);if(!node&&shouldVirtualizeList()){schedule.animationFrame(focusNode);return}if(node){schedule.timeout(()=>{node.focus();},0);focusedOriginalIndexRef.current=currentFocusedItemRef.originalIndex;if(onFocus){onFocus(node);}}};if(shouldVirtualizeList()){schedule.animationFrame(focusNode);}else {focusNode();}},[openRef,schedule,shouldVirtualizeList]);const scheduleToFocusCurrentItem=React.useCallback(onFocus=>{if(shouldVirtualizeList()){schedule.animationFrame(()=>{focusCurrentItem(onFocus);});}else {focusCurrentItem(onFocus);}},[focusCurrentItem,schedule,shouldVirtualizeList]);const maybeFocusInitialItem=React.useCallback(()=>{if(!autoFocus){return}if(open){resetFocusedIndex();scheduleToFocusCurrentItem();}else if(!open){itemsClickedRef.current=false;}},[autoFocus,open,resetFocusedIndex,scheduleToFocusCurrentItem]);React.useEffect(()=>{if(!open){return}const handleInteract=event=>{const target=event.target;const thisElement=rootRef.current;if(thisElement&&!thisElement.contains(target)&&popperElementRef.current&&!popperElementRef.current.contains(target)){onOpenChangedRef.current(false);}};document.addEventListener("mouseup",handleInteract);document.addEventListener("touchend",handleInteract);return ()=>{document.removeEventListener("mouseup",handleInteract);document.removeEventListener("touchend",handleInteract);}},[open,onOpenChangedRef]);useOnMountEffect(()=>{maybeFocusInitialItem();});const prevRenderRef=React.useRef(null);React.useEffect(()=>{const prevProps=prevRenderRef.current;prevRenderRef.current={open,searchText,derivedItems};if(!prevProps||prevProps.derivedItems===derivedItems){return}if(prevProps.open!==open){maybeFocusInitialItem();}else if(open){const{itemRefs,sameItemsFocusable}=derivedItems;if(sameItemsFocusable||prevProps.searchText!==searchText){return}else {const newFocusableIndex=itemRefs.findIndex(ref=>ref.originalIndex===focusedOriginalIndexRef.current);if(newFocusableIndex===-1){focusedIndexRef.current=0;itemsClickedRef.current=false;scheduleToFocusCurrentItem();}else {focusedIndexRef.current=newFocusableIndex;}}}});const focusPreviousItem=React.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=itemRefsRef.current.length-1;}else if(focusedIndexRef.current===0){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=itemRefsRef.current.length-1;}else {focusedIndexRef.current-=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const focusNextItem=React.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=0;}else if(focusedIndexRef.current===itemRefsRef.current.length-1){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=0;}else {focusedIndexRef.current+=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const restoreTabOrder=React.useCallback(()=>{if(openerElement){openerElement.focus();}},[openerElement]);const handleKeyDownDebounceResult=React.useCallback(key=>{const foundIndex=items.filter(item=>item.focusable).findIndex(({component})=>{if(SeparatorItem.isClassOf(component)){return false}if(OptionItem.isClassOf(component)){const optionItemProps=component.props;return getLabel(optionItemProps).toLowerCase().startsWith(key.toLowerCase())}return false});if(foundIndex>=0){const isClosed=!open;if(isClosed){onOpenChanged(true);}focusedIndexRef.current=foundIndex;scheduleToFocusCurrentItem(node=>{if(selectionType==="single"&&isClosed&&node){node.click();onOpenChanged(false);}});}textSuggestionRef.current="";},[items,onOpenChanged,open,scheduleToFocusCurrentItem,selectionType]);const handleKeyDownDebounceResultRef=React.useRef(handleKeyDownDebounceResult);handleKeyDownDebounceResultRef.current=handleKeyDownDebounceResult;const handleKeyDownDebounced=React.useMemo(()=>debounce(key=>handleKeyDownDebounceResultRef.current(key),500),[]);const handleKeyDown=event=>{const key=event.key;if(enableTypeAhead&&getStringForKey(key)){event.stopPropagation();textSuggestionRef.current+=key;handleKeyDownDebounced(textSuggestionRef.current);}if(!open){if(key===keys.down){event.preventDefault();onOpenChanged(true);return}return}switch(key){case keys.tab:if(isSearchFieldFocused()&&searchText){return}restoreTabOrder();onOpenChanged(false);return;case keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case keys.up:event.preventDefault();focusPreviousItem();return;case keys.down:event.preventDefault();focusNextItem();return}};const handleKeyUp=event=>{const key=event.key;switch(key){case keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case keys.escape:if(open){event.stopPropagation();restoreTabOrder();onOpenChanged(false);}return}};const handleClickFocus=index=>{itemsClickedRef.current=true;focusedIndexRef.current=index;focusedOriginalIndexRef.current=derivedItems.itemRefs[focusedIndexRef.current].originalIndex;};const handleDropdownMouseUp=event=>{if(event.nativeEvent.stopImmediatePropagation){event.nativeEvent.stopImmediatePropagation();}else {event.stopPropagation();}};const getItemRole=()=>{switch(role){case"listbox":return "option";case"menu":return "menuitem";default:throw new Error(`Expected "listbox" or "menu" for role, but receieved "${role}" instead.`)}};const maybeRenderNoResults=()=>{const noResults=labels?.noResults||strings.noResults;const numResults=items.length;if(numResults===0){return jsx(BodyText,{style:styles$7.noResult,testId:"dropdown-core-no-results",children:noResults})}return null};const handleItemClick=(focusIndex,item)=>{handleClickFocus(focusIndex);if(item.component.props.onClick){item.component.props.onClick();}if(item.populatedProps.onClick){item.populatedProps.onClick();}};const renderList=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{if(SeparatorItem.isClassOf(item.component)){return item.component}const{component,focusable,populatedProps}=item;if(focusable){focusCounter+=1;}const focusIndex=focusCounter-1;const currentRef=derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null;return React.cloneElement(component,{...populatedProps,key:index,onClick:()=>{handleItemClick(focusIndex,item);},ref:focusable?currentRef:null,role:populatedProps.role||itemRole})})};const parseVirtualizedItems=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{const{populatedProps}=item;if(!SeparatorItem.isClassOf(item.component)&&item.focusable){focusCounter+=1;}const focusIndex=focusCounter-1;return {...item,role:populatedProps.role||itemRole,ref:item.focusable&&derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null,onClick:()=>{handleItemClick(focusIndex,item);}}})};const renderVirtualizedList=()=>{const virtualizedItems=parseVirtualizedItems();return jsx(DropdownCoreVirtualized$1,{data:virtualizedItems,listRef:virtualizedListRef})};const handleSearchTextChanged=searchText=>{if(onSearchTextChanged){onSearchTextChanged(searchText);}};const renderSearchField=()=>{return jsx(SearchField,{clearAriaLabel:labels?.clearSearch||strings.iconAltClearSearch,onChange:handleSearchTextChanged,placeholder:labels?.filter||strings.filter,ref:searchFieldRef,style:styles$7.searchInputStyle,value:searchText||""})};const renderDropdownMenu=(listRenderer,isReferenceHidden)=>{const openerStyle=openerElement&&window.getComputedStyle(openerElement);const minDropdownWidth=openerStyle?openerStyle.getPropertyValue("width"):0;return jsxs(View,{onMouseUp:handleDropdownMouseUp,style:[styles$7.dropdown,isReferenceHidden&&styles$7.hidden,dropdownStyle],testId:"dropdown-core-container",children:[isFilterable&&renderSearchField(),jsx(View,{id:id,role:role,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,style:[styles$7.listboxOrMenu,{minInlineSize:minDropdownWidth}],"aria-invalid":role==="listbox"?ariaInvalid:undefined,"aria-required":role==="listbox"?ariaRequired:undefined,children:listRenderer}),maybeRenderNoResults()]})};const renderDropdown=()=>{const listRenderer=shouldVirtualizeList()?renderVirtualizedList():renderList();return jsx(DropdownPopper,{alignment:alignment,onPopperElement:popperElement=>{popperElementRef.current=popperElement;},referenceElement:openerElement,children:isReferenceHidden=>renderDropdownMenu(listRenderer,isReferenceHidden)})};return jsxs(View,{ref:rootRef,onKeyDown:!disabled?handleKeyDown:undefined,onKeyUp:!disabled?handleKeyUp:undefined,style:[styles$7.menuWrapper,style],className:className,children:[opener,open&&renderDropdown()]})};const styles$7=StyleSheet.create({menuWrapper:{width:"fit-content",maxInlineSize:"100%"},dropdown:{backgroundColor:semanticColor.core.background.base.default,borderRadius:theme.listbox.border.radius,paddingBlock:theme.listbox.layout.padding.block,paddingInline:theme.listbox.layout.padding.inline,border:`solid ${border.width.thin} ${semanticColor.core.border.neutral.subtle}`,boxShadow:theme.listbox.shadow.default,maxBlockSize:"var(--popper-max-height)"},listboxOrMenu:{overflowY:"auto"},hidden:{pointerEvents:"none",visibility:"hidden"},noResult:{color:semanticColor.core.foreground.neutral.default,alignSelf:"center",marginBlockStart:sizing.size_060},searchInputStyle:{margin:sizing.size_080,marginBlockStart:sizing.size_040,minBlockSize:"auto",position:"sticky"},srOnly:{border:0,clip:"rect(0,0,0,0)",height:1,margin:-1,overflow:"hidden",padding:0,position:"absolute",width:1}});
|
|
59
|
+
const VIRTUALIZE_THRESHOLD=125;const isFocusableElement=value=>typeof value==="object"&&value!==null&&"nodeType"in value&&value.nodeType===1&&"focus"in value&&typeof value.focus==="function";const sameItemsFocusable=(prevItems,currentItems)=>{if(prevItems.length!==currentItems.length){return false}for(let i=0;i<prevItems.length;i++){if(prevItems[i].focusable!==currentItems[i].focusable){return false}}return true};const createItemRefs=items=>{const itemRefs=[];for(let i=0;i<items.length;i++){if(items[i].focusable){const ref=React.createRef();itemRefs.push({ref,originalIndex:i});}}return itemRefs};const DropdownCore=props=>{const{strings}=useWonderBlocksI18n();const{"aria-invalid":ariaInvalid,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,"aria-required":ariaRequired,alignment="left",autoFocus=true,className,disabled,dropdownStyle,enableTypeAhead=true,id,initialFocusedIndex,isFilterable,items,labels,onOpenChanged,onSearchTextChanged,open,opener,openerElement,role,searchText,selectionType="single",style}=props;const schedule=useActionScheduler();const openRef=useLatestRef(open);const onOpenChangedRef=useLatestRef(onOpenChanged);const rootRef=React.useRef(null);const popperElementRef=React.useRef(undefined);const virtualizedListRef=React.useRef(null);const searchFieldRef=React.useRef(null);const textSuggestionRef=React.useRef("");const committedItemsRef=React.useRef({itemRefs:[],prevItems:items});const{itemRefs:prevItemRefs,prevItems}=committedItemsRef.current;const shouldCreateItemRefs=prevItemRefs.length===0&&open||!sameItemsFocusable(prevItems,items);const derivedItems=shouldCreateItemRefs?{itemRefs:createItemRefs(items),sameItemsFocusable:false}:{itemRefs:prevItemRefs,sameItemsFocusable:true};const itemRefsRef=React.useRef(derivedItems.itemRefs);React.useEffect(()=>{committedItemsRef.current={itemRefs:derivedItems.itemRefs,prevItems:items};itemRefsRef.current=derivedItems.itemRefs;});const hasSearchField=React.useCallback(()=>{return !!isFilterable},[isFilterable]);const isSearchFieldFocused=React.useCallback(()=>{return hasSearchField()&&document.activeElement===searchFieldRef.current},[hasSearchField]);const focusSearchField=React.useCallback(()=>{if(searchFieldRef.current){searchFieldRef.current.focus();}},[]);const focusedIndexRef=React.useRef(-1);const focusedOriginalIndexRef=React.useRef(-1);const itemsClickedRef=React.useRef(false);const resetFocusedIndex=React.useCallback(()=>{if(typeof initialFocusedIndex!=="undefined"){focusedIndexRef.current=initialFocusedIndex;}else {if(hasSearchField()&&!isSearchFieldFocused()){return focusSearchField()}focusedIndexRef.current=0;}},[focusSearchField,hasSearchField,initialFocusedIndex,isSearchFieldFocused]);const initializedRef=React.useRef(false);if(!initializedRef.current){initializedRef.current=true;resetFocusedIndex();}const shouldVirtualizeList=React.useCallback(()=>{return items.length>VIRTUALIZE_THRESHOLD},[items]);const focusCurrentItem=React.useCallback(onFocus=>{const focusedItemRef=itemRefsRef.current[focusedIndexRef.current];if(!focusedItemRef){return}const{current:virtualizedList}=virtualizedListRef;if(virtualizedList){virtualizedList.scrollToItem(focusedItemRef.originalIndex);}const focusNode=()=>{if(!openRef.current){return}const currentFocusedItemRef=itemRefsRef.current[focusedIndexRef.current];const refValue=currentFocusedItemRef.ref.current;const node=isFocusableElement(refValue)?refValue:null;if(refValue==null&&shouldVirtualizeList()){schedule.animationFrame(focusNode);return}if(node){schedule.timeout(()=>{node.focus();},0);focusedOriginalIndexRef.current=currentFocusedItemRef.originalIndex;if(onFocus){onFocus(node);}}};if(shouldVirtualizeList()){schedule.animationFrame(focusNode);}else {focusNode();}},[openRef,schedule,shouldVirtualizeList]);const scheduleToFocusCurrentItem=React.useCallback(onFocus=>{if(shouldVirtualizeList()){schedule.animationFrame(()=>{focusCurrentItem(onFocus);});}else {focusCurrentItem(onFocus);}},[focusCurrentItem,schedule,shouldVirtualizeList]);const maybeFocusInitialItem=React.useCallback(()=>{if(!autoFocus){return}if(open){resetFocusedIndex();scheduleToFocusCurrentItem();}else if(!open){itemsClickedRef.current=false;}},[autoFocus,open,resetFocusedIndex,scheduleToFocusCurrentItem]);React.useEffect(()=>{if(!open){return}const handleInteract=event=>{const target=event.target;const thisElement=rootRef.current;if(thisElement&&!thisElement.contains(target)&&popperElementRef.current&&!popperElementRef.current.contains(target)){onOpenChangedRef.current(false);}};document.addEventListener("mouseup",handleInteract);document.addEventListener("touchend",handleInteract);return ()=>{document.removeEventListener("mouseup",handleInteract);document.removeEventListener("touchend",handleInteract);}},[open,onOpenChangedRef]);useOnMountEffect(()=>{maybeFocusInitialItem();});const prevRenderRef=React.useRef(null);React.useEffect(()=>{const prevProps=prevRenderRef.current;prevRenderRef.current={open,searchText,derivedItems};if(!prevProps||prevProps.derivedItems===derivedItems){return}if(prevProps.open!==open){maybeFocusInitialItem();}else if(open){const{itemRefs,sameItemsFocusable}=derivedItems;if(sameItemsFocusable||prevProps.searchText!==searchText){return}else {const newFocusableIndex=itemRefs.findIndex(ref=>ref.originalIndex===focusedOriginalIndexRef.current);if(newFocusableIndex===-1){focusedIndexRef.current=0;itemsClickedRef.current=false;scheduleToFocusCurrentItem();}else {focusedIndexRef.current=newFocusableIndex;}}}});const focusPreviousItem=React.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=itemRefsRef.current.length-1;}else if(focusedIndexRef.current===0){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=itemRefsRef.current.length-1;}else {focusedIndexRef.current-=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const focusNextItem=React.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=0;}else if(focusedIndexRef.current===itemRefsRef.current.length-1){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=0;}else {focusedIndexRef.current+=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const restoreTabOrder=React.useCallback(()=>{if(openerElement){openerElement.focus();}},[openerElement]);const handleKeyDownDebounceResult=React.useCallback(key=>{const foundIndex=items.filter(item=>item.focusable).findIndex(({component})=>{if(SeparatorItem.isComponentOf(component)){return false}if(OptionItem.isComponentOf(component)){const optionItemProps=component.props;return getLabel(optionItemProps).toLowerCase().startsWith(key.toLowerCase())}return false});if(foundIndex>=0){const isClosed=!open;if(isClosed){onOpenChanged(true);}focusedIndexRef.current=foundIndex;scheduleToFocusCurrentItem(node=>{if(selectionType==="single"&&isClosed&&node){node.click();onOpenChanged(false);}});}textSuggestionRef.current="";},[items,onOpenChanged,open,scheduleToFocusCurrentItem,selectionType]);const handleKeyDownDebounceResultRef=React.useRef(handleKeyDownDebounceResult);handleKeyDownDebounceResultRef.current=handleKeyDownDebounceResult;const handleKeyDownDebounced=React.useMemo(()=>debounce(key=>handleKeyDownDebounceResultRef.current(key),500),[]);const handleKeyDown=event=>{const key=event.key;if(enableTypeAhead&&getStringForKey(key)){event.stopPropagation();textSuggestionRef.current+=key;handleKeyDownDebounced(textSuggestionRef.current);}if(!open){if(key===keys.down){event.preventDefault();onOpenChanged(true);return}return}switch(key){case keys.tab:if(isSearchFieldFocused()&&searchText){return}restoreTabOrder();onOpenChanged(false);return;case keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case keys.up:event.preventDefault();focusPreviousItem();return;case keys.down:event.preventDefault();focusNextItem();return}};const handleKeyUp=event=>{const key=event.key;switch(key){case keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case keys.escape:if(open){event.stopPropagation();restoreTabOrder();onOpenChanged(false);}return}};const handleClickFocus=index=>{itemsClickedRef.current=true;focusedIndexRef.current=index;focusedOriginalIndexRef.current=derivedItems.itemRefs[focusedIndexRef.current].originalIndex;};const handleDropdownMouseUp=event=>{if(event.nativeEvent.stopImmediatePropagation){event.nativeEvent.stopImmediatePropagation();}else {event.stopPropagation();}};const getItemRole=()=>{switch(role){case"listbox":return "option";case"menu":return "menuitem";default:throw new Error(`Expected "listbox" or "menu" for role, but receieved "${role}" instead.`)}};const maybeRenderNoResults=()=>{const noResults=labels?.noResults||strings.noResults;const numResults=items.length;if(numResults===0){return jsx(BodyText,{style:styles$7.noResult,testId:"dropdown-core-no-results",children:noResults})}return null};const handleItemClick=(focusIndex,item)=>{handleClickFocus(focusIndex);if(item.component.props.onClick){item.component.props.onClick();}if(item.populatedProps.onClick){item.populatedProps.onClick();}};const renderList=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{if(SeparatorItem.isComponentOf(item.component)){return item.component}const{component,focusable,populatedProps}=item;if(focusable){focusCounter+=1;}const focusIndex=focusCounter-1;const currentRef=derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null;return React.cloneElement(component,{...populatedProps,key:index,onClick:()=>{handleItemClick(focusIndex,item);},ref:focusable?currentRef:null,role:populatedProps.role||itemRole})})};const parseVirtualizedItems=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{const{populatedProps}=item;if(!SeparatorItem.isComponentOf(item.component)&&item.focusable){focusCounter+=1;}const focusIndex=focusCounter-1;return {...item,role:populatedProps.role||itemRole,ref:item.focusable&&derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null,onClick:()=>{handleItemClick(focusIndex,item);}}})};const renderVirtualizedList=()=>{const virtualizedItems=parseVirtualizedItems();return jsx(DropdownCoreVirtualized$1,{data:virtualizedItems,listRef:virtualizedListRef})};const handleSearchTextChanged=searchText=>{if(onSearchTextChanged){onSearchTextChanged(searchText);}};const renderSearchField=()=>{return jsx(SearchField,{clearAriaLabel:labels?.clearSearch||strings.iconAltClearSearch,onChange:handleSearchTextChanged,placeholder:labels?.filter||strings.filter,ref:searchFieldRef,style:styles$7.searchInputStyle,value:searchText||""})};const renderDropdownMenu=(listRenderer,isReferenceHidden)=>{const openerStyle=openerElement&&window.getComputedStyle(openerElement);const minDropdownWidth=openerStyle?openerStyle.getPropertyValue("width"):0;return jsxs(View,{onMouseUp:handleDropdownMouseUp,style:[styles$7.dropdown,isReferenceHidden&&styles$7.hidden,dropdownStyle],testId:"dropdown-core-container",children:[isFilterable&&renderSearchField(),jsx(View,{id:id,role:role,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,style:[styles$7.listboxOrMenu,{minInlineSize:minDropdownWidth}],"aria-invalid":role==="listbox"?ariaInvalid:undefined,"aria-required":role==="listbox"?ariaRequired:undefined,children:listRenderer}),maybeRenderNoResults()]})};const renderDropdown=()=>{const listRenderer=shouldVirtualizeList()?renderVirtualizedList():renderList();return jsx(DropdownPopper,{alignment:alignment,onPopperElement:popperElement=>{popperElementRef.current=popperElement;},referenceElement:openerElement,children:isReferenceHidden=>renderDropdownMenu(listRenderer,isReferenceHidden)})};return jsxs(View,{ref:rootRef,onKeyDown:!disabled?handleKeyDown:undefined,onKeyUp:!disabled?handleKeyUp:undefined,style:[styles$7.menuWrapper,style],className:className,children:[opener,open&&renderDropdown()]})};const styles$7=StyleSheet.create({menuWrapper:{width:"fit-content",maxInlineSize:"100%"},dropdown:{backgroundColor:semanticColor.core.background.base.default,borderRadius:theme.listbox.border.radius,paddingBlock:theme.listbox.layout.padding.block,paddingInline:theme.listbox.layout.padding.inline,border:`solid ${border.width.thin} ${semanticColor.core.border.neutral.subtle}`,boxShadow:theme.listbox.shadow.default,maxBlockSize:"var(--popper-max-height)"},listboxOrMenu:{overflowY:"auto"},hidden:{pointerEvents:"none",visibility:"hidden"},noResult:{color:semanticColor.core.foreground.neutral.default,alignSelf:"center",marginBlockStart:sizing.size_060},searchInputStyle:{margin:sizing.size_080,marginBlockStart:sizing.size_040,minBlockSize:"auto",position:"sticky"},srOnly:{border:0,clip:"rect(0,0,0,0)",height:1,margin:-1,overflow:"hidden",padding:0,position:"absolute",width:1}});
|
|
60
60
|
|
|
61
61
|
const ActionMenuOpenerCore=React.forwardRef(function ActionMenuOpenerCore(props,ref){const{children,disabled,waiting:_,testId,opened,"aria-label":ariaLabel,...restProps}=props;return jsx(Button,{"aria-expanded":opened?"true":"false","aria-haspopup":"menu",kind:"tertiary","aria-label":ariaLabel,disabled:disabled,...restProps,testId:testId,endIcon:caretDownIcon,ref:ref,children:children})});
|
|
62
62
|
|
|
63
|
-
const ActionMenu=React.forwardRef(function ActionMenu({alignment="left","aria-label":ariaLabel,disabled=false,children,menuText,opened:openedProp,onToggle,onChange,selectedValues,testId,dropdownStyle,style,className,opener,dropdownId,id},ref){const[internalOpened,setInternalOpened]=React.useState(false);const[openerElement,setOpenerElement]=React.useState(null);const generatedUniqueOpenerId=React.useId();const generatedUniqueDropdownId=React.useId();const uniqueOpenerId=id??generatedUniqueOpenerId;const uniqueDropdownId=dropdownId??generatedUniqueDropdownId;const opened=typeof openedProp==="boolean"?openedProp:internalOpened;const handleOpenChanged=React.useCallback(newOpened=>{setInternalOpened(newOpened);if(onToggle){onToggle(newOpened);}},[onToggle]);const handleItemSelected=React.useCallback(()=>{handleOpenChanged(false);openerElement?.focus();},[handleOpenChanged,openerElement]);const handleOptionSelected=React.useCallback(selectedValue=>{if(!onChange||!selectedValues){return}if(selectedValues.includes(selectedValue)){const index=selectedValues.indexOf(selectedValue);const updatedSelection=[...selectedValues.slice(0,index),...selectedValues.slice(index+1)];onChange(updatedSelection);}else {onChange([...selectedValues,selectedValue]);}handleItemSelected();},[onChange,selectedValues,handleItemSelected]);const getMenuItems=React.useCallback(()=>{const allChildren=React.Children.toArray(children).filter(Boolean);const isOptionItemIncluded=allChildren.some(item=>OptionItem.
|
|
63
|
+
const ActionMenu=React.forwardRef(function ActionMenu({alignment="left","aria-label":ariaLabel,disabled=false,children,menuText,opened:openedProp,onToggle,onChange,selectedValues,testId,dropdownStyle,style,className,opener,dropdownId,id},ref){const[internalOpened,setInternalOpened]=React.useState(false);const[openerElement,setOpenerElement]=React.useState(null);const generatedUniqueOpenerId=React.useId();const generatedUniqueDropdownId=React.useId();const uniqueOpenerId=id??generatedUniqueOpenerId;const uniqueDropdownId=dropdownId??generatedUniqueDropdownId;const opened=typeof openedProp==="boolean"?openedProp:internalOpened;const handleOpenChanged=React.useCallback(newOpened=>{setInternalOpened(newOpened);if(onToggle){onToggle(newOpened);}},[onToggle]);const handleItemSelected=React.useCallback(()=>{handleOpenChanged(false);openerElement?.focus();},[handleOpenChanged,openerElement]);const handleOptionSelected=React.useCallback(selectedValue=>{if(!onChange||!selectedValues){return}if(selectedValues.includes(selectedValue)){const index=selectedValues.indexOf(selectedValue);const updatedSelection=[...selectedValues.slice(0,index),...selectedValues.slice(index+1)];onChange(updatedSelection);}else {onChange([...selectedValues,selectedValue]);}handleItemSelected();},[onChange,selectedValues,handleItemSelected]);const getMenuItems=React.useCallback(()=>{const allChildren=React.Children.toArray(children).filter(Boolean);const isOptionItemIncluded=allChildren.some(item=>OptionItem.isComponentOf(item));return allChildren.map(item=>{const{value,disabled}=item.props;const itemObject={component:item,focusable:ActionItem.isComponentOf(item)||OptionItem.isComponentOf(item)?!disabled:false,populatedProps:{}};if(ActionItem.isComponentOf(item)){return {...itemObject,populatedProps:{indent:isOptionItemIncluded,onClick:handleItemSelected}}}else if(OptionItem.isComponentOf(item)){const selected=selectedValues?selectedValues.includes(value):false;return {...itemObject,populatedProps:{onToggle:handleOptionSelected,selected,variant:"check",role:"menuitemcheckbox","aria-checked":selected,"aria-selected":undefined}}}else {return itemObject}})},[children,selectedValues,handleItemSelected,handleOptionSelected]);const handleOpenerRef=React.useCallback(node=>{if(node instanceof HTMLElement||node==null){setOpenerElement(node??null);}else {setOpenerElement(document.getElementById(uniqueOpenerId));}},[uniqueOpenerId]);React.useEffect(()=>{if(openerElement?.isConnected){return}setOpenerElement(document.getElementById(uniqueOpenerId));},[openerElement,opener,uniqueOpenerId]);React.useImperativeHandle(ref,()=>openerElement,[openerElement]);const handleClick=React.useCallback(e=>{handleOpenChanged(!opened);},[handleOpenChanged,opened]);const renderOpener=(numItems,dropdownId)=>{return jsx(DropdownOpener,{id:uniqueOpenerId,"aria-controls":dropdownId,"aria-haspopup":"menu",onClick:handleClick,disabled:numItems===0||disabled,text:menuText,ref:handleOpenerRef,testId:opener?undefined:testId,opened:opened,role:"button","aria-label":ariaLabel,children:opener?opener:openerProps=>{const{text,opened,...eventState}=openerProps;return jsx(ActionMenuOpenerCore,{...eventState,disabled:disabled,opened:!!opened,testId:testId,children:menuText})}})};const items=getMenuItems();return jsx(DropdownCore,{id:uniqueDropdownId,role:"menu",style:style,className:className,opener:renderOpener(items.length,uniqueDropdownId),alignment:alignment,open:opened,items:items,openerElement:openerElement??undefined,onOpenChanged:handleOpenChanged,dropdownStyle:[styles$6.menuTopSpace,dropdownStyle],"aria-labelledby":uniqueOpenerId})});const styles$6=StyleSheet.create({caret:{marginInlineStart:sizing.size_040},opener:{whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},menuTopSpace:{insetBlockStart:`calc(-1 * ${sizing.size_040})`}});
|
|
64
64
|
|
|
65
65
|
const StyledButton$1=addStyle("button");class SelectOpener extends React.Component{render(){const{children,disabled,readOnly,error,id,isPlaceholder,open,testId,"aria-label":ariaLabel,"aria-required":ariaRequired,"aria-controls":ariaControls,onBlur,onOpenChanged,...sharedProps}=this.props;const iconColor=disabled?semanticColor.core.foreground.disabled.default:semanticColor.core.foreground.neutral.default;const style=[styles$5.shared,styles$5.default,disabled&&styles$5.disabled,error&&styles$5.error,isPlaceholder&&styles$5.placeholder,isPlaceholder&&disabled&&styles$5.disabledPlaceholder,!disabled&&!readOnly&&this.state.pressed&&styles$5.press,readOnly&&styles$5.readOnly,readOnly&&isPlaceholder&&styles$5.placeholder];const allowInteraction=!disabled&&!readOnly;return jsxs(StyledButton$1,{...sharedProps,"aria-disabled":readOnly||disabled||undefined,"aria-expanded":open?"true":"false","aria-invalid":error,"aria-label":ariaLabel??undefined,"aria-required":ariaRequired,"aria-haspopup":"listbox","aria-controls":ariaControls,"data-testid":testId,id:id,role:"combobox",type:"button",style:style,onClick:allowInteraction?this.handleClick:undefined,onKeyDown:allowInteraction?this.handleKeyDown:undefined,onKeyUp:allowInteraction?this.handleKeyUp:undefined,onBlur:onBlur,children:[jsx(BodyText,{tag:"span",style:styles$5.text,children:children||jsx("span",{"aria-hidden":"true",children:" "})}),jsx(PhosphorIcon,{icon:caretDownIcon,color:iconColor,size:"small",style:styles$5.caret,"aria-hidden":"true"})]})}constructor(props){super(props),this.handleClick=e=>{const{open}=this.props;this.props.onOpenChanged(!open);},this.handleKeyDown=e=>{const keyName=e.key;if(keyName===keys.enter||keyName===keys.space){this.setState({pressed:true});e.preventDefault();}},this.handleKeyUp=e=>{const keyName=e.key;if(keyName===keys.enter||keyName===keys.space){this.setState({pressed:false});this.handleClick(e);}};this.state={pressed:false};}}SelectOpener.defaultProps={disabled:false,readOnly:false,error:false,isPlaceholder:false};const PRESS_SHADOW=`0 0 0 ${border.width.thin} ${semanticColor.input.default.border}`;const styles$5=StyleSheet.create({shared:{position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"space-between",color:semanticColor.core.foreground.neutral.strong,height:DROPDOWN_ITEM_HEIGHT,paddingInlineStart:theme.opener.layout.padding.inlineStart,paddingInlineEnd:theme.opener.layout.padding.inlineEnd,borderWidth:0,borderRadius:theme.opener.border.radius.rest,borderStyle:"solid",outline:"none",textDecoration:"none",boxSizing:"border-box",whiteSpace:"nowrap",touchAction:"manipulation"},text:{marginInlineEnd:sizing.size_080,whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},caret:{minInlineSize:sizing.size_160},default:{background:semanticColor.input.default.background,border:`${border.width.thin} solid ${semanticColor.input.default.border}`,color:semanticColor.input.default.foreground,cursor:"pointer",":active":{boxShadow:PRESS_SHADOW},":focus":{...focusStyles.focus[":focus-visible"]},[":focus:active"]:{boxShadow:`${PRESS_SHADOW}, ${focusStyles.focus[":focus-visible"].boxShadow}`}},error:{background:semanticColor.input.error.background,border:`${theme.opener.border.width.error} solid ${semanticColor.input.error.border}`,color:semanticColor.input.error.foreground,[":focus:active"]:{boxShadow:`${PRESS_SHADOW}, ${focusStyles.focus[":focus-visible"].boxShadow}`}},disabled:{background:semanticColor.input.disabled.background,border:`${border.width.thin} solid ${semanticColor.input.disabled.border}`,color:semanticColor.input.disabled.foreground,cursor:"not-allowed",":active":{boxShadow:"none"},[":focus:active"]:{boxShadow:focusStyles.focus[":focus-visible"].boxShadow}},press:{boxShadow:PRESS_SHADOW,":focus-visible":{boxShadow:`${PRESS_SHADOW}, ${focusStyles.focus[":focus-visible"].boxShadow}`}},placeholder:{color:semanticColor.input.default.placeholder},disabledPlaceholder:{color:semanticColor.input.disabled.placeholder},readOnly:{background:semanticColor.input.readOnly.background,color:semanticColor.input.readOnly.text,":active":{boxShadow:"none"},[":focus:active"]:{boxShadow:focusStyles.focus[":focus-visible"].boxShadow}}});
|
|
66
66
|
|
|
@@ -46,36 +46,75 @@ export declare function useListbox({ children: options, disabled, disableSpaceSe
|
|
|
46
46
|
isListboxFocused: boolean;
|
|
47
47
|
focusedIndex: number;
|
|
48
48
|
setFocusedIndex: React.Dispatch<React.SetStateAction<number>>;
|
|
49
|
-
renderList: React.ReactElement<
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
renderList: React.ReactElement<{
|
|
50
|
+
readonly "aria-activedescendant"?: string | undefined;
|
|
51
|
+
readonly "aria-atomic"?: boolean | "false" | "true" | undefined;
|
|
52
|
+
readonly "aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined;
|
|
53
|
+
readonly "aria-busy"?: boolean | "false" | "true" | undefined;
|
|
54
|
+
readonly "aria-checked"?: boolean | "false" | "mixed" | "true" | undefined;
|
|
55
|
+
readonly "aria-colcount"?: number | undefined;
|
|
56
|
+
readonly "aria-colindex"?: number | undefined;
|
|
57
|
+
readonly "aria-colspan"?: number | undefined;
|
|
58
|
+
readonly "aria-controls"?: string | undefined;
|
|
59
|
+
readonly "aria-current"?: boolean | "false" | "true" | "page" | "step" | "location" | "date" | "time" | undefined;
|
|
60
|
+
readonly "aria-describedby"?: string | undefined;
|
|
61
|
+
readonly "aria-details"?: string | undefined;
|
|
62
|
+
readonly "aria-disabled"?: boolean | "false" | "true" | undefined;
|
|
63
|
+
readonly "aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined;
|
|
64
|
+
readonly "aria-errormessage"?: string | undefined;
|
|
65
|
+
readonly "aria-expanded"?: boolean | "false" | "true" | undefined;
|
|
66
|
+
readonly "aria-flowto"?: string | undefined;
|
|
67
|
+
readonly "aria-grabbed"?: boolean | "false" | "true" | undefined;
|
|
68
|
+
readonly "aria-haspopup"?: boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | undefined;
|
|
69
|
+
readonly "aria-hidden"?: boolean | "false" | "true" | undefined;
|
|
70
|
+
readonly "aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined;
|
|
71
|
+
readonly "aria-keyshortcuts"?: string | undefined;
|
|
72
|
+
readonly "aria-label"?: string | undefined;
|
|
73
|
+
readonly "aria-labelledby"?: string | undefined;
|
|
74
|
+
readonly "aria-level"?: number | undefined;
|
|
75
|
+
readonly "aria-live"?: "off" | "assertive" | "polite" | undefined;
|
|
76
|
+
readonly "aria-modal"?: boolean | "false" | "true" | undefined;
|
|
77
|
+
readonly "aria-multiline"?: boolean | "false" | "true" | undefined;
|
|
78
|
+
readonly "aria-multiselectable"?: boolean | "false" | "true" | undefined;
|
|
79
|
+
readonly "aria-orientation"?: "horizontal" | "vertical" | undefined;
|
|
80
|
+
readonly "aria-owns"?: string | undefined;
|
|
81
|
+
readonly "aria-placeholder"?: string | undefined;
|
|
82
|
+
readonly "aria-posinset"?: number | undefined;
|
|
83
|
+
readonly "aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined;
|
|
84
|
+
readonly "aria-readonly"?: boolean | "false" | "true" | undefined;
|
|
85
|
+
readonly "aria-relevant"?: "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text" | "text additions" | "text removals" | undefined;
|
|
86
|
+
readonly "aria-required"?: boolean | "false" | "true" | undefined;
|
|
87
|
+
readonly "aria-roledescription"?: string | undefined;
|
|
88
|
+
readonly "aria-rowcount"?: number | undefined;
|
|
89
|
+
readonly "aria-rowindex"?: number | undefined;
|
|
90
|
+
readonly "aria-rowspan"?: number | undefined;
|
|
91
|
+
readonly "aria-selected"?: boolean | "false" | "true" | undefined;
|
|
92
|
+
readonly "aria-setsize"?: number | undefined;
|
|
93
|
+
readonly "aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined;
|
|
94
|
+
readonly "aria-valuemax"?: number | undefined;
|
|
95
|
+
readonly "aria-valuemin"?: number | undefined;
|
|
96
|
+
readonly "aria-valuenow"?: number | undefined;
|
|
97
|
+
readonly "aria-valuetext"?: string | undefined;
|
|
98
|
+
role?: "menuitem" | "menuitemcheckbox" | "option" | undefined;
|
|
52
99
|
label: import("../util/types").OptionLabel;
|
|
53
100
|
labelAsText?: string;
|
|
54
101
|
value: string;
|
|
55
|
-
disabled
|
|
102
|
+
disabled?: boolean | undefined;
|
|
56
103
|
onClick?: () => unknown;
|
|
57
|
-
onToggle
|
|
58
|
-
selected
|
|
59
|
-
focused
|
|
60
|
-
role: "menuitem" | "option" | "menuitemcheckbox";
|
|
104
|
+
onToggle?: ((value: string) => unknown) | undefined;
|
|
105
|
+
selected?: boolean | undefined;
|
|
106
|
+
focused?: boolean | undefined;
|
|
61
107
|
testId?: string;
|
|
62
108
|
variant?: "check" | "checkbox";
|
|
63
109
|
style?: import("@khanacademy/wonder-blocks-core").StyleType;
|
|
64
110
|
parentComponent?: "dropdown" | "listbox";
|
|
65
111
|
id?: string;
|
|
66
|
-
horizontalRule
|
|
112
|
+
horizontalRule?: import("../util/types").CellProps["horizontalRule"];
|
|
67
113
|
leftAccessory?: import("../util/types").CellProps["leftAccessory"];
|
|
68
114
|
rightAccessory?: import("../util/types").CellProps["rightAccessory"];
|
|
69
115
|
subtitle1?: import("../util/types").CellProps["subtitle1"];
|
|
70
116
|
subtitle2?: import("../util/types").CellProps["subtitle2"];
|
|
71
|
-
}
|
|
72
|
-
role?: "menuitem" | "menuitemcheckbox" | "option" | undefined;
|
|
73
|
-
disabled?: boolean | undefined;
|
|
74
|
-
onToggle?: ((value: string) => unknown) | undefined;
|
|
75
|
-
selected?: boolean | undefined;
|
|
76
|
-
focused?: boolean | undefined;
|
|
77
|
-
horizontalRule?: import("../util/types").CellProps["horizontalRule"];
|
|
78
|
-
} & {}, string | React.JSXElementConstructor<any>>[];
|
|
117
|
+
} & React.RefAttributes<HTMLElement>, string | React.JSXElementConstructor<any>>[];
|
|
79
118
|
setSelected: React.Dispatch<React.SetStateAction<string | import("../util/types").MaybeString[] | null | undefined>>;
|
|
80
119
|
selected: string | import("../util/types").MaybeString[] | null | undefined;
|
|
81
120
|
handleKeyDown: (event: React.KeyboardEvent) => void;
|
package/dist/index.js
CHANGED
|
@@ -13,10 +13,10 @@ var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
|
|
|
13
13
|
var wonderBlocksIcon = require('@khanacademy/wonder-blocks-icon');
|
|
14
14
|
var checkIcon = require('@phosphor-icons/core/bold/check-bold.svg');
|
|
15
15
|
var wonderBlocksClickable = require('@khanacademy/wonder-blocks-clickable');
|
|
16
|
-
var ReactDOM = require('react-dom');
|
|
17
16
|
var SearchField = require('@khanacademy/wonder-blocks-search-field');
|
|
18
17
|
var wonderBlocksTiming = require('@khanacademy/wonder-blocks-timing');
|
|
19
18
|
var wonderBlocksConfig = require('@khanacademy/wonder-blocks-config');
|
|
19
|
+
var ReactDOM = require('react-dom');
|
|
20
20
|
var reactWindow = require('react-window');
|
|
21
21
|
var reactPopper = require('react-popper');
|
|
22
22
|
var wonderBlocksModal = require('@khanacademy/wonder-blocks-modal');
|
|
@@ -51,8 +51,8 @@ function _interopNamespace(e) {
|
|
|
51
51
|
|
|
52
52
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
53
53
|
var checkIcon__default = /*#__PURE__*/_interopDefaultLegacy(checkIcon);
|
|
54
|
-
var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
|
|
55
54
|
var SearchField__default = /*#__PURE__*/_interopDefaultLegacy(SearchField);
|
|
55
|
+
var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
|
|
56
56
|
var caretDownIcon__default = /*#__PURE__*/_interopDefaultLegacy(caretDownIcon);
|
|
57
57
|
var Button__default = /*#__PURE__*/_interopDefaultLegacy(Button);
|
|
58
58
|
var caretDownIcon__default$1 = /*#__PURE__*/_interopDefaultLegacy(caretDownIcon$1);
|
|
@@ -65,23 +65,23 @@ var themeDefault = {listbox:{border:{radius:wonderBlocksTokens.border.radius.rad
|
|
|
65
65
|
|
|
66
66
|
var theme = wonderBlocksTokens.mapValuesToCssVars(themeDefault,"--wb-c-dropdown-");
|
|
67
67
|
|
|
68
|
-
class
|
|
68
|
+
class ActionItemInner extends React__namespace.Component{render(){const{disabled,horizontalRule,href,target,indent,label,lang,leftAccessory,rightAccessory,onClick,role,style,subtitle1,subtitle2,testId,active,"aria-label":ariaLabel,forwardedRef}=this.props;const defaultStyle=[styles$c.wrapper,style];const labelComponent=typeof label==="string"?jsxRuntime.jsx(wonderBlocksTypography.BodyText,{tag:"div",lang:lang,style:styles$c.label,children:label}):React__namespace.cloneElement(label,{lang,style:styles$c.label,...label.props});return jsxRuntime.jsx(wonderBlocksCell.DetailCell,{disabled:disabled,horizontalRule:horizontalRule,leftAccessory:leftAccessory,rightAccessory:rightAccessory,styles:{root:[defaultStyle,styles$c.shared,indent&&styles$c.indent]},role:role,testId:testId,subtitle1:subtitle1,title:labelComponent,subtitle2:subtitle2,href:href,target:target,onClick:onClick,active:active,"aria-label":ariaLabel,ref:forwardedRef})}}ActionItemInner.defaultProps={disabled:false,horizontalRule:"none",indent:false,role:"menuitem"};const isComponentOf$1=instance=>{if(typeof instance!=="object"||instance===null){return false}const type="type"in instance?instance.type:undefined;return typeof type==="object"&&type!==null&&"__IS_ACTION_ITEM__"in type&&type.__IS_ACTION_ITEM__===true};const ActionItem=React__namespace.forwardRef(function ActionItem(props,ref){return jsxRuntime.jsx(ActionItemInner,{...props,forwardedRef:ref})});ActionItem.isComponentOf=isComponentOf$1;ActionItem.__IS_ACTION_ITEM__=true;const styles$c=aphrodite.StyleSheet.create({wrapper:{minBlockSize:DROPDOWN_ITEM_HEIGHT,touchAction:"manipulation",":focus":{borderRadius:theme.item.border.radius.default,outline:wonderBlocksStyles.focusStyles.focus[":focus-visible"].outline,outlineOffset:`calc(${wonderBlocksTokens.border.width.medium} * -1)`,boxShadow:`inset 0 0 0 calc(${wonderBlocksTokens.border.width.medium}*2) ${wonderBlocksTokens.semanticColor.focus.inner}`,[":after"]:{content:"unset"}}},shared:{minBlockSize:DROPDOWN_ITEM_HEIGHT,paddingBlock:theme.item.layout.padding.block},label:{fontWeight:theme.item.font.weight,lineHeight:wonderBlocksTokens.sizing.size_200,whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},indent:{paddingInlineStart:wonderBlocksTokens.sizing.size_320}});
|
|
69
69
|
|
|
70
70
|
const Check=function(props){const{selected,disabled}=props;const iconColor=disabled?wonderBlocksTokens.semanticColor.core.foreground.disabled.strong:wonderBlocksTokens.semanticColor.core.foreground.instructive.default;return jsxRuntime.jsx(wonderBlocksIcon.PhosphorIcon,{color:iconColor,icon:checkIcon__default["default"],size:"small",style:[styles$b.bounds,!selected&&styles$b.hide]})};const styles$b=aphrodite.StyleSheet.create({bounds:{alignSelf:"center",height:wonderBlocksTokens.sizing.size_160,minBlockSize:wonderBlocksTokens.sizing.size_160,minInlineSize:wonderBlocksTokens.sizing.size_160},hide:{visibility:"hidden"}});
|
|
71
71
|
|
|
72
72
|
const Checkbox=function(props){const{disabled,selected}=props;return jsxRuntime.jsx(wonderBlocksCore.View,{className:"checkbox",style:[styles$a.checkbox,selected&&!disabled&&styles$a.selected,disabled&&styles$a.disabledCheckbox],children:selected&&jsxRuntime.jsx(wonderBlocksIcon.PhosphorIcon,{icon:checkIcon__default["default"],size:"small",className:"check",style:[{width:wonderBlocksTokens.sizing.size_120,height:wonderBlocksTokens.sizing.size_120,margin:wonderBlocksTokens.sizing.size_020},disabled&&selected&&styles$a.disabledCheckFormatting]})})};const checkboxTokens={color:{default:{border:wonderBlocksTokens.semanticColor.input.default.border,background:wonderBlocksTokens.semanticColor.input.default.background},disabled:{border:wonderBlocksTokens.semanticColor.input.disabled.border,background:wonderBlocksTokens.semanticColor.input.disabled.background},selected:{background:wonderBlocksTokens.semanticColor.input.checked.background,foreground:wonderBlocksTokens.semanticColor.input.checked.foreground}}};const styles$a=aphrodite.StyleSheet.create({checkbox:{alignSelf:"center",minBlockSize:wonderBlocksTokens.sizing.size_160,minInlineSize:wonderBlocksTokens.sizing.size_160,height:wonderBlocksTokens.sizing.size_160,background:checkboxTokens.color.default.background,borderRadius:3,borderWidth:wonderBlocksTokens.border.width.thin,borderStyle:"solid",borderColor:checkboxTokens.color.default.border},selected:{borderWidth:0,background:checkboxTokens.color.selected.background,color:checkboxTokens.color.selected.foreground},disabledCheckbox:{borderColor:checkboxTokens.color.disabled.border,backgroundColor:checkboxTokens.color.disabled.background},disabledCheckFormatting:{position:"absolute",insetBlockStart:-1,insetInlineStart:-1}});
|
|
73
73
|
|
|
74
|
-
class
|
|
74
|
+
class OptionItemInner extends React__namespace.Component{getCheckComponent(){if(this.props.variant==="check"){return Check}else {return Checkbox}}render(){const{disabled,focused,label,selected,testId,leftAccessory,horizontalRule,parentComponent,rightAccessory,style,subtitle1,subtitle2,value,onClick,onToggle,variant,role,forwardedRef,...sharedProps}=this.props;const CheckComponent=this.getCheckComponent();const defaultStyle=[styles$9.optionItem,style];const listboxStyles=[styles$9.listboxOptionItem,focused&&styles$9.listboxOptionItemFocused];const selectStyles=[styles$9.selectOptionItem];return jsxRuntime.jsx(wonderBlocksCell.DetailCell,{disabled:disabled,horizontalRule:horizontalRule,styles:{root:[defaultStyle,parentComponent==="listbox"?listboxStyles:selectStyles]},"aria-selected":selected?"true":"false",role:role,testId:testId,leftAccessory:jsxRuntime.jsx(jsxRuntime.Fragment,{children:leftAccessory?jsxRuntime.jsxs(wonderBlocksCore.View,{style:{flexDirection:"row",gap:wonderBlocksTokens.sizing.size_080},children:[jsxRuntime.jsx(CheckComponent,{disabled:disabled,selected:selected}),leftAccessory]}):jsxRuntime.jsx(CheckComponent,{disabled:disabled,selected:selected})}),rightAccessory:rightAccessory,subtitle1:subtitle1,title:jsxRuntime.jsx(wonderBlocksTypography.BodyText,{tag:"div",style:styles$9.label,children:label}),subtitle2:subtitle2,onClick:this.handleClick,tabIndex:parentComponent==="listbox"?-1:undefined,...sharedProps,ref:forwardedRef})}constructor(...args){super(...args),this.handleClick=()=>{const{onClick,onToggle,value}=this.props;onToggle(value);if(onClick){onClick();}};}}OptionItemInner.defaultProps={disabled:false,focused:false,horizontalRule:"none",onToggle:()=>void 0,role:"option",selected:false};const isComponentOf=instance=>{if(typeof instance!=="object"||instance===null){return false}const type="type"in instance?instance.type:undefined;return typeof type==="object"&&type!==null&&"__IS_OPTION_ITEM__"in type&&type.__IS_OPTION_ITEM__===true};const OptionItem=React__namespace.forwardRef(function OptionItem(props,ref){return jsxRuntime.jsx(OptionItemInner,{...props,forwardedRef:ref})});OptionItem.isComponentOf=isComponentOf;OptionItem.__IS_OPTION_ITEM__=true;const focusedStyle={borderRadius:theme.item.border.radius.default,outline:wonderBlocksStyles.focusStyles.focus[":focus-visible"].outline,outlineOffset:`calc(${wonderBlocksTokens.border.width.medium} * -1)`,boxShadow:`inset 0 0 0 calc(${wonderBlocksTokens.border.width.medium}*2) ${wonderBlocksTokens.semanticColor.focus.inner}`};const resetFocusStyle={outline:"none",boxShadow:"none"};const styles$9=aphrodite.StyleSheet.create({optionItem:{paddingBlock:theme.item.layout.padding.block,paddingInlineStart:theme.item.layout.padding.inlineStart,paddingInlineEnd:theme.item.layout.padding.inlineEnd,whiteSpace:"nowrap",minBlockSize:wonderBlocksTokens.sizing.size_400,":active":{borderRadius:theme.item.border.radius.press},[":is([aria-disabled=true])"]:{":focus":resetFocusStyle}},listboxOptionItem:{":focus-visible":resetFocusStyle},listboxOptionItemFocused:{...focusedStyle,":focus-visible":focusedStyle},selectOptionItem:{":focus":focusedStyle},label:{fontWeight:theme.item.font.weight,lineHeight:wonderBlocksTokens.sizing.size_200,whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},hide:{visibility:"hidden"}});
|
|
75
75
|
|
|
76
|
-
class SeparatorItem extends React__namespace.Component{static
|
|
76
|
+
class SeparatorItem extends React__namespace.Component{static isComponentOf(instance){if(typeof instance!=="object"||instance===null){return false}const type="type"in instance?instance.type:undefined;return typeof type==="function"&&"__IS_SEPARATOR_ITEM__"in type&&type.__IS_SEPARATOR_ITEM__===true}render(){return jsxRuntime.jsx(wonderBlocksCore.View,{style:[styles$8.separator,this.props.style],"aria-hidden":"true"})}}SeparatorItem.__IS_SEPARATOR_ITEM__=true;const styles$8=aphrodite.StyleSheet.create({separator:{borderBlockStart:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,height:1,minBlockSize:1,marginBlock:wonderBlocksTokens.sizing.size_040}});
|
|
77
77
|
|
|
78
78
|
const DropdownOpener=React__namespace.forwardRef((props,ref)=>{const{disabled=false,readOnly=false,testId,text,opened,"aria-controls":ariaControls,"aria-haspopup":ariaHasPopUp,"aria-required":ariaRequired,"aria-label":ariaLabel,id,role,onBlur,onClick,children,error}=props;const renderAnchorChildren=(eventState,clickableChildrenProps)=>{const renderedChildren=children({...eventState,text,opened});const childrenProps=renderedChildren.props;const childrenTestId=childrenProps?.testId||childrenProps?.["data-testid"];const renderedAriaLabel=childrenProps["aria-label"]??ariaLabel;return React__namespace.cloneElement(renderedChildren,{...clickableChildrenProps,ref,"aria-label":renderedAriaLabel??undefined,"aria-invalid":error,disabled,"aria-controls":ariaControls,role,id,"aria-expanded":opened?"true":"false","aria-haspopup":ariaHasPopUp,"aria-required":ariaRequired,"aria-disabled":readOnly||disabled||undefined,onClick:childrenProps.onClick?e=>{childrenProps.onClick(e);clickableChildrenProps.onClick(e);}:clickableChildrenProps.onClick,"data-testid":childrenTestId||testId,onBlur:onBlur?e=>{onBlur(e);clickableChildrenProps.onBlur(e);}:clickableChildrenProps.onBlur})};return jsxRuntime.jsx(wonderBlocksClickable.ClickableBehavior,{onClick:onClick,disabled:disabled||readOnly,tabIndex:0,children:(eventState,handlers)=>renderAnchorChildren(eventState,handlers)})});DropdownOpener.displayName="DropdownOpener";
|
|
79
79
|
|
|
80
|
-
class DropdownVirtualizedItem extends React__namespace.Component{render(){const{data,index,style}=this.props;const item=data[index];if(SeparatorItem.
|
|
80
|
+
class DropdownVirtualizedItem extends React__namespace.Component{render(){const{data,index,style}=this.props;const item=data[index];if(SeparatorItem.isComponentOf(item.component)){return React__namespace.cloneElement(item.component,{style})}else {const{component,populatedProps,onClick,role,ref}=item;return React__namespace.cloneElement(component,{style,...populatedProps,key:index,onClick,ref:item.focusable&&ref,role})}}}
|
|
81
81
|
|
|
82
|
-
function getDropdownMenuHeight(items,initialHeight=0){return items.slice(0,MAX_VISIBLE_ITEMS).reduce((sum,item)=>{if(SeparatorItem.
|
|
82
|
+
function getDropdownMenuHeight(items,initialHeight=0){return items.slice(0,MAX_VISIBLE_ITEMS).reduce((sum,item)=>{if(SeparatorItem.isComponentOf(item.component)){return sum+SEPARATOR_ITEM_HEIGHT}else {return sum+DROPDOWN_ITEM_HEIGHT}},initialHeight)}
|
|
83
83
|
|
|
84
|
-
class DropdownCoreVirtualized extends React__namespace.Component{componentDidMount(){const{schedule}=this.props;schedule.animationFrame(()=>{this.setWidth();});}componentDidUpdate(prevProps){const{data,listRef}=this.props;if(prevProps.data.length!==data.length){this.setHeight();if(listRef&&listRef.current){listRef.current.resetAfterIndex(1);}}}setWidth(){const rootNode=ReactDOM__namespace.findDOMNode(this);const parentNode=rootNode?.parentElement;if(parentNode){const width=parentNode.getBoundingClientRect().width;this.setState({width});}}setHeight(){const height=getDropdownMenuHeight(this.props.data);this.setState({height});}renderInitialItems(){const{data}=this.props;const allComponents=data.map(e=>e.component);const longestItems=React__namespace.Children.toArray(allComponents).filter(Boolean).sort((a,b)=>{if(b.props.label&&a.props.label){return b.props.label.length-a.props.label.length}return -1}).slice(0,MAX_VISIBLE_ITEMS);return longestItems.map(item=>React__namespace.cloneElement(item,{style:{visibility:"hidden"}}))}renderVirtualizedList(width,height){const{data,listRef}=this.props;return jsxRuntime.jsx(reactWindow.VariableSizeList,{height:height,itemCount:data.length,itemSize:this.getItemSize,itemData:data,style:{overflowX:"hidden"},width:width,overscanCount:5,ref:listRef,children:DropdownVirtualizedItem})}render(){const{width,height}=this.state;if(width==null){return this.renderInitialItems()}else {return this.renderVirtualizedList(width,height)}}constructor(props){super(props),this.getItemSize=index=>{const item=this.props.data[index];if(SeparatorItem.
|
|
84
|
+
class DropdownCoreVirtualized extends React__namespace.Component{componentDidMount(){const{schedule}=this.props;schedule.animationFrame(()=>{this.setWidth();});}componentDidUpdate(prevProps){const{data,listRef}=this.props;if(prevProps.data.length!==data.length){this.setHeight();if(listRef&&listRef.current){listRef.current.resetAfterIndex(1);}}}setWidth(){const rootNode=ReactDOM__namespace.findDOMNode(this);const parentNode=rootNode?.parentElement;if(parentNode){const width=parentNode.getBoundingClientRect().width;this.setState({width});}}setHeight(){const height=getDropdownMenuHeight(this.props.data);this.setState({height});}renderInitialItems(){const{data}=this.props;const allComponents=data.map(e=>e.component);const longestItems=React__namespace.Children.toArray(allComponents).filter(Boolean).sort((a,b)=>{if(b.props.label&&a.props.label){return b.props.label.length-a.props.label.length}return -1}).slice(0,MAX_VISIBLE_ITEMS);return longestItems.map(item=>React__namespace.cloneElement(item,{style:{visibility:"hidden"}}))}renderVirtualizedList(width,height){const{data,listRef}=this.props;return jsxRuntime.jsx(reactWindow.VariableSizeList,{height:height,itemCount:data.length,itemSize:this.getItemSize,itemData:data,style:{overflowX:"hidden"},width:width,overscanCount:5,ref:listRef,children:DropdownVirtualizedItem})}render(){const{width,height}=this.state;if(width==null){return this.renderInitialItems()}else {return this.renderVirtualizedList(width,height)}}constructor(props){super(props),this.getItemSize=index=>{const item=this.props.data[index];if(SeparatorItem.isComponentOf(item.component)){return SEPARATOR_ITEM_HEIGHT}else {return DROPDOWN_ITEM_HEIGHT}};this.state={height:getDropdownMenuHeight(props.data),width:props.width};}}var DropdownCoreVirtualized$1 = wonderBlocksTiming.withActionScheduler(DropdownCoreVirtualized);
|
|
85
85
|
|
|
86
86
|
function modifyMaxHeight({state,options}){const overflow=core.detectOverflow(state,options);const{y}=state.modifiersData.preventOverflow||{x:0,y:0};const{height}=state.rects.popper;const[basePlacement]=state.placement.split("-");const heightProp=basePlacement==="top"?"top":"bottom";const maxHeight=height-overflow[heightProp]-y;state.styles.popper={...state.styles.popper,maxHeight:`${maxHeight}px`,["--popper-max-height"]:`${maxHeight}px`};}const maxHeightModifier={name:"maxHeight",enabled:true,phase:"main",options:{padding:DROPDOWN_ITEM_HEIGHT},requiresIfExists:["offset","preventOverflow","flip"],fn:modifyMaxHeight};
|
|
87
87
|
|
|
@@ -89,11 +89,11 @@ const modifiers=[{name:"preventOverflow",options:{rootBoundary:"viewport",altAxi
|
|
|
89
89
|
|
|
90
90
|
function getStringForKey(key){if(key.length===1||!/^[A-Z]/i.test(key)){return key}return ""}function debounce(callback,wait){let timeout;return function executedFunction(...args){const later=()=>{clearTimeout(timeout);callback(...args);};clearTimeout(timeout);timeout=setTimeout(later,wait);}}function isString(x){return typeof x==="string"}function getLabel(props){if(isString(props.label)){return props.label}if(isString(props.labelAsText)){return props.labelAsText}return ""}function getSelectOpenerLabel(showOpenerLabelAsText,props){if(showOpenerLabelAsText){return getLabel(props)}return props.label}function getListboxLabelProps({ariaLabel,ariaLabelledBy,openerElement}){const openerLabel=getOpenerLabel(openerElement);const labelId=ariaLabelledBy||openerLabel?.id;if(labelId){return {"aria-labelledby":labelId}}const label=openerLabel?.textContent||ariaLabel;return label?{"aria-label":label}:{}}function getOpenerLabel(openerElement){if(!openerElement||!("labels"in openerElement)){return undefined}return openerElement.labels?.[0]}
|
|
91
91
|
|
|
92
|
-
const VIRTUALIZE_THRESHOLD=125;const sameItemsFocusable=(prevItems,currentItems)=>{if(prevItems.length!==currentItems.length){return false}for(let i=0;i<prevItems.length;i++){if(prevItems[i].focusable!==currentItems[i].focusable){return false}}return true};const createItemRefs=items=>{const itemRefs=[];for(let i=0;i<items.length;i++){if(items[i].focusable){const ref=React__namespace.createRef();itemRefs.push({ref,originalIndex:i});}}return itemRefs};const DropdownCore=props=>{const{strings}=wonderBlocksConfig.useWonderBlocksI18n();const{"aria-invalid":ariaInvalid,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,"aria-required":ariaRequired,alignment="left",autoFocus=true,className,disabled,dropdownStyle,enableTypeAhead=true,id,initialFocusedIndex,isFilterable,items,labels,onOpenChanged,onSearchTextChanged,open,opener,openerElement,role,searchText,selectionType="single",style}=props;const schedule=wonderBlocksTiming.useActionScheduler();const openRef=wonderBlocksCore.useLatestRef(open);const onOpenChangedRef=wonderBlocksCore.useLatestRef(onOpenChanged);const rootRef=React__namespace.useRef(null);const popperElementRef=React__namespace.useRef(undefined);const virtualizedListRef=React__namespace.useRef(null);const searchFieldRef=React__namespace.useRef(null);const textSuggestionRef=React__namespace.useRef("");const committedItemsRef=React__namespace.useRef({itemRefs:[],prevItems:items});const{itemRefs:prevItemRefs,prevItems}=committedItemsRef.current;const shouldCreateItemRefs=prevItemRefs.length===0&&open||!sameItemsFocusable(prevItems,items);const derivedItems=shouldCreateItemRefs?{itemRefs:createItemRefs(items),sameItemsFocusable:false}:{itemRefs:prevItemRefs,sameItemsFocusable:true};const itemRefsRef=React__namespace.useRef(derivedItems.itemRefs);React__namespace.useEffect(()=>{committedItemsRef.current={itemRefs:derivedItems.itemRefs,prevItems:items};itemRefsRef.current=derivedItems.itemRefs;});const hasSearchField=React__namespace.useCallback(()=>{return !!isFilterable},[isFilterable]);const isSearchFieldFocused=React__namespace.useCallback(()=>{return hasSearchField()&&document.activeElement===searchFieldRef.current},[hasSearchField]);const focusSearchField=React__namespace.useCallback(()=>{if(searchFieldRef.current){searchFieldRef.current.focus();}},[]);const focusedIndexRef=React__namespace.useRef(-1);const focusedOriginalIndexRef=React__namespace.useRef(-1);const itemsClickedRef=React__namespace.useRef(false);const resetFocusedIndex=React__namespace.useCallback(()=>{if(typeof initialFocusedIndex!=="undefined"){focusedIndexRef.current=initialFocusedIndex;}else {if(hasSearchField()&&!isSearchFieldFocused()){return focusSearchField()}focusedIndexRef.current=0;}},[focusSearchField,hasSearchField,initialFocusedIndex,isSearchFieldFocused]);const initializedRef=React__namespace.useRef(false);if(!initializedRef.current){initializedRef.current=true;resetFocusedIndex();}const shouldVirtualizeList=React__namespace.useCallback(()=>{return items.length>VIRTUALIZE_THRESHOLD},[items]);const focusCurrentItem=React__namespace.useCallback(onFocus=>{const focusedItemRef=itemRefsRef.current[focusedIndexRef.current];if(!focusedItemRef){return}const{current:virtualizedList}=virtualizedListRef;if(virtualizedList){virtualizedList.scrollToItem(focusedItemRef.originalIndex);}const focusNode=()=>{if(!openRef.current){return}const currentFocusedItemRef=itemRefsRef.current[focusedIndexRef.current];const node=ReactDOM__namespace.findDOMNode(currentFocusedItemRef.ref.current);if(!node&&shouldVirtualizeList()){schedule.animationFrame(focusNode);return}if(node){schedule.timeout(()=>{node.focus();},0);focusedOriginalIndexRef.current=currentFocusedItemRef.originalIndex;if(onFocus){onFocus(node);}}};if(shouldVirtualizeList()){schedule.animationFrame(focusNode);}else {focusNode();}},[openRef,schedule,shouldVirtualizeList]);const scheduleToFocusCurrentItem=React__namespace.useCallback(onFocus=>{if(shouldVirtualizeList()){schedule.animationFrame(()=>{focusCurrentItem(onFocus);});}else {focusCurrentItem(onFocus);}},[focusCurrentItem,schedule,shouldVirtualizeList]);const maybeFocusInitialItem=React__namespace.useCallback(()=>{if(!autoFocus){return}if(open){resetFocusedIndex();scheduleToFocusCurrentItem();}else if(!open){itemsClickedRef.current=false;}},[autoFocus,open,resetFocusedIndex,scheduleToFocusCurrentItem]);React__namespace.useEffect(()=>{if(!open){return}const handleInteract=event=>{const target=event.target;const thisElement=rootRef.current;if(thisElement&&!thisElement.contains(target)&&popperElementRef.current&&!popperElementRef.current.contains(target)){onOpenChangedRef.current(false);}};document.addEventListener("mouseup",handleInteract);document.addEventListener("touchend",handleInteract);return ()=>{document.removeEventListener("mouseup",handleInteract);document.removeEventListener("touchend",handleInteract);}},[open,onOpenChangedRef]);wonderBlocksCore.useOnMountEffect(()=>{maybeFocusInitialItem();});const prevRenderRef=React__namespace.useRef(null);React__namespace.useEffect(()=>{const prevProps=prevRenderRef.current;prevRenderRef.current={open,searchText,derivedItems};if(!prevProps||prevProps.derivedItems===derivedItems){return}if(prevProps.open!==open){maybeFocusInitialItem();}else if(open){const{itemRefs,sameItemsFocusable}=derivedItems;if(sameItemsFocusable||prevProps.searchText!==searchText){return}else {const newFocusableIndex=itemRefs.findIndex(ref=>ref.originalIndex===focusedOriginalIndexRef.current);if(newFocusableIndex===-1){focusedIndexRef.current=0;itemsClickedRef.current=false;scheduleToFocusCurrentItem();}else {focusedIndexRef.current=newFocusableIndex;}}}});const focusPreviousItem=React__namespace.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=itemRefsRef.current.length-1;}else if(focusedIndexRef.current===0){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=itemRefsRef.current.length-1;}else {focusedIndexRef.current-=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const focusNextItem=React__namespace.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=0;}else if(focusedIndexRef.current===itemRefsRef.current.length-1){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=0;}else {focusedIndexRef.current+=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const restoreTabOrder=React__namespace.useCallback(()=>{if(openerElement){openerElement.focus();}},[openerElement]);const handleKeyDownDebounceResult=React__namespace.useCallback(key=>{const foundIndex=items.filter(item=>item.focusable).findIndex(({component})=>{if(SeparatorItem.isClassOf(component)){return false}if(OptionItem.isClassOf(component)){const optionItemProps=component.props;return getLabel(optionItemProps).toLowerCase().startsWith(key.toLowerCase())}return false});if(foundIndex>=0){const isClosed=!open;if(isClosed){onOpenChanged(true);}focusedIndexRef.current=foundIndex;scheduleToFocusCurrentItem(node=>{if(selectionType==="single"&&isClosed&&node){node.click();onOpenChanged(false);}});}textSuggestionRef.current="";},[items,onOpenChanged,open,scheduleToFocusCurrentItem,selectionType]);const handleKeyDownDebounceResultRef=React__namespace.useRef(handleKeyDownDebounceResult);handleKeyDownDebounceResultRef.current=handleKeyDownDebounceResult;const handleKeyDownDebounced=React__namespace.useMemo(()=>debounce(key=>handleKeyDownDebounceResultRef.current(key),500),[]);const handleKeyDown=event=>{const key=event.key;if(enableTypeAhead&&getStringForKey(key)){event.stopPropagation();textSuggestionRef.current+=key;handleKeyDownDebounced(textSuggestionRef.current);}if(!open){if(key===wonderBlocksCore.keys.down){event.preventDefault();onOpenChanged(true);return}return}switch(key){case wonderBlocksCore.keys.tab:if(isSearchFieldFocused()&&searchText){return}restoreTabOrder();onOpenChanged(false);return;case wonderBlocksCore.keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case wonderBlocksCore.keys.up:event.preventDefault();focusPreviousItem();return;case wonderBlocksCore.keys.down:event.preventDefault();focusNextItem();return}};const handleKeyUp=event=>{const key=event.key;switch(key){case wonderBlocksCore.keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case wonderBlocksCore.keys.escape:if(open){event.stopPropagation();restoreTabOrder();onOpenChanged(false);}return}};const handleClickFocus=index=>{itemsClickedRef.current=true;focusedIndexRef.current=index;focusedOriginalIndexRef.current=derivedItems.itemRefs[focusedIndexRef.current].originalIndex;};const handleDropdownMouseUp=event=>{if(event.nativeEvent.stopImmediatePropagation){event.nativeEvent.stopImmediatePropagation();}else {event.stopPropagation();}};const getItemRole=()=>{switch(role){case"listbox":return "option";case"menu":return "menuitem";default:throw new Error(`Expected "listbox" or "menu" for role, but receieved "${role}" instead.`)}};const maybeRenderNoResults=()=>{const noResults=labels?.noResults||strings.noResults;const numResults=items.length;if(numResults===0){return jsxRuntime.jsx(wonderBlocksTypography.BodyText,{style:styles$7.noResult,testId:"dropdown-core-no-results",children:noResults})}return null};const handleItemClick=(focusIndex,item)=>{handleClickFocus(focusIndex);if(item.component.props.onClick){item.component.props.onClick();}if(item.populatedProps.onClick){item.populatedProps.onClick();}};const renderList=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{if(SeparatorItem.isClassOf(item.component)){return item.component}const{component,focusable,populatedProps}=item;if(focusable){focusCounter+=1;}const focusIndex=focusCounter-1;const currentRef=derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null;return React__namespace.cloneElement(component,{...populatedProps,key:index,onClick:()=>{handleItemClick(focusIndex,item);},ref:focusable?currentRef:null,role:populatedProps.role||itemRole})})};const parseVirtualizedItems=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{const{populatedProps}=item;if(!SeparatorItem.isClassOf(item.component)&&item.focusable){focusCounter+=1;}const focusIndex=focusCounter-1;return {...item,role:populatedProps.role||itemRole,ref:item.focusable&&derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null,onClick:()=>{handleItemClick(focusIndex,item);}}})};const renderVirtualizedList=()=>{const virtualizedItems=parseVirtualizedItems();return jsxRuntime.jsx(DropdownCoreVirtualized$1,{data:virtualizedItems,listRef:virtualizedListRef})};const handleSearchTextChanged=searchText=>{if(onSearchTextChanged){onSearchTextChanged(searchText);}};const renderSearchField=()=>{return jsxRuntime.jsx(SearchField__default["default"],{clearAriaLabel:labels?.clearSearch||strings.iconAltClearSearch,onChange:handleSearchTextChanged,placeholder:labels?.filter||strings.filter,ref:searchFieldRef,style:styles$7.searchInputStyle,value:searchText||""})};const renderDropdownMenu=(listRenderer,isReferenceHidden)=>{const openerStyle=openerElement&&window.getComputedStyle(openerElement);const minDropdownWidth=openerStyle?openerStyle.getPropertyValue("width"):0;return jsxRuntime.jsxs(wonderBlocksCore.View,{onMouseUp:handleDropdownMouseUp,style:[styles$7.dropdown,isReferenceHidden&&styles$7.hidden,dropdownStyle],testId:"dropdown-core-container",children:[isFilterable&&renderSearchField(),jsxRuntime.jsx(wonderBlocksCore.View,{id:id,role:role,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,style:[styles$7.listboxOrMenu,{minInlineSize:minDropdownWidth}],"aria-invalid":role==="listbox"?ariaInvalid:undefined,"aria-required":role==="listbox"?ariaRequired:undefined,children:listRenderer}),maybeRenderNoResults()]})};const renderDropdown=()=>{const listRenderer=shouldVirtualizeList()?renderVirtualizedList():renderList();return jsxRuntime.jsx(DropdownPopper,{alignment:alignment,onPopperElement:popperElement=>{popperElementRef.current=popperElement;},referenceElement:openerElement,children:isReferenceHidden=>renderDropdownMenu(listRenderer,isReferenceHidden)})};return jsxRuntime.jsxs(wonderBlocksCore.View,{ref:rootRef,onKeyDown:!disabled?handleKeyDown:undefined,onKeyUp:!disabled?handleKeyUp:undefined,style:[styles$7.menuWrapper,style],className:className,children:[opener,open&&renderDropdown()]})};const styles$7=aphrodite.StyleSheet.create({menuWrapper:{width:"fit-content",maxInlineSize:"100%"},dropdown:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,borderRadius:theme.listbox.border.radius,paddingBlock:theme.listbox.layout.padding.block,paddingInline:theme.listbox.layout.padding.inline,border:`solid ${wonderBlocksTokens.border.width.thin} ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,boxShadow:theme.listbox.shadow.default,maxBlockSize:"var(--popper-max-height)"},listboxOrMenu:{overflowY:"auto"},hidden:{pointerEvents:"none",visibility:"hidden"},noResult:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.default,alignSelf:"center",marginBlockStart:wonderBlocksTokens.sizing.size_060},searchInputStyle:{margin:wonderBlocksTokens.sizing.size_080,marginBlockStart:wonderBlocksTokens.sizing.size_040,minBlockSize:"auto",position:"sticky"},srOnly:{border:0,clip:"rect(0,0,0,0)",height:1,margin:-1,overflow:"hidden",padding:0,position:"absolute",width:1}});
|
|
92
|
+
const VIRTUALIZE_THRESHOLD=125;const isFocusableElement=value=>typeof value==="object"&&value!==null&&"nodeType"in value&&value.nodeType===1&&"focus"in value&&typeof value.focus==="function";const sameItemsFocusable=(prevItems,currentItems)=>{if(prevItems.length!==currentItems.length){return false}for(let i=0;i<prevItems.length;i++){if(prevItems[i].focusable!==currentItems[i].focusable){return false}}return true};const createItemRefs=items=>{const itemRefs=[];for(let i=0;i<items.length;i++){if(items[i].focusable){const ref=React__namespace.createRef();itemRefs.push({ref,originalIndex:i});}}return itemRefs};const DropdownCore=props=>{const{strings}=wonderBlocksConfig.useWonderBlocksI18n();const{"aria-invalid":ariaInvalid,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,"aria-required":ariaRequired,alignment="left",autoFocus=true,className,disabled,dropdownStyle,enableTypeAhead=true,id,initialFocusedIndex,isFilterable,items,labels,onOpenChanged,onSearchTextChanged,open,opener,openerElement,role,searchText,selectionType="single",style}=props;const schedule=wonderBlocksTiming.useActionScheduler();const openRef=wonderBlocksCore.useLatestRef(open);const onOpenChangedRef=wonderBlocksCore.useLatestRef(onOpenChanged);const rootRef=React__namespace.useRef(null);const popperElementRef=React__namespace.useRef(undefined);const virtualizedListRef=React__namespace.useRef(null);const searchFieldRef=React__namespace.useRef(null);const textSuggestionRef=React__namespace.useRef("");const committedItemsRef=React__namespace.useRef({itemRefs:[],prevItems:items});const{itemRefs:prevItemRefs,prevItems}=committedItemsRef.current;const shouldCreateItemRefs=prevItemRefs.length===0&&open||!sameItemsFocusable(prevItems,items);const derivedItems=shouldCreateItemRefs?{itemRefs:createItemRefs(items),sameItemsFocusable:false}:{itemRefs:prevItemRefs,sameItemsFocusable:true};const itemRefsRef=React__namespace.useRef(derivedItems.itemRefs);React__namespace.useEffect(()=>{committedItemsRef.current={itemRefs:derivedItems.itemRefs,prevItems:items};itemRefsRef.current=derivedItems.itemRefs;});const hasSearchField=React__namespace.useCallback(()=>{return !!isFilterable},[isFilterable]);const isSearchFieldFocused=React__namespace.useCallback(()=>{return hasSearchField()&&document.activeElement===searchFieldRef.current},[hasSearchField]);const focusSearchField=React__namespace.useCallback(()=>{if(searchFieldRef.current){searchFieldRef.current.focus();}},[]);const focusedIndexRef=React__namespace.useRef(-1);const focusedOriginalIndexRef=React__namespace.useRef(-1);const itemsClickedRef=React__namespace.useRef(false);const resetFocusedIndex=React__namespace.useCallback(()=>{if(typeof initialFocusedIndex!=="undefined"){focusedIndexRef.current=initialFocusedIndex;}else {if(hasSearchField()&&!isSearchFieldFocused()){return focusSearchField()}focusedIndexRef.current=0;}},[focusSearchField,hasSearchField,initialFocusedIndex,isSearchFieldFocused]);const initializedRef=React__namespace.useRef(false);if(!initializedRef.current){initializedRef.current=true;resetFocusedIndex();}const shouldVirtualizeList=React__namespace.useCallback(()=>{return items.length>VIRTUALIZE_THRESHOLD},[items]);const focusCurrentItem=React__namespace.useCallback(onFocus=>{const focusedItemRef=itemRefsRef.current[focusedIndexRef.current];if(!focusedItemRef){return}const{current:virtualizedList}=virtualizedListRef;if(virtualizedList){virtualizedList.scrollToItem(focusedItemRef.originalIndex);}const focusNode=()=>{if(!openRef.current){return}const currentFocusedItemRef=itemRefsRef.current[focusedIndexRef.current];const refValue=currentFocusedItemRef.ref.current;const node=isFocusableElement(refValue)?refValue:null;if(refValue==null&&shouldVirtualizeList()){schedule.animationFrame(focusNode);return}if(node){schedule.timeout(()=>{node.focus();},0);focusedOriginalIndexRef.current=currentFocusedItemRef.originalIndex;if(onFocus){onFocus(node);}}};if(shouldVirtualizeList()){schedule.animationFrame(focusNode);}else {focusNode();}},[openRef,schedule,shouldVirtualizeList]);const scheduleToFocusCurrentItem=React__namespace.useCallback(onFocus=>{if(shouldVirtualizeList()){schedule.animationFrame(()=>{focusCurrentItem(onFocus);});}else {focusCurrentItem(onFocus);}},[focusCurrentItem,schedule,shouldVirtualizeList]);const maybeFocusInitialItem=React__namespace.useCallback(()=>{if(!autoFocus){return}if(open){resetFocusedIndex();scheduleToFocusCurrentItem();}else if(!open){itemsClickedRef.current=false;}},[autoFocus,open,resetFocusedIndex,scheduleToFocusCurrentItem]);React__namespace.useEffect(()=>{if(!open){return}const handleInteract=event=>{const target=event.target;const thisElement=rootRef.current;if(thisElement&&!thisElement.contains(target)&&popperElementRef.current&&!popperElementRef.current.contains(target)){onOpenChangedRef.current(false);}};document.addEventListener("mouseup",handleInteract);document.addEventListener("touchend",handleInteract);return ()=>{document.removeEventListener("mouseup",handleInteract);document.removeEventListener("touchend",handleInteract);}},[open,onOpenChangedRef]);wonderBlocksCore.useOnMountEffect(()=>{maybeFocusInitialItem();});const prevRenderRef=React__namespace.useRef(null);React__namespace.useEffect(()=>{const prevProps=prevRenderRef.current;prevRenderRef.current={open,searchText,derivedItems};if(!prevProps||prevProps.derivedItems===derivedItems){return}if(prevProps.open!==open){maybeFocusInitialItem();}else if(open){const{itemRefs,sameItemsFocusable}=derivedItems;if(sameItemsFocusable||prevProps.searchText!==searchText){return}else {const newFocusableIndex=itemRefs.findIndex(ref=>ref.originalIndex===focusedOriginalIndexRef.current);if(newFocusableIndex===-1){focusedIndexRef.current=0;itemsClickedRef.current=false;scheduleToFocusCurrentItem();}else {focusedIndexRef.current=newFocusableIndex;}}}});const focusPreviousItem=React__namespace.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=itemRefsRef.current.length-1;}else if(focusedIndexRef.current===0){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=itemRefsRef.current.length-1;}else {focusedIndexRef.current-=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const focusNextItem=React__namespace.useCallback(()=>{if(isSearchFieldFocused()){focusedIndexRef.current=0;}else if(focusedIndexRef.current===itemRefsRef.current.length-1){if(hasSearchField()){return focusSearchField()}focusedIndexRef.current=0;}else {focusedIndexRef.current+=1;}scheduleToFocusCurrentItem();},[focusSearchField,hasSearchField,isSearchFieldFocused,scheduleToFocusCurrentItem]);const restoreTabOrder=React__namespace.useCallback(()=>{if(openerElement){openerElement.focus();}},[openerElement]);const handleKeyDownDebounceResult=React__namespace.useCallback(key=>{const foundIndex=items.filter(item=>item.focusable).findIndex(({component})=>{if(SeparatorItem.isComponentOf(component)){return false}if(OptionItem.isComponentOf(component)){const optionItemProps=component.props;return getLabel(optionItemProps).toLowerCase().startsWith(key.toLowerCase())}return false});if(foundIndex>=0){const isClosed=!open;if(isClosed){onOpenChanged(true);}focusedIndexRef.current=foundIndex;scheduleToFocusCurrentItem(node=>{if(selectionType==="single"&&isClosed&&node){node.click();onOpenChanged(false);}});}textSuggestionRef.current="";},[items,onOpenChanged,open,scheduleToFocusCurrentItem,selectionType]);const handleKeyDownDebounceResultRef=React__namespace.useRef(handleKeyDownDebounceResult);handleKeyDownDebounceResultRef.current=handleKeyDownDebounceResult;const handleKeyDownDebounced=React__namespace.useMemo(()=>debounce(key=>handleKeyDownDebounceResultRef.current(key),500),[]);const handleKeyDown=event=>{const key=event.key;if(enableTypeAhead&&getStringForKey(key)){event.stopPropagation();textSuggestionRef.current+=key;handleKeyDownDebounced(textSuggestionRef.current);}if(!open){if(key===wonderBlocksCore.keys.down){event.preventDefault();onOpenChanged(true);return}return}switch(key){case wonderBlocksCore.keys.tab:if(isSearchFieldFocused()&&searchText){return}restoreTabOrder();onOpenChanged(false);return;case wonderBlocksCore.keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case wonderBlocksCore.keys.up:event.preventDefault();focusPreviousItem();return;case wonderBlocksCore.keys.down:event.preventDefault();focusNextItem();return}};const handleKeyUp=event=>{const key=event.key;switch(key){case wonderBlocksCore.keys.space:if(isSearchFieldFocused()){return}event.preventDefault();return;case wonderBlocksCore.keys.escape:if(open){event.stopPropagation();restoreTabOrder();onOpenChanged(false);}return}};const handleClickFocus=index=>{itemsClickedRef.current=true;focusedIndexRef.current=index;focusedOriginalIndexRef.current=derivedItems.itemRefs[focusedIndexRef.current].originalIndex;};const handleDropdownMouseUp=event=>{if(event.nativeEvent.stopImmediatePropagation){event.nativeEvent.stopImmediatePropagation();}else {event.stopPropagation();}};const getItemRole=()=>{switch(role){case"listbox":return "option";case"menu":return "menuitem";default:throw new Error(`Expected "listbox" or "menu" for role, but receieved "${role}" instead.`)}};const maybeRenderNoResults=()=>{const noResults=labels?.noResults||strings.noResults;const numResults=items.length;if(numResults===0){return jsxRuntime.jsx(wonderBlocksTypography.BodyText,{style:styles$7.noResult,testId:"dropdown-core-no-results",children:noResults})}return null};const handleItemClick=(focusIndex,item)=>{handleClickFocus(focusIndex);if(item.component.props.onClick){item.component.props.onClick();}if(item.populatedProps.onClick){item.populatedProps.onClick();}};const renderList=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{if(SeparatorItem.isComponentOf(item.component)){return item.component}const{component,focusable,populatedProps}=item;if(focusable){focusCounter+=1;}const focusIndex=focusCounter-1;const currentRef=derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null;return React__namespace.cloneElement(component,{...populatedProps,key:index,onClick:()=>{handleItemClick(focusIndex,item);},ref:focusable?currentRef:null,role:populatedProps.role||itemRole})})};const parseVirtualizedItems=()=>{let focusCounter=0;const itemRole=getItemRole();return items.map((item,index)=>{const{populatedProps}=item;if(!SeparatorItem.isComponentOf(item.component)&&item.focusable){focusCounter+=1;}const focusIndex=focusCounter-1;return {...item,role:populatedProps.role||itemRole,ref:item.focusable&&derivedItems.itemRefs[focusIndex]?derivedItems.itemRefs[focusIndex].ref:null,onClick:()=>{handleItemClick(focusIndex,item);}}})};const renderVirtualizedList=()=>{const virtualizedItems=parseVirtualizedItems();return jsxRuntime.jsx(DropdownCoreVirtualized$1,{data:virtualizedItems,listRef:virtualizedListRef})};const handleSearchTextChanged=searchText=>{if(onSearchTextChanged){onSearchTextChanged(searchText);}};const renderSearchField=()=>{return jsxRuntime.jsx(SearchField__default["default"],{clearAriaLabel:labels?.clearSearch||strings.iconAltClearSearch,onChange:handleSearchTextChanged,placeholder:labels?.filter||strings.filter,ref:searchFieldRef,style:styles$7.searchInputStyle,value:searchText||""})};const renderDropdownMenu=(listRenderer,isReferenceHidden)=>{const openerStyle=openerElement&&window.getComputedStyle(openerElement);const minDropdownWidth=openerStyle?openerStyle.getPropertyValue("width"):0;return jsxRuntime.jsxs(wonderBlocksCore.View,{onMouseUp:handleDropdownMouseUp,style:[styles$7.dropdown,isReferenceHidden&&styles$7.hidden,dropdownStyle],testId:"dropdown-core-container",children:[isFilterable&&renderSearchField(),jsxRuntime.jsx(wonderBlocksCore.View,{id:id,role:role,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledby,style:[styles$7.listboxOrMenu,{minInlineSize:minDropdownWidth}],"aria-invalid":role==="listbox"?ariaInvalid:undefined,"aria-required":role==="listbox"?ariaRequired:undefined,children:listRenderer}),maybeRenderNoResults()]})};const renderDropdown=()=>{const listRenderer=shouldVirtualizeList()?renderVirtualizedList():renderList();return jsxRuntime.jsx(DropdownPopper,{alignment:alignment,onPopperElement:popperElement=>{popperElementRef.current=popperElement;},referenceElement:openerElement,children:isReferenceHidden=>renderDropdownMenu(listRenderer,isReferenceHidden)})};return jsxRuntime.jsxs(wonderBlocksCore.View,{ref:rootRef,onKeyDown:!disabled?handleKeyDown:undefined,onKeyUp:!disabled?handleKeyUp:undefined,style:[styles$7.menuWrapper,style],className:className,children:[opener,open&&renderDropdown()]})};const styles$7=aphrodite.StyleSheet.create({menuWrapper:{width:"fit-content",maxInlineSize:"100%"},dropdown:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,borderRadius:theme.listbox.border.radius,paddingBlock:theme.listbox.layout.padding.block,paddingInline:theme.listbox.layout.padding.inline,border:`solid ${wonderBlocksTokens.border.width.thin} ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,boxShadow:theme.listbox.shadow.default,maxBlockSize:"var(--popper-max-height)"},listboxOrMenu:{overflowY:"auto"},hidden:{pointerEvents:"none",visibility:"hidden"},noResult:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.default,alignSelf:"center",marginBlockStart:wonderBlocksTokens.sizing.size_060},searchInputStyle:{margin:wonderBlocksTokens.sizing.size_080,marginBlockStart:wonderBlocksTokens.sizing.size_040,minBlockSize:"auto",position:"sticky"},srOnly:{border:0,clip:"rect(0,0,0,0)",height:1,margin:-1,overflow:"hidden",padding:0,position:"absolute",width:1}});
|
|
93
93
|
|
|
94
94
|
const ActionMenuOpenerCore=React__namespace.forwardRef(function ActionMenuOpenerCore(props,ref){const{children,disabled,waiting:_,testId,opened,"aria-label":ariaLabel,...restProps}=props;return jsxRuntime.jsx(Button__default["default"],{"aria-expanded":opened?"true":"false","aria-haspopup":"menu",kind:"tertiary","aria-label":ariaLabel,disabled:disabled,...restProps,testId:testId,endIcon:caretDownIcon__default["default"],ref:ref,children:children})});
|
|
95
95
|
|
|
96
|
-
const ActionMenu=React__namespace.forwardRef(function ActionMenu({alignment="left","aria-label":ariaLabel,disabled=false,children,menuText,opened:openedProp,onToggle,onChange,selectedValues,testId,dropdownStyle,style,className,opener,dropdownId,id},ref){const[internalOpened,setInternalOpened]=React__namespace.useState(false);const[openerElement,setOpenerElement]=React__namespace.useState(null);const generatedUniqueOpenerId=React__namespace.useId();const generatedUniqueDropdownId=React__namespace.useId();const uniqueOpenerId=id??generatedUniqueOpenerId;const uniqueDropdownId=dropdownId??generatedUniqueDropdownId;const opened=typeof openedProp==="boolean"?openedProp:internalOpened;const handleOpenChanged=React__namespace.useCallback(newOpened=>{setInternalOpened(newOpened);if(onToggle){onToggle(newOpened);}},[onToggle]);const handleItemSelected=React__namespace.useCallback(()=>{handleOpenChanged(false);openerElement?.focus();},[handleOpenChanged,openerElement]);const handleOptionSelected=React__namespace.useCallback(selectedValue=>{if(!onChange||!selectedValues){return}if(selectedValues.includes(selectedValue)){const index=selectedValues.indexOf(selectedValue);const updatedSelection=[...selectedValues.slice(0,index),...selectedValues.slice(index+1)];onChange(updatedSelection);}else {onChange([...selectedValues,selectedValue]);}handleItemSelected();},[onChange,selectedValues,handleItemSelected]);const getMenuItems=React__namespace.useCallback(()=>{const allChildren=React__namespace.Children.toArray(children).filter(Boolean);const isOptionItemIncluded=allChildren.some(item=>OptionItem.
|
|
96
|
+
const ActionMenu=React__namespace.forwardRef(function ActionMenu({alignment="left","aria-label":ariaLabel,disabled=false,children,menuText,opened:openedProp,onToggle,onChange,selectedValues,testId,dropdownStyle,style,className,opener,dropdownId,id},ref){const[internalOpened,setInternalOpened]=React__namespace.useState(false);const[openerElement,setOpenerElement]=React__namespace.useState(null);const generatedUniqueOpenerId=React__namespace.useId();const generatedUniqueDropdownId=React__namespace.useId();const uniqueOpenerId=id??generatedUniqueOpenerId;const uniqueDropdownId=dropdownId??generatedUniqueDropdownId;const opened=typeof openedProp==="boolean"?openedProp:internalOpened;const handleOpenChanged=React__namespace.useCallback(newOpened=>{setInternalOpened(newOpened);if(onToggle){onToggle(newOpened);}},[onToggle]);const handleItemSelected=React__namespace.useCallback(()=>{handleOpenChanged(false);openerElement?.focus();},[handleOpenChanged,openerElement]);const handleOptionSelected=React__namespace.useCallback(selectedValue=>{if(!onChange||!selectedValues){return}if(selectedValues.includes(selectedValue)){const index=selectedValues.indexOf(selectedValue);const updatedSelection=[...selectedValues.slice(0,index),...selectedValues.slice(index+1)];onChange(updatedSelection);}else {onChange([...selectedValues,selectedValue]);}handleItemSelected();},[onChange,selectedValues,handleItemSelected]);const getMenuItems=React__namespace.useCallback(()=>{const allChildren=React__namespace.Children.toArray(children).filter(Boolean);const isOptionItemIncluded=allChildren.some(item=>OptionItem.isComponentOf(item));return allChildren.map(item=>{const{value,disabled}=item.props;const itemObject={component:item,focusable:ActionItem.isComponentOf(item)||OptionItem.isComponentOf(item)?!disabled:false,populatedProps:{}};if(ActionItem.isComponentOf(item)){return {...itemObject,populatedProps:{indent:isOptionItemIncluded,onClick:handleItemSelected}}}else if(OptionItem.isComponentOf(item)){const selected=selectedValues?selectedValues.includes(value):false;return {...itemObject,populatedProps:{onToggle:handleOptionSelected,selected,variant:"check",role:"menuitemcheckbox","aria-checked":selected,"aria-selected":undefined}}}else {return itemObject}})},[children,selectedValues,handleItemSelected,handleOptionSelected]);const handleOpenerRef=React__namespace.useCallback(node=>{if(node instanceof HTMLElement||node==null){setOpenerElement(node??null);}else {setOpenerElement(document.getElementById(uniqueOpenerId));}},[uniqueOpenerId]);React__namespace.useEffect(()=>{if(openerElement?.isConnected){return}setOpenerElement(document.getElementById(uniqueOpenerId));},[openerElement,opener,uniqueOpenerId]);React__namespace.useImperativeHandle(ref,()=>openerElement,[openerElement]);const handleClick=React__namespace.useCallback(e=>{handleOpenChanged(!opened);},[handleOpenChanged,opened]);const renderOpener=(numItems,dropdownId)=>{return jsxRuntime.jsx(DropdownOpener,{id:uniqueOpenerId,"aria-controls":dropdownId,"aria-haspopup":"menu",onClick:handleClick,disabled:numItems===0||disabled,text:menuText,ref:handleOpenerRef,testId:opener?undefined:testId,opened:opened,role:"button","aria-label":ariaLabel,children:opener?opener:openerProps=>{const{text,opened,...eventState}=openerProps;return jsxRuntime.jsx(ActionMenuOpenerCore,{...eventState,disabled:disabled,opened:!!opened,testId:testId,children:menuText})}})};const items=getMenuItems();return jsxRuntime.jsx(DropdownCore,{id:uniqueDropdownId,role:"menu",style:style,className:className,opener:renderOpener(items.length,uniqueDropdownId),alignment:alignment,open:opened,items:items,openerElement:openerElement??undefined,onOpenChanged:handleOpenChanged,dropdownStyle:[styles$6.menuTopSpace,dropdownStyle],"aria-labelledby":uniqueOpenerId})});const styles$6=aphrodite.StyleSheet.create({caret:{marginInlineStart:wonderBlocksTokens.sizing.size_040},opener:{whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},menuTopSpace:{insetBlockStart:`calc(-1 * ${wonderBlocksTokens.sizing.size_040})`}});
|
|
97
97
|
|
|
98
98
|
const StyledButton$1=wonderBlocksCore.addStyle("button");class SelectOpener extends React__namespace.Component{render(){const{children,disabled,readOnly,error,id,isPlaceholder,open,testId,"aria-label":ariaLabel,"aria-required":ariaRequired,"aria-controls":ariaControls,onBlur,onOpenChanged,...sharedProps}=this.props;const iconColor=disabled?wonderBlocksTokens.semanticColor.core.foreground.disabled.default:wonderBlocksTokens.semanticColor.core.foreground.neutral.default;const style=[styles$5.shared,styles$5.default,disabled&&styles$5.disabled,error&&styles$5.error,isPlaceholder&&styles$5.placeholder,isPlaceholder&&disabled&&styles$5.disabledPlaceholder,!disabled&&!readOnly&&this.state.pressed&&styles$5.press,readOnly&&styles$5.readOnly,readOnly&&isPlaceholder&&styles$5.placeholder];const allowInteraction=!disabled&&!readOnly;return jsxRuntime.jsxs(StyledButton$1,{...sharedProps,"aria-disabled":readOnly||disabled||undefined,"aria-expanded":open?"true":"false","aria-invalid":error,"aria-label":ariaLabel??undefined,"aria-required":ariaRequired,"aria-haspopup":"listbox","aria-controls":ariaControls,"data-testid":testId,id:id,role:"combobox",type:"button",style:style,onClick:allowInteraction?this.handleClick:undefined,onKeyDown:allowInteraction?this.handleKeyDown:undefined,onKeyUp:allowInteraction?this.handleKeyUp:undefined,onBlur:onBlur,children:[jsxRuntime.jsx(wonderBlocksTypography.BodyText,{tag:"span",style:styles$5.text,children:children||jsxRuntime.jsx("span",{"aria-hidden":"true",children:" "})}),jsxRuntime.jsx(wonderBlocksIcon.PhosphorIcon,{icon:caretDownIcon__default["default"],color:iconColor,size:"small",style:styles$5.caret,"aria-hidden":"true"})]})}constructor(props){super(props),this.handleClick=e=>{const{open}=this.props;this.props.onOpenChanged(!open);},this.handleKeyDown=e=>{const keyName=e.key;if(keyName===wonderBlocksCore.keys.enter||keyName===wonderBlocksCore.keys.space){this.setState({pressed:true});e.preventDefault();}},this.handleKeyUp=e=>{const keyName=e.key;if(keyName===wonderBlocksCore.keys.enter||keyName===wonderBlocksCore.keys.space){this.setState({pressed:false});this.handleClick(e);}};this.state={pressed:false};}}SelectOpener.defaultProps={disabled:false,readOnly:false,error:false,isPlaceholder:false};const PRESS_SHADOW=`0 0 0 ${wonderBlocksTokens.border.width.thin} ${wonderBlocksTokens.semanticColor.input.default.border}`;const styles$5=aphrodite.StyleSheet.create({shared:{position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"space-between",color:wonderBlocksTokens.semanticColor.core.foreground.neutral.strong,height:DROPDOWN_ITEM_HEIGHT,paddingInlineStart:theme.opener.layout.padding.inlineStart,paddingInlineEnd:theme.opener.layout.padding.inlineEnd,borderWidth:0,borderRadius:theme.opener.border.radius.rest,borderStyle:"solid",outline:"none",textDecoration:"none",boxSizing:"border-box",whiteSpace:"nowrap",touchAction:"manipulation"},text:{marginInlineEnd:wonderBlocksTokens.sizing.size_080,whiteSpace:"nowrap",userSelect:"none",overflow:"hidden",textOverflow:"ellipsis"},caret:{minInlineSize:wonderBlocksTokens.sizing.size_160},default:{background:wonderBlocksTokens.semanticColor.input.default.background,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.input.default.border}`,color:wonderBlocksTokens.semanticColor.input.default.foreground,cursor:"pointer",":active":{boxShadow:PRESS_SHADOW},":focus":{...wonderBlocksStyles.focusStyles.focus[":focus-visible"]},[":focus:active"]:{boxShadow:`${PRESS_SHADOW}, ${wonderBlocksStyles.focusStyles.focus[":focus-visible"].boxShadow}`}},error:{background:wonderBlocksTokens.semanticColor.input.error.background,border:`${theme.opener.border.width.error} solid ${wonderBlocksTokens.semanticColor.input.error.border}`,color:wonderBlocksTokens.semanticColor.input.error.foreground,[":focus:active"]:{boxShadow:`${PRESS_SHADOW}, ${wonderBlocksStyles.focusStyles.focus[":focus-visible"].boxShadow}`}},disabled:{background:wonderBlocksTokens.semanticColor.input.disabled.background,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.input.disabled.border}`,color:wonderBlocksTokens.semanticColor.input.disabled.foreground,cursor:"not-allowed",":active":{boxShadow:"none"},[":focus:active"]:{boxShadow:wonderBlocksStyles.focusStyles.focus[":focus-visible"].boxShadow}},press:{boxShadow:PRESS_SHADOW,":focus-visible":{boxShadow:`${PRESS_SHADOW}, ${wonderBlocksStyles.focusStyles.focus[":focus-visible"].boxShadow}`}},placeholder:{color:wonderBlocksTokens.semanticColor.input.default.placeholder},disabledPlaceholder:{color:wonderBlocksTokens.semanticColor.input.disabled.placeholder},readOnly:{background:wonderBlocksTokens.semanticColor.input.readOnly.background,color:wonderBlocksTokens.semanticColor.input.readOnly.text,":active":{boxShadow:"none"},[":focus:active"]:{boxShadow:wonderBlocksStyles.focusStyles.focus[":focus-visible"].boxShadow}}});
|
|
99
99
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Dropdown variants for Wonder Blocks.",
|
|
4
4
|
"author": "Khan Academy",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "11.0.0",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@khanacademy/wonder-blocks-announcer": "1.1.2",
|
|
32
32
|
"@khanacademy/wonder-blocks-button": "11.7.13",
|
|
33
|
-
"@khanacademy/wonder-blocks-cell": "6.
|
|
33
|
+
"@khanacademy/wonder-blocks-cell": "6.4.0",
|
|
34
34
|
"@khanacademy/wonder-blocks-clickable": "8.3.2",
|
|
35
35
|
"@khanacademy/wonder-blocks-config": "0.7.1",
|
|
36
36
|
"@khanacademy/wonder-blocks-core": "12.5.0",
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"@khanacademy/wonder-blocks-icon": "6.0.3",
|
|
39
39
|
"@khanacademy/wonder-blocks-icon-button": "12.0.2",
|
|
40
40
|
"@khanacademy/wonder-blocks-modal": "8.10.3",
|
|
41
|
-
"@khanacademy/wonder-blocks-pill": "3.1.83",
|
|
42
41
|
"@khanacademy/wonder-blocks-search-field": "5.2.6",
|
|
43
42
|
"@khanacademy/wonder-blocks-styles": "0.4.1",
|
|
44
43
|
"@khanacademy/wonder-blocks-timing": "7.1.0",
|