@fibery/ui-kit 1.22.0 → 1.24.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/package.json +4 -3
- package/src/design-system.ts +2 -0
- package/src/emoji-picker/app-icon-picker.tsx +21 -15
- package/src/emoji-picker/emoji-picker-content-with-color.tsx +9 -11
- package/src/emoji-picker/emoji-picker-preview-footer.tsx +94 -0
- package/src/emoji-picker/emoji-picker.tsx +3 -28
- package/src/emoji-picker/icon-emoji-picker.tsx +1 -1
- package/src/emoji-picker/primitives/category-label.tsx +42 -0
- package/src/emoji-picker/primitives/content.tsx +15 -3
- package/src/emoji-picker/primitives/footer.tsx +4 -2
- package/src/emoji-picker/primitives/grid-item.tsx +73 -0
- package/src/emoji-picker/primitives/grid.tsx +332 -76
- package/src/emoji-picker/primitives/preview-provider.tsx +27 -0
- package/src/emoji-picker/primitives/root.tsx +8 -5
- package/src/emoji-picker/primitives/search.tsx +50 -6
- package/src/emoji-picker/stores/emoji-data-store.tsx +13 -10
- package/src/emoji-picker/stores/lazy-icon-data-store.tsx +4 -2
- package/src/emoji-picker/stores/static-emoji-data-store.tsx +11 -6
- package/src/lists/list-row-surface.tsx +8 -0
- package/src/select/index.tsx +5 -0
- package/src/emoji-picker/primitives/category.tsx +0 -177
- package/src/emoji-picker/stores/lazy-emoji-data-store.tsx +0 -29
|
@@ -28,17 +28,25 @@ export const listRowSurfaceStylesBase = css`
|
|
|
28
28
|
color: ${themeVars.textColor};
|
|
29
29
|
border-radius: ${border.radius6}px;
|
|
30
30
|
transition: background-color;
|
|
31
|
+
|
|
32
|
+
&:focus {
|
|
33
|
+
outline: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
${NATURAL_HOVER},
|
|
32
37
|
&.hover {
|
|
33
38
|
cursor: pointer;
|
|
34
39
|
}
|
|
40
|
+
|
|
35
41
|
&.done {
|
|
36
42
|
cursor: not-allowed;
|
|
37
43
|
color: ${themeVars.colorTextListItemGeneralDisabled};
|
|
44
|
+
|
|
38
45
|
> * {
|
|
39
46
|
opacity: ${themeVars.opacityListItemGeneralDisabled};
|
|
40
47
|
}
|
|
41
48
|
}
|
|
49
|
+
|
|
42
50
|
&.selected {
|
|
43
51
|
cursor: default;
|
|
44
52
|
}
|
package/src/select/index.tsx
CHANGED
|
@@ -103,6 +103,11 @@ function countOptions<Option, Group extends GroupBase<Option>>(categorizedOption
|
|
|
103
103
|
}, 0);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Draws a select input.
|
|
108
|
+
* Please use formatOptionLabel instead of Option component override. Select has smart optimisations for large lists
|
|
109
|
+
* those would be lost and your select slow if options are too numerous
|
|
110
|
+
*/
|
|
106
111
|
export const Select = forwardRef(function Select<
|
|
107
112
|
Option = unknown,
|
|
108
113
|
IsMulti extends boolean = boolean,
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import {Category, EmojiItem} from "@fibery/emoji-data";
|
|
2
|
-
import {css} from "@linaria/core";
|
|
3
|
-
import {memo} from "react";
|
|
4
|
-
import {useInView} from "react-intersection-observer";
|
|
5
|
-
import {IconButton} from "../../button/icon-button";
|
|
6
|
-
import {space, textStyles, themeVars} from "../../design-system";
|
|
7
|
-
import {Settings} from "../../icons/react";
|
|
8
|
-
import {useEmojiDataStoreSelector} from "../stores/emoji-data-store";
|
|
9
|
-
import {useEmojiPickerContentSettings} from "./content";
|
|
10
|
-
import {Emoji} from "./emoji";
|
|
11
|
-
import {emojiPadding} from "./layout";
|
|
12
|
-
import {useEmojiPickerCtx, useEmojiPickerI18N} from "./root";
|
|
13
|
-
import {useEmojiSkin} from "./skin-provider";
|
|
14
|
-
|
|
15
|
-
const categoryCss = css``;
|
|
16
|
-
|
|
17
|
-
const categoryLabelCss = css`
|
|
18
|
-
${textStyles.heading6}
|
|
19
|
-
color: ${themeVars.accentTextColor};
|
|
20
|
-
background-color: ${themeVars.actionMenuBg};
|
|
21
|
-
padding: ${space.s12}px ${space.s6}px ${space.s4}px ${space.s6}px;
|
|
22
|
-
position: sticky;
|
|
23
|
-
top: 0;
|
|
24
|
-
|
|
25
|
-
display: flex;
|
|
26
|
-
align-items: center;
|
|
27
|
-
gap: ${space.s4}px;
|
|
28
|
-
|
|
29
|
-
z-index: 1;
|
|
30
|
-
`;
|
|
31
|
-
|
|
32
|
-
const categoryListCss = css`
|
|
33
|
-
display: flex;
|
|
34
|
-
flex-wrap: wrap;
|
|
35
|
-
margin: 0;
|
|
36
|
-
padding: 0;
|
|
37
|
-
|
|
38
|
-
& li {
|
|
39
|
-
list-style: none;
|
|
40
|
-
margin: 0;
|
|
41
|
-
padding: 0;
|
|
42
|
-
|
|
43
|
-
line-height: 1;
|
|
44
|
-
}
|
|
45
|
-
`;
|
|
46
|
-
|
|
47
|
-
const notFoundCss = css`
|
|
48
|
-
padding-top: 70px;
|
|
49
|
-
text-align: center;
|
|
50
|
-
|
|
51
|
-
${textStyles.regular};
|
|
52
|
-
color: ${themeVars.accentTextColor};
|
|
53
|
-
`;
|
|
54
|
-
|
|
55
|
-
const NotFound = () => {
|
|
56
|
-
const i18n = useEmojiPickerI18N();
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<div className={notFoundCss}>
|
|
60
|
-
<Emoji emoji="sleuth_or_spy" size={38} />
|
|
61
|
-
<div>{i18n.notfound}</div>
|
|
62
|
-
</div>
|
|
63
|
-
);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
type CategoryItemProps = {
|
|
67
|
-
id: string;
|
|
68
|
-
/** Custom renderer for emoji items */
|
|
69
|
-
renderEmoji?: (args: {emoji: EmojiItem}) => React.ReactNode;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const CategoryItem: React.FC<CategoryItemProps> = ({id, renderEmoji}) => {
|
|
73
|
-
const skin = useEmojiSkin();
|
|
74
|
-
const emojiPickerCtx = useEmojiPickerCtx();
|
|
75
|
-
const emojiContentSettings = useEmojiPickerContentSettings();
|
|
76
|
-
|
|
77
|
-
const emoji = useEmojiDataStoreSelector((store) => store.get(id, {skin}));
|
|
78
|
-
|
|
79
|
-
if (!emoji) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// TODO: title should be shown in preview in footer
|
|
84
|
-
const title = emoji.shortNames ? emoji.shortNames[0] : undefined;
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<IconButton
|
|
88
|
-
size="big"
|
|
89
|
-
onClick={() => emojiPickerCtx.onEmojiSelect(emoji)}
|
|
90
|
-
className={css`
|
|
91
|
-
&:hover:not(:disabled),
|
|
92
|
-
&:focus-visible {
|
|
93
|
-
background-color: var(--fibery-emoji-hover-color, ${themeVars.badgeBgColor});
|
|
94
|
-
}
|
|
95
|
-
`}
|
|
96
|
-
title={title}
|
|
97
|
-
aria-label={emoji.name}
|
|
98
|
-
>
|
|
99
|
-
{renderEmoji ? (
|
|
100
|
-
renderEmoji({emoji})
|
|
101
|
-
) : (
|
|
102
|
-
<Emoji
|
|
103
|
-
emoji={id}
|
|
104
|
-
size={emojiContentSettings.emojiSize}
|
|
105
|
-
version={emojiPickerCtx.version}
|
|
106
|
-
skin={skin}
|
|
107
|
-
native={emojiPickerCtx.native}
|
|
108
|
-
/>
|
|
109
|
-
)}
|
|
110
|
-
</IconButton>
|
|
111
|
-
);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export type EmojiPickerCategoryProps = {
|
|
115
|
-
category: Category;
|
|
116
|
-
|
|
117
|
-
preRender?: boolean;
|
|
118
|
-
scrollParent: Element | null;
|
|
119
|
-
} & Pick<CategoryItemProps, "renderEmoji">;
|
|
120
|
-
|
|
121
|
-
export const EmojiPickerCategory = memo<EmojiPickerCategoryProps>(function EmojiPickerCategoryComponent({
|
|
122
|
-
category,
|
|
123
|
-
renderEmoji,
|
|
124
|
-
scrollParent,
|
|
125
|
-
preRender = false,
|
|
126
|
-
}) {
|
|
127
|
-
const i18n = useEmojiPickerI18N();
|
|
128
|
-
const emojiPickerCtx = useEmojiPickerCtx();
|
|
129
|
-
const emojiContentSettings = useEmojiPickerContentSettings();
|
|
130
|
-
|
|
131
|
-
const {ref, inView} = useInView({
|
|
132
|
-
root: scrollParent,
|
|
133
|
-
rootMargin: `129px 0px`, // grid height / 2
|
|
134
|
-
initialInView: preRender,
|
|
135
|
-
fallbackInView: true,
|
|
136
|
-
triggerOnce: true,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const label = i18n.categories[category.id as keyof (typeof i18n)["categories"]] || category.name;
|
|
140
|
-
|
|
141
|
-
const emojiSize = emojiContentSettings.emojiSize + emojiPadding * 2;
|
|
142
|
-
|
|
143
|
-
return (
|
|
144
|
-
<section className={categoryCss} aria-label={label}>
|
|
145
|
-
<div className={categoryLabelCss}>
|
|
146
|
-
{/* already labeled by the section aria-label */}
|
|
147
|
-
<span aria-hidden={true}>{label}</span>
|
|
148
|
-
|
|
149
|
-
{category.id === "custom" && emojiPickerCtx.onCustomCategorySettings && (
|
|
150
|
-
<IconButton onClick={emojiPickerCtx.onCustomCategorySettings}>
|
|
151
|
-
<Settings iconSize={16} />
|
|
152
|
-
</IconButton>
|
|
153
|
-
)}
|
|
154
|
-
</div>
|
|
155
|
-
|
|
156
|
-
{category.emojis.length > 0 ? (
|
|
157
|
-
<ul ref={ref} className={categoryListCss}>
|
|
158
|
-
{category.emojis.map((id) => {
|
|
159
|
-
return (
|
|
160
|
-
<li
|
|
161
|
-
key={id}
|
|
162
|
-
style={{
|
|
163
|
-
width: emojiSize,
|
|
164
|
-
height: emojiSize,
|
|
165
|
-
}}
|
|
166
|
-
>
|
|
167
|
-
{inView ? <CategoryItem id={id} renderEmoji={renderEmoji} /> : null}
|
|
168
|
-
</li>
|
|
169
|
-
);
|
|
170
|
-
})}
|
|
171
|
-
</ul>
|
|
172
|
-
) : (
|
|
173
|
-
<NotFound />
|
|
174
|
-
)}
|
|
175
|
-
</section>
|
|
176
|
-
);
|
|
177
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {makeEmojiData} from "@fibery/emoji-data";
|
|
2
|
-
import {Suspense, lazy} from "react";
|
|
3
|
-
import {EmojiDataStoreProvider} from "./emoji-data-store";
|
|
4
|
-
import {getEmojiSet} from "../utils/emoji-set";
|
|
5
|
-
import {loadEmojiData} from "../utils/load-emoji-data";
|
|
6
|
-
|
|
7
|
-
const LazyEmojiDataStoreComponent = lazy(async () => {
|
|
8
|
-
const rawData = await loadEmojiData();
|
|
9
|
-
|
|
10
|
-
const emojiData = makeEmojiData(rawData, {set: getEmojiSet()});
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
default: function EmojiDataStore({children}: React.PropsWithChildren) {
|
|
14
|
-
return <EmojiDataStoreProvider data={emojiData}>{children}</EmojiDataStoreProvider>;
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
export const LazyEmojiDataStore: React.FC<
|
|
20
|
-
React.PropsWithChildren<{
|
|
21
|
-
fallback: React.ReactNode;
|
|
22
|
-
}>
|
|
23
|
-
> = ({fallback, children}) => {
|
|
24
|
-
return (
|
|
25
|
-
<Suspense fallback={fallback}>
|
|
26
|
-
<LazyEmojiDataStoreComponent>{children}</LazyEmojiDataStoreComponent>
|
|
27
|
-
</Suspense>
|
|
28
|
-
);
|
|
29
|
-
};
|