@fibery/ui-kit 3.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/esfint.config.mjs +0 -17
- package/package.json +18 -13
- package/scripts/generate-icons.mjs +45 -44
- package/src/actions-menu/actions-menu-item.tsx +2 -1
- package/src/actions-menu/actions-menu.tsx +1 -3
- package/src/actions-menu/context-actions-menu.tsx +1 -1
- package/src/animated-height-container.tsx +1 -1
- package/src/antd/ant-modal.tsx +158 -9
- package/src/antd/ant-upload.tsx +285 -27
- package/src/antd/auto-complete.tsx +145 -0
- package/src/antd/auto-width-transparent-textarea.tsx +9 -2
- package/src/antd/global-overrides.ts +352 -0
- package/src/antd/index.tsx +3 -2
- package/src/antd/input-number.tsx +97 -11
- package/src/antd/input.tsx +127 -8
- package/src/antd/styles.ts +92 -32
- package/src/antd/tabs.tsx +139 -27
- package/src/app-icon-with-fallback.tsx +3 -7
- package/src/app-icon-wrapper.tsx +1 -13
- package/src/avatar.tsx +2 -56
- package/src/breadcrumb.tsx +5 -1
- package/src/color-adjuster.ts +24 -1
- package/src/color-utils.test.ts +2 -2
- package/src/color-utils.ts +2 -2
- package/src/copy-to-clipboard.ts +14 -3
- package/src/count-badge.tsx +10 -1
- package/src/date-picker/contexts.ts +6 -3
- package/src/date-picker/date-range-picker.tsx +7 -8
- package/src/date-picker/single-date-picker.tsx +3 -5
- package/src/date-picker/types.ts +1 -1
- package/src/date-picker/with-popup-control.tsx +3 -9
- package/src/day-select/iso-week-day-select.tsx +2 -2
- package/src/design-system/colors-callout.warm-dark.test.ts +22 -22
- package/src/design-system/colors-callout.warm-light.test.ts +19 -19
- package/src/design-system/colors-css.ts +1 -1
- package/src/design-system/colors-enum.dark.warm.test.ts +63 -63
- package/src/design-system/colors-enum.light.warm.test.ts +54 -54
- package/src/design-system/colors-highlight.warm-dark.test.ts +21 -21
- package/src/design-system/colors-highlight.warm-light.test.ts +21 -21
- package/src/design-system/colors.ts +4 -4
- package/src/design-system/fns.badge.dark.warm.test.ts +34 -34
- package/src/design-system/fns.badge.light.warm.test.ts +31 -31
- package/src/design-system/fns.deneutralize.test.ts +44 -0
- package/src/design-system/fns.icon.dark.warm.test.ts +21 -21
- package/src/design-system/fns.icon.light.warm.test.ts +17 -17
- package/src/design-system/fns.icon.ts +21 -13
- package/src/design-system/fns.ts +27 -3
- package/src/design-system/typography.ts +1 -1
- package/src/design-system.ts +1 -1
- package/src/emoji-picker/icon-emoji-picker.tsx +3 -3
- package/src/fibermoji-placeholder.tsx +2 -3
- package/src/icons/ast/index.tsx +446 -446
- package/src/icons/icon.tsx +23 -1
- package/src/icons/icons-integrity.test.ts +145 -0
- package/src/icons/react/index.tsx +446 -446
- package/src/icons/types.ts +1 -1
- package/src/images-gallery/images-gallery.tsx +2 -2
- package/src/images-gallery/slide-buttons.tsx +2 -4
- package/src/layout-styles.ts +5 -1
- package/src/link-input/components/ant-text-area-with-custom-read-state.tsx +2 -1
- package/src/lists/actions-menu-row-surface.tsx +1 -1
- package/src/media-query-utils.ts +5 -14
- package/src/mobile-keyboard-aware-popup.tsx +1 -1
- package/src/number-input/decimal.ts +6 -9
- package/src/number-input/number-input-inline-with-autosize.tsx +1 -1
- package/src/online-users.tsx +4 -5
- package/src/palettes/inspect.defs.colors.neutral-arch.test.ts +4 -4
- package/src/palettes/inspect.defs.colors.neutral-user.test.ts +4 -4
- package/src/palettes/inspect.defs.colors.warm-arch.test.ts +141 -141
- package/src/palettes/inspect.defs.colors.warm-user.test.ts +141 -141
- package/src/palettes/warm.ts +2 -0
- package/src/popover/index.tsx +4 -4
- package/src/popover/mobile-popover-context.tsx +1 -1
- package/src/popover/modifiers.tsx +1 -1
- package/src/rich-input-loader.tsx +1 -1
- package/src/root-theme-provider.test.tsx +1 -1
- package/src/select/components/menu-list-virtua.tsx +15 -16
- package/src/select/components/menu-list-virtualized.tsx +26 -29
- package/src/select/components/menu.tsx +3 -3
- package/src/select/index.tsx +4 -4
- package/src/select/reflection.ts +4 -5
- package/src/select/select-in-popover.tsx +34 -51
- package/src/select/select.tsx +5 -5
- package/src/select/styles.ts +1 -7
- package/src/select/util.ts +2 -2
- package/src/theme-provider.test.tsx +1 -1
- package/src/theme-provider.tsx +3 -9
- package/src/theme-snapshots.test.ts +9 -13
- package/src/{theming/build.ts → theming.build.ts} +6 -9
- package/src/{theming/theming-fibery.snapshot.css → theming.generated.css} +60 -60
- package/src/{theming/theming-fibery.snapshot.ts → theming.generated.ts} +60 -60
- package/src/type-badge.tsx +1 -2
- package/src/{themed-ink.tsx → type-label.tsx} +2 -5
- package/src/use-on-screen-keyboard-data.tsx +1 -1
- package/src/with-data.tsx +1 -1
- package/src/antd/auto-complete.d.ts +0 -2
- package/src/antd/auto-complete.ts +0 -37
- package/src/antd/tabs.d.ts +0 -5
- package/src/theming/index.ts +0 -20
- package/src/theming/theming-vzdbery.snapshot.css +0 -2001
- package/src/theming/theming-vzdbery.snapshot.ts +0 -2519
package/src/antd/styles.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {css} from "@linaria/core";
|
|
2
2
|
|
|
3
|
-
import {border, layout, shadows, space, textStyles, themeVars,
|
|
3
|
+
import {border, layout, shadows, space, textStyles, themeVars, transitions} from "../design-system";
|
|
4
4
|
|
|
5
5
|
const inputVariables = {
|
|
6
6
|
default: {
|
|
@@ -32,7 +32,7 @@ export const inputOverrides = {
|
|
|
32
32
|
paddingRight: space.s12,
|
|
33
33
|
border: 0,
|
|
34
34
|
borderColor: themeVars.transparent,
|
|
35
|
-
transition: `box-shadow ${
|
|
35
|
+
transition: `box-shadow ${transitions.faster}`,
|
|
36
36
|
boxShadow: `var(--input-border, ${themeVars.inputBorderColor})`,
|
|
37
37
|
letterSpacing: 0,
|
|
38
38
|
"&::placeholder": {
|
|
@@ -41,18 +41,18 @@ export const inputOverrides = {
|
|
|
41
41
|
},
|
|
42
42
|
hover: {
|
|
43
43
|
boxShadow: `var(--input-hover-border, 0 0 0 1px ${themeVars.colorAccentStrokeHover}) !important`,
|
|
44
|
-
transition: `box-shadow ${
|
|
44
|
+
transition: `box-shadow ${transitions.faster}`,
|
|
45
45
|
},
|
|
46
46
|
focus: {
|
|
47
47
|
boxShadow: `var(--input-focus-border, 0 0 0 1px ${themeVars.colorAccentStroke}), var(--input-focus-shadow) !important`,
|
|
48
|
-
transition: `box-shadow ${
|
|
48
|
+
transition: `box-shadow ${transitions.faster}`,
|
|
49
49
|
},
|
|
50
50
|
disabled: {
|
|
51
51
|
color: `${themeVars.textColor}`,
|
|
52
52
|
backgroundColor: `${themeVars.inputDisabledBgColor} !important`,
|
|
53
53
|
borderColor: themeVars.transparent,
|
|
54
54
|
boxShadow: `${themeVars.inputDisabledBorderColor} !important`,
|
|
55
|
-
transition: `box-shadow ${
|
|
55
|
+
transition: `box-shadow ${transitions.faster}`,
|
|
56
56
|
WebkitTextFillColor: "currentColor",
|
|
57
57
|
cursor: "default",
|
|
58
58
|
"&:hover": {
|
|
@@ -69,6 +69,58 @@ export const inputStyles = css`
|
|
|
69
69
|
}
|
|
70
70
|
${{
|
|
71
71
|
...textStyles.regular,
|
|
72
|
+
"& .ant-input, & .ant-input-affix-wrapper, & .ant-input-group-wrapper, & .ant-input-wrapper": {
|
|
73
|
+
boxSizing: "border-box",
|
|
74
|
+
},
|
|
75
|
+
"& .ant-input-affix-wrapper": {
|
|
76
|
+
display: "inline-flex",
|
|
77
|
+
alignItems: "center",
|
|
78
|
+
width: "100%",
|
|
79
|
+
position: "relative",
|
|
80
|
+
font: "inherit",
|
|
81
|
+
padding: 0,
|
|
82
|
+
border: "none",
|
|
83
|
+
boxShadow: "none",
|
|
84
|
+
backgroundColor: themeVars.transparent,
|
|
85
|
+
},
|
|
86
|
+
"& .ant-input-affix-wrapper > input.ant-input": {
|
|
87
|
+
minWidth: 0,
|
|
88
|
+
flex: 1,
|
|
89
|
+
padding: "0 12px",
|
|
90
|
+
border: "inherit",
|
|
91
|
+
outline: "inherit",
|
|
92
|
+
},
|
|
93
|
+
"& .ant-input-prefix, & .ant-input-suffix": {
|
|
94
|
+
display: "flex",
|
|
95
|
+
flex: "none",
|
|
96
|
+
alignItems: "center",
|
|
97
|
+
},
|
|
98
|
+
// antd source: spacing between adjacent icons when prefix/suffix holds multiple nodes.
|
|
99
|
+
"& .ant-input-prefix > *:not(:last-child), & .ant-input-suffix > *:not(:last-child)": {
|
|
100
|
+
marginRight: space.s8,
|
|
101
|
+
},
|
|
102
|
+
"& .ant-input-suffix": {
|
|
103
|
+
marginLeft: space.s6,
|
|
104
|
+
},
|
|
105
|
+
"& .ant-input-clear-icon": {
|
|
106
|
+
display: "inline-flex",
|
|
107
|
+
alignItems: "center",
|
|
108
|
+
color: themeVars.iconColor,
|
|
109
|
+
cursor: "pointer",
|
|
110
|
+
lineHeight: 1,
|
|
111
|
+
},
|
|
112
|
+
"& .ant-input-clear-icon-hidden": {
|
|
113
|
+
visibility: "hidden",
|
|
114
|
+
},
|
|
115
|
+
"& .ant-input-group-wrapper": {
|
|
116
|
+
display: "inline-block",
|
|
117
|
+
width: "100%",
|
|
118
|
+
},
|
|
119
|
+
"& .ant-input-wrapper.ant-input-group": {
|
|
120
|
+
display: "inline-flex",
|
|
121
|
+
width: "100%",
|
|
122
|
+
alignItems: "stretch",
|
|
123
|
+
},
|
|
72
124
|
"& .ant-input-group-addon": {
|
|
73
125
|
backgroundColor: themeVars.transparent,
|
|
74
126
|
border: "none",
|
|
@@ -79,23 +131,37 @@ export const inputStyles = css`
|
|
|
79
131
|
"&:focus": inputOverrides.focus,
|
|
80
132
|
},
|
|
81
133
|
"& .ant-input-group": {borderSpacing: 1, ...textStyles.regular},
|
|
82
|
-
"& .ant-input":
|
|
134
|
+
"& .ant-input": {
|
|
135
|
+
...inputOverrides.main,
|
|
136
|
+
// antd source: .ant-input { width: 100%; min-width: 0 } — without it, bare <AntInput>
|
|
137
|
+
// doesn't fill its container and can't shrink inside a flex parent. AutoComplete's
|
|
138
|
+
// .ant-select-selection-search .ant-input rule (two-class selector) beats this on
|
|
139
|
+
// specificity for combobox inputs, so the nested-AntAutoComplete case is unaffected.
|
|
140
|
+
width: "100%",
|
|
141
|
+
minWidth: 0,
|
|
142
|
+
},
|
|
143
|
+
// antd source: long placeholders get ellipsis instead of wrap-clip.
|
|
144
|
+
"& .ant-input:placeholder-shown": {
|
|
145
|
+
textOverflow: "ellipsis",
|
|
146
|
+
},
|
|
147
|
+
// bordered={false} → wrap with `ant-input-borderless` class; strip the box-shadow ring + bg.
|
|
148
|
+
// antd source covers base + hover/focus/disabled with the same declarations.
|
|
149
|
+
// !important needed to beat inputOverrides.main's !important on backgroundColor/boxShadow.
|
|
150
|
+
"& .ant-input.ant-input-borderless, & .ant-input.ant-input-borderless:hover, & .ant-input.ant-input-borderless:focus, & .ant-input.ant-input-borderless:disabled, & .ant-input.ant-input-borderless[disabled]":
|
|
151
|
+
{
|
|
152
|
+
boxShadow: "none !important",
|
|
153
|
+
backgroundColor: `${themeVars.transparent} !important`,
|
|
154
|
+
},
|
|
155
|
+
// antd source: inner input inside affix-wrapper must not paint its own focus ring —
|
|
156
|
+
// the wrapper owns the visual focus state. Without this prefix/suffix usage shows a
|
|
157
|
+
// double ring.
|
|
158
|
+
"& .ant-input-affix-wrapper > .ant-input:focus": {
|
|
159
|
+
boxShadow: "none !important",
|
|
160
|
+
},
|
|
83
161
|
"& .ant-input-status-error": inputVariables.error,
|
|
84
162
|
"& .ant-input[readonly].ant-input[readonly]": {...inputOverrides.disabled, cursor: "inherit"},
|
|
85
163
|
"& .ant-input:hover[readonly].ant-input:hover[readonly]": {...inputOverrides.disabled, cursor: "inherit"},
|
|
86
164
|
"& .ant-input-affix-wrapper:hover .ant-input[readonly]": {...inputOverrides.disabled, cursor: "inherit"},
|
|
87
|
-
"& .ant-input-affix-wrapper > input.ant-input": {
|
|
88
|
-
padding: "0 12px",
|
|
89
|
-
border: "inherit",
|
|
90
|
-
outline: "inherit",
|
|
91
|
-
},
|
|
92
|
-
"& .ant-input-affix-wrapper": {
|
|
93
|
-
font: "inherit",
|
|
94
|
-
padding: 0,
|
|
95
|
-
border: "none",
|
|
96
|
-
boxShadow: "none",
|
|
97
|
-
backgroundColor: themeVars.transparent,
|
|
98
|
-
},
|
|
99
165
|
"& .ant-input-affix-wrapper.ant-input-affix-wrapper-readonly": {
|
|
100
166
|
border: "none !important",
|
|
101
167
|
outline: "none !important",
|
|
@@ -104,32 +170,26 @@ export const inputStyles = css`
|
|
|
104
170
|
"& .ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled)": {
|
|
105
171
|
borderColor: "transparent",
|
|
106
172
|
},
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
...textStyles.regular,
|
|
111
|
-
"& .ant-select-selection--single": {height: layout.inputHeight},
|
|
112
|
-
"& .ant-input": inputOverrides.main,
|
|
113
|
-
"& .ant-input.ant-input:hover": inputOverrides.hover,
|
|
114
|
-
"& .ant-input.ant-input:focus": inputOverrides.focus,
|
|
115
|
-
"& .ant-input.ant-input-disabled": inputOverrides.disabled,
|
|
116
|
-
},
|
|
173
|
+
// antd source: textarea defaults — min-height anchors empty <AntTextArea> to a sane
|
|
174
|
+
// height, max-width prevents user-resize from blowing out the container, and
|
|
175
|
+
// vertical-align: bottom matches the baseline of a single-line <input> next to it.
|
|
117
176
|
"& textarea.ant-input": {
|
|
118
177
|
paddingTop: space.s8,
|
|
119
178
|
paddingBottom: space.s8,
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
179
|
+
minHeight: layout.inputHeight,
|
|
180
|
+
maxWidth: "100%",
|
|
181
|
+
verticalAlign: "bottom",
|
|
123
182
|
},
|
|
124
183
|
"&& input:hover:not(:focus):not(:disabled), && textarea:hover:not(:focus):not(:disabled), && .ant-input:hover:not(:focus):not(:disabled)":
|
|
125
184
|
inputOverrides.hover,
|
|
185
|
+
"&& .ant-input-affix-wrapper > input.ant-input:focus, && .ant-input-affix-wrapper > input.ant-input:active":
|
|
186
|
+
inputOverrides.focus,
|
|
126
187
|
"&& input:focus, && textarea:focus, && input:active, && textarea:active": inputOverrides.focus,
|
|
127
188
|
"&& .ant-input-disabled, && .ant-input-disabled:hover, && .ant-input-disabled:focus, && .ant-input-disabled:active":
|
|
128
189
|
inputOverrides.disabled,
|
|
129
190
|
"&& input::placeholder, && textarea::placeholder": {
|
|
130
191
|
color: themeVars.inputPlaceholderTextColor,
|
|
131
192
|
},
|
|
132
|
-
"& .ant-input-affix-wrapper .ant-input-prefix": {left: space.s6},
|
|
133
193
|
"& .ant-input-affix-wrapper .ant-input:not(:first-child)": {paddingLeft: space.s6 + space.s24 + space.s8}, // Match TitlePreview spacing
|
|
134
194
|
}}
|
|
135
195
|
`;
|
package/src/antd/tabs.tsx
CHANGED
|
@@ -1,32 +1,108 @@
|
|
|
1
|
-
import {css
|
|
2
|
-
import Tabs from "
|
|
1
|
+
import {css} from "@linaria/core";
|
|
2
|
+
import Tabs from "rc-tabs";
|
|
3
|
+
import type {ComponentProps} from "react";
|
|
3
4
|
import {forwardRef} from "react";
|
|
4
|
-
import "antd/lib/tabs/style/css";
|
|
5
5
|
|
|
6
|
-
import {textStyles, space, themeVars} from "../design-system";
|
|
6
|
+
import {textStyles, space, themeVars, transitions} from "../design-system";
|
|
7
|
+
import {getWrapper} from "./get-wrapper";
|
|
7
8
|
import {wrapWith} from "./utils";
|
|
8
9
|
|
|
10
|
+
type TabsPropsAny = ComponentProps<typeof Tabs>;
|
|
11
|
+
|
|
12
|
+
const PrefixedTabs = forwardRef<HTMLDivElement, TabsPropsAny>(function PrefixedTabs(props, ref) {
|
|
13
|
+
return <Tabs prefixCls="ant-tabs" {...props} ref={ref} />;
|
|
14
|
+
});
|
|
15
|
+
|
|
9
16
|
export const tabsStyles = css`
|
|
10
17
|
${{
|
|
11
18
|
width: "100%",
|
|
12
|
-
"& .ant-tabs
|
|
19
|
+
"& .ant-tabs": {
|
|
20
|
+
boxSizing: "border-box",
|
|
21
|
+
display: "flex",
|
|
22
|
+
overflow: "visible",
|
|
23
|
+
width: "100%",
|
|
24
|
+
},
|
|
25
|
+
"& .ant-tabs-top, & .ant-tabs-bottom": {
|
|
26
|
+
flexDirection: "column",
|
|
27
|
+
},
|
|
28
|
+
"& .ant-tabs-nav": {
|
|
29
|
+
display: "flex",
|
|
30
|
+
flex: "none",
|
|
31
|
+
alignItems: "center",
|
|
13
32
|
margin: 0,
|
|
33
|
+
width: "100%",
|
|
34
|
+
position: "relative",
|
|
35
|
+
"&::before": {
|
|
36
|
+
position: "absolute",
|
|
37
|
+
right: 0,
|
|
38
|
+
bottom: 0,
|
|
39
|
+
left: 0,
|
|
40
|
+
borderBottom: themeVars.borderSolidFilterGroup,
|
|
41
|
+
content: "''",
|
|
42
|
+
},
|
|
14
43
|
},
|
|
15
44
|
"& .ant-tabs-nav-wrap": {
|
|
45
|
+
display: "flex",
|
|
46
|
+
flex: "auto",
|
|
47
|
+
overflow: "hidden",
|
|
48
|
+
whiteSpace: "nowrap",
|
|
49
|
+
position: "relative",
|
|
50
|
+
alignSelf: "stretch",
|
|
51
|
+
transform: "translate(0)",
|
|
16
52
|
marginBottom: 1,
|
|
17
53
|
marginLeft: space.s12,
|
|
18
54
|
marginRight: space.s12,
|
|
19
55
|
},
|
|
20
|
-
"& .ant-tabs": {
|
|
21
|
-
|
|
56
|
+
"& .ant-tabs-nav-wrap::before, & .ant-tabs-nav-wrap::after": {
|
|
57
|
+
position: "absolute",
|
|
58
|
+
zIndex: 1,
|
|
59
|
+
opacity: 0,
|
|
60
|
+
transition: `opacity ${transitions.slow}`,
|
|
61
|
+
content: "''",
|
|
62
|
+
pointerEvents: "none",
|
|
63
|
+
},
|
|
64
|
+
"& .ant-tabs-nav-list": {
|
|
65
|
+
position: "relative",
|
|
66
|
+
display: "flex",
|
|
67
|
+
transition: `transform ${transitions.normal}`,
|
|
68
|
+
},
|
|
69
|
+
"& .ant-tabs-nav-operations": {
|
|
70
|
+
display: "flex",
|
|
71
|
+
alignSelf: "stretch",
|
|
72
|
+
},
|
|
73
|
+
"& .ant-tabs-nav-operations-hidden": {
|
|
74
|
+
position: "absolute",
|
|
75
|
+
visibility: "hidden",
|
|
76
|
+
pointerEvents: "none",
|
|
77
|
+
},
|
|
78
|
+
"& .ant-tabs-nav-more": {
|
|
79
|
+
position: "relative",
|
|
80
|
+
padding: `${space.s8}px ${space.s16}px`,
|
|
81
|
+
backgroundColor: themeVars.transparent,
|
|
82
|
+
border: 0,
|
|
83
|
+
},
|
|
84
|
+
"& .ant-tabs-nav-more::after": {
|
|
85
|
+
position: "absolute",
|
|
86
|
+
right: 0,
|
|
87
|
+
bottom: 0,
|
|
88
|
+
left: 0,
|
|
89
|
+
height: 5,
|
|
90
|
+
transform: "translateY(100%)",
|
|
91
|
+
content: "''",
|
|
92
|
+
},
|
|
93
|
+
"& .ant-tabs-extra-content": {
|
|
94
|
+
flex: "none",
|
|
95
|
+
},
|
|
96
|
+
"& .ant-tabs-centered .ant-tabs-nav-wrap:not([class*='ant-tabs-nav-wrap-ping'])": {
|
|
97
|
+
justifyContent: "center",
|
|
22
98
|
},
|
|
23
99
|
"& .ant-tabs-ink-bar": {
|
|
100
|
+
position: "absolute",
|
|
101
|
+
bottom: 0,
|
|
24
102
|
backgroundColor: themeVars.colorAccent,
|
|
25
103
|
height: 2,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
margin: 0,
|
|
29
|
-
width: "100%",
|
|
104
|
+
pointerEvents: "none",
|
|
105
|
+
transition: `left ${transitions.faster}, right ${transitions.faster}, width ${transitions.faster}`,
|
|
30
106
|
},
|
|
31
107
|
"& .ant-tabs-tab, & .ant-tabs-tab:hover, & .ant-tabs-tab-btn:active, & .ant-tabs-tabpane, & .ant-tabs-tab-active .ant-tabs-tab-btn":
|
|
32
108
|
{
|
|
@@ -34,29 +110,65 @@ export const tabsStyles = css`
|
|
|
34
110
|
textShadow: "none",
|
|
35
111
|
},
|
|
36
112
|
"& .ant-tabs-tab": {
|
|
113
|
+
position: "relative",
|
|
114
|
+
display: "inline-flex",
|
|
115
|
+
alignItems: "center",
|
|
37
116
|
padding: "12px 12px",
|
|
38
117
|
margin: `0 ${space.s8}px 0 0`,
|
|
118
|
+
cursor: "pointer",
|
|
119
|
+
outline: "none",
|
|
39
120
|
},
|
|
40
121
|
"& .ant-tabs-tab + .ant-tabs-tab": {
|
|
41
122
|
margin: `0 ${space.s8}px 0 0`,
|
|
42
123
|
},
|
|
43
|
-
".ant-tabs-
|
|
44
|
-
|
|
124
|
+
"& .ant-tabs-tab-btn": {
|
|
125
|
+
outline: "none",
|
|
126
|
+
transition: `all ${transitions.slow}`,
|
|
127
|
+
},
|
|
128
|
+
"& .ant-tabs-tab-active .ant-tabs-tab-btn": {
|
|
129
|
+
color: themeVars.colorAccent,
|
|
130
|
+
},
|
|
131
|
+
"& .ant-tabs-content-holder": {
|
|
132
|
+
flex: "auto",
|
|
133
|
+
minWidth: 0,
|
|
134
|
+
minHeight: 0,
|
|
135
|
+
},
|
|
136
|
+
"& .ant-tabs-content": {
|
|
137
|
+
position: "relative",
|
|
138
|
+
display: "flex",
|
|
139
|
+
width: "100%",
|
|
140
|
+
},
|
|
141
|
+
"& .ant-tabs-tabpane": {
|
|
142
|
+
flex: "none",
|
|
143
|
+
width: "100%",
|
|
144
|
+
outline: "none",
|
|
145
|
+
},
|
|
146
|
+
"& .ant-tabs-tabpane-hidden": {
|
|
147
|
+
display: "none",
|
|
148
|
+
},
|
|
149
|
+
"& .ant-tabs-switch-appear, & .ant-tabs-switch-enter": {
|
|
150
|
+
transition: "none",
|
|
151
|
+
},
|
|
152
|
+
"& .ant-tabs-switch-appear-start, & .ant-tabs-switch-enter-start": {
|
|
153
|
+
opacity: 0,
|
|
154
|
+
},
|
|
155
|
+
"& .ant-tabs-switch-appear-active, & .ant-tabs-switch-enter-active": {
|
|
156
|
+
opacity: 1,
|
|
157
|
+
transition: `opacity ${transitions.slow}`,
|
|
158
|
+
},
|
|
159
|
+
"& .ant-tabs-switch-leave": {
|
|
160
|
+
position: "absolute",
|
|
161
|
+
inset: 0,
|
|
162
|
+
transition: "none",
|
|
163
|
+
},
|
|
164
|
+
"& .ant-tabs-switch-leave-start": {
|
|
165
|
+
opacity: 1,
|
|
166
|
+
},
|
|
167
|
+
"& .ant-tabs-switch-leave-active": {
|
|
168
|
+
opacity: 0,
|
|
169
|
+
transition: `opacity ${transitions.slow}`,
|
|
45
170
|
},
|
|
46
171
|
}}
|
|
47
172
|
`;
|
|
48
173
|
|
|
49
|
-
|
|
50
|
-
return forwardRef<HTMLDivElement, {children: React.ReactNode; className?: string}>(function TabWrapper(
|
|
51
|
-
{children, className},
|
|
52
|
-
ref
|
|
53
|
-
) {
|
|
54
|
-
return (
|
|
55
|
-
<div className={cx(className, tabsStyles)} ref={ref}>
|
|
56
|
-
{children}
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export const AntTabs = wrapWith(getWrapper(), Tabs);
|
|
174
|
+
export const AntTabs = wrapWith(getWrapper(tabsStyles), PrefixedTabs);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import {css} from "@linaria/core";
|
|
2
|
-
import fromPairs from "lodash/fromPairs";
|
|
3
2
|
import type {FC} from "react";
|
|
4
3
|
import {lazy, Suspense} from "react";
|
|
5
4
|
|
|
6
5
|
import {AppIconWrapper} from "./app-icon-wrapper";
|
|
7
6
|
import {alpha, iconSize, layout} from "./design-system";
|
|
8
|
-
import {isFlagPresent} from "./flags";
|
|
9
7
|
import {Icon} from "./icons/icon";
|
|
10
8
|
import {useTheme} from "./theme-provider";
|
|
11
9
|
import {useIsPhone} from "./use-is-phone";
|
|
@@ -94,7 +92,7 @@ type UglyExternalIconProps = Omit<UglyExternalIconImplProps, "appIconsLookup">;
|
|
|
94
92
|
|
|
95
93
|
const UglyExternalIcon = lazy(async () => {
|
|
96
94
|
const appIcons = await import("./app-icons.json");
|
|
97
|
-
const appIconsLookup =
|
|
95
|
+
const appIconsLookup = Object.fromEntries(
|
|
98
96
|
appIcons.default.flatMap((appIcon) => appIcon.short_names.map((shortName) => [shortName, appIcon]))
|
|
99
97
|
);
|
|
100
98
|
|
|
@@ -146,12 +144,10 @@ export const AppIcon: FC<AppIconProps> = ({icon, color: neutralColor, isSelected
|
|
|
146
144
|
const isPhone = useIsPhone();
|
|
147
145
|
const defaultIconSize = isPhone ? layout.mobileSidebarIconSize : layout.newMenuIconSize;
|
|
148
146
|
const {iconSize = defaultIconSize, containerSize = defaultIconSize} = rest;
|
|
149
|
-
const {fg
|
|
150
|
-
|
|
151
|
-
const bgColor = !isFlagPresent("no-sidebar-app-icon-bg") ? alpha(fg, 0.2) : bg;
|
|
147
|
+
const {fg} = theme.fns.icon(neutralColor);
|
|
152
148
|
|
|
153
149
|
return (
|
|
154
|
-
<AppIconWrapper color={
|
|
150
|
+
<AppIconWrapper color={alpha(fg, 0.2)} borderless={isSelected} containerSize={containerSize}>
|
|
155
151
|
<AppIconWithFallback name={icon} color={fg} colorProcessed containerSize={containerSize} iconSize={iconSize} />
|
|
156
152
|
</AppIconWrapper>
|
|
157
153
|
);
|
package/src/app-icon-wrapper.tsx
CHANGED
|
@@ -3,20 +3,12 @@ import cn from "classnames";
|
|
|
3
3
|
import type {ReactNode} from "react";
|
|
4
4
|
|
|
5
5
|
import {border, layout} from "./design-system";
|
|
6
|
-
import {isFlagPresent} from "./flags";
|
|
7
|
-
import {useTheme} from "./theme-provider";
|
|
8
6
|
import {useIsPhone} from "./use-is-phone";
|
|
9
7
|
|
|
10
8
|
const appIconContainerStyle = css`
|
|
11
9
|
border-radius: ${border.radius4}px;
|
|
12
10
|
`;
|
|
13
11
|
|
|
14
|
-
const appIconGradientStyle = css`
|
|
15
|
-
${{
|
|
16
|
-
backgroundImage: "linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0))",
|
|
17
|
-
}}
|
|
18
|
-
`;
|
|
19
|
-
|
|
20
12
|
export const AppIconWrapper = ({
|
|
21
13
|
children,
|
|
22
14
|
color,
|
|
@@ -28,16 +20,12 @@ export const AppIconWrapper = ({
|
|
|
28
20
|
borderless?: boolean;
|
|
29
21
|
containerSize?: number;
|
|
30
22
|
}) => {
|
|
31
|
-
const theme = useTheme();
|
|
32
23
|
const isPhone = useIsPhone();
|
|
33
24
|
const {containerSize = isPhone ? layout.mobileSidebarIconSize : layout.newMenuIconSize} = rest;
|
|
34
25
|
return (
|
|
35
26
|
<div
|
|
36
27
|
style={{backgroundColor: borderless ? "transparent" : color, width: containerSize, height: containerSize}}
|
|
37
|
-
className={cn(
|
|
38
|
-
appIconContainerStyle,
|
|
39
|
-
!borderless && isFlagPresent("no-sidebar-app-icon-bg") && theme.mode === "dark" && appIconGradientStyle
|
|
40
|
-
)}
|
|
28
|
+
className={cn(appIconContainerStyle)}
|
|
41
29
|
>
|
|
42
30
|
{children}
|
|
43
31
|
</div>
|
package/src/avatar.tsx
CHANGED
|
@@ -3,12 +3,9 @@ import {css, cx} from "@linaria/core";
|
|
|
3
3
|
import type {CSSProperties, FC} from "react";
|
|
4
4
|
import {memo, useCallback, useMemo, useState} from "react";
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {useFeatures} from "./features";
|
|
9
|
-
import {FibermojiPlaceholder} from "./fibermoji-placeholder";
|
|
6
|
+
import {border, space, themeVars} from "./design-system";
|
|
7
|
+
import {FibermojiPlaceholder as AvatarPlaceholder} from "./fibermoji-placeholder";
|
|
10
8
|
import {getShiftStyle} from "./icons/get-shift-style";
|
|
11
|
-
import {useTheme} from "./theme-provider";
|
|
12
9
|
|
|
13
10
|
export const getContainerStyle = memoize((containerSize: number) => {
|
|
14
11
|
return {
|
|
@@ -167,57 +164,6 @@ const AvatarImage: FC<AvatarImageProps> = memo(function AvatarImage({
|
|
|
167
164
|
);
|
|
168
165
|
});
|
|
169
166
|
|
|
170
|
-
const avatarPlaceholderStaticClassName = css`
|
|
171
|
-
text-align: center;
|
|
172
|
-
text-transform: uppercase;
|
|
173
|
-
letter-spacing: -0.2px;
|
|
174
|
-
`;
|
|
175
|
-
|
|
176
|
-
const getAvatarPlaceholderStyle = ({
|
|
177
|
-
size,
|
|
178
|
-
backgroundColor,
|
|
179
|
-
radius,
|
|
180
|
-
}: {
|
|
181
|
-
size: number;
|
|
182
|
-
backgroundColor: string;
|
|
183
|
-
radius?: number;
|
|
184
|
-
}) => ({
|
|
185
|
-
backgroundColor: getDarkenColor(backgroundColor),
|
|
186
|
-
color: themeVars.whiteColor,
|
|
187
|
-
lineHeight: `${size}px`,
|
|
188
|
-
fontSize: size / 2.222222,
|
|
189
|
-
width: size,
|
|
190
|
-
height: size,
|
|
191
|
-
borderRadius: radius ?? "50%",
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
type AvatarPlaceholderProps = {
|
|
195
|
-
size: number;
|
|
196
|
-
title?: string;
|
|
197
|
-
radius?: number;
|
|
198
|
-
hasAccess?: boolean;
|
|
199
|
-
backgroundColor?: string;
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
const AvatarPlaceholder: FC<AvatarPlaceholderProps> = memo(function AvatarPlaceholder(props) {
|
|
203
|
-
const features = useFeatures<{enableFibermojiAvatars: boolean}>();
|
|
204
|
-
const theme = useTheme();
|
|
205
|
-
if (features.enableFibermojiAvatars) {
|
|
206
|
-
return <FibermojiPlaceholder {...props} />;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const {size, title, radius, backgroundColor = getObjectColorMemoized(title)} = props;
|
|
210
|
-
const displayBg = theme.fns.deneutralize(backgroundColor);
|
|
211
|
-
return (
|
|
212
|
-
<div
|
|
213
|
-
className={cx(textClasses.regular, avatarPlaceholderStaticClassName)}
|
|
214
|
-
style={getAvatarPlaceholderStyle({size, backgroundColor: displayBg, radius})}
|
|
215
|
-
>
|
|
216
|
-
{abbreviateName(title)}
|
|
217
|
-
</div>
|
|
218
|
-
);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
167
|
const getNullUserAvatarContainerStyle = ({containerSize}: {containerSize: number}) => ({
|
|
222
168
|
width: containerSize,
|
|
223
169
|
height: containerSize,
|
package/src/breadcrumb.tsx
CHANGED
|
@@ -64,10 +64,14 @@ const liReset = css`
|
|
|
64
64
|
padding: 0;
|
|
65
65
|
`;
|
|
66
66
|
|
|
67
|
+
const separatorIconCss = css`
|
|
68
|
+
--fibery-icon-size: var(--breadcrumb-separator-size, 16px);
|
|
69
|
+
`;
|
|
70
|
+
|
|
67
71
|
export const BreadcrumbSeparator = ({children, className, ...props}: React.ComponentProps<"li">) => {
|
|
68
72
|
return (
|
|
69
73
|
<li role="presentation" aria-hidden="true" className={cx(liReset, className)} {...props}>
|
|
70
|
-
{children ?? <ArrowRight color={breadcrumbColor}
|
|
74
|
+
{children ?? <ArrowRight color={breadcrumbColor} className={separatorIconCss} />}
|
|
71
75
|
</li>
|
|
72
76
|
);
|
|
73
77
|
};
|
package/src/color-adjuster.ts
CHANGED
|
@@ -7,6 +7,11 @@ export type AdjustSpec = {
|
|
|
7
7
|
achromaticTint?: {h: number; c: number};
|
|
8
8
|
strengths?: {common?: number; l?: number; c?: number; h?: number};
|
|
9
9
|
lFade?: {lo?: number; hi?: number};
|
|
10
|
+
// Linear strength ramp from `min` at c=0 to 1 at c=hi, then 1 above.
|
|
11
|
+
// Softens pastels (Notion imports, vizydrop "Fibery" preset) without touching saturated swatches.
|
|
12
|
+
cFade?: {hi: number; min: number};
|
|
13
|
+
// Inputs with c ≤ greyC skip cFade so designer cool-greys keep full warmth.
|
|
14
|
+
greyC?: number;
|
|
10
15
|
};
|
|
11
16
|
|
|
12
17
|
const lerp = (a: number, b: number, t: number) => a + (b - a) * t;
|
|
@@ -60,6 +65,21 @@ function makeStrengthFromL(lo: number, hi: number) {
|
|
|
60
65
|
};
|
|
61
66
|
}
|
|
62
67
|
|
|
68
|
+
function makeStrengthFromC(spec: AdjustSpec["cFade"]) {
|
|
69
|
+
if (!spec || spec.min >= 1 || spec.hi <= 0) {
|
|
70
|
+
return function strengthFromC(_c: number) {
|
|
71
|
+
return 1;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const {hi, min} = spec;
|
|
75
|
+
return function strengthFromC(c: number) {
|
|
76
|
+
if (c >= hi) {
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
return lerp(min, 1, c / hi);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
63
83
|
export function makeAdjust(adjuster: AdjustSpec) {
|
|
64
84
|
const derive = makeDerive(adjuster);
|
|
65
85
|
const sCommon = adjuster.strengths?.common ?? 1;
|
|
@@ -70,14 +90,17 @@ export function makeAdjust(adjuster: AdjustSpec) {
|
|
|
70
90
|
adjuster.lFade?.lo ?? WARM_L_LO_DEFAULT,
|
|
71
91
|
adjuster.lFade?.hi ?? WARM_L_HI_DEFAULT
|
|
72
92
|
);
|
|
93
|
+
const strengthFromC = makeStrengthFromC(adjuster.cFade);
|
|
94
|
+
const greyC = adjuster.greyC ?? 0;
|
|
73
95
|
return function adjust(color: Oklch): Oklch {
|
|
74
96
|
const hue = color.h ?? 0;
|
|
97
|
+
const isGrey = color.h === null || color.c <= greyC;
|
|
75
98
|
|
|
76
99
|
const mulL = 1 + (derive(hue, (p) => p.mul.l) - 1) * sL;
|
|
77
100
|
const powC = 1 + (derive(hue, (p) => p.pow.c) - 1) * sC;
|
|
78
101
|
const addH = derive(hue, (p) => p.add.h) * sH;
|
|
79
102
|
|
|
80
|
-
const strength = strengthFromL(color.l);
|
|
103
|
+
const strength = strengthFromL(color.l) * (isGrey ? 1 : strengthFromC(color.c));
|
|
81
104
|
|
|
82
105
|
const l = Math.min(lerp(color.l, color.l * mulL, strength), 0.999);
|
|
83
106
|
let c: number;
|
package/src/color-utils.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// oxlint-disable typescript/consistent-type-imports
|
|
2
|
-
import {cssFromUnsafe, getColorDistance, getLuminance, isValidColor} from "./color-utils";
|
|
2
|
+
import {cssFromUnsafe, getColorDistance, getLuminance, isValidColor, invalidColorFallback} from "./color-utils";
|
|
3
3
|
|
|
4
4
|
describe("color-utils", () => {
|
|
5
5
|
describe("cssFromUnsafe", () => {
|
|
@@ -21,7 +21,7 @@ describe("color-utils", () => {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it("returns fallback for invalid color", () => {
|
|
24
|
-
expect(cssFromUnsafe("invalid")).
|
|
24
|
+
expect(cssFromUnsafe("invalid")).toEqual(invalidColorFallback);
|
|
25
25
|
});
|
|
26
26
|
});
|
|
27
27
|
|
package/src/color-utils.ts
CHANGED
|
@@ -27,8 +27,8 @@ export const oklchFrom = converter("oklch");
|
|
|
27
27
|
const mapToSrgb = toGamut("rgb", "oklch");
|
|
28
28
|
|
|
29
29
|
export const isValidColor = (color: string) => parse(color) !== undefined;
|
|
30
|
-
|
|
31
|
-
export function colorFromUnsafe(color: string, fallback =
|
|
30
|
+
export const invalidColorFallback = "rgb(94, 94, 94)";
|
|
31
|
+
export function colorFromUnsafe(color: string, fallback = invalidColorFallback): Color {
|
|
32
32
|
const parsed = parse(resolveColorArg(color, "colorFromUnsafe") ?? "") ?? parse(fallback)!;
|
|
33
33
|
if (!parsed) {
|
|
34
34
|
throw new Error(`Failed to parse fallback color ${fallback}`);
|
package/src/copy-to-clipboard.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
function checkClipboard() {
|
|
2
|
+
if (!navigator.clipboard) {
|
|
3
|
+
throw new Error("Clipboard disabled by browser permissions policy");
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const copyToClipboard = async (text: string) => {
|
|
8
|
+
checkClipboard();
|
|
9
|
+
await navigator.clipboard.writeText(text);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const copyUrlToClipboard = async ({url, label}: {url: string; label?: string}) => {
|
|
13
|
+
checkClipboard();
|
|
3
14
|
const htmlString = `<a href="${url}" target="_blank">${label || url}</a>`;
|
|
4
15
|
|
|
5
|
-
|
|
16
|
+
await navigator.clipboard.write([
|
|
6
17
|
new ClipboardItem({
|
|
7
18
|
"text/html": new Blob([htmlString], {type: "text/html"}),
|
|
8
19
|
"text/plain": url,
|
package/src/count-badge.tsx
CHANGED
|
@@ -34,8 +34,17 @@ const warningStyle = css`
|
|
|
34
34
|
color: ${themeVars.textColor};
|
|
35
35
|
`;
|
|
36
36
|
|
|
37
|
+
const countBadgeLimitOverride = Number.parseInt(
|
|
38
|
+
new URLSearchParams(window.location.search).get("count-badge-limit") ?? ""
|
|
39
|
+
);
|
|
40
|
+
const COUNT_BADGE_LIMIT = Number.isInteger(countBadgeLimitOverride) ? countBadgeLimitOverride : 99;
|
|
41
|
+
|
|
37
42
|
export function CountBadge({className, count}: Props) {
|
|
38
|
-
return
|
|
43
|
+
return (
|
|
44
|
+
<span className={cx(countStyle, countBadgeStyle, className)}>
|
|
45
|
+
{count <= COUNT_BADGE_LIMIT ? count : `${COUNT_BADGE_LIMIT}+`}
|
|
46
|
+
</span>
|
|
47
|
+
);
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
export function CountBadgeWithNoLimits({count, warning}: {count: number | string; warning?: boolean}) {
|