@fibery/ui-kit 4.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 +12 -0
- package/esfint.config.mjs +0 -17
- package/package.json +5 -6
- package/scripts/generate-icons.mjs +45 -44
- package/src/actions-menu/actions-menu-item.tsx +1 -1
- package/src/actions-menu/context-actions-menu.tsx +1 -1
- package/src/animated-height-container.tsx +1 -1
- package/src/antd/ant-modal.tsx +21 -21
- package/src/antd/styles.ts +2 -0
- package/src/app-icon-with-fallback.tsx +3 -7
- package/src/app-icon-wrapper.tsx +1 -13
- package/src/breadcrumb.tsx +5 -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/date-picker/contexts.ts +6 -3
- package/src/date-picker/date-range-picker.tsx +1 -2
- package/src/date-picker/single-date-picker.tsx +1 -2
- package/src/day-select/iso-week-day-select.tsx +2 -2
- package/src/design-system/colors.ts +3 -3
- package/src/emoji-picker/icon-emoji-picker.tsx +3 -3
- package/src/icons/ast/index.tsx +446 -446
- package/src/icons/icon.tsx +14 -2
- package/src/icons/icons-integrity.test.ts +145 -0
- package/src/icons/react/index.tsx +446 -446
- package/src/images-gallery/images-gallery.tsx +2 -2
- package/src/images-gallery/slide-buttons.tsx +2 -4
- package/src/lists/actions-menu-row-surface.tsx +1 -1
- package/src/media-query-utils.ts +1 -1
- 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 +4 -4
- package/src/palettes/inspect.defs.colors.warm-user.test.ts +4 -4
- 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/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 +1 -1
- package/src/select/reflection.ts +4 -5
- package/src/select/select.tsx +3 -3
- package/src/select/styles.ts +1 -7
- package/src/select/util.ts +2 -2
- package/src/theming.generated.css +8 -8
- package/src/theming.generated.ts +8 -8
- package/src/type-badge.tsx +1 -2
- package/src/use-on-screen-keyboard-data.tsx +1 -1
- package/src/with-data.tsx +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @fibery/ui-kit
|
|
2
2
|
|
|
3
|
+
## 4.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- fb2ba1d: Add `isRecord`, `noop`, `identity`, `truthy` to `_.ts` in `@fibery/helpers`; drop `lodash` from `@fibery/ui-kit` dependencies.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [fb2ba1d]
|
|
12
|
+
- @fibery/helpers@3.1.0
|
|
13
|
+
- @fibery/react@1.5.4
|
|
14
|
+
|
|
3
15
|
## 4.0.0
|
|
4
16
|
|
|
5
17
|
### Major Changes
|
package/esfint.config.mjs
CHANGED
|
@@ -13,21 +13,4 @@ export default [
|
|
|
13
13
|
"unicorn/filename-case": "off",
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
|
-
{
|
|
17
|
-
files: ["src/design-system/**/*"],
|
|
18
|
-
rules: {
|
|
19
|
-
"no-restricted-imports": [
|
|
20
|
-
"error",
|
|
21
|
-
{
|
|
22
|
-
patterns: [
|
|
23
|
-
{group: ["@fibery/ui-kit/*"]},
|
|
24
|
-
{
|
|
25
|
-
group: ["lodash", "lodash/*", "lodash-es", "lodash-es/*"],
|
|
26
|
-
message: "lodash is not allowed in design-system",
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
16
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/ui-kit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"dependencies": {
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"d3-shape": "1.3.7",
|
|
34
34
|
"date-fns": "2.29.2",
|
|
35
35
|
"invariant": "2.2.4",
|
|
36
|
-
"lodash": "4.17.21",
|
|
37
36
|
"lru-cache": "11.2.2",
|
|
38
37
|
"md5": "2.2.1",
|
|
39
38
|
"moment": "2.29.4",
|
|
39
|
+
"node-types-local": "npm:@types/node@^24",
|
|
40
40
|
"photoswipe": "5.4.4",
|
|
41
41
|
"popper-max-size-modifier": "0.2.0",
|
|
42
42
|
"prop-types": "15.7.2",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tabbable": "5.2.1",
|
|
61
61
|
"virtua": "0.48.8",
|
|
62
62
|
"@fibery/emoji-data": "2.7.3",
|
|
63
|
-
"@fibery/helpers": "3.
|
|
64
|
-
"@fibery/react": "1.5.
|
|
63
|
+
"@fibery/helpers": "3.1.0",
|
|
64
|
+
"@fibery/react": "1.5.4"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@babel/core": "7.28.5",
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
"@types/culori": "4.0.1",
|
|
75
75
|
"@types/history": "4.7.11",
|
|
76
76
|
"@types/invariant": "2.2.34",
|
|
77
|
-
"@types/lodash": "4.14.172",
|
|
78
77
|
"@types/prop-types": "15.7.5",
|
|
79
78
|
"@types/react": "18.3.12",
|
|
80
79
|
"@types/react-color": "2.13.5",
|
|
@@ -82,7 +81,7 @@
|
|
|
82
81
|
"@typescript/native-preview": "beta",
|
|
83
82
|
"csstype": "3.0.8",
|
|
84
83
|
"fs-extra": "10.0.0",
|
|
85
|
-
"glob": "
|
|
84
|
+
"glob": "13.0.6",
|
|
86
85
|
"react": "18.3.1",
|
|
87
86
|
"react-dom": "18.3.1",
|
|
88
87
|
"svg-parser": "2.0.4",
|
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import {readFile} from "fs/promises";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import {fileURLToPath} from "url";
|
|
4
|
-
import {promisify} from "util";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {fileURLToPath} from "node:url";
|
|
5
4
|
|
|
6
5
|
import fs from "fs-extra";
|
|
7
|
-
import glob from "glob";
|
|
8
|
-
import _ from "lodash";
|
|
6
|
+
import {glob} from "glob";
|
|
9
7
|
import {parse} from "svg-parser";
|
|
10
8
|
import svgo from "svgo";
|
|
11
9
|
import {recursiveReduce} from "unist-util-reduce";
|
|
12
10
|
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
|
|
14
|
+
const WORD_RE = /[A-Z]+(?![a-z])|[A-Z]?[a-z]+|\d+/g;
|
|
15
|
+
const words = (s) => String(s).match(WORD_RE) ?? [];
|
|
16
|
+
const cap = (w) => w[0].toUpperCase() + w.slice(1).toLowerCase();
|
|
17
|
+
const pascalCase = (s) => words(s).map(cap).join("");
|
|
18
|
+
const camelCase = (s) =>
|
|
19
|
+
words(s)
|
|
20
|
+
.map((w, i) => (i ? cap(w) : w.toLowerCase()))
|
|
21
|
+
.join("");
|
|
22
|
+
const kebabCase = (s) =>
|
|
23
|
+
words(s)
|
|
24
|
+
.map((w) => w.toLowerCase())
|
|
25
|
+
.join("-");
|
|
26
|
+
|
|
13
27
|
const svgoConfig = (prefix) => ({
|
|
14
28
|
plugins: [
|
|
15
29
|
{
|
|
@@ -24,55 +38,55 @@ const svgoConfig = (prefix) => ({
|
|
|
24
38
|
],
|
|
25
39
|
});
|
|
26
40
|
|
|
27
|
-
const
|
|
28
|
-
const __dirname = path.dirname(__filename);
|
|
29
|
-
|
|
30
|
-
const preludeTemplate = `/**
|
|
41
|
+
const preludeTemplate = ({source, generator}) => `/**
|
|
31
42
|
* This file was automatically generated. Do not edit manually.
|
|
32
|
-
*
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
* ${
|
|
44
|
+
source
|
|
45
|
+
? `
|
|
46
|
+
* @see import("${source}")`
|
|
47
|
+
: ""
|
|
48
|
+
}
|
|
49
|
+
* @see import("${generator}")
|
|
35
50
|
*/
|
|
36
51
|
`;
|
|
37
52
|
|
|
38
|
-
const render =
|
|
39
|
-
`${preludeTemplate}
|
|
53
|
+
const render = ({source, generator, svgIdentifier, svgIdentifierPath}) =>
|
|
54
|
+
`${preludeTemplate({source, generator})}
|
|
40
55
|
import {forwardRef} from "react";
|
|
41
|
-
import
|
|
56
|
+
import ${svgIdentifier}Svg from "../ast/${svgIdentifierPath}";
|
|
42
57
|
import {Icon} from "../icon";
|
|
43
58
|
import type {IconBaseProps} from "../types";
|
|
44
59
|
|
|
45
|
-
const
|
|
60
|
+
const ${svgIdentifier} = forwardRef<SVGSVGElement, IconBaseProps>(function ${svgIdentifier}(
|
|
46
61
|
props: IconBaseProps,
|
|
47
62
|
ref: React.Ref<SVGSVGElement>
|
|
48
|
-
) {return <Icon {...props} className={props.className} ref={ref} icon={
|
|
63
|
+
) {return <Icon {...props} className={props.className} ref={ref} icon={${svgIdentifier}Svg} />});
|
|
49
64
|
|
|
50
|
-
export default
|
|
51
|
-
`.trim()
|
|
52
|
-
);
|
|
65
|
+
export default ${svgIdentifier};
|
|
66
|
+
`.trim();
|
|
53
67
|
|
|
54
|
-
const defTemplate =
|
|
68
|
+
const defTemplate = ({source, generator, identifier, content}) => `${preludeTemplate({source, generator})}
|
|
55
69
|
import type {IconDefinition} from "../types";
|
|
56
70
|
|
|
57
|
-
const
|
|
71
|
+
const ${identifier}: IconDefinition = ${content};
|
|
58
72
|
|
|
59
|
-
export default
|
|
60
|
-
|
|
73
|
+
export default ${identifier};
|
|
74
|
+
`;
|
|
61
75
|
|
|
62
76
|
const iconsDir = path.join(__dirname, "../src/icons");
|
|
63
77
|
const iconsSvgPathDir = path.join(iconsDir, "./svg");
|
|
64
78
|
const iconsReactPathDir = path.join(iconsDir, "./react");
|
|
65
79
|
const iconsAstPathDir = path.join(iconsDir, "./ast");
|
|
66
80
|
const pattern = "**/*.svg";
|
|
67
|
-
const icons = await
|
|
81
|
+
const icons = await glob(pattern, {cwd: iconsSvgPathDir});
|
|
68
82
|
|
|
69
83
|
await fs.remove(iconsReactPathDir);
|
|
70
84
|
await fs.remove(iconsAstPathDir);
|
|
71
85
|
|
|
72
86
|
const generator = path.relative(iconsReactPathDir, __filename);
|
|
73
|
-
let barrelExportContent =
|
|
87
|
+
let barrelExportContent = preludeTemplate({source: null, generator: generator}) + "\n";
|
|
74
88
|
for (const icon of icons) {
|
|
75
|
-
const name =
|
|
89
|
+
const name = pascalCase(icon.replace("/", "-").replace(".svg", ""));
|
|
76
90
|
const resultFileName = icon.replaceAll("/", "-").replace(".svg", "");
|
|
77
91
|
const iconPath = path.join(iconsSvgPathDir, icon);
|
|
78
92
|
const source = path.relative(iconsReactPathDir, iconPath);
|
|
@@ -97,17 +111,17 @@ for (const icon of icons) {
|
|
|
97
111
|
value.split(";").forEach((styleItem) => {
|
|
98
112
|
const [styleKey, styleValue] = styleItem.split(":").map((s) => s.trim());
|
|
99
113
|
if (styleKey && styleValue) {
|
|
100
|
-
style[
|
|
114
|
+
style[camelCase(styleKey)] = styleValue;
|
|
101
115
|
}
|
|
102
116
|
});
|
|
103
|
-
return [
|
|
117
|
+
return [camelCase(key), style];
|
|
104
118
|
}
|
|
105
|
-
return [
|
|
119
|
+
return [camelCase(key), value];
|
|
106
120
|
})
|
|
107
121
|
),
|
|
108
122
|
};
|
|
109
123
|
}),
|
|
110
|
-
name:
|
|
124
|
+
name: kebabCase(name),
|
|
111
125
|
}),
|
|
112
126
|
})
|
|
113
127
|
);
|
|
@@ -126,16 +140,3 @@ for (const icon of icons) {
|
|
|
126
140
|
}
|
|
127
141
|
await fs.outputFile(path.join(iconsReactPathDir, `./index.tsx`), barrelExportContent);
|
|
128
142
|
await fs.outputFile(path.join(iconsAstPathDir, `./index.tsx`), barrelExportContent);
|
|
129
|
-
|
|
130
|
-
// import {getSvg, iconNames} from "../Icon";
|
|
131
|
-
//
|
|
132
|
-
// it.skip("generate", async () => {
|
|
133
|
-
// console.log(iconNames);
|
|
134
|
-
// for (const iconName of iconNames) {
|
|
135
|
-
// await fs.outputFile(
|
|
136
|
-
// path.join(__dirname, "./icons", iconName.replace(":icon", "svg") + ".svg"),
|
|
137
|
-
// `<?xml version="1.0" standalone="no"?>\n` + getSvg({name: iconName})
|
|
138
|
-
// );
|
|
139
|
-
// }
|
|
140
|
-
// expect(true).toEqual(true);
|
|
141
|
-
// });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import {noop} from "@fibery/helpers/src/_";
|
|
1
2
|
import {stopPropagation} from "@fibery/react/src/stop-propagation";
|
|
2
3
|
import {useCallbackRef} from "@fibery/react/src/use-callback-ref";
|
|
3
4
|
import {css, cx} from "@linaria/core";
|
|
4
|
-
import noop from "lodash/noop";
|
|
5
5
|
import type {FunctionComponent, ReactNode} from "react";
|
|
6
6
|
import {memo, useId} from "react";
|
|
7
7
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import {noop} from "@fibery/helpers/src/_";
|
|
1
2
|
import {preventDefault} from "@fibery/react/src/prevent-default";
|
|
2
3
|
import {useControllableState} from "@fibery/react/src/use-controllable-state";
|
|
3
|
-
import noop from "lodash/noop";
|
|
4
4
|
import {useState} from "react";
|
|
5
5
|
|
|
6
6
|
import * as ContextMenu from "../context-menu";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import {noop} from "@fibery/helpers/src/_";
|
|
1
2
|
import {useComposedRefs} from "@fibery/react/src/use-composed-refs";
|
|
2
3
|
import {useSize} from "@fibery/react/src/use-size";
|
|
3
|
-
import noop from "lodash/noop";
|
|
4
4
|
import type {ComponentProps} from "react";
|
|
5
5
|
import React, {forwardRef, useEffect, useRef, useState} from "react";
|
|
6
6
|
|
package/src/antd/ant-modal.tsx
CHANGED
|
@@ -10,7 +10,7 @@ import {ThemeProvider} from "../theme-provider";
|
|
|
10
10
|
const defaultCloseIcon = <CloseIcon />;
|
|
11
11
|
|
|
12
12
|
const modalCss = css`
|
|
13
|
-
& .ant-modal-mask {
|
|
13
|
+
:where(&) .ant-modal-mask {
|
|
14
14
|
position: fixed;
|
|
15
15
|
inset: 0;
|
|
16
16
|
z-index: 1000;
|
|
@@ -18,7 +18,7 @@ const modalCss = css`
|
|
|
18
18
|
background-color: ${themeVars.modalBg};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
& .ant-modal-wrap {
|
|
21
|
+
:where(&) .ant-modal-wrap {
|
|
22
22
|
position: fixed;
|
|
23
23
|
inset: 0;
|
|
24
24
|
z-index: 1000;
|
|
@@ -27,7 +27,7 @@ const modalCss = css`
|
|
|
27
27
|
-webkit-overflow-scrolling: touch;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
& .ant-modal {
|
|
30
|
+
:where(&) .ant-modal {
|
|
31
31
|
position: relative;
|
|
32
32
|
top: 100px;
|
|
33
33
|
margin: 0 auto;
|
|
@@ -35,11 +35,11 @@ const modalCss = css`
|
|
|
35
35
|
pointer-events: none;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
& .ant-modal-centered {
|
|
38
|
+
:where(&) .ant-modal-centered {
|
|
39
39
|
text-align: center;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
& .ant-modal-centered::before {
|
|
42
|
+
:where(&) .ant-modal-centered::before {
|
|
43
43
|
display: inline-block;
|
|
44
44
|
width: 0;
|
|
45
45
|
height: 100%;
|
|
@@ -47,7 +47,7 @@ const modalCss = css`
|
|
|
47
47
|
content: "";
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
& .ant-modal-centered .ant-modal {
|
|
50
|
+
:where(&) .ant-modal-centered .ant-modal {
|
|
51
51
|
top: 0;
|
|
52
52
|
display: inline-block;
|
|
53
53
|
padding-bottom: 0;
|
|
@@ -55,7 +55,7 @@ const modalCss = css`
|
|
|
55
55
|
vertical-align: middle;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
& .ant-modal-content {
|
|
58
|
+
:where(&) .ant-modal-content {
|
|
59
59
|
position: relative;
|
|
60
60
|
box-shadow: ${themeVars.shadowPopup};
|
|
61
61
|
margin-left: ${space.s6}px;
|
|
@@ -65,11 +65,11 @@ const modalCss = css`
|
|
|
65
65
|
pointer-events: auto;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
& .ant-modal-body {
|
|
68
|
+
:where(&) .ant-modal-body {
|
|
69
69
|
padding: ${space.s20}px;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
& .ant-modal-close {
|
|
72
|
+
:where(&) .ant-modal-close {
|
|
73
73
|
position: absolute;
|
|
74
74
|
top: 0;
|
|
75
75
|
right: 0;
|
|
@@ -87,34 +87,34 @@ const modalCss = css`
|
|
|
87
87
|
cursor: pointer;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
& .ant-fade-enter,
|
|
91
|
-
& .ant-fade-appear {
|
|
90
|
+
:where(&) .ant-fade-enter,
|
|
91
|
+
:where(&) .ant-fade-appear {
|
|
92
92
|
opacity: 0;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
& .ant-fade-enter-active,
|
|
96
|
-
& .ant-fade-appear-active {
|
|
95
|
+
:where(&) .ant-fade-enter-active,
|
|
96
|
+
:where(&) .ant-fade-appear-active {
|
|
97
97
|
opacity: 1;
|
|
98
98
|
transition: opacity ${transitions.normal};
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
& .ant-fade-leave {
|
|
101
|
+
:where(&) .ant-fade-leave {
|
|
102
102
|
opacity: 1;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
& .ant-fade-leave-active {
|
|
105
|
+
:where(&) .ant-fade-leave-active {
|
|
106
106
|
opacity: 0;
|
|
107
107
|
transition: opacity ${transitions.normal};
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
& .ant-zoom-enter,
|
|
111
|
-
& .ant-zoom-appear {
|
|
110
|
+
:where(&) .ant-zoom-enter,
|
|
111
|
+
:where(&) .ant-zoom-appear {
|
|
112
112
|
opacity: 0;
|
|
113
113
|
transform: scale(0.96);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
& .ant-zoom-enter-active,
|
|
117
|
-
& .ant-zoom-appear-active {
|
|
116
|
+
:where(&) .ant-zoom-enter-active,
|
|
117
|
+
:where(&) .ant-zoom-appear-active {
|
|
118
118
|
opacity: 1;
|
|
119
119
|
transform: scale(1);
|
|
120
120
|
transition:
|
|
@@ -122,12 +122,12 @@ const modalCss = css`
|
|
|
122
122
|
transform ${transitions.normal};
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
& .ant-zoom-leave {
|
|
125
|
+
:where(&) .ant-zoom-leave {
|
|
126
126
|
opacity: 1;
|
|
127
127
|
transform: scale(1);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
& .ant-zoom-leave-active {
|
|
130
|
+
:where(&) .ant-zoom-leave-active {
|
|
131
131
|
opacity: 0;
|
|
132
132
|
transform: scale(0.96);
|
|
133
133
|
transition:
|
package/src/antd/styles.ts
CHANGED
|
@@ -182,6 +182,8 @@ export const inputStyles = css`
|
|
|
182
182
|
},
|
|
183
183
|
"&& input:hover:not(:focus):not(:disabled), && textarea:hover:not(:focus):not(:disabled), && .ant-input:hover:not(:focus):not(:disabled)":
|
|
184
184
|
inputOverrides.hover,
|
|
185
|
+
"&& .ant-input-affix-wrapper > input.ant-input:focus, && .ant-input-affix-wrapper > input.ant-input:active":
|
|
186
|
+
inputOverrides.focus,
|
|
185
187
|
"&& input:focus, && textarea:focus, && input:active, && textarea:active": inputOverrides.focus,
|
|
186
188
|
"&& .ant-input-disabled, && .ant-input-disabled:hover, && .ant-input-disabled:focus, && .ant-input-disabled:active":
|
|
187
189
|
inputOverrides.disabled,
|
|
@@ -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/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-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,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import noop from "
|
|
2
|
-
import {createContext} from "react";
|
|
1
|
+
import {noop} from "@fibery/helpers/src/_";
|
|
2
|
+
import {createContext, type Dispatch, type SetStateAction} from "react";
|
|
3
3
|
|
|
4
|
-
export const StartEndFocusContext = createContext
|
|
4
|
+
export const StartEndFocusContext = createContext<{
|
|
5
|
+
focusOnStart: boolean;
|
|
6
|
+
setFocusOnStart: Dispatch<SetStateAction<boolean>>;
|
|
7
|
+
}>({
|
|
5
8
|
focusOnStart: true,
|
|
6
9
|
setFocusOnStart: noop,
|
|
7
10
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {stopPropagation} from "@fibery/react/src/stop-propagation";
|
|
2
2
|
import {css} from "@linaria/core";
|
|
3
|
-
import omit from "lodash/omit";
|
|
4
3
|
import moment from "moment";
|
|
5
4
|
import {forwardRef, useCallback, useRef} from "react";
|
|
6
5
|
import {focusable} from "tabbable";
|
|
@@ -111,7 +110,7 @@ export const DateRangePicker = forwardRef<
|
|
|
111
110
|
>
|
|
112
111
|
<DateRangePickerPopupContent
|
|
113
112
|
ref={ref}
|
|
114
|
-
{...
|
|
113
|
+
{...props}
|
|
115
114
|
onChange={onDatesChange}
|
|
116
115
|
value={dateValue}
|
|
117
116
|
onKeyDown={onDatePickerKeyDown}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {stopPropagation} from "@fibery/react/src/stop-propagation";
|
|
2
2
|
import {css, cx} from "@linaria/core";
|
|
3
|
-
import omit from "lodash/omit";
|
|
4
3
|
import type {Moment} from "moment";
|
|
5
4
|
import moment from "moment";
|
|
6
5
|
|
|
@@ -191,7 +190,7 @@ export const SingleDatePickerPopoverContent = forwardRef<
|
|
|
191
190
|
{!allowRelativeDate || activeButton === "exact" ? (
|
|
192
191
|
<SingleDatePickerPopupContent
|
|
193
192
|
ref={ref}
|
|
194
|
-
{...
|
|
193
|
+
{...props}
|
|
195
194
|
onChange={onDateChange}
|
|
196
195
|
value={!isRelativeValue && value ? (value as Moment).toDate() : null}
|
|
197
196
|
onKeyDown={onDatePickerKeyDown}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import range from "lodash/range";
|
|
2
1
|
import moment from "moment";
|
|
3
2
|
|
|
4
3
|
import type {Props} from "./day-select";
|
|
5
4
|
import {DaySelect} from "./day-select";
|
|
6
5
|
|
|
7
|
-
const isoWeekDays =
|
|
6
|
+
const isoWeekDays = Array.from({length: 7}, (_, i) => {
|
|
7
|
+
const day = i + 1;
|
|
8
8
|
return {
|
|
9
9
|
key: String(day),
|
|
10
10
|
title: moment().isoWeekday(day).format("dd").charAt(0),
|
|
@@ -560,9 +560,9 @@ export function defsFromPalette({
|
|
|
560
560
|
colorBgListItemGeneral: transparentAlways,
|
|
561
561
|
colorBgListItemGeneralHover: surface.level3_4,
|
|
562
562
|
colorBgListItemGeneralFocus: surface.level4_6,
|
|
563
|
-
colorBgListItemGeneralSelected:
|
|
564
|
-
colorBgListItemGeneralSelectedHover:
|
|
565
|
-
colorBgListItemGeneralSelectedFocus:
|
|
563
|
+
colorBgListItemGeneralSelected: [accent[5], accentDark[5]],
|
|
564
|
+
colorBgListItemGeneralSelectedHover: [accent[6], accentDark[6]],
|
|
565
|
+
colorBgListItemGeneralSelectedFocus: [accent[6], accentDark[6]],
|
|
566
566
|
colorBgListItemGeneralDisabled: transparentAlways,
|
|
567
567
|
colorTextListItemGeneralDisabled: fg.muted,
|
|
568
568
|
colorBgListItemGeneralSelectedDisabled: [accent[5], accentDark[5]],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import {truthy} from "@fibery/helpers/src/_";
|
|
1
2
|
import {css} from "@linaria/core";
|
|
2
|
-
import compact from "lodash/compact";
|
|
3
3
|
import {useState} from "react";
|
|
4
4
|
|
|
5
5
|
import {Button} from "../button/button";
|
|
@@ -48,7 +48,7 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
48
48
|
color,
|
|
49
49
|
getHoverColor,
|
|
50
50
|
}) => {
|
|
51
|
-
const items =
|
|
51
|
+
const items = [
|
|
52
52
|
onEmojiSelect && {
|
|
53
53
|
key: "emojis" as const,
|
|
54
54
|
label: "Emojis",
|
|
@@ -80,7 +80,7 @@ export const IconEmojiPicker: React.FC<IconEmojiPickerProps> = ({
|
|
|
80
80
|
/>
|
|
81
81
|
),
|
|
82
82
|
},
|
|
83
|
-
]);
|
|
83
|
+
].filter(truthy);
|
|
84
84
|
|
|
85
85
|
const firstTab = items[0];
|
|
86
86
|
const [activeTab, setActiveTab] = useState(defaultTab || firstTab?.key);
|