@portabletext/plugin-typography 4.0.23 → 4.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -8
- package/src/create-decorator-guard.ts +0 -70
- package/src/disallow-in-code.feature +0 -53
- package/src/disallow-in-code.test.tsx +0 -41
- package/src/global.d.ts +0 -4
- package/src/index.ts +0 -3
- package/src/input-rule.ellipsis.feature +0 -95
- package/src/input-rule.ellipsis.test.tsx +0 -31
- package/src/input-rule.em-dash.feature +0 -103
- package/src/input-rule.em-dash.test.tsx +0 -31
- package/src/input-rule.multiplication.feature +0 -22
- package/src/input-rule.multiplication.test.tsx +0 -31
- package/src/input-rule.smart-quotes.feature +0 -72
- package/src/input-rule.smart-quotes.test.tsx +0 -31
- package/src/input-rules.typography.ts +0 -190
- package/src/plugin.typography.tsx +0 -147
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/plugin-typography",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.25",
|
|
4
4
|
"description": "Automatically transform text to typographic variants",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"portabletext",
|
|
@@ -30,12 +30,11 @@
|
|
|
30
30
|
"main": "./dist/index.js",
|
|
31
31
|
"types": "./dist/index.d.ts",
|
|
32
32
|
"files": [
|
|
33
|
-
"dist"
|
|
34
|
-
"src"
|
|
33
|
+
"dist"
|
|
35
34
|
],
|
|
36
35
|
"dependencies": {
|
|
37
36
|
"react-compiler-runtime": "^1.0.0",
|
|
38
|
-
"@portabletext/plugin-input-rule": "^1.0.
|
|
37
|
+
"@portabletext/plugin-input-rule": "^1.0.25"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
41
40
|
"@sanity/pkg-utils": "^10.1.1",
|
|
@@ -52,12 +51,12 @@
|
|
|
52
51
|
"typescript": "5.9.3",
|
|
53
52
|
"typescript-eslint": "^8.48.0",
|
|
54
53
|
"vitest": "^4.0.14",
|
|
55
|
-
"@portabletext/editor": "^3.3.
|
|
56
|
-
"@portabletext/schema": "^2.0.
|
|
57
|
-
"racejar": "2.0.
|
|
54
|
+
"@portabletext/editor": "^3.3.5",
|
|
55
|
+
"@portabletext/schema": "^2.0.1",
|
|
56
|
+
"racejar": "2.0.1"
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
|
60
|
-
"@portabletext/editor": "^3.3.
|
|
59
|
+
"@portabletext/editor": "^3.3.5",
|
|
61
60
|
"react": "^18.3 || ^19"
|
|
62
61
|
},
|
|
63
62
|
"engines": {
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type {EditorContext, EditorSchema} from '@portabletext/editor'
|
|
2
|
-
import {
|
|
3
|
-
getSelectedSpans,
|
|
4
|
-
isActiveDecorator,
|
|
5
|
-
} from '@portabletext/editor/selectors'
|
|
6
|
-
import type {InputRuleGuard} from '@portabletext/plugin-input-rule'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @public
|
|
10
|
-
* Create an `InputRuleGuard` that can prevent the rule from running inside
|
|
11
|
-
* certain decorators.
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```tsx
|
|
15
|
-
* const guard = createDecoratorGuard({
|
|
16
|
-
* decorators: ({context}) => context.schema.decorators.flatMap((decorator) => decorator.name === 'code' ? [] : [decorator.name]),
|
|
17
|
-
* })
|
|
18
|
-
*
|
|
19
|
-
* <TypographyPlugin guard={guard} />
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export function createDecoratorGuard(config: {
|
|
23
|
-
decorators: ({
|
|
24
|
-
context,
|
|
25
|
-
}: {
|
|
26
|
-
context: Pick<EditorContext, 'schema'>
|
|
27
|
-
}) => Array<EditorSchema['decorators'][number]['name']>
|
|
28
|
-
}): InputRuleGuard {
|
|
29
|
-
return ({snapshot, event}) => {
|
|
30
|
-
const allowedDecorators = config.decorators({
|
|
31
|
-
context: {
|
|
32
|
-
schema: snapshot.context.schema,
|
|
33
|
-
},
|
|
34
|
-
})
|
|
35
|
-
const decorators = snapshot.context.schema.decorators.flatMap(
|
|
36
|
-
(decorator) =>
|
|
37
|
-
allowedDecorators.includes(decorator.name) ? [] : [decorator.name],
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
if (decorators.length === 0) {
|
|
41
|
-
return true
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const matchedSpans = event.matches.flatMap((match) =>
|
|
45
|
-
getSelectedSpans({
|
|
46
|
-
...snapshot,
|
|
47
|
-
context: {
|
|
48
|
-
...snapshot.context,
|
|
49
|
-
selection: match.selection,
|
|
50
|
-
},
|
|
51
|
-
}),
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
let preventInputRule = false
|
|
55
|
-
|
|
56
|
-
for (const decorator of decorators) {
|
|
57
|
-
if (isActiveDecorator(decorator)(snapshot)) {
|
|
58
|
-
preventInputRule = true
|
|
59
|
-
break
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (matchedSpans.some((span) => span.node.marks?.includes(decorator))) {
|
|
63
|
-
preventInputRule = true
|
|
64
|
-
break
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return !preventInputRule
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
Feature: Disallow in code
|
|
2
|
-
|
|
3
|
-
Scenario Outline: Decorated text
|
|
4
|
-
Given the text <text>
|
|
5
|
-
And "code" around <decorated>
|
|
6
|
-
When the caret is put <position>
|
|
7
|
-
And "->" is typed
|
|
8
|
-
Then the text is <new text>
|
|
9
|
-
|
|
10
|
-
Examples:
|
|
11
|
-
| text | decorated | position | new text |
|
|
12
|
-
| "foo" | "foo" | after "foo" | "foo->" |
|
|
13
|
-
| "foo bar baz" | "bar" | after "bar" | "foo ,bar->, baz" |
|
|
14
|
-
| "foo bar baz" | "bar" | before "bar" | "foo →,bar, baz" |
|
|
15
|
-
| "foo bar baz" | "bar" | before "ar baz" | "foo ,b->ar, baz" |
|
|
16
|
-
|
|
17
|
-
Scenario Outline: Partially decorated text
|
|
18
|
-
Given the text "foo bar2x baz"
|
|
19
|
-
And "code" around "bar2x"
|
|
20
|
-
When the caret is put after "bar2x"
|
|
21
|
-
And "2" is typed
|
|
22
|
-
Then the text is "foo ,bar2x2, baz"
|
|
23
|
-
|
|
24
|
-
Scenario Outline: Partially decorated text with decorator toggled off
|
|
25
|
-
Given the text <text>
|
|
26
|
-
And "code" around <decorated>
|
|
27
|
-
When the caret is put <position>
|
|
28
|
-
And "code" is toggled
|
|
29
|
-
And <inserted text> is typed
|
|
30
|
-
Then the text is <new text>
|
|
31
|
-
|
|
32
|
-
Examples:
|
|
33
|
-
| text | decorated | position | inserted text | new text |
|
|
34
|
-
| "foo bar baz" | "bar" | after "bar" | "2x2" | "foo ,bar,2×2 baz" |
|
|
35
|
-
| "foo bar2 baz" | "bar2" | after "bar2" | "x2" | "foo ,bar2,x2 baz" |
|
|
36
|
-
| "foo bar2x baz" | "bar2x" | after "bar2x" | "2" | "foo ,bar2x,2 baz" |
|
|
37
|
-
|
|
38
|
-
Scenario Outline: Decorated and annotated text
|
|
39
|
-
Given the text "foo bar baz"
|
|
40
|
-
And <decorator> around "bar"
|
|
41
|
-
And a "link" "l1" around "bar"
|
|
42
|
-
When the caret is put <position>
|
|
43
|
-
And "->" is typed
|
|
44
|
-
Then the text is <new text>
|
|
45
|
-
|
|
46
|
-
Examples:
|
|
47
|
-
| decorator | position | new text |
|
|
48
|
-
| "code" | after "bar" | "foo ,bar,→ baz" |
|
|
49
|
-
| "strong" | after "bar" | "foo ,bar,→ baz" |
|
|
50
|
-
| "code" | before "bar" | "foo →,bar, baz" |
|
|
51
|
-
| "strong" | before "bar" | "foo →,bar, baz" |
|
|
52
|
-
| "code" | before "ar baz" | "foo ,b->ar, baz" |
|
|
53
|
-
| "strong" | before "ar baz" | "foo ,b→ar, baz" |
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import {parameterTypes} from '@portabletext/editor/test'
|
|
2
|
-
import {
|
|
3
|
-
createTestEditor,
|
|
4
|
-
stepDefinitions,
|
|
5
|
-
type Context,
|
|
6
|
-
} from '@portabletext/editor/test/vitest'
|
|
7
|
-
import {defineSchema} from '@portabletext/schema'
|
|
8
|
-
import {Before} from 'racejar'
|
|
9
|
-
import {Feature} from 'racejar/vitest'
|
|
10
|
-
import {createDecoratorGuard} from './create-decorator-guard'
|
|
11
|
-
import disallowInCodeFeature from './disallow-in-code.feature?raw'
|
|
12
|
-
import {TypographyPlugin} from './plugin.typography'
|
|
13
|
-
|
|
14
|
-
const codeGuard = createDecoratorGuard({
|
|
15
|
-
decorators: ({context}) =>
|
|
16
|
-
context.schema.decorators.flatMap((decorator) =>
|
|
17
|
-
decorator.name === 'code' ? [] : [decorator.name],
|
|
18
|
-
),
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
Feature({
|
|
22
|
-
hooks: [
|
|
23
|
-
Before(async (context: Context) => {
|
|
24
|
-
const {editor, locator} = await createTestEditor({
|
|
25
|
-
children: (
|
|
26
|
-
<TypographyPlugin guard={codeGuard} enable={['multiplication']} />
|
|
27
|
-
),
|
|
28
|
-
schemaDefinition: defineSchema({
|
|
29
|
-
decorators: [{name: 'strong'}, {name: 'code'}],
|
|
30
|
-
annotations: [{name: 'link'}],
|
|
31
|
-
}),
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
context.locator = locator
|
|
35
|
-
context.editor = editor
|
|
36
|
-
}),
|
|
37
|
-
],
|
|
38
|
-
featureText: disallowInCodeFeature,
|
|
39
|
-
stepDefinitions,
|
|
40
|
-
parameterTypes,
|
|
41
|
-
})
|
package/src/global.d.ts
DELETED
package/src/index.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
Feature: Ellipsis Input Rule
|
|
2
|
-
|
|
3
|
-
Background:
|
|
4
|
-
Given a global keymap
|
|
5
|
-
|
|
6
|
-
Scenario Outline: Inserting ellipsis in unformatted text
|
|
7
|
-
Given the text <text>
|
|
8
|
-
# The "When {string} is inserted" step inserts all characters at once to
|
|
9
|
-
# mimic how insert.text behaves on Android
|
|
10
|
-
When <inserted text> is inserted
|
|
11
|
-
Then the text is <before undo>
|
|
12
|
-
When undo is performed
|
|
13
|
-
Then the text is <after undo>
|
|
14
|
-
|
|
15
|
-
Examples:
|
|
16
|
-
| text | inserted text | before undo | after undo |
|
|
17
|
-
| ".." | "." | "…" | "..." |
|
|
18
|
-
| "" | "..." | "…" | "..." |
|
|
19
|
-
| "foo" | "..." | "foo…" | "foo..." |
|
|
20
|
-
| "" | "foo..." | "foo…" | "foo..." |
|
|
21
|
-
| "foo.." | ".bar" | "foo…bar" | "foo...bar" |
|
|
22
|
-
| "" | "foo...bar..." | "foo…bar…" | "foo...bar..." |
|
|
23
|
-
| "foo...bar..." | "baz..." | "foo...bar...baz…" | "foo...bar...baz..." |
|
|
24
|
-
|
|
25
|
-
Scenario: Inserting ellipsis inside a decorator
|
|
26
|
-
Given the text "foo.."
|
|
27
|
-
And "strong" around "foo.."
|
|
28
|
-
When the caret is put after "foo.."
|
|
29
|
-
And "." is typed
|
|
30
|
-
Then the text is "foo…"
|
|
31
|
-
And "foo…" has marks "strong"
|
|
32
|
-
|
|
33
|
-
Scenario: Inserting ellipsis at the edge of a decorator
|
|
34
|
-
Given the text "foo.."
|
|
35
|
-
And "strong" around "foo"
|
|
36
|
-
When the caret is put after "foo.."
|
|
37
|
-
And "." is typed
|
|
38
|
-
Then the text is "foo,…"
|
|
39
|
-
And "foo" has marks "strong"
|
|
40
|
-
And "…" has no marks
|
|
41
|
-
|
|
42
|
-
Scenario: Inserting ellipsis inside an annotation
|
|
43
|
-
Given the text "foo.."
|
|
44
|
-
And a "link" "l1" around "foo.."
|
|
45
|
-
When the caret is put after "foo.."
|
|
46
|
-
And "." is typed
|
|
47
|
-
Then the text is "foo…"
|
|
48
|
-
And "foo…" has marks "l1"
|
|
49
|
-
|
|
50
|
-
Scenario: Inserting ellipsis at the edge of an annotation
|
|
51
|
-
Given the text "foo.."
|
|
52
|
-
And a "link" "l1" around "foo"
|
|
53
|
-
When the caret is put after "foo.."
|
|
54
|
-
And "." is typed
|
|
55
|
-
Then the text is "foo,…"
|
|
56
|
-
And "foo" has marks "l1"
|
|
57
|
-
And "…" has no marks
|
|
58
|
-
|
|
59
|
-
Scenario Outline: Smart undo with Backspace
|
|
60
|
-
Given the text <text>
|
|
61
|
-
When <inserted text> is inserted
|
|
62
|
-
And "{Backspace}" is pressed
|
|
63
|
-
Then the text is <new text>
|
|
64
|
-
|
|
65
|
-
Examples:
|
|
66
|
-
| text | inserted text | new text |
|
|
67
|
-
| ".." | "." | "..." |
|
|
68
|
-
| "" | "..." | "..." |
|
|
69
|
-
| "foo" | "..." | "foo..." |
|
|
70
|
-
| "" | "foo..." | "foo..." |
|
|
71
|
-
| "foo.." | ".bar" | "foo...bar" |
|
|
72
|
-
| "" | "foo...bar..." | "foo...bar..." |
|
|
73
|
-
| "foo...bar..." | "baz..." | "foo...bar...baz..." |
|
|
74
|
-
|
|
75
|
-
Scenario Outline: Smart undo aborted after text changes
|
|
76
|
-
Given the text <text>
|
|
77
|
-
When <inserted text> is inserted
|
|
78
|
-
And <new text> is typed
|
|
79
|
-
And "{Backspace}" is pressed
|
|
80
|
-
Then the text is <final text>
|
|
81
|
-
|
|
82
|
-
Examples:
|
|
83
|
-
| text | inserted text | new text | final text |
|
|
84
|
-
| "" | "..." | "n" | "…" |
|
|
85
|
-
|
|
86
|
-
Scenario Outline: Smart undo aborted after selection changes
|
|
87
|
-
Given the text <text>
|
|
88
|
-
When <inserted text> is inserted
|
|
89
|
-
And "{ArrowLeft}" is pressed
|
|
90
|
-
And "{Backspace}" is pressed
|
|
91
|
-
Then the text is <final text>
|
|
92
|
-
|
|
93
|
-
Examples:
|
|
94
|
-
| text | inserted text | final text |
|
|
95
|
-
| "foo" | "..." | "fo…" |
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {parameterTypes} from '@portabletext/editor/test'
|
|
2
|
-
import {
|
|
3
|
-
createTestEditor,
|
|
4
|
-
stepDefinitions,
|
|
5
|
-
type Context,
|
|
6
|
-
} from '@portabletext/editor/test/vitest'
|
|
7
|
-
import {defineSchema} from '@portabletext/schema'
|
|
8
|
-
import {Before} from 'racejar'
|
|
9
|
-
import {Feature} from 'racejar/vitest'
|
|
10
|
-
import ellipsisFeature from './input-rule.ellipsis.feature?raw'
|
|
11
|
-
import {TypographyPlugin} from './plugin.typography'
|
|
12
|
-
|
|
13
|
-
Feature({
|
|
14
|
-
hooks: [
|
|
15
|
-
Before(async (context: Context) => {
|
|
16
|
-
const {editor, locator} = await createTestEditor({
|
|
17
|
-
children: <TypographyPlugin />,
|
|
18
|
-
schemaDefinition: defineSchema({
|
|
19
|
-
decorators: [{name: 'strong'}],
|
|
20
|
-
annotations: [{name: 'link'}],
|
|
21
|
-
}),
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
context.locator = locator
|
|
25
|
-
context.editor = editor
|
|
26
|
-
}),
|
|
27
|
-
],
|
|
28
|
-
featureText: ellipsisFeature,
|
|
29
|
-
stepDefinitions,
|
|
30
|
-
parameterTypes,
|
|
31
|
-
})
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
Feature: Em Dash Input Rule
|
|
2
|
-
|
|
3
|
-
Background:
|
|
4
|
-
Given a global keymap
|
|
5
|
-
|
|
6
|
-
Scenario Outline: Inserting em dash in unformatted text
|
|
7
|
-
Given the text <text>
|
|
8
|
-
# The "When {string} is inserted" step inserts all characters at once to
|
|
9
|
-
# mimic how insert.text behaves on Android
|
|
10
|
-
When <inserted text> is inserted
|
|
11
|
-
Then the text is <before undo>
|
|
12
|
-
When undo is performed
|
|
13
|
-
Then the text is <after undo>
|
|
14
|
-
|
|
15
|
-
Examples:
|
|
16
|
-
| text | inserted text | before undo | after undo |
|
|
17
|
-
| "-" | "-" | "—" | "--" |
|
|
18
|
-
| "" | "--" | "—" | "--" |
|
|
19
|
-
| "foo" | "--" | "foo—" | "foo--" |
|
|
20
|
-
| "" | "foo--" | "foo—" | "foo--" |
|
|
21
|
-
| "foo-" | "-bar" | "foo—bar" | "foo--bar" |
|
|
22
|
-
| "" | "foo--bar--" | "foo—bar—" | "foo--bar--" |
|
|
23
|
-
| "foo--bar--" | "baz--" | "foo--bar--baz—" | "foo--bar--baz--" |
|
|
24
|
-
|
|
25
|
-
Scenario: Inserting em dash inside a decorator
|
|
26
|
-
Given the text "foo-"
|
|
27
|
-
And "strong" around "foo-"
|
|
28
|
-
When the caret is put after "foo-"
|
|
29
|
-
And "-" is typed
|
|
30
|
-
Then the text is "foo—"
|
|
31
|
-
And "foo—" has marks "strong"
|
|
32
|
-
|
|
33
|
-
Scenario: Inserting em dash at the edge of a decorator
|
|
34
|
-
Given the text "foo-"
|
|
35
|
-
And "strong" around "foo"
|
|
36
|
-
When the caret is put after "foo-"
|
|
37
|
-
And "-" is typed
|
|
38
|
-
Then the text is "foo,—"
|
|
39
|
-
And "foo" has marks "strong"
|
|
40
|
-
And "—" has no marks
|
|
41
|
-
|
|
42
|
-
Scenario: Inserting em dash inside an annotation
|
|
43
|
-
Given the text "foo-"
|
|
44
|
-
And a "link" "l1" around "foo-"
|
|
45
|
-
When the caret is put after "foo-"
|
|
46
|
-
And "-" is typed
|
|
47
|
-
Then the text is "foo—"
|
|
48
|
-
And "foo—" has marks "l1"
|
|
49
|
-
|
|
50
|
-
Scenario: Inserting em dash halfway inside an annotation
|
|
51
|
-
Given the text "foo-"
|
|
52
|
-
And a "link" "l1" around "foo-"
|
|
53
|
-
When the caret is put after "foo-"
|
|
54
|
-
And "-" is typed
|
|
55
|
-
Then the text is "foo—"
|
|
56
|
-
And "foo—" has marks "l1"
|
|
57
|
-
|
|
58
|
-
Scenario: Inserting em dash at the edge of an annotation
|
|
59
|
-
Given the text "foo-"
|
|
60
|
-
And a "link" "l1" around "foo"
|
|
61
|
-
When the caret is put after "foo-"
|
|
62
|
-
And "-" is typed
|
|
63
|
-
Then the text is "foo,—"
|
|
64
|
-
And "foo" has marks "l1"
|
|
65
|
-
And "—" has no marks
|
|
66
|
-
|
|
67
|
-
Scenario Outline: Smart undo with Backspace
|
|
68
|
-
Given the text <text>
|
|
69
|
-
When <inserted text> is inserted
|
|
70
|
-
And "{Backspace}" is pressed
|
|
71
|
-
Then the text is <new text>
|
|
72
|
-
|
|
73
|
-
Examples:
|
|
74
|
-
| text | inserted text | new text |
|
|
75
|
-
| "-" | "-" | "--" |
|
|
76
|
-
| "" | "--" | "--" |
|
|
77
|
-
| "foo" | "--" | "foo--" |
|
|
78
|
-
| "" | "foo--" | "foo--" |
|
|
79
|
-
| "foo-" | "-bar" | "foo--bar" |
|
|
80
|
-
| "" | "foo--bar--" | "foo--bar--" |
|
|
81
|
-
| "foo--bar--" | "baz--" | "foo--bar--baz--" |
|
|
82
|
-
|
|
83
|
-
Scenario Outline: Smart undo aborted after text changes
|
|
84
|
-
Given the text <text>
|
|
85
|
-
When <inserted text> is inserted
|
|
86
|
-
And <new text> is typed
|
|
87
|
-
And "{Backspace}" is pressed
|
|
88
|
-
Then the text is <final text>
|
|
89
|
-
|
|
90
|
-
Examples:
|
|
91
|
-
| text | inserted text | new text | final text |
|
|
92
|
-
| "" | "--" | "n" | "—" |
|
|
93
|
-
|
|
94
|
-
Scenario Outline: Smart undo aborted after selection changes
|
|
95
|
-
Given the text <text>
|
|
96
|
-
When <inserted text> is inserted
|
|
97
|
-
And "{ArrowLeft}" is pressed
|
|
98
|
-
And "{Backspace}" is pressed
|
|
99
|
-
Then the text is <final text>
|
|
100
|
-
|
|
101
|
-
Examples:
|
|
102
|
-
| text | inserted text | final text |
|
|
103
|
-
| "foo" | "--" | "fo—" |
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {parameterTypes} from '@portabletext/editor/test'
|
|
2
|
-
import {
|
|
3
|
-
createTestEditor,
|
|
4
|
-
stepDefinitions,
|
|
5
|
-
type Context,
|
|
6
|
-
} from '@portabletext/editor/test/vitest'
|
|
7
|
-
import {defineSchema} from '@portabletext/schema'
|
|
8
|
-
import {Before} from 'racejar'
|
|
9
|
-
import {Feature} from 'racejar/vitest'
|
|
10
|
-
import emDashFeature from './input-rule.em-dash.feature?raw'
|
|
11
|
-
import {TypographyPlugin} from './plugin.typography'
|
|
12
|
-
|
|
13
|
-
Feature({
|
|
14
|
-
hooks: [
|
|
15
|
-
Before(async (context: Context) => {
|
|
16
|
-
const {editor, locator} = await createTestEditor({
|
|
17
|
-
children: <TypographyPlugin />,
|
|
18
|
-
schemaDefinition: defineSchema({
|
|
19
|
-
decorators: [{name: 'strong'}],
|
|
20
|
-
annotations: [{name: 'link'}],
|
|
21
|
-
}),
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
context.locator = locator
|
|
25
|
-
context.editor = editor
|
|
26
|
-
}),
|
|
27
|
-
],
|
|
28
|
-
featureText: emDashFeature,
|
|
29
|
-
stepDefinitions,
|
|
30
|
-
parameterTypes,
|
|
31
|
-
})
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Feature: Multiplication Input Rule
|
|
2
|
-
|
|
3
|
-
Scenario Outline: Inserting multiplication sign
|
|
4
|
-
Given the text <text>
|
|
5
|
-
When <inserted text> is inserted
|
|
6
|
-
Then the text is <new text>
|
|
7
|
-
|
|
8
|
-
Examples:
|
|
9
|
-
| text | inserted text | new text |
|
|
10
|
-
| "" | "1*2" | "1×2" |
|
|
11
|
-
| "" | "1*2*3" | "1×2×3" |
|
|
12
|
-
|
|
13
|
-
Scenario Outline: Inserting multiplication sign and writing afterwards
|
|
14
|
-
Given the text <text>
|
|
15
|
-
When <inserted text> is inserted
|
|
16
|
-
And "new" is typed
|
|
17
|
-
Then the text is <new text>
|
|
18
|
-
|
|
19
|
-
Examples:
|
|
20
|
-
| text | inserted text | new text |
|
|
21
|
-
| "" | "1*2" | "1×2new" |
|
|
22
|
-
| "" | "1*2*3" | "1×2×3new" |
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {parameterTypes} from '@portabletext/editor/test'
|
|
2
|
-
import {
|
|
3
|
-
createTestEditor,
|
|
4
|
-
stepDefinitions,
|
|
5
|
-
type Context,
|
|
6
|
-
} from '@portabletext/editor/test/vitest'
|
|
7
|
-
import {defineSchema} from '@portabletext/schema'
|
|
8
|
-
import {Before} from 'racejar'
|
|
9
|
-
import {Feature} from 'racejar/vitest'
|
|
10
|
-
import multiplicationFeature from './input-rule.multiplication.feature?raw'
|
|
11
|
-
import {TypographyPlugin} from './plugin.typography'
|
|
12
|
-
|
|
13
|
-
Feature({
|
|
14
|
-
hooks: [
|
|
15
|
-
Before(async (context: Context) => {
|
|
16
|
-
const {editor, locator} = await createTestEditor({
|
|
17
|
-
children: <TypographyPlugin enable={['multiplication']} />,
|
|
18
|
-
schemaDefinition: defineSchema({
|
|
19
|
-
decorators: [{name: 'strong'}],
|
|
20
|
-
annotations: [{name: 'link'}],
|
|
21
|
-
}),
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
context.locator = locator
|
|
25
|
-
context.editor = editor
|
|
26
|
-
}),
|
|
27
|
-
],
|
|
28
|
-
featureText: multiplicationFeature,
|
|
29
|
-
stepDefinitions,
|
|
30
|
-
parameterTypes,
|
|
31
|
-
})
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Feature: Smart Quotes Input Rule
|
|
2
|
-
|
|
3
|
-
Background:
|
|
4
|
-
Given a global keymap
|
|
5
|
-
|
|
6
|
-
Scenario Outline: Typing turns double quotes into smart quotes
|
|
7
|
-
Given the text <text>
|
|
8
|
-
When <inserted text> is typed
|
|
9
|
-
Then the text is <new text>
|
|
10
|
-
|
|
11
|
-
Examples:
|
|
12
|
-
| text | inserted text | new text |
|
|
13
|
-
| "" | "\"foo\"" | "“foo”" |
|
|
14
|
-
| "“foo”" | " \"bar\"" | "“foo” “bar”" |
|
|
15
|
-
| "" | "\"foo\" \"bar\"" | "“foo” “bar”" |
|
|
16
|
-
|
|
17
|
-
Scenario Outline: Inserting double smart quotes in unformatted text
|
|
18
|
-
Given the text <text>
|
|
19
|
-
# The "When {string} is inserted" step inserts all characters at once to
|
|
20
|
-
# mimic how insert.text behaves on Android
|
|
21
|
-
When <inserted text> is inserted
|
|
22
|
-
Then the text is <before undo>
|
|
23
|
-
When undo is performed
|
|
24
|
-
Then the text is <after undo>
|
|
25
|
-
|
|
26
|
-
Examples:
|
|
27
|
-
| text | inserted text | before undo | after undo |
|
|
28
|
-
| "" | "\"" | "“" | """ |
|
|
29
|
-
| "" | "\"\"" | "““" | """" |
|
|
30
|
-
| "" | "\"\"\"" | "“““" | """"" |
|
|
31
|
-
| "”" | "\"" | "””" | "”"" |
|
|
32
|
-
# | "”" | "\"\"" | "”””" | "””"" |
|
|
33
|
-
| "" | "\"foo\"" | "“foo”" | ""foo"" |
|
|
34
|
-
| "“foo" | "\"" | "“foo”" | "“foo"" |
|
|
35
|
-
| ""foo" | "\"" | ""foo”" | ""foo"" |
|
|
36
|
-
| ""foo"" | "\"bar\"" | ""foo"“bar”" | ""foo""bar"" |
|
|
37
|
-
| "“foo”" | "\"" | "“foo””" | "“foo”"" |
|
|
38
|
-
|
|
39
|
-
# | "“foo”" | "\"\"" | "“foo”””" | "“foo”""" |
|
|
40
|
-
Scenario Outline: Inserting single smart quotes in unformatted text
|
|
41
|
-
Given the text <text>
|
|
42
|
-
# The "When {string} is inserted" step inserts all characters at once to
|
|
43
|
-
# mimic how insert.text behaves on Android
|
|
44
|
-
When <inserted text> is inserted
|
|
45
|
-
Then the text is <before undo>
|
|
46
|
-
When undo is performed
|
|
47
|
-
Then the text is <after undo>
|
|
48
|
-
|
|
49
|
-
Examples:
|
|
50
|
-
| text | inserted text | before undo | after undo |
|
|
51
|
-
| "" | "'" | "‘" | "'" |
|
|
52
|
-
| "" | "'foo'" | "‘foo’" | "'foo'" |
|
|
53
|
-
| "‘foo" | "'" | "‘foo’" | "‘foo'" |
|
|
54
|
-
| "'foo" | "'" | "'foo’" | "'foo'" |
|
|
55
|
-
| "'foo'" | "'bar'" | "'foo'‘bar’" | "'foo''bar'" |
|
|
56
|
-
|
|
57
|
-
Scenario: Mixed quotes
|
|
58
|
-
Given the text ""
|
|
59
|
-
When "\"'sorry' you say?\" she asked" is typed
|
|
60
|
-
Then the text is "“‘sorry’ you say?” she asked"
|
|
61
|
-
|
|
62
|
-
Scenario Outline: Contractions
|
|
63
|
-
When <text> is typed
|
|
64
|
-
Then the text is <new text>
|
|
65
|
-
|
|
66
|
-
Examples:
|
|
67
|
-
| text | new text |
|
|
68
|
-
| "it's" | "it’s" |
|
|
69
|
-
| "don't" | "don’t" |
|
|
70
|
-
| "won't" | "won’t" |
|
|
71
|
-
| "I'm" | "I’m" |
|
|
72
|
-
| "you're" | "you’re" |
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {parameterTypes} from '@portabletext/editor/test'
|
|
2
|
-
import {
|
|
3
|
-
createTestEditor,
|
|
4
|
-
stepDefinitions,
|
|
5
|
-
type Context,
|
|
6
|
-
} from '@portabletext/editor/test/vitest'
|
|
7
|
-
import {defineSchema} from '@portabletext/schema'
|
|
8
|
-
import {Before} from 'racejar'
|
|
9
|
-
import {Feature} from 'racejar/vitest'
|
|
10
|
-
import smartQuotesFeature from './input-rule.smart-quotes.feature?raw'
|
|
11
|
-
import {TypographyPlugin} from './plugin.typography'
|
|
12
|
-
|
|
13
|
-
Feature({
|
|
14
|
-
hooks: [
|
|
15
|
-
Before(async (context: Context) => {
|
|
16
|
-
const {editor, locator} = await createTestEditor({
|
|
17
|
-
children: <TypographyPlugin />,
|
|
18
|
-
schemaDefinition: defineSchema({
|
|
19
|
-
decorators: [{name: 'strong'}],
|
|
20
|
-
annotations: [{name: 'link'}],
|
|
21
|
-
}),
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
context.locator = locator
|
|
25
|
-
context.editor = editor
|
|
26
|
-
}),
|
|
27
|
-
],
|
|
28
|
-
featureText: smartQuotesFeature,
|
|
29
|
-
stepDefinitions,
|
|
30
|
-
parameterTypes,
|
|
31
|
-
})
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineTextTransformRule,
|
|
3
|
-
type InputRule,
|
|
4
|
-
} from '@portabletext/plugin-input-rule'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
export const emDashRule = defineTextTransformRule({
|
|
10
|
-
on: /--/,
|
|
11
|
-
transform: () => '—',
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @public
|
|
16
|
-
*/
|
|
17
|
-
export const ellipsisRule = defineTextTransformRule({
|
|
18
|
-
on: /\.\.\./,
|
|
19
|
-
transform: () => '…',
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @public
|
|
24
|
-
*/
|
|
25
|
-
export const openingDoubleQuoteRule = defineTextTransformRule({
|
|
26
|
-
on: /(?:^|(?<=[\s{[(<'"\u2018\u201C]))"/g,
|
|
27
|
-
transform: () => '“',
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @public
|
|
32
|
-
*/
|
|
33
|
-
export const closingDoubleQuoteRule = defineTextTransformRule({
|
|
34
|
-
on: /"/g,
|
|
35
|
-
transform: () => '”',
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @public
|
|
40
|
-
*/
|
|
41
|
-
export const openingSingleQuoteRule = defineTextTransformRule({
|
|
42
|
-
on: /(?:^|(?<=[\s{[(<'"\u2018\u201C]))'/g,
|
|
43
|
-
transform: () => '‘',
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* @public
|
|
48
|
-
*/
|
|
49
|
-
export const closingSingleQuoteRule = defineTextTransformRule({
|
|
50
|
-
on: /'/g,
|
|
51
|
-
transform: () => '’',
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @public
|
|
56
|
-
*/
|
|
57
|
-
export const smartQuotesRules: Array<InputRule> = [
|
|
58
|
-
openingDoubleQuoteRule,
|
|
59
|
-
closingDoubleQuoteRule,
|
|
60
|
-
openingSingleQuoteRule,
|
|
61
|
-
closingSingleQuoteRule,
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @public
|
|
66
|
-
*/
|
|
67
|
-
export const leftArrowRule = defineTextTransformRule({
|
|
68
|
-
on: /<-/,
|
|
69
|
-
transform: () => '←',
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @public
|
|
74
|
-
*/
|
|
75
|
-
export const rightArrowRule = defineTextTransformRule({
|
|
76
|
-
on: /->/,
|
|
77
|
-
transform: () => '→',
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @public
|
|
82
|
-
*/
|
|
83
|
-
export const copyrightRule = defineTextTransformRule({
|
|
84
|
-
on: /\(c\)/,
|
|
85
|
-
transform: () => '©',
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @public
|
|
90
|
-
*/
|
|
91
|
-
export const servicemarkRule = defineTextTransformRule({
|
|
92
|
-
on: /\(sm\)/,
|
|
93
|
-
transform: () => '℠',
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* @public
|
|
98
|
-
*/
|
|
99
|
-
export const trademarkRule = defineTextTransformRule({
|
|
100
|
-
on: /\(tm\)/,
|
|
101
|
-
transform: () => '™',
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* @beta
|
|
106
|
-
*/
|
|
107
|
-
export const registeredTrademarkRule = defineTextTransformRule({
|
|
108
|
-
on: /\(r\)/,
|
|
109
|
-
transform: () => '®',
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* @public
|
|
114
|
-
*/
|
|
115
|
-
export const oneHalfRule = defineTextTransformRule({
|
|
116
|
-
on: /(?:^|\s)(1\/2)\s/,
|
|
117
|
-
transform: () => '½',
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* @public
|
|
122
|
-
*/
|
|
123
|
-
export const plusMinusRule = defineTextTransformRule({
|
|
124
|
-
on: /\+\/-/,
|
|
125
|
-
transform: () => '±',
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* @public
|
|
130
|
-
*/
|
|
131
|
-
export const notEqualRule = defineTextTransformRule({
|
|
132
|
-
on: /!=/,
|
|
133
|
-
transform: () => '≠',
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* @public
|
|
138
|
-
*/
|
|
139
|
-
export const laquoRule = defineTextTransformRule({
|
|
140
|
-
on: /<</,
|
|
141
|
-
transform: () => '«',
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* @public
|
|
146
|
-
*/
|
|
147
|
-
export const raquoRule = defineTextTransformRule({
|
|
148
|
-
on: />>/,
|
|
149
|
-
transform: () => '»',
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* @public
|
|
154
|
-
*/
|
|
155
|
-
export const multiplicationRule = defineTextTransformRule({
|
|
156
|
-
on: /\d+\s?([*x])\s?\d+/,
|
|
157
|
-
transform: () => '×',
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* @public
|
|
162
|
-
*/
|
|
163
|
-
export const superscriptTwoRule = defineTextTransformRule({
|
|
164
|
-
on: /\^2/,
|
|
165
|
-
transform: () => '²',
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* @public
|
|
170
|
-
*/
|
|
171
|
-
export const superscriptThreeRule = defineTextTransformRule({
|
|
172
|
-
on: /\^3/,
|
|
173
|
-
transform: () => '³',
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* @public
|
|
178
|
-
*/
|
|
179
|
-
export const oneQuarterRule = defineTextTransformRule({
|
|
180
|
-
on: /(?:^|\s)(1\/4)\s/,
|
|
181
|
-
transform: () => '¼',
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* @public
|
|
186
|
-
*/
|
|
187
|
-
export const threeQuartersRule = defineTextTransformRule({
|
|
188
|
-
on: /(?:^|\s)(3\/4)\s/,
|
|
189
|
-
transform: () => '¾',
|
|
190
|
-
})
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
InputRulePlugin,
|
|
3
|
-
type InputRuleGuard,
|
|
4
|
-
} from '@portabletext/plugin-input-rule'
|
|
5
|
-
import {useMemo} from 'react'
|
|
6
|
-
import {
|
|
7
|
-
closingDoubleQuoteRule,
|
|
8
|
-
closingSingleQuoteRule,
|
|
9
|
-
copyrightRule,
|
|
10
|
-
ellipsisRule,
|
|
11
|
-
emDashRule,
|
|
12
|
-
laquoRule,
|
|
13
|
-
leftArrowRule,
|
|
14
|
-
multiplicationRule,
|
|
15
|
-
notEqualRule,
|
|
16
|
-
oneHalfRule,
|
|
17
|
-
oneQuarterRule,
|
|
18
|
-
openingDoubleQuoteRule,
|
|
19
|
-
openingSingleQuoteRule,
|
|
20
|
-
plusMinusRule,
|
|
21
|
-
raquoRule,
|
|
22
|
-
registeredTrademarkRule,
|
|
23
|
-
rightArrowRule,
|
|
24
|
-
servicemarkRule,
|
|
25
|
-
superscriptThreeRule,
|
|
26
|
-
superscriptTwoRule,
|
|
27
|
-
threeQuartersRule,
|
|
28
|
-
trademarkRule,
|
|
29
|
-
} from './input-rules.typography'
|
|
30
|
-
|
|
31
|
-
const defaultRuleConfig = [
|
|
32
|
-
{name: 'emDash', rule: emDashRule, state: 'on'},
|
|
33
|
-
{name: 'ellipsis', rule: ellipsisRule, state: 'on'},
|
|
34
|
-
{name: 'openingDoubleQuote', rule: openingDoubleQuoteRule, state: 'on'},
|
|
35
|
-
{name: 'closingDoubleQuote', rule: closingDoubleQuoteRule, state: 'on'},
|
|
36
|
-
{name: 'openingSingleQuote', rule: openingSingleQuoteRule, state: 'on'},
|
|
37
|
-
{name: 'closingSingleQuote', rule: closingSingleQuoteRule, state: 'on'},
|
|
38
|
-
{name: 'leftArrow', rule: leftArrowRule, state: 'on'},
|
|
39
|
-
{name: 'rightArrow', rule: rightArrowRule, state: 'on'},
|
|
40
|
-
{name: 'copyright', rule: copyrightRule, state: 'on'},
|
|
41
|
-
{name: 'trademark', rule: trademarkRule, state: 'on'},
|
|
42
|
-
{name: 'servicemark', rule: servicemarkRule, state: 'on'},
|
|
43
|
-
{name: 'registeredTrademark', rule: registeredTrademarkRule, state: 'on'},
|
|
44
|
-
{name: 'oneHalf', rule: oneHalfRule, state: 'off'},
|
|
45
|
-
{name: 'plusMinus', rule: plusMinusRule, state: 'off'},
|
|
46
|
-
{name: 'laquo', rule: laquoRule, state: 'off'},
|
|
47
|
-
{name: 'notEqual', rule: notEqualRule, state: 'off'},
|
|
48
|
-
{name: 'raquo', rule: raquoRule, state: 'off'},
|
|
49
|
-
{name: 'multiplication', rule: multiplicationRule, state: 'off'},
|
|
50
|
-
{name: 'superscriptTwo', rule: superscriptTwoRule, state: 'off'},
|
|
51
|
-
{name: 'superscriptThree', rule: superscriptThreeRule, state: 'off'},
|
|
52
|
-
{name: 'oneQuarter', rule: oneQuarterRule, state: 'off'},
|
|
53
|
-
{name: 'threeQuarters', rule: threeQuartersRule, state: 'off'},
|
|
54
|
-
] as const
|
|
55
|
-
|
|
56
|
-
type RuleName = (typeof defaultRuleConfig)[number]['name']
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* @public
|
|
60
|
-
*/
|
|
61
|
-
export type TypographyPluginProps<
|
|
62
|
-
TEnabledRuleName extends RuleName = never,
|
|
63
|
-
TDisabledRuleName extends Exclude<RuleName, TEnabledRuleName> = never,
|
|
64
|
-
> = {
|
|
65
|
-
guard?: InputRuleGuard
|
|
66
|
-
/**
|
|
67
|
-
* Preset configuration for rules.
|
|
68
|
-
* - `'default'`: Common typography rules enabled (em dash, ellipsis, quotes, arrows, copyright symbols)
|
|
69
|
-
* - `'all'`: All rules enabled
|
|
70
|
-
* - `'none'`: No rules enabled (use with `enable` prop)
|
|
71
|
-
*
|
|
72
|
-
* @defaultValue 'default'
|
|
73
|
-
*/
|
|
74
|
-
preset?: 'default' | 'all' | 'none'
|
|
75
|
-
/**
|
|
76
|
-
* Enable specific rules (additive to preset).
|
|
77
|
-
* Use this to enable additional rules beyond the preset.
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```tsx
|
|
81
|
-
* // Enable multiplication and plusMinus in addition to default rules
|
|
82
|
-
* <TypographyPlugin enable={['multiplication', 'plusMinus']} />
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
enable?: ReadonlyArray<TEnabledRuleName>
|
|
86
|
-
/**
|
|
87
|
-
* Disable specific rules (subtractive from preset).
|
|
88
|
-
* Use this to disable rules that would otherwise be enabled by the preset.
|
|
89
|
-
* Cannot contain rules that are in the `enable` array (TypeScript will enforce this).
|
|
90
|
-
*
|
|
91
|
-
* @example
|
|
92
|
-
* ```tsx
|
|
93
|
-
* // Disable em dash from the default rules
|
|
94
|
-
* <TypographyPlugin disable={['emDash']} />
|
|
95
|
-
* ```
|
|
96
|
-
*/
|
|
97
|
-
disable?: ReadonlyArray<TDisabledRuleName>
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @public
|
|
102
|
-
*/
|
|
103
|
-
export function TypographyPlugin<
|
|
104
|
-
TEnabledRuleName extends RuleName = never,
|
|
105
|
-
TDisabledRuleName extends Exclude<RuleName, TEnabledRuleName> = never,
|
|
106
|
-
>(props: TypographyPluginProps<TEnabledRuleName, TDisabledRuleName>) {
|
|
107
|
-
const {preset = 'default', enable = [], disable = [], guard} = props
|
|
108
|
-
|
|
109
|
-
const configuredInputRules = useMemo(() => {
|
|
110
|
-
// Determine which rules should be enabled based on preset
|
|
111
|
-
const enabledRules = new Set<RuleName>()
|
|
112
|
-
|
|
113
|
-
if (preset === 'all') {
|
|
114
|
-
// Enable all rules
|
|
115
|
-
for (const rule of defaultRuleConfig) {
|
|
116
|
-
enabledRules.add(rule.name)
|
|
117
|
-
}
|
|
118
|
-
} else if (preset === 'default') {
|
|
119
|
-
// Enable only default rules (state: 'on')
|
|
120
|
-
for (const rule of defaultRuleConfig) {
|
|
121
|
-
if (rule.state === 'on') {
|
|
122
|
-
enabledRules.add(rule.name)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
// preset === 'none' starts with empty set
|
|
127
|
-
|
|
128
|
-
// Apply enable list (additive)
|
|
129
|
-
for (const ruleName of enable) {
|
|
130
|
-
enabledRules.add(ruleName)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Apply disable list (subtractive)
|
|
134
|
-
for (const ruleName of disable) {
|
|
135
|
-
enabledRules.delete(ruleName)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Build final rule list
|
|
139
|
-
return defaultRuleConfig.flatMap((rule) =>
|
|
140
|
-
enabledRules.has(rule.name)
|
|
141
|
-
? [{...rule.rule, guard: guard ?? (() => true)}]
|
|
142
|
-
: [],
|
|
143
|
-
)
|
|
144
|
-
}, [preset, enable, disable, guard])
|
|
145
|
-
|
|
146
|
-
return <InputRulePlugin rules={configuredInputRules} />
|
|
147
|
-
}
|