orcs-design-system 3.3.1 → 3.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.
@@ -0,0 +1,64 @@
1
+ import React from "react";
2
+ import TabsAlt from ".";
3
+ import { BrowserRouter, Route, Switch } from "react-router-dom";
4
+ import Box from "../Box";
5
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
+ export default {
7
+ title: "Components/TabsAlt",
8
+ decorators: [storyFn => /*#__PURE__*/_jsx(Box, {
9
+ boxBorder: "default",
10
+ shadow: "default",
11
+ pb: "200px",
12
+ children: storyFn()
13
+ })],
14
+ component: TabsAlt
15
+ };
16
+ const tabsList = [{
17
+ label: "Details",
18
+ path: "/details"
19
+ }, {
20
+ label: "Strategy",
21
+ path: "/strategy"
22
+ }, {
23
+ label: "Associations",
24
+ path: "/associations"
25
+ }, {
26
+ label: "Visualisation",
27
+ path: "/visualisation"
28
+ }, {
29
+ label: "Principles",
30
+ path: "/principles"
31
+ }, {
32
+ label: "Planner",
33
+ path: "/planner"
34
+ }, {
35
+ label: "Forecast",
36
+ path: "/forecast"
37
+ }, {
38
+ label: "Team Builder",
39
+ path: "/teambuilder"
40
+ }, {
41
+ label: "History",
42
+ path: "/history",
43
+ isVisible: false
44
+ }];
45
+ export const defaultTabs = () => /*#__PURE__*/_jsxs(BrowserRouter, {
46
+ children: [/*#__PURE__*/_jsx(TabsAlt, {
47
+ tabsList: tabsList
48
+ }), /*#__PURE__*/_jsx(Switch, {
49
+ children: tabsList.map(tab => /*#__PURE__*/_jsx(Route, {
50
+ path: tab.path,
51
+ children: /*#__PURE__*/_jsxs(Box, {
52
+ p: "l",
53
+ mt: "l",
54
+ children: ["ROUTE RENDERED: ", tab.label]
55
+ })
56
+ }, tab.path))
57
+ })]
58
+ });
59
+ defaultTabs.storyName = "Default";
60
+ defaultTabs.__docgenInfo = {
61
+ "description": "",
62
+ "methods": [],
63
+ "displayName": "defaultTabs"
64
+ };
@@ -0,0 +1,211 @@
1
+ import React, { useState, useRef, useEffect, useCallback } from "react";
2
+ import styled, { css } from "styled-components";
3
+ import { NavLink, useLocation } from "react-router-dom";
4
+ import { isEqual } from "lodash";
5
+ import ActionsMenu, { ActionsMenuItem } from "../ActionsMenu";
6
+ import Icon from "../Icon";
7
+ import FlexItem from "../Flex";
8
+ import { themeGet } from "@styled-system/theme-get";
9
+ import PropTypes from "prop-types";
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const TabsContainer = styled.div.withConfig({
12
+ displayName: "TabsAlt__TabsContainer",
13
+ componentId: "sc-hkpvfu-0"
14
+ })(["position:relative;width:100%;&:after{content:\"\";position:absolute;bottom:0;width:100%;height:37px;background-color:", ";border-bottom:2px solid ", ";z-index:0;}"], themeGet("colors.white"), themeGet("colors.greyLighter"));
15
+ const TabWrapper = styled.div.withConfig({
16
+ displayName: "TabsAlt__TabWrapper",
17
+ componentId: "sc-hkpvfu-1"
18
+ })(["position:relative;width:100%;z-index:1;"]);
19
+ const VisibleTabs = styled.div.withConfig({
20
+ displayName: "TabsAlt__VisibleTabs",
21
+ componentId: "sc-hkpvfu-2"
22
+ })(["flex-shrink:1;display:flex;align-items:center;justify-content:flex-start;overflow:hidden;"]);
23
+ const activeTabStyle = css(["background-color:", ";color:", ";border-bottom:2px solid ", ";cursor:default;&:hover,&:focus{background-color:", ";color:", ";box-shadow:none;}"], themeGet("colors.white"), themeGet("colors.primary"), themeGet("colors.primary"), themeGet("colors.white"), themeGet("colors.primary"));
24
+ const Tab = styled(NavLink).withConfig({
25
+ displayName: "TabsAlt__Tab",
26
+ componentId: "sc-hkpvfu-3"
27
+ })(["width:", ";display:block;transition:background 200ms ease-in-out,color 200ms ease-in-out;border-bottom:2px solid ", ";padding:", " ", ";font-size:", ";font-weight:", ";position:relative;white-space:nowrap;text-decoration:none;text-align:center;background-color:", ";color:", ";cursor:pointer;", " &:hover{background-color:", ";color:", ";box-shadow:inset 0 2px 5px 0 ", ";}&:focus{outline:0;box-shadow:inset 0 2px 5px 0 ", ";}&.active{", "}"], _ref => {
28
+ let {
29
+ fullWidth
30
+ } = _ref;
31
+ return fullWidth ? "100%" : "fit-content";
32
+ }, themeGet("colors.greyLighter"), themeGet("space.3"), themeGet("space.4"), themeGet("fontSizes.1"), themeGet("fontWeights.2"), themeGet("colors.white"), themeGet("colors.greyDark"), _ref2 => {
33
+ let {
34
+ tabInShowMore
35
+ } = _ref2;
36
+ return tabInShowMore ? css(["position:absolute;visibility:hidden;"]) : "";
37
+ }, themeGet("colors.white"), themeGet("colors.primary"), themeGet("colors.primaryLightest"), themeGet("colors.primaryLightest"), activeTabStyle);
38
+ const ShowMoreButton = styled.button.withConfig({
39
+ displayName: "TabsAlt__ShowMoreButton",
40
+ componentId: "sc-hkpvfu-4"
41
+ })(["appearance:none;border:none;font-family:", ";font-size:", ";font-weight:", ";background-color:", ";border-bottom:2px solid ", ";transition:", ";padding:", " ", ";color:", ";display:", ";align-items:center;cursor:pointer;&:hover{background-color:", ";color:", ";box-shadow:inset 0 2px 5px 0 ", ";}&:focus{outline:0;box-shadow:inset 0 2px 5px 0 ", ";}&.hasActive{", "}"], themeGet("fonts.main"), themeGet("fontSizes.1"), themeGet("fontWeights.2"), themeGet("colors.white"), themeGet("colors.greyLighter"), themeGet("transition.transitionDefault"), themeGet("space.3"), themeGet("space.4"), themeGet("colors.greyDark"), _ref3 => {
42
+ let {
43
+ showMoreVisible
44
+ } = _ref3;
45
+ return showMoreVisible ? "flex" : "none";
46
+ }, themeGet("colors.white"), themeGet("colors.primary"), themeGet("colors.primaryLightest"), themeGet("colors.primaryLightest"), activeTabStyle);
47
+ const ShowMoreTabs = styled.div.withConfig({
48
+ displayName: "TabsAlt__ShowMoreTabs",
49
+ componentId: "sc-hkpvfu-5"
50
+ })(["border-radius:", ";background-color:", ";width:fit-content;overflow:hidden;display:flex;gap:1px;flex-direction:column;justify-content:flex-start;box-shadow:", ";& [class^=\"TabsAlt__Tab\"]{border:0;padding:", ";text-align:left;}"], themeGet("radii.2"), themeGet("colors.greyLighter"), themeGet("shadows.boxDefault"), themeGet("space.3"));
51
+ const tabsGap = 0;
52
+ const TabsAlt = _ref4 => {
53
+ let {
54
+ tabsList
55
+ } = _ref4;
56
+ const [isMounted, setIsMounted] = useState(false);
57
+ const containerRef = useRef(null);
58
+ const containerVisibleWidth = useRef(0);
59
+ const [showMoreTabs, setShowMoreTabs] = useState([]);
60
+ const calculateVisibility = useCallback(actionElements => {
61
+ const showMoreButton = document.getElementById("show-more-button");
62
+ const showMoreButtonWidth = showMoreButton?.offsetWidth ?? 0;
63
+ // as we loop through the tabs, we need to calculate the width of the visible tabs.
64
+ let calculatedWidth = showMoreTabs.length ? showMoreButtonWidth : 0;
65
+
66
+ // variable for the list of hidden tabs which will be put to react state
67
+ const newShowMoreTabs = [];
68
+ [...actionElements].filter(el => el.tagName === "A") // this ensures that the ShowMore button is not included in this logic
69
+ .forEach((actionEl, i) => {
70
+ // visibleElementsWidth will be increased by
71
+ // the corresponding width of the element + gapWidth
72
+ calculatedWidth += actionEl.offsetWidth + tabsGap;
73
+
74
+ // compare computed widths and push into newShowMoreTabs if current tab width is bigger than container width
75
+ if (calculatedWidth >= containerVisibleWidth.current) {
76
+ newShowMoreTabs.push(i);
77
+ }
78
+ });
79
+ if (!isEqual(showMoreTabs, newShowMoreTabs)) {
80
+ // update React state with the list of hidden tabs
81
+ setShowMoreTabs(newShowMoreTabs);
82
+ }
83
+ }, [showMoreTabs]);
84
+ useEffect(() => {
85
+ const actionElements = containerRef.current?.children || [];
86
+ const resizeObserver = new ResizeObserver(entries => {
87
+ for (const entry of entries) {
88
+ if (entry.contentBoxSize) {
89
+ const contentBoxSize = entry.contentBoxSize[0];
90
+
91
+ // Math.ceil is necessary to round up and return
92
+ // the smallest integer for the size of observed element
93
+ containerVisibleWidth.current = Math.ceil(contentBoxSize.inlineSize);
94
+
95
+ // invoke the functions which calculates tabs visibility
96
+ // and sets data to the list of hidden tabs
97
+ calculateVisibility(actionElements);
98
+ }
99
+ }
100
+ });
101
+
102
+ // This is to help in cases where useEffect callback is triggered before React repaint.
103
+ if (!isMounted) {
104
+ setTimeout(() => {
105
+ setIsMounted(true);
106
+ calculateVisibility(actionElements);
107
+ }, 500);
108
+ } else {
109
+ // adding ResizeObserver to the observed container
110
+ resizeObserver.observe(containerRef.current);
111
+ }
112
+ }, [calculateVisibility, isMounted]);
113
+ const visibleTabsList = tabsList.filter(tab => tab.isVisible ?? true);
114
+ const showMoreTabsList = visibleTabsList.filter((_tab, i) => showMoreTabs.includes(i));
115
+ const location = useLocation();
116
+ const showMoreItemActive = showMoreTabsList.find(action => location.pathname.endsWith(action.path));
117
+ return /*#__PURE__*/_jsx(TabsContainer, {
118
+ children: /*#__PURE__*/_jsx(TabWrapper, {
119
+ children: /*#__PURE__*/_jsxs(VisibleTabs, {
120
+ style: {
121
+ gap: tabsGap
122
+ },
123
+ ref: containerRef,
124
+ role: "tablist",
125
+ children: [visibleTabsList.map((tab, i) => /*#__PURE__*/_jsx(Tab, {
126
+ className: tab.className,
127
+ id: tab.id,
128
+ "data-testid": tab["data-testid"],
129
+ tabInShowMore: showMoreTabs.includes(i),
130
+ to: tab.path,
131
+ role: "tab",
132
+ children: tab.label
133
+ }, tab.path)), /*#__PURE__*/_jsx(ActionsMenu, {
134
+ direction: "bottom-end",
135
+ role: "presentation",
136
+ renderTrigger: props => /*#__PURE__*/_jsxs(ShowMoreButton, {
137
+ ...props,
138
+ showMoreVisible: showMoreTabsList.length,
139
+ id: "show-more-button",
140
+ className: showMoreItemActive && "hasActive",
141
+ role: "tab",
142
+ children: [/*#__PURE__*/_jsx(FlexItem, {
143
+ flex: "0 0 auto",
144
+ children: "More"
145
+ }), /*#__PURE__*/_jsx(FlexItem, {
146
+ flex: "0 0 auto",
147
+ children: /*#__PURE__*/_jsx(Icon, {
148
+ icon: ["fas", "chevron-down"],
149
+ title: "Down",
150
+ ml: "xs",
151
+ size: "sm"
152
+ })
153
+ })]
154
+ }),
155
+ closeOnClick: true,
156
+ children: /*#__PURE__*/_jsx(ShowMoreTabs, {
157
+ children: showMoreTabsList.map(tab => /*#__PURE__*/_jsx(ActionsMenuItem, {
158
+ className: tab.className,
159
+ id: tab.id,
160
+ "data-testid": tab["data-testid"],
161
+ Component: Tab,
162
+ fullWidth: true,
163
+ to: tab.path,
164
+ children: tab.label
165
+ }, tab.path))
166
+ })
167
+ })]
168
+ })
169
+ })
170
+ });
171
+ };
172
+ TabsAlt.propTypes = {
173
+ /** isVisible defaults to true if not passed */
174
+ tabsList: PropTypes.arrayOf(PropTypes.shape({
175
+ label: PropTypes.string.isRequired,
176
+ path: PropTypes.string.isRequired,
177
+ isVisible: PropTypes.bool
178
+ })).isRequired
179
+ };
180
+ TabsAlt.__docgenInfo = {
181
+ "description": "",
182
+ "methods": [],
183
+ "displayName": "TabsAlt",
184
+ "props": {
185
+ "tabsList": {
186
+ "description": "isVisible defaults to true if not passed",
187
+ "type": {
188
+ "name": "arrayOf",
189
+ "value": {
190
+ "name": "shape",
191
+ "value": {
192
+ "label": {
193
+ "name": "string",
194
+ "required": true
195
+ },
196
+ "path": {
197
+ "name": "string",
198
+ "required": true
199
+ },
200
+ "isVisible": {
201
+ "name": "bool",
202
+ "required": false
203
+ }
204
+ }
205
+ }
206
+ },
207
+ "required": true
208
+ }
209
+ }
210
+ };
211
+ export default TabsAlt;
@@ -59,6 +59,7 @@ test("all components exported", () => {
59
59
  "SystemThemeProvider",
60
60
  "Table",
61
61
  "Tabs",
62
+ "TabsAlt",
62
63
  "Tag",
63
64
  "Text",
64
65
  "TextArea",
package/es/index.js CHANGED
@@ -40,6 +40,7 @@ export { default as StatusDot } from "./components/StatusDot";
40
40
  export { default as StyledLink, styleLink } from "./components/StyledLink";
41
41
  export { default as Table } from "./components/Table";
42
42
  export { default as Tabs } from "./components/Tabs";
43
+ export { default as TabsAlt } from "./components/TabsAlt";
43
44
  export { default as Tag } from "./components/Tag";
44
45
  export { default as TextInput } from "./components/TextInput";
45
46
  export { default as TextArea } from "./components/TextArea";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orcs-design-system",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "engines": {
5
5
  "node": "20.12.2"
6
6
  },