Feature/plate editor (#115)

* Add plate editor
This commit is contained in:
Daniel Lautzenheiser 2022-12-01 19:29:33 -05:00 committed by GitHub
parent f3c4337268
commit 147592a8b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
345 changed files with 12561 additions and 4346 deletions

View File

@ -55,6 +55,24 @@ module.exports = {
caughtErrorsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_',
}, },
], ],
'@typescript-eslint/no-restricted-imports': [
'error',
{
patterns: [
{
group: ['@mui/*/*/*', '!@mui/material/test-utils/*'],
message: 'Do not import material imports as 3rd level imports',
allowTypeImports: true,
},
{
group: ['@mui/material', '!@mui/material/'],
message: 'Please import material imports as defaults or 2nd level imports',
allowTypeImports: true,
},
],
},
],
'import/prefer-default-export': 'error',
}, },
plugins: ['babel', '@emotion', 'cypress', 'unicorn', 'react-hooks'], plugins: ['babel', '@emotion', 'cypress', 'unicorn', 'react-hooks'],
settings: { settings: {
@ -62,9 +80,7 @@ module.exports = {
version: 'detect', version: 'detect',
}, },
'import/resolver': { 'import/resolver': {
node: { typescript: {}, // this loads <rootdir>/tsconfig.json to eslint
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
}, },
'import/core-modules': ['src'], 'import/core-modules': ['src'],
}, },

View File

@ -68,9 +68,7 @@
content: '{}', content: '{}',
}, },
'image.json': { 'image.json': {
content: `{ content: `{}`,
"required": "/assets/uploads/moby-dick.jpg"
}`,
}, },
'map.json': { 'map.json': {
content: '{}', content: '{}',
@ -125,7 +123,71 @@
dateString + dateString +
'T00:00:00.000Z\n---\n# The post is number ' + 'T00:00:00.000Z\n---\n# The post is number ' +
i + i +
'\n\nAnd this is yet another identical post body', `\n\n![Static CMS](https://raw.githubusercontent.com/StaticJsCMS/static-cms/main/static-cms-logo.png)
# Awesome Editor!
It was _released as open source in 2022_ and is **_continually_** evolving to be the **best editor experience** available for static site generators.
## MDX
The output out this widget is \`mdx\`, a mixture of \`markdown\` and \`javascript components\`. See [MDX documentation](https://mdxjs.com/docs/).
\`\`\`yaml
name: body
label: Blog post content
widget: markdown
\`\`\`
\`\`\`js
name: 'body',
label: 'Blog post content',
widget: 'markdown',
\`\`\`
> See the table below for default options
> More API information can be found in the document
| Name | Type | Default | Description |
| ------------- | --------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| default | string | \`''\` | _Optional_. The default value for the field. Accepts markdown content |
| media_library | Media Library Options | \`{}\` | _Optional_. Media library settings to apply when a media library is opened by the current widget. See [Media Library Options](#media-library-options) |
| media_folder | string | | _Optional_. Specifies the folder path where uploaded files should be saved, relative to the base of the repo |
| public_folder | string | | _Optional_. Specifies the folder path where the files uploaded by the media library will be accessed, relative to the base of the built site |
### Media Library Options
| Name | Type | Default | Description |
| -------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| allow_multiple | boolean | \`true\` | _Optional_. When set to \`false\`, prevents multiple selection for any media library extension, but must be supported by the extension in use |
| config | string | \`{}\` | _Optional_. A configuration object that will be passed directly to the media library being used - available options are determined by the library |
| choose_url | string<br />\\| boolean | \`true\` | _Optional_. When set to \`false\`, the "Insert from URL" button will be hidden
## Features
* CommonMark + GFM Specifications
* Live \`Preview\`
* Auto Indent
* Syntax Highlight
1. Rich Editor
2. Preview
## Formatting
<font style={{ color: 'red', backgroundColor: 'black' }}>Colored Text</font>
<p align="center">Centered Text</p>
**Bold**, *Italic*, ***both***, <u>Underlined</u>
~~Strikethrough~~, <sub>subscript</sub>, <sup>superscript</sup>
## Support
> * Supports remark plugins
> * Supports wrappers
> 1. [x] React
> 2. [ ] More coming soon`,
}; };
} }

View File

@ -41,30 +41,41 @@
"last 2 Safari versions" "last 2 Safari versions"
], ],
"dependencies": { "dependencies": {
"@codemirror/commands": "6.1.2",
"@codemirror/view": "6.6.0",
"@emotion/babel-preset-css-prop": "11.10.0", "@emotion/babel-preset-css-prop": "11.10.0",
"@emotion/css": "11.10.0", "@emotion/css": "11.10.0",
"@emotion/react": "11.10.4", "@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4", "@emotion/styled": "11.10.4",
"@ltd/j-toml": "1.35.3", "@ltd/j-toml": "1.35.3",
"@mdx-js/mdx": "2.1.5",
"@mdx-js/react": "2.1.5",
"@mui/icons-material": "5.10.6", "@mui/icons-material": "5.10.6",
"@mui/material": "5.10.10", "@mui/material": "5.10.10",
"@mui/system": "5.4.1", "@mui/system": "5.4.1",
"@mui/x-date-pickers": "5.0.9", "@mui/x-date-pickers": "5.0.9",
"@reduxjs/toolkit": "1.8.5", "@reduxjs/toolkit": "1.9.1",
"@toast-ui/react-editor": "3.2.2", "@styled-icons/fluentui-system-regular": "10.46.0",
"@styled-icons/remix-editor": "10.46.0",
"@udecode/plate": "18.9.0",
"@udecode/plate-juice": "18.9.0",
"@udecode/plate-serializer-md": "18.9.0",
"@uiw/codemirror-extensions-langs": "4.14.2",
"@uiw/react-codemirror": "4.14.2",
"ajv": "8.11.2", "ajv": "8.11.2",
"ajv-errors": "3.0.0", "ajv-errors": "3.0.0",
"ajv-keywords": "5.1.0", "ajv-keywords": "5.1.0",
"array-move": "4.0.0", "array-move": "4.0.0",
"buffer": "6.0.3", "buffer": "6.0.3",
"clean-stack": "4.2.0", "clean-stack": "4.2.0",
"codemirror": "5.65.9", "codemirror": "6.0.1",
"common-tags": "1.8.1", "common-tags": "1.8.1",
"copy-text-to-clipboard": "3.0.1", "copy-text-to-clipboard": "3.0.1",
"create-react-class": "15.7.0", "create-react-class": "15.7.0",
"date-fns": "2.29.3", "date-fns": "2.29.3",
"deepmerge": "4.2.2", "deepmerge": "4.2.2",
"diacritics": "1.3.0", "diacritics": "1.3.0",
"escape-html": "1.0.3",
"eslint-config-prettier": "8.5.0", "eslint-config-prettier": "8.5.0",
"eslint-plugin-babel": "5.3.1", "eslint-plugin-babel": "5.3.1",
"fuzzy": "0.1.3", "fuzzy": "0.1.3",
@ -74,7 +85,7 @@
"graphql-tag": "2.12.6", "graphql-tag": "2.12.6",
"gray-matter": "4.0.3", "gray-matter": "4.0.3",
"history": "4.10.1", "history": "4.10.1",
"immer": "9.0.15", "immer": "9.0.16",
"ini": "2.0.0", "ini": "2.0.0",
"is-hotkey": "0.2.0", "is-hotkey": "0.2.0",
"js-base64": "3.7.2", "js-base64": "3.7.2",
@ -88,15 +99,14 @@
"ol": "6.15.1", "ol": "6.15.1",
"path-browserify": "1.0.1", "path-browserify": "1.0.1",
"react": "18.2.0", "react": "18.2.0",
"react-codemirror2": "7.2.1",
"react-color": "2.19.3", "react-color": "2.19.3",
"react-dnd": "14.0.5", "react-dnd": "16.0.1",
"react-dnd-html5-backend": "14.1.0", "react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-frame-component": "5.2.3", "react-frame-component": "5.2.3",
"react-is": "18.2.0", "react-is": "18.2.0",
"react-polyglot": "0.7.2", "react-polyglot": "0.7.2",
"react-redux": "8.0.4", "react-redux": "8.0.5",
"react-router-dom": "6.4.1", "react-router-dom": "6.4.1",
"react-scroll-sync": "0.9.0", "react-scroll-sync": "0.9.0",
"react-sortable-hoc": "2.0.0", "react-sortable-hoc": "2.0.0",
@ -105,17 +115,31 @@
"react-virtualized-auto-sizer": "1.0.7", "react-virtualized-auto-sizer": "1.0.7",
"react-waypoint": "10.3.0", "react-waypoint": "10.3.0",
"react-window": "1.8.7", "react-window": "1.8.7",
"remark-gfm": "3.0.1",
"remark-html": "15.0.1",
"remark-mdx": "2.1.5",
"remark-parse": "10.0.1",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"semaphore": "1.1.0", "semaphore": "1.1.0",
"slate": "0.85.0",
"slate-history": "0.85.0",
"slate-hyperscript": "0.77.0",
"slate-react": "0.83.2",
"stream-browserify": "3.0.0", "stream-browserify": "3.0.0",
"styled-components": "5.3.6",
"symbol-observable": "4.0.0", "symbol-observable": "4.0.0",
"ts-loader": "9.4.1", "ts-loader": "9.4.1",
"unified": "10.1.2",
"unist-util-visit": "4.1.1",
"uploadcare-widget": "3.19.0", "uploadcare-widget": "3.19.0",
"uploadcare-widget-tab-effects": "1.5.0", "uploadcare-widget-tab-effects": "1.5.0",
"url": "0.11.0", "url": "0.11.0",
"url-join": "4.0.1", "url-join": "4.0.1",
"uuid": "3.4.0", "uuid": "3.4.0",
"validate-color": "2.2.1", "validate-color": "2.2.1",
"vfile": "5.3.6",
"vfile-message": "3.1.3",
"vfile-statistics": "2.0.0",
"what-input": "5.2.12", "what-input": "5.2.12",
"what-the-diff": "0.6.0", "what-the-diff": "0.6.0",
"yaml": "1.10.2" "yaml": "1.10.2"
@ -137,7 +161,7 @@
"@octokit/core": "4.1.0", "@octokit/core": "4.1.0",
"@octokit/rest": "16.43.2", "@octokit/rest": "16.43.2",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10", "@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
"@types/codemirror": "5.60.5", "@simbathesailor/use-what-changed": "2.0.0",
"@types/common-tags": "1.8.0", "@types/common-tags": "1.8.0",
"@types/create-react-class": "15.6.3", "@types/create-react-class": "15.6.3",
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
@ -149,6 +173,7 @@
"@types/jwt-decode": "2.2.1", "@types/jwt-decode": "2.2.1",
"@types/lodash": "4.14.191", "@types/lodash": "4.14.191",
"@types/minimatch": "5.1.2", "@types/minimatch": "5.1.2",
"@types/node": "16.18.4",
"@types/node-fetch": "2.6.2", "@types/node-fetch": "2.6.2",
"@types/react": "18.0.25", "@types/react": "18.0.25",
"@types/react-color": "3.0.6", "@types/react-color": "3.0.6",
@ -156,6 +181,7 @@
"@types/react-scroll-sync": "0.8.4", "@types/react-scroll-sync": "0.8.4",
"@types/react-virtualized-auto-sizer": "1.0.1", "@types/react-virtualized-auto-sizer": "1.0.1",
"@types/react-window": "1.8.5", "@types/react-window": "1.8.5",
"@types/styled-components": "5.1.26",
"@types/url-join": "4.0.1", "@types/url-join": "4.0.1",
"@types/uuid": "3.4.10", "@types/uuid": "3.4.10",
"@typescript-eslint/eslint-plugin": "5.38.0", "@typescript-eslint/eslint-plugin": "5.38.0",
@ -179,6 +205,7 @@
"css-loader": "3.6.0", "css-loader": "3.6.0",
"dotenv": "10.0.0", "dotenv": "10.0.0",
"eslint": "8.24.0", "eslint": "8.24.0",
"eslint-import-resolver-typescript": "3.5.2",
"eslint-plugin-cypress": "2.12.1", "eslint-plugin-cypress": "2.12.1",
"eslint-plugin-import": "2.26.0", "eslint-plugin-import": "2.26.0",
"eslint-plugin-prettier": "4.2.1", "eslint-plugin-prettier": "4.2.1",
@ -208,6 +235,7 @@
"source-map-loader": "4.0.0", "source-map-loader": "4.0.0",
"style-loader": "3.3.1", "style-loader": "3.3.1",
"to-string-loader": "1.2.0", "to-string-loader": "1.2.0",
"tsconfig-paths-webpack-plugin": "4.0.0",
"typescript": "4.8.4", "typescript": "4.8.4",
"webpack": "5.74.0", "webpack": "5.74.0",
"webpack-cli": "4.10.0", "webpack-cli": "4.10.0",

View File

@ -5,7 +5,7 @@ import trimStart from 'lodash/trimStart';
import yaml from 'yaml'; import yaml from 'yaml';
import { resolveBackend } from '../backend'; import { resolveBackend } from '../backend';
import { validateConfig } from '../constants/configSchema'; import validateConfig from '../constants/configSchema';
import { I18N, I18N_FIELD, I18N_STRUCTURE } from '../lib/i18n'; import { I18N, I18N_FIELD, I18N_STRUCTURE } from '../lib/i18n';
import { selectDefaultSortableFields } from '../lib/util/collection.util'; import { selectDefaultSortableFields } from '../lib/util/collection.util';
import { getIntegrations, selectIntegration } from '../reducers/integrations'; import { getIntegrations, selectIntegration } from '../reducers/integrations';

View File

@ -14,7 +14,7 @@ import { selectEntriesSortFields, selectIsFetching } from '../reducers/entries';
import { navigateToEntry } from '../routing/history'; import { navigateToEntry } from '../routing/history';
import { addSnackbar } from '../store/slices/snackbars'; import { addSnackbar } from '../store/slices/snackbars';
import { createAssetProxy } from '../valueObjects/AssetProxy'; import { createAssetProxy } from '../valueObjects/AssetProxy';
import { createEntry } from '../valueObjects/Entry'; import createEntry from '../valueObjects/createEntry';
import { addAssets, getAsset } from './media'; import { addAssets, getAsset } from './media';
import { loadMedia, waitForMediaLibraryToLoad } from './mediaLibrary'; import { loadMedia, waitForMediaLibraryToLoad } from './mediaLibrary';
import { waitUntil } from './waitUntil'; import { waitUntil } from './waitUntil';
@ -475,18 +475,16 @@ export function changeDraftField({
path, path,
field, field,
value, value,
entry,
i18n, i18n,
}: { }: {
path: string; path: string;
field: Field; field: Field;
value: ValueOrNestedValue; value: ValueOrNestedValue;
entry?: Entry | null;
i18n?: I18nSettings; i18n?: I18nSettings;
}) { }) {
return { return {
type: DRAFT_CHANGE_FIELD, type: DRAFT_CHANGE_FIELD,
payload: { path, field, value, entry, i18n }, payload: { path, field, value, i18n },
} as const; } as const;
} }
@ -884,7 +882,7 @@ export function createEmptyDraftData(
fields: Field[], fields: Field[],
skipField: (field: Field) => boolean = () => false, skipField: (field: Field) => boolean = () => false,
) { ) {
return fields.reduce((acc, item) => { const ddd = fields.reduce((acc, item) => {
if (skipField(item)) { if (skipField(item)) {
return acc; return acc;
} }
@ -904,7 +902,7 @@ export function createEmptyDraftData(
} else { } else {
const asList = Array.isArray(subfields) ? subfields : [subfields]; const asList = Array.isArray(subfields) ? subfields : [subfields];
const subDefaultValue = Array.isArray(subfields) const subDefaultValue = list
? [createEmptyDraftData(asList, skipField)] ? [createEmptyDraftData(asList, skipField)]
: createEmptyDraftData(asList, skipField); : createEmptyDraftData(asList, skipField);
@ -921,6 +919,8 @@ export function createEmptyDraftData(
return acc; return acc;
}, {} as ObjectValue); }, {} as ObjectValue);
return ddd;
} }
function createEmptyDraftI18nData(collection: Collection, dataFields: Field[]) { function createEmptyDraftI18nData(collection: Collection, dataFields: Field[]) {

View File

@ -42,7 +42,7 @@ export function loadAssetFailure(path: string, error: Error) {
return { type: LOAD_ASSET_FAILURE, payload: { path, error } } as const; return { type: LOAD_ASSET_FAILURE, payload: { path, error } } as const;
} }
const emptyAsset = createAssetProxy({ export const emptyAsset = createAssetProxy({
path: 'empty.svg', path: 'empty.svg',
file: new File([`<svg xmlns="http://www.w3.org/2000/svg"></svg>`], 'empty.svg', { file: new File([`<svg xmlns="http://www.w3.org/2000/svg"></svg>`], 'empty.svg', {
type: 'image/svg+xml', type: 'image/svg+xml',
@ -84,7 +84,7 @@ async function loadAsset(
const promiseCache: Record<string, Promise<AssetProxy>> = {}; const promiseCache: Record<string, Promise<AssetProxy>> = {};
export function getAsset<F extends BaseField = UnknownField>( export function getAsset<F extends BaseField = UnknownField>(
collection: Collection | null | undefined, collection: Collection<F> | null | undefined,
entry: Entry | null | undefined, entry: Entry | null | undefined,
path: string, path: string,
field?: F, field?: F,
@ -104,7 +104,7 @@ export function getAsset<F extends BaseField = UnknownField>(
const resolvedPath = selectMediaFilePath( const resolvedPath = selectMediaFilePath(
state.config.config, state.config.config,
collection, collection as Collection,
entry, entry,
path, path,
field as Field, field as Field,

View File

@ -41,7 +41,7 @@ import {
import { selectMediaFilePath } from './lib/util/media.util'; import { selectMediaFilePath } from './lib/util/media.util';
import { set } from './lib/util/object.util'; import { set } from './lib/util/object.util';
import { dateParsers, expandPath, extractTemplateVars } from './lib/widgets/stringTemplate'; import { dateParsers, expandPath, extractTemplateVars } from './lib/widgets/stringTemplate';
import { createEntry } from './valueObjects/Entry'; import createEntry from './valueObjects/createEntry';
import type { import type {
BackendClass, BackendClass,

View File

@ -15,11 +15,11 @@ import {
then, then,
throwOnConflictingBranches, throwOnConflictingBranches,
unsentRequest, unsentRequest,
} from '../../lib/util'; } from '@staticcms/core/lib/util';
import type { DataFile, PersistOptions } from '../../interface'; import type { DataFile, PersistOptions } from '@staticcms/core/interface';
import type { ApiRequest, FetchError } from '../../lib/util'; import type { ApiRequest, FetchError } from '@staticcms/core/lib/util';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
interface Config { interface Config {
apiRoot?: string; apiRoot?: string;

View File

@ -1,12 +1,12 @@
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import AuthenticationPage from '../../components/UI/AuthenticationPage'; import AuthenticationPage from '@staticcms/core/components/UI/AuthenticationPage';
import Icon from '../../components/UI/Icon'; import Icon from '@staticcms/core/components/UI/Icon';
import { ImplicitAuthenticator, NetlifyAuthenticator } from '../../lib/auth'; import { ImplicitAuthenticator, NetlifyAuthenticator } from '@staticcms/core/lib/auth';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import type { AuthenticationPageProps, TranslatedProps } from '../../interface'; import type { AuthenticationPageProps, TranslatedProps } from '@staticcms/core/interface';
const LoginButtonIcon = styled(Icon)` const LoginButtonIcon = styled(Icon)`
margin-right: 18px; margin-right: 18px;

View File

@ -1,8 +1,8 @@
import minimatch from 'minimatch'; import minimatch from 'minimatch';
import { unsentRequest } from '../../lib/util'; import { unsentRequest } from '@staticcms/core/lib/util';
import type { ApiRequest, PointerFile } from '../../lib/util'; import type { ApiRequest, PointerFile } from '@staticcms/core/lib/util';
type MakeAuthorizedRequest = (req: ApiRequest) => Promise<Response>; type MakeAuthorizedRequest = (req: ApiRequest) => Promise<Response>;
@ -37,7 +37,7 @@ interface LfsBatchUploadResponse {
objects: (LfsBatchObjectUpload | LfsBatchObjectError)[]; objects: (LfsBatchObjectUpload | LfsBatchObjectError)[];
} }
export class GitLfsClient { export default class GitLfsClient {
private static defaultContentHeaders = { private static defaultContentHeaders = {
Accept: 'application/vnd.git-lfs+json', Accept: 'application/vnd.git-lfs+json',
['Content-Type']: 'application/vnd.git-lfs+json', ['Content-Type']: 'application/vnd.git-lfs+json',

View File

@ -2,7 +2,7 @@ import { stripIndent } from 'common-tags';
import trimStart from 'lodash/trimStart'; import trimStart from 'lodash/trimStart';
import semaphore from 'semaphore'; import semaphore from 'semaphore';
import { NetlifyAuthenticator } from '../../lib/auth'; import { NetlifyAuthenticator } from '@staticcms/core/lib/auth';
import { import {
AccessTokenError, AccessTokenError,
allEntriesByFolder, allEntriesByFolder,
@ -22,10 +22,10 @@ import {
localForage, localForage,
runWithLock, runWithLock,
unsentRequest, unsentRequest,
} from '../../lib/util'; } from '@staticcms/core/lib/util';
import API, { API_NAME } from './API'; import API, { API_NAME } from './API';
import AuthenticationPage from './AuthenticationPage'; import AuthenticationPage from './AuthenticationPage';
import { GitLfsClient } from './git-lfs-client'; import GitLfsClient from './git-lfs-client';
import type { Semaphore } from 'semaphore'; import type { Semaphore } from 'semaphore';
import type { import type {
@ -37,9 +37,9 @@ import type {
ImplementationFile, ImplementationFile,
PersistOptions, PersistOptions,
User, User,
} from '../../interface'; } from '@staticcms/core/interface';
import type { ApiRequest, AsyncLock, Cursor, FetchError } from '../../lib/util'; import type { ApiRequest, AsyncLock, Cursor, FetchError } from '@staticcms/core/lib/util';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
const MAX_CONCURRENT_DOWNLOADS = 10; const MAX_CONCURRENT_DOWNLOADS = 10;

View File

@ -1,8 +1,8 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import AuthenticationPage from '../../components/UI/AuthenticationPage'; import AuthenticationPage from '@staticcms/core/components/UI/AuthenticationPage';
import type { AuthenticationPageProps, TranslatedProps, User } from '../../interface'; import type { AuthenticationPageProps, TranslatedProps, User } from '@staticcms/core/interface';
function useNetlifyIdentifyEvent(eventName: 'login', callback: (login: User) => void): void; function useNetlifyIdentifyEvent(eventName: 'login', callback: (login: User) => void): void;
function useNetlifyIdentifyEvent(eventName: 'logout', callback: () => void): void; function useNetlifyIdentifyEvent(eventName: 'logout', callback: () => void): void;

View File

@ -1,7 +1,7 @@
import { APIError } from '../../lib/util'; import { APIError } from '@staticcms/core/lib/util';
import { API as GithubAPI } from '../github'; import { API as GithubAPI } from '../github';
import type { FetchError } from '../../lib/util'; import type { FetchError } from '@staticcms/core/lib/util';
import type { Config as GitHubConfig } from '../github/API'; import type { Config as GitHubConfig } from '../github/API';
type Config = GitHubConfig & { type Config = GitHubConfig & {

View File

@ -1,8 +1,8 @@
import { unsentRequest } from '../../lib/util'; import { unsentRequest } from '@staticcms/core/lib/util';
import { API as GitlabAPI } from '../gitlab'; import { API as GitlabAPI } from '../gitlab';
import type { Config as GitLabConfig, CommitAuthor } from '../gitlab/API'; import type { Config as GitLabConfig, CommitAuthor } from '../gitlab/API';
import type { ApiRequest } from '../../lib/util'; import type { ApiRequest } from '@staticcms/core/lib/util';
type Config = GitLabConfig & { tokenPromise: () => Promise<string>; commitAuthor: CommitAuthor }; type Config = GitLabConfig & { tokenPromise: () => Promise<string>; commitAuthor: CommitAuthor };

View File

@ -15,7 +15,7 @@ import {
getPointerFileForMediaFileObj, getPointerFileForMediaFileObj,
parsePointerFile, parsePointerFile,
unsentRequest, unsentRequest,
} from '../../lib/util'; } from '@staticcms/core/lib/util';
import { API as BitBucketAPI, BitbucketBackend } from '../bitbucket'; import { API as BitBucketAPI, BitbucketBackend } from '../bitbucket';
import { GitHubBackend } from '../github'; import { GitHubBackend } from '../github';
import { GitLabBackend } from '../gitlab'; import { GitLabBackend } from '../gitlab';
@ -36,9 +36,9 @@ import type {
PersistOptions, PersistOptions,
TranslatedProps, TranslatedProps,
User, User,
} from '../../interface'; } from '@staticcms/core/interface';
import type { ApiRequest, Cursor } from '../../lib/util'; import type { ApiRequest, Cursor } from '@staticcms/core/lib/util';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
import type { Client } from './netlify-lfs-client'; import type { Client } from './netlify-lfs-client';
const STATUS_PAGE = 'https://www.netlifystatus.com'; const STATUS_PAGE = 'https://www.netlifystatus.com';

View File

@ -3,9 +3,9 @@ import isPlainObject from 'lodash/isPlainObject';
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import minimatch from 'minimatch'; import minimatch from 'minimatch';
import { unsentRequest } from '../../lib/util'; import { unsentRequest } from '@staticcms/core/lib/util';
import type { ApiRequest, PointerFile } from '../../lib/util'; import type { ApiRequest, PointerFile } from '@staticcms/core/lib/util';
type MakeAuthorizedRequest = (req: ApiRequest) => Promise<Response>; type MakeAuthorizedRequest = (req: ApiRequest) => Promise<Response>;

View File

@ -17,13 +17,13 @@ import {
readFileMetadata, readFileMetadata,
requestWithBackoff, requestWithBackoff,
unsentRequest, unsentRequest,
} from '../../lib/util'; } from '@staticcms/core/lib/util';
import type { Octokit } from '@octokit/rest'; import type { Octokit } from '@octokit/rest';
import type { Semaphore } from 'semaphore'; import type { Semaphore } from 'semaphore';
import type { DataFile, PersistOptions } from '../../interface'; import type { DataFile, PersistOptions } from '@staticcms/core/interface';
import type { ApiRequest, FetchError } from '../../lib/util'; import type { ApiRequest, FetchError } from '@staticcms/core/lib/util';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
type GitHubUser = Octokit.UsersGetAuthenticatedResponse; type GitHubUser = Octokit.UsersGetAuthenticatedResponse;
type GitCreateTreeParamsTree = Octokit.GitCreateTreeParamsTree; type GitCreateTreeParamsTree = Octokit.GitCreateTreeParamsTree;

View File

@ -1,12 +1,12 @@
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import AuthenticationPage from '../../components/UI/AuthenticationPage'; import AuthenticationPage from '@staticcms/core/components/UI/AuthenticationPage';
import Icon from '../../components/UI/Icon'; import Icon from '@staticcms/core/components/UI/Icon';
import { NetlifyAuthenticator } from '../../lib/auth'; import { NetlifyAuthenticator } from '@staticcms/core/lib/auth';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import type { AuthenticationPageProps, TranslatedProps } from '../../interface'; import type { AuthenticationPageProps, TranslatedProps } from '@staticcms/core/interface';
const LoginButtonIcon = styled(Icon)` const LoginButtonIcon = styled(Icon)`
margin-right: 18px; margin-right: 18px;

View File

@ -16,7 +16,7 @@ import {
getMediaDisplayURL, getMediaDisplayURL,
runWithLock, runWithLock,
unsentRequest, unsentRequest,
} from '../../lib/util'; } from '@staticcms/core/lib/util';
import API, { API_NAME } from './API'; import API, { API_NAME } from './API';
import AuthenticationPage from './AuthenticationPage'; import AuthenticationPage from './AuthenticationPage';
@ -31,9 +31,9 @@ import type {
ImplementationFile, ImplementationFile,
PersistOptions, PersistOptions,
User, User,
} from '../../interface'; } from '@staticcms/core/interface';
import type { AsyncLock } from '../../lib/util'; import type { AsyncLock } from '@staticcms/core/lib/util';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
type GitHubUser = Octokit.UsersGetAuthenticatedResponse; type GitHubUser = Octokit.UsersGetAuthenticatedResponse;

View File

@ -1,3 +1,4 @@
/* eslint-disable import/prefer-default-export */
import { gql } from 'graphql-tag'; import { gql } from 'graphql-tag';
import * as fragments from './fragments'; import * as fragments from './fragments';

View File

@ -15,11 +15,11 @@ import {
responseParser, responseParser,
throwOnConflictingBranches, throwOnConflictingBranches,
unsentRequest, unsentRequest,
} from '../../lib/util'; } from '@staticcms/core/lib/util';
import type { DataFile, PersistOptions } from '../../interface'; import type { DataFile, PersistOptions } from '@staticcms/core/interface';
import type { ApiRequest, FetchError } from '../../lib/util'; import type { ApiRequest, FetchError } from '@staticcms/core/lib/util';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
export const API_NAME = 'GitLab'; export const API_NAME = 'GitLab';

View File

@ -1,17 +1,17 @@
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import AuthenticationPage from '../../components/UI/AuthenticationPage'; import AuthenticationPage from '@staticcms/core/components/UI/AuthenticationPage';
import Icon from '../../components/UI/Icon'; import Icon from '@staticcms/core/components/UI/Icon';
import { NetlifyAuthenticator, PkceAuthenticator } from '../../lib/auth'; import { NetlifyAuthenticator, PkceAuthenticator } from '@staticcms/core/lib/auth';
import { isNotEmpty } from '../../lib/util/string.util'; import { isNotEmpty } from '@staticcms/core/lib/util/string.util';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import type { import type {
AuthenticationPageProps, AuthenticationPageProps,
AuthenticatorConfig, AuthenticatorConfig,
TranslatedProps, TranslatedProps,
} from '../../interface'; } from '@staticcms/core/interface';
const LoginButtonIcon = styled(Icon)` const LoginButtonIcon = styled(Icon)`
margin-right: 18px; margin-right: 18px;

View File

@ -17,12 +17,12 @@ import {
getMediaDisplayURL, getMediaDisplayURL,
localForage, localForage,
runWithLock, runWithLock,
} from '../../lib/util'; } from '@staticcms/core/lib/util';
import API, { API_NAME } from './API'; import API, { API_NAME } from './API';
import AuthenticationPage from './AuthenticationPage'; import AuthenticationPage from './AuthenticationPage';
import type { Semaphore } from 'semaphore'; import type { Semaphore } from 'semaphore';
import type { AsyncLock, Cursor } from '../../lib/util'; import type { AsyncLock, Cursor } from '@staticcms/core/lib/util';
import type { import type {
Config, Config,
Credentials, Credentials,
@ -32,8 +32,8 @@ import type {
ImplementationFile, ImplementationFile,
PersistOptions, PersistOptions,
User, User,
} from '../../interface'; } from '@staticcms/core/interface';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
const MAX_CONCURRENT_DOWNLOADS = 10; const MAX_CONCURRENT_DOWNLOADS = 10;

View File

@ -2,11 +2,11 @@ import Button from '@mui/material/Button';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import GoBackButton from '../../components/UI/GoBackButton'; import GoBackButton from '@staticcms/core/components/UI/GoBackButton';
import Icon from '../../components/UI/Icon'; import Icon from '@staticcms/core/components/UI/Icon';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import type { AuthenticationPageProps, TranslatedProps } from '../../interface'; import type { AuthenticationPageProps, TranslatedProps } from '@staticcms/core/interface';
const StyledAuthenticationPage = styled('section')` const StyledAuthenticationPage = styled('section')`
display: flex; display: flex;

View File

@ -1,4 +1,4 @@
import { APIError, basename, blobToFileObj, unsentRequest } from '../../lib/util'; import { APIError, basename, blobToFileObj, unsentRequest } from '@staticcms/core/lib/util';
import AuthenticationPage from './AuthenticationPage'; import AuthenticationPage from './AuthenticationPage';
import type { import type {
@ -10,9 +10,9 @@ import type {
ImplementationFile, ImplementationFile,
PersistOptions, PersistOptions,
User, User,
} from '../../interface'; } from '@staticcms/core/interface';
import type { Cursor } from '../../lib/util'; import type { Cursor } from '@staticcms/core/lib/util';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
async function serializeAsset(assetProxy: AssetProxy) { async function serializeAsset(assetProxy: AssetProxy) {
const base64content = await assetProxy.toBase64!(); const base64content = await assetProxy.toBase64!();

View File

@ -2,11 +2,11 @@ import Button from '@mui/material/Button';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback, useEffect } from 'react'; import React, { useCallback, useEffect } from 'react';
import GoBackButton from '../../components/UI/GoBackButton'; import GoBackButton from '@staticcms/core/components/UI/GoBackButton';
import Icon from '../../components/UI/Icon'; import Icon from '@staticcms/core/components/UI/Icon';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import type { AuthenticationPageProps, TranslatedProps } from '../../interface'; import type { AuthenticationPageProps, TranslatedProps } from '@staticcms/core/interface';
const StyledAuthenticationPage = styled('section')` const StyledAuthenticationPage = styled('section')`
display: flex; display: flex;

View File

@ -5,7 +5,7 @@ import unset from 'lodash/unset';
import { extname } from 'path'; import { extname } from 'path';
import uuid from 'uuid/v4'; import uuid from 'uuid/v4';
import { basename, Cursor, CURSOR_COMPATIBILITY_SYMBOL } from '../../lib/util'; import { basename, Cursor, CURSOR_COMPATIBILITY_SYMBOL } from '@staticcms/core/lib/util';
import AuthenticationPage from './AuthenticationPage'; import AuthenticationPage from './AuthenticationPage';
import type { import type {
@ -16,8 +16,8 @@ import type {
ImplementationEntry, ImplementationEntry,
ImplementationFile, ImplementationFile,
User, User,
} from '../../interface'; } from '@staticcms/core/interface';
import type AssetProxy from '../../valueObjects/AssetProxy'; import type AssetProxy from '@staticcms/core/valueObjects/AssetProxy';
type RepoFile = { path: string; content: string | AssetProxy }; type RepoFile = { path: string; content: string | AssetProxy };
type RepoTree = { [key: string]: RepoFile | RepoTree }; type RepoTree = { [key: string]: RepoFile | RepoTree };

View File

@ -12,7 +12,7 @@ import { loadConfig } from './actions/config';
import App from './components/App/App'; import App from './components/App/App';
import './components/EditorWidgets'; import './components/EditorWidgets';
import { ErrorBoundary } from './components/UI'; import { ErrorBoundary } from './components/UI';
import { addExtensions } from './extensions'; import addExtensions from './extensions';
import { getPhrases } from './lib/phrases'; import { getPhrases } from './lib/phrases';
import './mediaLibrary'; import './mediaLibrary';
import { selectLocale } from './reducers/config'; import { selectLocale } from './reducers/config';

View File

@ -1,18 +1,18 @@
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
import Fab from '@mui/material/Fab'; import Fab from '@mui/material/Fab';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useEffect, useMemo } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom'; import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom';
import { ScrollSync } from 'react-scroll-sync'; import { ScrollSync } from 'react-scroll-sync';
import TopBarProgress from 'react-topbar-progress-indicator'; import TopBarProgress from 'react-topbar-progress-indicator';
import { loginUser as loginUserAction } from '../../actions/auth'; import { loginUser as loginUserAction } from '@staticcms/core/actions/auth';
import { discardDraft as discardDraftAction } from '../../actions/entries'; import { discardDraft as discardDraftAction } from '@staticcms/core/actions/entries';
import { currentBackend } from '../../backend'; import { currentBackend } from '@staticcms/core/backend';
import { colors, GlobalStyles } from '../../components/UI/styles'; import { colors, GlobalStyles } from '@staticcms/core/components/UI/styles';
import { history } from '../../routing/history'; import { history } from '@staticcms/core/routing/history';
import CollectionRoute from '../Collection/CollectionRoute'; import CollectionRoute from '../Collection/CollectionRoute';
import EditorRoute from '../Editor/EditorRoute'; import EditorRoute from '../Editor/EditorRoute';
import MediaLibrary from '../MediaLibrary/MediaLibrary'; import MediaLibrary from '../MediaLibrary/MediaLibrary';
@ -24,10 +24,10 @@ import Loader from '../UI/Loader';
import ScrollTop from '../UI/ScrollTop'; import ScrollTop from '../UI/ScrollTop';
import NotFoundPage from './NotFoundPage'; import NotFoundPage from './NotFoundPage';
import type { Collections, Credentials, TranslatedProps } from '@staticcms/core/interface';
import type { RootState } from '@staticcms/core/store';
import type { ComponentType } from 'react'; import type { ComponentType } from 'react';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { Collections, Credentials, TranslatedProps } from '../../interface';
import type { RootState } from '../../store';
TopBarProgress.config({ TopBarProgress.config({
barColors: { barColors: {
@ -162,7 +162,7 @@ const App = ({
const defaultPath = useMemo(() => getDefaultPath(collections), [collections]); const defaultPath = useMemo(() => getDefaultPath(collections), [collections]);
const { pathname } = useLocation(); const { pathname } = useLocation();
React.useEffect(() => { useEffect(() => {
if (!/\/collections\/[a-zA-Z0-9_-]+\/entries\/[a-zA-Z0-9_-]+/g.test(pathname)) { if (!/\/collections\/[a-zA-Z0-9_-]+\/entries\/[a-zA-Z0-9_-]+/g.test(pathname)) {
discardDraft(); discardDraft();
} }

View File

@ -1,4 +1,3 @@
import { styled } from '@mui/material/styles';
import DescriptionIcon from '@mui/icons-material/Description'; import DescriptionIcon from '@mui/icons-material/Description';
import ImageIcon from '@mui/icons-material/Image'; import ImageIcon from '@mui/icons-material/Image';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
@ -8,24 +7,25 @@ import Button from '@mui/material/Button';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import { styled } from '@mui/material/styles';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import React, { useCallback, useEffect, useMemo } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { logoutUser as logoutUserAction } from '../../actions/auth'; import { logoutUser as logoutUserAction } from '@staticcms/core/actions/auth';
import { createNewEntry } from '../../actions/collections'; import { createNewEntry } from '@staticcms/core/actions/collections';
import { openMediaLibrary as openMediaLibraryAction } from '../../actions/mediaLibrary'; import { openMediaLibrary as openMediaLibraryAction } from '@staticcms/core/actions/mediaLibrary';
import { checkBackendStatus as checkBackendStatusAction } from '../../actions/status'; import { checkBackendStatus as checkBackendStatusAction } from '@staticcms/core/actions/status';
import { buttons, colors } from '../../components/UI/styles'; import { buttons, colors } from '@staticcms/core/components/UI/styles';
import { stripProtocol } from '../../lib/urlHelper'; import { stripProtocol } from '@staticcms/core/lib/urlHelper';
import NavLink from '../UI/NavLink'; import NavLink from '../UI/NavLink';
import SettingsDropdown from '../UI/SettingsDropdown'; import SettingsDropdown from '../UI/SettingsDropdown';
import type { ComponentType } from 'react'; import type { TranslatedProps } from '@staticcms/core/interface';
import type { RootState } from '@staticcms/core/store';
import type { ComponentType, MouseEvent } from 'react';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { TranslatedProps } from '../../interface';
import type { RootState } from '../../store';
const StyledAppBar = styled(AppBar)` const StyledAppBar = styled(AppBar)`
background-color: ${colors.foreground}; background-color: ${colors.foreground};
@ -73,9 +73,9 @@ const Header = ({
showMediaButton, showMediaButton,
checkBackendStatus, checkBackendStatus,
}: TranslatedProps<HeaderProps>) => { }: TranslatedProps<HeaderProps>) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {

View File

@ -2,7 +2,7 @@ import { styled } from '@mui/material/styles';
import React from 'react'; import React from 'react';
import TopBarProgress from 'react-topbar-progress-indicator'; import TopBarProgress from 'react-topbar-progress-indicator';
import { colors } from '../../components/UI/styles'; import { colors } from '@staticcms/core/components/UI/styles';
import Header from './Header'; import Header from './Header';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';

View File

@ -2,7 +2,7 @@ import { styled } from '@mui/material/styles';
import React from 'react'; import React from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { lengths } from '../../components/UI/styles'; import { lengths } from '@staticcms/core/components/UI/styles';
import type { ComponentType } from 'react'; import type { ComponentType } from 'react';
import type { TranslateProps } from 'react-polyglot'; import type { TranslateProps } from 'react-polyglot';

View File

@ -8,21 +8,21 @@ import {
filterByField as filterByFieldAction, filterByField as filterByFieldAction,
groupByField as groupByFieldAction, groupByField as groupByFieldAction,
sortByField as sortByFieldAction, sortByField as sortByFieldAction,
} from '../../actions/entries'; } from '@staticcms/core/actions/entries';
import { components } from '../../components/UI/styles'; import { components } from '@staticcms/core/components/UI/styles';
import { SORT_DIRECTION_ASCENDING } from '../../constants'; import { SORT_DIRECTION_ASCENDING } from '@staticcms/core/constants';
import { getNewEntryUrl } from '../../lib/urlHelper'; import { getNewEntryUrl } from '@staticcms/core/lib/urlHelper';
import { import {
selectSortableFields, selectSortableFields,
selectViewFilters, selectViewFilters,
selectViewGroups, selectViewGroups,
} from '../../lib/util/collection.util'; } from '@staticcms/core/lib/util/collection.util';
import { import {
selectEntriesFilter, selectEntriesFilter,
selectEntriesGroup, selectEntriesGroup,
selectEntriesSort, selectEntriesSort,
selectViewStyle, selectViewStyle,
} from '../../reducers/entries'; } from '@staticcms/core/reducers/entries';
import CollectionControls from './CollectionControls'; import CollectionControls from './CollectionControls';
import CollectionTop from './CollectionTop'; import CollectionTop from './CollectionTop';
import EntriesCollection from './Entries/EntriesCollection'; import EntriesCollection from './Entries/EntriesCollection';
@ -37,8 +37,8 @@ import type {
TranslatedProps, TranslatedProps,
ViewFilter, ViewFilter,
ViewGroup, ViewGroup,
} from '../../interface'; } from '@staticcms/core/interface';
import type { RootState } from '../../store'; import type { RootState } from '@staticcms/core/store';
const CollectionMain = styled('main')` const CollectionMain = styled('main')`
width: 100%; width: 100%;

View File

@ -6,7 +6,7 @@ import GroupControl from './GroupControl';
import SortControl from './SortControl'; import SortControl from './SortControl';
import ViewStyleControl from './ViewStyleControl'; import ViewStyleControl from './ViewStyleControl';
import type { CollectionViewStyle } from '../../constants/collectionViews'; import type { CollectionViewStyle } from '@staticcms/core/constants/collectionViews';
import type { import type {
FilterMap, FilterMap,
GroupMap, GroupMap,
@ -16,7 +16,7 @@ import type {
TranslatedProps, TranslatedProps,
ViewFilter, ViewFilter,
ViewGroup, ViewGroup,
} from '../../interface'; } from '@staticcms/core/interface';
const CollectionControlsContainer = styled('div')` const CollectionControlsContainer = styled('div')`
display: flex; display: flex;

View File

@ -4,7 +4,7 @@ import { Navigate, useParams } from 'react-router-dom';
import MainView from '../App/MainView'; import MainView from '../App/MainView';
import Collection from './Collection'; import Collection from './Collection';
import type { Collections } from '../../interface'; import type { Collections } from '@staticcms/core/interface';
function getDefaultPath(collections: Collections) { function getDefaultPath(collections: Collections) {
const first = Object.values(collections).filter(collection => collection.hide !== true)[0]; const first = Object.values(collections).filter(collection => collection.hide !== true)[0];

View File

@ -6,11 +6,11 @@ import TextField from '@mui/material/TextField';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { colors, colorsRaw, lengths } from '../../components/UI/styles'; import { colors, colorsRaw, lengths } from '@staticcms/core/components/UI/styles';
import { transientOptions } from '../../lib'; import { transientOptions } from '@staticcms/core/lib';
import type { ChangeEvent, FocusEvent, KeyboardEvent, MouseEvent } from 'react'; import type { ChangeEvent, FocusEvent, KeyboardEvent, MouseEvent } from 'react';
import type { Collection, Collections, TranslatedProps } from '../../interface'; import type { Collection, Collections, TranslatedProps } from '@staticcms/core/interface';
const SearchContainer = styled('div')` const SearchContainer = styled('div')`
position: relative; position: relative;

View File

@ -6,9 +6,9 @@ import React, { useCallback } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { components } from '../../components/UI/styles'; import { components } from '@staticcms/core/components/UI/styles';
import type { Collection, TranslatedProps } from '../../interface'; import type { Collection, TranslatedProps } from '@staticcms/core/interface';
const CollectionTopRow = styled('div')` const CollectionTopRow = styled('div')`
display: flex; display: flex;

View File

@ -2,12 +2,12 @@ import { styled } from '@mui/material/styles';
import React from 'react'; import React from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import Loader from '../../UI/Loader'; import Loader from '@staticcms/core/components/UI/Loader';
import EntryListing from './EntryListing'; import EntryListing from './EntryListing';
import type { CollectionViewStyle } from '../../../constants/collectionViews'; import type { CollectionViewStyle } from '@staticcms/core/constants/collectionViews';
import type { Collection, Collections, Entry, TranslatedProps } from '../../../interface'; import type { Collection, Collections, Entry, TranslatedProps } from '@staticcms/core/interface';
import type Cursor from '../../../lib/util/Cursor'; import type Cursor from '@staticcms/core/lib/util/Cursor';
const PaginationMessage = styled('div')` const PaginationMessage = styled('div')`
padding: 16px; padding: 16px;

View File

@ -6,24 +6,24 @@ import { connect } from 'react-redux';
import { import {
loadEntries as loadEntriesAction, loadEntries as loadEntriesAction,
traverseCollectionCursor as traverseCollectionCursorAction, traverseCollectionCursor as traverseCollectionCursorAction,
} from '../../../actions/entries'; } from '@staticcms/core/actions/entries';
import { colors } from '../../../components/UI/styles'; import { colors } from '@staticcms/core/components/UI/styles';
import { Cursor } from '../../../lib/util'; import { Cursor } from '@staticcms/core/lib/util';
import { selectCollectionEntriesCursor } from '../../../reducers/cursors'; import { selectCollectionEntriesCursor } from '@staticcms/core/reducers/cursors';
import { import {
selectEntries, selectEntries,
selectEntriesLoaded, selectEntriesLoaded,
selectGroups, selectGroups,
selectIsFetching, selectIsFetching,
} from '../../../reducers/entries'; } from '@staticcms/core/reducers/entries';
import Entries from './Entries'; import Entries from './Entries';
import type { ComponentType } from 'react'; import type { ComponentType } from 'react';
import type { t } from 'react-polyglot'; import type { t } from 'react-polyglot';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { CollectionViewStyle } from '../../../constants/collectionViews'; import type { CollectionViewStyle } from '@staticcms/core/constants/collectionViews';
import type { Collection, Entry, GroupOfEntries, TranslatedProps } from '../../../interface'; import type { Collection, Entry, GroupOfEntries, TranslatedProps } from '@staticcms/core/interface';
import type { RootState } from '../../../store'; import type { RootState } from '@staticcms/core/store';
const GroupHeading = styled('h2')` const GroupHeading = styled('h2')`
font-size: 23px; font-size: 23px;

View File

@ -5,15 +5,15 @@ import { connect } from 'react-redux';
import { import {
clearSearch as clearSearchAction, clearSearch as clearSearchAction,
searchEntries as searchEntriesAction, searchEntries as searchEntriesAction,
} from '../../../actions/search'; } from '@staticcms/core/actions/search';
import { Cursor } from '../../../lib/util'; import { Cursor } from '@staticcms/core/lib/util';
import { selectSearchedEntries } from '../../../reducers'; import { selectSearchedEntries } from '@staticcms/core/reducers';
import Entries from './Entries'; import Entries from './Entries';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { CollectionViewStyle } from '../../../constants/collectionViews'; import type { CollectionViewStyle } from '@staticcms/core/constants/collectionViews';
import type { Collections } from '../../../interface'; import type { Collections } from '@staticcms/core/interface';
import type { RootState } from '../../../store'; import type { RootState } from '@staticcms/core/store';
const EntriesSearch = ({ const EntriesSearch = ({
collections, collections,

View File

@ -7,15 +7,15 @@ import React, { useEffect, useMemo, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { getAsset as getAssetAction } from '../../../actions/media'; import { getAsset as getAssetAction } from '@staticcms/core/actions/media';
import { VIEW_STYLE_GRID, VIEW_STYLE_LIST } from '../../../constants/collectionViews'; import { VIEW_STYLE_GRID, VIEW_STYLE_LIST } from '@staticcms/core/constants/collectionViews';
import { selectEntryCollectionTitle } from '../../../lib/util/collection.util'; import { selectEntryCollectionTitle } from '@staticcms/core/lib/util/collection.util';
import { selectIsLoadingAsset } from '../../../reducers/medias'; import { selectIsLoadingAsset } from '@staticcms/core/reducers/medias';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { CollectionViewStyle } from '../../../constants/collectionViews'; import type { CollectionViewStyle } from '@staticcms/core/constants/collectionViews';
import type { Field, Collection, Entry } from '../../../interface'; import type { Field, Collection, Entry } from '@staticcms/core/interface';
import type { RootState } from '../../../store'; import type { RootState } from '@staticcms/core/store';
const EntryCard = ({ const EntryCard = ({
collection, collection,

View File

@ -2,14 +2,14 @@ import { styled } from '@mui/material/styles';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import { Waypoint } from 'react-waypoint'; import { Waypoint } from 'react-waypoint';
import { VIEW_STYLE_LIST } from '../../../constants/collectionViews'; import { VIEW_STYLE_LIST } from '@staticcms/core/constants/collectionViews';
import { transientOptions } from '../../../lib'; import { transientOptions } from '@staticcms/core/lib';
import { selectFields, selectInferedField } from '../../../lib/util/collection.util'; import { selectFields, selectInferedField } from '@staticcms/core/lib/util/collection.util';
import EntryCard from './EntryCard'; import EntryCard from './EntryCard';
import type { CollectionViewStyle } from '../../../constants/collectionViews'; import type { CollectionViewStyle } from '@staticcms/core/constants/collectionViews';
import type { Field, Collection, Collections, Entry } from '../../../interface'; import type { Field, Collection, Collections, Entry } from '@staticcms/core/interface';
import type Cursor from '../../../lib/util/Cursor'; import type Cursor from '@staticcms/core/lib/util/Cursor';
interface CardsGridProps { interface CardsGridProps {
$layout: CollectionViewStyle; $layout: CollectionViewStyle;

View File

@ -5,10 +5,11 @@ import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText'; import ListItemText from '@mui/material/ListItemText';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import type { FilterMap, TranslatedProps, ViewFilter } from '../../interface'; import type { FilterMap, TranslatedProps, ViewFilter } from '@staticcms/core/interface';
import type { MouseEvent } from 'react';
interface FilterControlProps { interface FilterControlProps {
filter: Record<string, FilterMap>; filter: Record<string, FilterMap>;
@ -22,9 +23,9 @@ const FilterControl = ({
onFilterClick, onFilterClick,
filter, filter,
}: TranslatedProps<FilterControlProps>) => { }: TranslatedProps<FilterControlProps>) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {

View File

@ -1,14 +1,15 @@
import CheckIcon from '@mui/icons-material/Check';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import Button from '@mui/material/Button/Button'; import Button from '@mui/material/Button';
import ListItemText from '@mui/material/ListItemText'; import ListItemText from '@mui/material/ListItemText';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import React, { useCallback, useMemo } from 'react';
import { translate } from 'react-polyglot';
import CheckIcon from '@mui/icons-material/Check';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback, useMemo, useState } from 'react';
import { translate } from 'react-polyglot';
import type { GroupMap, TranslatedProps, ViewGroup } from '../../interface'; import type { GroupMap, TranslatedProps, ViewGroup } from '@staticcms/core/interface';
import type { MouseEvent } from 'react';
const StyledMenuIconWrapper = styled('div')` const StyledMenuIconWrapper = styled('div')`
width: 32px; width: 32px;
@ -30,9 +31,9 @@ const GroupControl = ({
t, t,
onGroupClick, onGroupClick,
}: TranslatedProps<GroupControlProps>) => { }: TranslatedProps<GroupControlProps>) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {

View File

@ -1,20 +1,20 @@
import { styled } from '@mui/material/styles';
import ArticleIcon from '@mui/icons-material/Article'; import ArticleIcon from '@mui/icons-material/Article';
import { styled } from '@mui/material/styles';
import sortBy from 'lodash/sortBy'; import sortBy from 'lodash/sortBy';
import { dirname, sep } from 'path'; import { dirname, sep } from 'path';
import React, { useCallback, useEffect, useState } from 'react'; import React, { Fragment, useCallback, useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { colors, components } from '../../components/UI/styles'; import { colors, components } from '@staticcms/core/components/UI/styles';
import { transientOptions } from '../../lib'; import { transientOptions } from '@staticcms/core/lib';
import { selectEntryCollectionTitle } from '../../lib/util/collection.util'; import { selectEntryCollectionTitle } from '@staticcms/core/lib/util/collection.util';
import { stringTemplate } from '../../lib/widgets'; import { stringTemplate } from '@staticcms/core/lib/widgets';
import { selectEntries } from '../../reducers/entries'; import { selectEntries } from '@staticcms/core/reducers/entries';
import type { Collection, Entry } from '@staticcms/core/interface';
import type { RootState } from '@staticcms/core/store';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { Collection, Entry } from '../../interface';
import type { RootState } from '../../store';
const { addFileTemplateFields } = stringTemplate; const { addFileTemplateFields } = stringTemplate;
@ -124,7 +124,7 @@ const TreeNode = ({ collection, treeData, depth = 0, onToggle }: TreeNodeProps)
const hasChildren = depth === 0 || node.children.some(c => c.children.some(c => c.isDir)); const hasChildren = depth === 0 || node.children.some(c => c.children.some(c => c.isDir));
return ( return (
<React.Fragment key={node.path}> <Fragment key={node.path}>
<TreeNavLink <TreeNavLink
to={to} to={to}
$activeClassName="sidebar-active" $activeClassName="sidebar-active"
@ -146,7 +146,7 @@ const TreeNode = ({ collection, treeData, depth = 0, onToggle }: TreeNodeProps)
onToggle={onToggle} onToggle={onToggle}
/> />
)} )}
</React.Fragment> </Fragment>
); );
})} })}
</> </>

View File

@ -11,15 +11,15 @@ import Typography from '@mui/material/Typography';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { searchCollections } from '../../actions/collections'; import { searchCollections } from '@staticcms/core/actions/collections';
import { colors } from '../../components/UI/styles'; import { colors } from '@staticcms/core/components/UI/styles';
import { getAdditionalLinks, getIcon } from '../../lib/registry'; import { getAdditionalLinks, getIcon } from '@staticcms/core/lib/registry';
import NavLink from '../UI/NavLink'; import NavLink from '../UI/NavLink';
import CollectionSearch from './CollectionSearch'; import CollectionSearch from './CollectionSearch';
import NestedCollection from './NestedCollection'; import NestedCollection from './NestedCollection';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import type { Collection, Collections, TranslatedProps } from '../../interface'; import type { Collection, Collections, TranslatedProps } from '@staticcms/core/interface';
const StyledSidebar = styled('div')` const StyledSidebar = styled('div')`
position: sticky; position: sticky;

View File

@ -1,20 +1,26 @@
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
import { styled } from '@mui/material';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import ListItemText from '@mui/material/ListItemText'; import ListItemText from '@mui/material/ListItemText';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import React, { useCallback, useMemo } from 'react'; import { styled } from '@mui/material/styles';
import React, { useCallback, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { import {
SORT_DIRECTION_ASCENDING, SORT_DIRECTION_ASCENDING,
SORT_DIRECTION_DESCENDING, SORT_DIRECTION_DESCENDING,
SORT_DIRECTION_NONE, SORT_DIRECTION_NONE,
} from '../../constants'; } from '@staticcms/core/constants';
import type { SortableField, SortDirection, SortMap, TranslatedProps } from '../../interface'; import type {
SortableField,
SortDirection,
SortMap,
TranslatedProps,
} from '@staticcms/core/interface';
import type { MouseEvent } from 'react';
const StyledMenuIconWrapper = styled('div')` const StyledMenuIconWrapper = styled('div')`
width: 32px; width: 32px;
@ -42,9 +48,9 @@ interface SortControlProps {
} }
const SortControl = ({ t, fields, onSortClick, sort }: TranslatedProps<SortControlProps>) => { const SortControl = ({ t, fields, onSortClick, sort }: TranslatedProps<SortControlProps>) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {

View File

@ -4,9 +4,9 @@ import ReorderSharpIcon from '@mui/icons-material/ReorderSharp';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import React from 'react'; import React from 'react';
import { VIEW_STYLE_GRID, VIEW_STYLE_LIST } from '../../constants/collectionViews'; import { VIEW_STYLE_GRID, VIEW_STYLE_LIST } from '@staticcms/core/constants/collectionViews';
import type { CollectionViewStyle } from '../../constants/collectionViews'; import type { CollectionViewStyle } from '@staticcms/core/constants/collectionViews';
const ViewControlsSection = styled('div')` const ViewControlsSection = styled('div')`
margin-left: 24px; margin-left: 24px;

View File

@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { logoutUser as logoutUserAction } from '../../actions/auth'; import { logoutUser as logoutUserAction } from '@staticcms/core/actions/auth';
import { import {
changeDraftFieldValidation as changeDraftFieldValidationAction, changeDraftFieldValidation as changeDraftFieldValidationAction,
createDraftDuplicateFromEntry as createDraftDuplicateFromEntryAction, createDraftDuplicateFromEntry as createDraftDuplicateFromEntryAction,
@ -18,15 +18,15 @@ import {
persistEntry as persistEntryAction, persistEntry as persistEntryAction,
persistLocalBackup as persistLocalBackupAction, persistLocalBackup as persistLocalBackupAction,
retrieveLocalBackup as retrieveLocalBackupAction, retrieveLocalBackup as retrieveLocalBackupAction,
} from '../../actions/entries'; } from '@staticcms/core/actions/entries';
import { import {
loadScroll as loadScrollAction, loadScroll as loadScrollAction,
toggleScroll as toggleScrollAction, toggleScroll as toggleScrollAction,
} from '../../actions/scroll'; } from '@staticcms/core/actions/scroll';
import { selectFields } from '../../lib/util/collection.util'; import { selectFields } from '@staticcms/core/lib/util/collection.util';
import { useWindowEvent } from '../../lib/util/window.util'; import { useWindowEvent } from '@staticcms/core/lib/util/window.util';
import { selectEntry } from '../../reducers'; import { selectEntry } from '@staticcms/core/reducers';
import { history, navigateToCollection, navigateToNewEntry } from '../../routing/history'; import { history, navigateToCollection, navigateToNewEntry } from '@staticcms/core/routing/history';
import confirm from '../UI/Confirm'; import confirm from '../UI/Confirm';
import Loader from '../UI/Loader'; import Loader from '../UI/Loader';
import EditorInterface from './EditorInterface'; import EditorInterface from './EditorInterface';
@ -34,8 +34,13 @@ import EditorInterface from './EditorInterface';
import type { TransitionPromptHook } from 'history'; import type { TransitionPromptHook } from 'history';
import type { ComponentType } from 'react'; import type { ComponentType } from 'react';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { Collection, EditorPersistOptions, Entry, TranslatedProps } from '../../interface'; import type {
import type { RootState } from '../../store'; Collection,
EditorPersistOptions,
Entry,
TranslatedProps,
} from '@staticcms/core/interface';
import type { RootState } from '@staticcms/core/store';
const Editor = ({ const Editor = ({
entry, entry,

View File

@ -1,30 +1,30 @@
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import { isEqual } from 'lodash';
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { createElement, useCallback, useEffect, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
changeDraftField as changeDraftFieldAction, changeDraftField as changeDraftFieldAction,
changeDraftFieldValidation as changeDraftFieldValidationAction, changeDraftFieldValidation as changeDraftFieldValidationAction,
} from '../../../actions/entries'; } from '@staticcms/core/actions/entries';
import { getAsset as getAssetAction } from '../../../actions/media'; import { getAsset as getAssetAction } from '@staticcms/core/actions/media';
import { import {
clearMediaControl as clearMediaControlAction, clearMediaControl as clearMediaControlAction,
openMediaLibrary as openMediaLibraryAction, openMediaLibrary as openMediaLibraryAction,
removeInsertedMedia as removeInsertedMediaAction, removeInsertedMedia as removeInsertedMediaAction,
removeMediaControl as removeMediaControlAction, removeMediaControl as removeMediaControlAction,
} from '../../../actions/mediaLibrary'; } from '@staticcms/core/actions/mediaLibrary';
import { query as queryAction } from '../../../actions/search'; import { query as queryAction } from '@staticcms/core/actions/search';
import { borders, colors, lengths, transitions } from '../../../components/UI/styles'; import { borders, colors, lengths, transitions } from '@staticcms/core/components/UI/styles';
import { transientOptions } from '../../../lib'; import { transientOptions } from '@staticcms/core/lib';
import { resolveWidget } from '../../../lib/registry'; import useMemoCompare from '@staticcms/core/lib/hooks/useMemoCompare';
import { getFieldLabel } from '../../../lib/util/field.util'; import { resolveWidget } from '@staticcms/core/lib/registry';
import { validate } from '../../../lib/util/validation.util'; import { getFieldLabel } from '@staticcms/core/lib/util/field.util';
import { selectIsLoadingAsset } from '../../../reducers/medias'; import { validate } from '@staticcms/core/lib/util/validation.util';
import { selectIsLoadingAsset } from '@staticcms/core/reducers/medias';
import type { ComponentType } from 'react';
import type { ConnectedProps } from 'react-redux';
import type { import type {
Field, Field,
FieldsErrors, FieldsErrors,
@ -34,8 +34,10 @@ import type {
UnknownField, UnknownField,
ValueOrNestedValue, ValueOrNestedValue,
Widget, Widget,
} from '../../../interface'; } from '@staticcms/core/interface';
import type { RootState } from '../../../store'; import type { RootState } from '@staticcms/core/store';
import type { ComponentType } from 'react';
import type { ConnectedProps } from 'react-redux';
/** /**
* This is a necessary bridge as we are still passing classnames to widgets * This is a necessary bridge as we are still passing classnames to widgets
@ -130,7 +132,6 @@ const ControlHint = styled(
); );
const EditorControl = ({ const EditorControl = ({
className,
clearMediaControl, clearMediaControl,
collection, collection,
config: configState, config: configState,
@ -167,7 +168,8 @@ const EditorControl = ({
); );
const [dirty, setDirty] = useState(!isEmpty(value)); const [dirty, setDirty] = useState(!isEmpty(value));
const errors = useMemo(() => fieldsErrors[path] ?? [], [fieldsErrors, path]); // eslint-disable-next-line react-hooks/exhaustive-deps
const errors = useMemo(() => fieldsErrors[path] ?? [], [fieldsErrors[path]]);
const hasErrors = (submitted || dirty) && Boolean(errors.length); const hasErrors = (submitted || dirty) && Boolean(errors.length);
const handleGetAsset: GetAssetFunction = useMemo( const handleGetAsset: GetAssetFunction = useMemo(
@ -189,71 +191,101 @@ const EditorControl = ({
const handleChangeDraftField = useCallback( const handleChangeDraftField = useCallback(
(value: ValueOrNestedValue) => { (value: ValueOrNestedValue) => {
setDirty(true); setDirty(true);
changeDraftField({ path, field, value, entry, i18n }); changeDraftField({ path, field, value, i18n });
}, },
[changeDraftField, entry, field, i18n, path], [changeDraftField, field, i18n, path],
); );
const config = useMemo(() => configState.config, [configState.config]); const config = useMemo(() => configState.config, [configState.config]);
if (!collection || !entry || !config) {
return null;
}
return ( const finalValue = useMemoCompare(value, isEqual);
<ControlContainer className={className} $isHidden={isHidden}>
<> return useMemo(() => {
{React.createElement(widget.control, { if (!collection || !entry || !config) {
key: `field_${path}`, return null;
collection, }
config,
entry, return (
field: field as UnknownField, <ControlContainer $isHidden={isHidden}>
fieldsErrors, <>
submitted, {createElement(widget.control, {
getAsset: handleGetAsset, key: `field_${path}`,
isDisabled: isDisabled ?? false, collection,
isFieldDuplicate, config,
isFieldHidden, entry,
label: getFieldLabel(field, t), field: field as UnknownField,
locale, fieldsErrors,
mediaPaths, submitted,
onChange: handleChangeDraftField, getAsset: handleGetAsset,
clearMediaControl, isDisabled: isDisabled ?? false,
openMediaLibrary, isFieldDuplicate,
removeInsertedMedia, isFieldHidden,
removeMediaControl, label: getFieldLabel(field, t),
path, locale,
query, mediaPaths,
t, onChange: handleChangeDraftField,
value, clearMediaControl,
forList, openMediaLibrary,
i18n, removeInsertedMedia,
hasErrors, removeMediaControl,
})} path,
{fieldHint ? ( query,
<ControlHint key="hint" $error={hasErrors}> t,
{fieldHint} value: finalValue,
</ControlHint> forList,
) : null} i18n,
{hasErrors ? ( hasErrors,
<ControlErrorsList key="errors"> })}
{errors.map(error => { {fieldHint ? (
return ( <ControlHint key="hint" $error={hasErrors}>
error.message && {fieldHint}
typeof error.message === 'string' && ( </ControlHint>
<li key={error.message.trim().replace(/[^a-z0-9]+/gi, '-')}>{error.message}</li> ) : null}
) {hasErrors ? (
); <ControlErrorsList key="errors">
})} {errors.map(error => {
</ControlErrorsList> return (
) : null} error.message &&
</> typeof error.message === 'string' && (
</ControlContainer> <li key={error.message.trim().replace(/[^a-z0-9]+/gi, '-')}>{error.message}</li>
); )
);
})}
</ControlErrorsList>
) : null}
</>
</ControlContainer>
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
collection,
config,
path,
errors,
isHidden,
widget.control,
field,
submitted,
handleGetAsset,
isDisabled,
t,
locale,
mediaPaths,
handleChangeDraftField,
clearMediaControl,
openMediaLibrary,
removeInsertedMedia,
removeMediaControl,
query,
finalValue,
forList,
i18n,
hasErrors,
fieldHint,
]);
}; };
interface EditorControlOwnProps { interface EditorControlOwnProps {
className?: string;
field: Field; field: Field;
fieldsErrors: FieldsErrors; fieldsErrors: FieldsErrors;
submitted: boolean; submitted: boolean;

View File

@ -3,11 +3,11 @@ import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import get from 'lodash/get'; import get from 'lodash/get';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { changeDraftField as changeDraftFieldAction } from '../../../actions/entries'; import { changeDraftField as changeDraftFieldAction } from '@staticcms/core/actions/entries';
import confirm from '../../../components/UI/Confirm'; import confirm from '@staticcms/core/components/UI/Confirm';
import { import {
getI18nInfo, getI18nInfo,
getLocaleDataPath, getLocaleDataPath,
@ -15,10 +15,9 @@ import {
isFieldDuplicate, isFieldDuplicate,
isFieldHidden, isFieldHidden,
isFieldTranslatable, isFieldTranslatable,
} from '../../../lib/i18n'; } from '@staticcms/core/lib/i18n';
import EditorControl from './EditorControl'; import EditorControl from './EditorControl';
import type { ConnectedProps } from 'react-redux';
import type { import type {
Collection, Collection,
Entry, Entry,
@ -27,8 +26,10 @@ import type {
I18nSettings, I18nSettings,
TranslatedProps, TranslatedProps,
ValueOrNestedValue, ValueOrNestedValue,
} from '../../../interface'; } from '@staticcms/core/interface';
import type { RootState } from '../../../store'; import type { RootState } from '@staticcms/core/store';
import type { MouseEvent } from 'react';
import type { ConnectedProps } from 'react-redux';
const ControlPaneContainer = styled('div')` const ControlPaneContainer = styled('div')`
max-width: 1000px; max-width: 1000px;
@ -50,9 +51,9 @@ interface LocaleDropdownProps {
} }
const LocaleDropdown = ({ locales, dropdownText, onLocaleChange }: LocaleDropdownProps) => { const LocaleDropdown = ({ locales, dropdownText, onLocaleChange }: LocaleDropdownProps) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {
@ -154,7 +155,7 @@ const EditorControlPane = ({
sourceLocale !== i18n?.defaultLocale, sourceLocale !== i18n?.defaultLocale,
sourceLocale, sourceLocale,
); );
changeDraftField({ path: field.name, field, value: copyValue, entry, i18n }); changeDraftField({ path: field.name, field, value: copyValue, i18n });
} }
}); });
}, },

View File

@ -6,10 +6,10 @@ import { styled } from '@mui/material/styles';
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { ScrollSync, ScrollSyncPane } from 'react-scroll-sync'; import { ScrollSync, ScrollSyncPane } from 'react-scroll-sync';
import { colorsRaw, components, zIndex } from '../../components/UI/styles'; import { colorsRaw, components, zIndex } from '@staticcms/core/components/UI/styles';
import { transientOptions } from '../../lib'; import { transientOptions } from '@staticcms/core/lib';
import { getI18nInfo, getPreviewEntry, hasI18n } from '../../lib/i18n'; import { getI18nInfo, getPreviewEntry, hasI18n } from '@staticcms/core/lib/i18n';
import { getFileFromSlug } from '../../lib/util/collection.util'; import { getFileFromSlug } from '@staticcms/core/lib/util/collection.util';
import EditorControlPane from './EditorControlPane/EditorControlPane'; import EditorControlPane from './EditorControlPane/EditorControlPane';
import EditorPreviewPane from './EditorPreviewPane/EditorPreviewPane'; import EditorPreviewPane from './EditorPreviewPane/EditorPreviewPane';
import EditorToolbar from './EditorToolbar'; import EditorToolbar from './EditorToolbar';
@ -22,7 +22,7 @@ import type {
FieldsErrors, FieldsErrors,
TranslatedProps, TranslatedProps,
User, User,
} from '../../interface'; } from '@staticcms/core/interface';
const PREVIEW_VISIBLE = 'cms.preview-visible'; const PREVIEW_VISIBLE = 'cms.preview-visible';
const I18N_VISIBLE = 'cms.i18n-visible'; const I18N_VISIBLE = 'cms.i18n-visible';

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import type { Field, TemplatePreviewProps } from '../../../interface'; import type { Field, TemplatePreviewProps } from '@staticcms/core/interface';
function isVisible(field: Field) { function isVisible(field: Field) {
return field.widget !== 'hidden'; return field.widget !== 'hidden';

View File

@ -1,6 +1,6 @@
import React, { memo } from 'react'; import { createElement, memo } from 'react';
import type { TemplatePreviewComponent, TemplatePreviewProps } from '../../../interface'; import type { TemplatePreviewComponent, TemplatePreviewProps } from '@staticcms/core/interface';
interface EditorPreviewContentProps { interface EditorPreviewContentProps {
previewComponent?: TemplatePreviewComponent; previewComponent?: TemplatePreviewComponent;
@ -13,7 +13,7 @@ const EditorPreviewContent = memo(
return null; return null;
} }
return React.createElement(previewComponent, previewProps); return createElement(previewComponent, previewProps);
}, },
); );

View File

@ -1,26 +1,24 @@
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { isValidElement, useCallback, useMemo } from 'react'; import React, { Fragment, isValidElement, useCallback, useMemo } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import Frame, { FrameContextConsumer } from 'react-frame-component'; import Frame, { FrameContextConsumer } from 'react-frame-component';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { ScrollSyncPane } from 'react-scroll-sync'; import { ScrollSyncPane } from 'react-scroll-sync';
import { getAsset as getAssetAction } from '../../../actions/media'; import { getAsset as getAssetAction } from '@staticcms/core/actions/media';
import { lengths } from '../../../components/UI/styles'; import { ErrorBoundary } from '@staticcms/core/components/UI';
import { getPreviewStyles, getPreviewTemplate, resolveWidget } from '../../../lib/registry'; import { lengths } from '@staticcms/core/components/UI/styles';
import { selectTemplateName, useInferedFields } from '../../../lib/util/collection.util'; import { getPreviewStyles, getPreviewTemplate, resolveWidget } from '@staticcms/core/lib/registry';
import { selectField } from '../../../lib/util/field.util'; import { selectTemplateName, useInferedFields } from '@staticcms/core/lib/util/collection.util';
import { selectIsLoadingAsset } from '../../../reducers/medias'; import { selectField } from '@staticcms/core/lib/util/field.util';
import { getTypedFieldForValue } from '../../../widgets/list/typedListHelpers'; import { selectIsLoadingAsset } from '@staticcms/core/reducers/medias';
import { ErrorBoundary } from '../../UI'; import { getTypedFieldForValue } from '@staticcms/list/typedListHelpers';
import EditorPreview from './EditorPreview'; import EditorPreview from './EditorPreview';
import EditorPreviewContent from './EditorPreviewContent'; import EditorPreviewContent from './EditorPreviewContent';
import PreviewHOC from './PreviewHOC'; import PreviewHOC from './PreviewHOC';
import type { ComponentType, ReactFragment, ReactNode } from 'react'; import type { InferredField } from '@staticcms/core/constants/fieldInference';
import type { ConnectedProps } from 'react-redux';
import type { InferredField } from '../../../constants/fieldInference';
import type { import type {
Collection, Collection,
Config, Config,
@ -35,8 +33,10 @@ import type {
TranslatedProps, TranslatedProps,
ValueOrNestedValue, ValueOrNestedValue,
WidgetPreviewComponent, WidgetPreviewComponent,
} from '../../../interface'; } from '@staticcms/core/interface';
import type { RootState } from '../../../store'; import type { RootState } from '@staticcms/core/store';
import type { ComponentType, ReactFragment, ReactNode } from 'react';
import type { ConnectedProps } from 'react-redux';
const PreviewPaneFrame = styled(Frame)` const PreviewPaneFrame = styled(Frame)`
width: 100%; width: 100%;
@ -180,10 +180,10 @@ function isJsxElement(value: any): value is JSX.Element {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
function isReactFragment(value: any): value is ReactFragment { function isReactFragment(value: any): value is ReactFragment {
if (value.type) { if (value.type) {
return value.type === React.Fragment; return value.type === Fragment;
} }
return value === React.Fragment; return value === Fragment;
} }
function getWidget( function getWidget(
@ -478,7 +478,9 @@ const PreviewPane = (props: TranslatedProps<EditorPreviewPaneProps>) => {
() => ` () => `
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head><base target="_blank"/></head> <head>
<base target="_blank"/>
</head>
<body><div></div></body> <body><div></div></body>
</html> </html>
`, `,

View File

@ -1,6 +1,6 @@
import React from 'react'; import { cloneElement, createElement, isValidElement } from 'react';
import type { WidgetPreviewComponent, WidgetPreviewProps } from '../../../interface'; import type { WidgetPreviewComponent, WidgetPreviewProps } from '@staticcms/core/interface';
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
interface PreviewHOCProps extends Omit<WidgetPreviewProps, 'widgetFor'> { interface PreviewHOCProps extends Omit<WidgetPreviewProps, 'widgetFor'> {
@ -11,10 +11,10 @@ interface PreviewHOCProps extends Omit<WidgetPreviewProps, 'widgetFor'> {
const PreviewHOC = ({ previewComponent, ...props }: PreviewHOCProps) => { const PreviewHOC = ({ previewComponent, ...props }: PreviewHOCProps) => {
if (!previewComponent) { if (!previewComponent) {
return null; return null;
} else if (React.isValidElement(previewComponent)) { } else if (isValidElement(previewComponent)) {
return React.cloneElement(previewComponent, props); return cloneElement(previewComponent, props);
} else { } else {
return React.createElement(previewComponent, props); return createElement(previewComponent, props);
} }
}; };

View File

@ -3,7 +3,7 @@ import { Navigate, useParams } from 'react-router-dom';
import Editor from './Editor'; import Editor from './Editor';
import type { Collections } from '../../interface'; import type { Collections } from '@staticcms/core/interface';
function getDefaultPath(collections: Collections) { function getDefaultPath(collections: Collections) {
const first = Object.values(collections).filter(collection => collection.hide !== true)[0]; const first = Object.values(collections).filter(collection => collection.hide !== true)[0];

View File

@ -3,7 +3,7 @@ import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import green from '@mui/material/colors/green'; import { green } from '@mui/material/colors';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
@ -11,13 +11,18 @@ import Toolbar from '@mui/material/Toolbar';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { colors, components, zIndex } from '../../components/UI/styles'; import { colors, components, zIndex } from '@staticcms/core/components/UI/styles';
import { selectAllowDeletion } from '../../lib/util/collection.util'; import { selectAllowDeletion } from '@staticcms/core/lib/util/collection.util';
import { SettingsDropdown } from '../UI'; import { SettingsDropdown } from '../UI';
import NavLink from '../UI/NavLink'; import NavLink from '../UI/NavLink';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import type { Collection, EditorPersistOptions, TranslatedProps, User } from '../../interface'; import type {
Collection,
EditorPersistOptions,
TranslatedProps,
User,
} from '@staticcms/core/interface';
const StyledAppBar = styled(AppBar)` const StyledAppBar = styled(AppBar)`
background-color: ${colors.foreground}; background-color: ${colors.foreground};

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import type { WidgetControlProps, TranslatedProps } from '../../../interface'; import type { WidgetControlProps, TranslatedProps } from '@staticcms/core/interface';
const UnknownControl = ({ field, t }: TranslatedProps<WidgetControlProps<unknown>>) => { const UnknownControl = ({ field, t }: TranslatedProps<WidgetControlProps<unknown>>) => {
return <div>{t('editor.editorWidgets.unknownControl.noControl', { widget: field.widget })}</div>; return <div>{t('editor.editorWidgets.unknownControl.noControl', { widget: field.widget })}</div>;

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import type { WidgetPreviewProps, TranslatedProps } from '../../../interface'; import type { WidgetPreviewProps, TranslatedProps } from '@staticcms/core/interface';
const UnknownPreview = ({ field, t }: TranslatedProps<WidgetPreviewProps>) => { const UnknownPreview = ({ field, t }: TranslatedProps<WidgetPreviewProps>) => {
return ( return (

View File

@ -1,4 +1,4 @@
import { registerWidget } from '../../lib/registry'; import { registerWidget } from '@staticcms/core/lib/registry';
import UnknownControl from './Unknown/UnknownControl'; import UnknownControl from './Unknown/UnknownControl';
import UnknownPreview from './Unknown/UnknownPreview'; import UnknownPreview from './Unknown/UnknownPreview';

View File

@ -10,17 +10,17 @@ import {
loadMedia as loadMediaAction, loadMedia as loadMediaAction,
loadMediaDisplayURL as loadMediaDisplayURLAction, loadMediaDisplayURL as loadMediaDisplayURLAction,
persistMedia as persistMediaAction, persistMedia as persistMediaAction,
} from '../../actions/mediaLibrary'; } from '@staticcms/core/actions/mediaLibrary';
import { fileExtension } from '../../lib/util'; import { fileExtension } from '@staticcms/core/lib/util';
import { selectMediaFiles } from '../../reducers/mediaLibrary'; import { selectMediaFiles } from '@staticcms/core/reducers/mediaLibrary';
import alert from '../UI/Alert'; import alert from '../UI/Alert';
import confirm from '../UI/Confirm'; import confirm from '../UI/Confirm';
import MediaLibraryModal from './MediaLibraryModal'; import MediaLibraryModal from './MediaLibraryModal';
import type { ChangeEvent, KeyboardEvent } from 'react'; import type { ChangeEvent, KeyboardEvent } from 'react';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { MediaFile, TranslatedProps } from '../../interface'; import type { MediaFile, TranslatedProps } from '@staticcms/core/interface';
import type { RootState } from '../../store'; import type { RootState } from '@staticcms/core/store';
/** /**
* Extensions used to determine which files to show when the media library is * Extensions used to determine which files to show when the media library is

View File

@ -2,9 +2,9 @@ import Button from '@mui/material/Button';
import copyToClipboard from 'copy-text-to-clipboard'; import copyToClipboard from 'copy-text-to-clipboard';
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { isAbsolutePath } from '../../lib/util'; import { isAbsolutePath } from '@staticcms/core/lib/util';
import type { TranslatedProps } from '../../interface'; import type { TranslatedProps } from '@staticcms/core/interface';
export interface CopyToClipBoardButtonProps { export interface CopyToClipBoardButtonProps {
disabled: boolean; disabled: boolean;

View File

@ -1,10 +1,10 @@
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useEffect, useMemo } from 'react'; import React, { useEffect, useMemo } from 'react';
import { borders, colors, effects, lengths, shadows } from '../../components/UI/styles'; import { borders, colors, effects, lengths, shadows } from '@staticcms/core/components/UI/styles';
import { transientOptions } from '../../lib'; import { transientOptions } from '@staticcms/core/lib';
import type { MediaLibraryDisplayURL } from '../../reducers/mediaLibrary'; import type { MediaLibraryDisplayURL } from '@staticcms/core/reducers/mediaLibrary';
const IMAGE_HEIGHT = 160; const IMAGE_HEIGHT = 160;

View File

@ -7,8 +7,11 @@ import { FixedSizeGrid as Grid } from 'react-window';
import MediaLibraryCard from './MediaLibraryCard'; import MediaLibraryCard from './MediaLibraryCard';
import type { GridChildComponentProps } from 'react-window'; import type { GridChildComponentProps } from 'react-window';
import type { MediaFile } from '../../interface'; import type { MediaFile } from '@staticcms/core/interface';
import type { MediaLibraryDisplayURL, MediaLibraryState } from '../../reducers/mediaLibrary'; import type {
MediaLibraryDisplayURL,
MediaLibraryState,
} from '@staticcms/core/reducers/mediaLibrary';
export interface MediaLibraryCardItem { export interface MediaLibraryCardItem {
displayURL?: MediaLibraryDisplayURL; displayURL?: MediaLibraryDisplayURL;

View File

@ -12,8 +12,8 @@ import MediaLibraryCardGrid from './MediaLibraryCardGrid';
import MediaLibraryTop from './MediaLibraryTop'; import MediaLibraryTop from './MediaLibraryTop';
import type { ChangeEvent, ChangeEventHandler, KeyboardEventHandler } from 'react'; import type { ChangeEvent, ChangeEventHandler, KeyboardEventHandler } from 'react';
import type { MediaFile, TranslatedProps } from '../../interface'; import type { MediaFile, TranslatedProps } from '@staticcms/core/interface';
import type { MediaLibraryState } from '../../reducers/mediaLibrary'; import type { MediaLibraryState } from '@staticcms/core/reducers/mediaLibrary';
const StyledFab = styled(Fab)` const StyledFab = styled(Fab)`
position: absolute; position: absolute;

View File

@ -5,11 +5,11 @@ import React from 'react';
import { CopyToClipBoardButton } from './MediaLibraryButtons'; import { CopyToClipBoardButton } from './MediaLibraryButtons';
import MediaLibrarySearch from './MediaLibrarySearch'; import MediaLibrarySearch from './MediaLibrarySearch';
import { buttons, shadows, zIndex } from '../../components/UI/styles'; import { buttons, shadows, zIndex } from '@staticcms/core/components/UI/styles';
import FileUploadButton from '../UI/FileUploadButton'; import FileUploadButton from '../UI/FileUploadButton';
import type { ChangeEvent, ChangeEventHandler, KeyboardEventHandler } from 'react'; import type { ChangeEvent, ChangeEventHandler, KeyboardEventHandler } from 'react';
import type { MediaFile, TranslatedProps } from '../../interface'; import type { MediaFile, TranslatedProps } from '@staticcms/core/interface';
const LibraryTop = styled('div')` const LibraryTop = styled('div')`
position: relative; position: relative;

View File

@ -7,8 +7,8 @@ import DialogTitle from '@mui/material/DialogTitle';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import AlertEvent from '../../lib/util/events/AlertEvent'; import AlertEvent from '@staticcms/core/lib/util/events/AlertEvent';
import { useWindowEvent } from '../../lib/util/window.util'; import { useWindowEvent } from '@staticcms/core/lib/util/window.util';
import type { TranslateProps } from 'react-polyglot'; import type { TranslateProps } from 'react-polyglot';

View File

@ -6,7 +6,7 @@ import GoBackButton from './GoBackButton';
import Icon from './Icon'; import Icon from './Icon';
import type { MouseEventHandler, ReactNode } from 'react'; import type { MouseEventHandler, ReactNode } from 'react';
import type { TranslatedProps } from '../../interface'; import type { TranslatedProps } from '@staticcms/core/interface';
const StyledAuthenticationPage = styled('section')` const StyledAuthenticationPage = styled('section')`
display: flex; display: flex;

View File

@ -7,8 +7,8 @@ import DialogTitle from '@mui/material/DialogTitle';
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import ConfirmEvent from '../../lib/util/events/ConfirmEvent'; import ConfirmEvent from '@staticcms/core/lib/util/events/ConfirmEvent';
import { useWindowEvent } from '../../lib/util/window.util'; import { useWindowEvent } from '@staticcms/core/lib/util/window.util';
import type { TranslateProps } from 'react-polyglot'; import type { TranslateProps } from 'react-polyglot';

View File

@ -2,15 +2,15 @@ import { styled } from '@mui/material/styles';
import cleanStack from 'clean-stack'; import cleanStack from 'clean-stack';
import copyToClipboard from 'copy-text-to-clipboard'; import copyToClipboard from 'copy-text-to-clipboard';
import truncate from 'lodash/truncate'; import truncate from 'lodash/truncate';
import React from 'react'; import React, { Component } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import yaml from 'yaml'; import yaml from 'yaml';
import { localForage } from '../../lib/util'; import { buttons, colors } from '@staticcms/core/components/UI/styles';
import { buttons, colors } from '../../components/UI/styles'; import { localForage } from '@staticcms/core/lib/util';
import type { Config, TranslatedProps } from '@staticcms/core/interface';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import type { Config, TranslatedProps } from '../../interface';
const ISSUE_URL = 'https://github.com/StaticJsCMS/static-cms/issues/new?'; const ISSUE_URL = 'https://github.com/StaticJsCMS/static-cms/issues/new?';
@ -45,7 +45,7 @@ function buildIssueTemplate(config: Config) {
} }
const template = getIssueTemplate( const template = getIssueTemplate(
version, version,
config.backend.name, config?.backend?.name,
navigator.userAgent, navigator.userAgent,
yaml.stringify(config), yaml.stringify(config),
); );
@ -145,7 +145,7 @@ interface ErrorBoundaryState {
backup: string; backup: string;
} }
export class ErrorBoundary extends React.Component< export class ErrorBoundary extends Component<
TranslatedProps<ErrorBoundaryProps>, TranslatedProps<ErrorBoundaryProps>,
ErrorBoundaryState ErrorBoundaryState
> { > {

View File

@ -1,10 +1,12 @@
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import React from 'react'; import React from 'react';
import type { ChangeEventHandler } from 'react';
export interface FileUploadButtonProps { export interface FileUploadButtonProps {
label: string; label: string;
imagesOnly?: boolean; imagesOnly?: boolean;
onChange: React.ChangeEventHandler<HTMLInputElement>; onChange: ChangeEventHandler<HTMLInputElement>;
disabled?: boolean; disabled?: boolean;
} }

View File

@ -2,7 +2,7 @@ import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import React from 'react'; import React from 'react';
import type { TranslatedProps } from '../../interface'; import type { TranslatedProps } from '@staticcms/core/interface';
interface GoBackButtonProps { interface GoBackButtonProps {
href: string; href: string;

View File

@ -2,7 +2,7 @@ import { styled } from '@mui/material/styles';
import React from 'react'; import React from 'react';
import icons from './Icon/icons'; import icons from './Icon/icons';
import transientOptions from '../../lib/util/transientOptions'; import transientOptions from '@staticcms/core/lib/util/transientOptions';
import type { IconType } from './Icon/icons'; import type { IconType } from './Icon/icons';

View File

@ -5,7 +5,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import React from 'react'; import React from 'react';
import { transientOptions } from '../../lib/util'; import { transientOptions } from '@staticcms/core/lib/util';
import { buttons, colors, lengths, transitions } from './styles'; import { buttons, colors, lengths, transitions } from './styles';
import type { ComponentClass, MouseEvent, ReactNode } from 'react'; import type { ComponentClass, MouseEvent, ReactNode } from 'react';

View File

@ -2,8 +2,8 @@ import React, { forwardRef } from 'react';
import { NavLink as NavLinkBase } from 'react-router-dom'; import { NavLink as NavLinkBase } from 'react-router-dom';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import { colors } from '../../components/UI/styles'; import { colors } from '@staticcms/core/components/UI/styles';
import { transientOptions } from '../../lib'; import { transientOptions } from '@staticcms/core/lib';
import type { RefAttributes } from 'react'; import type { RefAttributes } from 'react';
import type { NavLinkProps as RouterNavLinkProps } from 'react-router-dom'; import type { NavLinkProps as RouterNavLinkProps } from 'react-router-dom';

View File

@ -5,13 +5,13 @@ import IconButton from '@mui/material/IconButton';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React, { useCallback } from 'react'; import React, { useCallback, useState } from 'react';
import { transientOptions } from '../../lib'; import { transientOptions } from '@staticcms/core/lib';
import { colors, colorsRaw, transitions } from './styles'; import { colors, colorsRaw, transitions } from './styles';
import type { ObjectField, TranslatedProps } from '@staticcms/core/interface';
import type { MouseEvent, ReactNode } from 'react'; import type { MouseEvent, ReactNode } from 'react';
import type { ObjectField, TranslatedProps } from '../../interface';
const TopBarContainer = styled('div')` const TopBarContainer = styled('div')`
position: relative; position: relative;
@ -67,9 +67,9 @@ const ObjectWidgetTopBar = ({
hasError = false, hasError = false,
t, t,
}: TranslatedProps<ObjectWidgetTopBarProps>) => { }: TranslatedProps<ObjectWidgetTopBarProps>) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {

View File

@ -1,7 +1,7 @@
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import React from 'react'; import React from 'react';
import transientOptions from '../../lib/util/transientOptions'; import transientOptions from '@staticcms/core/lib/util/transientOptions';
interface StyledOutlineProps { interface StyledOutlineProps {
$active: boolean; $active: boolean;

View File

@ -3,6 +3,8 @@ import { styled } from '@mui/material/styles';
import useScrollTrigger from '@mui/material/useScrollTrigger'; import useScrollTrigger from '@mui/material/useScrollTrigger';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { ReactNode, MouseEvent } from 'react';
const StyledScrollTop = styled('div')` const StyledScrollTop = styled('div')`
position: fixed; position: fixed;
bottom: 16px; bottom: 16px;
@ -10,7 +12,7 @@ const StyledScrollTop = styled('div')`
`; `;
interface ScrollTopProps { interface ScrollTopProps {
children: React.ReactNode; children: ReactNode;
} }
const ScrollTop = ({ children }: ScrollTopProps) => { const ScrollTop = ({ children }: ScrollTopProps) => {
@ -19,7 +21,7 @@ const ScrollTop = ({ children }: ScrollTopProps) => {
threshold: 100, threshold: 100,
}); });
const handleClick = useCallback((event: React.MouseEvent<HTMLDivElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLDivElement>) => {
const anchor = ((event.target as HTMLDivElement).ownerDocument || document).querySelector( const anchor = ((event.target as HTMLDivElement).ownerDocument || document).querySelector(
'#back-to-top-anchor', '#back-to-top-anchor',
); );

View File

@ -1,13 +1,14 @@
import PersonIcon from '@mui/icons-material/Person';
import Avatar from '@mui/material/Avatar'; import Avatar from '@mui/material/Avatar';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import Menu from '@mui/material/Menu'; import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useCallback } from 'react'; import React, { useCallback, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import PersonIcon from '@mui/icons-material/Person';
import type { TranslatedProps } from '../../interface'; import type { TranslatedProps } from '@staticcms/core/interface';
import type { MouseEvent } from 'react';
interface AvatarImageProps { interface AvatarImageProps {
imageUrl: string | undefined; imageUrl: string | undefined;
@ -33,9 +34,9 @@ const SettingsDropdown = ({
onLogoutClick, onLogoutClick,
t, t,
}: TranslatedProps<SettingsDropdownProps>) => { }: TranslatedProps<SettingsDropdownProps>) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {

View File

@ -519,10 +519,7 @@ function GlobalStyles() {
} }
${quantifier} { ${quantifier} {
font-family: ${fonts.primary};
font-weight: normal;
background-color: ${colors.background}; background-color: ${colors.background};
color: ${colors.text};
margin: 0; margin: 0;
.ol-viewport { .ol-viewport {

View File

@ -4,13 +4,13 @@ import { translate } from 'react-polyglot';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { getAdditionalLink } from '../../lib/registry'; import { getAdditionalLink } from '@staticcms/core/lib/registry';
import MainView from '../App/MainView'; import MainView from '../App/MainView';
import Sidebar from '../Collection/Sidebar'; import Sidebar from '../Collection/Sidebar';
import type { ComponentType } from 'react'; import type { ComponentType } from 'react';
import type { ConnectedProps } from 'react-redux'; import type { ConnectedProps } from 'react-redux';
import type { RootState } from '../../store'; import type { RootState } from '@staticcms/core/store';
const StyledPageContent = styled('div')` const StyledPageContent = styled('div')`
width: 100%; width: 100%;

View File

@ -5,17 +5,18 @@ import Snackbar from '@mui/material/Snackbar';
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { translate } from 'react-polyglot'; import { translate } from 'react-polyglot';
import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { useAppDispatch, useAppSelector } from '@staticcms/core/store/hooks';
import { removeSnackbarById, selectSnackbars } from '../../store/slices/snackbars'; import { removeSnackbarById, selectSnackbars } from '@staticcms/core/store/slices/snackbars';
import type { TranslatedProps } from '../../interface'; import type { TranslatedProps } from '@staticcms/core/interface';
import type { SnackbarMessage } from '../../store/slices/snackbars'; import type { SnackbarMessage } from '@staticcms/core/store/slices/snackbars';
import type { SyntheticEvent } from 'react';
// eslint-disable-next-line @typescript-eslint/no-empty-interface // eslint-disable-next-line @typescript-eslint/no-empty-interface
interface SnackbarsProps {} interface SnackbarsProps {}
const Snackbars = ({ t }: TranslatedProps<SnackbarsProps>) => { const Snackbars = ({ t }: TranslatedProps<SnackbarsProps>) => {
const [open, setOpen] = React.useState(false); const [open, setOpen] = useState(false);
const [messageInfo, setMessageInfo] = useState<SnackbarMessage | undefined>(undefined); const [messageInfo, setMessageInfo] = useState<SnackbarMessage | undefined>(undefined);
const snackbars = useAppSelector(selectSnackbars); const snackbars = useAppSelector(selectSnackbars);
@ -34,7 +35,7 @@ const Snackbars = ({ t }: TranslatedProps<SnackbarsProps>) => {
} }
}, [snackbars, messageInfo, open, dispatch]); }, [snackbars, messageInfo, open, dispatch]);
const handleClose = useCallback((_event?: React.SyntheticEvent | Event, reason?: string) => { const handleClose = useCallback((_event?: SyntheticEvent | Event, reason?: string) => {
if (reason === 'clickaway') { if (reason === 'clickaway') {
return; return;
} }

View File

@ -343,7 +343,7 @@ class ConfigError extends Error {
* `validateConfig` is a pure function. It does not mutate * `validateConfig` is a pure function. It does not mutate
* the config that is passed in. * the config that is passed in.
*/ */
export function validateConfig(config: Config) { export default function validateConfig(config: Config) {
const ajv = new AJV({ allErrors: true, allowUnionTypes: true, $data: true }); const ajv = new AJV({ allErrors: true, allowUnionTypes: true, $data: true });
uniqueItemProperties(ajv); uniqueItemProperties(ajv);
select(ajv); select(ajv);

View File

@ -1,2 +1,3 @@
/* eslint-disable import/prefer-default-export */
export const IMAGE_EXTENSION_REGEX = export const IMAGE_EXTENSION_REGEX =
/(\.apng|\.avif|\.gif|\.jpg|\.jpeg|\.jfif|\.pjpeg|\.pjp|\.png|\.svg|\.webp)$/g; /(\.apng|\.avif|\.gif|\.jpg|\.jpeg|\.jfif|\.pjpeg|\.pjp|\.png|\.svg|\.webp)$/g;

View File

@ -7,7 +7,7 @@ import {
TestBackend, TestBackend,
} from './backends'; } from './backends';
import { registerBackend, registerLocale, registerWidget } from './lib/registry'; import { registerBackend, registerLocale, registerWidget } from './lib/registry';
import { locales } from './locales'; import locales from './locales';
import { import {
BooleanWidget, BooleanWidget,
CodeWidget, CodeWidget,
@ -26,7 +26,7 @@ import {
TextWidget, TextWidget,
} from './widgets'; } from './widgets';
export function addExtensions() { export default function addExtensions() {
// Register all the things // Register all the things
registerBackend('git-gateway', GitGatewayBackend); registerBackend('git-gateway', GitGatewayBackend);
registerBackend('github', GitHubBackend); registerBackend('github', GitHubBackend);

View File

@ -1,4 +1,4 @@
export abstract class FileFormatter { export default abstract class FileFormatter {
abstract fromFile(content: string): object; abstract fromFile(content: string): object;
abstract toFile(data: object, sortedKeys?: string[], comments?: Record<string, string>): string; abstract toFile(data: object, sortedKeys?: string[], comments?: Record<string, string>): string;
} }

View File

@ -1,4 +1,4 @@
import { FileFormatter } from './FileFormatter'; import FileFormatter from './FileFormatter';
class JsonFormatter extends FileFormatter { class JsonFormatter extends FileFormatter {
fromFile(content: string) { fromFile(content: string) {

View File

@ -1,6 +1,6 @@
import toml from '@ltd/j-toml'; import toml from '@ltd/j-toml';
import { FileFormatter } from './FileFormatter'; import FileFormatter from './FileFormatter';
class TomlFormatter extends FileFormatter { class TomlFormatter extends FileFormatter {
fromFile(content: string) { fromFile(content: string) {

View File

@ -1,7 +1,7 @@
import yaml from 'yaml'; import yaml from 'yaml';
import { sortKeys } from './helpers'; import { sortKeys } from './helpers';
import { FileFormatter } from './FileFormatter'; import FileFormatter from './FileFormatter';
import type { Pair, YAMLMap, YAMLSeq } from 'yaml/types'; import type { Pair, YAMLMap, YAMLSeq } from 'yaml/types';

View File

@ -5,7 +5,7 @@ import { FrontmatterInfer, frontmatterJSON, frontmatterTOML, frontmatterYAML } f
import type { Delimiter } from './frontmatter'; import type { Delimiter } from './frontmatter';
import type { Collection, Entry, Format } from '../interface'; import type { Collection, Entry, Format } from '../interface';
import type { FileFormatter } from './FileFormatter'; import type FileFormatter from './FileFormatter';
export const frontmatterFormats = ['yaml-frontmatter', 'toml-frontmatter', 'json-frontmatter']; export const frontmatterFormats = ['yaml-frontmatter', 'toml-frontmatter', 'json-frontmatter'];

View File

@ -3,7 +3,7 @@ import matter from 'gray-matter';
import YamlFormatter from './YamlFormatter'; import YamlFormatter from './YamlFormatter';
import TomlFormatter from './TomlFormatter'; import TomlFormatter from './TomlFormatter';
import JsonFormatter from './JsonFormatter'; import JsonFormatter from './JsonFormatter';
import { FileFormatter } from './FileFormatter'; import FileFormatter from './FileFormatter';
const Languages = { const Languages = {
YAML: 'yaml', YAML: 'yaml',

View File

@ -1,3 +1,4 @@
/* eslint-disable import/prefer-default-export */
export function sortKeys<Item>( export function sortKeys<Item>(
sortedKeys: string[], sortedKeys: string[],
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@ -1,5 +1,5 @@
import createReactClass from 'create-react-class'; import createReactClass from 'create-react-class';
import React from 'react'; import { createElement, useCallback, useEffect, useMemo, useState } from 'react';
import bootstrap from './bootstrap'; import bootstrap from './bootstrap';
import Registry from './lib/registry'; import Registry from './lib/registry';
@ -7,7 +7,7 @@ import Registry from './lib/registry';
export * from './backends'; export * from './backends';
export * from './widgets'; export * from './widgets';
export * from './media-libraries'; export * from './media-libraries';
export * from './locales'; export { default as locales } from './locales';
export * from './lib'; export * from './lib';
export * from './interface'; export * from './interface';
@ -20,11 +20,11 @@ const CMS = {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
window.CMS = CMS; window.CMS = CMS;
window.createClass = window.createClass || createReactClass; window.createClass = window.createClass || createReactClass;
window.useState = window.useState || React.useState; window.useState = window.useState || useState;
window.useMemo = window.useMemo || React.useMemo; window.useMemo = window.useMemo || useMemo;
window.useEffect = window.useEffect || React.useEffect; window.useEffect = window.useEffect || useEffect;
window.useCallback = window.useCallback || React.useCallback; window.useCallback = window.useCallback || useCallback;
window.h = window.h || React.createElement; window.h = window.h || createElement;
} }
export default CMS; export default CMS;

View File

@ -1,10 +1,10 @@
import flatten from 'lodash/flatten'; import flatten from 'lodash/flatten';
import { unsentRequest } from '../../../lib/util'; import { unsentRequest } from '@staticcms/core/lib/util';
import { selectEntrySlug } from '../../../lib/util/collection.util'; import { selectEntrySlug } from '@staticcms/core/lib/util/collection.util';
import { createEntry } from '../../../valueObjects/Entry'; import createEntry from '@staticcms/core/valueObjects/createEntry';
import type { AlgoliaConfig, Collection, Entry, SearchResponse } from '../../../interface'; import type { AlgoliaConfig, Collection, Entry, SearchResponse } from '@staticcms/core/interface';
const { fetchWithTimeout: fetch } = unsentRequest; const { fetchWithTimeout: fetch } = unsentRequest;

View File

@ -1,10 +1,12 @@
import type { import type { LanguageName } from '@uiw/codemirror-extensions-langs';
EditorPlugin as MarkdownPlugin,
EditorType as MarkdownEditorType,
} from '@toast-ui/editor/types/editor';
import type { ToolbarItemOptions as MarkdownToolbarItemOptions } from '@toast-ui/editor/types/ui';
import type { PropertiesSchema } from 'ajv/dist/types/json-schema'; import type { PropertiesSchema } from 'ajv/dist/types/json-schema';
import type { ComponentType, FunctionComponent, ReactNode } from 'react'; import type {
ComponentType,
FunctionComponent,
JSXElementConstructor,
ReactElement,
ReactNode,
} from 'react';
import type { t, TranslateProps as ReactPolyglotTranslateProps } from 'react-polyglot'; import type { t, TranslateProps as ReactPolyglotTranslateProps } from 'react-polyglot';
import type { MediaFile as BackendMediaFile } from './backend'; import type { MediaFile as BackendMediaFile } from './backend';
import type { EditorControlProps } from './components/Editor/EditorControlPane/EditorControl'; import type { EditorControlProps } from './components/Editor/EditorControlPane/EditorControl';
@ -18,7 +20,6 @@ import type { I18N_STRUCTURE } from './lib/i18n';
import type { AllowedEvent } from './lib/registry'; import type { AllowedEvent } from './lib/registry';
import type Cursor from './lib/util/Cursor'; import type Cursor from './lib/util/Cursor';
import type AssetProxy from './valueObjects/AssetProxy'; import type AssetProxy from './valueObjects/AssetProxy';
import type { MediaHolder } from './widgets/markdown/hooks/useMedia';
export interface Pages { export interface Pages {
[collection: string]: { isFetching?: boolean; page?: number; ids: string[] }; [collection: string]: { isFetching?: boolean; page?: number; ids: string[] };
@ -278,7 +279,7 @@ export interface WidgetPreviewProps<T = unknown, F extends BaseField = UnknownFi
export type WidgetPreviewComponent<T = unknown, F extends BaseField = UnknownField> = export type WidgetPreviewComponent<T = unknown, F extends BaseField = UnknownField> =
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
| React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ReactElement<unknown, string | JSXElementConstructor<any>>
| ComponentType<WidgetPreviewProps<T, F>>; | ComponentType<WidgetPreviewProps<T, F>>;
export type WidgetsFor<P = EntryData> = <K extends keyof P>( export type WidgetsFor<P = EntryData> = <K extends keyof P>(
@ -286,11 +287,11 @@ export type WidgetsFor<P = EntryData> = <K extends keyof P>(
) => P[K] extends Array<infer U> ) => P[K] extends Array<infer U>
? { ? {
data: U | null; data: U | null;
widgets: Record<keyof U, React.ReactNode>; widgets: Record<keyof U, ReactNode>;
}[] }[]
: { : {
data: P[K] | null; data: P[K] | null;
widgets: Record<keyof P[K], React.ReactNode>; widgets: Record<keyof P[K], ReactNode>;
}; };
export interface TemplatePreviewProps<T = EntryData, EF extends BaseField = UnknownField> { export interface TemplatePreviewProps<T = EntryData, EF extends BaseField = UnknownField> {
@ -841,7 +842,7 @@ export interface I18nInfo {
export interface ProcessedCodeLanguage { export interface ProcessedCodeLanguage {
label: string; label: string;
identifiers: string[]; identifiers: string[];
codemirror_mode: string; codemirror_mode: LanguageName;
codemirror_mime_type: string; codemirror_mime_type: string;
} }
@ -862,22 +863,25 @@ export interface PreviewStyle {
export interface MarkdownPluginFactoryProps { export interface MarkdownPluginFactoryProps {
config: Config<MarkdownField>; config: Config<MarkdownField>;
field: MarkdownField; field: MarkdownField;
media: MediaHolder;
mode: 'editor' | 'preview'; mode: 'editor' | 'preview';
} }
export type MarkdownPluginFactory = (props: MarkdownPluginFactoryProps) => MarkdownPlugin; // eslint-disable-next-line @typescript-eslint/no-explicit-any
export type MarkdownPluginFactory = (props: MarkdownPluginFactoryProps) => any;
export interface MarkdownToolbarItemsFactoryProps { export interface MarkdownToolbarItemsFactoryProps {
imageToolbarButton: MarkdownToolbarItemOptions; // eslint-disable-next-line @typescript-eslint/no-explicit-any
imageToolbarButton: any;
} }
export type MarkdownToolbarItemsFactory = ( export type MarkdownToolbarItemsFactory = (
props: MarkdownToolbarItemsFactoryProps, props: MarkdownToolbarItemsFactoryProps,
) => (string | MarkdownToolbarItemOptions)[][]; // eslint-disable-next-line @typescript-eslint/no-explicit-any
) => (string | any)[][];
export interface MarkdownEditorOptions { export interface MarkdownEditorOptions {
initialEditType?: MarkdownEditorType; // eslint-disable-next-line @typescript-eslint/no-explicit-any
initialEditType?: any;
height?: string; height?: string;
toolbarItems?: MarkdownToolbarItemsFactory; toolbarItems?: MarkdownToolbarItemsFactory;
plugins?: MarkdownPluginFactory[]; plugins?: MarkdownPluginFactory[];

View File

@ -3,7 +3,7 @@ import trimEnd from 'lodash/trimEnd';
import { createNonce, isInsecureProtocol, validateNonce } from './utils'; import { createNonce, isInsecureProtocol, validateNonce } from './utils';
import type { User, AuthenticatorConfig } from '../../interface'; import type { User, AuthenticatorConfig } from '@staticcms/core/interface';
import type { NetlifyError } from './netlify-auth'; import type { NetlifyError } from './netlify-auth';
export default class ImplicitAuthenticator { export default class ImplicitAuthenticator {

View File

@ -1,7 +1,7 @@
import trim from 'lodash/trim'; import trim from 'lodash/trim';
import trimEnd from 'lodash/trimEnd'; import trimEnd from 'lodash/trimEnd';
import type { User, AuthenticatorConfig } from '../../interface'; import type { User, AuthenticatorConfig } from '@staticcms/core/interface';
const NETLIFY_API = 'https://api.netlify.com'; const NETLIFY_API = 'https://api.netlify.com';
const AUTH_ENDPOINT = 'auth'; const AUTH_ENDPOINT = 'auth';

View File

@ -3,7 +3,7 @@ import trimEnd from 'lodash/trimEnd';
import { createNonce, isInsecureProtocol, validateNonce } from './utils'; import { createNonce, isInsecureProtocol, validateNonce } from './utils';
import type { User, AuthenticatorConfig } from '../../interface'; import type { User, AuthenticatorConfig } from '@staticcms/core/interface';
import type { NetlifyError } from './netlify-auth'; import type { NetlifyError } from './netlify-auth';
async function sha256(text: string) { async function sha256(text: string) {

View File

@ -0,0 +1,22 @@
import { useEffect, useState } from 'react';
export default function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
if (delay === 0) {
setDebouncedValue(value);
return;
}
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return delay === 0 ? value : debouncedValue;
}

Some files were not shown because too many files have changed in this diff Show More