@fibery/ui-kit 1.40.3 → 1.41.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 +14 -0
- package/eslint.config.mjs +16 -0
- package/package.json +11 -13
- package/src/a11y-color.test.ts +162 -0
- package/src/a11y-color.ts +13 -20
- package/src/actions-menu/actions-menu-item.tsx +9 -12
- package/src/actions-menu/context-actions-menu.tsx +8 -3
- package/src/ai/model.tsx +0 -1
- package/src/ai/temperature.tsx +0 -1
- package/src/animated-height-container.tsx +3 -3
- package/src/antd/ant-modal.tsx +10 -5
- package/src/antd/index.tsx +3 -0
- package/src/antd/input.tsx +0 -1
- package/src/antd/styles.ts +15 -15
- package/src/app-icon-with-fallback.tsx +6 -6
- package/src/app-icon-wrapper.tsx +2 -3
- package/src/app-icon.tsx +4 -4
- package/src/avatar.tsx +3 -3
- package/src/button/base-button.tsx +0 -1
- package/src/button/button.tsx +1 -0
- package/src/button/make-button-colors.ts +5 -13
- package/src/checkbox.tsx +2 -2
- package/src/collapsible-section.tsx +11 -1
- package/src/color-picker/ColorPickerOrLoader.js +2 -2
- package/src/color-utils.test.ts +307 -0
- package/src/color-utils.ts +215 -0
- package/src/command-menu/index.tsx +1 -0
- package/src/comment.tsx +3 -2
- package/src/context-menu/index.tsx +12 -7
- package/src/date-picker/contexts.ts +2 -2
- package/src/date-picker/date-range-picker.tsx +3 -4
- package/src/date-picker/single-date-picker.tsx +147 -119
- package/src/date-picker/types.ts +4 -3
- package/src/day-select/iso-week-day-select.tsx +2 -2
- package/src/day-select/week-day-select.tsx +2 -2
- package/src/delayed.tsx +0 -1
- package/src/design-system/alpha.test.ts +59 -0
- package/src/design-system/alpha.ts +41 -0
- package/src/design-system/animation.ts +10 -0
- package/src/design-system/colors-css.test.ts +39 -0
- package/src/design-system/colors-css.ts +25 -0
- package/src/design-system/colors-js.test.ts +232 -0
- package/src/design-system/colors-js.ts +107 -0
- package/src/design-system/colors.test.ts +74 -0
- package/src/design-system/colors.ts +759 -0
- package/src/design-system/date.ts +3 -0
- package/src/design-system/layout.ts +106 -0
- package/src/design-system/theme.test.ts +94 -0
- package/src/design-system/theme.ts +93 -0
- package/src/design-system/typography.ts +179 -0
- package/src/design-system/vars.test.ts +1679 -0
- package/src/design-system/vars.ts +52 -0
- package/src/design-system.test.ts +45 -22
- package/src/design-system.ts +25 -1339
- package/src/dropdown-menu/index.tsx +21 -16
- package/src/emoji-picker/app-icon-picker.tsx +5 -5
- package/src/emoji-picker/emoji-picker-content-with-color.tsx +4 -4
- package/src/emoji-picker/icon-emoji-picker.tsx +3 -3
- package/src/favorites-icon.tsx +1 -1
- package/src/fibermoji-placeholder.tsx +3 -3
- package/src/field-container.tsx +11 -2
- package/src/file-item/file-icon.tsx +169 -0
- package/src/file-item/file-menu-items.tsx +68 -0
- package/src/file-item/file-preview-actions.tsx +38 -0
- package/src/file-item/file-title.tsx +48 -0
- package/src/file-item/types.ts +27 -0
- package/src/file-item/use-register-in-image-gallery.tsx +70 -0
- package/src/file-item-2.tsx +32 -348
- package/src/file-item.tsx +6 -3
- package/src/hue-shift.test.ts +91 -0
- package/src/icons/ast/ChatBubble.ts +8 -0
- package/src/icons/ast/ChatFloat.ts +8 -0
- package/src/icons/ast/ChatSidebar.ts +8 -0
- package/src/icons/ast/FileCounter.ts +8 -0
- package/src/icons/ast/FileMultiple.ts +8 -0
- package/src/icons/ast/FileOther.ts +8 -0
- package/src/icons/ast/NoBorder.ts +8 -0
- package/src/icons/ast/NoFill.ts +8 -0
- package/src/icons/ast/ValueEdit.ts +8 -0
- package/src/icons/ast/index.tsx +9 -0
- package/src/icons/react/ChatBubble.tsx +13 -0
- package/src/icons/react/ChatFloat.tsx +13 -0
- package/src/icons/react/ChatSidebar.tsx +13 -0
- package/src/icons/react/FileCounter.tsx +13 -0
- package/src/icons/react/FileMultiple.tsx +13 -0
- package/src/icons/react/FileOther.tsx +13 -0
- package/src/icons/react/NoBorder.tsx +13 -0
- package/src/icons/react/NoFill.tsx +13 -0
- package/src/icons/react/ValueEdit.tsx +13 -0
- package/src/icons/react/index.tsx +9 -0
- package/src/icons/svg/chat-bubble.svg +4 -0
- package/src/icons/svg/chat-float.svg +4 -0
- package/src/icons/svg/chat-sidebar.svg +4 -0
- package/src/icons/svg/file-counter.svg +3 -0
- package/src/icons/svg/file-multiple.svg +3 -0
- package/src/icons/svg/file-other.svg +3 -0
- package/src/icons/svg/no-border.svg +17 -0
- package/src/icons/svg/no-fill.svg +4 -0
- package/src/icons/svg/value-edit.svg +3 -0
- package/src/images-gallery/images-gallery.tsx +8 -6
- package/src/images-gallery/slide-buttons.tsx +4 -11
- package/src/is-iOS.ts +0 -1
- package/src/is-in-popup.ts +2 -1
- package/src/lists/actions-menu-row-surface.tsx +7 -7
- package/src/loading-sausage.tsx +2 -2
- package/src/media-query-utils.ts +1 -2
- package/src/mobile-keyboard-aware-popup.tsx +6 -5
- package/src/modal-menu/modal-menu-content.tsx +2 -2
- package/src/number-input/decimal.js +9 -7
- package/src/number-input/{number-inline-input-with-autosize.tsx → number-input-inline-with-autosize.tsx} +20 -41
- package/src/number-input/number-input-inline.tsx +118 -0
- package/src/number-input/{index.test.js → number-input.test.tsx} +38 -43
- package/src/number-input/number-input.tsx +63 -121
- package/src/number-input/types.ts +19 -0
- package/src/number-input/utils.ts +61 -0
- package/src/online-users.tsx +2 -2
- package/src/palette-generator.test.ts +309 -0
- package/src/palette-generator.ts +160 -0
- package/src/palettes/_.ts +72 -0
- package/src/palettes/slate-arch.colors-snapshot.test.ts +1689 -0
- package/src/palettes/slate-arch.ts +188 -0
- package/src/palettes/slate-user.colors-snapshot.test.ts +1689 -0
- package/src/palettes/slate-user.ts +187 -0
- package/src/palettes/warm-arch.colors-snapshot.test.ts +1689 -0
- package/src/palettes/warm-arch.ts +222 -0
- package/src/palettes/warm-user.colors-snapshot.test.ts +1689 -0
- package/src/palettes/warm-user.ts +222 -0
- package/src/platform.ts +0 -3
- package/src/popover/get-element-ref.ts +28 -0
- package/src/popover/index.tsx +236 -339
- package/src/popover/{mobile-popup-context.tsx → mobile-popover-context.tsx} +7 -7
- package/src/popover/mobile-popover.tsx +169 -0
- package/src/popover/modifiers.tsx +2 -2
- package/src/popover/popup-stack-context.tsx +8 -9
- package/src/progress.tsx +2 -2
- package/src/reactions/reaction-button.tsx +12 -6
- package/src/root-theme-provider.test.tsx +411 -0
- package/src/scale-generator.ts +356 -0
- package/src/select/components/menu-list-virtualized.tsx +12 -25
- package/src/select/components/menu.tsx +12 -2
- package/src/select/index.tsx +6 -5
- package/src/select/select.tsx +38 -39
- package/src/select/styles.ts +0 -1
- package/src/select/util.ts +1 -1
- package/src/static-palettes.ts +356 -0
- package/src/thematic-color-picker.tsx +266 -0
- package/src/thematic-constants.tsx +27 -0
- package/src/thematic-controls.tsx +144 -0
- package/src/thematic-scales.tsx +122 -0
- package/src/thematic-state.ts +370 -0
- package/src/thematic.tsx +386 -0
- package/src/theme-provider.test.tsx +820 -0
- package/src/theme-provider.tsx +158 -92
- package/src/theme-settings.ts +67 -12
- package/src/theme-styles.ts +58 -6
- package/src/toast/toast-action.tsx +1 -1
- package/src/toast/toast.tsx +1 -2
- package/src/toggle-on-off.tsx +2 -2
- package/src/toggle.tsx +7 -8
- package/src/tooltip.tsx +14 -10
- package/src/type-badge.tsx +7 -14
- package/src/unit/styles.ts +2 -25
- package/src/unit/unit-with-tooltip.tsx +3 -2
- package/src/use-is-phone.tsx +7 -2
- package/src/use-long-press.tsx +2 -2
- package/src/use-on-screen-keyboard-data.tsx +2 -2
- package/src/with-data.tsx +4 -3
- package/src/workflow-progress-icon.tsx +2 -2
- package/.eslintignore +0 -3
- package/.eslintrc +0 -14
- package/src/__mocks__/createInlineTheme.js +0 -3
- package/src/create-inline-theme.ts +0 -66
- package/src/number-input/index.js +0 -191
- package/src/palette.ts +0 -237
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type {Coords, PlainColorObject} from "colorjs.io/fn";
|
|
2
|
+
import {
|
|
3
|
+
ColorSpace,
|
|
4
|
+
contrastWCAG21,
|
|
5
|
+
deltaE76,
|
|
6
|
+
getLuminance as getLuminanceUnsafe,
|
|
7
|
+
HSL,
|
|
8
|
+
Lab,
|
|
9
|
+
LCH,
|
|
10
|
+
mix,
|
|
11
|
+
OKLCH,
|
|
12
|
+
P3,
|
|
13
|
+
parse,
|
|
14
|
+
serialize,
|
|
15
|
+
set,
|
|
16
|
+
sRGB,
|
|
17
|
+
to,
|
|
18
|
+
toGamut,
|
|
19
|
+
} from "colorjs.io/fn";
|
|
20
|
+
|
|
21
|
+
ColorSpace.register(sRGB);
|
|
22
|
+
ColorSpace.register(HSL);
|
|
23
|
+
ColorSpace.register(Lab);
|
|
24
|
+
ColorSpace.register(LCH);
|
|
25
|
+
ColorSpace.register(OKLCH);
|
|
26
|
+
ColorSpace.register(P3);
|
|
27
|
+
|
|
28
|
+
type Color = PlainColorObject;
|
|
29
|
+
|
|
30
|
+
// FIXME consolidate as common util
|
|
31
|
+
const isFlagPresent = (flag: string) => globalThis.window && new RegExp(`[?&]${flag}\\b`).test(window.location.search);
|
|
32
|
+
|
|
33
|
+
const defaultColorSpace = isFlagPresent("oklch") ? OKLCH : sRGB;
|
|
34
|
+
|
|
35
|
+
function colorSafe(
|
|
36
|
+
color: string,
|
|
37
|
+
fallback = "hsl(220, 62%, 56%)" /* formerly brandColor.blue, currently accent[9] */,
|
|
38
|
+
space: ColorSpace = defaultColorSpace
|
|
39
|
+
): Color {
|
|
40
|
+
try {
|
|
41
|
+
return to(color, space);
|
|
42
|
+
} catch {
|
|
43
|
+
return to(fallback, space);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const coords = (a: number, b: number, c: number): Coords => [a, b, c];
|
|
48
|
+
const clamp01 = (v: number | null): number => Math.max(0, Math.min(1, v ?? 0));
|
|
49
|
+
const white: PlainColorObject = {space: sRGB, coords: [1, 1, 1], alpha: 1};
|
|
50
|
+
const black: PlainColorObject = {space: sRGB, coords: [0, 0, 0], alpha: 1};
|
|
51
|
+
|
|
52
|
+
function serializesRGB(color: Color): string {
|
|
53
|
+
const rgb = toGamut(to(color, sRGB), {space: sRGB});
|
|
54
|
+
const r = Math.round(clamp01(rgb.coords[0]) * 255);
|
|
55
|
+
const g = Math.round(clamp01(rgb.coords[1]) * 255);
|
|
56
|
+
const b = Math.round(clamp01(rgb.coords[2]) * 255);
|
|
57
|
+
const a = rgb.alpha ?? 1;
|
|
58
|
+
return a < 1 ? `rgba(${r},${g},${b},${a})` : `rgb(${r},${g},${b})`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type ColorTransform = (color: PlainColorObject) => PlainColorObject | void;
|
|
62
|
+
|
|
63
|
+
export function produceColor(
|
|
64
|
+
color: string,
|
|
65
|
+
transforms: ColorTransform | ColorTransform[],
|
|
66
|
+
space: ColorSpace = defaultColorSpace
|
|
67
|
+
): string {
|
|
68
|
+
let c = colorSafe(color);
|
|
69
|
+
for (const transform of Array.isArray(transforms) ? transforms : [transforms]) {
|
|
70
|
+
const result = transform(c);
|
|
71
|
+
if (result !== undefined) {
|
|
72
|
+
c = result;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// TODO make sRGB default space and apply colorjs.io outputs CSS Level 4 format (rgb(100% 0% 0%))
|
|
76
|
+
// instead of compatible format (rgb(255,0,0))
|
|
77
|
+
if (space === sRGB) {
|
|
78
|
+
return serializesRGB(c);
|
|
79
|
+
}
|
|
80
|
+
return serialize(to(c, space));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @deprecated chroma-js compatibility artifact, try using newer apis
|
|
85
|
+
* Set relative luminance by binary-search interpolation toward white/black in sRGB.
|
|
86
|
+
* This targets relative luminance (Y in XYZ), not perceptual lightness.
|
|
87
|
+
*/
|
|
88
|
+
export function setLuminanceChroma(color: PlainColorObject, target: number): PlainColorObject {
|
|
89
|
+
const curLum = getLuminanceUnsafe(color);
|
|
90
|
+
if (Math.abs(curLum - target) < 1e-7) {
|
|
91
|
+
return color;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const endpoint = target > curLum ? white : black;
|
|
95
|
+
let lo = 0;
|
|
96
|
+
let hi = 1;
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < 12; i++) {
|
|
99
|
+
const mid = (lo + hi) / 2;
|
|
100
|
+
const lum = getLuminanceUnsafe(mix(color, endpoint, mid, {space: sRGB}));
|
|
101
|
+
if (target > curLum ? lum < target : lum > target) {
|
|
102
|
+
lo = mid;
|
|
103
|
+
} else {
|
|
104
|
+
hi = mid;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = mix(color, endpoint, (lo + hi) / 2, {space: sRGB});
|
|
109
|
+
result.alpha = color.alpha ?? 1;
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @deprecated chroma-js compatibility artifact, try using newer apis
|
|
115
|
+
* Darken by reducing L* in Lab color space using colorjs.io set().
|
|
116
|
+
* Matches chroma-js: darken(1) reduces Lab L* by 18 units.
|
|
117
|
+
* Negative L* values are handled by toGamut during serialization.
|
|
118
|
+
*/
|
|
119
|
+
export function darkenChroma(color: PlainColorObject, amount: number): PlainColorObject {
|
|
120
|
+
return set(color, "lab.l", (l) => l - amount * 18);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @deprecated chroma-js compatibility artifact, try using newer apis
|
|
125
|
+
* Desaturate by reducing C (chroma) in LCH color space using colorjs.io set().
|
|
126
|
+
* Matches chroma-js: desaturate(1) reduces LCH C by 18 units.
|
|
127
|
+
* Negative C values are handled by toGamut during serialization.
|
|
128
|
+
*/
|
|
129
|
+
export function desaturateChroma(color: PlainColorObject, amount: number): PlainColorObject {
|
|
130
|
+
return set(color, "lch.c", (c) => c - amount * 18);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function setAlpha(color: PlainColorObject, value: number): void {
|
|
134
|
+
color.alpha = value;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function isValidColor(color: string): boolean {
|
|
138
|
+
if (color === "transparent") {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
parse(color);
|
|
143
|
+
return true;
|
|
144
|
+
} catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function getAlpha(color: string): number {
|
|
150
|
+
return colorSafe(color).alpha ?? 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function getContrastRatio(color1: string, color2: string): number {
|
|
154
|
+
return contrastWCAG21(colorSafe(color1), colorSafe(color2));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function getColorDistance(color1: string, color2: string): number {
|
|
158
|
+
return deltaE76(colorSafe(color1), colorSafe(color2));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function getLuminance(color: string): number {
|
|
162
|
+
return getLuminanceUnsafe(colorSafe(color));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function fromHSL(h: number, s: number, l: number): string {
|
|
166
|
+
return serializesRGB({space: HSL, coords: coords(h, s * 100, l * 100), alpha: null});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function fromOKLCH(L: number, C: number, H: number, alpha = 1): string {
|
|
170
|
+
return serializesRGB({space: OKLCH, coords: [L, C, H] as [number, number, number], alpha});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function toOKLCH(color: string) {
|
|
174
|
+
return produceColor(color, [], OKLCH);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function toRGB(color: string) {
|
|
178
|
+
return produceColor(color, [], sRGB);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function getHsl(color: string): [number, number, number] {
|
|
182
|
+
const c = to(colorSafe(color), HSL);
|
|
183
|
+
return [c.coords[0] || 0, (c.coords[1] || 0) / 100, (c.coords[2] || 0) / 100];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** @deprecated do not use that, chroma-js compatibility */
|
|
187
|
+
export function clampRgb(color: PlainColorObject): PlainColorObject {
|
|
188
|
+
const rgb = to(color, sRGB);
|
|
189
|
+
rgb.coords = rgb.coords.map(clamp01) as Coords;
|
|
190
|
+
return rgb;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function toCss(color: string): string {
|
|
194
|
+
return produceColor(color, []);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @deprecated use toCss instead
|
|
199
|
+
*/
|
|
200
|
+
export function toHex(color: string): string {
|
|
201
|
+
const c = toGamut(to(colorSafe(color), sRGB), {space: sRGB});
|
|
202
|
+
const r = Math.round(clamp01(c.coords[0]) * 255);
|
|
203
|
+
const g = Math.round(clamp01(c.coords[1]) * 255);
|
|
204
|
+
const b = Math.round(clamp01(c.coords[2]) * 255);
|
|
205
|
+
const a = c.alpha ?? 1;
|
|
206
|
+
const hex = "#" + [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
207
|
+
return a < 1
|
|
208
|
+
? hex +
|
|
209
|
+
Math.round(a * 255)
|
|
210
|
+
.toString(16)
|
|
211
|
+
.padStart(2, "0")
|
|
212
|
+
: hex;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export {ColorSpace, mix, OKLCH, parse, set, sRGB, to, HSL, Lab, LCH};
|
package/src/comment.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import {border, iconSize, space, textStyles, themeVars, transition} from "./desi
|
|
|
6
6
|
import {formatDateFromNow} from "./format-date-from-now";
|
|
7
7
|
import {LoadingSausage, LoadingSausageList} from "./loading-sausage";
|
|
8
8
|
import {Tooltip} from "./tooltip";
|
|
9
|
-
import {
|
|
9
|
+
import {useIsPhone} from "./use-is-phone";
|
|
10
10
|
|
|
11
11
|
export const commentContentStyle = css`
|
|
12
12
|
${{
|
|
@@ -115,6 +115,7 @@ export const Comment = memo(
|
|
|
115
115
|
|
|
116
116
|
const {formatted, relative} = formatDateFromNow(date, {format: dateTimeFormat});
|
|
117
117
|
const IconComponent = icon ? icon : null;
|
|
118
|
+
const isPhone = useIsPhone();
|
|
118
119
|
return (
|
|
119
120
|
<div
|
|
120
121
|
ref={ref}
|
|
@@ -153,7 +154,7 @@ export const Comment = memo(
|
|
|
153
154
|
<div
|
|
154
155
|
className={cx(
|
|
155
156
|
actionsClassName,
|
|
156
|
-
(actionsShowed ||
|
|
157
|
+
(actionsShowed || isPhone) &&
|
|
157
158
|
css`
|
|
158
159
|
display: flex;
|
|
159
160
|
`
|
|
@@ -4,6 +4,7 @@ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
|
|
|
4
4
|
import {forwardRef} from "react";
|
|
5
5
|
import {border, layout, space, textStyles, themeVars} from "../design-system";
|
|
6
6
|
import {mobileRootSelector} from "../mobile-styles";
|
|
7
|
+
import {RadixPortalThemeProvider} from "../theme-provider";
|
|
7
8
|
|
|
8
9
|
export const Root = (contextMenuProps: ContextMenuPrimitive.ContextMenuProps) => (
|
|
9
10
|
<ContextMenuPrimitive.Root dir="ltr" {...contextMenuProps} />
|
|
@@ -94,12 +95,14 @@ export type ContentProps = ContextMenuPrimitive.ContextMenuContentProps;
|
|
|
94
95
|
export const Content = forwardRef<HTMLDivElement, ContentProps>(function ContextMenuContent({className, ...rest}, ref) {
|
|
95
96
|
return (
|
|
96
97
|
<ContextMenuPrimitive.Portal>
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
<RadixPortalThemeProvider>
|
|
99
|
+
<ContextMenuPrimitive.Content
|
|
100
|
+
ref={ref}
|
|
101
|
+
className={cx(dropdownMenuContentStyles, className)}
|
|
102
|
+
collisionPadding={space.s12 + space.s8}
|
|
103
|
+
{...rest}
|
|
104
|
+
/>
|
|
105
|
+
</RadixPortalThemeProvider>
|
|
103
106
|
</ContextMenuPrimitive.Portal>
|
|
104
107
|
);
|
|
105
108
|
});
|
|
@@ -132,7 +135,9 @@ export const SubContent = forwardRef<HTMLDivElement, ContextMenuPrimitive.Contex
|
|
|
132
135
|
function DropdownMenuSubContent({className, ...rest}, ref) {
|
|
133
136
|
return (
|
|
134
137
|
<ContextMenuPrimitive.Portal>
|
|
135
|
-
<
|
|
138
|
+
<RadixPortalThemeProvider>
|
|
139
|
+
<ContextMenuPrimitive.SubContent ref={ref} className={cx(dropdownMenuContentStyles, className)} {...rest} />
|
|
140
|
+
</RadixPortalThemeProvider>
|
|
136
141
|
</ContextMenuPrimitive.Portal>
|
|
137
142
|
);
|
|
138
143
|
}
|
|
@@ -7,7 +7,7 @@ import {css} from "@linaria/core";
|
|
|
7
7
|
import "react-day-picker/dist/style.css";
|
|
8
8
|
import {stopPropagation} from "@fibery/react/src/stop-propagation";
|
|
9
9
|
import {forwardRef, useCallback, useRef} from "react";
|
|
10
|
-
import
|
|
10
|
+
import omit from "lodash/omit";
|
|
11
11
|
import moment from "moment";
|
|
12
12
|
import {FakeDateInputWrapper} from "./fake-date-input";
|
|
13
13
|
import {formatDateRangeInputValue} from "./utils";
|
|
@@ -27,7 +27,6 @@ export const DateRangePicker = forwardRef<
|
|
|
27
27
|
bypassedRef,
|
|
28
28
|
value,
|
|
29
29
|
disabled = false,
|
|
30
|
-
renderInPortal = true,
|
|
31
30
|
onChange,
|
|
32
31
|
showTime = false,
|
|
33
32
|
dateFormat,
|
|
@@ -107,14 +106,14 @@ export const DateRangePicker = forwardRef<
|
|
|
107
106
|
popupContainerClassName={css`
|
|
108
107
|
z-index: 10001;
|
|
109
108
|
`}
|
|
110
|
-
renderInPortal={
|
|
109
|
+
renderInPortal={true}
|
|
111
110
|
preventOverflowOptions={{
|
|
112
111
|
altAxis: true,
|
|
113
112
|
}}
|
|
114
113
|
>
|
|
115
114
|
<DateRangePickerPopupContent
|
|
116
115
|
ref={ref}
|
|
117
|
-
{...
|
|
116
|
+
{...omit(props, ["onChange", "value"])}
|
|
118
117
|
onChange={onDatesChange}
|
|
119
118
|
value={dateValue}
|
|
120
119
|
onKeyDown={onDatePickerKeyDown}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ControlledDatePickerProps,
|
|
3
|
+
RelativeDateValue,
|
|
4
|
+
SingleDatePickerPopoverContentProps,
|
|
5
|
+
SingleDatePickerProps,
|
|
6
|
+
} from "./types";
|
|
2
7
|
import {FakeDateInputWrapper} from "./fake-date-input";
|
|
3
8
|
import {space, themeVars} from "../design-system";
|
|
4
9
|
import {withPopupControl} from "./with-popup-control";
|
|
5
|
-
import {css} from "@linaria/core";
|
|
10
|
+
import {css, cx} from "@linaria/core";
|
|
6
11
|
import "react-day-picker/dist/style.css";
|
|
7
12
|
import {SingleDatePickerPopupContent} from "./single-date-picker-popup-content";
|
|
8
13
|
import {stopPropagation} from "@fibery/react/src/stop-propagation";
|
|
9
14
|
import {forwardRef, useCallback, useRef, useState} from "react";
|
|
10
15
|
import moment, {Moment} from "moment";
|
|
11
|
-
import
|
|
16
|
+
import omit from "lodash/omit";
|
|
12
17
|
import {EmptyValue} from "../empty-value";
|
|
13
18
|
import {formatDateInputValue} from "./utils";
|
|
14
|
-
import {
|
|
19
|
+
import {Popover} from "../popover";
|
|
15
20
|
import {focusable} from "tabbable";
|
|
16
21
|
import {TabNavLink, TabNavList, TabNavRoot} from "../tab-nav/tab-nav";
|
|
17
22
|
import {RelativeDatePicker} from "./relative-date-picker";
|
|
@@ -69,43 +74,18 @@ interface ControlledSingleDatePickerWithForwardRefType extends React.FC<Uncontro
|
|
|
69
74
|
>;
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
type DatePickerRef = {
|
|
78
|
+
setValue: (value: string) => void;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const SingleDatePickerPopoverContent = forwardRef<
|
|
82
|
+
DatePickerRef,
|
|
83
|
+
{className?: string} & SingleDatePickerPopoverContentProps<boolean>
|
|
77
84
|
>((props, ref) => {
|
|
78
|
-
const {
|
|
79
|
-
title,
|
|
80
|
-
open,
|
|
81
|
-
onOpen,
|
|
82
|
-
onClose,
|
|
83
|
-
children,
|
|
84
|
-
bypassedRef,
|
|
85
|
-
value,
|
|
86
|
-
disabled = false,
|
|
87
|
-
placeholder,
|
|
88
|
-
renderInPortal = true,
|
|
89
|
-
onChange,
|
|
90
|
-
showTime = false,
|
|
91
|
-
dateFormat,
|
|
92
|
-
dateTimeFormat,
|
|
93
|
-
onKeyDown,
|
|
94
|
-
allowRelativeDate = false,
|
|
95
|
-
relativeDateToExactDate,
|
|
96
|
-
} = props;
|
|
85
|
+
const {className, value, onChange, onKeyDown, allowRelativeDate = false, relativeDateToExactDate} = props;
|
|
97
86
|
|
|
98
87
|
const isRelativeValue = allowRelativeDate ? isRelativeDatePlaceholder(value) : false;
|
|
99
88
|
|
|
100
|
-
const dateValueFormatted = isRelativeValue
|
|
101
|
-
? formatRelativeDate(value as RelativeDateValue)
|
|
102
|
-
: value
|
|
103
|
-
? formatDateInputValue((value as Moment).toDate(), {
|
|
104
|
-
showTime,
|
|
105
|
-
dateFormat,
|
|
106
|
-
dateTimeFormat,
|
|
107
|
-
})
|
|
108
|
-
: null;
|
|
109
89
|
const onDateChange = useCallback(
|
|
110
90
|
(value: Date | null) => {
|
|
111
91
|
// @ts-expect-error fix types
|
|
@@ -124,12 +104,6 @@ export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
|
|
|
124
104
|
|
|
125
105
|
const fakeWrapperRef = useRef<HTMLDivElement>(null);
|
|
126
106
|
|
|
127
|
-
const pickerValue = children || (
|
|
128
|
-
<FakeDateInputWrapper disabled={disabled} isPickerOpen={open}>
|
|
129
|
-
{!dateValueFormatted ? <EmptyValue>{placeholder}</EmptyValue> : <>{dateValueFormatted}</>}
|
|
130
|
-
</FakeDateInputWrapper>
|
|
131
|
-
);
|
|
132
|
-
|
|
133
107
|
const onDatePickerKeyDown = useCallback(
|
|
134
108
|
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
135
109
|
if (e.key === "Tab" || e.key === "Enter") {
|
|
@@ -151,93 +125,147 @@ export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
|
|
|
151
125
|
allowRelativeDate && (isRelativeValue || value === null) ? "relative" : "exact"
|
|
152
126
|
);
|
|
153
127
|
|
|
128
|
+
return (
|
|
129
|
+
<div
|
|
130
|
+
className={cx(
|
|
131
|
+
css`
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
`,
|
|
135
|
+
allowRelativeDate &&
|
|
136
|
+
css`
|
|
137
|
+
min-width: 320px;
|
|
138
|
+
`,
|
|
139
|
+
className
|
|
140
|
+
)}
|
|
141
|
+
>
|
|
142
|
+
{allowRelativeDate ? (
|
|
143
|
+
<div
|
|
144
|
+
className={css`
|
|
145
|
+
border-bottom: ${themeVars.separators.opacity5};
|
|
146
|
+
`}
|
|
147
|
+
>
|
|
148
|
+
<TabNavRoot>
|
|
149
|
+
<TabNavList
|
|
150
|
+
className={css`
|
|
151
|
+
padding-left: ${space.s12}px;
|
|
152
|
+
padding-right: ${space.s12}px;
|
|
153
|
+
padding-top: ${space.s6}px;
|
|
154
|
+
display: flex;
|
|
155
|
+
width: 100%;
|
|
156
|
+
justify-content: space-evenly;
|
|
157
|
+
`}
|
|
158
|
+
>
|
|
159
|
+
<TabNavLink
|
|
160
|
+
className={tabNavLinkClassName}
|
|
161
|
+
itemClassName={tabItemClassName}
|
|
162
|
+
active={activeButton === "relative"}
|
|
163
|
+
onSelect={() => setActiveButton("relative")}
|
|
164
|
+
>
|
|
165
|
+
Relative
|
|
166
|
+
</TabNavLink>
|
|
167
|
+
<TabNavLink
|
|
168
|
+
className={tabNavLinkClassName}
|
|
169
|
+
itemClassName={tabItemClassName}
|
|
170
|
+
active={activeButton === "exact"}
|
|
171
|
+
onSelect={() => setActiveButton("exact")}
|
|
172
|
+
>
|
|
173
|
+
Exact
|
|
174
|
+
</TabNavLink>
|
|
175
|
+
</TabNavList>
|
|
176
|
+
</TabNavRoot>
|
|
177
|
+
</div>
|
|
178
|
+
) : null}
|
|
179
|
+
<div>
|
|
180
|
+
{!allowRelativeDate || activeButton === "exact" ? (
|
|
181
|
+
<SingleDatePickerPopupContent
|
|
182
|
+
ref={ref}
|
|
183
|
+
{...omit(props, ["onChange", "value"])}
|
|
184
|
+
onChange={onDateChange}
|
|
185
|
+
value={!isRelativeValue && value ? (value as Moment).toDate() : null}
|
|
186
|
+
onKeyDown={onDatePickerKeyDown}
|
|
187
|
+
/>
|
|
188
|
+
) : (
|
|
189
|
+
<RelativeDatePicker
|
|
190
|
+
value={isRelativeValue ? (value as RelativeDateValue) : null}
|
|
191
|
+
onChange={onRelativeDateChange}
|
|
192
|
+
relativeDateToExactDate={relativeDateToExactDate}
|
|
193
|
+
/>
|
|
194
|
+
)}
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
|
|
201
|
+
DatePickerRef,
|
|
202
|
+
SingleDatePickerProps<boolean>
|
|
203
|
+
>((props, ref) => {
|
|
204
|
+
const {
|
|
205
|
+
title,
|
|
206
|
+
open,
|
|
207
|
+
onOpen,
|
|
208
|
+
onClose,
|
|
209
|
+
children,
|
|
210
|
+
bypassedRef,
|
|
211
|
+
value,
|
|
212
|
+
disabled = false,
|
|
213
|
+
placeholder,
|
|
214
|
+
showTime = false,
|
|
215
|
+
dateFormat,
|
|
216
|
+
dateTimeFormat,
|
|
217
|
+
allowRelativeDate = false,
|
|
218
|
+
} = props;
|
|
219
|
+
|
|
220
|
+
const isRelativeValue = allowRelativeDate ? isRelativeDatePlaceholder(value) : false;
|
|
221
|
+
|
|
222
|
+
const dateValueFormatted = isRelativeValue
|
|
223
|
+
? formatRelativeDate(value as RelativeDateValue)
|
|
224
|
+
: value
|
|
225
|
+
? formatDateInputValue((value as Moment).toDate(), {
|
|
226
|
+
showTime,
|
|
227
|
+
dateFormat,
|
|
228
|
+
dateTimeFormat,
|
|
229
|
+
})
|
|
230
|
+
: null;
|
|
231
|
+
|
|
232
|
+
const fakeWrapperRef = useRef<HTMLDivElement>(null);
|
|
233
|
+
|
|
234
|
+
const pickerValue = children || (
|
|
235
|
+
<FakeDateInputWrapper disabled={disabled} isPickerOpen={open}>
|
|
236
|
+
{!dateValueFormatted ? <EmptyValue>{placeholder}</EmptyValue> : <>{dateValueFormatted}</>}
|
|
237
|
+
</FakeDateInputWrapper>
|
|
238
|
+
);
|
|
239
|
+
|
|
154
240
|
if (disabled) {
|
|
155
241
|
return pickerValue;
|
|
156
242
|
}
|
|
157
243
|
|
|
158
244
|
return (
|
|
159
245
|
<div ref={bypassedRef}>
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
offset={[0, space.s6]}
|
|
163
|
-
trigger={
|
|
246
|
+
<Popover.Root open={open} onOpen={onOpen} onClose={onClose}>
|
|
247
|
+
<Popover.Trigger>
|
|
164
248
|
<div ref={fakeWrapperRef} onClick={stopPropagation}>
|
|
165
249
|
{pickerValue}
|
|
166
250
|
</div>
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
renderInPortal={renderInPortal}
|
|
177
|
-
preventOverflowOptions={{
|
|
178
|
-
altAxis: true,
|
|
179
|
-
}}
|
|
180
|
-
>
|
|
181
|
-
{allowRelativeDate ? (
|
|
182
|
-
<div
|
|
183
|
-
className={css`
|
|
184
|
-
border-bottom: ${themeVars.separators.opacity5};
|
|
251
|
+
</Popover.Trigger>
|
|
252
|
+
<Popover.Portal>
|
|
253
|
+
<Popover.Content
|
|
254
|
+
title={title}
|
|
255
|
+
offset={[0, space.s6]}
|
|
256
|
+
placement="bottom-start"
|
|
257
|
+
supportMobile
|
|
258
|
+
popupContainerClassName={css`
|
|
259
|
+
z-index: 10001;
|
|
185
260
|
`}
|
|
261
|
+
preventOverflowOptions={{
|
|
262
|
+
altAxis: true,
|
|
263
|
+
}}
|
|
186
264
|
>
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
padding-right: ${space.s12}px;
|
|
192
|
-
padding-top: ${space.s6}px;
|
|
193
|
-
display: flex;
|
|
194
|
-
width: 100%;
|
|
195
|
-
justify-content: space-evenly;
|
|
196
|
-
`}
|
|
197
|
-
>
|
|
198
|
-
<TabNavLink
|
|
199
|
-
className={tabNavLinkClassName}
|
|
200
|
-
itemClassName={tabItemClassName}
|
|
201
|
-
active={activeButton === "relative"}
|
|
202
|
-
onSelect={() => setActiveButton("relative")}
|
|
203
|
-
>
|
|
204
|
-
Relative
|
|
205
|
-
</TabNavLink>
|
|
206
|
-
<TabNavLink
|
|
207
|
-
className={tabNavLinkClassName}
|
|
208
|
-
itemClassName={tabItemClassName}
|
|
209
|
-
active={activeButton === "exact"}
|
|
210
|
-
onSelect={() => setActiveButton("exact")}
|
|
211
|
-
>
|
|
212
|
-
Exact
|
|
213
|
-
</TabNavLink>
|
|
214
|
-
</TabNavList>
|
|
215
|
-
</TabNavRoot>
|
|
216
|
-
</div>
|
|
217
|
-
) : null}
|
|
218
|
-
<div
|
|
219
|
-
style={allowRelativeDate ? {minWidth: 320} : undefined}
|
|
220
|
-
className={css`
|
|
221
|
-
width: 100%;
|
|
222
|
-
`}
|
|
223
|
-
>
|
|
224
|
-
{!allowRelativeDate || activeButton === "exact" ? (
|
|
225
|
-
<SingleDatePickerPopupContent
|
|
226
|
-
ref={ref}
|
|
227
|
-
{..._.omit(props, ["onChange", "value"])}
|
|
228
|
-
onChange={onDateChange}
|
|
229
|
-
value={!isRelativeValue && value ? (value as Moment).toDate() : null}
|
|
230
|
-
onKeyDown={onDatePickerKeyDown}
|
|
231
|
-
/>
|
|
232
|
-
) : (
|
|
233
|
-
<RelativeDatePicker
|
|
234
|
-
value={isRelativeValue ? (value as RelativeDateValue) : null}
|
|
235
|
-
onChange={onRelativeDateChange}
|
|
236
|
-
relativeDateToExactDate={relativeDateToExactDate}
|
|
237
|
-
/>
|
|
238
|
-
)}
|
|
239
|
-
</div>
|
|
240
|
-
</PopoverOld>
|
|
265
|
+
<SingleDatePickerPopoverContent ref={ref} {...props} />
|
|
266
|
+
</Popover.Content>
|
|
267
|
+
</Popover.Portal>
|
|
268
|
+
</Popover.Root>
|
|
241
269
|
</div>
|
|
242
270
|
);
|
|
243
271
|
});
|
package/src/date-picker/types.ts
CHANGED
|
@@ -27,7 +27,6 @@ export type DatePickerCommonProps = {
|
|
|
27
27
|
allowClear?: boolean;
|
|
28
28
|
bypassedRef?: React.Ref<$TSFixMe>;
|
|
29
29
|
disabled?: boolean;
|
|
30
|
-
renderInPortal?: boolean;
|
|
31
30
|
onKeyDown?: React.KeyboardEventHandler<$TSFixMe>;
|
|
32
31
|
placeholder: string;
|
|
33
32
|
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined;
|
|
@@ -49,10 +48,12 @@ export type NativeDateRangePickerProps = {
|
|
|
49
48
|
|
|
50
49
|
export type ControlledDatePickerProps = {open: boolean; onOpen: () => void; onClose: () => void};
|
|
51
50
|
|
|
52
|
-
export type
|
|
53
|
-
ControlledDatePickerProps &
|
|
51
|
+
export type SingleDatePickerPopoverContentProps<IsRelativeDate extends boolean = false> = DatePickerCommonProps &
|
|
54
52
|
MomentSingleDateProps<IsRelativeDate> & {
|
|
55
53
|
allowRelativeDate?: IsRelativeDate;
|
|
56
54
|
} & (IsRelativeDate extends true
|
|
57
55
|
? {relativeDateToExactDate?: (value: RelativeDateValue) => string} // Required if IsRelativeDate is true
|
|
58
56
|
: {relativeDateToExactDate?: never}); // Undefined if IsRelativeDate is false;
|
|
57
|
+
|
|
58
|
+
export type SingleDatePickerProps<IsRelativeDate extends boolean = false> = ControlledDatePickerProps &
|
|
59
|
+
SingleDatePickerPopoverContentProps<IsRelativeDate>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import range from "lodash/range";
|
|
2
2
|
import {DaySelect, Props} from "./day-select";
|
|
3
3
|
import moment from "moment";
|
|
4
4
|
|
|
5
|
-
const isoWeekDays =
|
|
5
|
+
const isoWeekDays = range(1, 8).map((day) => {
|
|
6
6
|
return {
|
|
7
7
|
key: String(day),
|
|
8
8
|
title: moment().isoWeekday(day).format("dd").charAt(0),
|