mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-21 22:45:18 +02:00
Reintroduce manual Android tests (#5884)
* Re-add manual Android tests * Remove trailing slash * Disable autofocus
This commit is contained in:
@@ -101,6 +101,10 @@ To run integrations with [Playwright](https://playwright.dev/), first run `yarn
|
||||
|
||||
[Here's a helpful page](https://github.com/Microsoft/vscode/wiki/IME-Test) detailing how to test various input scenarios on Windows, Mac and Linux.
|
||||
|
||||
## Android tests
|
||||
|
||||
When making changes that might affect Android compatibility, you can perform the manual Android tests at [/examples/android-tests](https://slatejs.org/examples/android-tests).
|
||||
|
||||
## Publishing Releases
|
||||
|
||||
**Important**: When creating releases using Lerna with the instructions below, you will be given choices around how to increase version numbers. You should always use a `major`, `minor` or `patch` release and must never use a `prerelease`. If a prerelease is used, the root package will not link to the packages in the `packages` directory creating hard to diagnose issues.
|
||||
|
@@ -10,7 +10,7 @@
|
||||
"build:rollup": "rollup --config ./config/rollup/rollup.config.js --bundleConfigAsCjs",
|
||||
"changesetversion": "yarn changeset version && yarn install && git add .",
|
||||
"clean": "rimraf './packages/*/{dist,lib,node_modules}' './site/{.next,out}' --glob",
|
||||
"fix": "yarn fix:prettier && yarn fix:eslint",
|
||||
"fix": "yarn tsc:examples && yarn fix:prettier && yarn fix:eslint",
|
||||
"fix:eslint": "yarn lint:eslint --fix",
|
||||
"fix:prettier": "yarn lint:prettier --write",
|
||||
"lint": "yarn lint:typescript && yarn lint:eslint && yarn lint:prettier",
|
||||
|
234
site/examples/js/android-tests.jsx
Normal file
234
site/examples/js/android-tests.jsx
Normal file
@@ -0,0 +1,234 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { createEditor } from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { Editable, Slate, withReact } from 'slate-react'
|
||||
import { css } from '@emotion/css'
|
||||
|
||||
const TEST_CASES = [
|
||||
{
|
||||
id: 'split-join',
|
||||
name: 'Split/Join',
|
||||
instructions:
|
||||
'Hit enter twice then backspace twice in the following places:\n- Before "before"\n- Between the two "d"s in "middle"\n- After "after"',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'One ' },
|
||||
{ text: 'before', bold: true },
|
||||
{ text: ' two ' },
|
||||
{ text: 'middle', bold: true },
|
||||
{ text: ' three ' },
|
||||
{ text: 'after', bold: true },
|
||||
{ text: ' four' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'insert',
|
||||
name: 'Insertion',
|
||||
instructions:
|
||||
'Enter text below each line of instruction, including mis-spelling "wasnt"',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Type by tapping keys: ', bold: true },
|
||||
{ text: 'It wasnt me. No.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Type using glide typing: ', bold: true },
|
||||
{ text: 'Yes Sam, I am.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Type using voice input: ', bold: true },
|
||||
{ text: 'The quick brown fox jumps over the lazy dog' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'Write any two words using an IME', bold: true }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'special',
|
||||
name: 'Special',
|
||||
instructions: 'Follow the instructions on each line',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Type "it is", move cursor to "i|t" and hit enter.',
|
||||
bold: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Move cursor to "mid|dle" and press space, backspace, space, backspace.',
|
||||
bold: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'The middle word.' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Place cursor in line below. Wait for caps on keyboard to show up. If not try again. Type "It me. No." and check it doesn\'t mangle on the last period.',
|
||||
bold: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'empty',
|
||||
name: 'Empty',
|
||||
instructions:
|
||||
'Type "hello world", press enter, "hi", press enter, "bye", and then backspace over everything',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'remove',
|
||||
name: 'Remove',
|
||||
instructions:
|
||||
'Select from ANCHOR to FOCUS and press backspace. Move cursor to end. Backspace over all remaining content.',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Go and ' },
|
||||
{ text: 'select', bold: true },
|
||||
{ text: ' from this ANCHOR and then' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'go and select' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'to this FOCUS then press ' },
|
||||
{ text: 'backspace.', bold: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'After you have done that move selection to very end.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Then try ' },
|
||||
{ text: 'backspacing', bold: true },
|
||||
{ text: ' over all remaining text.' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
const AndroidTestsExample = () => {
|
||||
const [testId, setTestId] = useState(
|
||||
() => window.location.hash.replace('#', '') || TEST_CASES[0].id
|
||||
)
|
||||
useEffect(() => {
|
||||
window.history.replaceState({}, '', `#${testId}`)
|
||||
}, [testId])
|
||||
const testCase = TEST_CASES.find(({ id }) => id === testId)
|
||||
if (!testCase) {
|
||||
throw new Error(`Could not find test case '${testId}'`)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
Test case:{' '}
|
||||
<select value={testId} onChange={e => setTestId(e.target.value)}>
|
||||
{TEST_CASES.map(({ name, id }) => (
|
||||
<option key={id} value={id}>
|
||||
{name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<p
|
||||
className={css`
|
||||
font-weight: 600;
|
||||
margin: 0.5rem 0;
|
||||
white-space: pre-line;
|
||||
`}
|
||||
>
|
||||
{testCase.instructions}
|
||||
</p>
|
||||
|
||||
<TestCase key={testId} {...testCase} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
const TestCase = ({ value }) => {
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
return (
|
||||
<Slate editor={editor} initialValue={value}>
|
||||
<Editable
|
||||
renderLeaf={renderLeaf}
|
||||
placeholder="Enter some text…"
|
||||
spellCheck
|
||||
/>
|
||||
</Slate>
|
||||
)
|
||||
}
|
||||
const Leaf = ({ attributes, children, leaf }) => {
|
||||
if (leaf.bold) {
|
||||
children = <strong>{children}</strong>
|
||||
}
|
||||
return <span {...attributes}>{children}</span>
|
||||
}
|
||||
export default AndroidTestsExample
|
@@ -1,22 +1,22 @@
|
||||
import React, { useMemo, useCallback } from 'react'
|
||||
import {
|
||||
Slate,
|
||||
Editable,
|
||||
withReact,
|
||||
useSlateStatic,
|
||||
useReadOnly,
|
||||
ReactEditor,
|
||||
} from 'slate-react'
|
||||
import { css } from '@emotion/css'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import {
|
||||
Editor,
|
||||
Transforms,
|
||||
Range,
|
||||
Point,
|
||||
createEditor,
|
||||
Range,
|
||||
Element as SlateElement,
|
||||
Transforms,
|
||||
createEditor,
|
||||
} from 'slate'
|
||||
import { css } from '@emotion/css'
|
||||
import { withHistory } from 'slate-history'
|
||||
import {
|
||||
Editable,
|
||||
ReactEditor,
|
||||
Slate,
|
||||
useReadOnly,
|
||||
useSlateStatic,
|
||||
withReact,
|
||||
} from 'slate-react'
|
||||
|
||||
const initialValue = [
|
||||
{
|
||||
|
254
site/examples/ts/android-tests.tsx
Normal file
254
site/examples/ts/android-tests.tsx
Normal file
@@ -0,0 +1,254 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { Descendant, createEditor } from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { Editable, RenderLeafProps, Slate, withReact } from 'slate-react'
|
||||
import { css } from '@emotion/css'
|
||||
|
||||
interface AndroidTestCase {
|
||||
id: string
|
||||
name: string
|
||||
instructions: string
|
||||
value: Descendant[]
|
||||
}
|
||||
|
||||
const TEST_CASES: AndroidTestCase[] = [
|
||||
{
|
||||
id: 'split-join',
|
||||
name: 'Split/Join',
|
||||
instructions:
|
||||
'Hit enter twice then backspace twice in the following places:\n- Before "before"\n- Between the two "d"s in "middle"\n- After "after"',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'One ' },
|
||||
{ text: 'before', bold: true },
|
||||
{ text: ' two ' },
|
||||
{ text: 'middle', bold: true },
|
||||
{ text: ' three ' },
|
||||
{ text: 'after', bold: true },
|
||||
{ text: ' four' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'insert',
|
||||
name: 'Insertion',
|
||||
instructions:
|
||||
'Enter text below each line of instruction, including mis-spelling "wasnt"',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Type by tapping keys: ', bold: true },
|
||||
{ text: 'It wasnt me. No.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Type using glide typing: ', bold: true },
|
||||
{ text: 'Yes Sam, I am.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Type using voice input: ', bold: true },
|
||||
{ text: 'The quick brown fox jumps over the lazy dog' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'Write any two words using an IME', bold: true }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'special',
|
||||
name: 'Special',
|
||||
instructions: 'Follow the instructions on each line',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Type "it is", move cursor to "i|t" and hit enter.',
|
||||
bold: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Move cursor to "mid|dle" and press space, backspace, space, backspace.',
|
||||
bold: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'The middle word.' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'Place cursor in line below. Wait for caps on keyboard to show up. If not try again. Type "It me. No." and check it doesn\'t mangle on the last period.',
|
||||
bold: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'empty',
|
||||
name: 'Empty',
|
||||
instructions:
|
||||
'Type "hello world", press enter, "hi", press enter, "bye", and then backspace over everything',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'remove',
|
||||
name: 'Remove',
|
||||
instructions:
|
||||
'Select from ANCHOR to FOCUS and press backspace. Move cursor to end. Backspace over all remaining content.',
|
||||
value: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Go and ' },
|
||||
{ text: 'select', bold: true },
|
||||
{ text: ' from this ANCHOR and then' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'go and select' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'to this FOCUS then press ' },
|
||||
{ text: 'backspace.', bold: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'After you have done that move selection to very end.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Then try ' },
|
||||
{ text: 'backspacing', bold: true },
|
||||
{ text: ' over all remaining text.' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const AndroidTestsExample = () => {
|
||||
const [testId, setTestId] = useState(
|
||||
() => window.location.hash.replace('#', '') || TEST_CASES[0].id
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
window.history.replaceState({}, '', `#${testId}`)
|
||||
}, [testId])
|
||||
|
||||
const testCase = TEST_CASES.find(({ id }) => id === testId)
|
||||
if (!testCase) {
|
||||
throw new Error(`Could not find test case '${testId}'`)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<label>
|
||||
Test case:{' '}
|
||||
<select value={testId} onChange={e => setTestId(e.target.value)}>
|
||||
{TEST_CASES.map(({ name, id }) => (
|
||||
<option key={id} value={id}>
|
||||
{name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<p
|
||||
className={css`
|
||||
font-weight: 600;
|
||||
margin: 0.5rem 0;
|
||||
white-space: pre-line;
|
||||
`}
|
||||
>
|
||||
{testCase.instructions}
|
||||
</p>
|
||||
|
||||
<TestCase key={testId} {...testCase} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const TestCase = ({ value }: AndroidTestCase) => {
|
||||
const renderLeaf = useCallback(
|
||||
(props: RenderLeafProps) => <Leaf {...props} />,
|
||||
[]
|
||||
)
|
||||
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} initialValue={value}>
|
||||
<Editable
|
||||
renderLeaf={renderLeaf}
|
||||
placeholder="Enter some text…"
|
||||
spellCheck
|
||||
/>
|
||||
</Slate>
|
||||
)
|
||||
}
|
||||
|
||||
const Leaf = ({ attributes, children, leaf }: RenderLeafProps) => {
|
||||
if (leaf.bold) {
|
||||
children = <strong>{children}</strong>
|
||||
}
|
||||
|
||||
return <span {...attributes}>{children}</span>
|
||||
}
|
||||
|
||||
export default AndroidTestsExample
|
@@ -7,6 +7,7 @@ import { ErrorBoundary } from 'react-error-boundary'
|
||||
|
||||
import { Icon } from '../../examples/ts/components/index'
|
||||
|
||||
import AndroidTests from '../../examples/ts/android-tests'
|
||||
import CheckLists from '../../examples/ts/check-lists'
|
||||
import CodeHighlighting from '../../examples/ts/code-highlighting'
|
||||
import EditableVoids from '../../examples/ts/editable-voids'
|
||||
@@ -33,13 +34,15 @@ import CustomPlaceholder from '../../examples/ts/custom-placeholder'
|
||||
// node
|
||||
import { getAllExamples } from '../api'
|
||||
|
||||
type ExampleTuple = [string, React.ComponentType, string]
|
||||
type ExampleTuple = [name: string, component: React.ComponentType, path: string]
|
||||
|
||||
const EXAMPLES: ExampleTuple[] = [
|
||||
['Android Tests', AndroidTests, 'android-tests'],
|
||||
['Checklists', CheckLists, 'check-lists'],
|
||||
['Code Highlighting', CodeHighlighting, 'code-highlighting'],
|
||||
['Custom Placeholder', CustomPlaceholder, 'custom-placeholder'],
|
||||
['Editable Voids', EditableVoids, 'editable-voids'],
|
||||
['Embeds', Embeds, 'embeds'],
|
||||
['Code Highlighting', CodeHighlighting, 'code-highlighting'],
|
||||
['Forced Layout', ForcedLayout, 'forced-layout'],
|
||||
['Hovering Toolbar', HoveringToolbar, 'hovering-toolbar'],
|
||||
['Huge Document', HugeDocument, 'huge-document'],
|
||||
@@ -51,15 +54,20 @@ const EXAMPLES: ExampleTuple[] = [
|
||||
['Paste HTML', PasteHtml, 'paste-html'],
|
||||
['Plain Text', PlainText, 'plaintext'],
|
||||
['Read-only', ReadOnly, 'read-only'],
|
||||
['Rendering in iframes', IFrames, 'iframe'],
|
||||
['Rich Text', RichText, 'richtext'],
|
||||
['Search Highlighting', SearchHighlighting, 'search-highlighting'],
|
||||
['Shadow DOM', ShadowDOM, 'shadow-dom'],
|
||||
['Styling', Styling, 'styling'],
|
||||
['Tables', Tables, 'tables'],
|
||||
['Rendering in iframes', IFrames, 'iframe'],
|
||||
['Custom placeholder', CustomPlaceholder, 'custom-placeholder'],
|
||||
]
|
||||
|
||||
const HIDDEN_EXAMPLES = ['android-tests']
|
||||
|
||||
const NON_HIDDEN_EXAMPLES = EXAMPLES.filter(
|
||||
([, , path]) => !HIDDEN_EXAMPLES.includes(path)
|
||||
)
|
||||
|
||||
const Header = (props: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
{...props}
|
||||
@@ -351,7 +359,7 @@ const ExamplePage = ({ example }: { example: string }) => {
|
||||
</ExampleTitle>
|
||||
</ExampleHeader>
|
||||
<TabList isVisible={showTabs}>
|
||||
{EXAMPLES.map(([n, , p]) => (
|
||||
{NON_HIDDEN_EXAMPLES.map(([n, , p]) => (
|
||||
<Link
|
||||
key={p as string}
|
||||
href="/examples/[example]"
|
||||
|
Reference in New Issue
Block a user