@sproutsocial/seeds-react-tabs 1.2.7 → 1.3.2
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.log +9 -9
- package/CHANGELOG.md +41 -0
- package/dist/esm/index.js +18 -19
- package/dist/esm/index.js.map +1 -1
- package/dist/index.js +18 -19
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Tabs.stories.tsx +50 -0
- package/src/Tabs.tsx +18 -19
- package/src/styles.ts +14 -23
package/.turbo/turbo-build.log
CHANGED
|
@@ -3,19 +3,19 @@ $ tsup --dts
|
|
|
3
3
|
[34mCLI[39m Building entry: src/index.ts
|
|
4
4
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
5
5
|
[34mCLI[39m tsup v8.5.0
|
|
6
|
-
[34mCLI[39m Using tsup config: /home/runner/
|
|
6
|
+
[34mCLI[39m Using tsup config: /home/runner/_work/seeds/seeds/seeds-react/seeds-react-tabs/tsup.config.ts
|
|
7
7
|
[34mCLI[39m Target: es2022
|
|
8
8
|
[34mCLI[39m Cleaning output folder
|
|
9
9
|
[34mCJS[39m Build start
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
|
12
|
-
[32mCJS[39m [1mdist/index.js.map [22m[32m12.
|
|
13
|
-
[32mCJS[39m ⚡️ Build success in
|
|
14
|
-
[32mESM[39m [1mdist/esm/index.js [22m[32m5.
|
|
15
|
-
[32mESM[39m [1mdist/esm/index.js.map [22m[32m12.
|
|
16
|
-
[32mESM[39m ⚡️ Build success in
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m7.72 KB[39m
|
|
12
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m12.13 KB[39m
|
|
13
|
+
[32mCJS[39m ⚡️ Build success in 73ms
|
|
14
|
+
[32mESM[39m [1mdist/esm/index.js [22m[32m5.75 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist/esm/index.js.map [22m[32m12.06 KB[39m
|
|
16
|
+
[32mESM[39m ⚡️ Build success in 73ms
|
|
17
17
|
[34mDTS[39m Build start
|
|
18
|
-
[32mDTS[39m ⚡️ Build success in
|
|
18
|
+
[32mDTS[39m ⚡️ Build success in 2174ms
|
|
19
19
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m2.63 KB[39m
|
|
20
20
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m2.63 KB[39m
|
|
21
|
-
Done in
|
|
21
|
+
Done in 3.65s.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @sproutsocial/seeds-react-tabs
|
|
2
2
|
|
|
3
|
+
## 1.3.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [7d54d67]
|
|
8
|
+
- @sproutsocial/seeds-react-button@1.4.0
|
|
9
|
+
|
|
10
|
+
## 1.3.1
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [17d4f12]
|
|
15
|
+
- @sproutsocial/seeds-react-theme@3.6.0
|
|
16
|
+
- @sproutsocial/seeds-react-button@1.3.20
|
|
17
|
+
|
|
18
|
+
## 1.3.0
|
|
19
|
+
|
|
20
|
+
### Minor Changes
|
|
21
|
+
|
|
22
|
+
- 651fc1b: Update TabButton structure to correct aria descendents
|
|
23
|
+
|
|
24
|
+
## 1.2.10
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- @sproutsocial/seeds-react-button@1.3.19
|
|
29
|
+
|
|
30
|
+
## 1.2.9
|
|
31
|
+
|
|
32
|
+
### Patch Changes
|
|
33
|
+
|
|
34
|
+
- Updated dependencies [118e300]
|
|
35
|
+
- @sproutsocial/seeds-react-theme@3.5.1
|
|
36
|
+
- @sproutsocial/seeds-react-button@1.3.18
|
|
37
|
+
|
|
38
|
+
## 1.2.8
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- @sproutsocial/seeds-react-button@1.3.17
|
|
43
|
+
|
|
3
44
|
## 1.2.7
|
|
4
45
|
|
|
5
46
|
### Patch Changes
|
package/dist/esm/index.js
CHANGED
|
@@ -20,8 +20,14 @@ var Container = styled.div`
|
|
|
20
20
|
|
|
21
21
|
${COMMON}
|
|
22
22
|
`;
|
|
23
|
-
var
|
|
23
|
+
var TabButton = styled(Button)`
|
|
24
24
|
margin-bottom: -1px;
|
|
25
|
+
padding: ${(props) => `${props.theme.space[350]} 0`};
|
|
26
|
+
color: ${(props) => props.theme.colors.text.headline};
|
|
27
|
+
border-radius: 0;
|
|
28
|
+
border-width: 0 0 3px;
|
|
29
|
+
width: 100%;
|
|
30
|
+
|
|
25
31
|
${(props) => props.fullWidth && css`
|
|
26
32
|
flex-grow: 1;
|
|
27
33
|
`};
|
|
@@ -32,23 +38,10 @@ var TabItem = styled.div`
|
|
|
32
38
|
`};
|
|
33
39
|
}
|
|
34
40
|
|
|
35
|
-
${(props) => props.isSelected && css`
|
|
36
|
-
box-shadow: ${(props2) => `inset 0 -3px 0 0 ${props2.theme.colors.button.primary.background.base}`};
|
|
37
|
-
`};
|
|
38
|
-
|
|
39
|
-
&:hover {
|
|
40
|
-
${(props) => props.isSelected && css`
|
|
41
|
-
box-shadow: ${(props2) => `inset 0 -3px 0 0 ${props2.theme.colors.button.primary.background.hover}`};
|
|
42
|
-
`};
|
|
43
|
-
}
|
|
44
|
-
`;
|
|
45
|
-
var TabButton = styled(Button)`
|
|
46
|
-
padding: ${(props) => `${props.theme.space[350]} 0`};
|
|
47
|
-
color: ${(props) => props.theme.colors.text.headline};
|
|
48
|
-
width: 100%;
|
|
49
|
-
|
|
50
41
|
${(props) => props.isSelected && css`
|
|
51
42
|
color: ${(props2) => props2.theme.colors.link.base};
|
|
43
|
+
border-color: transparent transparent
|
|
44
|
+
${(props2) => props2.theme.colors.button.primary.background.base};
|
|
52
45
|
`};
|
|
53
46
|
|
|
54
47
|
&:hover {
|
|
@@ -57,6 +50,11 @@ var TabButton = styled(Button)`
|
|
|
57
50
|
`};
|
|
58
51
|
}
|
|
59
52
|
|
|
53
|
+
&:focus,
|
|
54
|
+
&:active {
|
|
55
|
+
box-shadow: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
60
58
|
&:active {
|
|
61
59
|
transform: none;
|
|
62
60
|
}
|
|
@@ -88,7 +86,7 @@ var TabItemButton = class extends React2.Component {
|
|
|
88
86
|
const { children, id, ...rest } = this.props;
|
|
89
87
|
const { selectedId, onActivate, fullWidth } = this.context;
|
|
90
88
|
const isSelected = selectedId === id;
|
|
91
|
-
return /* @__PURE__ */ jsx(
|
|
89
|
+
return /* @__PURE__ */ jsx(
|
|
92
90
|
TabButton,
|
|
93
91
|
{
|
|
94
92
|
innerRef: this.buttonRef,
|
|
@@ -104,8 +102,9 @@ var TabItemButton = class extends React2.Component {
|
|
|
104
102
|
"aria-controls": `${id}-panel`,
|
|
105
103
|
...rest,
|
|
106
104
|
children
|
|
107
|
-
}
|
|
108
|
-
|
|
105
|
+
},
|
|
106
|
+
id
|
|
107
|
+
);
|
|
109
108
|
}
|
|
110
109
|
};
|
|
111
110
|
var TabPanel = ({ children, id, ...rest }) => {
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/Tabs.tsx","../../src/styles.ts","../../src/TabsTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Container, { TabItem, TabButton } from \"./styles\";\nimport type {\n TypeTabButtonsProps,\n TypeTabsProps,\n TypeTabPanelProps,\n} from \"./TabsTypes\";\n\ninterface TypeTabButtonRef {\n current: null | React.ElementRef<\"button\">;\n}\ninterface TypeTabButtonContext {\n onActivate: (arg0: string) => void;\n onTabMount: (id: string, ref: TypeTabButtonRef) => void;\n onTabUpdate: (previousId: string, nextId: string) => void;\n onTabUnmount: (id: string) => void;\n selectedId: string;\n fullWidth?: boolean;\n}\n\nconst TabButtonContext = React.createContext<Partial<TypeTabButtonContext>>({});\n\nclass TabItemButton extends React.Component<TypeTabButtonsProps> {\n static override contextType = TabButtonContext;\n // @ts-notes - using the legacy syntax here because `declare` does not play well with babel\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n context!: React.ContextType<typeof TabButtonContext>;\n\n buttonRef: TypeTabButtonRef = React.createRef<React.ElementRef<\"button\">>();\n\n override componentDidMount() {\n this.context.onTabMount?.(this.props.id, this.buttonRef);\n }\n\n override componentDidUpdate(prevProps: TypeTabButtonsProps) {\n if (prevProps.id !== this.props.id) {\n this.context.onTabUpdate?.(prevProps.id, this.props.id);\n }\n }\n\n override componentWillUnmount() {\n this.context.onTabUnmount?.(this.props.id);\n }\n\n override render() {\n const { children, id, ...rest } = this.props;\n const { selectedId, onActivate, fullWidth } = this.context;\n const isSelected = selectedId === id;\n\n return (\n <TabItem key={id} fullWidth={fullWidth} isSelected={isSelected}>\n <TabButton\n innerRef={this.buttonRef}\n id={id}\n onClick={() => onActivate?.(id)}\n isSelected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n fullWidth={fullWidth}\n data-qa-tab-button={id}\n data-qa-tab-button-state={isSelected}\n aria-selected={isSelected}\n role=\"tab\"\n aria-controls={`${id}-panel`}\n {...rest}\n >\n {children}\n </TabButton>\n </TabItem>\n );\n }\n}\n\nconst TabPanel: React.FC<TypeTabPanelProps> = ({ children, id, ...rest }) => {\n const panelId = `${id}-panel`;\n\n return (\n <div id={panelId} role=\"tabpanel\" aria-labelledby={id} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * Render a group of buttons in a tab-heading style\n */\nclass Tabs extends React.Component<TypeTabsProps> {\n static Button = TabItemButton;\n static Panel = TabPanel;\n buttonRefs: Record<string, TypeTabButtonRef | null | undefined> = {};\n tabList: string[] = [];\n\n getSelectedId = () => this.props.selectedId;\n onActivate = (id: string) => this.props.onSelect(id);\n onTabMount = (id: string, ref: TypeTabButtonRef) => {\n if (!this.tabList.includes(id)) {\n this.tabList.push(id);\n this.buttonRefs[id] = ref;\n }\n };\n\n onTabUpdate = (previousId: string, newId: string) => {\n if (this.tabList.includes(previousId)) {\n this.tabList = this.tabList.map((id) => (id === previousId ? newId : id));\n this.buttonRefs[newId] = this.buttonRefs[previousId];\n this.buttonRefs[previousId] = undefined;\n }\n };\n\n onTabUnmount = (id: string) => {\n if (this.tabList.includes(id)) {\n this.tabList = this.tabList.filter((currentId) => currentId !== id);\n this.buttonRefs[id] = undefined;\n }\n };\n\n selectNextTab = (id: string) => {\n const buttonRef = this.buttonRefs[id];\n this.props.onSelect(id);\n buttonRef &&\n buttonRef.current &&\n buttonRef.current.focus &&\n buttonRef.current.focus();\n };\n\n keyHandler = ({ keyCode }: React.KeyboardEvent<HTMLDivElement>) => {\n switch (keyCode) {\n // left arrow\n case 37:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index - 1 >= 0 ? index - 1 : count - 1;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n // right arrow\n case 39:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index + 1 < count ? index + 1 : 0;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n default:\n break;\n }\n };\n\n override render() {\n const { children, qa, onSelect, ...rest } = this.props;\n return (\n <Container\n data-qa-tabs=\"\"\n onKeyUp={this.keyHandler}\n onSelect={onSelect}\n role=\"tablist\"\n {...qa}\n {...rest}\n >\n <TabButtonContext.Provider\n value={{\n selectedId: this.getSelectedId(),\n fullWidth: this.props.fullWidth,\n onActivate: this.onActivate,\n onTabMount: this.onTabMount,\n onTabUpdate: this.onTabUpdate,\n onTabUnmount: this.onTabUnmount,\n }}\n >\n {children}\n </TabButtonContext.Provider>\n </Container>\n );\n }\n}\n\nexport default Tabs;\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { Button } from \"@sproutsocial/seeds-react-button\";\nimport { type TypeTabsProps } from \"./TabsTypes\";\n\ninterface TypeTabState {\n isSelected: boolean;\n}\ntype TypeFullWidth = Pick<TypeTabsProps, \"fullWidth\">;\ninterface TypeStyleProps extends TypeFullWidth, TypeTabState {}\n\nconst Container = styled.div<TypeTabsProps>`\n display: ${(props) => (props.fullWidth ? \"flex\" : \"inline-flex\")};\n justify-content: space-between;\n margin: 0;\n padding: 0;\n border-bottom: ${(props) => props.theme.borders[500]}\n ${(props) => props.theme.colors.container.border.base};\n\n ${COMMON}\n`;\n\nexport const TabItem = styled.div<TypeStyleProps>`\n margin-bottom: -1px;\n ${(props) =>\n props.fullWidth &&\n css`\n flex-grow: 1;\n `};\n\n &:not(:last-child) {\n ${(props) =>\n !props.fullWidth &&\n css`\n margin-right: ${(props) => props.theme.space[350]};\n `};\n }\n\n ${(props) =>\n props.isSelected &&\n css`\n box-shadow: ${(props) =>\n `inset 0 -3px 0 0 ${props.theme.colors.button.primary.background.base}`};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n box-shadow: ${(props) =>\n `inset 0 -3px 0 0 ${props.theme.colors.button.primary.background.hover}`};\n `};\n }\n`;\n\nexport const TabButton = styled(Button)<TypeStyleProps>`\n padding: ${(props) => `${props.theme.space[350]} 0`};\n color: ${(props) => props.theme.colors.text.headline};\n width: 100%;\n\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.base};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.hover};\n `};\n }\n\n &:active {\n transform: none;\n }\n`;\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\n\nexport interface TypeTabButtonsProps extends TypeButtonProps {\n children: React.ReactNode;\n\n /** Should be unique among sibling elements */\n id: string;\n}\n\nexport interface TypeTabPanelProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n children: React.ReactNode;\n\n /** Should match the corresponding tab button id */\n id: string;\n}\n\nexport interface TypeTabsProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<\n React.ComponentPropsWithoutRef<\"ul\">,\n keyof TypeSystemCommonProps | \"onSelect\"\n > {\n children: React.ReactNode;\n onSelect: (arg0: string) => void;\n\n /** Whether or not the tabs should stretch to fill the width of their container */\n fullWidth?: boolean;\n qa?: object;\n\n /** ID of the selected tab */\n selectedId: string;\n}\n","import Tabs from \"./Tabs\";\n\nexport default Tabs;\nexport { Tabs };\nexport * from \"./TabsTypes\";\n"],"mappings":";AAAA,YAAYA,YAAW;;;ACAvB,OAAO,UAAU,WAAW;AAC5B,SAAS,cAAc;AACvB,SAAS,cAAc;;;ACFvB,OAAuB;;;ADWvB,IAAM,YAAY,OAAO;AAAA,aACZ,CAAC,UAAW,MAAM,YAAY,SAAS,aAAc;AAAA;AAAA;AAAA;AAAA,mBAI/C,CAAC,UAAU,MAAM,MAAM,QAAQ,GAAG,CAAC;AAAA,MAChD,CAAC,UAAU,MAAM,MAAM,OAAO,UAAU,OAAO,IAAI;AAAA;AAAA,IAErD,MAAM;AAAA;AAGH,IAAM,UAAU,OAAO;AAAA;AAAA,IAE1B,CAAC,UACD,MAAM,aACN;AAAA;AAAA,KAEC;AAAA;AAAA;AAAA,MAGC,CAAC,UACD,CAAC,MAAM,aACP;AAAA,wBACkB,CAACC,WAAUA,OAAM,MAAM,MAAM,GAAG,CAAC;AAAA,OAClD;AAAA;AAAA;AAAA,IAGH,CAAC,UACD,MAAM,cACN;AAAA,oBACgB,CAACA,WACb,oBAAoBA,OAAM,MAAM,OAAO,OAAO,QAAQ,WAAW,IAAI,EAAE;AAAA,KAC1E;AAAA;AAAA;AAAA,MAGC,CAAC,UACD,MAAM,cACN;AAAA,sBACgB,CAACA,WACb,oBAAoBA,OAAM,MAAM,OAAO,OAAO,QAAQ,WAAW,KAAK,EAAE;AAAA,OAC3E;AAAA;AAAA;AAIA,IAAM,YAAY,OAAO,MAAM;AAAA,aACzB,CAAC,UAAU,GAAG,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI;AAAA,WAC1C,CAAC,UAAU,MAAM,MAAM,OAAO,KAAK,QAAQ;AAAA;AAAA;AAAA,IAGlD,CAAC,UACD,MAAM,cACN;AAAA,eACW,CAACA,WAAUA,OAAM,MAAM,OAAO,KAAK,IAAI;AAAA,KACjD;AAAA;AAAA;AAAA,MAGC,CAAC,UACD,MAAM,cACN;AAAA,iBACW,CAACA,WAAUA,OAAM,MAAM,OAAO,KAAK,KAAK;AAAA,OAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOP,IAAO,iBAAQ;;;AD1BP;AAhCR,IAAM,mBAAyB,qBAA6C,CAAC,CAAC;AAE9E,IAAM,gBAAN,cAAkC,iBAA+B;AAAA,EAC/D,OAAgB,cAAc;AAAA;AAAA;AAAA;AAAA,EAI9B;AAAA,EAEA,YAAoC,iBAAsC;AAAA,EAEjE,oBAAoB;AAC3B,SAAK,QAAQ,aAAa,KAAK,MAAM,IAAI,KAAK,SAAS;AAAA,EACzD;AAAA,EAES,mBAAmB,WAAgC;AAC1D,QAAI,UAAU,OAAO,KAAK,MAAM,IAAI;AAClC,WAAK,QAAQ,cAAc,UAAU,IAAI,KAAK,MAAM,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EAES,uBAAuB;AAC9B,SAAK,QAAQ,eAAe,KAAK,MAAM,EAAE;AAAA,EAC3C;AAAA,EAES,SAAS;AAChB,UAAM,EAAE,UAAU,IAAI,GAAG,KAAK,IAAI,KAAK;AACvC,UAAM,EAAE,YAAY,YAAY,UAAU,IAAI,KAAK;AACnD,UAAM,aAAa,eAAe;AAElC,WACE,oBAAC,WAAiB,WAAsB,YACtC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,KAAK;AAAA,QACf;AAAA,QACA,SAAS,MAAM,aAAa,EAAE;AAAA,QAC9B;AAAA,QACA,UAAU,aAAa,IAAI;AAAA,QAC3B;AAAA,QACA,sBAAoB;AAAA,QACpB,4BAA0B;AAAA,QAC1B,iBAAe;AAAA,QACf,MAAK;AAAA,QACL,iBAAe,GAAG,EAAE;AAAA,QACnB,GAAG;AAAA,QAEH;AAAA;AAAA,IACH,KAhBY,EAiBd;AAAA,EAEJ;AACF;AAEA,IAAM,WAAwC,CAAC,EAAE,UAAU,IAAI,GAAG,KAAK,MAAM;AAC3E,QAAM,UAAU,GAAG,EAAE;AAErB,SACE,oBAAC,SAAI,IAAI,SAAS,MAAK,YAAW,mBAAiB,IAAK,GAAG,MACxD,UACH;AAEJ;AAKA,IAAM,OAAN,cAAyB,iBAAyB;AAAA,EAChD,OAAO,SAAS;AAAA,EAChB,OAAO,QAAQ;AAAA,EACf,aAAkE,CAAC;AAAA,EACnE,UAAoB,CAAC;AAAA,EAErB,gBAAgB,MAAM,KAAK,MAAM;AAAA,EACjC,aAAa,CAAC,OAAe,KAAK,MAAM,SAAS,EAAE;AAAA,EACnD,aAAa,CAAC,IAAY,QAA0B;AAClD,QAAI,CAAC,KAAK,QAAQ,SAAS,EAAE,GAAG;AAC9B,WAAK,QAAQ,KAAK,EAAE;AACpB,WAAK,WAAW,EAAE,IAAI;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,cAAc,CAAC,YAAoB,UAAkB;AACnD,QAAI,KAAK,QAAQ,SAAS,UAAU,GAAG;AACrC,WAAK,UAAU,KAAK,QAAQ,IAAI,CAAC,OAAQ,OAAO,aAAa,QAAQ,EAAG;AACxE,WAAK,WAAW,KAAK,IAAI,KAAK,WAAW,UAAU;AACnD,WAAK,WAAW,UAAU,IAAI;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,eAAe,CAAC,OAAe;AAC7B,QAAI,KAAK,QAAQ,SAAS,EAAE,GAAG;AAC7B,WAAK,UAAU,KAAK,QAAQ,OAAO,CAAC,cAAc,cAAc,EAAE;AAClE,WAAK,WAAW,EAAE,IAAI;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,gBAAgB,CAAC,OAAe;AAC9B,UAAM,YAAY,KAAK,WAAW,EAAE;AACpC,SAAK,MAAM,SAAS,EAAE;AACtB,iBACE,UAAU,WACV,UAAU,QAAQ,SAClB,UAAU,QAAQ,MAAM;AAAA,EAC5B;AAAA,EAEA,aAAa,CAAC,EAAE,QAAQ,MAA2C;AACjE,YAAQ,SAAS;AAAA;AAAA,MAEf,KAAK;AACH,aAAK,QAAQ,QAAQ,CAAC,IAAI,UAAU;AAClC,cAAI,OAAO,KAAK,cAAc,GAAG;AAC/B,kBAAM,QAAQ,KAAK,QAAQ;AAC3B,kBAAM,YAAY,QAAQ,KAAK,IAAI,QAAQ,IAAI,QAAQ;AACvD,kBAAM,SAAS,KAAK,QAAQ,SAAS;AACrC,iBAAK,cAAc,SAAS,SAAS,EAAE;AAAA,UACzC;AAAA,QACF,CAAC;AACD;AAAA;AAAA,MAGF,KAAK;AACH,aAAK,QAAQ,QAAQ,CAAC,IAAI,UAAU;AAClC,cAAI,OAAO,KAAK,cAAc,GAAG;AAC/B,kBAAM,QAAQ,KAAK,QAAQ;AAC3B,kBAAM,YAAY,QAAQ,IAAI,QAAQ,QAAQ,IAAI;AAClD,kBAAM,SAAS,KAAK,QAAQ,SAAS;AACrC,iBAAK,cAAc,SAAS,SAAS,EAAE;AAAA,UACzC;AAAA,QACF,CAAC;AACD;AAAA,MAEF;AACE;AAAA,IACJ;AAAA,EACF;AAAA,EAES,SAAS;AAChB,UAAM,EAAE,UAAU,IAAI,UAAU,GAAG,KAAK,IAAI,KAAK;AACjD,WACE;AAAA,MAAC;AAAA;AAAA,QACC,gBAAa;AAAA,QACb,SAAS,KAAK;AAAA,QACd;AAAA,QACA,MAAK;AAAA,QACJ,GAAG;AAAA,QACH,GAAG;AAAA,QAEJ;AAAA,UAAC,iBAAiB;AAAA,UAAjB;AAAA,YACC,OAAO;AAAA,cACL,YAAY,KAAK,cAAc;AAAA,cAC/B,WAAW,KAAK,MAAM;AAAA,cACtB,YAAY,KAAK;AAAA,cACjB,YAAY,KAAK;AAAA,cACjB,aAAa,KAAK;AAAA,cAClB,cAAc,KAAK;AAAA,YACrB;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AAEA,IAAO,eAAQ;;;AGtLf,IAAO,gBAAQ;","names":["React","props"]}
|
|
1
|
+
{"version":3,"sources":["../../src/Tabs.tsx","../../src/styles.ts","../../src/TabsTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Container, { TabButton } from \"./styles\";\nimport type {\n TypeTabButtonsProps,\n TypeTabsProps,\n TypeTabPanelProps,\n} from \"./TabsTypes\";\n\ninterface TypeTabButtonRef {\n current: null | React.ElementRef<\"button\">;\n}\ninterface TypeTabButtonContext {\n onActivate: (arg0: string) => void;\n onTabMount: (id: string, ref: TypeTabButtonRef) => void;\n onTabUpdate: (previousId: string, nextId: string) => void;\n onTabUnmount: (id: string) => void;\n selectedId: string;\n fullWidth?: boolean;\n}\n\nconst TabButtonContext = React.createContext<Partial<TypeTabButtonContext>>({});\n\nclass TabItemButton extends React.Component<TypeTabButtonsProps> {\n static override contextType = TabButtonContext;\n // @ts-notes - using the legacy syntax here because `declare` does not play well with babel\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n context!: React.ContextType<typeof TabButtonContext>;\n\n buttonRef: TypeTabButtonRef = React.createRef<React.ElementRef<\"button\">>();\n\n override componentDidMount() {\n this.context.onTabMount?.(this.props.id, this.buttonRef);\n }\n\n override componentDidUpdate(prevProps: TypeTabButtonsProps) {\n if (prevProps.id !== this.props.id) {\n this.context.onTabUpdate?.(prevProps.id, this.props.id);\n }\n }\n\n override componentWillUnmount() {\n this.context.onTabUnmount?.(this.props.id);\n }\n\n override render() {\n const { children, id, ...rest } = this.props;\n const { selectedId, onActivate, fullWidth } = this.context;\n const isSelected = selectedId === id;\n\n return (\n <TabButton\n key={id}\n innerRef={this.buttonRef}\n id={id}\n onClick={() => onActivate?.(id)}\n isSelected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n fullWidth={fullWidth}\n data-qa-tab-button={id}\n data-qa-tab-button-state={isSelected}\n aria-selected={isSelected}\n role=\"tab\"\n aria-controls={`${id}-panel`}\n {...rest}\n >\n {children}\n </TabButton>\n );\n }\n}\n\nconst TabPanel: React.FC<TypeTabPanelProps> = ({ children, id, ...rest }) => {\n const panelId = `${id}-panel`;\n\n return (\n <div id={panelId} role=\"tabpanel\" aria-labelledby={id} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * Render a group of buttons in a tab-heading style\n */\nclass Tabs extends React.Component<TypeTabsProps> {\n static Button = TabItemButton;\n static Panel = TabPanel;\n buttonRefs: Record<string, TypeTabButtonRef | null | undefined> = {};\n tabList: string[] = [];\n\n getSelectedId = () => this.props.selectedId;\n onActivate = (id: string) => this.props.onSelect(id);\n onTabMount = (id: string, ref: TypeTabButtonRef) => {\n if (!this.tabList.includes(id)) {\n this.tabList.push(id);\n this.buttonRefs[id] = ref;\n }\n };\n\n onTabUpdate = (previousId: string, newId: string) => {\n if (this.tabList.includes(previousId)) {\n this.tabList = this.tabList.map((id) => (id === previousId ? newId : id));\n this.buttonRefs[newId] = this.buttonRefs[previousId];\n this.buttonRefs[previousId] = undefined;\n }\n };\n\n onTabUnmount = (id: string) => {\n if (this.tabList.includes(id)) {\n this.tabList = this.tabList.filter((currentId) => currentId !== id);\n this.buttonRefs[id] = undefined;\n }\n };\n\n selectNextTab = (id: string) => {\n const buttonRef = this.buttonRefs[id];\n this.props.onSelect(id);\n buttonRef &&\n buttonRef.current &&\n buttonRef.current.focus &&\n buttonRef.current.focus();\n };\n\n keyHandler = ({ keyCode }: React.KeyboardEvent<HTMLDivElement>) => {\n switch (keyCode) {\n // left arrow\n case 37:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index - 1 >= 0 ? index - 1 : count - 1;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n // right arrow\n case 39:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index + 1 < count ? index + 1 : 0;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n default:\n break;\n }\n };\n\n override render() {\n const { children, qa, onSelect, ...rest } = this.props;\n return (\n <Container\n data-qa-tabs=\"\"\n onKeyUp={this.keyHandler}\n onSelect={onSelect}\n role=\"tablist\"\n {...qa}\n {...rest}\n >\n <TabButtonContext.Provider\n value={{\n selectedId: this.getSelectedId(),\n fullWidth: this.props.fullWidth,\n onActivate: this.onActivate,\n onTabMount: this.onTabMount,\n onTabUpdate: this.onTabUpdate,\n onTabUnmount: this.onTabUnmount,\n }}\n >\n {children}\n </TabButtonContext.Provider>\n </Container>\n );\n }\n}\n\nexport default Tabs;\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { Button } from \"@sproutsocial/seeds-react-button\";\nimport { type TypeTabsProps } from \"./TabsTypes\";\n\ninterface TypeTabState {\n isSelected: boolean;\n}\ntype TypeFullWidth = Pick<TypeTabsProps, \"fullWidth\">;\ninterface TypeStyleProps extends TypeFullWidth, TypeTabState {}\n\nconst Container = styled.div<TypeTabsProps>`\n display: ${(props) => (props.fullWidth ? \"flex\" : \"inline-flex\")};\n justify-content: space-between;\n margin: 0;\n padding: 0;\n border-bottom: ${(props) => props.theme.borders[500]}\n ${(props) => props.theme.colors.container.border.base};\n\n ${COMMON}\n`;\n\nexport const TabButton = styled(Button)<TypeStyleProps>`\n margin-bottom: -1px;\n padding: ${(props) => `${props.theme.space[350]} 0`};\n color: ${(props) => props.theme.colors.text.headline};\n border-radius: 0;\n border-width: 0 0 3px;\n width: 100%;\n\n ${(props) =>\n props.fullWidth &&\n css`\n flex-grow: 1;\n `};\n\n &:not(:last-child) {\n ${(props) =>\n !props.fullWidth &&\n css`\n margin-right: ${(props) => props.theme.space[350]};\n `};\n }\n\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.base};\n border-color: transparent transparent\n ${(props) => props.theme.colors.button.primary.background.base};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.hover};\n `};\n }\n\n &:focus,\n &:active {\n box-shadow: none;\n }\n\n &:active {\n transform: none;\n }\n`;\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\n\nexport interface TypeTabButtonsProps extends TypeButtonProps {\n children: React.ReactNode;\n\n /** Should be unique among sibling elements */\n id: string;\n}\n\nexport interface TypeTabPanelProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n children: React.ReactNode;\n\n /** Should match the corresponding tab button id */\n id: string;\n}\n\nexport interface TypeTabsProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<\n React.ComponentPropsWithoutRef<\"ul\">,\n keyof TypeSystemCommonProps | \"onSelect\"\n > {\n children: React.ReactNode;\n onSelect: (arg0: string) => void;\n\n /** Whether or not the tabs should stretch to fill the width of their container */\n fullWidth?: boolean;\n qa?: object;\n\n /** ID of the selected tab */\n selectedId: string;\n}\n","import Tabs from \"./Tabs\";\n\nexport default Tabs;\nexport { Tabs };\nexport * from \"./TabsTypes\";\n"],"mappings":"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","names":["React","props"]}
|
package/dist/index.js
CHANGED
|
@@ -57,8 +57,14 @@ var Container = import_styled_components.default.div`
|
|
|
57
57
|
|
|
58
58
|
${import_seeds_react_system_props.COMMON}
|
|
59
59
|
`;
|
|
60
|
-
var
|
|
60
|
+
var TabButton = (0, import_styled_components.default)(import_seeds_react_button.Button)`
|
|
61
61
|
margin-bottom: -1px;
|
|
62
|
+
padding: ${(props) => `${props.theme.space[350]} 0`};
|
|
63
|
+
color: ${(props) => props.theme.colors.text.headline};
|
|
64
|
+
border-radius: 0;
|
|
65
|
+
border-width: 0 0 3px;
|
|
66
|
+
width: 100%;
|
|
67
|
+
|
|
62
68
|
${(props) => props.fullWidth && import_styled_components.css`
|
|
63
69
|
flex-grow: 1;
|
|
64
70
|
`};
|
|
@@ -69,23 +75,10 @@ var TabItem = import_styled_components.default.div`
|
|
|
69
75
|
`};
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
${(props) => props.isSelected && import_styled_components.css`
|
|
73
|
-
box-shadow: ${(props2) => `inset 0 -3px 0 0 ${props2.theme.colors.button.primary.background.base}`};
|
|
74
|
-
`};
|
|
75
|
-
|
|
76
|
-
&:hover {
|
|
77
|
-
${(props) => props.isSelected && import_styled_components.css`
|
|
78
|
-
box-shadow: ${(props2) => `inset 0 -3px 0 0 ${props2.theme.colors.button.primary.background.hover}`};
|
|
79
|
-
`};
|
|
80
|
-
}
|
|
81
|
-
`;
|
|
82
|
-
var TabButton = (0, import_styled_components.default)(import_seeds_react_button.Button)`
|
|
83
|
-
padding: ${(props) => `${props.theme.space[350]} 0`};
|
|
84
|
-
color: ${(props) => props.theme.colors.text.headline};
|
|
85
|
-
width: 100%;
|
|
86
|
-
|
|
87
78
|
${(props) => props.isSelected && import_styled_components.css`
|
|
88
79
|
color: ${(props2) => props2.theme.colors.link.base};
|
|
80
|
+
border-color: transparent transparent
|
|
81
|
+
${(props2) => props2.theme.colors.button.primary.background.base};
|
|
89
82
|
`};
|
|
90
83
|
|
|
91
84
|
&:hover {
|
|
@@ -94,6 +87,11 @@ var TabButton = (0, import_styled_components.default)(import_seeds_react_button.
|
|
|
94
87
|
`};
|
|
95
88
|
}
|
|
96
89
|
|
|
90
|
+
&:focus,
|
|
91
|
+
&:active {
|
|
92
|
+
box-shadow: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
97
95
|
&:active {
|
|
98
96
|
transform: none;
|
|
99
97
|
}
|
|
@@ -125,7 +123,7 @@ var TabItemButton = class extends React2.Component {
|
|
|
125
123
|
const { children, id, ...rest } = this.props;
|
|
126
124
|
const { selectedId, onActivate, fullWidth } = this.context;
|
|
127
125
|
const isSelected = selectedId === id;
|
|
128
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
126
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
129
127
|
TabButton,
|
|
130
128
|
{
|
|
131
129
|
innerRef: this.buttonRef,
|
|
@@ -141,8 +139,9 @@ var TabItemButton = class extends React2.Component {
|
|
|
141
139
|
"aria-controls": `${id}-panel`,
|
|
142
140
|
...rest,
|
|
143
141
|
children
|
|
144
|
-
}
|
|
145
|
-
|
|
142
|
+
},
|
|
143
|
+
id
|
|
144
|
+
);
|
|
146
145
|
}
|
|
147
146
|
};
|
|
148
147
|
var TabPanel = ({ children, id, ...rest }) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Tabs.tsx","../src/styles.ts","../src/TabsTypes.ts"],"sourcesContent":["import Tabs from \"./Tabs\";\n\nexport default Tabs;\nexport { Tabs };\nexport * from \"./TabsTypes\";\n","import * as React from \"react\";\nimport Container, { TabItem, TabButton } from \"./styles\";\nimport type {\n TypeTabButtonsProps,\n TypeTabsProps,\n TypeTabPanelProps,\n} from \"./TabsTypes\";\n\ninterface TypeTabButtonRef {\n current: null | React.ElementRef<\"button\">;\n}\ninterface TypeTabButtonContext {\n onActivate: (arg0: string) => void;\n onTabMount: (id: string, ref: TypeTabButtonRef) => void;\n onTabUpdate: (previousId: string, nextId: string) => void;\n onTabUnmount: (id: string) => void;\n selectedId: string;\n fullWidth?: boolean;\n}\n\nconst TabButtonContext = React.createContext<Partial<TypeTabButtonContext>>({});\n\nclass TabItemButton extends React.Component<TypeTabButtonsProps> {\n static override contextType = TabButtonContext;\n // @ts-notes - using the legacy syntax here because `declare` does not play well with babel\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n context!: React.ContextType<typeof TabButtonContext>;\n\n buttonRef: TypeTabButtonRef = React.createRef<React.ElementRef<\"button\">>();\n\n override componentDidMount() {\n this.context.onTabMount?.(this.props.id, this.buttonRef);\n }\n\n override componentDidUpdate(prevProps: TypeTabButtonsProps) {\n if (prevProps.id !== this.props.id) {\n this.context.onTabUpdate?.(prevProps.id, this.props.id);\n }\n }\n\n override componentWillUnmount() {\n this.context.onTabUnmount?.(this.props.id);\n }\n\n override render() {\n const { children, id, ...rest } = this.props;\n const { selectedId, onActivate, fullWidth } = this.context;\n const isSelected = selectedId === id;\n\n return (\n <TabItem key={id} fullWidth={fullWidth} isSelected={isSelected}>\n <TabButton\n innerRef={this.buttonRef}\n id={id}\n onClick={() => onActivate?.(id)}\n isSelected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n fullWidth={fullWidth}\n data-qa-tab-button={id}\n data-qa-tab-button-state={isSelected}\n aria-selected={isSelected}\n role=\"tab\"\n aria-controls={`${id}-panel`}\n {...rest}\n >\n {children}\n </TabButton>\n </TabItem>\n );\n }\n}\n\nconst TabPanel: React.FC<TypeTabPanelProps> = ({ children, id, ...rest }) => {\n const panelId = `${id}-panel`;\n\n return (\n <div id={panelId} role=\"tabpanel\" aria-labelledby={id} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * Render a group of buttons in a tab-heading style\n */\nclass Tabs extends React.Component<TypeTabsProps> {\n static Button = TabItemButton;\n static Panel = TabPanel;\n buttonRefs: Record<string, TypeTabButtonRef | null | undefined> = {};\n tabList: string[] = [];\n\n getSelectedId = () => this.props.selectedId;\n onActivate = (id: string) => this.props.onSelect(id);\n onTabMount = (id: string, ref: TypeTabButtonRef) => {\n if (!this.tabList.includes(id)) {\n this.tabList.push(id);\n this.buttonRefs[id] = ref;\n }\n };\n\n onTabUpdate = (previousId: string, newId: string) => {\n if (this.tabList.includes(previousId)) {\n this.tabList = this.tabList.map((id) => (id === previousId ? newId : id));\n this.buttonRefs[newId] = this.buttonRefs[previousId];\n this.buttonRefs[previousId] = undefined;\n }\n };\n\n onTabUnmount = (id: string) => {\n if (this.tabList.includes(id)) {\n this.tabList = this.tabList.filter((currentId) => currentId !== id);\n this.buttonRefs[id] = undefined;\n }\n };\n\n selectNextTab = (id: string) => {\n const buttonRef = this.buttonRefs[id];\n this.props.onSelect(id);\n buttonRef &&\n buttonRef.current &&\n buttonRef.current.focus &&\n buttonRef.current.focus();\n };\n\n keyHandler = ({ keyCode }: React.KeyboardEvent<HTMLDivElement>) => {\n switch (keyCode) {\n // left arrow\n case 37:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index - 1 >= 0 ? index - 1 : count - 1;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n // right arrow\n case 39:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index + 1 < count ? index + 1 : 0;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n default:\n break;\n }\n };\n\n override render() {\n const { children, qa, onSelect, ...rest } = this.props;\n return (\n <Container\n data-qa-tabs=\"\"\n onKeyUp={this.keyHandler}\n onSelect={onSelect}\n role=\"tablist\"\n {...qa}\n {...rest}\n >\n <TabButtonContext.Provider\n value={{\n selectedId: this.getSelectedId(),\n fullWidth: this.props.fullWidth,\n onActivate: this.onActivate,\n onTabMount: this.onTabMount,\n onTabUpdate: this.onTabUpdate,\n onTabUnmount: this.onTabUnmount,\n }}\n >\n {children}\n </TabButtonContext.Provider>\n </Container>\n );\n }\n}\n\nexport default Tabs;\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { Button } from \"@sproutsocial/seeds-react-button\";\nimport { type TypeTabsProps } from \"./TabsTypes\";\n\ninterface TypeTabState {\n isSelected: boolean;\n}\ntype TypeFullWidth = Pick<TypeTabsProps, \"fullWidth\">;\ninterface TypeStyleProps extends TypeFullWidth, TypeTabState {}\n\nconst Container = styled.div<TypeTabsProps>`\n display: ${(props) => (props.fullWidth ? \"flex\" : \"inline-flex\")};\n justify-content: space-between;\n margin: 0;\n padding: 0;\n border-bottom: ${(props) => props.theme.borders[500]}\n ${(props) => props.theme.colors.container.border.base};\n\n ${COMMON}\n`;\n\nexport const TabItem = styled.div<TypeStyleProps>`\n margin-bottom: -1px;\n ${(props) =>\n props.fullWidth &&\n css`\n flex-grow: 1;\n `};\n\n &:not(:last-child) {\n ${(props) =>\n !props.fullWidth &&\n css`\n margin-right: ${(props) => props.theme.space[350]};\n `};\n }\n\n ${(props) =>\n props.isSelected &&\n css`\n box-shadow: ${(props) =>\n `inset 0 -3px 0 0 ${props.theme.colors.button.primary.background.base}`};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n box-shadow: ${(props) =>\n `inset 0 -3px 0 0 ${props.theme.colors.button.primary.background.hover}`};\n `};\n }\n`;\n\nexport const TabButton = styled(Button)<TypeStyleProps>`\n padding: ${(props) => `${props.theme.space[350]} 0`};\n color: ${(props) => props.theme.colors.text.headline};\n width: 100%;\n\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.base};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.hover};\n `};\n }\n\n &:active {\n transform: none;\n }\n`;\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\n\nexport interface TypeTabButtonsProps extends TypeButtonProps {\n children: React.ReactNode;\n\n /** Should be unique among sibling elements */\n id: string;\n}\n\nexport interface TypeTabPanelProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n children: React.ReactNode;\n\n /** Should match the corresponding tab button id */\n id: string;\n}\n\nexport interface TypeTabsProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<\n React.ComponentPropsWithoutRef<\"ul\">,\n keyof TypeSystemCommonProps | \"onSelect\"\n > {\n children: React.ReactNode;\n onSelect: (arg0: string) => void;\n\n /** Whether or not the tabs should stretch to fill the width of their container */\n fullWidth?: boolean;\n qa?: object;\n\n /** ID of the selected tab */\n selectedId: string;\n}\n"],"mappings":"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","names":["React","styled","props"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Tabs.tsx","../src/styles.ts","../src/TabsTypes.ts"],"sourcesContent":["import Tabs from \"./Tabs\";\n\nexport default Tabs;\nexport { Tabs };\nexport * from \"./TabsTypes\";\n","import * as React from \"react\";\nimport Container, { TabButton } from \"./styles\";\nimport type {\n TypeTabButtonsProps,\n TypeTabsProps,\n TypeTabPanelProps,\n} from \"./TabsTypes\";\n\ninterface TypeTabButtonRef {\n current: null | React.ElementRef<\"button\">;\n}\ninterface TypeTabButtonContext {\n onActivate: (arg0: string) => void;\n onTabMount: (id: string, ref: TypeTabButtonRef) => void;\n onTabUpdate: (previousId: string, nextId: string) => void;\n onTabUnmount: (id: string) => void;\n selectedId: string;\n fullWidth?: boolean;\n}\n\nconst TabButtonContext = React.createContext<Partial<TypeTabButtonContext>>({});\n\nclass TabItemButton extends React.Component<TypeTabButtonsProps> {\n static override contextType = TabButtonContext;\n // @ts-notes - using the legacy syntax here because `declare` does not play well with babel\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n context!: React.ContextType<typeof TabButtonContext>;\n\n buttonRef: TypeTabButtonRef = React.createRef<React.ElementRef<\"button\">>();\n\n override componentDidMount() {\n this.context.onTabMount?.(this.props.id, this.buttonRef);\n }\n\n override componentDidUpdate(prevProps: TypeTabButtonsProps) {\n if (prevProps.id !== this.props.id) {\n this.context.onTabUpdate?.(prevProps.id, this.props.id);\n }\n }\n\n override componentWillUnmount() {\n this.context.onTabUnmount?.(this.props.id);\n }\n\n override render() {\n const { children, id, ...rest } = this.props;\n const { selectedId, onActivate, fullWidth } = this.context;\n const isSelected = selectedId === id;\n\n return (\n <TabButton\n key={id}\n innerRef={this.buttonRef}\n id={id}\n onClick={() => onActivate?.(id)}\n isSelected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n fullWidth={fullWidth}\n data-qa-tab-button={id}\n data-qa-tab-button-state={isSelected}\n aria-selected={isSelected}\n role=\"tab\"\n aria-controls={`${id}-panel`}\n {...rest}\n >\n {children}\n </TabButton>\n );\n }\n}\n\nconst TabPanel: React.FC<TypeTabPanelProps> = ({ children, id, ...rest }) => {\n const panelId = `${id}-panel`;\n\n return (\n <div id={panelId} role=\"tabpanel\" aria-labelledby={id} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * Render a group of buttons in a tab-heading style\n */\nclass Tabs extends React.Component<TypeTabsProps> {\n static Button = TabItemButton;\n static Panel = TabPanel;\n buttonRefs: Record<string, TypeTabButtonRef | null | undefined> = {};\n tabList: string[] = [];\n\n getSelectedId = () => this.props.selectedId;\n onActivate = (id: string) => this.props.onSelect(id);\n onTabMount = (id: string, ref: TypeTabButtonRef) => {\n if (!this.tabList.includes(id)) {\n this.tabList.push(id);\n this.buttonRefs[id] = ref;\n }\n };\n\n onTabUpdate = (previousId: string, newId: string) => {\n if (this.tabList.includes(previousId)) {\n this.tabList = this.tabList.map((id) => (id === previousId ? newId : id));\n this.buttonRefs[newId] = this.buttonRefs[previousId];\n this.buttonRefs[previousId] = undefined;\n }\n };\n\n onTabUnmount = (id: string) => {\n if (this.tabList.includes(id)) {\n this.tabList = this.tabList.filter((currentId) => currentId !== id);\n this.buttonRefs[id] = undefined;\n }\n };\n\n selectNextTab = (id: string) => {\n const buttonRef = this.buttonRefs[id];\n this.props.onSelect(id);\n buttonRef &&\n buttonRef.current &&\n buttonRef.current.focus &&\n buttonRef.current.focus();\n };\n\n keyHandler = ({ keyCode }: React.KeyboardEvent<HTMLDivElement>) => {\n switch (keyCode) {\n // left arrow\n case 37:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index - 1 >= 0 ? index - 1 : count - 1;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n // right arrow\n case 39:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index + 1 < count ? index + 1 : 0;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n default:\n break;\n }\n };\n\n override render() {\n const { children, qa, onSelect, ...rest } = this.props;\n return (\n <Container\n data-qa-tabs=\"\"\n onKeyUp={this.keyHandler}\n onSelect={onSelect}\n role=\"tablist\"\n {...qa}\n {...rest}\n >\n <TabButtonContext.Provider\n value={{\n selectedId: this.getSelectedId(),\n fullWidth: this.props.fullWidth,\n onActivate: this.onActivate,\n onTabMount: this.onTabMount,\n onTabUpdate: this.onTabUpdate,\n onTabUnmount: this.onTabUnmount,\n }}\n >\n {children}\n </TabButtonContext.Provider>\n </Container>\n );\n }\n}\n\nexport default Tabs;\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { Button } from \"@sproutsocial/seeds-react-button\";\nimport { type TypeTabsProps } from \"./TabsTypes\";\n\ninterface TypeTabState {\n isSelected: boolean;\n}\ntype TypeFullWidth = Pick<TypeTabsProps, \"fullWidth\">;\ninterface TypeStyleProps extends TypeFullWidth, TypeTabState {}\n\nconst Container = styled.div<TypeTabsProps>`\n display: ${(props) => (props.fullWidth ? \"flex\" : \"inline-flex\")};\n justify-content: space-between;\n margin: 0;\n padding: 0;\n border-bottom: ${(props) => props.theme.borders[500]}\n ${(props) => props.theme.colors.container.border.base};\n\n ${COMMON}\n`;\n\nexport const TabButton = styled(Button)<TypeStyleProps>`\n margin-bottom: -1px;\n padding: ${(props) => `${props.theme.space[350]} 0`};\n color: ${(props) => props.theme.colors.text.headline};\n border-radius: 0;\n border-width: 0 0 3px;\n width: 100%;\n\n ${(props) =>\n props.fullWidth &&\n css`\n flex-grow: 1;\n `};\n\n &:not(:last-child) {\n ${(props) =>\n !props.fullWidth &&\n css`\n margin-right: ${(props) => props.theme.space[350]};\n `};\n }\n\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.base};\n border-color: transparent transparent\n ${(props) => props.theme.colors.button.primary.background.base};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.hover};\n `};\n }\n\n &:focus,\n &:active {\n box-shadow: none;\n }\n\n &:active {\n transform: none;\n }\n`;\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\n\nexport interface TypeTabButtonsProps extends TypeButtonProps {\n children: React.ReactNode;\n\n /** Should be unique among sibling elements */\n id: string;\n}\n\nexport interface TypeTabPanelProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n children: React.ReactNode;\n\n /** Should match the corresponding tab button id */\n id: string;\n}\n\nexport interface TypeTabsProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<\n React.ComponentPropsWithoutRef<\"ul\">,\n keyof TypeSystemCommonProps | \"onSelect\"\n > {\n children: React.ReactNode;\n onSelect: (arg0: string) => void;\n\n /** Whether or not the tabs should stretch to fill the width of their container */\n fullWidth?: boolean;\n qa?: object;\n\n /** ID of the selected tab */\n selectedId: string;\n}\n"],"mappings":"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","names":["React","styled","props"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sproutsocial/seeds-react-tabs",
|
|
3
|
-
"version": "1.2
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "Seeds React Tabs",
|
|
5
5
|
"author": "Sprout Social, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"test:watch": "jest --watch --coverage=false"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@sproutsocial/seeds-react-theme": "^3.
|
|
21
|
+
"@sproutsocial/seeds-react-theme": "^3.6.0",
|
|
22
22
|
"@sproutsocial/seeds-react-system-props": "^3.0.1",
|
|
23
|
-
"@sproutsocial/seeds-react-button": "^1.
|
|
23
|
+
"@sproutsocial/seeds-react-button": "^1.4.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/react": "^18.0.0",
|
package/src/Tabs.stories.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { Icon, type TypeIconName } from "@sproutsocial/seeds-react-icon";
|
|
|
4
4
|
import { Tabs } from "./";
|
|
5
5
|
import { Text } from "@sproutsocial/seeds-react-text";
|
|
6
6
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
7
|
+
import Box from "@sproutsocial/seeds-react-box";
|
|
7
8
|
|
|
8
9
|
interface TypeTabData {
|
|
9
10
|
id: string;
|
|
@@ -77,6 +78,55 @@ export const Default: Story = {
|
|
|
77
78
|
name: "Default",
|
|
78
79
|
};
|
|
79
80
|
|
|
81
|
+
export const FullWidth: Story = {
|
|
82
|
+
render: (args) => {
|
|
83
|
+
const [selectedId, setSelectedId] = useState("notifications");
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Box width="100%" display="flex" flexDirection="column">
|
|
87
|
+
<Tabs
|
|
88
|
+
selectedId={selectedId}
|
|
89
|
+
onSelect={(selected) => setSelectedId(selected)}
|
|
90
|
+
fullWidth
|
|
91
|
+
>
|
|
92
|
+
<Tabs.Button id="notifications">
|
|
93
|
+
<Icon name="bell-outline" mr="12px" aria-hidden />
|
|
94
|
+
<Text size="300" fontWeight="600">
|
|
95
|
+
Notifications
|
|
96
|
+
</Text>
|
|
97
|
+
</Tabs.Button>
|
|
98
|
+
<Tabs.Button id="issues">
|
|
99
|
+
<Icon name="triangle-exclamation-outline" mr="12px" aria-hidden />
|
|
100
|
+
<Text size="300" fontWeight="600">
|
|
101
|
+
Issues
|
|
102
|
+
</Text>
|
|
103
|
+
</Tabs.Button>
|
|
104
|
+
</Tabs>
|
|
105
|
+
|
|
106
|
+
{selectedId === "notifications" && (
|
|
107
|
+
<Tabs.Panel id="notifications">
|
|
108
|
+
<Text mt="24px">
|
|
109
|
+
Notifications panel content goes here. This panel is properly
|
|
110
|
+
connected to the "Notifications" tab via ARIA attributes for
|
|
111
|
+
accessibility.
|
|
112
|
+
</Text>
|
|
113
|
+
</Tabs.Panel>
|
|
114
|
+
)}
|
|
115
|
+
|
|
116
|
+
{selectedId === "issues" && (
|
|
117
|
+
<Tabs.Panel id="issues">
|
|
118
|
+
<Text mt="24px">
|
|
119
|
+
Issues panel content goes here. Screen readers will announce the
|
|
120
|
+
relationship between tabs and panels.
|
|
121
|
+
</Text>
|
|
122
|
+
</Tabs.Panel>
|
|
123
|
+
)}
|
|
124
|
+
</Box>
|
|
125
|
+
);
|
|
126
|
+
},
|
|
127
|
+
name: "Full width",
|
|
128
|
+
};
|
|
129
|
+
|
|
80
130
|
export const RemoveATab: Story = {
|
|
81
131
|
render: (args) => {
|
|
82
132
|
const [state, setState] = useState<TypeTabsStoryState>({
|
package/src/Tabs.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import Container, {
|
|
2
|
+
import Container, { TabButton } from "./styles";
|
|
3
3
|
import type {
|
|
4
4
|
TypeTabButtonsProps,
|
|
5
5
|
TypeTabsProps,
|
|
@@ -49,24 +49,23 @@ class TabItemButton extends React.Component<TypeTabButtonsProps> {
|
|
|
49
49
|
const isSelected = selectedId === id;
|
|
50
50
|
|
|
51
51
|
return (
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
</TabItem>
|
|
52
|
+
<TabButton
|
|
53
|
+
key={id}
|
|
54
|
+
innerRef={this.buttonRef}
|
|
55
|
+
id={id}
|
|
56
|
+
onClick={() => onActivate?.(id)}
|
|
57
|
+
isSelected={isSelected}
|
|
58
|
+
tabIndex={isSelected ? 0 : -1}
|
|
59
|
+
fullWidth={fullWidth}
|
|
60
|
+
data-qa-tab-button={id}
|
|
61
|
+
data-qa-tab-button-state={isSelected}
|
|
62
|
+
aria-selected={isSelected}
|
|
63
|
+
role="tab"
|
|
64
|
+
aria-controls={`${id}-panel`}
|
|
65
|
+
{...rest}
|
|
66
|
+
>
|
|
67
|
+
{children}
|
|
68
|
+
</TabButton>
|
|
70
69
|
);
|
|
71
70
|
}
|
|
72
71
|
}
|
package/src/styles.ts
CHANGED
|
@@ -20,8 +20,14 @@ const Container = styled.div<TypeTabsProps>`
|
|
|
20
20
|
${COMMON}
|
|
21
21
|
`;
|
|
22
22
|
|
|
23
|
-
export const
|
|
23
|
+
export const TabButton = styled(Button)<TypeStyleProps>`
|
|
24
24
|
margin-bottom: -1px;
|
|
25
|
+
padding: ${(props) => `${props.theme.space[350]} 0`};
|
|
26
|
+
color: ${(props) => props.theme.colors.text.headline};
|
|
27
|
+
border-radius: 0;
|
|
28
|
+
border-width: 0 0 3px;
|
|
29
|
+
width: 100%;
|
|
30
|
+
|
|
25
31
|
${(props) =>
|
|
26
32
|
props.fullWidth &&
|
|
27
33
|
css`
|
|
@@ -36,32 +42,12 @@ export const TabItem = styled.div<TypeStyleProps>`
|
|
|
36
42
|
`};
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
${(props) =>
|
|
40
|
-
props.isSelected &&
|
|
41
|
-
css`
|
|
42
|
-
box-shadow: ${(props) =>
|
|
43
|
-
`inset 0 -3px 0 0 ${props.theme.colors.button.primary.background.base}`};
|
|
44
|
-
`};
|
|
45
|
-
|
|
46
|
-
&:hover {
|
|
47
|
-
${(props) =>
|
|
48
|
-
props.isSelected &&
|
|
49
|
-
css`
|
|
50
|
-
box-shadow: ${(props) =>
|
|
51
|
-
`inset 0 -3px 0 0 ${props.theme.colors.button.primary.background.hover}`};
|
|
52
|
-
`};
|
|
53
|
-
}
|
|
54
|
-
`;
|
|
55
|
-
|
|
56
|
-
export const TabButton = styled(Button)<TypeStyleProps>`
|
|
57
|
-
padding: ${(props) => `${props.theme.space[350]} 0`};
|
|
58
|
-
color: ${(props) => props.theme.colors.text.headline};
|
|
59
|
-
width: 100%;
|
|
60
|
-
|
|
61
45
|
${(props) =>
|
|
62
46
|
props.isSelected &&
|
|
63
47
|
css`
|
|
64
48
|
color: ${(props) => props.theme.colors.link.base};
|
|
49
|
+
border-color: transparent transparent
|
|
50
|
+
${(props) => props.theme.colors.button.primary.background.base};
|
|
65
51
|
`};
|
|
66
52
|
|
|
67
53
|
&:hover {
|
|
@@ -72,6 +58,11 @@ export const TabButton = styled(Button)<TypeStyleProps>`
|
|
|
72
58
|
`};
|
|
73
59
|
}
|
|
74
60
|
|
|
61
|
+
&:focus,
|
|
62
|
+
&:active {
|
|
63
|
+
box-shadow: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
75
66
|
&:active {
|
|
76
67
|
transform: none;
|
|
77
68
|
}
|