@via-profit/ui-kit 0.9.1 → 0.10.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/Badge/BadgeContainer.js +1 -1
- package/Badge/BadgeTextWrapper.js +3 -1
- package/Button/buttonVariants.d.ts +1 -1
- package/Button/buttonVariants.js +57 -8
- package/Button/index.d.ts +4 -4
- package/CHANGELOG.md +21 -0
- package/Calendar/CalendarControlButton.d.ts +1 -1
- package/Calendar/CalendarWeekDayLabel.js +1 -1
- package/Menu/MenuContainer.d.ts +26 -0
- package/Menu/MenuContainer.js +40 -17
- package/Menu/MenuList.d.ts +4 -0
- package/Menu/MenuList.js +3 -3
- package/Menu/MenuSeparator.d.ts +8 -0
- package/Menu/MenuSeparator.js +29 -0
- package/Menu/index.d.ts +1 -0
- package/Menu/index.js +1 -0
- package/Modal/BaseModal/ModalInner.js +2 -1
- package/Pagination/PaginationItem.d.ts +1 -1
- package/Stepper/Step.d.ts +51 -0
- package/Stepper/Step.js +169 -0
- package/Stepper/Stepper.d.ts +49 -0
- package/Stepper/Stepper.js +74 -0
- package/Stepper/context.d.ts +21 -0
- package/Stepper/context.js +12 -0
- package/Stepper/index.d.ts +6 -0
- package/Stepper/index.js +10 -0
- package/Surface/SurfaceSubheader.js +4 -3
- package/Tabs/Tab.d.ts +8 -0
- package/Tabs/Tab.js +75 -32
- package/Tabs/TabList.js +24 -5
- package/Tabs/Tabs.d.ts +25 -1
- package/Tabs/Tabs.js +5 -1
- package/Tabs/context.d.ts +18 -0
- package/Tabs/context.js +9 -1
- package/Tabs/index.d.ts +1 -1
- package/ThemeProvider/index.d.ts +6 -1
- package/ThemeProvider/tokens.js +1 -0
- package/esm/Badge/BadgeContainer.js +1 -1
- package/esm/Badge/BadgeTextWrapper.js +3 -1
- package/esm/Button/buttonVariants.js +57 -8
- package/esm/Calendar/CalendarWeekDayLabel.js +1 -1
- package/esm/Menu/MenuContainer.js +40 -17
- package/esm/Menu/MenuList.js +3 -3
- package/esm/Menu/MenuSeparator.js +23 -0
- package/esm/Menu/index.js +1 -0
- package/esm/Modal/BaseModal/ModalInner.js +2 -1
- package/esm/Stepper/Step.js +164 -0
- package/esm/Stepper/Stepper.js +69 -0
- package/esm/Stepper/context.js +6 -0
- package/esm/Stepper/index.js +3 -0
- package/esm/Surface/SurfaceSubheader.js +4 -3
- package/esm/Tabs/Tab.js +77 -34
- package/esm/Tabs/TabList.js +24 -5
- package/esm/Tabs/Tabs.js +5 -1
- package/esm/Tabs/context.js +8 -0
- package/esm/ThemeProvider/tokens.js +1 -0
- package/package.json +31 -1
package/Stepper/Step.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
const react_1 = __importDefault(require("react"));
|
|
18
|
+
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
19
|
+
const react_2 = require("@emotion/react");
|
|
20
|
+
const context_1 = require("./context");
|
|
21
|
+
const Container = styled_1.default.div `
|
|
22
|
+
position: relative;
|
|
23
|
+
display: flex;
|
|
24
|
+
${({ $orientation, $alternativeLabel, $last }) => $orientation === 'vertical'
|
|
25
|
+
? (0, react_2.css) `
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
`
|
|
28
|
+
: $alternativeLabel
|
|
29
|
+
? (0, react_2.css) `
|
|
30
|
+
flex: 1 1 0;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
align-items: center;
|
|
33
|
+
text-align: center;
|
|
34
|
+
`
|
|
35
|
+
: (0, react_2.css) `
|
|
36
|
+
flex: ${$last ? '0 0 auto' : '1 1 auto'};
|
|
37
|
+
align-items: center;
|
|
38
|
+
`}
|
|
39
|
+
`;
|
|
40
|
+
const Head = styled_1.default.div `
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: ${({ $alternativeLabel }) => ($alternativeLabel ? 'center' : 'flex-start')};
|
|
43
|
+
flex-direction: ${({ $alternativeLabel }) => ($alternativeLabel ? 'column' : 'row')};
|
|
44
|
+
gap: ${({ $alternativeLabel }) => ($alternativeLabel ? '0.35em' : '0.5em')};
|
|
45
|
+
flex-shrink: 0;
|
|
46
|
+
`;
|
|
47
|
+
/**
|
|
48
|
+
* The circle of the step: the check of the completed one, the number of the others
|
|
49
|
+
*/
|
|
50
|
+
const Icon = styled_1.default.span `
|
|
51
|
+
position: relative;
|
|
52
|
+
z-index: 1;
|
|
53
|
+
display: inline-flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
box-sizing: border-box;
|
|
58
|
+
width: 1.6em;
|
|
59
|
+
height: 1.6em;
|
|
60
|
+
border-radius: 50%;
|
|
61
|
+
font-size: 1em;
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
${({ theme, $state, $color, $contrastColor, $status }) => {
|
|
64
|
+
// the attention (warning, error) colors the step that is not completed
|
|
65
|
+
const main = $status ? theme.color[$status] : $color;
|
|
66
|
+
switch ($state) {
|
|
67
|
+
// done: the pale plate of the color and the check of the color
|
|
68
|
+
case 'completed':
|
|
69
|
+
return (0, react_2.css) `
|
|
70
|
+
background-color: ${$color.alpha(0.15).toString()};
|
|
71
|
+
color: ${$color.toString()};
|
|
72
|
+
`;
|
|
73
|
+
// now: the contrast plate of the color, the border and the number of the color
|
|
74
|
+
case 'active':
|
|
75
|
+
return (0, react_2.css) `
|
|
76
|
+
border: 2px solid ${main.toString()};
|
|
77
|
+
background-color: ${($status ? theme.color.surface : $contrastColor).toString()};
|
|
78
|
+
color: ${main.toString()};
|
|
79
|
+
`;
|
|
80
|
+
// ahead: pale grey
|
|
81
|
+
default:
|
|
82
|
+
return $status
|
|
83
|
+
? (0, react_2.css) `
|
|
84
|
+
border: 1.5px solid ${main.toString()};
|
|
85
|
+
background-color: ${theme.color.surface.toString()};
|
|
86
|
+
color: ${main.darken(20).toString()};
|
|
87
|
+
`
|
|
88
|
+
: (0, react_2.css) `
|
|
89
|
+
background-color: ${theme.color.textPrimary.alpha(0.06).toString()};
|
|
90
|
+
color: ${theme.color.textSecondary.alpha(0.7).toString()};
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
}}
|
|
94
|
+
& > span {
|
|
95
|
+
font-size: 0.75em;
|
|
96
|
+
}
|
|
97
|
+
& > svg {
|
|
98
|
+
width: 0.85em;
|
|
99
|
+
height: 0.85em;
|
|
100
|
+
}
|
|
101
|
+
`;
|
|
102
|
+
const Label = styled_1.default.span `
|
|
103
|
+
display: flex;
|
|
104
|
+
flex-direction: column;
|
|
105
|
+
padding-top: 0.15em;
|
|
106
|
+
line-height: 1.3;
|
|
107
|
+
font-size: 0.929em;
|
|
108
|
+
font-weight: ${({ $state }) => ($state === 'active' ? 600 : 400)};
|
|
109
|
+
color: ${({ theme, $state }) => ($state === 'pending' ? theme.color.textSecondary : theme.color.textPrimary).toString()};
|
|
110
|
+
`;
|
|
111
|
+
const Caption = styled_1.default.span `
|
|
112
|
+
font-size: 0.857em;
|
|
113
|
+
font-weight: 400;
|
|
114
|
+
color: ${({ theme }) => theme.color.textSecondary.toString()};
|
|
115
|
+
`;
|
|
116
|
+
/**
|
|
117
|
+
* The line to the next step: accented after the completed step
|
|
118
|
+
*/
|
|
119
|
+
const Connector = styled_1.default.span `
|
|
120
|
+
background-color: ${({ theme, $done, $color }) => ($done ? $color : theme.color.textPrimary.alpha(0.15)).toString()};
|
|
121
|
+
${({ $orientation, $alternativeLabel }) => $orientation === 'vertical'
|
|
122
|
+
? (0, react_2.css) `
|
|
123
|
+
width: 1.5px;
|
|
124
|
+
min-height: 0.75em;
|
|
125
|
+
margin: 0.25em 0 0.25em calc(0.8em - 0.75px);
|
|
126
|
+
flex: 1 1 auto;
|
|
127
|
+
`
|
|
128
|
+
: $alternativeLabel
|
|
129
|
+
? (0, react_2.css) `
|
|
130
|
+
position: absolute;
|
|
131
|
+
top: calc(0.8em - 0.75px);
|
|
132
|
+
left: calc(50% + 1.1em);
|
|
133
|
+
right: calc(-50% + 1.1em);
|
|
134
|
+
height: 1.5px;
|
|
135
|
+
`
|
|
136
|
+
: (0, react_2.css) `
|
|
137
|
+
flex: 1 1 auto;
|
|
138
|
+
min-width: 1em;
|
|
139
|
+
height: 1.5px;
|
|
140
|
+
margin: 0 0.5em;
|
|
141
|
+
`}
|
|
142
|
+
`;
|
|
143
|
+
const Check = () => (react_1.default.createElement("svg", { viewBox: "0 0 24 24", "aria-hidden": true },
|
|
144
|
+
react_1.default.createElement("path", { d: "M5 12.5l4.5 4.5L19 7.5", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" })));
|
|
145
|
+
/**
|
|
146
|
+
* One step of the `<Stepper>`
|
|
147
|
+
*/
|
|
148
|
+
const Step = (props, ref) => {
|
|
149
|
+
const { children, caption, completed, status, icon } = props, nativeProps = __rest(props, ["children", "caption", "completed", "status", "icon"]);
|
|
150
|
+
const stepper = react_1.default.useContext(context_1.StepperContext);
|
|
151
|
+
const { index, last } = react_1.default.useContext(context_1.StepIndexContext);
|
|
152
|
+
if (!stepper) {
|
|
153
|
+
throw new Error('<Step> should be placed inside <Stepper>');
|
|
154
|
+
}
|
|
155
|
+
const { activeStep, orientation, alternativeLabel, color, contrastColor } = stepper;
|
|
156
|
+
const state = completed || (typeof completed === 'undefined' && index < activeStep)
|
|
157
|
+
? 'completed'
|
|
158
|
+
: index === activeStep
|
|
159
|
+
? 'active'
|
|
160
|
+
: 'pending';
|
|
161
|
+
return (react_1.default.createElement(Container, Object.assign({ role: "listitem", "aria-current": state === 'active' ? 'step' : undefined }, nativeProps, { "$orientation": orientation, "$alternativeLabel": alternativeLabel, "$last": last, ref: ref }),
|
|
162
|
+
react_1.default.createElement(Head, { "$alternativeLabel": alternativeLabel },
|
|
163
|
+
react_1.default.createElement(Icon, { "$state": state, "$color": color, "$contrastColor": contrastColor, "$status": status !== null && status !== void 0 ? status : null }, state === 'completed' ? react_1.default.createElement(Check, null) : (icon !== null && icon !== void 0 ? icon : react_1.default.createElement("span", null, index + 1))),
|
|
164
|
+
react_1.default.createElement(Label, { "$state": state },
|
|
165
|
+
children,
|
|
166
|
+
caption && react_1.default.createElement(Caption, null, caption))),
|
|
167
|
+
!last && (react_1.default.createElement(Connector, { "$orientation": orientation, "$alternativeLabel": alternativeLabel, "$done": state === 'completed', "$color": color }))));
|
|
168
|
+
};
|
|
169
|
+
exports.default = react_1.default.forwardRef(Step);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StepperOrientation } from './context';
|
|
3
|
+
export type StepperProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
4
|
+
/**
|
|
5
|
+
* The current step from 0: the steps before it are completed. `-1` — nothing is started,
|
|
6
|
+
* the number of the steps — everything is completed
|
|
7
|
+
* Default: `0`
|
|
8
|
+
*/
|
|
9
|
+
readonly activeStep?: number;
|
|
10
|
+
/**
|
|
11
|
+
* `horizontal` — the steps in a row, `vertical` — in a column
|
|
12
|
+
* Default: `horizontal`
|
|
13
|
+
*/
|
|
14
|
+
readonly orientation?: StepperOrientation;
|
|
15
|
+
/**
|
|
16
|
+
* The labels under the icons (the horizontal stepper only): the steps share the width equally
|
|
17
|
+
* Default: false
|
|
18
|
+
*/
|
|
19
|
+
readonly alternativeLabel?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The color of the completed and the current steps: the primary, secondary name or any CSS color
|
|
22
|
+
* Default: `primary`
|
|
23
|
+
*/
|
|
24
|
+
readonly color?: 'primary' | 'secondary' | string;
|
|
25
|
+
};
|
|
26
|
+
declare const _default: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
27
|
+
/**
|
|
28
|
+
* The current step from 0: the steps before it are completed. `-1` — nothing is started,
|
|
29
|
+
* the number of the steps — everything is completed
|
|
30
|
+
* Default: `0`
|
|
31
|
+
*/
|
|
32
|
+
readonly activeStep?: number;
|
|
33
|
+
/**
|
|
34
|
+
* `horizontal` — the steps in a row, `vertical` — in a column
|
|
35
|
+
* Default: `horizontal`
|
|
36
|
+
*/
|
|
37
|
+
readonly orientation?: StepperOrientation;
|
|
38
|
+
/**
|
|
39
|
+
* The labels under the icons (the horizontal stepper only): the steps share the width equally
|
|
40
|
+
* Default: false
|
|
41
|
+
*/
|
|
42
|
+
readonly alternativeLabel?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* The color of the completed and the current steps: the primary, secondary name or any CSS color
|
|
45
|
+
* Default: `primary`
|
|
46
|
+
*/
|
|
47
|
+
readonly color?: "primary" | "secondary" | string;
|
|
48
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
49
|
+
export default _default;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
const react_1 = __importDefault(require("react"));
|
|
18
|
+
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
19
|
+
const react_2 = require("@emotion/react");
|
|
20
|
+
const Color_1 = __importDefault(require("../Color"));
|
|
21
|
+
const context_1 = require("./context");
|
|
22
|
+
const StyledStepper = styled_1.default.div `
|
|
23
|
+
display: flex;
|
|
24
|
+
${({ $orientation, $alternativeLabel }) => $orientation === 'vertical'
|
|
25
|
+
? (0, react_2.css) `
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
`
|
|
28
|
+
: (0, react_2.css) `
|
|
29
|
+
flex-direction: row;
|
|
30
|
+
align-items: ${$alternativeLabel ? 'flex-start' : 'center'};
|
|
31
|
+
`}
|
|
32
|
+
`;
|
|
33
|
+
/**
|
|
34
|
+
* The steps of a process: done, the current one, ahead. Children — the `<Step>` elements
|
|
35
|
+
*/
|
|
36
|
+
const Stepper = (props, ref) => {
|
|
37
|
+
const { activeStep = 0, orientation = 'horizontal', alternativeLabel = false, color = 'primary', children } = props, nativeProps = __rest(props, ["activeStep", "orientation", "alternativeLabel", "color", "children"]);
|
|
38
|
+
const theme = (0, react_2.useTheme)();
|
|
39
|
+
const [resolvedColor, contrastColor] = react_1.default.useMemo(() => {
|
|
40
|
+
if (color === 'primary') {
|
|
41
|
+
return [theme.color.accentPrimary, theme.color.accentPrimaryContrast];
|
|
42
|
+
}
|
|
43
|
+
if (color === 'secondary') {
|
|
44
|
+
return [theme.color.accentSecondary, theme.color.accentSecondaryContrast];
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const own = Color_1.default.fromString(color);
|
|
48
|
+
return [own, own.getContrastColor()];
|
|
49
|
+
}
|
|
50
|
+
catch (_a) {
|
|
51
|
+
return [theme.color.accentPrimary, theme.color.accentPrimaryContrast];
|
|
52
|
+
}
|
|
53
|
+
}, [
|
|
54
|
+
color,
|
|
55
|
+
theme.color.accentPrimary,
|
|
56
|
+
theme.color.accentPrimaryContrast,
|
|
57
|
+
theme.color.accentSecondary,
|
|
58
|
+
theme.color.accentSecondaryContrast,
|
|
59
|
+
]);
|
|
60
|
+
const context = react_1.default.useMemo(() => ({
|
|
61
|
+
activeStep,
|
|
62
|
+
orientation,
|
|
63
|
+
alternativeLabel: orientation === 'horizontal' && alternativeLabel,
|
|
64
|
+
color: resolvedColor,
|
|
65
|
+
contrastColor,
|
|
66
|
+
}), [activeStep, orientation, alternativeLabel, resolvedColor, contrastColor]);
|
|
67
|
+
const steps = react_1.default.Children.toArray(children).filter(react_1.default.isValidElement);
|
|
68
|
+
return (react_1.default.createElement(context_1.StepperContext.Provider, { value: context },
|
|
69
|
+
react_1.default.createElement(StyledStepper, Object.assign({ role: "list", "aria-orientation": orientation }, nativeProps, { "$orientation": orientation, "$alternativeLabel": context.alternativeLabel, ref: ref }), steps.map((step, index) => {
|
|
70
|
+
var _a;
|
|
71
|
+
return (react_1.default.createElement(context_1.StepIndexContext.Provider, { key: (_a = step.key) !== null && _a !== void 0 ? _a : index, value: { index, last: index === steps.length - 1 } }, step));
|
|
72
|
+
}))));
|
|
73
|
+
};
|
|
74
|
+
exports.default = react_1.default.forwardRef(Stepper);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Color from '../Color';
|
|
3
|
+
export type StepperOrientation = 'horizontal' | 'vertical';
|
|
4
|
+
export type StepperContextValue = {
|
|
5
|
+
readonly activeStep: number;
|
|
6
|
+
readonly orientation: StepperOrientation;
|
|
7
|
+
readonly alternativeLabel: boolean;
|
|
8
|
+
readonly color: Color;
|
|
9
|
+
/**
|
|
10
|
+
* The plate of the current step: the contrast color of the theme for the accent
|
|
11
|
+
*/
|
|
12
|
+
readonly contrastColor: Color;
|
|
13
|
+
};
|
|
14
|
+
export declare const StepperContext: React.Context<StepperContextValue | null>;
|
|
15
|
+
/**
|
|
16
|
+
* The place of the step in the stepper: set by the stepper for every child
|
|
17
|
+
*/
|
|
18
|
+
export declare const StepIndexContext: React.Context<{
|
|
19
|
+
readonly index: number;
|
|
20
|
+
readonly last: boolean;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StepIndexContext = exports.StepperContext = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
exports.StepperContext = react_1.default.createContext(null);
|
|
9
|
+
/**
|
|
10
|
+
* The place of the step in the stepper: set by the stepper for every child
|
|
11
|
+
*/
|
|
12
|
+
exports.StepIndexContext = react_1.default.createContext({ index: 0, last: true });
|
package/Stepper/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Step = void 0;
|
|
7
|
+
const Stepper_1 = __importDefault(require("./Stepper"));
|
|
8
|
+
var Step_1 = require("./Step");
|
|
9
|
+
Object.defineProperty(exports, "Step", { enumerable: true, get: function () { return __importDefault(Step_1).default; } });
|
|
10
|
+
exports.default = Stepper_1.default;
|
|
@@ -19,11 +19,12 @@ const styled_1 = __importDefault(require("@emotion/styled"));
|
|
|
19
19
|
const tokens_1 = require("../ThemeProvider/tokens");
|
|
20
20
|
const StyledHeader = styled_1.default.div `
|
|
21
21
|
padding: ${({ $noPadding, theme }) => {
|
|
22
|
-
const { y, x } = (0, tokens_1.themePadding)(theme, 'container'
|
|
22
|
+
const { y, x } = (0, tokens_1.themePadding)(theme, 'container');
|
|
23
23
|
return $noPadding ? '0' : `calc(${y} / 2) ${x} 0 ${x}`;
|
|
24
24
|
}};
|
|
25
|
-
|
|
26
|
-
font-
|
|
25
|
+
/* the size of the text, the secondary color and Light: quieter than the text, but not small */
|
|
26
|
+
font-size: 1em;
|
|
27
|
+
font-weight: 300;
|
|
27
28
|
color: ${({ theme }) => theme.color.textSecondary.toString()};
|
|
28
29
|
`;
|
|
29
30
|
const SurfaceSubheader = (props, ref) => {
|
package/Tabs/Tab.d.ts
CHANGED
|
@@ -4,11 +4,19 @@ export type TabProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'valu
|
|
|
4
4
|
* The value of the tab. The panel with the same value is shown when the tab is selected
|
|
5
5
|
*/
|
|
6
6
|
readonly value: string;
|
|
7
|
+
/**
|
|
8
|
+
* The counter after the label: the badge of the color of the tabs, grey for zero
|
|
9
|
+
*/
|
|
10
|
+
readonly counter?: number;
|
|
7
11
|
};
|
|
8
12
|
declare const _default: React.ForwardRefExoticComponent<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "value"> & {
|
|
9
13
|
/**
|
|
10
14
|
* The value of the tab. The panel with the same value is shown when the tab is selected
|
|
11
15
|
*/
|
|
12
16
|
readonly value: string;
|
|
17
|
+
/**
|
|
18
|
+
* The counter after the label: the badge of the color of the tabs, grey for zero
|
|
19
|
+
*/
|
|
20
|
+
readonly counter?: number;
|
|
13
21
|
} & React.RefAttributes<HTMLButtonElement>>;
|
|
14
22
|
export default _default;
|
package/Tabs/Tab.js
CHANGED
|
@@ -17,10 +17,70 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
const react_1 = __importDefault(require("react"));
|
|
18
18
|
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
19
19
|
const react_2 = require("@emotion/react");
|
|
20
|
+
const Badge_1 = __importDefault(require("../Badge"));
|
|
20
21
|
const context_1 = require("./context");
|
|
21
22
|
const tokens_1 = require("../ThemeProvider/tokens");
|
|
23
|
+
const underlineStyles = ({ theme, $color, $selected, $orientation, }) => $orientation === 'vertical'
|
|
24
|
+
? (0, react_2.css) `
|
|
25
|
+
/* The indicator of the selected tab on the right edge of the list */
|
|
26
|
+
&::after {
|
|
27
|
+
content: '';
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 0.3em;
|
|
30
|
+
bottom: 0.3em;
|
|
31
|
+
right: -1px;
|
|
32
|
+
width: 2px;
|
|
33
|
+
border-radius: 2px;
|
|
34
|
+
background-color: ${$color.toString()};
|
|
35
|
+
transform: scaleY(${$selected ? 1 : 0});
|
|
36
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
37
|
+
}
|
|
38
|
+
&:hover:not(:disabled) {
|
|
39
|
+
background-color: ${theme.color.textPrimary.alpha(0.05).toString()};
|
|
40
|
+
}
|
|
41
|
+
`
|
|
42
|
+
: (0, react_2.css) `
|
|
43
|
+
/* The hover is the rounded background over the line, the line is under the text only */
|
|
44
|
+
&::before {
|
|
45
|
+
content: '';
|
|
46
|
+
position: absolute;
|
|
47
|
+
inset: 0.2em 0 0.3em 0;
|
|
48
|
+
z-index: -1;
|
|
49
|
+
border-radius: inherit;
|
|
50
|
+
transition: background-color 150ms ease-out;
|
|
51
|
+
}
|
|
52
|
+
&:hover:not(:disabled)::before {
|
|
53
|
+
background-color: ${theme.color.textPrimary.alpha(0.05).toString()};
|
|
54
|
+
}
|
|
55
|
+
&::after {
|
|
56
|
+
content: '';
|
|
57
|
+
position: absolute;
|
|
58
|
+
left: var(--tab-x);
|
|
59
|
+
right: var(--tab-x);
|
|
60
|
+
bottom: 0;
|
|
61
|
+
height: 2px;
|
|
62
|
+
border-radius: 2px;
|
|
63
|
+
background-color: ${$color.toString()};
|
|
64
|
+
transform: scaleX(${$selected ? 1 : 0});
|
|
65
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
const segmentedStyles = ({ theme, $color, $selected }) => (0, react_2.css) `
|
|
69
|
+
&:hover:not(:disabled) {
|
|
70
|
+
background-color: ${$selected
|
|
71
|
+
? $color.alpha(0.2).toString()
|
|
72
|
+
: theme.color.textPrimary.alpha(0.05).toString()};
|
|
73
|
+
}
|
|
74
|
+
${$selected &&
|
|
75
|
+
(0, react_2.css) `
|
|
76
|
+
background-color: ${$color.alpha(0.14).toString()};
|
|
77
|
+
`}
|
|
78
|
+
`;
|
|
22
79
|
const StyledTab = styled_1.default.button `
|
|
80
|
+
--tab-x: ${({ $size }) => context_1.TAB_SIZES[$size].x};
|
|
23
81
|
position: relative;
|
|
82
|
+
/* The own stacking context: the hover background lies under the text, over the panel */
|
|
83
|
+
isolation: isolate;
|
|
24
84
|
display: inline-flex;
|
|
25
85
|
align-items: center;
|
|
26
86
|
justify-content: center;
|
|
@@ -28,18 +88,17 @@ const StyledTab = styled_1.default.button `
|
|
|
28
88
|
flex-shrink: 0;
|
|
29
89
|
box-sizing: border-box;
|
|
30
90
|
margin: 0;
|
|
31
|
-
padding: ${({
|
|
32
|
-
const { y, x } = (0, tokens_1.themePadding)(theme, 'item');
|
|
33
|
-
return `${y} ${x}`;
|
|
34
|
-
}};
|
|
91
|
+
padding: ${({ $size }) => `${context_1.TAB_SIZES[$size].y} var(--tab-x)`};
|
|
35
92
|
border: 0;
|
|
93
|
+
border-radius: ${({ theme }) => theme.shape.radiusFactor * 2}em;
|
|
36
94
|
background: none;
|
|
37
95
|
font: inherit;
|
|
38
|
-
font-size:
|
|
39
|
-
|
|
96
|
+
font-size: ${({ $size }) => context_1.TAB_SIZES[$size].fontSize};
|
|
97
|
+
/* light: the tabs are the navigation, not the headings */
|
|
98
|
+
font-weight: ${({ $selected }) => ($selected ? 500 : 400)};
|
|
40
99
|
white-space: nowrap;
|
|
41
100
|
cursor: pointer;
|
|
42
|
-
color: ${({ theme, $color, $selected }) => $selected ? $color.toString() : theme.color.textSecondary.toString()};
|
|
101
|
+
color: ${({ theme, $color, $selected }) => $selected ? $color.darken(20).toString() : theme.color.textSecondary.toString()};
|
|
43
102
|
transition:
|
|
44
103
|
color 150ms ease-out,
|
|
45
104
|
background-color 150ms ease-out;
|
|
@@ -54,7 +113,7 @@ const StyledTab = styled_1.default.button `
|
|
|
54
113
|
`}
|
|
55
114
|
|
|
56
115
|
&:hover:not(:disabled) {
|
|
57
|
-
|
|
116
|
+
color: ${({ theme, $color, $selected }) => $selected ? $color.darken(20).toString() : theme.color.textPrimary.toString()};
|
|
58
117
|
}
|
|
59
118
|
|
|
60
119
|
&:focus-visible {
|
|
@@ -67,31 +126,11 @@ const StyledTab = styled_1.default.button `
|
|
|
67
126
|
opacity: 0.45;
|
|
68
127
|
}
|
|
69
128
|
|
|
70
|
-
|
|
71
|
-
&::after {
|
|
72
|
-
content: '';
|
|
73
|
-
position: absolute;
|
|
74
|
-
background-color: ${({ $color }) => $color.toString()};
|
|
75
|
-
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
76
|
-
${({ $orientation, $selected }) => $orientation === 'vertical'
|
|
77
|
-
? (0, react_2.css) `
|
|
78
|
-
top: 0;
|
|
79
|
-
bottom: 0;
|
|
80
|
-
right: -1px;
|
|
81
|
-
width: 2px;
|
|
82
|
-
transform: scaleY(${$selected ? 1 : 0});
|
|
83
|
-
`
|
|
84
|
-
: (0, react_2.css) `
|
|
85
|
-
left: 0;
|
|
86
|
-
right: 0;
|
|
87
|
-
bottom: 0;
|
|
88
|
-
height: 2px;
|
|
89
|
-
transform: scaleX(${$selected ? 1 : 0});
|
|
90
|
-
`}
|
|
91
|
-
}
|
|
129
|
+
${props => (props.$variant === 'segmented' ? segmentedStyles(props) : underlineStyles(props))}
|
|
92
130
|
|
|
93
131
|
@media (prefers-reduced-motion: reduce) {
|
|
94
132
|
&,
|
|
133
|
+
&::before,
|
|
95
134
|
&::after {
|
|
96
135
|
transition: none;
|
|
97
136
|
}
|
|
@@ -99,7 +138,7 @@ const StyledTab = styled_1.default.button `
|
|
|
99
138
|
${({ theme }) => (0, tokens_1.themeFocusRing)(theme)}
|
|
100
139
|
`;
|
|
101
140
|
const Tab = (props, ref) => {
|
|
102
|
-
const { value, children, onClick, disabled } = props, nativeProps = __rest(props, ["value", "children", "onClick", "disabled"]);
|
|
141
|
+
const { value, counter, children, onClick, disabled } = props, nativeProps = __rest(props, ["value", "counter", "children", "onClick", "disabled"]);
|
|
103
142
|
const context = (0, context_1.useTabsContext)('Tab');
|
|
104
143
|
const isSelected = context.value === value;
|
|
105
144
|
const tabRef = react_1.default.useRef(null);
|
|
@@ -126,6 +165,10 @@ const Tab = (props, ref) => {
|
|
|
126
165
|
context.select(value, event);
|
|
127
166
|
}
|
|
128
167
|
};
|
|
129
|
-
return (react_1.default.createElement(StyledTab, Object.assign({ type: "button", role: "tab", id: context.getTabId(value), "aria-controls": context.getPanelId(value), "aria-selected": isSelected, tabIndex: isSelected ? 0 : -1, "data-tab-value": value }, nativeProps, { disabled: disabled, onClick: handleClick, "$color": context.color, "$selected": isSelected, "$orientation": context.orientation, "$fullWidth": context.fullWidth, ref: tabRef }),
|
|
168
|
+
return (react_1.default.createElement(StyledTab, Object.assign({ type: "button", role: "tab", id: context.getTabId(value), "aria-controls": context.getPanelId(value), "aria-selected": isSelected, tabIndex: isSelected ? 0 : -1, "data-tab-value": value }, nativeProps, { disabled: disabled, onClick: handleClick, "$color": context.color, "$selected": isSelected, "$orientation": context.orientation, "$variant": context.variant, "$size": context.size, "$fullWidth": context.fullWidth, ref: tabRef }),
|
|
169
|
+
children,
|
|
170
|
+
typeof counter === 'number' && (
|
|
171
|
+
// soft: the pale background of the color — the counter does not argue with the label
|
|
172
|
+
react_1.default.createElement(Badge_1.default, { variant: "soft", color: counter > 0 ? context.color.toString() : 'default' }, String(counter)))));
|
|
130
173
|
};
|
|
131
174
|
exports.default = react_1.default.forwardRef(Tab);
|
package/Tabs/TabList.js
CHANGED
|
@@ -21,27 +21,46 @@ const context_1 = require("./context");
|
|
|
21
21
|
const StyledList = styled_1.default.div `
|
|
22
22
|
display: flex;
|
|
23
23
|
box-sizing: border-box;
|
|
24
|
-
|
|
24
|
+
gap: 0.25em;
|
|
25
|
+
${({ $orientation }) => $orientation === 'vertical'
|
|
25
26
|
? (0, react_2.css) `
|
|
26
27
|
flex-direction: column;
|
|
27
28
|
flex-shrink: 0;
|
|
28
|
-
border-right: 1px solid ${theme.color.textPrimary.alpha(0.12).toString()};
|
|
29
29
|
`
|
|
30
30
|
: (0, react_2.css) `
|
|
31
31
|
flex-direction: row;
|
|
32
32
|
/* Many tabs on the narrow screen scroll instead of breaking the layout */
|
|
33
33
|
overflow-x: auto;
|
|
34
34
|
scrollbar-width: none;
|
|
35
|
-
border-bottom: 1px solid ${theme.color.textPrimary.alpha(0.12).toString()};
|
|
36
35
|
&::-webkit-scrollbar {
|
|
37
36
|
display: none;
|
|
38
37
|
}
|
|
39
38
|
`}
|
|
39
|
+
${({ theme, $orientation, $variant }) => $variant === 'segmented'
|
|
40
|
+
? (0, react_2.css) `
|
|
41
|
+
/* The tray: the tabs lie in the pale rounded plate */
|
|
42
|
+
${$orientation === 'horizontal' &&
|
|
43
|
+
(0, react_2.css) `
|
|
44
|
+
align-self: flex-start;
|
|
45
|
+
display: inline-flex;
|
|
46
|
+
max-width: 100%;
|
|
47
|
+
`}
|
|
48
|
+
padding: 0.25em;
|
|
49
|
+
border-radius: ${theme.shape.radiusFactor * 2.5}em;
|
|
50
|
+
background-color: ${theme.color.textPrimary.alpha(0.05).toString()};
|
|
51
|
+
`
|
|
52
|
+
: $orientation === 'vertical'
|
|
53
|
+
? (0, react_2.css) `
|
|
54
|
+
border-right: 1px solid ${theme.color.textPrimary.alpha(0.1).toString()};
|
|
55
|
+
`
|
|
56
|
+
: (0, react_2.css) `
|
|
57
|
+
border-bottom: 1px solid ${theme.color.textPrimary.alpha(0.1).toString()};
|
|
58
|
+
`}
|
|
40
59
|
`;
|
|
41
60
|
const getEnabledTabs = (list) => Array.from(list.querySelectorAll('[role="tab"]')).filter(tab => tab.closest('[role="tablist"]') === list && !tab.hasAttribute('disabled'));
|
|
42
61
|
const TabList = (props, ref) => {
|
|
43
62
|
const { children, onKeyDown } = props, nativeProps = __rest(props, ["children", "onKeyDown"]);
|
|
44
|
-
const { orientation, activation, value, isUncontrolledEmpty, selectInitial } = (0, context_1.useTabsContext)('TabList');
|
|
63
|
+
const { orientation, variant, activation, value, isUncontrolledEmpty, selectInitial } = (0, context_1.useTabsContext)('TabList');
|
|
45
64
|
const listRef = react_1.default.useRef(null);
|
|
46
65
|
react_1.default.useImperativeHandle(ref, () => listRef.current);
|
|
47
66
|
// The tab order needs one focusable tab. Normally it is the selected one,
|
|
@@ -99,6 +118,6 @@ const TabList = (props, ref) => {
|
|
|
99
118
|
target.click();
|
|
100
119
|
}
|
|
101
120
|
};
|
|
102
|
-
return (react_1.default.createElement(StyledList, Object.assign({ role: "tablist", "aria-orientation": orientation }, nativeProps, { onKeyDown: handleKeyDown, "$orientation": orientation, ref: listRef }), children));
|
|
121
|
+
return (react_1.default.createElement(StyledList, Object.assign({ role: "tablist", "aria-orientation": orientation }, nativeProps, { onKeyDown: handleKeyDown, "$orientation": orientation, "$variant": variant, ref: listRef }), children));
|
|
103
122
|
};
|
|
104
123
|
exports.default = react_1.default.forwardRef(TabList);
|
package/Tabs/Tabs.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { TabsOrientation } from './context';
|
|
2
|
+
import { TabsOrientation, TabsSize, TabsVariant } from './context';
|
|
3
3
|
export type TabsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'> & {
|
|
4
4
|
/**
|
|
5
5
|
* The selected tab of the controlled tabs. Pass it together with `onChange`
|
|
@@ -32,6 +32,18 @@ export type TabsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' |
|
|
|
32
32
|
* Default: false
|
|
33
33
|
*/
|
|
34
34
|
readonly fullWidth?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* `underline`: the line under the text of the selected tab — the tabs of the page, the list, the window.\
|
|
37
|
+
* `segmented`: the tabs in the pale tray, the selected one is the plate — the short switches
|
|
38
|
+
* («Day / Week / Month»)
|
|
39
|
+
* Default: `underline`
|
|
40
|
+
*/
|
|
41
|
+
readonly variant?: TabsVariant;
|
|
42
|
+
/**
|
|
43
|
+
* The height of the tab at the text of 14px: `s` — 32px, `m` — 40px, `l` — 48px
|
|
44
|
+
* Default: `m`
|
|
45
|
+
*/
|
|
46
|
+
readonly size?: TabsSize;
|
|
35
47
|
/**
|
|
36
48
|
* The color of the selected tab: the primary, default, secondary name of the colors or your specified color value
|
|
37
49
|
* Default: `default`
|
|
@@ -70,6 +82,18 @@ declare const _default: React.ForwardRefExoticComponent<Omit<React.HTMLAttribute
|
|
|
70
82
|
* Default: false
|
|
71
83
|
*/
|
|
72
84
|
readonly fullWidth?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* `underline`: the line under the text of the selected tab — the tabs of the page, the list, the window.\
|
|
87
|
+
* `segmented`: the tabs in the pale tray, the selected one is the plate — the short switches
|
|
88
|
+
* («Day / Week / Month»)
|
|
89
|
+
* Default: `underline`
|
|
90
|
+
*/
|
|
91
|
+
readonly variant?: TabsVariant;
|
|
92
|
+
/**
|
|
93
|
+
* The height of the tab at the text of 14px: `s` — 32px, `m` — 40px, `l` — 48px
|
|
94
|
+
* Default: `m`
|
|
95
|
+
*/
|
|
96
|
+
readonly size?: TabsSize;
|
|
73
97
|
/**
|
|
74
98
|
* The color of the selected tab: the primary, default, secondary name of the colors or your specified color value
|
|
75
99
|
* Default: `default`
|