Skip to content

Commit

Permalink
Fix circular dependencies (#612)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmatown authored Aug 31, 2023
1 parent 8baf6e0 commit dbd09f0
Show file tree
Hide file tree
Showing 27 changed files with 208 additions and 198 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-news-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystatic/core': patch
---

Fix circular dependencies
2 changes: 1 addition & 1 deletion packages/keystatic/src/app/ItemPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import { Heading, Text } from '@keystar/ui/typography';
import { Config } from '../config';
import { createGetPreviewProps } from '../form/preview-props';
import { fields } from '../form/api';
import { SlugFieldInfo } from '../form/fields/text/ui';
import { clientSideValidateProp } from '../form/errors';
import { useEventCallback } from '../form/fields/document/DocumentEditor/ui-utils';

Expand Down Expand Up @@ -64,6 +63,7 @@ import {
isGitHubConfig,
} from './utils';
import { notFound } from './not-found';
import { SlugFieldInfo } from '../form/fields/text/path-slug-context';

type ItemPageProps = {
collection: string;
Expand Down
6 changes: 3 additions & 3 deletions packages/keystatic/src/app/entry-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { createContext, useContext } from 'react';

import { ReadonlyPropPath } from '../form/fields/document/DocumentEditor/component-blocks/utils';
import {
PathContextProvider,
SlugFieldProvider,
AddToPathProvider,
PathContextProvider,
SlugFieldInfo,
} from '../form/fields/text/ui';
SlugFieldProvider,
} from '../form/fields/text/path-slug-context';
import {
NonChildFieldComponentSchema,
InnerFormValueContentFromPreviewProps,
Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/app/useItemData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import LRUCache from 'lru-cache';
import { useCallback, useMemo } from 'react';
import { Config } from '../config';
import { SlugFieldInfo } from '../form/fields/text/ui';
import { SlugFieldInfo } from '../form/fields/text/path-slug-context';
import { ComponentSchema, fields } from '..';
import { parseProps } from '../form/parse-props';
import { getAuth } from './auth';
Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/errors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getSlugFromState } from '../app/utils';
import { ComponentSchema } from './api';
import { SlugFieldInfo } from './fields/text/ui';
import { SlugFieldInfo } from './fields/text/path-slug-context';
import { FieldDataError } from './fields/error';
import { PropValidationError } from './parse-props';
import { ReadonlyPropPath } from './fields/document/DocumentEditor/component-blocks/utils';
Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/fields/array/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
} from '../../form-from-preview';
import { getInitialPropsValue } from '../../initial-values';
import { useEventCallback } from '../document/DocumentEditor/ui-utils';
import { SlugFieldInfo } from '../text/ui';
import { SlugFieldInfo } from '../text/path-slug-context';
import { ArrayField, ComponentSchema, GenericPreviewProps } from '../../api';

export function ArrayFieldInput<Element extends ComponentSchema>(
Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/fields/conditional/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
isNonChildFieldPreviewProps,
InnerFormValueContentFromPreviewProps,
} from '../../form-from-preview';
import { AddToPathProvider } from '../text/ui';
import { AddToPathProvider } from '../text/path-slug-context';

export function ConditionalFieldInput<
DiscriminantField extends BasicFormField<string | boolean>,
Expand Down
30 changes: 1 addition & 29 deletions packages/keystatic/src/form/fields/date/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,7 @@ import {
basicFormFieldWithSimpleReaderParse,
} from '../utils';
import { DateFieldInput } from './ui';

export function validateDate(
validation: { min?: string; max?: string; isRequired?: boolean } | undefined,
value: string | null,
label: string
) {
if (value !== null && !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
return `${label} is not a valid date`;
}

if (validation?.isRequired && value === null) {
return `${label} is required`;
}
if ((validation?.min || validation?.max) && value !== null) {
const date = new Date(value);
if (validation?.min !== undefined) {
const min = new Date(validation.min);
if (date < min) {
return `${label} must be after ${min.toLocaleDateString()}`;
}
}
if (validation?.max !== undefined) {
const max = new Date(validation.max);
if (date > max) {
return `${label} must be no later than ${max.toLocaleDateString()}`;
}
}
}
}
import { validateDate } from './validateDate';

export function date<IsRequired extends boolean | undefined>({
label,
Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/fields/date/ui.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
import { TextField } from '@keystar/ui/text-field';
import { useReducer } from 'react';
import { validateDate } from '.';
import { validateDate } from './validateDate';
import { FormFieldInputProps } from '../../api';

export function DateFieldInput(
Expand Down
28 changes: 28 additions & 0 deletions packages/keystatic/src/form/fields/date/validateDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export function validateDate(
validation: { min?: string; max?: string; isRequired?: boolean } | undefined,
value: string | null,
label: string
) {
if (value !== null && !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
return `${label} is not a valid date`;
}

if (validation?.isRequired && value === null) {
return `${label} is required`;
}
if ((validation?.min || validation?.max) && value !== null) {
const date = new Date(value);
if (validation?.min !== undefined) {
const min = new Date(validation.min);
if (date < min) {
return `${label} must be after ${min.toLocaleDateString()}`;
}
}
if (validation?.max !== undefined) {
const max = new Date(validation.max);
if (date > max) {
return `${label} must be no later than ${max.toLocaleDateString()}`;
}
}
}
}
30 changes: 1 addition & 29 deletions packages/keystatic/src/form/fields/datetime/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,7 @@ import {
basicFormFieldWithSimpleReaderParse,
} from '../utils';
import { DatetimeFieldInput } from './ui';

export function validateDatetime(
validation: { min?: string; max?: string; isRequired?: boolean } | undefined,
value: string | null,
label: string
) {
if (value !== null && !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(value)) {
return `${label} is not a valid datetime`;
}

if (validation?.isRequired && value === null) {
return `${label} is required`;
}
if ((validation?.min || validation?.max) && value !== null) {
const datetime = new Date(value);
if (validation?.min !== undefined) {
const min = new Date(validation.min);
if (datetime < min) {
return `${label} must be after ${min.toISOString()}`;
}
}
if (validation?.max !== undefined) {
const max = new Date(validation.max);
if (datetime > max) {
return `${label} must be no later than ${max.toISOString()}`;
}
}
}
}
import { validateDatetime } from './validateDatetime';

export function datetime<IsRequired extends boolean | undefined>({
label,
Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/fields/datetime/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
'use client';
import { TextField } from '@keystar/ui/text-field';
import { useReducer } from 'react';
import { validateDatetime } from '.';
import { validateDatetime } from './validateDatetime';
import { FormFieldInputProps } from '../../api';

export function DatetimeFieldInput(
Expand Down
28 changes: 28 additions & 0 deletions packages/keystatic/src/form/fields/datetime/validateDatetime.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export function validateDatetime(
validation: { min?: string; max?: string; isRequired?: boolean } | undefined,
value: string | null,
label: string
) {
if (value !== null && !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(value)) {
return `${label} is not a valid datetime`;
}

if (validation?.isRequired && value === null) {
return `${label} is required`;
}
if ((validation?.min || validation?.max) && value !== null) {
const datetime = new Date(value);
if (validation?.min !== undefined) {
const min = new Date(validation.min);
if (datetime < min) {
return `${label} must be after ${min.toISOString()}`;
}
}
if (validation?.max !== undefined) {
const max = new Date(validation.max);
if (datetime > max) {
return `${label} must be no later than ${max.toISOString()}`;
}
}
}
}
26 changes: 1 addition & 25 deletions packages/keystatic/src/form/fields/integer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,7 @@ import {
basicFormFieldWithSimpleReaderParse,
} from '../utils';
import { IntegerFieldInput } from './ui';

export function validateInteger(
validation: { min?: number; max?: number; isRequired?: boolean } | undefined,
value: unknown,
label: string
) {
if (
value !== null &&
(typeof value !== 'number' || !Number.isFinite(value))
) {
return `${label} is not a valid whole number`;
}

if (validation?.isRequired && value === null) {
return `${label} is required`;
}
if (value !== null) {
if (validation?.min !== undefined && value < validation.min) {
return `${label} must be at least ${validation.min}`;
}
if (validation?.max !== undefined && value > validation.max) {
return `${label} must be at most ${validation.max}`;
}
}
}
import { validateInteger } from './validateInteger';

export function integer<IsRequired extends boolean | undefined>({
label,
Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/fields/integer/ui.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
import { NumberField } from '@keystar/ui/number-field';
import { useReducer } from 'react';
import { validateInteger } from '.';
import { validateInteger } from './validateInteger';
import { FormFieldInputProps } from '../../api';

export function IntegerFieldInput(
Expand Down
24 changes: 24 additions & 0 deletions packages/keystatic/src/form/fields/integer/validateInteger.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export function validateInteger(
validation: { min?: number; max?: number; isRequired?: boolean } | undefined,
value: unknown,
label: string
) {
if (
value !== null &&
(typeof value !== 'number' || !Number.isFinite(value))
) {
return `${label} is not a valid whole number`;
}

if (validation?.isRequired && value === null) {
return `${label} is required`;
}
if (value !== null) {
if (validation?.min !== undefined && value < validation.min) {
return `${label} must be at least ${validation.min}`;
}
if (validation?.max !== undefined && value > validation.max) {
return `${label} must be at most ${validation.max}`;
}
}
}
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/fields/object/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
isNonChildFieldPreviewProps,
InnerFormValueContentFromPreviewProps,
} from '../../form-from-preview';
import { AddToPathProvider } from '../text/ui';
import { AddToPathProvider } from '../text/path-slug-context';
import { useId } from 'react';
import { Text } from '@keystar/ui/typography';

Expand Down
2 changes: 1 addition & 1 deletion packages/keystatic/src/form/fields/slug/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FormFieldStoredValue, SlugFormField } from '../../api';
import slugify from '@sindresorhus/slugify';
import { validateText } from '../text';
import { validateText } from '../text/validateText';
import { SlugFieldInput } from './ui';
import { FieldDataError } from '../error';
import { Glob } from '../../..';
Expand Down
4 changes: 2 additions & 2 deletions packages/keystatic/src/form/fields/slug/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Flex, Box } from '@keystar/ui/layout';
import { TextField } from '@keystar/ui/text-field';
import { useContext, useState } from 'react';
import { FormFieldInputProps } from '../../api';
import { SlugFieldContext, PathContext } from '../text/ui';
import { validateText } from '../text';
import { SlugFieldContext, PathContext } from '../text/path-slug-context';
import { validateText } from '../text/validateText';

const emptySet = new Set<string>();

Expand Down
49 changes: 1 addition & 48 deletions packages/keystatic/src/form/fields/text/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,7 @@ import { FormFieldStoredValue } from '../../..';
import { SlugFormField } from '../../api';
import { FieldDataError } from '../error';
import { TextFieldInput } from './ui';

export function validateText(
val: string,
min: number,
max: number,
fieldLabel: string,
slugInfo: { slugs: Set<string>; glob: Glob } | undefined
) {
if (val.length < min) {
if (min === 1) {
return `${fieldLabel} must not be empty`;
} else {
return `${fieldLabel} must be at least ${min} characters long`;
}
}
if (val.length > max) {
return `${fieldLabel} must be no longer than ${max} characters`;
}
if (slugInfo) {
if (val === '') {
return `${fieldLabel} must not be empty`;
}
if (val === '..') {
return `${fieldLabel} must not be ..`;
}
if (val === '.') {
return `${fieldLabel} must not be .`;
}
if (slugInfo.glob === '**') {
const split = val.split('/');
if (split.some(s => s === '..')) {
return `${fieldLabel} must not contain ..`;
}
if (split.some(s => s === '.')) {
return `${fieldLabel} must not be .`;
}
}
if ((slugInfo.glob === '*' ? /[\\/]/ : /[\\]/).test(val)) {
return `${fieldLabel} must not contain slashes`;
}
if (/^\s|\s$/.test(val)) {
return `${fieldLabel} must not start or end with spaces`;
}
if (slugInfo.slugs.has(val)) {
return `${fieldLabel} must be unique`;
}
}
}
import { validateText } from './validateText';

function parseAsNormalField(value: FormFieldStoredValue) {
if (value === undefined) {
Expand Down
Loading

2 comments on commit dbd09f0

@vercel
Copy link

@vercel vercel bot commented on dbd09f0 Aug 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

keystar-ui – ./design-system/docs

keystar-ui.vercel.app
voussoir.vercel.app
keystar-ui-git-main-thinkmill-labs.vercel.app
keystar-ui-thinkmill-labs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on dbd09f0 Aug 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

keystatic – ./dev-projects/next-app

keystatic.vercel.app
keystatic-thinkmill-labs.vercel.app
keystatic-git-main-thinkmill-labs.vercel.app

Please sign in to comment.