tinacms 1.5.5 → 1.5.7
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/dist/admin/pages/CollectionCreatePage.d.ts +9 -1
- package/dist/index.es.js +42 -10
- package/dist/index.js +42 -10
- package/dist/internalClient/index.d.ts +2 -3
- package/dist/react.d.ts +15 -9
- package/dist/react.es.js +167 -10
- package/dist/react.js +168 -9
- package/dist/style.css +3 -0
- package/package.json +3 -3
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
+
import type { TinaCMS } from '@tinacms/toolkit';
|
|
2
3
|
declare const CollectionCreatePage: () => JSX.Element;
|
|
3
|
-
export declare const RenderForm: ({ cms, collection, folder, templateName, mutationInfo, customDefaults, }:
|
|
4
|
+
export declare const RenderForm: ({ cms, collection, folder, templateName, mutationInfo, customDefaults, }: {
|
|
5
|
+
cms: TinaCMS;
|
|
6
|
+
collection: any;
|
|
7
|
+
folder: any;
|
|
8
|
+
templateName: any;
|
|
9
|
+
mutationInfo: any;
|
|
10
|
+
customDefaults?: any;
|
|
11
|
+
}) => JSX.Element;
|
|
4
12
|
export default CollectionCreatePage;
|
package/dist/index.es.js
CHANGED
|
@@ -255,10 +255,8 @@ mutation addPendingDocumentMutation(
|
|
|
255
255
|
}
|
|
256
256
|
return json.data;
|
|
257
257
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const jsonRes = await res.json();
|
|
261
|
-
return jsonRes;
|
|
258
|
+
get appDashboardLink() {
|
|
259
|
+
return `${this.frontendUrl}/projects/${this.clientId}`;
|
|
262
260
|
}
|
|
263
261
|
async checkSyncStatus({
|
|
264
262
|
assetsSyncing
|
|
@@ -290,6 +288,12 @@ mutation addPendingDocumentMutation(
|
|
|
290
288
|
}).join(""));
|
|
291
289
|
return JSON.parse(jsonPayload);
|
|
292
290
|
}
|
|
291
|
+
async getProject() {
|
|
292
|
+
const res = await this.fetchWithToken(`${this.identityApiUrl}/v2/apps/${this.clientId}`, {
|
|
293
|
+
method: "GET"
|
|
294
|
+
});
|
|
295
|
+
return res.json();
|
|
296
|
+
}
|
|
293
297
|
async getRefreshedToken(tokens) {
|
|
294
298
|
const { access_token, id_token, refresh_token } = JSON.parse(tokens);
|
|
295
299
|
const { exp, iss, client_id } = this.parseJwt(access_token);
|
|
@@ -1962,6 +1966,9 @@ var styles = `.tina-tailwind {
|
|
|
1962
1966
|
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
|
1963
1967
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
1964
1968
|
}
|
|
1969
|
+
.tina-tailwind .outline {
|
|
1970
|
+
outline-style: solid;
|
|
1971
|
+
}
|
|
1965
1972
|
.tina-tailwind .ring-1 {
|
|
1966
1973
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
|
1967
1974
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
|
@@ -3202,9 +3209,10 @@ const useCollectionFolder = () => {
|
|
|
3202
3209
|
const loc = useLocation();
|
|
3203
3210
|
useEffect(() => {
|
|
3204
3211
|
const match = loc.pathname.match(folderRegex);
|
|
3212
|
+
const folderName = match ? decodeURIComponent(match[1]) : "";
|
|
3205
3213
|
const update = {
|
|
3206
|
-
name:
|
|
3207
|
-
fullyQualifiedName: match ?
|
|
3214
|
+
name: folderName,
|
|
3215
|
+
fullyQualifiedName: match ? folderName ? `~/${folderName}` : "~" : "",
|
|
3208
3216
|
loading: false,
|
|
3209
3217
|
parentName: ""
|
|
3210
3218
|
};
|
|
@@ -4104,6 +4112,18 @@ const RenderForm$1 = ({
|
|
|
4104
4112
|
const windowWidth = useWindowWidth();
|
|
4105
4113
|
const renderNavToggle = windowWidth < navBreakpoint + 1;
|
|
4106
4114
|
const headerPadding = renderNavToggle ? "px-20" : "px-6";
|
|
4115
|
+
React.useEffect(() => {
|
|
4116
|
+
cms.dispatch({ type: "forms:add", value: form });
|
|
4117
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: form.id });
|
|
4118
|
+
return () => {
|
|
4119
|
+
cms.dispatch({ type: "forms:remove", value: form.id });
|
|
4120
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: null });
|
|
4121
|
+
};
|
|
4122
|
+
}, [JSON.stringify(formInfo.fields)]);
|
|
4123
|
+
if (!cms.state.activeFormId) {
|
|
4124
|
+
return null;
|
|
4125
|
+
}
|
|
4126
|
+
const activeForm = cms.state.forms.find(({ tinaForm }) => tinaForm.id === form.id);
|
|
4107
4127
|
return /* @__PURE__ */ React.createElement(PageWrapper, null, /* @__PURE__ */ React.createElement(React.Fragment, null, ((_f = (_e = cms == null ? void 0 : cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.isLocalMode) ? /* @__PURE__ */ React.createElement(LocalWarning, null) : /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", {
|
|
4108
4128
|
className: `py-4 border-b border-gray-200 bg-white ${headerPadding}`
|
|
4109
4129
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
@@ -4121,8 +4141,8 @@ const RenderForm$1 = ({
|
|
|
4121
4141
|
className: "text-xl text-gray-700 font-medium leading-tight"
|
|
4122
4142
|
}, "Create New")), /* @__PURE__ */ React.createElement(FormStatus, {
|
|
4123
4143
|
pristine: formIsPristine
|
|
4124
|
-
}))), /* @__PURE__ */ React.createElement(FormBuilder, {
|
|
4125
|
-
form,
|
|
4144
|
+
}))), activeForm && /* @__PURE__ */ React.createElement(FormBuilder, {
|
|
4145
|
+
form: activeForm,
|
|
4126
4146
|
onPristineChange: setFormIsPristine
|
|
4127
4147
|
})));
|
|
4128
4148
|
};
|
|
@@ -4284,6 +4304,18 @@ const RenderForm = ({
|
|
|
4284
4304
|
const windowWidth = useWindowWidth();
|
|
4285
4305
|
const renderNavToggle = windowWidth < navBreakpoint + 1;
|
|
4286
4306
|
const headerPadding = renderNavToggle ? "px-20" : "px-6";
|
|
4307
|
+
React.useEffect(() => {
|
|
4308
|
+
cms.dispatch({ type: "forms:add", value: form });
|
|
4309
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: form.id });
|
|
4310
|
+
return () => {
|
|
4311
|
+
cms.dispatch({ type: "forms:remove", value: form.id });
|
|
4312
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: null });
|
|
4313
|
+
};
|
|
4314
|
+
}, [JSON.stringify(document._values)]);
|
|
4315
|
+
if (!cms.state.activeFormId) {
|
|
4316
|
+
return null;
|
|
4317
|
+
}
|
|
4318
|
+
const activeForm = cms.state.forms.find(({ tinaForm }) => tinaForm.id === form.id);
|
|
4287
4319
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, ((_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode) ? /* @__PURE__ */ React.createElement(LocalWarning, null) : /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", {
|
|
4288
4320
|
className: `py-4 border-b border-gray-200 bg-white ${headerPadding}`
|
|
4289
4321
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
@@ -4301,8 +4333,8 @@ const RenderForm = ({
|
|
|
4301
4333
|
className: "text-xl text-gray-700 font-medium leading-tight"
|
|
4302
4334
|
}, "Edit ", `${filename}.${collection.format}`)), /* @__PURE__ */ React.createElement(FormStatus, {
|
|
4303
4335
|
pristine: formIsPristine
|
|
4304
|
-
}))), /* @__PURE__ */ React.createElement(FormBuilder, {
|
|
4305
|
-
form,
|
|
4336
|
+
}))), activeForm && /* @__PURE__ */ React.createElement(FormBuilder, {
|
|
4337
|
+
form: activeForm,
|
|
4306
4338
|
onPristineChange: setFormIsPristine
|
|
4307
4339
|
}));
|
|
4308
4340
|
};
|
package/dist/index.js
CHANGED
|
@@ -270,10 +270,8 @@ mutation addPendingDocumentMutation(
|
|
|
270
270
|
}
|
|
271
271
|
return json.data;
|
|
272
272
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const jsonRes = await res.json();
|
|
276
|
-
return jsonRes;
|
|
273
|
+
get appDashboardLink() {
|
|
274
|
+
return `${this.frontendUrl}/projects/${this.clientId}`;
|
|
277
275
|
}
|
|
278
276
|
async checkSyncStatus({
|
|
279
277
|
assetsSyncing
|
|
@@ -305,6 +303,12 @@ mutation addPendingDocumentMutation(
|
|
|
305
303
|
}).join(""));
|
|
306
304
|
return JSON.parse(jsonPayload);
|
|
307
305
|
}
|
|
306
|
+
async getProject() {
|
|
307
|
+
const res = await this.fetchWithToken(`${this.identityApiUrl}/v2/apps/${this.clientId}`, {
|
|
308
|
+
method: "GET"
|
|
309
|
+
});
|
|
310
|
+
return res.json();
|
|
311
|
+
}
|
|
308
312
|
async getRefreshedToken(tokens) {
|
|
309
313
|
const { access_token, id_token, refresh_token } = JSON.parse(tokens);
|
|
310
314
|
const { exp, iss, client_id } = this.parseJwt(access_token);
|
|
@@ -1977,6 +1981,9 @@ mutation addPendingDocumentMutation(
|
|
|
1977
1981
|
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
|
1978
1982
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
1979
1983
|
}
|
|
1984
|
+
.tina-tailwind .outline {
|
|
1985
|
+
outline-style: solid;
|
|
1986
|
+
}
|
|
1980
1987
|
.tina-tailwind .ring-1 {
|
|
1981
1988
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
|
1982
1989
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
|
@@ -3217,9 +3224,10 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3217
3224
|
const loc = reactRouterDom.useLocation();
|
|
3218
3225
|
React.useEffect(() => {
|
|
3219
3226
|
const match = loc.pathname.match(folderRegex);
|
|
3227
|
+
const folderName = match ? decodeURIComponent(match[1]) : "";
|
|
3220
3228
|
const update = {
|
|
3221
|
-
name:
|
|
3222
|
-
fullyQualifiedName: match ?
|
|
3229
|
+
name: folderName,
|
|
3230
|
+
fullyQualifiedName: match ? folderName ? `~/${folderName}` : "~" : "",
|
|
3223
3231
|
loading: false,
|
|
3224
3232
|
parentName: ""
|
|
3225
3233
|
};
|
|
@@ -4119,6 +4127,18 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4119
4127
|
const windowWidth = windowSize.useWindowWidth();
|
|
4120
4128
|
const renderNavToggle = windowWidth < navBreakpoint + 1;
|
|
4121
4129
|
const headerPadding = renderNavToggle ? "px-20" : "px-6";
|
|
4130
|
+
React__default["default"].useEffect(() => {
|
|
4131
|
+
cms.dispatch({ type: "forms:add", value: form });
|
|
4132
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: form.id });
|
|
4133
|
+
return () => {
|
|
4134
|
+
cms.dispatch({ type: "forms:remove", value: form.id });
|
|
4135
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: null });
|
|
4136
|
+
};
|
|
4137
|
+
}, [JSON.stringify(formInfo.fields)]);
|
|
4138
|
+
if (!cms.state.activeFormId) {
|
|
4139
|
+
return null;
|
|
4140
|
+
}
|
|
4141
|
+
const activeForm = cms.state.forms.find(({ tinaForm }) => tinaForm.id === form.id);
|
|
4122
4142
|
return /* @__PURE__ */ React__default["default"].createElement(PageWrapper, null, /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, ((_f = (_e = cms == null ? void 0 : cms.api) == null ? void 0 : _e.tina) == null ? void 0 : _f.isLocalMode) ? /* @__PURE__ */ React__default["default"].createElement(toolkit.LocalWarning, null) : /* @__PURE__ */ React__default["default"].createElement(toolkit.BillingWarning, null), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
4123
4143
|
className: `py-4 border-b border-gray-200 bg-white ${headerPadding}`
|
|
4124
4144
|
}, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
@@ -4136,8 +4156,8 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4136
4156
|
className: "text-xl text-gray-700 font-medium leading-tight"
|
|
4137
4157
|
}, "Create New")), /* @__PURE__ */ React__default["default"].createElement(toolkit.FormStatus, {
|
|
4138
4158
|
pristine: formIsPristine
|
|
4139
|
-
}))), /* @__PURE__ */ React__default["default"].createElement(toolkit.FormBuilder, {
|
|
4140
|
-
form,
|
|
4159
|
+
}))), activeForm && /* @__PURE__ */ React__default["default"].createElement(toolkit.FormBuilder, {
|
|
4160
|
+
form: activeForm,
|
|
4141
4161
|
onPristineChange: setFormIsPristine
|
|
4142
4162
|
})));
|
|
4143
4163
|
};
|
|
@@ -4299,6 +4319,18 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4299
4319
|
const windowWidth = windowSize.useWindowWidth();
|
|
4300
4320
|
const renderNavToggle = windowWidth < navBreakpoint + 1;
|
|
4301
4321
|
const headerPadding = renderNavToggle ? "px-20" : "px-6";
|
|
4322
|
+
React__default["default"].useEffect(() => {
|
|
4323
|
+
cms.dispatch({ type: "forms:add", value: form });
|
|
4324
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: form.id });
|
|
4325
|
+
return () => {
|
|
4326
|
+
cms.dispatch({ type: "forms:remove", value: form.id });
|
|
4327
|
+
cms.dispatch({ type: "forms:set-active-form-id", value: null });
|
|
4328
|
+
};
|
|
4329
|
+
}, [JSON.stringify(document._values)]);
|
|
4330
|
+
if (!cms.state.activeFormId) {
|
|
4331
|
+
return null;
|
|
4332
|
+
}
|
|
4333
|
+
const activeForm = cms.state.forms.find(({ tinaForm }) => tinaForm.id === form.id);
|
|
4302
4334
|
return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, ((_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode) ? /* @__PURE__ */ React__default["default"].createElement(toolkit.LocalWarning, null) : /* @__PURE__ */ React__default["default"].createElement(toolkit.BillingWarning, null), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
4303
4335
|
className: `py-4 border-b border-gray-200 bg-white ${headerPadding}`
|
|
4304
4336
|
}, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
@@ -4316,8 +4348,8 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4316
4348
|
className: "text-xl text-gray-700 font-medium leading-tight"
|
|
4317
4349
|
}, "Edit ", `${filename}.${collection.format}`)), /* @__PURE__ */ React__default["default"].createElement(toolkit.FormStatus, {
|
|
4318
4350
|
pristine: formIsPristine
|
|
4319
|
-
}))), /* @__PURE__ */ React__default["default"].createElement(toolkit.FormBuilder, {
|
|
4320
|
-
form,
|
|
4351
|
+
}))), activeForm && /* @__PURE__ */ React__default["default"].createElement(toolkit.FormBuilder, {
|
|
4352
|
+
form: activeForm,
|
|
4321
4353
|
onPristineChange: setFormIsPristine
|
|
4322
4354
|
}));
|
|
4323
4355
|
};
|
|
@@ -160,9 +160,7 @@ export declare class Client {
|
|
|
160
160
|
request<ReturnType>(query: ((gqlTag: typeof gql) => DocumentNode) | string, { variables }: {
|
|
161
161
|
variables: object;
|
|
162
162
|
}): Promise<ReturnType>;
|
|
163
|
-
|
|
164
|
-
assetsSyncing: string[];
|
|
165
|
-
}>;
|
|
163
|
+
get appDashboardLink(): string;
|
|
166
164
|
checkSyncStatus({ assetsSyncing, }: {
|
|
167
165
|
assetsSyncing: string[];
|
|
168
166
|
}): Promise<{
|
|
@@ -179,6 +177,7 @@ export declare class Client {
|
|
|
179
177
|
cursor?: string;
|
|
180
178
|
}>;
|
|
181
179
|
parseJwt(token: any): any;
|
|
180
|
+
getProject(): Promise<any>;
|
|
182
181
|
getRefreshedToken(tokens: string): Promise<TokenObject>;
|
|
183
182
|
isAuthorized(): Promise<boolean>;
|
|
184
183
|
isAuthenticated(): Promise<boolean>;
|
package/dist/react.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This is an experimental version of the useTina hook,
|
|
3
|
-
* it is only meant to be used with Tina in "iframe mode".
|
|
4
|
-
*/
|
|
5
1
|
export declare function useTina<T extends object>(props: {
|
|
6
2
|
query: string;
|
|
7
3
|
variables: object;
|
|
@@ -19,9 +15,19 @@ export declare function useEditState(): {
|
|
|
19
15
|
* is working with.
|
|
20
16
|
*/
|
|
21
17
|
export declare const tinaField: <T extends object & {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
fields: Record<string, string>;
|
|
18
|
+
_content_source?: {
|
|
19
|
+
queryId: string;
|
|
20
|
+
path: (number | string)[];
|
|
26
21
|
};
|
|
27
|
-
}>(
|
|
22
|
+
}>(object: T, property?: Exclude<keyof T, "__typename" | "_sys">, index?: number) => string;
|
|
23
|
+
export declare const addMetadata: <T extends object>(id: string, object: T & {
|
|
24
|
+
type?: string;
|
|
25
|
+
_content_source?: unknown;
|
|
26
|
+
}, path: (string | number)[]) => T;
|
|
27
|
+
/**
|
|
28
|
+
* This is a pretty rudimentary approach to hashing the query and variables to
|
|
29
|
+
* ensure we treat multiple queries on the page uniquely. It's possible
|
|
30
|
+
* that we would have collisions, and I'm not sure of the likeliness but seems
|
|
31
|
+
* like it'd be rare.
|
|
32
|
+
*/
|
|
33
|
+
export declare const hashFromQuery: (input: string) => string;
|
package/dist/react.es.js
CHANGED
|
@@ -1,23 +1,110 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
function useTina(props) {
|
|
3
|
+
const stringifiedQuery = JSON.stringify({
|
|
4
|
+
query: props.query,
|
|
5
|
+
variables: props.variables
|
|
6
|
+
});
|
|
7
|
+
const id = React.useMemo(() => hashFromQuery(stringifiedQuery), [stringifiedQuery]);
|
|
3
8
|
const [data, setData] = React.useState(props.data);
|
|
4
9
|
const [isClient, setIsClient] = React.useState(false);
|
|
5
|
-
const
|
|
10
|
+
const [quickEditEnabled, setQuickEditEnabled] = React.useState(false);
|
|
11
|
+
const [isInTinaIframe, setIsInTinaIframe] = React.useState(false);
|
|
6
12
|
React.useEffect(() => {
|
|
7
13
|
setIsClient(true);
|
|
8
14
|
setData(props.data);
|
|
9
15
|
}, [id]);
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (quickEditEnabled) {
|
|
18
|
+
let mouseDownHandler = function(e) {
|
|
19
|
+
const attributeNames = e.target.getAttributeNames();
|
|
20
|
+
const tinaAttribute = attributeNames.find((name) => name.startsWith("data-tina-field"));
|
|
21
|
+
let fieldName;
|
|
22
|
+
if (tinaAttribute) {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
e.stopPropagation();
|
|
25
|
+
fieldName = e.target.getAttribute(tinaAttribute);
|
|
26
|
+
} else {
|
|
27
|
+
const ancestor = e.target.closest("[data-tina-field], [data-tina-field-overlay]");
|
|
28
|
+
if (ancestor) {
|
|
29
|
+
const attributeNames2 = ancestor.getAttributeNames();
|
|
30
|
+
const tinaAttribute2 = attributeNames2.find((name) => name.startsWith("data-tina-field"));
|
|
31
|
+
if (tinaAttribute2) {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
e.stopPropagation();
|
|
34
|
+
fieldName = ancestor.getAttribute(tinaAttribute2);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (fieldName) {
|
|
39
|
+
if (isInTinaIframe) {
|
|
40
|
+
parent.postMessage({ type: "field:selected", fieldName }, window.location.origin);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const style = document.createElement("style");
|
|
45
|
+
style.type = "text/css";
|
|
46
|
+
style.textContent = `
|
|
47
|
+
[data-tina-field] {
|
|
48
|
+
outline: 2px dashed rgba(34,150,254,0.5);
|
|
49
|
+
transition: box-shadow ease-out 150ms;
|
|
50
|
+
}
|
|
51
|
+
[data-tina-field]:hover {
|
|
52
|
+
box-shadow: inset 100vi 100vh rgba(34,150,254,0.3);
|
|
53
|
+
outline: 2px solid rgba(34,150,254,1);
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
}
|
|
56
|
+
[data-tina-field-overlay] {
|
|
57
|
+
outline: 2px dashed rgba(34,150,254,0.5);
|
|
58
|
+
position: relative;
|
|
59
|
+
}
|
|
60
|
+
[data-tina-field-overlay]:hover {
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
outline: 2px solid rgba(34,150,254,1);
|
|
63
|
+
}
|
|
64
|
+
[data-tina-field-overlay]::after {
|
|
65
|
+
content: '';
|
|
66
|
+
position: absolute;
|
|
67
|
+
inset: 0;
|
|
68
|
+
z-index: 20;
|
|
69
|
+
transition: opacity ease-out 150ms;
|
|
70
|
+
background-color: rgba(34,150,254,0.3);
|
|
71
|
+
opacity: 0;
|
|
72
|
+
}
|
|
73
|
+
[data-tina-field-overlay]:hover::after {
|
|
74
|
+
opacity: 1;
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
document.head.appendChild(style);
|
|
78
|
+
document.body.classList.add("__tina-quick-editing-enabled");
|
|
79
|
+
document.addEventListener("click", mouseDownHandler, true);
|
|
80
|
+
return () => {
|
|
81
|
+
document.removeEventListener("click", mouseDownHandler, true);
|
|
82
|
+
document.body.classList.remove("__tina-quick-editing-enabled");
|
|
83
|
+
style.remove();
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}, [quickEditEnabled, isInTinaIframe]);
|
|
10
87
|
React.useEffect(() => {
|
|
11
88
|
parent.postMessage({ type: "open", ...props, id }, window.location.origin);
|
|
12
89
|
window.addEventListener("message", (event) => {
|
|
90
|
+
if (event.data.type === "quickEditEnabled") {
|
|
91
|
+
setQuickEditEnabled(event.data.value);
|
|
92
|
+
}
|
|
13
93
|
if (event.data.id === id && event.data.type === "updateData") {
|
|
14
94
|
setData(event.data.data);
|
|
95
|
+
setIsInTinaIframe(true);
|
|
96
|
+
const anyTinaField = document.querySelector("[data-tina-field]");
|
|
97
|
+
if (anyTinaField) {
|
|
98
|
+
parent.postMessage({ type: "quick-edit", value: true }, window.location.origin);
|
|
99
|
+
} else {
|
|
100
|
+
parent.postMessage({ type: "quick-edit", value: false }, window.location.origin);
|
|
101
|
+
}
|
|
15
102
|
}
|
|
16
103
|
});
|
|
17
104
|
return () => {
|
|
18
105
|
parent.postMessage({ type: "close", id }, window.location.origin);
|
|
19
106
|
};
|
|
20
|
-
}, [id]);
|
|
107
|
+
}, [id, setQuickEditEnabled]);
|
|
21
108
|
return { data, isClient };
|
|
22
109
|
}
|
|
23
110
|
function useEditState() {
|
|
@@ -35,16 +122,86 @@ function useEditState() {
|
|
|
35
122
|
}, []);
|
|
36
123
|
return { edit };
|
|
37
124
|
}
|
|
38
|
-
const tinaField = (
|
|
125
|
+
const tinaField = (object, property, index) => {
|
|
39
126
|
var _a, _b, _c;
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
127
|
+
if (object._content_source) {
|
|
128
|
+
if (!property) {
|
|
129
|
+
return [
|
|
130
|
+
(_a = object._content_source) == null ? void 0 : _a.queryId,
|
|
131
|
+
object._content_source.path.join(".")
|
|
132
|
+
].join("---");
|
|
133
|
+
}
|
|
134
|
+
if (typeof index === "number") {
|
|
135
|
+
return [
|
|
136
|
+
(_b = object._content_source) == null ? void 0 : _b.queryId,
|
|
137
|
+
[...object._content_source.path, property, index].join(".")
|
|
138
|
+
].join("---");
|
|
46
139
|
}
|
|
140
|
+
return [
|
|
141
|
+
(_c = object._content_source) == null ? void 0 : _c.queryId,
|
|
142
|
+
[...object._content_source.path, property].join(".")
|
|
143
|
+
].join("---");
|
|
47
144
|
}
|
|
48
145
|
return "";
|
|
49
146
|
};
|
|
50
|
-
|
|
147
|
+
const addMetadata = (id, object, path) => {
|
|
148
|
+
Object.entries(object).forEach(([key, value]) => {
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
value.forEach((item, index) => {
|
|
151
|
+
if (isScalarOrUndefined(item)) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (Array.isArray(item)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const itemObject = item;
|
|
158
|
+
addMetadata(id, itemObject, [...path, key, index]);
|
|
159
|
+
});
|
|
160
|
+
} else {
|
|
161
|
+
if (isScalarOrUndefined(value)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const itemObject = value;
|
|
165
|
+
addMetadata(id, itemObject, [...path, key]);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
if ((object == null ? void 0 : object.type) === "root") {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
object._content_source = {
|
|
172
|
+
queryId: id,
|
|
173
|
+
path
|
|
174
|
+
};
|
|
175
|
+
return object;
|
|
176
|
+
};
|
|
177
|
+
function isScalarOrUndefined(value) {
|
|
178
|
+
const type = typeof value;
|
|
179
|
+
if (type === "string")
|
|
180
|
+
return true;
|
|
181
|
+
if (type === "number")
|
|
182
|
+
return true;
|
|
183
|
+
if (type === "boolean")
|
|
184
|
+
return true;
|
|
185
|
+
if (type === "undefined")
|
|
186
|
+
return true;
|
|
187
|
+
if (value == null)
|
|
188
|
+
return true;
|
|
189
|
+
if (value instanceof String)
|
|
190
|
+
return true;
|
|
191
|
+
if (value instanceof Number)
|
|
192
|
+
return true;
|
|
193
|
+
if (value instanceof Boolean)
|
|
194
|
+
return true;
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
const hashFromQuery = (input) => {
|
|
198
|
+
let hash = 0;
|
|
199
|
+
for (let i = 0; i < input.length; i++) {
|
|
200
|
+
const char = input.charCodeAt(i);
|
|
201
|
+
hash = (hash << 5) - hash + char & 4294967295;
|
|
202
|
+
}
|
|
203
|
+
const nonNegativeHash = Math.abs(hash);
|
|
204
|
+
const alphanumericHash = nonNegativeHash.toString(36);
|
|
205
|
+
return alphanumericHash;
|
|
206
|
+
};
|
|
207
|
+
export { addMetadata, hashFromQuery, tinaField, useEditState, useTina };
|
package/dist/react.js
CHANGED
|
@@ -7,24 +7,111 @@
|
|
|
7
7
|
}
|
|
8
8
|
var React__default = /* @__PURE__ */ _interopDefaultLegacy(React);
|
|
9
9
|
function useTina(props) {
|
|
10
|
+
const stringifiedQuery = JSON.stringify({
|
|
11
|
+
query: props.query,
|
|
12
|
+
variables: props.variables
|
|
13
|
+
});
|
|
14
|
+
const id = React__default["default"].useMemo(() => hashFromQuery(stringifiedQuery), [stringifiedQuery]);
|
|
10
15
|
const [data, setData] = React__default["default"].useState(props.data);
|
|
11
16
|
const [isClient, setIsClient] = React__default["default"].useState(false);
|
|
12
|
-
const
|
|
17
|
+
const [quickEditEnabled, setQuickEditEnabled] = React__default["default"].useState(false);
|
|
18
|
+
const [isInTinaIframe, setIsInTinaIframe] = React__default["default"].useState(false);
|
|
13
19
|
React__default["default"].useEffect(() => {
|
|
14
20
|
setIsClient(true);
|
|
15
21
|
setData(props.data);
|
|
16
22
|
}, [id]);
|
|
23
|
+
React__default["default"].useEffect(() => {
|
|
24
|
+
if (quickEditEnabled) {
|
|
25
|
+
let mouseDownHandler = function(e) {
|
|
26
|
+
const attributeNames = e.target.getAttributeNames();
|
|
27
|
+
const tinaAttribute = attributeNames.find((name) => name.startsWith("data-tina-field"));
|
|
28
|
+
let fieldName;
|
|
29
|
+
if (tinaAttribute) {
|
|
30
|
+
e.preventDefault();
|
|
31
|
+
e.stopPropagation();
|
|
32
|
+
fieldName = e.target.getAttribute(tinaAttribute);
|
|
33
|
+
} else {
|
|
34
|
+
const ancestor = e.target.closest("[data-tina-field], [data-tina-field-overlay]");
|
|
35
|
+
if (ancestor) {
|
|
36
|
+
const attributeNames2 = ancestor.getAttributeNames();
|
|
37
|
+
const tinaAttribute2 = attributeNames2.find((name) => name.startsWith("data-tina-field"));
|
|
38
|
+
if (tinaAttribute2) {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
e.stopPropagation();
|
|
41
|
+
fieldName = ancestor.getAttribute(tinaAttribute2);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (fieldName) {
|
|
46
|
+
if (isInTinaIframe) {
|
|
47
|
+
parent.postMessage({ type: "field:selected", fieldName }, window.location.origin);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const style = document.createElement("style");
|
|
52
|
+
style.type = "text/css";
|
|
53
|
+
style.textContent = `
|
|
54
|
+
[data-tina-field] {
|
|
55
|
+
outline: 2px dashed rgba(34,150,254,0.5);
|
|
56
|
+
transition: box-shadow ease-out 150ms;
|
|
57
|
+
}
|
|
58
|
+
[data-tina-field]:hover {
|
|
59
|
+
box-shadow: inset 100vi 100vh rgba(34,150,254,0.3);
|
|
60
|
+
outline: 2px solid rgba(34,150,254,1);
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
}
|
|
63
|
+
[data-tina-field-overlay] {
|
|
64
|
+
outline: 2px dashed rgba(34,150,254,0.5);
|
|
65
|
+
position: relative;
|
|
66
|
+
}
|
|
67
|
+
[data-tina-field-overlay]:hover {
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
outline: 2px solid rgba(34,150,254,1);
|
|
70
|
+
}
|
|
71
|
+
[data-tina-field-overlay]::after {
|
|
72
|
+
content: '';
|
|
73
|
+
position: absolute;
|
|
74
|
+
inset: 0;
|
|
75
|
+
z-index: 20;
|
|
76
|
+
transition: opacity ease-out 150ms;
|
|
77
|
+
background-color: rgba(34,150,254,0.3);
|
|
78
|
+
opacity: 0;
|
|
79
|
+
}
|
|
80
|
+
[data-tina-field-overlay]:hover::after {
|
|
81
|
+
opacity: 1;
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
document.head.appendChild(style);
|
|
85
|
+
document.body.classList.add("__tina-quick-editing-enabled");
|
|
86
|
+
document.addEventListener("click", mouseDownHandler, true);
|
|
87
|
+
return () => {
|
|
88
|
+
document.removeEventListener("click", mouseDownHandler, true);
|
|
89
|
+
document.body.classList.remove("__tina-quick-editing-enabled");
|
|
90
|
+
style.remove();
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}, [quickEditEnabled, isInTinaIframe]);
|
|
17
94
|
React__default["default"].useEffect(() => {
|
|
18
95
|
parent.postMessage({ type: "open", ...props, id }, window.location.origin);
|
|
19
96
|
window.addEventListener("message", (event) => {
|
|
97
|
+
if (event.data.type === "quickEditEnabled") {
|
|
98
|
+
setQuickEditEnabled(event.data.value);
|
|
99
|
+
}
|
|
20
100
|
if (event.data.id === id && event.data.type === "updateData") {
|
|
21
101
|
setData(event.data.data);
|
|
102
|
+
setIsInTinaIframe(true);
|
|
103
|
+
const anyTinaField = document.querySelector("[data-tina-field]");
|
|
104
|
+
if (anyTinaField) {
|
|
105
|
+
parent.postMessage({ type: "quick-edit", value: true }, window.location.origin);
|
|
106
|
+
} else {
|
|
107
|
+
parent.postMessage({ type: "quick-edit", value: false }, window.location.origin);
|
|
108
|
+
}
|
|
22
109
|
}
|
|
23
110
|
});
|
|
24
111
|
return () => {
|
|
25
112
|
parent.postMessage({ type: "close", id }, window.location.origin);
|
|
26
113
|
};
|
|
27
|
-
}, [id]);
|
|
114
|
+
}, [id, setQuickEditEnabled]);
|
|
28
115
|
return { data, isClient };
|
|
29
116
|
}
|
|
30
117
|
function useEditState() {
|
|
@@ -42,18 +129,90 @@
|
|
|
42
129
|
}, []);
|
|
43
130
|
return { edit };
|
|
44
131
|
}
|
|
45
|
-
const tinaField = (
|
|
132
|
+
const tinaField = (object, property, index) => {
|
|
46
133
|
var _a, _b, _c;
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
134
|
+
if (object._content_source) {
|
|
135
|
+
if (!property) {
|
|
136
|
+
return [
|
|
137
|
+
(_a = object._content_source) == null ? void 0 : _a.queryId,
|
|
138
|
+
object._content_source.path.join(".")
|
|
139
|
+
].join("---");
|
|
140
|
+
}
|
|
141
|
+
if (typeof index === "number") {
|
|
142
|
+
return [
|
|
143
|
+
(_b = object._content_source) == null ? void 0 : _b.queryId,
|
|
144
|
+
[...object._content_source.path, property, index].join(".")
|
|
145
|
+
].join("---");
|
|
53
146
|
}
|
|
147
|
+
return [
|
|
148
|
+
(_c = object._content_source) == null ? void 0 : _c.queryId,
|
|
149
|
+
[...object._content_source.path, property].join(".")
|
|
150
|
+
].join("---");
|
|
54
151
|
}
|
|
55
152
|
return "";
|
|
56
153
|
};
|
|
154
|
+
const addMetadata = (id, object, path) => {
|
|
155
|
+
Object.entries(object).forEach(([key, value]) => {
|
|
156
|
+
if (Array.isArray(value)) {
|
|
157
|
+
value.forEach((item, index) => {
|
|
158
|
+
if (isScalarOrUndefined(item)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (Array.isArray(item)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const itemObject = item;
|
|
165
|
+
addMetadata(id, itemObject, [...path, key, index]);
|
|
166
|
+
});
|
|
167
|
+
} else {
|
|
168
|
+
if (isScalarOrUndefined(value)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const itemObject = value;
|
|
172
|
+
addMetadata(id, itemObject, [...path, key]);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
if ((object == null ? void 0 : object.type) === "root") {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
object._content_source = {
|
|
179
|
+
queryId: id,
|
|
180
|
+
path
|
|
181
|
+
};
|
|
182
|
+
return object;
|
|
183
|
+
};
|
|
184
|
+
function isScalarOrUndefined(value) {
|
|
185
|
+
const type = typeof value;
|
|
186
|
+
if (type === "string")
|
|
187
|
+
return true;
|
|
188
|
+
if (type === "number")
|
|
189
|
+
return true;
|
|
190
|
+
if (type === "boolean")
|
|
191
|
+
return true;
|
|
192
|
+
if (type === "undefined")
|
|
193
|
+
return true;
|
|
194
|
+
if (value == null)
|
|
195
|
+
return true;
|
|
196
|
+
if (value instanceof String)
|
|
197
|
+
return true;
|
|
198
|
+
if (value instanceof Number)
|
|
199
|
+
return true;
|
|
200
|
+
if (value instanceof Boolean)
|
|
201
|
+
return true;
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
const hashFromQuery = (input) => {
|
|
205
|
+
let hash = 0;
|
|
206
|
+
for (let i = 0; i < input.length; i++) {
|
|
207
|
+
const char = input.charCodeAt(i);
|
|
208
|
+
hash = (hash << 5) - hash + char & 4294967295;
|
|
209
|
+
}
|
|
210
|
+
const nonNegativeHash = Math.abs(hash);
|
|
211
|
+
const alphanumericHash = nonNegativeHash.toString(36);
|
|
212
|
+
return alphanumericHash;
|
|
213
|
+
};
|
|
214
|
+
exports2.addMetadata = addMetadata;
|
|
215
|
+
exports2.hashFromQuery = hashFromQuery;
|
|
57
216
|
exports2.tinaField = tinaField;
|
|
58
217
|
exports2.useEditState = useEditState;
|
|
59
218
|
exports2.useTina = useTina;
|
package/dist/style.css
CHANGED
|
@@ -991,6 +991,9 @@
|
|
|
991
991
|
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
|
992
992
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
993
993
|
}
|
|
994
|
+
.tina-tailwind .outline {
|
|
995
|
+
outline-style: solid;
|
|
996
|
+
}
|
|
994
997
|
.tina-tailwind .ring-1 {
|
|
995
998
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
|
996
999
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinacms",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.7",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "./dist/index.es.js",
|
|
6
6
|
"exports": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"@react-hook/window-size": "^3.0.7",
|
|
59
59
|
"@tinacms/schema-tools": "1.4.4",
|
|
60
60
|
"@tinacms/sharedctx": "1.0.1",
|
|
61
|
-
"@tinacms/toolkit": "1.7.
|
|
61
|
+
"@tinacms/toolkit": "1.7.3",
|
|
62
62
|
"crypto-js": "^4.0.0",
|
|
63
63
|
"encoding": "0.1.13",
|
|
64
64
|
"fetch-ponyfill": "^7.1.0",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"lodash.set": "^4.3.2",
|
|
69
69
|
"prism-react-renderer": "^1.3.5",
|
|
70
70
|
"react-icons": "^4.3.1",
|
|
71
|
-
"react-router-dom": "6",
|
|
71
|
+
"react-router-dom": "6.3.0",
|
|
72
72
|
"yup": "^0.32.0",
|
|
73
73
|
"zod": "^3.14.3"
|
|
74
74
|
},
|