@tinacms/app 2.4.8 → 2.5.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 +23 -0
- package/package.json +4 -4
- package/src/lib/graphql-reducer.ts +46 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @tinacms/app
|
|
2
2
|
|
|
3
|
+
## 2.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#6843](https://github.com/tinacms/tinacms/pull/6843) [`0509095`](https://github.com/tinacms/tinacms/commit/0509095601fedc87f05a622e219e6414ef51a6b6) Thanks [@wicksipedia](https://github.com/wicksipedia)! - Support TinaCMS visual editing on statically-built Astro pages.
|
|
8
|
+
|
|
9
|
+
Wrap editable regions in `<TinaIsland>` and visual editing now works under `output: 'static'` (and mixed static/SSR), provided the adapter can serve the one on-demand route `/tina-island/[name]`. Highlights:
|
|
10
|
+
|
|
11
|
+
- **Static page support.** `<TinaIsland>` emits a tiny in-iframe bootstrap that fetches `/admin/bridge.js`; on init the bridge "primes" any page with island markers but no server-injected form payloads by calling the island endpoints, which now return the page's form payloads alongside region HTML.
|
|
12
|
+
- **Bridge served as a static asset.** Dropped the injected `/_tina/bridge.js` route (some adapters 404'd it) in favour of serving `/admin/bridge.js` from a dev-only Vite plugin and emitting the bundle into the build client output — no source-tree writes. The `@tinacms/astro/bridge-route` subpath export is removed.
|
|
13
|
+
- **Re-prime on soft navigation.** `refreshForms` now re-primes when it sees island markers without server-injected payloads, so Astro `ClientRouter` swaps work without a hard reload.
|
|
14
|
+
- **Primary-form selection.** Mark the page's main form via `requestWithMetadata(..., { priority: 'primary' })` (SSR) or the `primary` prop on `<TinaIsland>` (static); the admin reducer routes around its default selection so multi-form pages no longer land on "Referenced Files".
|
|
15
|
+
- **Prerender-safe middleware.** `tina()` now short-circuits on `context.isPrerendered`, fixing the `Astro.request.headers` warnings that fired on every prerendered route during `astro build`.
|
|
16
|
+
- **New `tinaAdminDevRedirect` Vite plugin** at `@tinacms/astro/vite` — redirects `/admin` and `/admin/` to `/admin/index.html` during `astro dev` so a bare `/admin` request lands on the SPA.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [#6938](https://github.com/tinacms/tinacms/pull/6938) [`4757225`](https://github.com/tinacms/tinacms/commit/475722599ff350b45bfdb4f7a6af2e37d33c81c3) Thanks [@isaaclombardssw](https://github.com/isaaclombardssw)! - chore(deps): upgrade react-router-dom from 6.3.0 to ^6.30.3 to resolve GHSA-9jcx-v3wj-wh4m (unexpected external redirect via untrusted paths)
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [[`33feeac`](https://github.com/tinacms/tinacms/commit/33feeacf6585be2736a0a14c5a800c1b6db34e44), [`8ac0776`](https://github.com/tinacms/tinacms/commit/8ac0776dea0c0650a5e5098c143b24c17fc25b8e), [`df50cbf`](https://github.com/tinacms/tinacms/commit/df50cbf35536bf2028a742832aebd57701dc3bb6), [`b9eaf61`](https://github.com/tinacms/tinacms/commit/b9eaf61c28c25814ae65b5fbe72d5b33df0b3596), [`cf73a11`](https://github.com/tinacms/tinacms/commit/cf73a115c3a58fac26e2518734dd3cb49133260d), [`4757225`](https://github.com/tinacms/tinacms/commit/475722599ff350b45bfdb4f7a6af2e37d33c81c3)]:
|
|
23
|
+
- tinacms@3.8.2
|
|
24
|
+
- @tinacms/mdx@2.1.5
|
|
25
|
+
|
|
3
26
|
## 2.4.8
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/app",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"main": "src/main.tsx",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"devDependencies": {
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"monaco-editor": "0.31.0",
|
|
24
24
|
"react": "^18.3.1",
|
|
25
25
|
"react-dom": "^18.3.1",
|
|
26
|
-
"react-router-dom": "6.3
|
|
26
|
+
"react-router-dom": "^6.30.3",
|
|
27
27
|
"typescript": "^5.7.3",
|
|
28
28
|
"zod": "^3.24.2",
|
|
29
|
-
"
|
|
30
|
-
"tinacms": "
|
|
29
|
+
"tinacms": "3.8.2",
|
|
30
|
+
"@tinacms/mdx": "2.1.5"
|
|
31
31
|
},
|
|
32
32
|
"repository": {
|
|
33
33
|
"url": "https://github.com/tinacms/tinacms.git",
|
|
@@ -190,6 +190,13 @@ export const useGraphQLReducer = (
|
|
|
190
190
|
ResolvedDocument[]
|
|
191
191
|
>([]);
|
|
192
192
|
const [operationIndex, setOperationIndex] = React.useState(0);
|
|
193
|
+
// Pending `user-select-form` request whose form hasn't been built yet.
|
|
194
|
+
// Set when the bridge's `open` is still in flight (the bridge retries
|
|
195
|
+
// user-select-form but stops once it sees `updateData`, so we can't
|
|
196
|
+
// rely on a future message landing after `forms:add` resolves).
|
|
197
|
+
const [pendingPrimaryId, setPendingPrimaryId] = React.useState<string | null>(
|
|
198
|
+
null
|
|
199
|
+
);
|
|
193
200
|
|
|
194
201
|
const activeField = searchParams.get('active-field');
|
|
195
202
|
|
|
@@ -498,13 +505,32 @@ export const useGraphQLReducer = (
|
|
|
498
505
|
]
|
|
499
506
|
);
|
|
500
507
|
|
|
508
|
+
// The bridge sends `formId` keyed by query id (hashFromQuery output), but
|
|
509
|
+
// `state.forms` is keyed by document path. Match by either so callers using
|
|
510
|
+
// `useTina`'s `experimental___selectFormByFormId` (which usually returns a
|
|
511
|
+
// path) keep working too. Returns false when the form isn't built yet.
|
|
512
|
+
const activateFormByWireId = React.useCallback(
|
|
513
|
+
(wireId: string): boolean => {
|
|
514
|
+
const match = cms.state.forms.find(
|
|
515
|
+
({ tinaForm }) =>
|
|
516
|
+
tinaForm.id === wireId || tinaForm.queries.includes(wireId)
|
|
517
|
+
);
|
|
518
|
+
if (!match) return false;
|
|
519
|
+
cms.dispatch({
|
|
520
|
+
type: 'forms:set-active-form-id',
|
|
521
|
+
value: match.tinaForm.id,
|
|
522
|
+
});
|
|
523
|
+
return true;
|
|
524
|
+
},
|
|
525
|
+
[cms]
|
|
526
|
+
);
|
|
527
|
+
|
|
501
528
|
const handleMessage = React.useCallback(
|
|
502
529
|
(event: MessageEvent<PostMessage>) => {
|
|
503
530
|
if (event.data.type === 'user-select-form') {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
});
|
|
531
|
+
const incoming = event.data.formId;
|
|
532
|
+
// Buffer until `forms:add` resolves it if the form isn't built yet.
|
|
533
|
+
setPendingPrimaryId(activateFormByWireId(incoming) ? null : incoming);
|
|
508
534
|
}
|
|
509
535
|
|
|
510
536
|
if (event?.data?.type === 'quick-edit') {
|
|
@@ -586,11 +612,20 @@ export const useGraphQLReducer = (
|
|
|
586
612
|
return () => {
|
|
587
613
|
setPayloads([]);
|
|
588
614
|
setResults([]);
|
|
615
|
+
setPendingPrimaryId(null);
|
|
589
616
|
cms.removeAllForms();
|
|
590
617
|
cms.dispatch({ type: 'form-lists:clear' });
|
|
591
618
|
};
|
|
592
619
|
}, [url]);
|
|
593
620
|
|
|
621
|
+
// Drain a buffered `user-select-form` once the matching form lands in
|
|
622
|
+
// `state.forms`. Watches `forms.length` rather than the array identity
|
|
623
|
+
// so the effect doesn't re-run on unrelated form mutations.
|
|
624
|
+
React.useEffect(() => {
|
|
625
|
+
if (!pendingPrimaryId) return;
|
|
626
|
+
if (activateFormByWireId(pendingPrimaryId)) setPendingPrimaryId(null);
|
|
627
|
+
}, [cms.state.forms.length, pendingPrimaryId, activateFormByWireId]);
|
|
628
|
+
|
|
594
629
|
React.useEffect(() => {
|
|
595
630
|
iframe.current?.contentWindow?.postMessage({
|
|
596
631
|
type: 'quickEditEnabled',
|
|
@@ -1005,6 +1040,13 @@ const buildForm = ({
|
|
|
1005
1040
|
}
|
|
1006
1041
|
}
|
|
1007
1042
|
if (form) {
|
|
1043
|
+
// Track the payload (query) id on the form so wire-side lookups —
|
|
1044
|
+
// notably `user-select-form`, which the bridge sends keyed by query
|
|
1045
|
+
// id — can resolve to the document-path-keyed `form.id` used in
|
|
1046
|
+
// `state.forms`. `addQuery` is otherwise only called on the second
|
|
1047
|
+
// open for the same document (see the `existingForm` branch above),
|
|
1048
|
+
// so without this the very first open leaves `form.queries` empty.
|
|
1049
|
+
form.addQuery(payloadId);
|
|
1008
1050
|
if (shouldRegisterForm) {
|
|
1009
1051
|
if (collection.ui?.global) {
|
|
1010
1052
|
cms.plugins.add(new GlobalFormPlugin(form));
|