fontdue-js 3.0.0-alpha4 → 3.0.0-alpha6

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.
Files changed (156) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +517 -94
  3. package/dist/__generated__/CartItemAdditionalLicenses_orderItem.graphql.d.ts +4 -1
  4. package/dist/__generated__/CartItemAdditionalLicenses_orderItem.graphql.js +34 -22
  5. package/dist/__generated__/CartOrderCompleteOrderMutation.graphql.d.ts +1 -1
  6. package/dist/__generated__/CartOrderCompleteOrderMutation.graphql.js +19 -4
  7. package/dist/__generated__/CartOrderRemoveDiscountMutation.graphql.d.ts +1 -1
  8. package/dist/__generated__/CartOrderRemoveDiscountMutation.graphql.js +19 -4
  9. package/dist/__generated__/CartOrderUpdateMutation.graphql.d.ts +1 -1
  10. package/dist/__generated__/CartOrderUpdateMutation.graphql.js +19 -4
  11. package/dist/__generated__/CartQuery.graphql.d.ts +1 -1
  12. package/dist/__generated__/CartQuery.graphql.js +20 -5
  13. package/dist/__generated__/CartStateUpdateMutation.graphql.d.ts +1 -1
  14. package/dist/__generated__/CartStateUpdateMutation.graphql.js +19 -4
  15. package/dist/__generated__/CharacterViewerIDQuery.graphql.d.ts +1 -1
  16. package/dist/__generated__/CharacterViewerIDQuery.graphql.js +9 -3
  17. package/dist/__generated__/CharacterViewerSlugQuery.graphql.d.ts +1 -1
  18. package/dist/__generated__/CharacterViewerSlugQuery.graphql.js +9 -3
  19. package/dist/__generated__/CharacterViewerStyleRefetchQuery.graphql.d.ts +1 -1
  20. package/dist/__generated__/CharacterViewerStyleRefetchQuery.graphql.js +9 -3
  21. package/dist/__generated__/CheckoutUpdateCustomerMutation.graphql.d.ts +1 -1
  22. package/dist/__generated__/CheckoutUpdateCustomerMutation.graphql.js +19 -4
  23. package/dist/__generated__/CheckoutUpdateOrderMutation.graphql.d.ts +1 -1
  24. package/dist/__generated__/CheckoutUpdateOrderMutation.graphql.js +19 -4
  25. package/dist/__generated__/CollectionAa_Query.graphql.d.ts +1 -1
  26. package/dist/__generated__/CollectionAa_Query.graphql.js +9 -3
  27. package/dist/__generated__/FontFamiliesQuery.graphql.d.ts +1 -1
  28. package/dist/__generated__/FontFamiliesQuery.graphql.js +9 -3
  29. package/dist/__generated__/PrecartAddToCartMutation.graphql.d.ts +1 -1
  30. package/dist/__generated__/PrecartAddToCartMutation.graphql.js +40 -25
  31. package/dist/__generated__/PrecartQuery.graphql.d.ts +1 -1
  32. package/dist/__generated__/PrecartQuery.graphql.js +17 -7
  33. package/dist/__generated__/Precart_collection.graphql.d.ts +4 -1
  34. package/dist/__generated__/Precart_collection.graphql.js +13 -3
  35. package/dist/__generated__/Precart_license.graphql.d.ts +4 -1
  36. package/dist/__generated__/Precart_license.graphql.js +19 -9
  37. package/dist/__generated__/ServerConfigProviderQuery.graphql.js +8 -1
  38. package/dist/__generated__/StoreModalCartQuery.graphql.d.ts +1 -1
  39. package/dist/__generated__/StoreModalCartQuery.graphql.js +44 -5
  40. package/dist/__generated__/StoreModalContainerQuery.graphql.d.ts +1 -1
  41. package/dist/__generated__/StoreModalContainerQuery.graphql.js +9 -3
  42. package/dist/__generated__/StoreModalIndexQuery.graphql.d.ts +1 -1
  43. package/dist/__generated__/StoreModalIndexQuery.graphql.js +9 -3
  44. package/dist/__generated__/StoreModalProductLicense_license.graphql.d.ts +4 -1
  45. package/dist/__generated__/StoreModalProductLicense_license.graphql.js +11 -2
  46. package/dist/__generated__/StoreModalProductQuery.graphql.d.ts +5 -1
  47. package/dist/__generated__/StoreModalProductQuery.graphql.js +103 -60
  48. package/dist/__generated__/StoreModalProductRefetchQuery.graphql.d.ts +1 -1
  49. package/dist/__generated__/StoreModalProductRefetchQuery.graphql.js +48 -32
  50. package/dist/__generated__/StoreModalUnifiedCheckout_viewer.graphql.d.ts +5 -1
  51. package/dist/__generated__/StoreModalUnifiedCheckout_viewer.graphql.js +26 -2
  52. package/dist/__generated__/TestFontsFormUpdateCustomerMutation.graphql.d.ts +1 -1
  53. package/dist/__generated__/TestFontsFormUpdateCustomerMutation.graphql.js +19 -4
  54. package/dist/__generated__/TestModeBannerQuery.graphql.js +8 -1
  55. package/dist/__generated__/ThemeConfigQuery.graphql.js +8 -1
  56. package/dist/__generated__/TypeTesterFamiliesQuery.graphql.d.ts +29 -0
  57. package/dist/__generated__/TypeTesterFamiliesQuery.graphql.js +167 -0
  58. package/dist/__generated__/TypeTesterFamiliesStylesQuery.graphql.d.ts +35 -0
  59. package/dist/__generated__/TypeTesterFamiliesStylesQuery.graphql.js +163 -0
  60. package/dist/__generated__/TypeTesterStandaloneChangedStylesQuery.graphql.d.ts +1 -1
  61. package/dist/__generated__/TypeTesterStandaloneChangedStylesQuery.graphql.js +10 -4
  62. package/dist/__generated__/TypeTesterStandaloneQuery.graphql.d.ts +1 -3
  63. package/dist/__generated__/TypeTesterStandaloneQuery.graphql.js +84 -161
  64. package/dist/__generated__/TypeTesterStyleSelectData_fontStyle.graphql.d.ts +2 -1
  65. package/dist/__generated__/TypeTesterStyleSelectData_fontStyle.graphql.js +18 -17
  66. package/dist/__generated__/TypeTesterStyleSelectData_viewer.graphql.js +8 -1
  67. package/dist/__generated__/TypeTester_viewer.graphql.js +8 -1
  68. package/dist/__generated__/TypeTestersChangedStylesQuery.graphql.d.ts +1 -1
  69. package/dist/__generated__/TypeTestersChangedStylesQuery.graphql.js +10 -4
  70. package/dist/__generated__/TypeTestersIDQuery.graphql.d.ts +1 -5
  71. package/dist/__generated__/TypeTestersIDQuery.graphql.js +107 -195
  72. package/dist/__generated__/TypeTestersRefetchQuery.graphql.d.ts +1 -1
  73. package/dist/__generated__/TypeTestersRefetchQuery.graphql.js +10 -4
  74. package/dist/__generated__/TypeTestersSlugQuery.graphql.d.ts +1 -3
  75. package/dist/__generated__/TypeTestersSlugQuery.graphql.js +108 -178
  76. package/dist/__generated__/TypeTesters_viewer.graphql.js +8 -1
  77. package/dist/__generated__/useFontStyle_fontStyle.graphql.d.ts +2 -1
  78. package/dist/__generated__/useFontStyle_fontStyle.graphql.js +8 -2
  79. package/dist/__tests__/fontLoader.test.js +106 -0
  80. package/dist/__tests__/licenseExclusions.test.js +158 -0
  81. package/dist/components/BuyButton/index.d.ts +6 -3
  82. package/dist/components/BuyButton/index.js +7 -5
  83. package/dist/components/BuyButton/index.server.d.ts +2 -0
  84. package/dist/components/Cart/CartItem/CartItemAdditionalLicenses.js +11 -5
  85. package/dist/components/CartButton/index.d.ts +3 -9
  86. package/dist/components/CartButton/index.js +22 -33
  87. package/dist/components/CartButton/index.server.d.ts +1 -3
  88. package/dist/components/CartButton/index.server.js +14 -20
  89. package/dist/components/CharacterViewer/index.d.ts +6 -3
  90. package/dist/components/CharacterViewer/index.js +31 -12
  91. package/dist/components/CharacterViewer/index.server.d.ts +2 -0
  92. package/dist/components/ConfigContext.d.ts +5 -2
  93. package/dist/components/ConfigContext.js +28 -2
  94. package/dist/components/FontdueContextProvider/index.d.ts +2 -1
  95. package/dist/components/FontdueContextProvider/index.js +49 -9
  96. package/dist/components/FontdueProvider/FontdueProviderClientComponent.d.ts +4 -6
  97. package/dist/components/FontdueProvider/FontdueProviderClientComponent.js +40 -48
  98. package/dist/components/FontdueProvider/index.server.js +1 -3
  99. package/dist/components/Icons/Checkbox.js +10 -8
  100. package/dist/components/Icons/CheckboxChecked.js +4 -5
  101. package/dist/components/NewsletterSignup/index.d.ts +5 -3
  102. package/dist/components/NewsletterSignup/index.js +11 -5
  103. package/dist/components/NewsletterSignup/index.server.d.ts +4 -1
  104. package/dist/components/Precart/index.js +12 -7
  105. package/dist/components/StoreModal/StoreModalContainer.js +22 -10
  106. package/dist/components/StoreModal/StoreModalLicenseeIsBillingSelection.d.ts +4 -0
  107. package/dist/components/StoreModal/StoreModalProduct.js +35 -7
  108. package/dist/components/StoreModal/index.d.ts +5 -1
  109. package/dist/components/StoreModal/index.js +8 -2
  110. package/dist/components/StoreModal/types.d.ts +1 -0
  111. package/dist/components/StoreModalProductLicenseSelection/StoreModalProductLicense.js +10 -4
  112. package/dist/components/TestFontsForm/index.d.ts +5 -3
  113. package/dist/components/TestFontsForm/index.js +11 -5
  114. package/dist/components/TestFontsForm/index.server.d.ts +4 -1
  115. package/dist/components/ThemeConfig/index.server.js +14 -7
  116. package/dist/components/TypeTester/TypeTesterFamilies.d.ts +37 -0
  117. package/dist/components/TypeTester/TypeTesterFamilies.js +117 -0
  118. package/dist/components/TypeTester/TypeTesterStandalone.d.ts +6 -6
  119. package/dist/components/TypeTester/TypeTesterStandalone.js +9 -14
  120. package/dist/components/TypeTester/TypeTesterStandalone.server.js +1 -3
  121. package/dist/components/TypeTester/TypeTesterStyleSelect.d.ts +15 -5
  122. package/dist/components/TypeTester/TypeTesterStyleSelect.js +57 -47
  123. package/dist/components/TypeTester/TypeTesterStyleSelectData.d.ts +1 -3
  124. package/dist/components/TypeTester/TypeTesterStyleSelectData.js +212 -54
  125. package/dist/components/TypeTester/TypeTesterVariableAxes.js +17 -4
  126. package/dist/components/TypeTester/index.d.ts +1 -3
  127. package/dist/components/TypeTester/index.js +10 -5
  128. package/dist/components/TypeTester/useTypeTesterStyler.d.ts +1 -1
  129. package/dist/components/TypeTester/useTypeTesterStyler.js +19 -2
  130. package/dist/components/TypeTesters/index.d.ts +5 -4
  131. package/dist/components/TypeTesters/index.js +17 -31
  132. package/dist/components/TypeTesters/index.server.d.ts +4 -1
  133. package/dist/components/TypeTesters/index.server.js +2 -4
  134. package/dist/components/elements/EmptyCart/index.js +22 -8
  135. package/dist/components/elements/StoreModalLicenseeIsBillingIdentityElement.d.ts +5 -1
  136. package/dist/components/elements/StoreModalLicenseeIsBillingIdentityElement.js +17 -5
  137. package/dist/components/elements/StoreModalUnifiedCheckout.js +24 -4
  138. package/dist/components/useFont.d.ts +1 -4
  139. package/dist/components/useFontStyle.js +1 -1
  140. package/dist/fontLoader.d.ts +21 -1
  141. package/dist/fontLoader.js +36 -2
  142. package/dist/fontdue.css +205 -86
  143. package/dist/hooks.d.ts +1 -0
  144. package/dist/hooks.js +28 -1
  145. package/dist/index.d.ts +1 -2
  146. package/dist/index.js +1 -1
  147. package/dist/loadFontdueProviderQuery.d.ts +1 -2
  148. package/dist/loadFontdueProviderQuery.js +2 -2
  149. package/dist/reducer.d.ts +2 -0
  150. package/dist/reducer.js +12 -7
  151. package/dist/relay/environment.js +1 -1
  152. package/dist/relay/loadSerializableQuery.d.ts +1 -5
  153. package/dist/relay/loadSerializableQuery.js +2 -2
  154. package/dist/vite.js +42 -2
  155. package/fontdue.css +2 -1
  156. package/package.json +4 -6
package/README.md CHANGED
@@ -1,44 +1,59 @@
1
1
  # fontdue-js
2
2
 
3
- This package exports [Fontdue.js](https://docs.fontdue.com/fontduejs) components for React projects.
3
+ React components for [Fontdue](https://fontdue.com) sites. Framework-agnostic: works in Next.js, Astro, React Router 7, TanStack Start, Vike, Remix, and any other React SSR or client-only environment.
4
4
 
5
5
  ## Requirements
6
6
 
7
- - `react` >= 18
8
- - `node` >= 16
9
-
10
- If using TypeScript, update to >= 4.7 and change your `tsconfig.json` moduleResolution setting to `node16`:
11
-
12
- ``` json
7
+ - `react` 18 or 19
8
+ - `node` >= 18
9
+ - TypeScript (if used) with `moduleResolution` set to `node16`, `nodenext`, or `bundler` so the package's `exports` map resolves:
13
10
 
11
+ ```json
14
12
  {
15
13
  "compilerOptions": {
16
- "moduleResolution": "node16",
14
+ "moduleResolution": "nodenext"
17
15
  }
18
16
  }
19
-
20
17
  ```
21
18
 
19
+ `fontdue-js` is published ESM-only.
20
+
22
21
  ## Installation
23
22
 
24
- ``` shell
23
+ ```shell
25
24
  npm install fontdue-js@latest
26
25
  ```
27
26
 
28
- ## Usage
27
+ ## Configuration
29
28
 
30
- 1. Wrap the root of your project with the [`FontdueProvider`](#fontdueprovider) component. For example in a Next.js app, add it to your `app/layout.tsx` or `pages/_app.tsx`.
31
- 2. If using Next.js, add an environment variable to your app `NEXT_PUBLIC_FONTDUE_URL` pointing to your Fontdue store URL. Otherwise, you can include the `url` prop on the `FontdueProvider`.
32
- 3. Render the [`StoreModal`](#storemodal) component so that is it available on every page.
33
- 4. Import the `fontdue-js/fontdue.css` CSS file. (This example uses Next.js)
29
+ Point fontdue-js at your Fontdue URL via an environment variable. Pick the one your framework already uses for public env vars:
34
30
 
35
- ### Example
31
+ | Framework | Variable |
32
+ | --- | --- |
33
+ | Astro | `PUBLIC_FONTDUE_URL` |
34
+ | React Router 7 / TanStack Start / Vike / Remix (Vite) | `VITE_FONTDUE_URL` |
35
+ | Next.js | `NEXT_PUBLIC_FONTDUE_URL` |
36
+ | Other / framework-less SSR | `FONTDUE_URL` |
36
37
 
38
+ A single variable covers both server and client in every supported framework — Vite exposes `import.meta.env.PUBLIC_*` / `VITE_*` on both sides, and Next inlines `NEXT_PUBLIC_*` on both sides.
37
39
 
38
- ``` shell
39
- # .env.local
40
- NEXT_PUBLIC_FONTDUE_URL=https://example.fontdue.com
41
- ```
40
+ ## Setup
41
+
42
+ Pick the section that matches your framework. All four examples below have a working repo linked at the bottom.
43
+
44
+ The general pattern in every framework:
45
+
46
+ 1. Mount `<FontdueProvider>` once at the layout level — it sets up the Relay environment + Redux store and renders auxiliary UI (theme config, test-mode banner, consent banner, analytics tracking).
47
+ 2. Mount `<StoreModal />` once, alongside the provider — opens when a `<BuyButton>` or `<CartButton>` is clicked.
48
+ 3. (SSR only.) Preload in the layout with `loadFontdueProviderQuery()` and pass it as `<FontdueProvider preloadedQuery={…}>`. This ensures the page hydrates with preloaded data.
49
+ 4. (SSR only.) Preload per-page components with their `load{Component}Query()` helpers in route loaders / frontmatter / server components.
50
+
51
+ The shape of step 3 and 4 is the only thing that changes between frameworks.
52
+
53
+ <details>
54
+ <summary><b>Next.js (App Router)</b></summary>
55
+
56
+ No Vite plugin needed. The simplest setup omits the layout preload — with React Server Components, each fontdue-js component preloads its own query internally on the server and streams to the client.
42
57
 
43
58
  ```tsx
44
59
  // app/layout.tsx
@@ -46,17 +61,12 @@ import FontdueProvider from "fontdue-js/FontdueProvider";
46
61
  import StoreModal from "fontdue-js/StoreModal";
47
62
  import "fontdue-js/fontdue.css";
48
63
 
49
- export default async function RootLayout({
50
- children,
51
- }: {
52
- children: React.ReactNode;
53
- }) {
64
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
54
65
  return (
55
66
  <html lang="en">
56
67
  <body>
57
68
  <FontdueProvider>
58
69
  {children}
59
-
60
70
  <StoreModal />
61
71
  </FontdueProvider>
62
72
  </body>
@@ -65,183 +75,596 @@ export default async function RootLayout({
65
75
  }
66
76
  ```
67
77
 
68
- For details on integrating into your Next.js app, read our [Next.js guide](https://docs.fontdue.com/nextjs)
78
+ ```tsx
79
+ // app/fonts/[slug]/page.tsx — no explicit preload needed.
80
+ import TypeTester from "fontdue-js/TypeTester";
69
81
 
70
- ## IDs
82
+ export default function FontPage() {
83
+ return <TypeTester familyName="Example" styleName="Regular" />;
84
+ }
85
+ ```
86
+
87
+ Example repo: [`fontdue/fontdue-example-next`](https://github.com/fontdue/fontdue-example-next)
88
+
89
+ </details>
90
+
91
+ <details>
92
+ <summary><b>Astro</b></summary>
93
+
94
+ Add the Vite plugin to `astro.config.mjs`:
95
+
96
+ ```ts
97
+ import { defineConfig } from "astro/config";
98
+ import react from "@astrojs/react";
99
+ import fontdueJs from "fontdue-js/vite";
100
+
101
+ export default defineConfig({
102
+ integrations: [react()],
103
+ vite: { plugins: [fontdueJs()] },
104
+ });
105
+ ```
71
106
 
72
- ⚠️ Some components accept a `collectionId` prop. Note this is the `id` returned from the [GraphQL API](https://docs.fontdue.com/graphql-api).
107
+ In Astro, every `client:*` component is its own React island — `<FontdueProvider>` doesn't form a React parent of your page components. Instead, it's a sibling island that sets up Fontdue's core on your site. Per-page components (`<TypeTester>`, etc.) self-wrap their own context when no parent provider is in scope.
73
108
 
74
- You may alternatively specify a `collectionSlug` for these components, which can be useful if you are not consuming the GraphQL API. However, we recommend using `collectionId` when possible.
109
+ Because of this, there's **no global config** in Astro: `config` set on `<FontdueProvider>` doesn't reach your page components. Pass `config` to each component instead see [UI config](#ui-config).
110
+
111
+ ```astro
112
+ ---
113
+ // src/layouts/Layout.astro
114
+ import FontdueProvider, { loadFontdueProviderQuery } from "fontdue-js/FontdueProvider";
115
+ import StoreModal from "fontdue-js/StoreModal";
116
+ import "fontdue-js/fontdue.css";
117
+
118
+ const fontduePreload = await loadFontdueProviderQuery();
119
+ ---
120
+
121
+ <html lang="en">
122
+ <body>
123
+ <FontdueProvider client:load preloadedQuery={fontduePreload} />
124
+ <StoreModal client:load />
125
+ <slot />
126
+ </body>
127
+ </html>
128
+ ```
129
+
130
+ Per-page preload runs in frontmatter:
131
+
132
+ ```astro
133
+ ---
134
+ // src/pages/fonts/[slug].astro
135
+ import Layout from "../../layouts/Layout.astro";
136
+ import TypeTester, { loadTypeTesterQuery } from "fontdue-js/TypeTester";
137
+
138
+ const preloaded = await loadTypeTesterQuery({
139
+ familyName: "Example",
140
+ styleName: "Regular",
141
+ });
142
+ ---
143
+
144
+ <Layout>
145
+ <TypeTester client:load preloadedQuery={preloaded} content="The quick brown fox" fontSize={64} />
146
+ </Layout>
147
+ ```
148
+
149
+ Example repo: [`fontdue/example-astro`](https://github.com/fontdue/example-astro)
150
+
151
+ </details>
152
+
153
+ <details>
154
+ <summary><b>React Router 7</b></summary>
155
+
156
+ Add the Vite plugin to `vite.config.ts`:
157
+
158
+ ```ts
159
+ import { defineConfig } from "vite";
160
+ import { reactRouter } from "@react-router/dev/vite";
161
+ import fontdueJs from "fontdue-js/vite";
162
+
163
+ export default defineConfig({
164
+ plugins: [reactRouter(), fontdueJs()],
165
+ });
166
+ ```
167
+
168
+ Preload in the root route's loader, pass the result through `loaderData`:
169
+
170
+ ```tsx
171
+ // app/root.tsx
172
+ import { Outlet } from "react-router";
173
+ import FontdueProvider, { loadFontdueProviderQuery } from "fontdue-js/FontdueProvider";
174
+ import StoreModal from "fontdue-js/StoreModal";
175
+ import "fontdue-js/fontdue.css";
176
+ import type { Route } from "./+types/root";
177
+
178
+ export async function loader() {
179
+ return { fontduePreload: await loadFontdueProviderQuery() };
180
+ }
181
+
182
+ export default function App({ loaderData }: Route.ComponentProps) {
183
+ return (
184
+ <FontdueProvider preloadedQuery={loaderData.fontduePreload}>
185
+ <Outlet />
186
+ <StoreModal />
187
+ </FontdueProvider>
188
+ );
189
+ }
190
+ ```
191
+
192
+ Per-page preload mirrors the same shape:
193
+
194
+ ```tsx
195
+ // app/routes/fonts.$slug.tsx
196
+ import TypeTester, { loadTypeTesterQuery } from "fontdue-js/TypeTester";
197
+
198
+ export async function loader() {
199
+ return {
200
+ preloadedQuery: await loadTypeTesterQuery({
201
+ familyName: "Example",
202
+ styleName: "Regular",
203
+ }),
204
+ };
205
+ }
206
+
207
+ export default function FontPage({ loaderData }) {
208
+ return <TypeTester preloadedQuery={loaderData.preloadedQuery} content="…" fontSize={64} />;
209
+ }
210
+ ```
211
+
212
+ Example repo: [`fontdue/example-react-router`](https://github.com/fontdue/example-react-router)
213
+
214
+ </details>
215
+
216
+ <details>
217
+ <summary><b>TanStack Start</b></summary>
218
+
219
+ Add the Vite plugin to `vite.config.ts` (alongside TanStack's plugin). Preload in the root route's `loader`:
220
+
221
+ ```tsx
222
+ // src/routes/__root.tsx
223
+ import { Outlet, createRootRoute } from "@tanstack/react-router";
224
+ import FontdueProvider, { loadFontdueProviderQuery } from "fontdue-js/FontdueProvider";
225
+ import StoreModal from "fontdue-js/StoreModal";
226
+ import "fontdue-js/fontdue.css";
227
+
228
+ export const Route = createRootRoute({
229
+ loader: async () => ({ fontduePreload: await loadFontdueProviderQuery() }),
230
+ component: RootComponent,
231
+ });
232
+
233
+ function RootComponent() {
234
+ const { fontduePreload } = Route.useLoaderData();
235
+ return (
236
+ <FontdueProvider preloadedQuery={fontduePreload}>
237
+ <Outlet />
238
+ <StoreModal />
239
+ </FontdueProvider>
240
+ );
241
+ }
242
+ ```
243
+
244
+ Per-page preload uses each route's `loader`:
245
+
246
+ ```tsx
247
+ // src/routes/fonts.$slug.tsx
248
+ import { createFileRoute } from "@tanstack/react-router";
249
+ import TypeTester, { loadTypeTesterQuery } from "fontdue-js/TypeTester";
250
+
251
+ export const Route = createFileRoute("/fonts/$slug")({
252
+ loader: async () => ({
253
+ preloadedQuery: await loadTypeTesterQuery({
254
+ familyName: "Example",
255
+ styleName: "Regular",
256
+ }),
257
+ }),
258
+ component: FontPage,
259
+ });
260
+
261
+ function FontPage() {
262
+ const { preloadedQuery } = Route.useLoaderData();
263
+ return <TypeTester preloadedQuery={preloadedQuery} content="…" fontSize={64} />;
264
+ }
265
+ ```
266
+
267
+ Example repo: [`fontdue/example-tanstack`](https://github.com/fontdue/example-tanstack)
268
+
269
+ </details>
270
+
271
+ <details>
272
+ <summary><b>Other Vite-based frameworks (Vike, Remix, plain Vite SSR)</b></summary>
273
+
274
+ Add `fontdueJs()` to your Vite plugins. Run `loadFontdueProviderQuery()` wherever your framework loads layout-level data (Vike's `+data.ts`, Remix's root `loader`, etc.) and pass the result to `<FontdueProvider preloadedQuery>`. The component-level `load*Query()` helpers work the same way for per-page data.
275
+
276
+ Vike example — `+data.ts` for the layout, plus a per-page data loader. Re-export `Data = Awaited<ReturnType<typeof data>>` from each `+data.ts` so `useData<Data>()` gets a proper type without restating the shape:
277
+
278
+ ```ts
279
+ // pages/+data.ts
280
+ import { loadFontdueProviderQuery } from "fontdue-js/FontdueProvider";
281
+
282
+ export const data = async () => ({
283
+ fontduePreload: await loadFontdueProviderQuery(),
284
+ });
285
+ export type Data = Awaited<ReturnType<typeof data>>;
286
+ ```
287
+
288
+ ```tsx
289
+ // pages/+Layout.tsx
290
+ import { useData } from "vike-react/useData";
291
+ import FontdueProvider from "fontdue-js/FontdueProvider";
292
+ import StoreModal from "fontdue-js/StoreModal";
293
+ import "fontdue-js/fontdue.css";
294
+ import type { Data } from "./+data";
295
+
296
+ export default function Layout({ children }: { children: React.ReactNode }) {
297
+ const { fontduePreload } = useData<Data>();
298
+ return (
299
+ <FontdueProvider preloadedQuery={fontduePreload}>
300
+ {children}
301
+ <StoreModal />
302
+ </FontdueProvider>
303
+ );
304
+ }
305
+ ```
306
+
307
+ ```ts
308
+ // pages/fonts/@slug/+data.ts
309
+ import { loadTypeTesterQuery } from "fontdue-js/TypeTester";
310
+
311
+ export const data = async () => ({
312
+ preloadedQuery: await loadTypeTesterQuery({
313
+ familyName: "Example",
314
+ styleName: "Regular",
315
+ }),
316
+ });
317
+ export type Data = Awaited<ReturnType<typeof data>>;
318
+ ```
319
+
320
+ ```tsx
321
+ // pages/fonts/@slug/+Page.tsx
322
+ import { useData } from "vike-react/useData";
323
+ import TypeTester from "fontdue-js/TypeTester";
324
+ import type { Data } from "./+data";
325
+
326
+ export default function FontPage() {
327
+ const { preloadedQuery } = useData<Data>();
328
+ return <TypeTester preloadedQuery={preloadedQuery} content="…" fontSize={64} />;
329
+ }
330
+ ```
331
+
332
+ Remix follows the same shape with root `loader` / route `loader` + `useLoaderData()`. We don't ship an example repo for these yet — open an issue if you'd like one.
333
+
334
+ </details>
335
+
336
+ <details>
337
+ <summary><b>Client-only / no SSR</b></summary>
338
+
339
+ Mount `<FontdueProvider>` (no `preloadedQuery`) and render components with their lazy props (`{collectionId}`, `{familyName, styleName}`, etc.). They fetch on mount.
340
+
341
+ ```tsx
342
+ import FontdueProvider from "fontdue-js/FontdueProvider";
343
+ import StoreModal from "fontdue-js/StoreModal";
344
+ import TypeTester from "fontdue-js/TypeTester";
345
+ import "fontdue-js/fontdue.css";
346
+
347
+ export default function App() {
348
+ return (
349
+ <FontdueProvider>
350
+ <TypeTester familyName="Example" styleName="Regular" />
351
+ <StoreModal />
352
+ </FontdueProvider>
353
+ );
354
+ }
355
+ ```
356
+
357
+ </details>
358
+
359
+ ## UI config
360
+
361
+ Most components accept a `config` object that controls UI behavior — type-tester options (`selectable`, `priceBar`, size ranges, OpenType-feature UI…), store-modal layout, form styling, analytics tracking, and more. See the [full config reference](https://docs.fontdue.com/fontduejs#b3dec49aa08240bba2b4c71a67c08333).
362
+
363
+ There are two places to set it.
364
+
365
+ **On the provider.** `<FontdueProvider config={…}>` configures every Fontdue component rendered _inside_ it. This is the normal way wherever your components are React descendants of the provider — Next.js, React Router 7, TanStack Start, Vike, Remix, and client-only setups.
366
+
367
+ ```tsx
368
+ <FontdueProvider config={{ typeTester: { selectable: true } }}>
369
+ <TypeTester familyName="Example" styleName="Regular" />
370
+ </FontdueProvider>
371
+ ```
372
+
373
+ **Per component.** Every component below also accepts an optional `config` prop with the same shape. It's the way to configure a component used as a standalone island (see Astro, below).
374
+
375
+ ```tsx
376
+ <TypeTester preloadedQuery={preloaded} config={{ typeTester: { selectable: true } }} />
377
+ ```
378
+
379
+ The config type is exported from the package root, so you can type a shared object: `import type { Config } from "fontdue-js"`.
380
+
381
+ How the two compose:
382
+
383
+ - **Standalone** — a component with no `<FontdueProvider>` ancestor uses its own `config` prop in full.
384
+ - **Inside a provider** — the component's `config` deep-merges onto the provider's: the component's keys win, everything else is inherited.
385
+ - **Next.js App Router is the exception.** There, components render through React Server Components and read config from the `<FontdueProvider>` only — a per-component `config` prop is ignored. Set config on the provider.
386
+
387
+ ### Astro and other per-island frameworks: there is no global config
388
+
389
+ In Astro, Vike, and any framework that hydrates each `client:*` component as its own React island, `<FontdueProvider>` is a _sibling_ island, not a React ancestor of your page components. **Config set on the provider does not reach them**, and there is no global config to set.
390
+
391
+ Pass `config` to each island instead. Define it once and reuse it so every island agrees:
392
+
393
+ ```astro
394
+ ---
395
+ import type { Config } from "fontdue-js";
396
+ import TypeTester, { loadTypeTesterQuery } from "fontdue-js/TypeTester";
397
+
398
+ // One source of truth for this page's testers.
399
+ const fontdueConfig = { typeTester: { selectable: true } } satisfies Config;
400
+
401
+ const regular = await loadTypeTesterQuery({ familyName: "Example", styleName: "Regular" });
402
+ const italic = await loadTypeTesterQuery({ familyName: "Example", styleName: "Italic" });
403
+ ---
404
+
405
+ <TypeTester client:load preloadedQuery={regular} config={fontdueConfig} />
406
+ <TypeTester client:load preloadedQuery={italic} config={fontdueConfig} />
407
+ ```
408
+
409
+ `config` affects the server-rendered HTML, so keeping a single source of truth is also what keeps SSR and client hydration in agreement. To share config across many pages, export it from a module (e.g. `src/lib/fontdue.ts`) and import it wherever you mount a component.
410
+
411
+ ## IDs
412
+
413
+ > Some components accept a `collectionId`. This is the `id` returned from the [GraphQL API](https://docs.fontdue.com/graphql-api). You can alternatively pass `collectionSlug`, which is useful when you aren't consuming the GraphQL API directly. Prefer `collectionId` when possible.
75
414
 
76
415
  ---
77
416
 
78
417
  # Components
79
418
 
419
+ Every component below has a default export and (where applicable) a `load{Component}Query` named export for the SSR preload path. Both share a single entry point per component. Every component also accepts an optional `config` prop — see [UI config](#ui-config).
420
+
421
+ ## Lazy vs. preloaded props
422
+
423
+ Most components accept their data in one of two shapes:
424
+
425
+ - **Lazy props** — the identifying inputs the component needs to look up its own data: `collectionId` / `collectionSlug` for collection-bound components, `familyName` + `styleName` for the standalone `<TypeTester>`, nothing at all for forms like `<NewsletterSignup>` or `<TestFontsForm>`. The component fetches on mount, on the client, and shows nothing in the meantime.
426
+ - **`preloadedQuery`** — the result of calling the corresponding `load{Component}Query(…)` helper on the server. The component skips its own fetch, renders synchronously from the payload, and hydrates on the client without a re-fetch.
427
+
428
+ Both shapes are mutually exclusive on each component. You can mix them across the page — e.g. preload a `<TypeTester>` on a font-detail route while using a lazy `<BuyButton>` on the same page — and you can mix them across pages, since the choice is per-render.
429
+
430
+ ```tsx
431
+ // Lazy — fetches on the client.
432
+ <TypeTester familyName="Example" styleName="Regular" />
433
+
434
+ // Preloaded — server-rendered, hydrates without a fetch.
435
+ const preloadedQuery = await loadTypeTesterQuery({
436
+ familyName: "Example",
437
+ styleName: "Regular",
438
+ });
439
+ <TypeTester preloadedQuery={preloadedQuery} />
440
+ ```
441
+
442
+ **Which to use?**
443
+
444
+ - If you're in Next.js's App Router, use the lazy props — React Server Components takes care of the preload internally for you.
445
+ - If you're in any other framework with SSR (Astro, RR7, TanStack, Vike, Remix), prefer `preloadedQuery`. Otherwise the page hydrates with a flash of empty content while each component fetches.
446
+ - If your site is client-only (no SSR), lazy props are the only option.
447
+
448
+ A few components don't accept `preloadedQuery`:
449
+
450
+ - **`StoreModal`** and **`CartButton`** still render server-side, but without a preloaded query — their fetch always happens on the client after hydration, and the SSR output is the empty Suspense fallback. The reason: their data is per-customer-session (cart contents, modal-open state) and a build-time / CDN-cached SSR call would just cache an empty cart and delay the real one. `<CartButton>` reflects the right count as soon as the post-hydration fetch resolves; `<StoreModal>` renders nothing visible until opened, so there's nothing to flash.
451
+ - **`CustomerLoginForm`** has no preload helper today — it's a thin form with no upfront data needs.
80
452
 
81
453
  ## `FontdueProvider`
82
454
 
83
- The FontdueProvider provides necessary context for all the other Fontdue.js components, so it must be an ancestor of all other components. See example in our [guide](https://docs.fontdue.com/nextjs).
455
+ Provides the Fontdue context (Relay environment, Redux store, config, components map) and renders auxiliary UI (theme, test-mode banner, consent banner, tracking). Render once at the layout level.
84
456
 
85
457
  ```tsx
86
- import FontdueProvider from 'fontdue-js/FontdueProvider';
458
+ import FontdueProvider, { loadFontdueProviderQuery } from "fontdue-js/FontdueProvider";
87
459
  ```
88
460
 
89
461
  | Prop | Description |
90
462
  | --- | --- |
91
- | `url` | `string` Your Fontdue store URL, in the form `https://your-site.fontdue.com`. |
92
- | `config` | `object` Config object. Refer to the [Fontdue.js docs site](https://docs.fontdue.com/fontduejs#b3dec49aa08240bba2b4c71a67c08333) for available config options. |
93
- | `components` | `object` Component view overrides. This API will likely change. |
463
+ | `preloadedQuery` | (Recommended) Result of `loadFontdueProviderQuery()`. Warms aux UI synchronously. |
464
+ | `config` | `object` UI config applied to everything in the provider's tree. See [UI config](#ui-config). |
94
465
 
95
466
  ## `StoreModal`
96
467
 
97
- Renders the Fontdue cart + checkout experience as a modal. This appears when a user clicks on a [`BuyButton`](#buybutton) or the buy button within [`TypeTesters`](#typetesters)
468
+ The cart and checkout UI, rendered as a modal. Mount once at the layout level. Opens when a `BuyButton` is clicked or when navigated to from another component.
98
469
 
99
470
  ```tsx
100
- import StoreModal from 'fontdue-js/StoreModal';
471
+ import StoreModal from "fontdue-js/StoreModal";
101
472
  ```
102
473
 
103
- ## `BuyButton`
474
+ `StoreModal` doesn't accept `preloadedQuery` — its content is per-customer-session (cart contents, modal-open state), which isn't safe to resolve at SSR time. The component still renders server-side, but its data fetch always runs on the client after hydration. The modal is closed by default, so there's nothing visible to flash.
104
475
 
105
- A button which when clicked opens the Cart to the relevant collection, and selects the collection.
476
+ ## `BuyButton`
106
477
 
107
- Renders a button with the text `Buy {collectionName}`
478
+ A button that opens `StoreModal` to the relevant collection.
108
479
 
109
480
  ```tsx
110
- import BuyButton from 'fontdue-js/BuyButton';
481
+ import BuyButton, { loadBuyButtonQuery } from "fontdue-js/BuyButton";
111
482
  ```
112
483
 
113
484
  | Prop | Description |
114
485
  | --- | --- |
115
- | `collectionId` or `collectionSlug` | (Required) `string` Collection identifier |
116
- | `collectionName` | (Optional) `string` The name to render in the button: `Buy {collectionName}` |
117
- | `label` | (Optional) `string` Label for the button (defaults to `Buy {collectionName}`) |
486
+ | `collectionId` or `collectionSlug` | (Required, lazy) `string` Collection identifier. Omit if passing `preloadedQuery`. |
487
+ | `preloadedQuery` | (Required, SSR) Result of `loadBuyButtonQuery({ collectionId })` or `loadBuyButtonQuery({ collectionSlug })`. |
488
+ | `collectionName` | (Optional) `string` Name to render in the default label: `Buy {collectionName}`. |
489
+ | `label` | (Optional) `string` Override the button label entirely. |
118
490
 
119
491
  ## `CartButton`
120
492
 
121
- A button to open the Store Modal. If the user has items in their cart, the button will navigate straight to the Cart screen. Otherwise it opens the fonts index.
493
+ Opens `StoreModal`, jumping straight to the cart screen if there are items in it.
122
494
 
123
495
  ```tsx
124
- import CartButton from 'fontdue-js/CartButton';
496
+ import CartButton from "fontdue-js/CartButton";
125
497
  ```
126
498
 
499
+ No `preloadedQuery` (same reason as `StoreModal`). Renders server-side with an empty Suspense fallback, then fetches the cart on the client after hydration and updates with the live count. Render anywhere; safe with or without an explicit `<FontdueProvider>` ancestor.
500
+
127
501
  | Prop | Description |
128
502
  | --- | --- |
129
- | `buttonStyle` | (Optional) `'icon' \| 'inline'` Button style. If left blank, the button is unstyled. |
130
- | `label` | (Optional) `string` For non-icon style buttons, the text to render inside the button. Defaults to "Cart" |
503
+ | `buttonStyle` | (Optional) `string` Pass `'icon'` to render the cart icon instead of a text label. The value is also surfaced as `data-button-style` on the rendered `<button>` so you can target other styles via CSS. |
504
+ | `label` | (Optional) `string` Text content. Defaults to `"Cart"`. Ignored when `buttonStyle="icon"`. |
505
+ | `suffix` | (Optional) `string` Template appended to the label. Substitutions: `{count}`, `{subtotal}`. Hidden when the cart is empty. |
506
+ | `children` | (Optional) `ReactNode` Custom button contents. Replaces the default label / icon entirely. |
131
507
 
132
508
  ## `CharacterViewer`
133
509
 
134
- An interactive character/glyph explorer.
510
+ An interactive character / glyph explorer.
135
511
 
136
512
  ```tsx
137
- import CharacterViewer from 'fontdue-js/CharacterViewer';
513
+ import CharacterViewer, { loadCharacterViewerQuery } from "fontdue-js/CharacterViewer";
138
514
  ```
139
515
 
140
516
  | Prop | Description |
141
517
  | --- | --- |
142
- | `collectionId` or `collectionSlug` | (Required) `string` Identifier for collection |
143
-
518
+ | `collectionId` or `collectionSlug` | (Required, lazy) `string` Collection identifier. |
519
+ | `preloadedQuery` | (Required, SSR) Result of `loadCharacterViewerQuery({ collectionId })` or `loadCharacterViewerQuery({ collectionSlug })`. |
144
520
 
145
521
  ## `CustomerLoginForm`
146
522
 
147
- A form for customers to log in and retrieve their order history. When they enter
148
- their email address, they receive a link to a Fontdue-hosted page to view orders.
523
+ A form for customers to look up their order history. Submitting an email address sends a link to a Fontdue-hosted orders page.
149
524
 
150
525
  ```tsx
151
- import CustomerLoginForm from 'fontdue-js/CustomerLoginForm';
526
+ import CustomerLoginForm from "fontdue-js/CustomerLoginForm";
152
527
  ```
153
528
 
154
529
  | Prop | Description |
155
530
  | --- | --- |
156
- | `submitLabel` | `string` Label for the submit button, defaults to "Submit" |
531
+ | `submitLabel` | (Optional) `string` Submit button label. Defaults to `"Submit"`. |
157
532
 
158
533
  ## `TypeTesters`
159
534
 
160
- A group of type tester components for a collection. You must first add content for the collection's type testers through the Fontdue dashboard.
535
+ Group of type testers configured through the Fontdue dashboard.
161
536
 
162
537
  ```tsx
163
- import TypeTesters from 'fontdue-js/TypeTesters';
538
+ import TypeTesters, { loadTypeTestersQuery } from "fontdue-js/TypeTesters";
164
539
  ```
165
540
 
166
541
  | Prop | Description |
167
542
  | --- | --- |
168
- | `collectionId` or `collectionSlug` | (Required) `string` Identifier for collection |
169
- | `defaultMode` | (Optional) `'local' \| 'global'` The mode refers to the toggle in the UI: Affect all styles. `local` mode has this toggle turned off by default, `global` turns it on |
170
- | `autofit` | (Optional) `boolean` Set to `true` to make the sentences fit on one line. It will adjust to the width of the tester as the user changes their browser window. If the user changes the font size or edits content, autofitting is turned off for that tester |
171
- | `tags` | (Optional) `string[]` Will render only type testers that include any of these tags |
172
- | `excludeTags` | (Optional) `string[]` Will exclude type testers that include any of these tags |
173
- | `onFocus` | (Optional) `() => void` when any type tester is focused |
174
- | `onBlur` | (Optional) `() => void` when any type tester is blurred |
175
- | `onToolbarOpenClose` | (Optional) `(open: boolean) => void` Callback when toolbar is opened/closed |
543
+ | `collectionId` or `collectionSlug` | (Required, lazy) `string` Collection identifier. |
544
+ | `preloadedQuery` | (Required, SSR) Result of `loadTypeTestersQuery({ collectionId, tags?, excludeTags? })` or `loadTypeTestersQuery({ collectionSlug, tags?, excludeTags? })`. |
545
+ | `defaultMode` | (Optional) `'group' \| 'local'` Whether the "Affect all styles" toggle starts on (`group`) or off (`local`). |
546
+ | `autofit` | (Optional) `boolean` Make sentences fit on one line, adjusting size as the container resizes. Disables when the user changes font size or content. |
547
+ | `tags` | (Optional) `string[]` Render only testers tagged with any of these. |
548
+ | `excludeTags` | (Optional) `string[]` Exclude testers tagged with any of these. |
549
+ | `features` | (Optional) `string[]` OpenType feature codes to expose to users across all testers in the group (e.g. `['ss01', 'ss02']`). |
550
+ | `onFocus` | (Optional) `() => void` Fired when any tester gains focus. |
551
+ | `onBlur` | (Optional) `() => void` Fired when any tester loses focus. |
552
+ | `onToolbarOpenClose` | (Optional) `(open: boolean) => void` Fired when the toolbar opens or closes. |
176
553
 
177
554
  ## `TypeTester` (standalone)
178
555
 
179
- Standalone version of the type tester, which does not query the Fontdue CMS for content. You supply the content instead. Does not support the "Affect all styles" feature of the TypeTesters component.
556
+ Standalone tester driven by props rather than dashboard content. Doesn't support the "Affect all styles" toggle.
180
557
 
181
558
  ```tsx
182
- import TypeTester from 'fontdue-js/TypeTester';
559
+ import TypeTester, { loadTypeTesterQuery } from "fontdue-js/TypeTester";
183
560
  ```
184
561
 
185
562
  | Prop | Description |
186
563
  | --- | --- |
187
- | `familyName` | (Required) `string` Font family name (must have been already uploaded to your Fontdue admin) |
188
- | `styleName` | (Required) `string` The name of the style from the family to display. |
564
+ | `familyName` and `styleName` | (Required, lazy) `string` Identify the font style to render. The family/style must already be uploaded to your Fontdue admin. |
565
+ | `preloadedQuery` | (Required, SSR) Result of `loadTypeTesterQuery({ familyName, styleName })`. |
189
566
  | `fontSize` | (Optional) `number` Initial font size in pixels. |
190
- | `lineHeight` | (Optional) `number` Line-height as a proportional value where `1 == fontSize`. |
191
- | `content` | (Optional) `string` The initial content to display. |
192
- | `direction` | (Optional) `'ltr' \| 'rtl'` Writing direction |
193
- | `alignment` | (Optional) `'left' \| 'center' \| 'right'` Text alignment |
194
- | `features` | (Optional) `string[]` List of opentype feature codes to expose as options to users. (e.g. `['ss01', 'ss02']`) |
195
- | `axes` | (Optional) `string[]` List of variable axes to expose. (e.g. `['wdth', 'ital']`). You must provide the relevant `variableSettings` for each axis |
196
- | `autofit` | (Optional) See `TypeTesters.autofit` above |
197
- | `featureSettings` | (Optional) `{ feature: string, value: string }[]` List of features already selected, the `value` should be `"1"` to mark the feature as selected. The shape of this data is consistent with the `TypeTester.featureSettings` field in the GraphQL API. e.g. `[{ feature: 'ss01', value: '1' }]` |
198
- | `variableSettings` | (Optional) `{ axis: string, value: number }[]` List of variable settings selected, consistent with the `TypeTester.variableSettings` field. e.g. `[{ axis: 'wdth', value: 600 }, { axis: 'ital', value: 0.5 }]` |
567
+ | `lineHeight` | (Optional) `number` Proportional line height (`1` == `fontSize`). |
568
+ | `letterSpacing` | (Optional) `number` Letter spacing. |
569
+ | `content` | (Optional) `string` Initial content. |
570
+ | `direction` | (Optional) `'ltr' \| 'rtl'` Writing direction. |
571
+ | `alignment` | (Optional) `'left' \| 'center' \| 'right'` Text alignment. |
572
+ | `features` | (Optional) `string[]` OpenType feature codes to expose to users (e.g. `['ss01', 'ss02']`). |
573
+ | `featuresSelected` | (Optional) `string[]` Subset of `features` to mark as initially selected. |
574
+ | `axes` | (Optional) `string[]` Variable axes to expose (e.g. `['wdth', 'ital']`). Pair with `variableSettings`. |
575
+ | `featureSettings` | (Optional) `{ feature: string, value: string }[]` Pre-selected features. Shape matches `TypeTester.featureSettings` in the GraphQL API. |
576
+ | `variableSettings` | (Optional) `{ axis: string, value: number }[]` Pre-selected axis values. Shape matches `TypeTester.variableSettings` in the GraphQL API. |
577
+ | `autofit` | (Optional) See `TypeTesters.autofit` above. |
578
+ | `onFocus` / `onBlur` | (Optional) `() => void` |
199
579
 
200
580
  ## `TestFontsForm`
201
581
 
202
- Displays a form for users to enter their information and download test fonts. Make sure you have configured [Test Fonts](https://docs.fontdue.com/test-fonts) for this to work.
582
+ A form that lets visitors download test fonts after entering their details. Requires [Test Fonts](https://docs.fontdue.com/test-fonts) to be configured.
203
583
 
204
584
  ```tsx
205
- import TestFontsForm from 'fontdue-js/TestFontsForm';
585
+ import TestFontsForm, { loadTestFontsFormQuery } from "fontdue-js/TestFontsForm";
206
586
  ```
207
587
 
208
588
  | Prop | Description |
209
589
  | --- | --- |
210
- | `agreementLabel` | (Optional) `string` Label for required checkbox. Defaults to the field "EULA agreement text" in your Fontdue Labels settings |
211
- | `downloadLabel` | (Optional) `string` Download button label. Defaults to "Download test fonts" |
212
- | `newsletterCheckboxChecked` | (Optional) `boolean` Set the newsletter opt-in checkbox checked by default |
590
+ | `preloadedQuery` | (Optional, SSR) Result of `loadTestFontsFormQuery()`. Lazy if omitted. |
591
+ | `agreementLabel` | (Optional) `string` Label for the required agreement checkbox. Defaults to the "EULA agreement text" field in your Fontdue Labels settings. |
592
+ | `downloadLabel` | (Optional) `string` Submit button label. Defaults to `"Download test fonts"`. |
593
+ | `newsletterCheckboxChecked` | (Optional) `boolean` Pre-check the newsletter opt-in. |
213
594
 
214
595
  ## `NewsletterSignup`
215
596
 
216
- A newsletter signup form. Customers entering their information here simply adds them as a Customer in the Fontdue CMS.
597
+ A signup form that adds the visitor as a Customer in Fontdue.
217
598
 
218
599
  ```tsx
219
- import NewsletterSignup from 'fontdue-js/NewsletterSignup';
600
+ import NewsletterSignup, { loadNewsletterSignupQuery } from "fontdue-js/NewsletterSignup";
220
601
  ```
221
602
 
222
603
  | Prop | Description |
223
604
  | --- | --- |
224
- | `optInLabel` | (Required) `string` Label that appears with the checkbox required to be checked. |
225
- | `buttonLabel` | (Optional) `string` Label for the button. Defaults to "Subscribe" |
226
- | `optInCheckboxChecked` | (Optional) `boolean` Set the checkbox checked by default. |
605
+ | `preloadedQuery` | (Optional, SSR) Result of `loadNewsletterSignupQuery()`. Lazy if omitted. |
606
+ | `title` | (Optional) `string` Heading rendered above the form. |
607
+ | `intro` | (Optional) `string` Paragraph rendered between the title and the form. |
608
+ | `optInLabel` | (Optional) `string` Label rendered next to the opt-in checkbox. Defaults to the "Newsletter opt-in label" field in your Fontdue Labels settings. |
609
+ | `buttonLabel` | (Optional) `string` Submit button label. Defaults to `"Subscribe"`. |
610
+ | `successLabel` | (Optional) `string` Message shown after a successful submission. Defaults to the "Newsletter success label" field in your Fontdue Labels settings. |
611
+ | `optInCheckboxChecked` | (Optional) `boolean` Pre-check the opt-in box. |
612
+
613
+ ---
614
+
615
+ # Hooks
227
616
 
228
617
  ## `useFont`
229
618
 
230
- A hook to load and render a web font. Pass `webfontSources` to load fonts directly via the FontFace API (no CSS `@font-face` required). The `webfontSources` data is available from the `FontStyle.webfontSources` field in the GraphQL API.
619
+ Loads and renders a webfont. Pass `webfontSources` (available as `FontStyle.webfontSources` in the GraphQL API) to load via the FontFace API directly — no CSS `@font-face` needed.
231
620
 
232
621
  ```tsx
233
- import useFont from 'fontdue-js/useFont';
622
+ import useFont from "fontdue-js/useFont";
234
623
 
235
624
  const FontStyle = ({ familyName, styleName, webfontSources }) => {
236
625
  const { style, loaded } = useFont({
237
626
  fontFamily: `${familyName} ${styleName}`,
238
627
  webfontSources,
239
628
  });
240
-
241
629
  return <span style={style}>The quick brown fox</span>;
242
630
  };
243
631
  ```
244
632
 
245
- If `webfontSources` is omitted, the hook falls back to detecting fonts loaded by CSS `@font-face` rules.
633
+ If `webfontSources` is omitted, the hook falls back to detecting fonts loaded by your CSS `@font-face` rules.
634
+
635
+ Also available as `fontdue-js/useFontStyle` for backwards compatibility.
636
+
637
+ ## `useConsent`
638
+
639
+ Returns `true` when the visitor has granted consent for a given category. Re-renders when the consent state changes (e.g. the visitor accepts the consent banner).
640
+
641
+ ```tsx
642
+ import { useConsent } from "fontdue-js/useConsent";
643
+
644
+ const analyticsConsent = useConsent("analytics");
645
+ ```
646
+
647
+ ## `useAutofit`
648
+
649
+ Measures a string against a container and returns a font size that fits on one line. Used internally by `TypeTester`'s `autofit` prop; exported for custom layouts.
650
+
651
+ ```tsx
652
+ import useAutofit from "fontdue-js/useAutofit";
653
+
654
+ const { ref, fontSize, ready } = useAutofit({
655
+ text: "The quick brown fox",
656
+ fontFamily: "Tonka Regular",
657
+ fontSize: 200,
658
+ });
659
+ ```
660
+
661
+ ---
662
+
663
+ # Examples
664
+
665
+ Working repos for each supported framework, all hitting the same `example.fontdue.xyz` store and exercising every preloadable component:
246
666
 
247
- Also available as `fontdue-js/useFontStyle` for backward compatibility.
667
+ - Next.js [`fontdue/fontdue-example-next`](https://github.com/fontdue/fontdue-example-next)
668
+ - Astro — [`fontdue/example-astro`](https://github.com/fontdue/example-astro)
669
+ - React Router 7 — [`fontdue/example-react-router`](https://github.com/fontdue/example-react-router)
670
+ - TanStack Start — [`fontdue/example-tanstack`](https://github.com/fontdue/example-tanstack)