@khanacademy/wonder-blocks-tabs 0.3.36 → 0.4.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/CHANGELOG.md +18 -0
- package/dist/components/navigation-tabs.d.ts +4 -0
- package/dist/es/index.js +4 -4
- package/dist/index.js +4 -4
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-tabs
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 42c0f72: NavigationTabs: Add tag prop to allow overriding the underlying nav element
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 5db127a: Fix issue where TabPanel is set with tabIndex=0 before it has determined if it has focusable elements within it (related to a focus management bug when Tabs are used inside a Popover). Also apply WB focus styling to the tabpanel element since it is focusbale when there are no interactive elements in it.
|
|
12
|
+
|
|
13
|
+
## 0.3.37
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [70d6c08]
|
|
18
|
+
- @khanacademy/wonder-blocks-tokens@14.1.3
|
|
19
|
+
- @khanacademy/wonder-blocks-typography@4.2.27
|
|
20
|
+
|
|
3
21
|
## 0.3.36
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -69,4 +69,8 @@ export declare const NavigationTabs: React.ForwardRefExoticComponent<Readonly<im
|
|
|
69
69
|
* if the user has `prefers-reduced-motion` opted in. Defaults to `false`.
|
|
70
70
|
*/
|
|
71
71
|
animated?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* The HTML tag to render. Defaults to `nav`.
|
|
74
|
+
*/
|
|
75
|
+
tag?: keyof JSX.IntrinsicElements;
|
|
72
76
|
} & React.RefAttributes<HTMLElement>>;
|
package/dist/es/index.js
CHANGED
|
@@ -7,15 +7,15 @@ import { styles as styles$7 } from '@khanacademy/wonder-blocks-typography';
|
|
|
7
7
|
|
|
8
8
|
const useTabIndicator=props=>{const{animated,tabsContainerRef,isTabActive}=props;const indicatorIsReady=React.useRef(false);const[underlineStyle,setUnderlineStyle]=React.useState({left:0,width:0});const updateUnderlineStyle=React.useCallback(()=>{if(!tabsContainerRef.current){return}const activeTab=Array.from(tabsContainerRef.current.children).find(isTabActive);if(activeTab){const tabRect=activeTab.getBoundingClientRect();const parentRect=tabsContainerRef.current.getBoundingClientRect();const zoomFactor=parentRect.width/tabsContainerRef.current.offsetWidth;const left=(tabRect.left-parentRect.left)/zoomFactor;const width=tabRect.width/zoomFactor;setUnderlineStyle({left,width});}},[setUnderlineStyle,tabsContainerRef,isTabActive]);useOnMountEffect(()=>{if(!tabsContainerRef.current||!window?.ResizeObserver||!window?.MutationObserver){return}const resizeObserver=new window.ResizeObserver(([entry])=>{if(entry){updateUnderlineStyle();if(!indicatorIsReady.current){indicatorIsReady.current=true;}}});resizeObserver.observe(tabsContainerRef.current);const mutationObserver=new window.MutationObserver(([entry])=>{if(entry){updateUnderlineStyle();}});mutationObserver.observe(tabsContainerRef.current,{attributes:true,childList:true,subtree:true});return ()=>{resizeObserver.disconnect();mutationObserver.disconnect();}});const positioningStyle={transform:`translateX(${underlineStyle.left}px)`,width:`${underlineStyle.width}px`};const indicatorProps={style:{...styles$6.currentUnderline,...positioningStyle,...animated?styles$6.underlineTransition:{},...!indicatorIsReady.current?{display:"none"}:{}},role:"presentation"};return {indicatorProps}};const styles$6={currentUnderline:{position:"absolute",bottom:0,left:0,height:border.width.thick,backgroundColor:semanticColor.action.secondary.progressive.default.foreground},underlineTransition:{transition:"transform 0.3s ease, width 0.3s ease"}};
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const StyledUl=addStyle("ul");const StyledDiv$3=addStyle("div");const NavigationTabs=React.forwardRef(function NavigationTabs(props,ref){const{id,testId,children,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,styles:stylesProp,animated=false,tag="nav",...otherProps}=props;const StyledTag=React.useMemo(()=>addStyle(tag),[tag]);const listRef=React.useRef(null);const isTabActive=React.useCallback(navTabItemElement=>{return navTabItemElement.children[0]?.ariaCurrent==="page"},[]);const{indicatorProps}=useTabIndicator({animated,tabsContainerRef:listRef,isTabActive});return jsx(StyledTag,{id:id,"data-testid":testId,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,ref:ref,style:[styles$5.nav,stylesProp?.root],...otherProps,children:jsxs(StyledDiv$3,{style:styles$5.contents,children:[jsx(StyledUl,{style:[styles$5.list,stylesProp?.list],ref:listRef,children:children}),jsx("div",{...indicatorProps})]})})});const styles$5=StyleSheet.create({nav:{overflowX:"auto"},contents:{position:"relative"},list:{paddingInline:sizing.size_040,paddingBlock:sizing.size_0,margin:sizing.size_0,display:"flex",gap:sizing.size_160,flexWrap:"nowrap"}});
|
|
11
11
|
|
|
12
12
|
const StyledLi=addStyle("li");const NavigationTabItem=React.forwardRef(function NavigationTabItem(props,ref){const{children,id,testId,current,style,...otherProps}=props;function renderChildren(){const linkProps={style:[styles$7.Body,styles$4.link,current&&styles$4.currentLink],"aria-current":current?"page":undefined};if(typeof children==="function"){return children(linkProps)}return React.cloneElement(children,linkProps)}return jsx(StyledLi,{id:id,"data-testid":testId,style:[styles$4.root,current&&styles$4.current,style],ref:ref,...otherProps,children:renderChildren()})});const styles$4=StyleSheet.create({root:{listStyle:"none",display:"inline-flex",[":has(a:hover)"]:{boxShadow:`inset 0 calc(${sizing.size_020}*-1) 0 0 ${semanticColor.core.border.instructive.default}`},[":has(a:active)"]:{boxShadow:`inset 0 calc(${sizing.size_060}*-1) 0 0 ${semanticColor.core.border.instructive.strong}`},paddingBlockStart:sizing.size_080,paddingBlockEnd:sizing.size_180,[breakpoint.mediaQuery.mdOrLarger]:{paddingBlockStart:sizing.size_200,paddingBlockEnd:sizing.size_240}},current:{[":has(a:hover)"]:{boxShadow:"none"},[":has(a:active):not([aria-disabled=true])"]:{boxShadow:"none"}},currentLink:{color:semanticColor.link.rest,[":active:not([aria-disabled=true])"]:{color:semanticColor.link.rest}},link:{display:"flex",margin:0,color:semanticColor.core.foreground.neutral.subtle,paddingInline:0,position:"relative",whiteSpace:"nowrap",textDecoration:"none",[":hover:not([aria-disabled=true])"]:{textDecoration:"none",border:"none",outline:"none",color:semanticColor.link.hover,backgroundColor:"transparent"},[":active:not([aria-disabled=true])"]:{textDecoration:"none",border:"none",outline:"none",color:semanticColor.link.press},":focus-visible":{color:semanticColor.link.rest,border:"none",outline:"none",boxShadow:`0 0 0 ${sizing.size_020} ${semanticColor.focus.inner}, 0 0 0 ${sizing.size_040} ${semanticColor.focus.outer}`,borderRadius:border.radius.radius_0}}});
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const focus={":focus-visible":{boxShadow:`0 0 0 ${border.width.medium} ${semanticColor.focus.inner}`,outline:`${border.width.medium} solid ${semanticColor.focus.outer}`,outlineOffset:border.width.medium}};var focusStyles=Object.freeze({__proto__:null,focus:focus});const pressColor=`color-mix(in srgb, ${semanticColor.core.border.neutral.default} 55%, ${semanticColor.core.border.knockout.default})`;const inverse={":not([aria-disabled=true])":{borderColor:semanticColor.core.border.knockout.default,color:semanticColor.core.foreground.knockout.default},":hover:not([aria-disabled=true])":{color:semanticColor.core.foreground.knockout.default,borderColor:semanticColor.core.border.knockout.default},...focus,":active:not([aria-disabled=true])":{borderRadius:border.radius.radius_080,borderColor:pressColor,background:`color-mix(in srgb, ${semanticColor.core.background.base.default} 5%, transparent)`}};Object.freeze({__proto__:null,inverse:inverse});
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const FOCUSABLE_ELEMENTS='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function findFocusableNodes(root){return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS))}
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const StyledDiv$2=addStyle("div");const TabPanel=props=>{const{children,id,"aria-labelledby":ariaLabelledby,active=false,testId,style}=props;const ref=React.useRef(null);const[hasFocusableElement,setHasFocusableElement]=React.useState(null);React.useEffect(()=>{if(ref.current&&children){setHasFocusableElement(findFocusableNodes(ref.current).length>0);}},[active,ref,children]);return jsx(StyledDiv$2,{ref:ref,role:"tabpanel",id:id,"aria-labelledby":ariaLabelledby,tabIndex:hasFocusableElement===false?0:undefined,hidden:!active,"data-testid":testId,style:active&&[styles$3.tabPanel,style],children:children})};const styles$3=StyleSheet.create({tabPanel:{display:"flex",...focusStyles.focus}});
|
|
19
19
|
|
|
20
20
|
const StyledButton=addStyle("button");const Tab=React.forwardRef(function Tab(props,ref){const{children,onClick,id,"aria-controls":ariaControls,selected,onKeyDown,testId,style,...otherProps}=props;return jsx(StyledButton,{...otherProps,type:"button",role:"tab",onClick:onClick,ref:ref,id:id,"aria-controls":ariaControls,"aria-selected":selected,tabIndex:selected?0:-1,onKeyDown:onKeyDown,"data-testid":testId,style:[styles$7.Body,styles$2.tab,selected&&styles$2.selectedTab,style],children:children})});const bottomSpacing=sizing.size_140;const styles$2=StyleSheet.create({tab:{display:"flex",alignItems:"center",textWrap:"nowrap",backgroundColor:"transparent",border:"none",margin:0,padding:0,cursor:"pointer",marginBlockStart:sizing.size_080,marginBlockEnd:bottomSpacing,position:"relative",color:semanticColor.core.foreground.neutral.subtle,...focusStyles.focus,":after":{content:"''",position:"absolute",left:0,right:0,bottom:`calc(${bottomSpacing} * -1)`},[":hover:not([aria-selected='true'])"]:{color:semanticColor.link.hover,[":after"]:{height:border.width.thin,backgroundColor:semanticColor.link.hover}},[":active:not([aria-selected='true'])"]:{color:semanticColor.link.press,[":after"]:{height:border.width.thick,backgroundColor:semanticColor.link.press}}},selectedTab:{color:semanticColor.link.rest}});
|
|
21
21
|
|
package/dist/index.js
CHANGED
|
@@ -31,15 +31,15 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
|
31
31
|
|
|
32
32
|
const useTabIndicator=props=>{const{animated,tabsContainerRef,isTabActive}=props;const indicatorIsReady=React__namespace.useRef(false);const[underlineStyle,setUnderlineStyle]=React__namespace.useState({left:0,width:0});const updateUnderlineStyle=React__namespace.useCallback(()=>{if(!tabsContainerRef.current){return}const activeTab=Array.from(tabsContainerRef.current.children).find(isTabActive);if(activeTab){const tabRect=activeTab.getBoundingClientRect();const parentRect=tabsContainerRef.current.getBoundingClientRect();const zoomFactor=parentRect.width/tabsContainerRef.current.offsetWidth;const left=(tabRect.left-parentRect.left)/zoomFactor;const width=tabRect.width/zoomFactor;setUnderlineStyle({left,width});}},[setUnderlineStyle,tabsContainerRef,isTabActive]);wonderBlocksCore.useOnMountEffect(()=>{if(!tabsContainerRef.current||!window?.ResizeObserver||!window?.MutationObserver){return}const resizeObserver=new window.ResizeObserver(([entry])=>{if(entry){updateUnderlineStyle();if(!indicatorIsReady.current){indicatorIsReady.current=true;}}});resizeObserver.observe(tabsContainerRef.current);const mutationObserver=new window.MutationObserver(([entry])=>{if(entry){updateUnderlineStyle();}});mutationObserver.observe(tabsContainerRef.current,{attributes:true,childList:true,subtree:true});return ()=>{resizeObserver.disconnect();mutationObserver.disconnect();}});const positioningStyle={transform:`translateX(${underlineStyle.left}px)`,width:`${underlineStyle.width}px`};const indicatorProps={style:{...styles$6.currentUnderline,...positioningStyle,...animated?styles$6.underlineTransition:{},...!indicatorIsReady.current?{display:"none"}:{}},role:"presentation"};return {indicatorProps}};const styles$6={currentUnderline:{position:"absolute",bottom:0,left:0,height:wonderBlocksTokens.border.width.thick,backgroundColor:wonderBlocksTokens.semanticColor.action.secondary.progressive.default.foreground},underlineTransition:{transition:"transform 0.3s ease, width 0.3s ease"}};
|
|
33
33
|
|
|
34
|
-
const
|
|
34
|
+
const StyledUl=wonderBlocksCore.addStyle("ul");const StyledDiv$3=wonderBlocksCore.addStyle("div");const NavigationTabs=React__namespace.forwardRef(function NavigationTabs(props,ref){const{id,testId,children,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,styles:stylesProp,animated=false,tag="nav",...otherProps}=props;const StyledTag=React__namespace.useMemo(()=>wonderBlocksCore.addStyle(tag),[tag]);const listRef=React__namespace.useRef(null);const isTabActive=React__namespace.useCallback(navTabItemElement=>{return navTabItemElement.children[0]?.ariaCurrent==="page"},[]);const{indicatorProps}=useTabIndicator({animated,tabsContainerRef:listRef,isTabActive});return jsxRuntime.jsx(StyledTag,{id:id,"data-testid":testId,"aria-label":ariaLabel,"aria-labelledby":ariaLabelledBy,ref:ref,style:[styles$5.nav,stylesProp?.root],...otherProps,children:jsxRuntime.jsxs(StyledDiv$3,{style:styles$5.contents,children:[jsxRuntime.jsx(StyledUl,{style:[styles$5.list,stylesProp?.list],ref:listRef,children:children}),jsxRuntime.jsx("div",{...indicatorProps})]})})});const styles$5=aphrodite.StyleSheet.create({nav:{overflowX:"auto"},contents:{position:"relative"},list:{paddingInline:wonderBlocksTokens.sizing.size_040,paddingBlock:wonderBlocksTokens.sizing.size_0,margin:wonderBlocksTokens.sizing.size_0,display:"flex",gap:wonderBlocksTokens.sizing.size_160,flexWrap:"nowrap"}});
|
|
35
35
|
|
|
36
36
|
const StyledLi=wonderBlocksCore.addStyle("li");const NavigationTabItem=React__namespace.forwardRef(function NavigationTabItem(props,ref){const{children,id,testId,current,style,...otherProps}=props;function renderChildren(){const linkProps={style:[wonderBlocksTypography.styles.Body,styles$4.link,current&&styles$4.currentLink],"aria-current":current?"page":undefined};if(typeof children==="function"){return children(linkProps)}return React__namespace.cloneElement(children,linkProps)}return jsxRuntime.jsx(StyledLi,{id:id,"data-testid":testId,style:[styles$4.root,current&&styles$4.current,style],ref:ref,...otherProps,children:renderChildren()})});const styles$4=aphrodite.StyleSheet.create({root:{listStyle:"none",display:"inline-flex",[":has(a:hover)"]:{boxShadow:`inset 0 calc(${wonderBlocksTokens.sizing.size_020}*-1) 0 0 ${wonderBlocksTokens.semanticColor.core.border.instructive.default}`},[":has(a:active)"]:{boxShadow:`inset 0 calc(${wonderBlocksTokens.sizing.size_060}*-1) 0 0 ${wonderBlocksTokens.semanticColor.core.border.instructive.strong}`},paddingBlockStart:wonderBlocksTokens.sizing.size_080,paddingBlockEnd:wonderBlocksTokens.sizing.size_180,[wonderBlocksTokens.breakpoint.mediaQuery.mdOrLarger]:{paddingBlockStart:wonderBlocksTokens.sizing.size_200,paddingBlockEnd:wonderBlocksTokens.sizing.size_240}},current:{[":has(a:hover)"]:{boxShadow:"none"},[":has(a:active):not([aria-disabled=true])"]:{boxShadow:"none"}},currentLink:{color:wonderBlocksTokens.semanticColor.link.rest,[":active:not([aria-disabled=true])"]:{color:wonderBlocksTokens.semanticColor.link.rest}},link:{display:"flex",margin:0,color:wonderBlocksTokens.semanticColor.core.foreground.neutral.subtle,paddingInline:0,position:"relative",whiteSpace:"nowrap",textDecoration:"none",[":hover:not([aria-disabled=true])"]:{textDecoration:"none",border:"none",outline:"none",color:wonderBlocksTokens.semanticColor.link.hover,backgroundColor:"transparent"},[":active:not([aria-disabled=true])"]:{textDecoration:"none",border:"none",outline:"none",color:wonderBlocksTokens.semanticColor.link.press},":focus-visible":{color:wonderBlocksTokens.semanticColor.link.rest,border:"none",outline:"none",boxShadow:`0 0 0 ${wonderBlocksTokens.sizing.size_020} ${wonderBlocksTokens.semanticColor.focus.inner}, 0 0 0 ${wonderBlocksTokens.sizing.size_040} ${wonderBlocksTokens.semanticColor.focus.outer}`,borderRadius:wonderBlocksTokens.border.radius.radius_0}}});
|
|
37
37
|
|
|
38
|
-
const
|
|
38
|
+
const focus={":focus-visible":{boxShadow:`0 0 0 ${wonderBlocksTokens.border.width.medium} ${wonderBlocksTokens.semanticColor.focus.inner}`,outline:`${wonderBlocksTokens.border.width.medium} solid ${wonderBlocksTokens.semanticColor.focus.outer}`,outlineOffset:wonderBlocksTokens.border.width.medium}};var focusStyles=Object.freeze({__proto__:null,focus:focus});const pressColor=`color-mix(in srgb, ${wonderBlocksTokens.semanticColor.core.border.neutral.default} 55%, ${wonderBlocksTokens.semanticColor.core.border.knockout.default})`;const inverse={":not([aria-disabled=true])":{borderColor:wonderBlocksTokens.semanticColor.core.border.knockout.default,color:wonderBlocksTokens.semanticColor.core.foreground.knockout.default},":hover:not([aria-disabled=true])":{color:wonderBlocksTokens.semanticColor.core.foreground.knockout.default,borderColor:wonderBlocksTokens.semanticColor.core.border.knockout.default},...focus,":active:not([aria-disabled=true])":{borderRadius:wonderBlocksTokens.border.radius.radius_080,borderColor:pressColor,background:`color-mix(in srgb, ${wonderBlocksTokens.semanticColor.core.background.base.default} 5%, transparent)`}};Object.freeze({__proto__:null,inverse:inverse});
|
|
39
39
|
|
|
40
|
-
const
|
|
40
|
+
const FOCUSABLE_ELEMENTS='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function findFocusableNodes(root){return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS))}
|
|
41
41
|
|
|
42
|
-
const
|
|
42
|
+
const StyledDiv$2=wonderBlocksCore.addStyle("div");const TabPanel=props=>{const{children,id,"aria-labelledby":ariaLabelledby,active=false,testId,style}=props;const ref=React__namespace.useRef(null);const[hasFocusableElement,setHasFocusableElement]=React__namespace.useState(null);React__namespace.useEffect(()=>{if(ref.current&&children){setHasFocusableElement(findFocusableNodes(ref.current).length>0);}},[active,ref,children]);return jsxRuntime.jsx(StyledDiv$2,{ref:ref,role:"tabpanel",id:id,"aria-labelledby":ariaLabelledby,tabIndex:hasFocusableElement===false?0:undefined,hidden:!active,"data-testid":testId,style:active&&[styles$3.tabPanel,style],children:children})};const styles$3=aphrodite.StyleSheet.create({tabPanel:{display:"flex",...focusStyles.focus}});
|
|
43
43
|
|
|
44
44
|
const StyledButton=wonderBlocksCore.addStyle("button");const Tab=React__namespace.forwardRef(function Tab(props,ref){const{children,onClick,id,"aria-controls":ariaControls,selected,onKeyDown,testId,style,...otherProps}=props;return jsxRuntime.jsx(StyledButton,{...otherProps,type:"button",role:"tab",onClick:onClick,ref:ref,id:id,"aria-controls":ariaControls,"aria-selected":selected,tabIndex:selected?0:-1,onKeyDown:onKeyDown,"data-testid":testId,style:[wonderBlocksTypography.styles.Body,styles$2.tab,selected&&styles$2.selectedTab,style],children:children})});const bottomSpacing=wonderBlocksTokens.sizing.size_140;const styles$2=aphrodite.StyleSheet.create({tab:{display:"flex",alignItems:"center",textWrap:"nowrap",backgroundColor:"transparent",border:"none",margin:0,padding:0,cursor:"pointer",marginBlockStart:wonderBlocksTokens.sizing.size_080,marginBlockEnd:bottomSpacing,position:"relative",color:wonderBlocksTokens.semanticColor.core.foreground.neutral.subtle,...focusStyles.focus,":after":{content:"''",position:"absolute",left:0,right:0,bottom:`calc(${bottomSpacing} * -1)`},[":hover:not([aria-selected='true'])"]:{color:wonderBlocksTokens.semanticColor.link.hover,[":after"]:{height:wonderBlocksTokens.border.width.thin,backgroundColor:wonderBlocksTokens.semanticColor.link.hover}},[":active:not([aria-selected='true'])"]:{color:wonderBlocksTokens.semanticColor.link.press,[":after"]:{height:wonderBlocksTokens.border.width.thick,backgroundColor:wonderBlocksTokens.semanticColor.link.press}}},selectedTab:{color:wonderBlocksTokens.semanticColor.link.rest}});
|
|
45
45
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Tabs are used to control what content is shown",
|
|
4
4
|
"author": "Khan Academy",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.4.0",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"module": "dist/es/index.js",
|
|
21
21
|
"types": "dist/index.d.ts",
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@khanacademy/wonder-blocks-tokens": "14.1.3",
|
|
23
24
|
"@khanacademy/wonder-blocks-core": "12.4.2",
|
|
24
|
-
"@khanacademy/wonder-blocks-
|
|
25
|
-
"@khanacademy/wonder-blocks-typography": "4.2.26"
|
|
25
|
+
"@khanacademy/wonder-blocks-typography": "4.2.27"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"aphrodite": "^1.2.5",
|