Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"@sanity/diff-match-patch": "^3.2.0",
"@sanity/pkg-utils": "^10.2.1",
"@sanity/tsconfig": "^2.1.0",
"@textspec/notation": "^1.0.1",
"@textspec/notation": "^1.0.2",
"@types/debug": "^4.1.12",
"@types/node": "^20",
"@types/react": "^19.2.14",
Expand Down
211 changes: 165 additions & 46 deletions packages/plugin-typography/src/input-rule.smart-quotes.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,190 @@ Feature: Smart Quotes Input Rule
Given a global keymap

Scenario Outline: Typing turns double quotes into smart quotes
Given the text <text>
Given the editor state is <text>
When the editor is focused
And <inserted text> is typed
Then the text is <new text>
Then the editor state is <new text>

Examples:
| text | inserted text | new text |
| "" | "\"foo\"" | "“foo”" |
| "“foo”" | " \"bar\"" | "“foo” “bar”" |
| "" | "\"foo\" \"bar\"" | "“foo” “bar”" |
| text | inserted text | new text |
| "B: " | "\"foo\"" | "B: “foo”" |
| "B: “foo”" | " \"bar\"" | "B: “foo” “bar”" |
| "B: " | "\"foo\" \"bar\"" | "B: “foo” “bar”" |

Scenario Outline: Inserting double smart quotes in unformatted text
Given the text <text>
Scenario: Inserting double smart quotes - 1
Given the editor state is "B: "
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When <inserted text> is inserted
Then the text is <before undo>
When "\"" is inserted
Then the editor state is "B: “"
When undo is performed
Then the text is <after undo>
Then the editor state is
"""
B: \"
"""

Examples:
| text | inserted text | before undo | after undo |
| "" | "\"" | "“" | """ |
| "" | "\"\"" | "““" | """" |
| "" | "\"\"\"" | "“““" | """"" |
| "”" | "\"" | "””" | "”"" |
# | "”" | "\"\"" | "”””" | "””"" |
| "" | "\"foo\"" | "“foo”" | ""foo"" |
| "“foo" | "\"" | "“foo”" | "“foo"" |
| ""foo" | "\"" | ""foo”" | ""foo"" |
| ""foo"" | "\"bar\"" | ""foo"“bar”" | ""foo""bar"" |
| "“foo”" | "\"" | "“foo””" | "“foo”"" |

# | "“foo”" | "\"\"" | "“foo”””" | "“foo”""" |
Scenario Outline: Inserting single smart quotes in unformatted text
Given the text <text>
Scenario: Inserting double smart quotes - 2
Given the editor state is "B: "
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When <inserted text> is inserted
Then the text is <before undo>
When "\"\"" is inserted
Then the editor state is "B: ““"
When undo is performed
Then the text is <after undo>
Then the editor state is
"""
B: \"\"
"""

Examples:
| text | inserted text | before undo | after undo |
| "" | "'" | "‘" | "'" |
| "" | "'foo'" | "‘foo’" | "'foo'" |
| "‘foo" | "'" | "‘foo’" | "‘foo'" |
| "'foo" | "'" | "'foo’" | "'foo'" |
| "'foo'" | "'bar'" | "'foo'‘bar’" | "'foo''bar'" |
# Scenario: Inserting double smart quotes - 3 — skipped
# Inserting """ produces curly “““ via input rule, undo restores literal """.
# Cucumber-expressions {string} regex chokes on consecutive bare ", and
# gherkin docstring delivery silently strips repeated \" sequences.
# Cover this case once a custom textspec parameter type with a greedy matcher
# exists.
Scenario: Inserting double smart quotes - 4
Given the editor state is "B: ”"
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\"" is inserted
Then the editor state is "B: ””"
When undo is performed
Then the editor state is
"""
B: ”\"
"""

Scenario: Inserting double smart quotes - 5
Given the editor state is "B: "
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\"foo\"" is inserted
Then the editor state is "B: “foo”"
When undo is performed
Then the editor state is
"""
B: \"foo\"
"""

Scenario: Inserting double smart quotes - 6
Given the editor state is "B: “foo"
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\"" is inserted
Then the editor state is "B: “foo”"
When undo is performed
Then the editor state is
"""
B: “foo\"
"""

Scenario: Inserting double smart quotes - 7
Given the editor state is
"""
B: \"foo
"""
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\"" is inserted
Then the editor state is
"""
B: \"foo”
"""
When undo is performed
Then the editor state is
"""
B: \"foo\"
"""

Scenario: Inserting double smart quotes - 8
Given the editor state is
"""
B: \"foo\"
"""
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\"bar\"" is inserted
Then the editor state is
"""
B: \"foo\"“bar”
"""
When undo is performed
Then the editor state is
"""
B: \"foo\"\"bar\"
"""

Scenario: Inserting double smart quotes - 9
Given the editor state is "B: “foo”"
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\"" is inserted
Then the editor state is "B: “foo””"
When undo is performed
Then the editor state is
"""
B: “foo”\"
"""

Scenario: Inserting single smart quotes - 1
Given the editor state is "B: "
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\'" is inserted
Then the editor state is "B: ‘"
When undo is performed
Then the editor state is "B: '"

Scenario: Inserting single smart quotes - 2
Given the editor state is "B: "
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\'foo\'" is inserted
Then the editor state is "B: ‘foo’"
When undo is performed
Then the editor state is "B: 'foo'"

Scenario: Inserting single smart quotes - 3
Given the editor state is "B: ‘foo"
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\'" is inserted
Then the editor state is "B: ‘foo’"
When undo is performed
Then the editor state is "B: ‘foo'"

Scenario: Inserting single smart quotes - 4
Given the editor state is "B: 'foo"
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\'" is inserted
Then the editor state is "B: 'foo’"
When undo is performed
Then the editor state is "B: 'foo'"

Scenario: Inserting single smart quotes - 5
Given the editor state is "B: 'foo'"
# The "When {string} is inserted" step inserts all characters at once to
# mimic how insert.text behaves on Android
When "\'bar\'" is inserted
Then the editor state is "B: 'foo'‘bar’"
When undo is performed
Then the editor state is "B: 'foo''bar'"

Scenario: Mixed quotes
Given the text ""
Given the editor state is "B: "
When "\"'sorry' you say?\" she asked" is typed
Then the text is "“‘sorry’ you say?” she asked"
Then the editor state is "B: “‘sorry’ you say?” she asked"

Scenario Outline: Contractions
When the editor is focused
And <text> is typed
Then the text is <new text>
Then the editor state is <new text>

Examples:
| text | new text |
| "it's" | "it’s" |
| "don't" | "don’t" |
| "won't" | "won’t" |
| "I'm" | "I’m" |
| "you're" | "you’re" |
| text | new text |
| "it's" | "B: it’s" |
| "don't" | "B: don’t" |
| "won't" | "B: won’t" |
| "I'm" | "B: I’m" |
| "you're" | "B: you’re" |
Loading
Loading