@oxyhq/bloom 0.5.0 → 0.6.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/lib/commonjs/error-boundary/ErrorBoundary.js +27 -7
- package/lib/commonjs/error-boundary/ErrorBoundary.js.map +1 -1
- package/lib/commonjs/fonts/FontLoader.js +6 -5
- package/lib/commonjs/fonts/FontLoader.js.map +1 -1
- package/lib/commonjs/fonts/apply-font-faces.js +4 -4
- package/lib/commonjs/fonts/apply-font-faces.web.js +13 -12
- package/lib/commonjs/fonts/apply-font-faces.web.js.map +1 -1
- package/lib/commonjs/fonts/font-assets.js +2 -2
- package/lib/commonjs/fonts/font-data.web.js +22 -0
- package/lib/commonjs/fonts/font-data.web.js.map +1 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/skeleton/index.js +30 -0
- package/lib/commonjs/skeleton/index.js.map +1 -1
- package/lib/module/error-boundary/ErrorBoundary.js +27 -7
- package/lib/module/error-boundary/ErrorBoundary.js.map +1 -1
- package/lib/module/fonts/FontLoader.js +6 -5
- package/lib/module/fonts/FontLoader.js.map +1 -1
- package/lib/module/fonts/apply-font-faces.js +4 -4
- package/lib/module/fonts/apply-font-faces.web.js +13 -10
- package/lib/module/fonts/apply-font-faces.web.js.map +1 -1
- package/lib/module/fonts/font-assets.js +2 -2
- package/lib/module/fonts/font-data.web.js +18 -0
- package/lib/module/fonts/font-data.web.js.map +1 -0
- package/lib/module/fonts/index.web.js +4 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/skeleton/index.js +29 -0
- package/lib/module/skeleton/index.js.map +1 -1
- package/lib/typescript/commonjs/error-boundary/ErrorBoundary.d.ts +3 -1
- package/lib/typescript/commonjs/error-boundary/ErrorBoundary.d.ts.map +1 -1
- package/lib/typescript/commonjs/error-boundary/index.d.ts +1 -1
- package/lib/typescript/commonjs/error-boundary/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/error-boundary/types.d.ts +41 -2
- package/lib/typescript/commonjs/error-boundary/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/fonts/FontLoader.d.ts.map +1 -1
- package/lib/typescript/commonjs/fonts/apply-font-faces.web.d.ts +8 -1
- package/lib/typescript/commonjs/fonts/apply-font-faces.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/fonts/font-data.web.d.ts +5 -0
- package/lib/typescript/commonjs/fonts/font-data.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +1 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +1 -1
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/skeleton/index.d.ts +24 -1
- package/lib/typescript/commonjs/skeleton/index.d.ts.map +1 -1
- package/lib/typescript/module/error-boundary/ErrorBoundary.d.ts +3 -1
- package/lib/typescript/module/error-boundary/ErrorBoundary.d.ts.map +1 -1
- package/lib/typescript/module/error-boundary/index.d.ts +1 -1
- package/lib/typescript/module/error-boundary/index.d.ts.map +1 -1
- package/lib/typescript/module/error-boundary/types.d.ts +41 -2
- package/lib/typescript/module/error-boundary/types.d.ts.map +1 -1
- package/lib/typescript/module/fonts/FontLoader.d.ts.map +1 -1
- package/lib/typescript/module/fonts/apply-font-faces.web.d.ts +8 -1
- package/lib/typescript/module/fonts/apply-font-faces.web.d.ts.map +1 -1
- package/lib/typescript/module/fonts/font-data.web.d.ts +5 -0
- package/lib/typescript/module/fonts/font-data.web.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +1 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +1 -1
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/skeleton/index.d.ts +24 -1
- package/lib/typescript/module/skeleton/index.d.ts.map +1 -1
- package/package.json +36 -5
- package/src/__tests__/ErrorBoundary.test.tsx +217 -0
- package/src/__tests__/Skeleton.test.tsx +63 -0
- package/src/avatar/Avatar.stories.tsx +69 -0
- package/src/bottom-sheet/BottomSheet.stories.tsx +92 -0
- package/src/button/Button.stories.tsx +94 -0
- package/src/context-menu/ContextMenu.stories.tsx +71 -0
- package/src/dialog/Dialog.stories.tsx +112 -0
- package/src/error-boundary/ErrorBoundary.tsx +28 -5
- package/src/error-boundary/index.ts +5 -1
- package/src/error-boundary/types.ts +45 -2
- package/src/fonts/FontLoader.tsx +6 -5
- package/src/fonts/apply-font-faces.ts +4 -4
- package/src/fonts/apply-font-faces.web.ts +18 -10
- package/src/fonts/font-assets.ts +2 -2
- package/src/fonts/font-data.web.ts +15 -0
- package/src/fonts/index.web.ts +4 -4
- package/src/index.ts +5 -1
- package/src/index.web.ts +5 -1
- package/src/loading/Loading.stories.tsx +60 -0
- package/src/menu/Menu.stories.tsx +79 -0
- package/src/prompt-input/PromptInput.stories.tsx +82 -0
- package/src/select/Select.stories.tsx +84 -0
- package/src/settings-list/SettingsList.stories.tsx +106 -0
- package/src/skeleton/index.tsx +54 -1
- package/src/text-field/TextField.stories.tsx +90 -0
- package/src/toast/Toast.stories.tsx +109 -0
- package/lib/commonjs/fonts/assets/BlomusModernus-Bold.woff2 +0 -0
- package/lib/commonjs/fonts/assets/BlomusModernus-Regular.woff2 +0 -0
- package/lib/commonjs/fonts/assets/GeistMono-Variable.woff2 +0 -0
- package/lib/commonjs/fonts/assets/InterVariable.woff2 +0 -0
- package/lib/module/fonts/assets/BlomusModernus-Bold.woff2 +0 -0
- package/lib/module/fonts/assets/BlomusModernus-Regular.woff2 +0 -0
- package/lib/module/fonts/assets/GeistMono-Variable.woff2 +0 -0
- package/lib/module/fonts/assets/InterVariable.woff2 +0 -0
- package/lib/typescript/commonjs/__tests__/BloomThemeProvider.fonts-web.test.d.ts +0 -5
- package/lib/typescript/commonjs/__tests__/BloomThemeProvider.fonts-web.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/BloomThemeProvider.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/BloomThemeProvider.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/BottomSheet.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/BottomSheet.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/Button.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/Button.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/Code.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/Code.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/Dialog.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/Dialog.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/FontLoader.native.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/FontLoader.native.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/Pre.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/Pre.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/SettingsList.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/SettingsList.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/apply-font-faces.test.d.ts +0 -5
- package/lib/typescript/commonjs/__tests__/apply-font-faces.test.d.ts.map +0 -1
- package/lib/typescript/commonjs/__tests__/theme.test.d.ts +0 -2
- package/lib/typescript/commonjs/__tests__/theme.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/BloomThemeProvider.fonts-web.test.d.ts +0 -5
- package/lib/typescript/module/__tests__/BloomThemeProvider.fonts-web.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/BloomThemeProvider.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/BloomThemeProvider.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/BottomSheet.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/BottomSheet.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/Button.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/Button.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/Code.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/Code.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/Dialog.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/Dialog.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/FontLoader.native.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/FontLoader.native.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/Pre.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/Pre.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/SettingsList.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/SettingsList.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/apply-font-faces.test.d.ts +0 -5
- package/lib/typescript/module/__tests__/apply-font-faces.test.d.ts.map +0 -1
- package/lib/typescript/module/__tests__/theme.test.d.ts +0 -2
- package/lib/typescript/module/__tests__/theme.test.d.ts.map +0 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, View } from 'react-native';
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
4
|
+
|
|
5
|
+
import { Button } from '../button';
|
|
6
|
+
import { Dialog } from './Dialog';
|
|
7
|
+
import { useDialogControl } from './context';
|
|
8
|
+
import { alert } from './alert';
|
|
9
|
+
|
|
10
|
+
const meta: Meta<typeof Dialog> = {
|
|
11
|
+
title: 'Components/Dialog',
|
|
12
|
+
component: Dialog,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default meta;
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj<typeof Dialog>;
|
|
18
|
+
|
|
19
|
+
function DeclarativeDemo() {
|
|
20
|
+
const control = useDialogControl();
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<Button onPress={() => control.open()}>Open dialog</Button>
|
|
24
|
+
<Dialog
|
|
25
|
+
control={control}
|
|
26
|
+
title="Sign out?"
|
|
27
|
+
description="You'll need to enter your password to sign in again."
|
|
28
|
+
actions={[
|
|
29
|
+
{ label: 'Sign out', color: 'destructive' },
|
|
30
|
+
{ label: 'Cancel', color: 'cancel' },
|
|
31
|
+
]}
|
|
32
|
+
/>
|
|
33
|
+
</>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function CustomChildrenDemo() {
|
|
38
|
+
const control = useDialogControl();
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<Button onPress={() => control.open()}>Open custom dialog</Button>
|
|
42
|
+
<Dialog control={control} title="Custom body">
|
|
43
|
+
<View style={{ gap: 12 }}>
|
|
44
|
+
<Text>Render any JSX inside the dialog body.</Text>
|
|
45
|
+
<Button variant="secondary" onPress={() => control.close()}>
|
|
46
|
+
Done
|
|
47
|
+
</Button>
|
|
48
|
+
</View>
|
|
49
|
+
</Dialog>
|
|
50
|
+
</>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function AlertDemo() {
|
|
55
|
+
return (
|
|
56
|
+
<Button
|
|
57
|
+
onPress={() =>
|
|
58
|
+
alert('Delete project?', 'This action cannot be undone.', [
|
|
59
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
60
|
+
{ text: 'Delete', style: 'destructive' },
|
|
61
|
+
])
|
|
62
|
+
}
|
|
63
|
+
>
|
|
64
|
+
Trigger alert()
|
|
65
|
+
</Button>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function ThreeActionDemo() {
|
|
70
|
+
const control = useDialogControl();
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
<Button onPress={() => control.open()}>Three actions</Button>
|
|
74
|
+
<Dialog
|
|
75
|
+
control={control}
|
|
76
|
+
title="Save changes?"
|
|
77
|
+
description="You have unsaved changes."
|
|
78
|
+
actions={[
|
|
79
|
+
{ label: 'Save', color: 'default' },
|
|
80
|
+
{ label: 'Discard', color: 'destructive' },
|
|
81
|
+
{ label: 'Cancel', color: 'cancel' },
|
|
82
|
+
]}
|
|
83
|
+
/>
|
|
84
|
+
</>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const Basic: Story = {
|
|
89
|
+
render: () => <DeclarativeDemo />,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const CustomChildren: Story = {
|
|
93
|
+
render: () => <CustomChildrenDemo />,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const AlertHelper: Story = {
|
|
97
|
+
render: () => <AlertDemo />,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const ThreeAction: Story = {
|
|
101
|
+
render: () => <ThreeActionDemo />,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const Composition: Story = {
|
|
105
|
+
render: () => (
|
|
106
|
+
<View style={{ gap: 12, alignItems: 'flex-start' }}>
|
|
107
|
+
<DeclarativeDemo />
|
|
108
|
+
<CustomChildrenDemo />
|
|
109
|
+
<AlertDemo />
|
|
110
|
+
</View>
|
|
111
|
+
),
|
|
112
|
+
};
|
|
@@ -6,6 +6,8 @@ import type { ErrorBoundaryProps } from './types';
|
|
|
6
6
|
interface ErrorBoundaryState {
|
|
7
7
|
hasError: boolean;
|
|
8
8
|
error: Error | null;
|
|
9
|
+
errorInfo: ErrorInfo | null;
|
|
10
|
+
retryCount: number;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
/**
|
|
@@ -52,24 +54,45 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
52
54
|
state: ErrorBoundaryState = {
|
|
53
55
|
hasError: false,
|
|
54
56
|
error: null,
|
|
57
|
+
errorInfo: null,
|
|
58
|
+
retryCount: 0,
|
|
55
59
|
};
|
|
56
60
|
|
|
57
|
-
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
61
|
+
static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {
|
|
58
62
|
return { hasError: true, error };
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
|
|
66
|
+
this.setState({ errorInfo });
|
|
62
67
|
this.props.onError?.(error, errorInfo);
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
private handleRetry = (): void => {
|
|
66
|
-
this.setState(
|
|
71
|
+
this.setState((prev) => ({
|
|
72
|
+
hasError: false,
|
|
73
|
+
error: null,
|
|
74
|
+
errorInfo: null,
|
|
75
|
+
retryCount: prev.retryCount + 1,
|
|
76
|
+
}));
|
|
67
77
|
};
|
|
68
78
|
|
|
69
79
|
render(): ReactNode {
|
|
70
|
-
if (this.state.hasError) {
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
if (this.state.hasError && this.state.error) {
|
|
81
|
+
const { fallback } = this.props;
|
|
82
|
+
|
|
83
|
+
if (typeof fallback === 'function') {
|
|
84
|
+
// Render-prop variant — invoke with error context.
|
|
85
|
+
return fallback({
|
|
86
|
+
error: this.state.error,
|
|
87
|
+
errorInfo: this.state.errorInfo,
|
|
88
|
+
retry: this.handleRetry,
|
|
89
|
+
retryCount: this.state.retryCount,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (fallback !== undefined) {
|
|
94
|
+
// Static ReactNode variant (backward-compatible).
|
|
95
|
+
return fallback;
|
|
73
96
|
}
|
|
74
97
|
|
|
75
98
|
return (
|
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
import type { ReactNode, ErrorInfo } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Context passed to a render-prop `fallback` when an ErrorBoundary catches an
|
|
5
|
+
* error. Consumers can use this to render rich fallback UI (stack traces,
|
|
6
|
+
* report buttons, retry counters, i18n strings, etc).
|
|
7
|
+
*/
|
|
8
|
+
export interface ErrorBoundaryFallbackContext {
|
|
9
|
+
/** The error thrown by a descendant during render/commit. */
|
|
10
|
+
error: Error;
|
|
11
|
+
/**
|
|
12
|
+
* The React-supplied error info (`componentStack`). May be `null` if
|
|
13
|
+
* `componentDidCatch` has not run yet for the current crash — in practice it
|
|
14
|
+
* is populated before the fallback is shown.
|
|
15
|
+
*/
|
|
16
|
+
errorInfo: ErrorInfo | null;
|
|
17
|
+
/**
|
|
18
|
+
* Resets the boundary back to its non-error state and re-renders `children`.
|
|
19
|
+
* Increments {@link retryCount} as a side effect.
|
|
20
|
+
*/
|
|
21
|
+
retry: () => void;
|
|
22
|
+
/**
|
|
23
|
+
* Number of times {@link retry} has been invoked for the currently-mounted
|
|
24
|
+
* boundary instance. Starts at 0; increments by 1 on each `retry()` call.
|
|
25
|
+
* Useful for showing "Try again (n/max)" UIs and giving up after N attempts.
|
|
26
|
+
*/
|
|
27
|
+
retryCount: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The `fallback` may either be a plain ReactNode (rendered as-is, no error
|
|
32
|
+
* context) or a render function that receives the error context and returns
|
|
33
|
+
* a ReactNode.
|
|
34
|
+
*/
|
|
35
|
+
export type ErrorBoundaryFallback =
|
|
36
|
+
| ReactNode
|
|
37
|
+
| ((context: ErrorBoundaryFallbackContext) => ReactNode);
|
|
38
|
+
|
|
3
39
|
export interface ErrorBoundaryProps {
|
|
4
40
|
children: ReactNode;
|
|
5
|
-
/**
|
|
6
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Custom fallback UI to render on error. Accepts either:
|
|
43
|
+
* - a ReactNode (static — same UI on every error), or
|
|
44
|
+
* - a render-prop `(ctx) => ReactNode` receiving `{ error, errorInfo,
|
|
45
|
+
* retry, retryCount }`.
|
|
46
|
+
*
|
|
47
|
+
* Backward-compatible: passing a static node continues to work unchanged.
|
|
48
|
+
*/
|
|
49
|
+
fallback?: ErrorBoundaryFallback;
|
|
7
50
|
/** Error title (defaults to "Something went wrong") */
|
|
8
51
|
title?: string;
|
|
9
52
|
/** Error message (defaults to "An unexpected error occurred") */
|
package/src/fonts/FontLoader.tsx
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React, { useRef } from 'react';
|
|
2
2
|
// Reach for the web variant explicitly. The default `./apply-font-faces`
|
|
3
|
-
// is a no-op stub
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// bundlers — Metro selects `FontLoader.native.tsx` on iOS/Android
|
|
7
|
-
// is safe to take a direct dependency on the web implementation
|
|
3
|
+
// is a no-op stub on native — native loads its fonts via
|
|
4
|
+
// `useFonts(FONT_ASSETS)` in `FontLoader.native.tsx` and has no use for
|
|
5
|
+
// CSS `@font-face` injection. This file (`FontLoader.tsx`) is only picked
|
|
6
|
+
// up by web bundlers — Metro selects `FontLoader.native.tsx` on iOS/Android
|
|
7
|
+
// — so it is safe to take a direct dependency on the web implementation
|
|
8
|
+
// here.
|
|
8
9
|
import { applyFontFaces } from './apply-font-faces.web';
|
|
9
10
|
|
|
10
11
|
export interface FontLoaderProps {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// is selected by bundlers via the package.json conditions. RN consumers
|
|
3
3
|
// never need font-face injection — useFonts handles loading on native.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// imports
|
|
7
|
-
//
|
|
8
|
-
//
|
|
5
|
+
// The web variant does NOT pull in any `.woff2` files via asset imports —
|
|
6
|
+
// it imports base64 data URLs from `font-data.web.ts`. This stub stays
|
|
7
|
+
// here so the file split (`*.ts` vs `*.web.ts`) makes the platform
|
|
8
|
+
// intent explicit and so the runtime API surface matches across platforms.
|
|
9
9
|
export function applyFontFaces(): void {
|
|
10
10
|
// intentionally empty
|
|
11
11
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
blomusModernusRegular,
|
|
3
|
+
blomusModernusBold,
|
|
4
|
+
interVariable,
|
|
5
|
+
geistMonoVariable,
|
|
6
|
+
} from './font-data.web';
|
|
6
7
|
import { fontFamilies } from './tokens';
|
|
7
8
|
|
|
8
9
|
const STYLE_ID = 'bloom-fonts';
|
|
@@ -12,10 +13,17 @@ const STYLE_ID = 'bloom-fonts';
|
|
|
12
13
|
*
|
|
13
14
|
* Web-only. The native counterpart in `apply-font-faces.ts` is a no-op
|
|
14
15
|
* stub — Metro cannot parse `.woff2` imports, so the file split keeps
|
|
15
|
-
*
|
|
16
|
+
* the font payload out of the native bundle entirely. Idempotent: safe to
|
|
16
17
|
* call multiple times; subsequent calls early-return after the
|
|
17
18
|
* `<style id="bloom-fonts">` tag has been mounted. SSR-safe via the
|
|
18
19
|
* `typeof document === 'undefined'` guard.
|
|
20
|
+
*
|
|
21
|
+
* The font URLs come from `./font-data.web`, a generated module that
|
|
22
|
+
* embeds the woff2 bytes as base64 data URLs. Inlining (rather than
|
|
23
|
+
* relying on bundler asset loaders for `.woff2`) means consumers do not
|
|
24
|
+
* have to extend Metro's `assetExts` or add a webpack/Vite asset rule —
|
|
25
|
+
* the published JS is self-contained. See `scripts/generate-font-data.mjs`
|
|
26
|
+
* for the rationale and trade-offs.
|
|
19
27
|
*/
|
|
20
28
|
export function applyFontFaces(): void {
|
|
21
29
|
if (typeof document === 'undefined') return;
|
|
@@ -24,10 +32,10 @@ export function applyFontFaces(): void {
|
|
|
24
32
|
const style = document.createElement('style');
|
|
25
33
|
style.id = STYLE_ID;
|
|
26
34
|
style.textContent = `
|
|
27
|
-
@font-face { font-family: 'BlomusModernus'; src: url(${
|
|
28
|
-
@font-face { font-family: 'BlomusModernus'; src: url(${
|
|
29
|
-
@font-face { font-family: 'Inter'; src: url(${
|
|
30
|
-
@font-face { font-family: 'Geist Mono'; src: url(${
|
|
35
|
+
@font-face { font-family: 'BlomusModernus'; src: url(${blomusModernusRegular}) format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
|
|
36
|
+
@font-face { font-family: 'BlomusModernus'; src: url(${blomusModernusBold}) format('woff2'); font-weight: 700; font-style: normal; font-display: swap; }
|
|
37
|
+
@font-face { font-family: 'Inter'; src: url(${interVariable}) format('woff2-variations'); font-weight: 100 900; font-style: normal; font-display: swap; }
|
|
38
|
+
@font-face { font-family: 'Geist Mono'; src: url(${geistMonoVariable}) format('woff2-variations'); font-weight: 100 900; font-style: normal; font-display: swap; }
|
|
31
39
|
:root {
|
|
32
40
|
--bloom-font-display: ${fontFamilies.display};
|
|
33
41
|
--bloom-font-sans: ${fontFamilies.sans};
|
package/src/fonts/font-assets.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// covers all weights at runtime. `@fontsource(-variable)?/*` packages only
|
|
6
6
|
// publish .woff2 for their variable axes — modern react-native font loading
|
|
7
7
|
// requires .ttf, so we use the upstream variable TTFs instead. On web,
|
|
8
|
-
// `apply-font-faces.web.ts`
|
|
9
|
-
// file is never imported.
|
|
8
|
+
// `apply-font-faces.web.ts` inlines the .woff2 variants as base64 data URLs
|
|
9
|
+
// (see `font-data.web.ts`) and this file is never imported.
|
|
10
10
|
|
|
11
11
|
export const FONT_ASSETS = {
|
|
12
12
|
BlomusModernus: require('./assets/BlomusModernus-Regular.ttf'),
|