@oxy.so/bloom 2.12.2 → 2.12.3
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/lib/commonjs/button/shared.js +10 -1
- package/lib/commonjs/button/shared.js.map +1 -1
- package/lib/commonjs/sidebar/Sidebar.js +5 -1
- package/lib/commonjs/sidebar/Sidebar.js.map +1 -1
- package/lib/commonjs/sidebar/SidebarModeSwitcher.js +14 -20
- package/lib/commonjs/sidebar/SidebarModeSwitcher.js.map +1 -1
- package/lib/commonjs/sidebar/palette.js +2 -0
- package/lib/commonjs/sidebar/palette.js.map +1 -1
- package/lib/commonjs/social-button/OxyMark.js +4 -2
- package/lib/commonjs/social-button/OxyMark.js.map +1 -1
- package/lib/commonjs/social-button/SocialButton.js +2 -1
- package/lib/commonjs/social-button/SocialButton.js.map +1 -1
- package/lib/commonjs/social-button/use-svg-id.js +16 -0
- package/lib/commonjs/social-button/use-svg-id.js.map +1 -0
- package/lib/commonjs/theme-toggle/ThemeToggle.js +2 -2
- package/lib/commonjs/theme-toggle/ThemeToggle.js.map +1 -1
- package/lib/module/button/shared.js +9 -0
- package/lib/module/button/shared.js.map +1 -1
- package/lib/module/sidebar/Sidebar.js +5 -1
- package/lib/module/sidebar/Sidebar.js.map +1 -1
- package/lib/module/sidebar/SidebarModeSwitcher.js +16 -22
- package/lib/module/sidebar/SidebarModeSwitcher.js.map +1 -1
- package/lib/module/sidebar/palette.js +3 -1
- package/lib/module/sidebar/palette.js.map +1 -1
- package/lib/module/social-button/OxyMark.js +3 -2
- package/lib/module/social-button/OxyMark.js.map +1 -1
- package/lib/module/social-button/SocialButton.js +3 -2
- package/lib/module/social-button/SocialButton.js.map +1 -1
- package/lib/module/social-button/use-svg-id.js +13 -0
- package/lib/module/social-button/use-svg-id.js.map +1 -0
- package/lib/module/theme-toggle/ThemeToggle.js +3 -3
- package/lib/module/theme-toggle/ThemeToggle.js.map +1 -1
- package/lib/typescript/commonjs/button/shared.d.ts +8 -0
- package/lib/typescript/commonjs/button/shared.d.ts.map +1 -1
- package/lib/typescript/commonjs/sidebar/Sidebar.d.ts.map +1 -1
- package/lib/typescript/commonjs/sidebar/SidebarModeSwitcher.d.ts.map +1 -1
- package/lib/typescript/commonjs/sidebar/palette.d.ts +3 -0
- package/lib/typescript/commonjs/sidebar/palette.d.ts.map +1 -1
- package/lib/typescript/commonjs/social-button/OxyMark.d.ts.map +1 -1
- package/lib/typescript/commonjs/social-button/SocialButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/social-button/use-svg-id.d.ts +7 -0
- package/lib/typescript/commonjs/social-button/use-svg-id.d.ts.map +1 -0
- package/lib/typescript/commonjs/theme-toggle/ThemeToggle.d.ts.map +1 -1
- package/lib/typescript/module/button/shared.d.ts +8 -0
- package/lib/typescript/module/button/shared.d.ts.map +1 -1
- package/lib/typescript/module/sidebar/Sidebar.d.ts.map +1 -1
- package/lib/typescript/module/sidebar/SidebarModeSwitcher.d.ts.map +1 -1
- package/lib/typescript/module/sidebar/palette.d.ts +3 -0
- package/lib/typescript/module/sidebar/palette.d.ts.map +1 -1
- package/lib/typescript/module/social-button/OxyMark.d.ts.map +1 -1
- package/lib/typescript/module/social-button/SocialButton.d.ts.map +1 -1
- package/lib/typescript/module/social-button/use-svg-id.d.ts +7 -0
- package/lib/typescript/module/social-button/use-svg-id.d.ts.map +1 -0
- package/lib/typescript/module/theme-toggle/ThemeToggle.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/button/shared.ts +9 -0
- package/src/sidebar/Sidebar.tsx +5 -1
- package/src/sidebar/SidebarModeSwitcher.tsx +13 -14
- package/src/sidebar/palette.ts +6 -1
- package/src/social-button/OxyMark.tsx +4 -2
- package/src/social-button/SocialButton.tsx +3 -2
- package/src/social-button/use-svg-id.ts +10 -0
- package/src/theme-toggle/ThemeToggle.tsx +3 -9
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DOM-safe id prefix, per component instance. Two marks of one brand on a
|
|
3
|
+
* page must not resolve each other's `url(#…)`, and React's `useId` carries
|
|
4
|
+
* characters an SVG id cannot.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useSvgIdPrefix(prefix: string): string;
|
|
7
|
+
//# sourceMappingURL=use-svg-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-svg-id.d.ts","sourceRoot":"","sources":["../../../../src/social-button/use-svg-id.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeToggle.d.ts","sourceRoot":"","sources":["../../../../src/theme-toggle/ThemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ThemeToggle.d.ts","sourceRoot":"","sources":["../../../../src/theme-toggle/ThemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwD,MAAM,OAAO,CAAC;AA0B7E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqCvE,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;IACjE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,qBAAqB,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,aAAa,CAuCrE;AAkcD,eAAO,MAAM,WAAW,8CAA6B,CAAC"}
|
package/package.json
CHANGED
package/src/button/shared.ts
CHANGED
|
@@ -178,6 +178,15 @@ export const BUTTON_SIZE_ALIAS: Record<ButtonSize, ButtonResolvedSize> = {
|
|
|
178
178
|
/** The button's transition duration. */
|
|
179
179
|
export const BUTTON_TRANSITION_MS = 150;
|
|
180
180
|
|
|
181
|
+
/**
|
|
182
|
+
* The sliding thumb of a segmented control — the sidebar theme toggle and the
|
|
183
|
+
* sidebar's mode switcher — so the two move at one speed on one curve.
|
|
184
|
+
*/
|
|
185
|
+
export const SEGMENTED_THUMB_MS = 200;
|
|
186
|
+
/** Control points for `Easing.bezier(...)` — the constant itself stays out of
|
|
187
|
+
* this module, which every family imports and which must not pull Reanimated in. */
|
|
188
|
+
export const SEGMENTED_THUMB_EASE_BEZIER = [0.25, 0.1, 0.25, 1] as const;
|
|
189
|
+
|
|
181
190
|
/** Tailwind v4 `shadow-xs`, and its dark-mode override. */
|
|
182
191
|
export const BUTTON_SHADOW = {
|
|
183
192
|
light: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
|
package/src/sidebar/Sidebar.tsx
CHANGED
|
@@ -480,12 +480,16 @@ const SidebarPanel: React.FC<SidebarProps> = ({
|
|
|
480
480
|
shownItems.length === 0 && shownSecondary.length === 0 && shownFolders.length === 0 && !collapsed;
|
|
481
481
|
const hasTree = !!tree;
|
|
482
482
|
|
|
483
|
+
// A fresh closure here would re-render the memoised switcher on every
|
|
484
|
+
// keystroke in the quick-search field.
|
|
485
|
+
const handleModeChange = useCallback((key: string) => onModeChange?.(key), [onModeChange]);
|
|
486
|
+
|
|
483
487
|
const modeSwitcher =
|
|
484
488
|
modes && modes.length > 0 ? (
|
|
485
489
|
<SidebarModeSwitcher
|
|
486
490
|
modes={modes}
|
|
487
491
|
value={mode ?? modes[0]!.key}
|
|
488
|
-
onValueChange={
|
|
492
|
+
onValueChange={handleModeChange}
|
|
489
493
|
collapsed={collapsed}
|
|
490
494
|
accessibilityLabel={modesLabel}
|
|
491
495
|
testID={testID ? `${testID}-modes` : 'sidebar-modes'}
|
|
@@ -8,14 +8,13 @@ import Animated, {
|
|
|
8
8
|
withTiming,
|
|
9
9
|
} from 'react-native-reanimated';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { SEGMENTED_THUMB_EASE_BEZIER, SEGMENTED_THUMB_MS } from '../button/shared';
|
|
12
12
|
import { useInteractionState } from '../hooks/use-interaction-state';
|
|
13
13
|
import { borderRadius } from '../styles/tokens';
|
|
14
14
|
import type { WebCssStyle } from '../styles/web-view-style';
|
|
15
|
-
import { useTheme } from '../theme/use-theme';
|
|
16
15
|
import { Text } from '../typography';
|
|
17
16
|
import { useSidebarPalette } from './palette';
|
|
18
|
-
import { Collapsible, IS_WEB, useSidebarWebCss } from './parts';
|
|
17
|
+
import { Collapsible, IS_WEB, useSidebarWebCss, webHook } from './parts';
|
|
19
18
|
import type { SidebarMode, SidebarModeSwitcherProps } from './types';
|
|
20
19
|
|
|
21
20
|
/**
|
|
@@ -37,8 +36,7 @@ import type { SidebarMode, SidebarModeSwitcherProps } from './types';
|
|
|
37
36
|
const ROW_HEIGHT = 32;
|
|
38
37
|
const ROW_GAP = 4;
|
|
39
38
|
const PADDING = 4;
|
|
40
|
-
const
|
|
41
|
-
const EASE = Easing.bezier(0.25, 0.1, 0.25, 1);
|
|
39
|
+
const EASE = Easing.bezier(...SEGMENTED_THUMB_EASE_BEZIER);
|
|
42
40
|
|
|
43
41
|
function ModeRow({
|
|
44
42
|
mode,
|
|
@@ -69,7 +67,8 @@ function ModeRow({
|
|
|
69
67
|
|
|
70
68
|
return (
|
|
71
69
|
<Pressable
|
|
72
|
-
{...(
|
|
70
|
+
{...webHook('ring')}
|
|
71
|
+
{...(IS_WEB && collapsed ? { title: mode.label } : null)}
|
|
73
72
|
role="radio"
|
|
74
73
|
aria-checked={selected}
|
|
75
74
|
accessibilityState={{ checked: selected }}
|
|
@@ -112,22 +111,22 @@ const SidebarModeSwitcherComponent: React.FC<SidebarModeSwitcherProps> = ({
|
|
|
112
111
|
style,
|
|
113
112
|
testID,
|
|
114
113
|
}) => {
|
|
115
|
-
const theme = useTheme();
|
|
116
114
|
const palette = useSidebarPalette();
|
|
117
115
|
useSidebarWebCss();
|
|
118
116
|
const reducedMotion = useReducedMotion();
|
|
119
|
-
const { neutral: n } = resolveButtonRamps(theme);
|
|
120
117
|
|
|
121
|
-
|
|
118
|
+
// One scan answers both questions: which row the thumb sits on, and whether
|
|
119
|
+
// there is a selected row at all.
|
|
120
|
+
const selectedIndex = modes.findIndex((mode) => mode.key === value);
|
|
121
|
+
const selectedKnown = selectedIndex !== -1;
|
|
122
|
+
const index = Math.max(0, selectedIndex);
|
|
122
123
|
const offset = useSharedValue(index * (ROW_HEIGHT + ROW_GAP));
|
|
123
124
|
useEffect(() => {
|
|
124
125
|
const target = index * (ROW_HEIGHT + ROW_GAP);
|
|
125
|
-
offset.value = reducedMotion ? target : withTiming(target, { duration:
|
|
126
|
+
offset.value = reducedMotion ? target : withTiming(target, { duration: SEGMENTED_THUMB_MS, easing: EASE });
|
|
126
127
|
}, [index, reducedMotion, offset]);
|
|
127
128
|
const thumbStyle = useAnimatedStyle(() => ({ transform: [{ translateY: offset.value }] }), [offset]);
|
|
128
129
|
|
|
129
|
-
const selectedKnown = modes.some((mode) => mode.key === value);
|
|
130
|
-
|
|
131
130
|
return (
|
|
132
131
|
<View
|
|
133
132
|
role="radiogroup"
|
|
@@ -158,8 +157,8 @@ const SidebarModeSwitcherComponent: React.FC<SidebarModeSwitcherProps> = ({
|
|
|
158
157
|
right: PADDING,
|
|
159
158
|
height: ROW_HEIGHT,
|
|
160
159
|
borderRadius: borderRadius.full,
|
|
161
|
-
backgroundColor:
|
|
162
|
-
boxShadow:
|
|
160
|
+
backgroundColor: palette.segmentedThumb,
|
|
161
|
+
boxShadow: palette.segmentedThumbShadow,
|
|
163
162
|
},
|
|
164
163
|
thumbStyle,
|
|
165
164
|
]}
|
package/src/sidebar/palette.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
|
|
3
|
-
import { ACCENT_TABLE, colorRamp, mixColor, resolveButtonRamps } from '../button/shared';
|
|
3
|
+
import { ACCENT_TABLE, BUTTON_SHADOW, colorRamp, mixColor, resolveButtonRamps } from '../button/shared';
|
|
4
4
|
import { MENU_SHADOW } from '../floating/menu-palette';
|
|
5
5
|
import { PANEL_SHADOW, resolvePanelChrome } from '../styles/panel-chrome';
|
|
6
6
|
import { hairlineOn } from '../styles/surface-levels';
|
|
@@ -49,6 +49,9 @@ export interface SidebarPalette {
|
|
|
49
49
|
flat: string;
|
|
50
50
|
rowHover: string;
|
|
51
51
|
tertiary: string;
|
|
52
|
+
/** Fill and shadow of a segmented control's sliding thumb (the mode switcher). */
|
|
53
|
+
segmentedThumb: string;
|
|
54
|
+
segmentedThumbShadow: string;
|
|
52
55
|
tertiaryHover: string;
|
|
53
56
|
searchHover: string;
|
|
54
57
|
searchRing: string;
|
|
@@ -113,6 +116,8 @@ export function resolveSidebarPalette(theme: Theme): SidebarPalette {
|
|
|
113
116
|
flat: dark ? mixColor(n[900], n[950], 0.4) : card,
|
|
114
117
|
rowHover: dark ? n[800] : n[200],
|
|
115
118
|
tertiary: dark ? n[800] : n[200],
|
|
119
|
+
segmentedThumb: dark ? n[700] : card,
|
|
120
|
+
segmentedThumbShadow: dark ? BUTTON_SHADOW.dark : BUTTON_SHADOW.light,
|
|
116
121
|
tertiaryHover: dark ? n[700] : n[300],
|
|
117
122
|
// `hover:bg-background-tertiary-hover/55` over the panel.
|
|
118
123
|
searchHover: mixColor(panel, dark ? n[700] : n[300], 0.55),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import Svg, { ClipPath, Defs, G, Path } from 'react-native-svg';
|
|
3
3
|
|
|
4
|
+
import { useSvgIdPrefix } from './use-svg-id';
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* The Oxy mark for `SocialButton` — the same drawing the Oxy SDK ships.
|
|
6
8
|
*
|
|
@@ -29,7 +31,7 @@ export interface OxyMarkProps {
|
|
|
29
31
|
|
|
30
32
|
export function OxyMark({ size, color, letterColor }: OxyMarkProps) {
|
|
31
33
|
// Two marks on one page must not resolve each other's clip path.
|
|
32
|
-
const clipId =
|
|
34
|
+
const clipId = useSvgIdPrefix('bloom-oxy-mark');
|
|
33
35
|
return (
|
|
34
36
|
<Svg width={size} height={size} viewBox={OXY_MARK_VIEW_BOX} aria-hidden>
|
|
35
37
|
<Defs>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { memo, useCallback,
|
|
1
|
+
import React, { memo, useCallback, useMemo } from 'react';
|
|
2
2
|
import { Linking, Platform, View, type TextStyle, type ViewStyle } from 'react-native';
|
|
3
3
|
import Svg, { Circle, Defs, LinearGradient, Path, Stop } from 'react-native-svg';
|
|
4
4
|
|
|
@@ -20,6 +20,7 @@ import { StyledPressable } from '../styles/styled-primitives';
|
|
|
20
20
|
import type { WebCssStyle } from '../styles/web-view-style';
|
|
21
21
|
import { SOCIAL_COLOR_LOGOS } from './color-logos';
|
|
22
22
|
import { OxyMark } from './OxyMark';
|
|
23
|
+
import { useSvgIdPrefix } from './use-svg-id';
|
|
23
24
|
import { SOCIAL_PROVIDERS, type SocialColorLogo, type SocialProvider } from './providers';
|
|
24
25
|
import type {
|
|
25
26
|
SocialBrand,
|
|
@@ -343,7 +344,7 @@ function ColorLogo({
|
|
|
343
344
|
}) {
|
|
344
345
|
// Gradient ids are per logo upstream; two buttons of one brand on a page must
|
|
345
346
|
// not resolve each other's `url(#…)`, so every id is prefixed per instance.
|
|
346
|
-
const prefix =
|
|
347
|
+
const prefix = useSvgIdPrefix('bloom-social');
|
|
347
348
|
const resolveFill = (fill: string) =>
|
|
348
349
|
fill.startsWith('url(#') ? `url(#${prefix}${fill.slice(5)}` : fill;
|
|
349
350
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useId } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A DOM-safe id prefix, per component instance. Two marks of one brand on a
|
|
5
|
+
* page must not resolve each other's `url(#…)`, and React's `useId` carries
|
|
6
|
+
* characters an SVG id cannot.
|
|
7
|
+
*/
|
|
8
|
+
export function useSvgIdPrefix(prefix: string): string {
|
|
9
|
+
return `${prefix}-${useId().replace(/[^a-zA-Z0-9]/g, '')}-`;
|
|
10
|
+
}
|
|
@@ -17,13 +17,7 @@ import Animated, {
|
|
|
17
17
|
} from 'react-native-reanimated';
|
|
18
18
|
import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg';
|
|
19
19
|
|
|
20
|
-
import {
|
|
21
|
-
ACCENT_TABLE,
|
|
22
|
-
BUTTON_SHADOW,
|
|
23
|
-
colorRamp,
|
|
24
|
-
mixColor,
|
|
25
|
-
resolveButtonRamps,
|
|
26
|
-
} from '../button/shared';
|
|
20
|
+
import { ACCENT_TABLE, BUTTON_SHADOW, SEGMENTED_THUMB_EASE_BEZIER, SEGMENTED_THUMB_MS, colorRamp, mixColor, resolveButtonRamps } from '../button/shared';
|
|
27
21
|
import { useInteractionState } from '../hooks/use-interaction-state';
|
|
28
22
|
import { RiMoonLine, RiSunLine } from '../icons/remix';
|
|
29
23
|
import { adoptStyleSheet } from '../styles/adopt-style-sheet';
|
|
@@ -66,8 +60,8 @@ import { revealTheme, THEME_TRANSITION_DURATION, type RevealOrigin } from './vie
|
|
|
66
60
|
*/
|
|
67
61
|
|
|
68
62
|
const IS_WEB = Platform.OS === 'web';
|
|
69
|
-
const EASE = Easing.bezier(
|
|
70
|
-
const THUMB_MS =
|
|
63
|
+
const EASE = Easing.bezier(...SEGMENTED_THUMB_EASE_BEZIER);
|
|
64
|
+
const THUMB_MS = SEGMENTED_THUMB_MS;
|
|
71
65
|
const HOVER_MS = 150;
|
|
72
66
|
|
|
73
67
|
interface TogglePalette {
|