@portabletext/plugin-typography 2.0.3 → 3.0.0
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/README.md +71 -8
- package/dist/index.d.ts +161 -98
- package/dist/index.js +40 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/create-decorator-guard.ts +16 -4
- package/src/disallow-in-code.feature +8 -5
- package/src/disallow-in-code.test.tsx +4 -4
- package/src/input-rule.multiplication.test.tsx +1 -1
- package/src/plugin.typography.tsx +89 -124
package/README.md
CHANGED
|
@@ -76,21 +76,84 @@ The plugin includes the following typographic transformation rules:
|
|
|
76
76
|
| `oneQuarter` | `1/4` → `¼` |
|
|
77
77
|
| `threeQuarters` | `3/4` → `¾` |
|
|
78
78
|
|
|
79
|
-
## Configuring
|
|
79
|
+
## Configuring Rules
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
The plugin supports flexible configuration through `preset`, `enable`, and `disable` props:
|
|
82
|
+
|
|
83
|
+
### Using Presets
|
|
84
|
+
|
|
85
|
+
The `preset` prop provides quick configuration:
|
|
86
|
+
|
|
87
|
+
- `'default'` (default): Common typography rules enabled
|
|
88
|
+
- `'all'`: Enable all rules
|
|
89
|
+
- `'none'`: Start with no rules (use with `enable`)
|
|
82
90
|
|
|
83
91
|
```tsx
|
|
84
|
-
|
|
92
|
+
// Use default rules (most common transformations)
|
|
93
|
+
<TypographyPlugin />
|
|
94
|
+
|
|
95
|
+
// Enable everything
|
|
96
|
+
<TypographyPlugin preset="all" />
|
|
97
|
+
|
|
98
|
+
// Start from scratch and enable only specific rules
|
|
99
|
+
<TypographyPlugin preset="none" enable={['emDash', 'ellipsis']} />
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Enabling Additional Rules
|
|
103
|
+
|
|
104
|
+
Use `enable` to add rules beyond the preset:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// Add multiplication and plusMinus to default rules
|
|
108
|
+
<TypographyPlugin enable={['multiplication', 'plusMinus']} />
|
|
109
|
+
|
|
110
|
+
// Enable all rules except a few
|
|
111
|
+
<TypographyPlugin preset="all" disable={['emDash', 'ellipsis']} />
|
|
85
112
|
```
|
|
86
113
|
|
|
87
|
-
|
|
114
|
+
### Disabling Rules
|
|
115
|
+
|
|
116
|
+
Use `disable` to remove rules from the preset:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
// Use defaults but disable quote transformations
|
|
120
|
+
<TypographyPlugin
|
|
121
|
+
disable={[
|
|
122
|
+
'openingDoubleQuote',
|
|
123
|
+
'closingDoubleQuote',
|
|
124
|
+
'openingSingleQuote',
|
|
125
|
+
'closingSingleQuote',
|
|
126
|
+
]}
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Combining Options
|
|
131
|
+
|
|
132
|
+
All three props work together. The order of operations is:
|
|
133
|
+
|
|
134
|
+
1. Start with `preset` (default: `'default'`)
|
|
135
|
+
2. Add rules from `enable`
|
|
136
|
+
3. Remove rules from `disable`
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// Start with all rules, then customize
|
|
140
|
+
<TypographyPlugin
|
|
141
|
+
preset="all"
|
|
142
|
+
disable={['multiplication']}
|
|
143
|
+
/>
|
|
144
|
+
|
|
145
|
+
// Start with none, enable only math symbols
|
|
146
|
+
<TypographyPlugin
|
|
147
|
+
preset="none"
|
|
148
|
+
enable={['multiplication', 'plusMinus', 'notEqual']}
|
|
149
|
+
/>
|
|
150
|
+
```
|
|
88
151
|
|
|
89
152
|
## Controlling when Text Transformations Run
|
|
90
153
|
|
|
91
154
|
The `TypographyPlugin` has an optional `guard` prop that accepts any type of `BehaviorGuard`. Here, you'll have access to the current `EditorSnapshot` as well as information about the current rule being matched.
|
|
92
155
|
|
|
93
|
-
Because disallowing text transformations inside code is a common use case, this plugin ships a built-in `createDecoratorGuard` function. use that to create a `guard` that
|
|
156
|
+
Because disallowing text transformations inside code is a common use case, this plugin ships a built-in `createDecoratorGuard` function. use that to create a `guard` that only allows text transformations inside certain decorators:
|
|
94
157
|
|
|
95
158
|
```tsx
|
|
96
159
|
import {
|
|
@@ -101,9 +164,9 @@ import {
|
|
|
101
164
|
return (
|
|
102
165
|
<TypographyPlugin
|
|
103
166
|
guard={createDecoratorGuard({
|
|
104
|
-
decorators: ({
|
|
105
|
-
schema.decorators.flatMap((decorator) =>
|
|
106
|
-
decorator.name === 'code' ? [
|
|
167
|
+
decorators: ({context}) =>
|
|
168
|
+
context.schema.decorators.flatMap((decorator) =>
|
|
169
|
+
decorator.name === 'code' ? [] : [decorator.name],
|
|
107
170
|
),
|
|
108
171
|
})}
|
|
109
172
|
/>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {EditorSchema} from '@portabletext/editor'
|
|
1
|
+
import type {EditorContext, EditorSchema} from '@portabletext/editor'
|
|
2
2
|
import {InputRule, InputRuleGuard} from '@portabletext/plugin-input-rule'
|
|
3
3
|
import {JSX} from 'react'
|
|
4
4
|
|
|
@@ -25,16 +25,133 @@ export declare const copyrightRule: InputRule<true>
|
|
|
25
25
|
* @example
|
|
26
26
|
* ```tsx
|
|
27
27
|
* const guard = createDecoratorGuard({
|
|
28
|
-
*
|
|
28
|
+
* decorators: ({context}) => context.schema.decorators.flatMap((decorator) => decorator.name === 'code' ? [] : [decorator.name]),
|
|
29
29
|
* })
|
|
30
30
|
*
|
|
31
31
|
* <TypographyPlugin guard={guard} />
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
export declare function createDecoratorGuard(config: {
|
|
35
|
-
decorators: ({
|
|
35
|
+
decorators: ({
|
|
36
|
+
context,
|
|
37
|
+
}: {
|
|
38
|
+
context: Pick<EditorContext, 'schema'>
|
|
39
|
+
}) => Array<EditorSchema['decorators'][number]['name']>
|
|
36
40
|
}): InputRuleGuard
|
|
37
41
|
|
|
42
|
+
declare const defaultRuleConfig: readonly [
|
|
43
|
+
{
|
|
44
|
+
readonly name: 'emDash'
|
|
45
|
+
readonly rule: InputRule<true>
|
|
46
|
+
readonly state: 'on'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
readonly name: 'ellipsis'
|
|
50
|
+
readonly rule: InputRule<true>
|
|
51
|
+
readonly state: 'on'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
readonly name: 'openingDoubleQuote'
|
|
55
|
+
readonly rule: InputRule<true>
|
|
56
|
+
readonly state: 'on'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
readonly name: 'closingDoubleQuote'
|
|
60
|
+
readonly rule: InputRule<true>
|
|
61
|
+
readonly state: 'on'
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
readonly name: 'openingSingleQuote'
|
|
65
|
+
readonly rule: InputRule<true>
|
|
66
|
+
readonly state: 'on'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
readonly name: 'closingSingleQuote'
|
|
70
|
+
readonly rule: InputRule<true>
|
|
71
|
+
readonly state: 'on'
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
readonly name: 'leftArrow'
|
|
75
|
+
readonly rule: InputRule<true>
|
|
76
|
+
readonly state: 'on'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
readonly name: 'rightArrow'
|
|
80
|
+
readonly rule: InputRule<true>
|
|
81
|
+
readonly state: 'on'
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
readonly name: 'copyright'
|
|
85
|
+
readonly rule: InputRule<true>
|
|
86
|
+
readonly state: 'on'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
readonly name: 'trademark'
|
|
90
|
+
readonly rule: InputRule<true>
|
|
91
|
+
readonly state: 'on'
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
readonly name: 'servicemark'
|
|
95
|
+
readonly rule: InputRule<true>
|
|
96
|
+
readonly state: 'on'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
readonly name: 'registeredTrademark'
|
|
100
|
+
readonly rule: InputRule<true>
|
|
101
|
+
readonly state: 'on'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
readonly name: 'oneHalf'
|
|
105
|
+
readonly rule: InputRule<true>
|
|
106
|
+
readonly state: 'off'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
readonly name: 'plusMinus'
|
|
110
|
+
readonly rule: InputRule<true>
|
|
111
|
+
readonly state: 'off'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
readonly name: 'laquo'
|
|
115
|
+
readonly rule: InputRule<true>
|
|
116
|
+
readonly state: 'off'
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
readonly name: 'notEqual'
|
|
120
|
+
readonly rule: InputRule<true>
|
|
121
|
+
readonly state: 'off'
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
readonly name: 'raquo'
|
|
125
|
+
readonly rule: InputRule<true>
|
|
126
|
+
readonly state: 'off'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
readonly name: 'multiplication'
|
|
130
|
+
readonly rule: InputRule<true>
|
|
131
|
+
readonly state: 'off'
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
readonly name: 'superscriptTwo'
|
|
135
|
+
readonly rule: InputRule<true>
|
|
136
|
+
readonly state: 'off'
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
readonly name: 'superscriptThree'
|
|
140
|
+
readonly rule: InputRule<true>
|
|
141
|
+
readonly state: 'off'
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
readonly name: 'oneQuarter'
|
|
145
|
+
readonly rule: InputRule<true>
|
|
146
|
+
readonly state: 'off'
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
readonly name: 'threeQuarters'
|
|
150
|
+
readonly rule: InputRule<true>
|
|
151
|
+
readonly state: 'off'
|
|
152
|
+
},
|
|
153
|
+
]
|
|
154
|
+
|
|
38
155
|
/**
|
|
39
156
|
* @public
|
|
40
157
|
*/
|
|
@@ -105,6 +222,8 @@ export declare const registeredTrademarkRule: InputRule<true>
|
|
|
105
222
|
*/
|
|
106
223
|
export declare const rightArrowRule: InputRule<true>
|
|
107
224
|
|
|
225
|
+
declare type RuleName = (typeof defaultRuleConfig)[number]['name']
|
|
226
|
+
|
|
108
227
|
/**
|
|
109
228
|
* @public
|
|
110
229
|
*/
|
|
@@ -138,109 +257,53 @@ export declare const trademarkRule: InputRule<true>
|
|
|
138
257
|
/**
|
|
139
258
|
* @public
|
|
140
259
|
*/
|
|
141
|
-
export declare function TypographyPlugin
|
|
142
|
-
|
|
260
|
+
export declare function TypographyPlugin<
|
|
261
|
+
TEnabledRuleName extends RuleName = never,
|
|
262
|
+
TDisabledRuleName extends Exclude<RuleName, TEnabledRuleName> = never,
|
|
263
|
+
>(
|
|
264
|
+
props: TypographyPluginProps<TEnabledRuleName, TDisabledRuleName>,
|
|
143
265
|
): JSX.Element
|
|
144
266
|
|
|
145
267
|
/**
|
|
146
268
|
* @public
|
|
147
269
|
*/
|
|
148
|
-
export declare type TypographyPluginProps
|
|
270
|
+
export declare type TypographyPluginProps<
|
|
271
|
+
TEnabledRuleName extends RuleName = never,
|
|
272
|
+
TDisabledRuleName extends Exclude<RuleName, TEnabledRuleName> = never,
|
|
273
|
+
> = {
|
|
149
274
|
guard?: InputRuleGuard
|
|
150
275
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
276
|
+
* Preset configuration for rules.
|
|
277
|
+
* - `'default'`: Common typography rules enabled (em dash, ellipsis, quotes, arrows, copyright symbols)
|
|
278
|
+
* - `'all'`: All rules enabled
|
|
279
|
+
* - `'none'`: No rules enabled (use with `enable` prop)
|
|
280
|
+
*
|
|
281
|
+
* @defaultValue 'default'
|
|
282
|
+
*/
|
|
283
|
+
preset?: 'default' | 'all' | 'none'
|
|
284
|
+
/**
|
|
285
|
+
* Enable specific rules (additive to preset).
|
|
286
|
+
* Use this to enable additional rules beyond the preset.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```tsx
|
|
290
|
+
* // Enable multiplication and plusMinus in addition to default rules
|
|
291
|
+
* <TypographyPlugin enable={['multiplication', 'plusMinus']} />
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
enable?: ReadonlyArray<TEnabledRuleName>
|
|
295
|
+
/**
|
|
296
|
+
* Disable specific rules (subtractive from preset).
|
|
297
|
+
* Use this to disable rules that would otherwise be enabled by the preset.
|
|
298
|
+
* Cannot contain rules that are in the `enable` array (TypeScript will enforce this).
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```tsx
|
|
302
|
+
* // Disable em dash from the default rules
|
|
303
|
+
* <TypographyPlugin disable={['emDash']} />
|
|
304
|
+
* ```
|
|
153
305
|
*/
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* @defaultValue 'on'
|
|
157
|
-
*/
|
|
158
|
-
emDash?: 'on' | 'off'
|
|
159
|
-
/**
|
|
160
|
-
* @defaultValue 'on'
|
|
161
|
-
*/
|
|
162
|
-
ellipsis?: 'on' | 'off'
|
|
163
|
-
/**
|
|
164
|
-
* @defaultValue 'on'
|
|
165
|
-
*/
|
|
166
|
-
openingDoubleQuote?: 'on' | 'off'
|
|
167
|
-
/**
|
|
168
|
-
* @defaultValue 'on'
|
|
169
|
-
*/
|
|
170
|
-
closingDoubleQuote?: 'on' | 'off'
|
|
171
|
-
/**
|
|
172
|
-
* @defaultValue 'on'
|
|
173
|
-
*/
|
|
174
|
-
openingSingleQuote?: 'on' | 'off'
|
|
175
|
-
/**
|
|
176
|
-
* @defaultValue 'on'
|
|
177
|
-
*/
|
|
178
|
-
closingSingleQuote?: 'on' | 'off'
|
|
179
|
-
/**
|
|
180
|
-
* @defaultValue 'on'
|
|
181
|
-
*/
|
|
182
|
-
leftArrow?: 'on' | 'off'
|
|
183
|
-
/**
|
|
184
|
-
* @defaultValue 'on'
|
|
185
|
-
*/
|
|
186
|
-
rightArrow?: 'on' | 'off'
|
|
187
|
-
/**
|
|
188
|
-
* @defaultValue 'on'
|
|
189
|
-
*/
|
|
190
|
-
copyright?: 'on' | 'off'
|
|
191
|
-
/**
|
|
192
|
-
* @defaultValue 'on'
|
|
193
|
-
*/
|
|
194
|
-
trademark?: 'on' | 'off'
|
|
195
|
-
/**
|
|
196
|
-
* @defaultValue 'on'
|
|
197
|
-
*/
|
|
198
|
-
servicemark?: 'on' | 'off'
|
|
199
|
-
/**
|
|
200
|
-
* @defaultValue 'on'
|
|
201
|
-
*/
|
|
202
|
-
registeredTrademark?: 'on' | 'off'
|
|
203
|
-
/**
|
|
204
|
-
* @defaultValue 'off'
|
|
205
|
-
*/
|
|
206
|
-
oneHalf?: 'on' | 'off'
|
|
207
|
-
/**
|
|
208
|
-
* @defaultValue 'off'
|
|
209
|
-
*/
|
|
210
|
-
plusMinus?: 'on' | 'off'
|
|
211
|
-
/**
|
|
212
|
-
* @defaultValue 'off'
|
|
213
|
-
*/
|
|
214
|
-
notEqual?: 'on' | 'off'
|
|
215
|
-
/**
|
|
216
|
-
* @defaultValue 'off'
|
|
217
|
-
*/
|
|
218
|
-
laquo?: 'on' | 'off'
|
|
219
|
-
/**
|
|
220
|
-
* @defaultValue 'off'
|
|
221
|
-
*/
|
|
222
|
-
raquo?: 'on' | 'off'
|
|
223
|
-
/**
|
|
224
|
-
* @defaultValue 'off'
|
|
225
|
-
*/
|
|
226
|
-
multiplication?: 'on' | 'off'
|
|
227
|
-
/**
|
|
228
|
-
* @defaultValue 'off'
|
|
229
|
-
*/
|
|
230
|
-
superscriptTwo?: 'on' | 'off'
|
|
231
|
-
/**
|
|
232
|
-
* @defaultValue 'off'
|
|
233
|
-
*/
|
|
234
|
-
superscriptThree?: 'on' | 'off'
|
|
235
|
-
/**
|
|
236
|
-
* @defaultValue 'off'
|
|
237
|
-
*/
|
|
238
|
-
oneQuarter?: 'on' | 'off'
|
|
239
|
-
/**
|
|
240
|
-
* @defaultValue 'off'
|
|
241
|
-
*/
|
|
242
|
-
threeQuarters?: 'on' | 'off'
|
|
243
|
-
}
|
|
306
|
+
disable?: ReadonlyArray<TDisabledRuleName>
|
|
244
307
|
}
|
|
245
308
|
|
|
246
309
|
export {}
|
package/dist/index.js
CHANGED
|
@@ -7,9 +7,11 @@ function createDecoratorGuard(config) {
|
|
|
7
7
|
snapshot,
|
|
8
8
|
event
|
|
9
9
|
}) => {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const allowedDecorators = config.decorators({
|
|
11
|
+
context: {
|
|
12
|
+
schema: snapshot.context.schema
|
|
13
|
+
}
|
|
14
|
+
}), decorators = snapshot.context.schema.decorators.flatMap((decorator) => allowedDecorators.includes(decorator.name) ? [] : [decorator.name]);
|
|
13
15
|
if (decorators.length === 0)
|
|
14
16
|
return !0;
|
|
15
17
|
const matchedSpans = event.matches.flatMap((match) => getSelectedSpans({
|
|
@@ -189,21 +191,41 @@ const emDashRule = defineTextTransformRule({
|
|
|
189
191
|
state: "off"
|
|
190
192
|
}];
|
|
191
193
|
function TypographyPlugin(props) {
|
|
192
|
-
const $ = c(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
guard
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
194
|
+
const $ = c(13), {
|
|
195
|
+
preset: t0,
|
|
196
|
+
enable: t1,
|
|
197
|
+
disable: t2,
|
|
198
|
+
guard
|
|
199
|
+
} = props, preset = t0 === void 0 ? "default" : t0;
|
|
200
|
+
let t3;
|
|
201
|
+
$[0] !== t1 ? (t3 = t1 === void 0 ? [] : t1, $[0] = t1, $[1] = t3) : t3 = $[1];
|
|
202
|
+
const enable = t3;
|
|
203
|
+
let t4;
|
|
204
|
+
$[2] !== t2 ? (t4 = t2 === void 0 ? [] : t2, $[2] = t2, $[3] = t4) : t4 = $[3];
|
|
205
|
+
const disable = t4;
|
|
206
|
+
let enabledRules;
|
|
207
|
+
if ($[4] !== disable || $[5] !== enable || $[6] !== preset) {
|
|
208
|
+
if (enabledRules = /* @__PURE__ */ new Set(), preset === "all")
|
|
209
|
+
for (const rule of defaultRuleConfig)
|
|
210
|
+
enabledRules.add(rule.name);
|
|
211
|
+
else if (preset === "default")
|
|
212
|
+
for (const rule_0 of defaultRuleConfig)
|
|
213
|
+
rule_0.state === "on" && enabledRules.add(rule_0.name);
|
|
214
|
+
for (const ruleName of enable)
|
|
215
|
+
enabledRules.add(ruleName);
|
|
216
|
+
for (const ruleName_0 of disable)
|
|
217
|
+
enabledRules.delete(ruleName_0);
|
|
218
|
+
$[4] = disable, $[5] = enable, $[6] = preset, $[7] = enabledRules;
|
|
219
|
+
} else
|
|
220
|
+
enabledRules = $[7];
|
|
221
|
+
let t5;
|
|
222
|
+
$[8] !== enabledRules || $[9] !== guard ? (t5 = defaultRuleConfig.flatMap((rule_1) => enabledRules.has(rule_1.name) ? [{
|
|
223
|
+
...rule_1.rule,
|
|
224
|
+
guard: guard ?? _temp
|
|
225
|
+
}] : []), $[8] = enabledRules, $[9] = guard, $[10] = t5) : t5 = $[10];
|
|
226
|
+
const configuredInputRules = t5;
|
|
227
|
+
let t6;
|
|
228
|
+
return $[11] !== configuredInputRules ? (t6 = /* @__PURE__ */ jsx(InputRulePlugin, { rules: configuredInputRules }), $[11] = configuredInputRules, $[12] = t6) : t6 = $[12], t6;
|
|
207
229
|
}
|
|
208
230
|
function _temp() {
|
|
209
231
|
return !0;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/create-decorator-guard.ts","../src/input-rules.typography.ts","../src/plugin.typography.tsx"],"sourcesContent":["import type {EditorSchema} from '@portabletext/editor'\nimport {\n getSelectedSpans,\n isActiveDecorator,\n} from '@portabletext/editor/selectors'\nimport type {InputRuleGuard} from '@portabletext/plugin-input-rule'\n\n/**\n * @public\n * Create an `InputRuleGuard` that can prevent the rule from running inside\n * certain decorators.\n *\n * @example\n * ```tsx\n * const guard = createDecoratorGuard({\n * decorators: ({schema}) => schema.decorators.flatMap((decorator) => decorator.name === 'code' ? [decorator.name] : []),\n * })\n *\n * <TypographyPlugin guard={guard} />\n * ```\n */\nexport function createDecoratorGuard(config: {\n decorators: ({schema}: {schema: EditorSchema}) => Array<string>\n}): InputRuleGuard {\n return ({snapshot, event}) => {\n const decorators = config.decorators({schema: snapshot.context.schema})\n\n if (decorators.length === 0) {\n return true\n }\n\n const matchedSpans = event.matches.flatMap((match) =>\n getSelectedSpans({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: match.selection,\n },\n }),\n )\n\n let preventInputRule = false\n\n for (const decorator of decorators) {\n if (isActiveDecorator(decorator)(snapshot)) {\n preventInputRule = true\n break\n }\n\n if (matchedSpans.some((span) => span.node.marks?.includes(decorator))) {\n preventInputRule = true\n break\n }\n }\n\n return !preventInputRule\n }\n}\n","import {\n defineTextTransformRule,\n type InputRule,\n} from '@portabletext/plugin-input-rule'\n\n/**\n * @public\n */\nexport const emDashRule = defineTextTransformRule({\n on: /--/,\n transform: () => '—',\n})\n\n/**\n * @public\n */\nexport const ellipsisRule = defineTextTransformRule({\n on: /\\.\\.\\./,\n transform: () => '…',\n})\n\n/**\n * @public\n */\nexport const openingDoubleQuoteRule = defineTextTransformRule({\n on: /(?:^|(?<=[\\s{[(<'\"\\u2018\\u201C]))\"/g,\n transform: () => '“',\n})\n\n/**\n * @public\n */\nexport const closingDoubleQuoteRule = defineTextTransformRule({\n on: /\"/g,\n transform: () => '”',\n})\n\n/**\n * @public\n */\nexport const openingSingleQuoteRule = defineTextTransformRule({\n on: /(?:^|(?<=[\\s{[(<'\"\\u2018\\u201C]))'/g,\n transform: () => '‘',\n})\n\n/**\n * @public\n */\nexport const closingSingleQuoteRule = defineTextTransformRule({\n on: /'/g,\n transform: () => '’',\n})\n\n/**\n * @public\n */\nexport const smartQuotesRules: Array<InputRule> = [\n openingDoubleQuoteRule,\n closingDoubleQuoteRule,\n openingSingleQuoteRule,\n closingSingleQuoteRule,\n]\n\n/**\n * @public\n */\nexport const leftArrowRule = defineTextTransformRule({\n on: /<-/,\n transform: () => '←',\n})\n\n/**\n * @public\n */\nexport const rightArrowRule = defineTextTransformRule({\n on: /->/,\n transform: () => '→',\n})\n\n/**\n * @public\n */\nexport const copyrightRule = defineTextTransformRule({\n on: /\\(c\\)/,\n transform: () => '©',\n})\n\n/**\n * @public\n */\nexport const servicemarkRule = defineTextTransformRule({\n on: /\\(sm\\)/,\n transform: () => '℠',\n})\n\n/**\n * @public\n */\nexport const trademarkRule = defineTextTransformRule({\n on: /\\(tm\\)/,\n transform: () => '™',\n})\n\n/**\n * @beta\n */\nexport const registeredTrademarkRule = defineTextTransformRule({\n on: /\\(r\\)/,\n transform: () => '®',\n})\n\n/**\n * @public\n */\nexport const oneHalfRule = defineTextTransformRule({\n on: /(?:^|\\s)(1\\/2)\\s/,\n transform: () => '½',\n})\n\n/**\n * @public\n */\nexport const plusMinusRule = defineTextTransformRule({\n on: /\\+\\/-/,\n transform: () => '±',\n})\n\n/**\n * @public\n */\nexport const notEqualRule = defineTextTransformRule({\n on: /!=/,\n transform: () => '≠',\n})\n\n/**\n * @public\n */\nexport const laquoRule = defineTextTransformRule({\n on: /<</,\n transform: () => '«',\n})\n\n/**\n * @public\n */\nexport const raquoRule = defineTextTransformRule({\n on: />>/,\n transform: () => '»',\n})\n\n/**\n * @public\n */\nexport const multiplicationRule = defineTextTransformRule({\n on: /\\d+\\s?([*x])\\s?\\d+/,\n transform: () => '×',\n})\n\n/**\n * @public\n */\nexport const superscriptTwoRule = defineTextTransformRule({\n on: /\\^2/,\n transform: () => '²',\n})\n\n/**\n * @public\n */\nexport const superscriptThreeRule = defineTextTransformRule({\n on: /\\^3/,\n transform: () => '³',\n})\n\n/**\n * @public\n */\nexport const oneQuarterRule = defineTextTransformRule({\n on: /(?:^|\\s)(1\\/4)\\s/,\n transform: () => '¼',\n})\n\n/**\n * @public\n */\nexport const threeQuartersRule = defineTextTransformRule({\n on: /(?:^|\\s)(3\\/4)\\s/,\n transform: () => '¾',\n})\n","import {\n InputRulePlugin,\n type InputRule,\n type InputRuleGuard,\n} from '@portabletext/plugin-input-rule'\nimport {useMemo} from 'react'\nimport {\n closingDoubleQuoteRule,\n closingSingleQuoteRule,\n copyrightRule,\n ellipsisRule,\n emDashRule,\n laquoRule,\n leftArrowRule,\n multiplicationRule,\n notEqualRule,\n oneHalfRule,\n oneQuarterRule,\n openingDoubleQuoteRule,\n openingSingleQuoteRule,\n plusMinusRule,\n raquoRule,\n registeredTrademarkRule,\n rightArrowRule,\n servicemarkRule,\n superscriptThreeRule,\n superscriptTwoRule,\n threeQuartersRule,\n trademarkRule,\n} from './input-rules.typography'\n\n/**\n * @public\n */\nexport type TypographyPluginProps = {\n guard?: InputRuleGuard\n /**\n * Configure which rules to enable or disable. Ordinary rules like `emDash` and `ellipsis` are enabled by default.\n * Less common rules like `multiplication` are disabled by default.\n */\n rules?: {\n /**\n * @defaultValue 'on'\n */\n emDash?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n ellipsis?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n openingDoubleQuote?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n closingDoubleQuote?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n openingSingleQuote?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n closingSingleQuote?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n leftArrow?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n rightArrow?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n copyright?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n trademark?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n servicemark?: 'on' | 'off'\n /**\n * @defaultValue 'on'\n */\n registeredTrademark?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n oneHalf?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n plusMinus?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n notEqual?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n laquo?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n raquo?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n multiplication?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n superscriptTwo?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n superscriptThree?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n oneQuarter?: 'on' | 'off'\n /**\n * @defaultValue 'off'\n */\n threeQuarters?: 'on' | 'off'\n }\n}\n\ntype RuleName = keyof NonNullable<TypographyPluginProps['rules']>\n\nconst defaultRuleConfig: Array<{\n name: RuleName\n rule: InputRule\n state: 'on' | 'off'\n}> = [\n {name: 'emDash', rule: emDashRule, state: 'on'},\n {name: 'ellipsis', rule: ellipsisRule, state: 'on'},\n {name: 'openingDoubleQuote', rule: openingDoubleQuoteRule, state: 'on'},\n {name: 'closingDoubleQuote', rule: closingDoubleQuoteRule, state: 'on'},\n {name: 'openingSingleQuote', rule: openingSingleQuoteRule, state: 'on'},\n {name: 'closingSingleQuote', rule: closingSingleQuoteRule, state: 'on'},\n {name: 'leftArrow', rule: leftArrowRule, state: 'on'},\n {name: 'rightArrow', rule: rightArrowRule, state: 'on'},\n {name: 'copyright', rule: copyrightRule, state: 'on'},\n {name: 'trademark', rule: trademarkRule, state: 'on'},\n {name: 'servicemark', rule: servicemarkRule, state: 'on'},\n {name: 'registeredTrademark', rule: registeredTrademarkRule, state: 'on'},\n {name: 'oneHalf', rule: oneHalfRule, state: 'off'},\n {name: 'plusMinus', rule: plusMinusRule, state: 'off'},\n {name: 'laquo', rule: laquoRule, state: 'off'},\n {name: 'notEqual', rule: notEqualRule, state: 'off'},\n {name: 'raquo', rule: raquoRule, state: 'off'},\n {name: 'multiplication', rule: multiplicationRule, state: 'off'},\n {name: 'superscriptTwo', rule: superscriptTwoRule, state: 'off'},\n {name: 'superscriptThree', rule: superscriptThreeRule, state: 'off'},\n {name: 'oneQuarter', rule: oneQuarterRule, state: 'off'},\n {name: 'threeQuarters', rule: threeQuartersRule, state: 'off'},\n]\n\n/**\n * @public\n */\nexport function TypographyPlugin(props: TypographyPluginProps) {\n const configuredInputRules = useMemo(\n () =>\n defaultRuleConfig.flatMap((rule) =>\n props.rules && props.rules[rule.name] === 'on'\n ? {...rule.rule, guard: props.guard ?? (() => true)}\n : (props.rules && props.rules[rule.name] === 'off') ||\n rule.state === 'off'\n ? []\n : {...rule.rule, guard: props.guard ?? (() => true)},\n ),\n [props.guard, props.rules],\n )\n\n return <InputRulePlugin {...props} rules={configuredInputRules} />\n}\n"],"names":["createDecoratorGuard","config","snapshot","event","decorators","schema","context","length","matchedSpans","matches","flatMap","match","getSelectedSpans","selection","preventInputRule","decorator","isActiveDecorator","some","span","node","marks","includes","emDashRule","defineTextTransformRule","on","transform","ellipsisRule","openingDoubleQuoteRule","closingDoubleQuoteRule","openingSingleQuoteRule","closingSingleQuoteRule","smartQuotesRules","leftArrowRule","rightArrowRule","copyrightRule","servicemarkRule","trademarkRule","registeredTrademarkRule","oneHalfRule","plusMinusRule","notEqualRule","laquoRule","raquoRule","multiplicationRule","superscriptTwoRule","superscriptThreeRule","oneQuarterRule","threeQuartersRule","defaultRuleConfig","name","rule","state","TypographyPlugin","props","$","_c","t0","guard","rules","_temp","_temp2","configuredInputRules","t1"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/create-decorator-guard.ts","../src/input-rules.typography.ts","../src/plugin.typography.tsx"],"sourcesContent":["import type {EditorContext, EditorSchema} from '@portabletext/editor'\nimport {\n getSelectedSpans,\n isActiveDecorator,\n} from '@portabletext/editor/selectors'\nimport type {InputRuleGuard} from '@portabletext/plugin-input-rule'\n\n/**\n * @public\n * Create an `InputRuleGuard` that can prevent the rule from running inside\n * certain decorators.\n *\n * @example\n * ```tsx\n * const guard = createDecoratorGuard({\n * decorators: ({context}) => context.schema.decorators.flatMap((decorator) => decorator.name === 'code' ? [] : [decorator.name]),\n * })\n *\n * <TypographyPlugin guard={guard} />\n * ```\n */\nexport function createDecoratorGuard(config: {\n decorators: ({\n context,\n }: {\n context: Pick<EditorContext, 'schema'>\n }) => Array<EditorSchema['decorators'][number]['name']>\n}): InputRuleGuard {\n return ({snapshot, event}) => {\n const allowedDecorators = config.decorators({\n context: {\n schema: snapshot.context.schema,\n },\n })\n const decorators = snapshot.context.schema.decorators.flatMap(\n (decorator) =>\n allowedDecorators.includes(decorator.name) ? [] : [decorator.name],\n )\n\n if (decorators.length === 0) {\n return true\n }\n\n const matchedSpans = event.matches.flatMap((match) =>\n getSelectedSpans({\n ...snapshot,\n context: {\n ...snapshot.context,\n selection: match.selection,\n },\n }),\n )\n\n let preventInputRule = false\n\n for (const decorator of decorators) {\n if (isActiveDecorator(decorator)(snapshot)) {\n preventInputRule = true\n break\n }\n\n if (matchedSpans.some((span) => span.node.marks?.includes(decorator))) {\n preventInputRule = true\n break\n }\n }\n\n return !preventInputRule\n }\n}\n","import {\n defineTextTransformRule,\n type InputRule,\n} from '@portabletext/plugin-input-rule'\n\n/**\n * @public\n */\nexport const emDashRule = defineTextTransformRule({\n on: /--/,\n transform: () => '—',\n})\n\n/**\n * @public\n */\nexport const ellipsisRule = defineTextTransformRule({\n on: /\\.\\.\\./,\n transform: () => '…',\n})\n\n/**\n * @public\n */\nexport const openingDoubleQuoteRule = defineTextTransformRule({\n on: /(?:^|(?<=[\\s{[(<'\"\\u2018\\u201C]))\"/g,\n transform: () => '“',\n})\n\n/**\n * @public\n */\nexport const closingDoubleQuoteRule = defineTextTransformRule({\n on: /\"/g,\n transform: () => '”',\n})\n\n/**\n * @public\n */\nexport const openingSingleQuoteRule = defineTextTransformRule({\n on: /(?:^|(?<=[\\s{[(<'\"\\u2018\\u201C]))'/g,\n transform: () => '‘',\n})\n\n/**\n * @public\n */\nexport const closingSingleQuoteRule = defineTextTransformRule({\n on: /'/g,\n transform: () => '’',\n})\n\n/**\n * @public\n */\nexport const smartQuotesRules: Array<InputRule> = [\n openingDoubleQuoteRule,\n closingDoubleQuoteRule,\n openingSingleQuoteRule,\n closingSingleQuoteRule,\n]\n\n/**\n * @public\n */\nexport const leftArrowRule = defineTextTransformRule({\n on: /<-/,\n transform: () => '←',\n})\n\n/**\n * @public\n */\nexport const rightArrowRule = defineTextTransformRule({\n on: /->/,\n transform: () => '→',\n})\n\n/**\n * @public\n */\nexport const copyrightRule = defineTextTransformRule({\n on: /\\(c\\)/,\n transform: () => '©',\n})\n\n/**\n * @public\n */\nexport const servicemarkRule = defineTextTransformRule({\n on: /\\(sm\\)/,\n transform: () => '℠',\n})\n\n/**\n * @public\n */\nexport const trademarkRule = defineTextTransformRule({\n on: /\\(tm\\)/,\n transform: () => '™',\n})\n\n/**\n * @beta\n */\nexport const registeredTrademarkRule = defineTextTransformRule({\n on: /\\(r\\)/,\n transform: () => '®',\n})\n\n/**\n * @public\n */\nexport const oneHalfRule = defineTextTransformRule({\n on: /(?:^|\\s)(1\\/2)\\s/,\n transform: () => '½',\n})\n\n/**\n * @public\n */\nexport const plusMinusRule = defineTextTransformRule({\n on: /\\+\\/-/,\n transform: () => '±',\n})\n\n/**\n * @public\n */\nexport const notEqualRule = defineTextTransformRule({\n on: /!=/,\n transform: () => '≠',\n})\n\n/**\n * @public\n */\nexport const laquoRule = defineTextTransformRule({\n on: /<</,\n transform: () => '«',\n})\n\n/**\n * @public\n */\nexport const raquoRule = defineTextTransformRule({\n on: />>/,\n transform: () => '»',\n})\n\n/**\n * @public\n */\nexport const multiplicationRule = defineTextTransformRule({\n on: /\\d+\\s?([*x])\\s?\\d+/,\n transform: () => '×',\n})\n\n/**\n * @public\n */\nexport const superscriptTwoRule = defineTextTransformRule({\n on: /\\^2/,\n transform: () => '²',\n})\n\n/**\n * @public\n */\nexport const superscriptThreeRule = defineTextTransformRule({\n on: /\\^3/,\n transform: () => '³',\n})\n\n/**\n * @public\n */\nexport const oneQuarterRule = defineTextTransformRule({\n on: /(?:^|\\s)(1\\/4)\\s/,\n transform: () => '¼',\n})\n\n/**\n * @public\n */\nexport const threeQuartersRule = defineTextTransformRule({\n on: /(?:^|\\s)(3\\/4)\\s/,\n transform: () => '¾',\n})\n","import {\n InputRulePlugin,\n type InputRuleGuard,\n} from '@portabletext/plugin-input-rule'\nimport {useMemo} from 'react'\nimport {\n closingDoubleQuoteRule,\n closingSingleQuoteRule,\n copyrightRule,\n ellipsisRule,\n emDashRule,\n laquoRule,\n leftArrowRule,\n multiplicationRule,\n notEqualRule,\n oneHalfRule,\n oneQuarterRule,\n openingDoubleQuoteRule,\n openingSingleQuoteRule,\n plusMinusRule,\n raquoRule,\n registeredTrademarkRule,\n rightArrowRule,\n servicemarkRule,\n superscriptThreeRule,\n superscriptTwoRule,\n threeQuartersRule,\n trademarkRule,\n} from './input-rules.typography'\n\nconst defaultRuleConfig = [\n {name: 'emDash', rule: emDashRule, state: 'on'},\n {name: 'ellipsis', rule: ellipsisRule, state: 'on'},\n {name: 'openingDoubleQuote', rule: openingDoubleQuoteRule, state: 'on'},\n {name: 'closingDoubleQuote', rule: closingDoubleQuoteRule, state: 'on'},\n {name: 'openingSingleQuote', rule: openingSingleQuoteRule, state: 'on'},\n {name: 'closingSingleQuote', rule: closingSingleQuoteRule, state: 'on'},\n {name: 'leftArrow', rule: leftArrowRule, state: 'on'},\n {name: 'rightArrow', rule: rightArrowRule, state: 'on'},\n {name: 'copyright', rule: copyrightRule, state: 'on'},\n {name: 'trademark', rule: trademarkRule, state: 'on'},\n {name: 'servicemark', rule: servicemarkRule, state: 'on'},\n {name: 'registeredTrademark', rule: registeredTrademarkRule, state: 'on'},\n {name: 'oneHalf', rule: oneHalfRule, state: 'off'},\n {name: 'plusMinus', rule: plusMinusRule, state: 'off'},\n {name: 'laquo', rule: laquoRule, state: 'off'},\n {name: 'notEqual', rule: notEqualRule, state: 'off'},\n {name: 'raquo', rule: raquoRule, state: 'off'},\n {name: 'multiplication', rule: multiplicationRule, state: 'off'},\n {name: 'superscriptTwo', rule: superscriptTwoRule, state: 'off'},\n {name: 'superscriptThree', rule: superscriptThreeRule, state: 'off'},\n {name: 'oneQuarter', rule: oneQuarterRule, state: 'off'},\n {name: 'threeQuarters', rule: threeQuartersRule, state: 'off'},\n] as const\n\ntype RuleName = (typeof defaultRuleConfig)[number]['name']\n\n/**\n * @public\n */\nexport type TypographyPluginProps<\n TEnabledRuleName extends RuleName = never,\n TDisabledRuleName extends Exclude<RuleName, TEnabledRuleName> = never,\n> = {\n guard?: InputRuleGuard\n /**\n * Preset configuration for rules.\n * - `'default'`: Common typography rules enabled (em dash, ellipsis, quotes, arrows, copyright symbols)\n * - `'all'`: All rules enabled\n * - `'none'`: No rules enabled (use with `enable` prop)\n *\n * @defaultValue 'default'\n */\n preset?: 'default' | 'all' | 'none'\n /**\n * Enable specific rules (additive to preset).\n * Use this to enable additional rules beyond the preset.\n *\n * @example\n * ```tsx\n * // Enable multiplication and plusMinus in addition to default rules\n * <TypographyPlugin enable={['multiplication', 'plusMinus']} />\n * ```\n */\n enable?: ReadonlyArray<TEnabledRuleName>\n /**\n * Disable specific rules (subtractive from preset).\n * Use this to disable rules that would otherwise be enabled by the preset.\n * Cannot contain rules that are in the `enable` array (TypeScript will enforce this).\n *\n * @example\n * ```tsx\n * // Disable em dash from the default rules\n * <TypographyPlugin disable={['emDash']} />\n * ```\n */\n disable?: ReadonlyArray<TDisabledRuleName>\n}\n\n/**\n * @public\n */\nexport function TypographyPlugin<\n TEnabledRuleName extends RuleName = never,\n TDisabledRuleName extends Exclude<RuleName, TEnabledRuleName> = never,\n>(props: TypographyPluginProps<TEnabledRuleName, TDisabledRuleName>) {\n const {preset = 'default', enable = [], disable = [], guard} = props\n\n const configuredInputRules = useMemo(() => {\n // Determine which rules should be enabled based on preset\n const enabledRules = new Set<RuleName>()\n\n if (preset === 'all') {\n // Enable all rules\n for (const rule of defaultRuleConfig) {\n enabledRules.add(rule.name)\n }\n } else if (preset === 'default') {\n // Enable only default rules (state: 'on')\n for (const rule of defaultRuleConfig) {\n if (rule.state === 'on') {\n enabledRules.add(rule.name)\n }\n }\n }\n // preset === 'none' starts with empty set\n\n // Apply enable list (additive)\n for (const ruleName of enable) {\n enabledRules.add(ruleName)\n }\n\n // Apply disable list (subtractive)\n for (const ruleName of disable) {\n enabledRules.delete(ruleName)\n }\n\n // Build final rule list\n return defaultRuleConfig.flatMap((rule) =>\n enabledRules.has(rule.name)\n ? [{...rule.rule, guard: guard ?? (() => true)}]\n : [],\n )\n }, [preset, enable, disable, guard])\n\n return <InputRulePlugin rules={configuredInputRules} />\n}\n"],"names":["createDecoratorGuard","config","snapshot","event","allowedDecorators","decorators","context","schema","flatMap","decorator","includes","name","length","matchedSpans","matches","match","getSelectedSpans","selection","preventInputRule","isActiveDecorator","some","span","node","marks","emDashRule","defineTextTransformRule","on","transform","ellipsisRule","openingDoubleQuoteRule","closingDoubleQuoteRule","openingSingleQuoteRule","closingSingleQuoteRule","smartQuotesRules","leftArrowRule","rightArrowRule","copyrightRule","servicemarkRule","trademarkRule","registeredTrademarkRule","oneHalfRule","plusMinusRule","notEqualRule","laquoRule","raquoRule","multiplicationRule","superscriptTwoRule","superscriptThreeRule","oneQuarterRule","threeQuartersRule","defaultRuleConfig","rule","state","TypographyPlugin","props","$","_c","preset","t0","enable","t1","disable","t2","guard","undefined","t3","t4","enabledRules","Set","add","rule_0","ruleName","ruleName_0","delete","t5","rule_1","has","_temp","configuredInputRules","t6"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {EditorSchema} from '@portabletext/editor'
|
|
1
|
+
import type {EditorContext, EditorSchema} from '@portabletext/editor'
|
|
2
2
|
import {
|
|
3
3
|
getSelectedSpans,
|
|
4
4
|
isActiveDecorator,
|
|
@@ -13,17 +13,29 @@ import type {InputRuleGuard} from '@portabletext/plugin-input-rule'
|
|
|
13
13
|
* @example
|
|
14
14
|
* ```tsx
|
|
15
15
|
* const guard = createDecoratorGuard({
|
|
16
|
-
*
|
|
16
|
+
* decorators: ({context}) => context.schema.decorators.flatMap((decorator) => decorator.name === 'code' ? [] : [decorator.name]),
|
|
17
17
|
* })
|
|
18
18
|
*
|
|
19
19
|
* <TypographyPlugin guard={guard} />
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
export function createDecoratorGuard(config: {
|
|
23
|
-
decorators: ({
|
|
23
|
+
decorators: ({
|
|
24
|
+
context,
|
|
25
|
+
}: {
|
|
26
|
+
context: Pick<EditorContext, 'schema'>
|
|
27
|
+
}) => Array<EditorSchema['decorators'][number]['name']>
|
|
24
28
|
}): InputRuleGuard {
|
|
25
29
|
return ({snapshot, event}) => {
|
|
26
|
-
const
|
|
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
|
+
)
|
|
27
39
|
|
|
28
40
|
if (decorators.length === 0) {
|
|
29
41
|
return true
|
|
@@ -41,14 +41,17 @@ Feature: Disallow in code
|
|
|
41
41
|
|
|
42
42
|
Scenario Outline: Decorated and annotated text
|
|
43
43
|
Given the text "foo bar baz"
|
|
44
|
-
And
|
|
44
|
+
And <decorator> around "bar"
|
|
45
45
|
And a "link" "l1" around "bar"
|
|
46
46
|
When the caret is put <position>
|
|
47
47
|
And "->" is typed
|
|
48
48
|
Then the text is <new text>
|
|
49
49
|
|
|
50
50
|
Examples:
|
|
51
|
-
| position | new text |
|
|
52
|
-
| after "bar" | "foo ,bar,→ baz" |
|
|
53
|
-
|
|
|
54
|
-
| before "
|
|
51
|
+
| decorator | position | new text |
|
|
52
|
+
| "code" | after "bar" | "foo ,bar,→ baz" |
|
|
53
|
+
| "strong" | after "bar" | "foo ,bar,→ baz" |
|
|
54
|
+
| "code" | before "bar" | "foo →,bar, baz" |
|
|
55
|
+
| "strong" | before "bar" | "foo →,bar, baz" |
|
|
56
|
+
| "code" | before "ar baz" | "foo ,b->ar, baz" |
|
|
57
|
+
| "strong" | before "ar baz" | "foo ,b→ar, baz" |
|
|
@@ -12,9 +12,9 @@ import disallowInCodeFeature from './disallow-in-code.feature?raw'
|
|
|
12
12
|
import {TypographyPlugin} from './plugin.typography'
|
|
13
13
|
|
|
14
14
|
const codeGuard = createDecoratorGuard({
|
|
15
|
-
decorators: ({
|
|
16
|
-
schema.decorators.flatMap((decorator) =>
|
|
17
|
-
decorator.name === 'code' ? [
|
|
15
|
+
decorators: ({context}) =>
|
|
16
|
+
context.schema.decorators.flatMap((decorator) =>
|
|
17
|
+
decorator.name === 'code' ? [] : [decorator.name],
|
|
18
18
|
),
|
|
19
19
|
})
|
|
20
20
|
|
|
@@ -23,7 +23,7 @@ Feature({
|
|
|
23
23
|
Before(async (context: Context) => {
|
|
24
24
|
const {editor, locator} = await createTestEditor({
|
|
25
25
|
children: (
|
|
26
|
-
<TypographyPlugin guard={codeGuard}
|
|
26
|
+
<TypographyPlugin guard={codeGuard} enable={['multiplication']} />
|
|
27
27
|
),
|
|
28
28
|
schemaDefinition: defineSchema({
|
|
29
29
|
decorators: [{name: 'strong'}, {name: 'code'}],
|
|
@@ -14,7 +14,7 @@ Feature({
|
|
|
14
14
|
hooks: [
|
|
15
15
|
Before(async (context: Context) => {
|
|
16
16
|
const {editor, locator} = await createTestEditor({
|
|
17
|
-
children: <TypographyPlugin
|
|
17
|
+
children: <TypographyPlugin enable={['multiplication']} />,
|
|
18
18
|
schemaDefinition: defineSchema({
|
|
19
19
|
decorators: [{name: 'strong'}],
|
|
20
20
|
annotations: [{name: 'link'}],
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InputRulePlugin,
|
|
3
|
-
type InputRule,
|
|
4
3
|
type InputRuleGuard,
|
|
5
4
|
} from '@portabletext/plugin-input-rule'
|
|
6
5
|
import {useMemo} from 'react'
|
|
@@ -29,114 +28,7 @@ import {
|
|
|
29
28
|
trademarkRule,
|
|
30
29
|
} from './input-rules.typography'
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
* @public
|
|
34
|
-
*/
|
|
35
|
-
export type TypographyPluginProps = {
|
|
36
|
-
guard?: InputRuleGuard
|
|
37
|
-
/**
|
|
38
|
-
* Configure which rules to enable or disable. Ordinary rules like `emDash` and `ellipsis` are enabled by default.
|
|
39
|
-
* Less common rules like `multiplication` are disabled by default.
|
|
40
|
-
*/
|
|
41
|
-
rules?: {
|
|
42
|
-
/**
|
|
43
|
-
* @defaultValue 'on'
|
|
44
|
-
*/
|
|
45
|
-
emDash?: 'on' | 'off'
|
|
46
|
-
/**
|
|
47
|
-
* @defaultValue 'on'
|
|
48
|
-
*/
|
|
49
|
-
ellipsis?: 'on' | 'off'
|
|
50
|
-
/**
|
|
51
|
-
* @defaultValue 'on'
|
|
52
|
-
*/
|
|
53
|
-
openingDoubleQuote?: 'on' | 'off'
|
|
54
|
-
/**
|
|
55
|
-
* @defaultValue 'on'
|
|
56
|
-
*/
|
|
57
|
-
closingDoubleQuote?: 'on' | 'off'
|
|
58
|
-
/**
|
|
59
|
-
* @defaultValue 'on'
|
|
60
|
-
*/
|
|
61
|
-
openingSingleQuote?: 'on' | 'off'
|
|
62
|
-
/**
|
|
63
|
-
* @defaultValue 'on'
|
|
64
|
-
*/
|
|
65
|
-
closingSingleQuote?: 'on' | 'off'
|
|
66
|
-
/**
|
|
67
|
-
* @defaultValue 'on'
|
|
68
|
-
*/
|
|
69
|
-
leftArrow?: 'on' | 'off'
|
|
70
|
-
/**
|
|
71
|
-
* @defaultValue 'on'
|
|
72
|
-
*/
|
|
73
|
-
rightArrow?: 'on' | 'off'
|
|
74
|
-
/**
|
|
75
|
-
* @defaultValue 'on'
|
|
76
|
-
*/
|
|
77
|
-
copyright?: 'on' | 'off'
|
|
78
|
-
/**
|
|
79
|
-
* @defaultValue 'on'
|
|
80
|
-
*/
|
|
81
|
-
trademark?: 'on' | 'off'
|
|
82
|
-
/**
|
|
83
|
-
* @defaultValue 'on'
|
|
84
|
-
*/
|
|
85
|
-
servicemark?: 'on' | 'off'
|
|
86
|
-
/**
|
|
87
|
-
* @defaultValue 'on'
|
|
88
|
-
*/
|
|
89
|
-
registeredTrademark?: 'on' | 'off'
|
|
90
|
-
/**
|
|
91
|
-
* @defaultValue 'off'
|
|
92
|
-
*/
|
|
93
|
-
oneHalf?: 'on' | 'off'
|
|
94
|
-
/**
|
|
95
|
-
* @defaultValue 'off'
|
|
96
|
-
*/
|
|
97
|
-
plusMinus?: 'on' | 'off'
|
|
98
|
-
/**
|
|
99
|
-
* @defaultValue 'off'
|
|
100
|
-
*/
|
|
101
|
-
notEqual?: 'on' | 'off'
|
|
102
|
-
/**
|
|
103
|
-
* @defaultValue 'off'
|
|
104
|
-
*/
|
|
105
|
-
laquo?: 'on' | 'off'
|
|
106
|
-
/**
|
|
107
|
-
* @defaultValue 'off'
|
|
108
|
-
*/
|
|
109
|
-
raquo?: 'on' | 'off'
|
|
110
|
-
/**
|
|
111
|
-
* @defaultValue 'off'
|
|
112
|
-
*/
|
|
113
|
-
multiplication?: 'on' | 'off'
|
|
114
|
-
/**
|
|
115
|
-
* @defaultValue 'off'
|
|
116
|
-
*/
|
|
117
|
-
superscriptTwo?: 'on' | 'off'
|
|
118
|
-
/**
|
|
119
|
-
* @defaultValue 'off'
|
|
120
|
-
*/
|
|
121
|
-
superscriptThree?: 'on' | 'off'
|
|
122
|
-
/**
|
|
123
|
-
* @defaultValue 'off'
|
|
124
|
-
*/
|
|
125
|
-
oneQuarter?: 'on' | 'off'
|
|
126
|
-
/**
|
|
127
|
-
* @defaultValue 'off'
|
|
128
|
-
*/
|
|
129
|
-
threeQuarters?: 'on' | 'off'
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
type RuleName = keyof NonNullable<TypographyPluginProps['rules']>
|
|
134
|
-
|
|
135
|
-
const defaultRuleConfig: Array<{
|
|
136
|
-
name: RuleName
|
|
137
|
-
rule: InputRule
|
|
138
|
-
state: 'on' | 'off'
|
|
139
|
-
}> = [
|
|
31
|
+
const defaultRuleConfig = [
|
|
140
32
|
{name: 'emDash', rule: emDashRule, state: 'on'},
|
|
141
33
|
{name: 'ellipsis', rule: ellipsisRule, state: 'on'},
|
|
142
34
|
{name: 'openingDoubleQuote', rule: openingDoubleQuoteRule, state: 'on'},
|
|
@@ -159,24 +51,97 @@ const defaultRuleConfig: Array<{
|
|
|
159
51
|
{name: 'superscriptThree', rule: superscriptThreeRule, state: 'off'},
|
|
160
52
|
{name: 'oneQuarter', rule: oneQuarterRule, state: 'off'},
|
|
161
53
|
{name: 'threeQuarters', rule: threeQuartersRule, state: 'off'},
|
|
162
|
-
]
|
|
54
|
+
] as const
|
|
55
|
+
|
|
56
|
+
type RuleName = (typeof defaultRuleConfig)[number]['name']
|
|
163
57
|
|
|
164
58
|
/**
|
|
165
59
|
* @public
|
|
166
60
|
*/
|
|
167
|
-
export
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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])
|
|
180
145
|
|
|
181
|
-
return <InputRulePlugin
|
|
146
|
+
return <InputRulePlugin rules={configuredInputRules} />
|
|
182
147
|
}
|