Skip to content

Commit 36ed1e7

Browse files
Achisinghdcousens
andauthored
Add resize to document field (#7729)
Co-authored-by: Daniel Cousens <[email protected]>
1 parent a7e7cd8 commit 36ed1e7

File tree

5 files changed

+150
-115
lines changed

5 files changed

+150
-115
lines changed

.changeset/tame-meals-guess.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@keystone-6/fields-document': minor
3+
---
4+
5+
Changes the editors default overflow behaviour to align with other multi-line text inputs, supporting scrolling instead of an unbounded height for the field.

docs/components/docs/DocumentEditorDemo.tsx

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
/** @jsx jsx */
33
import { getInitialPropsValue } from '@keystone-6/fields-document/src/DocumentEditor/component-blocks/initial-values';
44
import React, { ReactNode, useContext, useEffect, useMemo, useState } from 'react';
5-
import { Toolbar } from '@keystone-6/fields-document/src/DocumentEditor/Toolbar';
65
import { DocumentFeatures } from '@keystone-6/fields-document/views';
76
import {
87
createDocumentEditor,
9-
DocumentEditorEditable,
10-
DocumentEditorProvider,
8+
DocumentEditor,
119
Editor,
1210
} from '@keystone-6/fields-document/src/DocumentEditor';
1311
import {
@@ -276,19 +274,21 @@ export function DocumentFeaturesFormAndCode() {
276274

277275
export const DocumentEditorDemo = () => {
278276
const [value, setValue] = useState(initialContent as any);
277+
const [key, setKey] = useState(0);
279278
const { documentFeatures, formValue } = useContext(DocumentFeaturesContext);
280279

281-
const editor = useMemo(
282-
() => createDocumentEditor(documentFeatures, componentBlocks, emptyObj),
283-
[documentFeatures]
284-
);
285-
286-
// this is why we're creating the editor ourselves and not using the DocumentEditor component
287280
useEffect(() => {
288281
// we want to force normalize when the document features change so
289282
// that no invalid things exist after a user changes something
283+
const editor = createDocumentEditor(documentFeatures, componentBlocks, emptyObj);
284+
editor.children = value;
290285
Editor.normalize(editor, { force: true });
291-
}, [editor, documentFeatures]);
286+
setValue(editor.children);
287+
// slate looks like it's a controlled component but it actually isn't
288+
// so we need to re-mount it so that it looks at the updated value
289+
setKey(x => x + 1);
290+
// eslint-disable-next-line react-hooks/exhaustive-deps
291+
}, [documentFeatures]);
292292

293293
return (
294294
<div
@@ -330,22 +330,14 @@ export const DocumentEditorDemo = () => {
330330
borderBottom: `1px var(--border) solid`,
331331
}}
332332
>
333-
<DocumentEditorProvider
333+
<DocumentEditor
334+
key={key}
334335
value={value}
335336
onChange={setValue}
336-
editor={editor}
337337
componentBlocks={componentBlocks}
338338
documentFeatures={documentFeatures}
339339
relationships={emptyObj}
340-
>
341-
{useMemo(
342-
() => (
343-
<Toolbar documentFeatures={documentFeatures} />
344-
),
345-
[documentFeatures]
346-
)}
347-
<DocumentEditorEditable />
348-
</DocumentEditorProvider>
340+
/>
349341
</div>
350342
<details css={{ marginBottom: 'var(--space-xlarge)' }}>
351343
<summary>View the Field Config</summary>

packages/fields-document/src/DocumentEditor/Toolbar.tsx

Lines changed: 87 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -55,87 +55,83 @@ export function Toolbar({
5555
const relationship = useContext(DocumentFieldRelationshipsContext);
5656
const blockComponent = useContext(ComponentBlockContext);
5757
const hasBlockItems = Object.entries(relationship).length || Object.keys(blockComponent).length;
58-
58+
const hasMarks = Object.values(documentFeatures.formatting.inlineMarks).some(x => x);
5959
return (
6060
<ToolbarContainer>
61-
{!!documentFeatures.formatting.headingLevels.length && (
62-
<Fragment>
61+
<ToolbarGroup>
62+
{!!documentFeatures.formatting.headingLevels.length && (
6363
<HeadingMenu headingLevels={documentFeatures.formatting.headingLevels} />
64-
<ToolbarSeparator />
65-
</Fragment>
66-
)}
67-
{Object.values(documentFeatures.formatting.inlineMarks).some(x => x) && (
68-
<Fragment>
69-
<InlineMarks marks={documentFeatures.formatting.inlineMarks} />
70-
<ToolbarSeparator />
71-
</Fragment>
72-
)}
73-
{(documentFeatures.formatting.alignment.center ||
74-
documentFeatures.formatting.alignment.end) && (
75-
<TextAlignMenu alignment={documentFeatures.formatting.alignment} />
76-
)}
77-
{documentFeatures.formatting.listTypes.unordered && (
78-
<Tooltip
79-
content={
80-
<Fragment>
81-
Bullet List <KeyboardInTooltip>- </KeyboardInTooltip>
82-
</Fragment>
83-
}
84-
weight="subtle"
85-
>
86-
{attrs => (
87-
<ListButton type="unordered-list" {...attrs}>
88-
<BulletListIcon />
89-
</ListButton>
90-
)}
91-
</Tooltip>
92-
)}
93-
{documentFeatures.formatting.listTypes.ordered && (
94-
<Tooltip
95-
content={
96-
<Fragment>
97-
Numbered List <KeyboardInTooltip>1. </KeyboardInTooltip>
98-
</Fragment>
99-
}
100-
weight="subtle"
101-
>
102-
{attrs => (
103-
<ListButton type="ordered-list" {...attrs}>
104-
<NumberedListIcon />
105-
</ListButton>
106-
)}
107-
</Tooltip>
108-
)}
109-
{(documentFeatures.formatting.alignment.center ||
110-
documentFeatures.formatting.alignment.end ||
111-
documentFeatures.formatting.listTypes.unordered ||
112-
documentFeatures.formatting.listTypes.ordered) && <ToolbarSeparator />}
113-
114-
{documentFeatures.dividers && dividerButton}
115-
{documentFeatures.links && linkButton}
116-
{documentFeatures.formatting.blockTypes.blockquote && blockquoteButton}
117-
{!!documentFeatures.layouts.length && <LayoutsButton layouts={documentFeatures.layouts} />}
118-
{documentFeatures.formatting.blockTypes.code && codeButton}
119-
{!!hasBlockItems && <InsertBlockMenu />}
64+
)}
65+
{hasMarks && <InlineMarks marks={documentFeatures.formatting.inlineMarks} />}
66+
{hasMarks && <ToolbarSeparator />}
67+
{(documentFeatures.formatting.alignment.center ||
68+
documentFeatures.formatting.alignment.end) && (
69+
<TextAlignMenu alignment={documentFeatures.formatting.alignment} />
70+
)}
71+
{documentFeatures.formatting.listTypes.unordered && (
72+
<Tooltip
73+
content={
74+
<Fragment>
75+
Bullet List <KeyboardInTooltip>- </KeyboardInTooltip>
76+
</Fragment>
77+
}
78+
weight="subtle"
79+
>
80+
{attrs => (
81+
<ListButton type="unordered-list" {...attrs}>
82+
<BulletListIcon />
83+
</ListButton>
84+
)}
85+
</Tooltip>
86+
)}
87+
{documentFeatures.formatting.listTypes.ordered && (
88+
<Tooltip
89+
content={
90+
<Fragment>
91+
Numbered List <KeyboardInTooltip>1. </KeyboardInTooltip>
92+
</Fragment>
93+
}
94+
weight="subtle"
95+
>
96+
{attrs => (
97+
<ListButton type="ordered-list" {...attrs}>
98+
<NumberedListIcon />
99+
</ListButton>
100+
)}
101+
</Tooltip>
102+
)}
103+
{(documentFeatures.formatting.alignment.center ||
104+
documentFeatures.formatting.alignment.end ||
105+
documentFeatures.formatting.listTypes.unordered ||
106+
documentFeatures.formatting.listTypes.ordered) && <ToolbarSeparator />}
120107

121-
<ToolbarSeparator />
108+
{documentFeatures.dividers && dividerButton}
109+
{documentFeatures.links && linkButton}
110+
{documentFeatures.formatting.blockTypes.blockquote && blockquoteButton}
111+
{!!documentFeatures.layouts.length && <LayoutsButton layouts={documentFeatures.layouts} />}
112+
{documentFeatures.formatting.blockTypes.code && codeButton}
113+
{!!hasBlockItems && <InsertBlockMenu />}
114+
</ToolbarGroup>
122115
{useMemo(() => {
123116
const ExpandIcon = viewState?.expanded ? Minimize2Icon : Maximize2Icon;
124117
return (
125118
viewState && (
126-
<Tooltip content={viewState.expanded ? 'Collapse' : 'Expand'} weight="subtle">
127-
{attrs => (
128-
<ToolbarButton
129-
onMouseDown={event => {
130-
event.preventDefault();
131-
viewState.toggle();
132-
}}
133-
{...attrs}
134-
>
135-
<ExpandIcon size="small" />
136-
</ToolbarButton>
137-
)}
138-
</Tooltip>
119+
<ToolbarGroup>
120+
<ToolbarSeparator />
121+
<Tooltip content={viewState.expanded ? 'Collapse' : 'Expand'} weight="subtle">
122+
{attrs => (
123+
<ToolbarButton
124+
onMouseDown={event => {
125+
event.preventDefault();
126+
viewState.toggle();
127+
}}
128+
{...attrs}
129+
>
130+
<ExpandIcon size="small" />
131+
</ToolbarButton>
132+
)}
133+
</Tooltip>
134+
</ToolbarGroup>
139135
)
140136
);
141137
}, [viewState])}
@@ -182,16 +178,28 @@ const ToolbarContainer = ({ children }: { children: ReactNode }) => {
182178
return (
183179
<div
184180
css={{
185-
backgroundColor: colors.background,
186-
boxShadow: `0 1px ${colors.border}, 0 -1px ${colors.border}`,
187-
paddingBottom: spacing.small,
188-
paddingTop: spacing.small,
181+
borderBottom: `1px solid ${colors.border}`,
182+
background: colors.background,
189183
position: 'sticky',
190184
top: 0,
191185
zIndex: 2,
186+
borderTopLeftRadius: 'inherit',
187+
borderTopRightRadius: 'inherit',
192188
}}
193189
>
194-
<ToolbarGroup>{children}</ToolbarGroup>
190+
<div
191+
css={{
192+
display: 'flex',
193+
flexDirection: 'row',
194+
justifyContent: 'space-between',
195+
alignItems: 'center',
196+
height: 40,
197+
paddingLeft: spacing.xsmall,
198+
paddingRight: spacing.xsmall,
199+
}}
200+
>
201+
{children}
202+
</div>
195203
</div>
196204
);
197205
};
@@ -487,7 +495,7 @@ function MoreFormattingDialog({
487495
return (
488496
<InlineDialog
489497
onMouseDown={event => {
490-
if ((event.target as any).nodeName === 'BUTTON') {
498+
if (event.target instanceof HTMLElement && event.target.closest('button')) {
491499
onCloseMenu();
492500
}
493501
}}

packages/fields-document/src/DocumentEditor/index.tsx

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export function DocumentEditor({
185185
relationships: Relationships;
186186
documentFeatures: DocumentFeatures;
187187
} & Omit<EditableProps, 'value' | 'onChange'>) {
188-
const { colors, spacing } = useTheme();
188+
const { radii, colors, spacing, fields } = useTheme();
189189
const [expanded, setExpanded] = useState(false);
190190
const editor = useMemo(
191191
() => createDocumentEditor(documentFeatures, componentBlocks, relationships),
@@ -196,10 +196,11 @@ export function DocumentEditor({
196196
<div
197197
css={[
198198
{
199-
display: 'flex',
200-
flexDirection: 'column',
199+
border: `1px solid ${colors.border}`,
200+
borderRadius: radii.small,
201201
},
202202
expanded && {
203+
border: 'none',
203204
background: colors.background,
204205
bottom: 0,
205206
left: 0,
@@ -248,12 +249,36 @@ export function DocumentEditor({
248249
)}
249250

250251
<DocumentEditorEditable
251-
css={
252-
expanded && {
253-
marginLeft: spacing.medium,
254-
marginRight: spacing.medium,
255-
}
256-
}
252+
css={[
253+
{
254+
borderRadius: 'inherit',
255+
background: fields.inputBackground,
256+
borderColor: fields.inputBorderColor,
257+
paddingLeft: spacing.medium,
258+
paddingRight: spacing.medium,
259+
':hover': {
260+
background: fields.hover.inputBackground,
261+
},
262+
':focus': {
263+
background: fields.focus.inputBackground,
264+
},
265+
':disabled': {
266+
background: fields.disabled.inputBackground,
267+
},
268+
},
269+
expanded
270+
? {
271+
height: 'auto !important',
272+
background: fields.focus.inputBackground,
273+
}
274+
: {
275+
height: 224,
276+
resize: 'vertical',
277+
overflowY: 'auto',
278+
minHeight: 120,
279+
scrollbarGutter: 'stable',
280+
},
281+
]}
257282
{...props}
258283
readOnly={onChange === undefined}
259284
/>

packages/fields-document/src/DocumentEditor/primitives/toolbar.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ export const ToolbarSeparator = () => {
3232
// Groups
3333
// ------------------------------
3434

35-
const autoFlowDirection = {
36-
column: 'row',
37-
row: 'column',
35+
type DirectionType = 'row' | 'column';
36+
37+
const directionToAlignment = {
38+
row: 'center',
39+
column: 'start',
3840
};
39-
type DirectionType = keyof typeof autoFlowDirection;
4041

4142
const ToolbarGroupContext = createContext<{ direction: DirectionType }>({ direction: 'row' });
4243
const useToolbarGroupContext = () => useContext(ToolbarGroupContext);
@@ -51,9 +52,12 @@ export const ToolbarGroup = forwardRefWithAs<'div', ToolbarGroupProps>(
5152
<Box
5253
ref={ref}
5354
css={{
54-
display: 'inline-grid',
55+
display: 'flex',
5556
gap: spacing.xxsmall,
56-
gridAutoFlow: autoFlowDirection[direction],
57+
flexDirection: direction,
58+
justifyContent: 'start',
59+
alignItems: directionToAlignment[direction],
60+
height: '100%',
5761
}}
5862
{...props}
5963
>
@@ -146,6 +150,7 @@ export const ToolbarButton = forwardRefWithAs<'button', ToolbarButtonProps>(func
146150
'&[data-display-mode=column]': {
147151
paddingLeft: spacing.medium,
148152
paddingRight: spacing.medium,
153+
width: '100%',
149154
},
150155
}}
151156
{...props}

0 commit comments

Comments
 (0)