Skip to content

Commit 9b5faad

Browse files
authored
Merge pull request #587064 from vueup/codex/toolbar-false
fix: support disabling toolbar prop
2 parents 0e2514d + 6ce8f52 commit 9b5faad

6 files changed

Lines changed: 104 additions & 10 deletions

File tree

docs/content/api/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@
5151
The name of the theme to apply to the editor, Quill features two officially supported themes: `snow` and `bubble`. Pass `""` to use the minimal core theme. See the [docs on themes](https://quilljs.com/docs/themes/) for more information on including the required stylesheets.
5252

5353
## toolbar
54-
- **Type:** `String | Array | Object`
54+
- **Type:** `String | Array | Object | false`
5555

56-
Toolbar options to configure the default toolbar icons using an array of format names, see [Toolbar](../guide/toolbar.md) section for more details.
56+
Toolbar options to configure the default toolbar icons using an array of format names. Pass `false` to disable the toolbar. See [Toolbar](../guide/toolbar.md) section for more details.
5757

5858
## modules
5959
- **Type:** `Object | Object[]`

docs/content/guide/toolbar.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Toolbar
22
The toolbar module allows users to easily format Quill’s contents. It can be configured with a [`toolbar` prop](../api/index.md#toolbar).
33

4-
There are 3 ways to configure the toolbar:
4+
There are 4 ways to configure the toolbar:
55

66
## Pre-Configure Toolbar Options
77

@@ -25,6 +25,16 @@ You can also set your own options like this:
2525

2626
See [Quill toolbar docs](https://quilljs.com/docs/modules/toolbar/) for more details.
2727

28+
## Disable Toolbar
29+
30+
Pass `false` to the `toolbar` prop to disable the toolbar module:
31+
32+
~~~ vue
33+
<template>
34+
<QuillEditor :toolbar="false" .../>
35+
</template>
36+
~~~
37+
2838
## Custom Toolbar Container
2939

3040
~~~ vue
@@ -57,4 +67,4 @@ You can also put your toolbar outside `QuillEditor` component, just make sure to
5767
</template>
5868
~~~
5969

60-
See [Quill toolbar docs](https://quilljs.com/docs/modules/toolbar/) for more details.
70+
See [Quill toolbar docs](https://quilljs.com/docs/modules/toolbar/) for more details.

examples/vue-quill/src/example-catalog.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe('Vue Quill example catalog', () => {
4141
it('documents supported toolbar and theme variations', () => {
4242
assert.deepEqual(
4343
toolbarExamples.map((toolbar) => toolbar.id),
44-
['minimal', 'array', 'custom-container'],
44+
['minimal', 'array', 'custom-container', 'disabled'],
4545
)
4646
assert.deepEqual(
4747
themeExamples.map((theme) => theme.value),

examples/vue-quill/src/example-catalog.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export type ExampleSectionId =
1010

1111
export type ThemeValue = 'snow' | 'bubble' | ''
1212

13-
export type ToolbarValue = string | unknown[]
13+
export type ToolbarValue = string | unknown[] | false
1414

1515
export type ExampleSection = {
1616
id: ExampleSectionId
@@ -20,7 +20,7 @@ export type ExampleSection = {
2020
}
2121

2222
export type ToolbarExample = {
23-
id: 'minimal' | 'array' | 'custom-container'
23+
id: 'minimal' | 'array' | 'custom-container' | 'disabled'
2424
label: string
2525
description: string
2626
toolbar: ToolbarValue
@@ -66,7 +66,7 @@ export const exampleSections: ExampleSection[] = [
6666
id: 'toolbars',
6767
title: 'Toolbar customization',
6868
description:
69-
'Switch between a built-in preset, an inline toolbar array, and a custom slot toolbar.',
69+
'Switch between a built-in preset, an inline toolbar array, a custom slot toolbar, and no toolbar.',
7070
coverage: ['configuration variations', 'toolbar customization'],
7171
},
7272
{
@@ -130,6 +130,12 @@ export const toolbarExamples: ToolbarExample[] = [
130130
description: 'Provides toolbar markup through the toolbar slot.',
131131
toolbar: '#article-toolbar',
132132
},
133+
{
134+
id: 'disabled',
135+
label: 'No toolbar',
136+
description: 'Passes false to disable the toolbar module.',
137+
toolbar: false,
138+
},
133139
]
134140

135141
export const themeExamples: ThemeExample[] = [
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import assert from 'node:assert/strict'
2+
import { readFileSync } from 'node:fs'
3+
import { describe, it } from 'node:test'
4+
import ts from 'typescript'
5+
6+
const sourceFile = ts.createSourceFile(
7+
'QuillEditor.ts',
8+
readFileSync(new URL('./QuillEditor.ts', import.meta.url), 'utf8'),
9+
ts.ScriptTarget.Latest,
10+
true,
11+
ts.ScriptKind.TS,
12+
)
13+
14+
const getPropertyName = (node: ts.PropertyName): string | undefined => {
15+
if (ts.isIdentifier(node) || ts.isStringLiteral(node)) return node.text
16+
return undefined
17+
}
18+
19+
const findToolbarProp = (): ts.ObjectLiteralExpression => {
20+
let toolbarProp: ts.ObjectLiteralExpression | undefined
21+
22+
const visit = (node: ts.Node) => {
23+
if (
24+
ts.isPropertyAssignment(node) &&
25+
getPropertyName(node.name) === 'toolbar' &&
26+
ts.isObjectLiteralExpression(node.initializer)
27+
) {
28+
toolbarProp = node.initializer
29+
return
30+
}
31+
32+
ts.forEachChild(node, visit)
33+
}
34+
35+
visit(sourceFile)
36+
37+
assert.ok(toolbarProp, 'toolbar prop should be defined')
38+
return toolbarProp
39+
}
40+
41+
describe('QuillEditor toolbar prop', () => {
42+
it('accepts false to disable the toolbar', () => {
43+
const typeProperty = findToolbarProp().properties.find(
44+
(property): property is ts.PropertyAssignment =>
45+
ts.isPropertyAssignment(property) &&
46+
getPropertyName(property.name) === 'type',
47+
)
48+
49+
assert.ok(typeProperty, 'toolbar prop should define runtime types')
50+
assert.match(
51+
typeProperty.initializer.getText(sourceFile),
52+
/\bBoolean\b/,
53+
'toolbar prop runtime types should include Boolean',
54+
)
55+
})
56+
57+
it('keeps the absent toolbar prop distinct from false', () => {
58+
const defaultProperty = findToolbarProp().properties.find(
59+
(property): property is ts.PropertyAssignment =>
60+
ts.isPropertyAssignment(property) &&
61+
getPropertyName(property.name) === 'default',
62+
)
63+
64+
assert.ok(defaultProperty, 'toolbar prop should define an explicit default')
65+
assert.equal(
66+
defaultProperty.initializer.getText(sourceFile),
67+
'undefined',
68+
'toolbar prop should not cast an absent prop to false',
69+
)
70+
})
71+
})

packages/vue-quill/src/components/QuillEditor.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { loadQuill, type QuillConstructor } from '../quill'
1818
export type Module = { name: string; module: unknown; options?: object }
1919

2020
type ContentPropType = string | Delta | undefined | null
21+
type ToolbarPropType = string | unknown[] | Record<string, unknown> | false
2122
type QuillWithImports = QuillConstructor & { imports?: Record<string, unknown> }
2223
type ToolbarModule = { container?: HTMLElement | null }
2324
type TextChangeHandler = (
@@ -80,9 +81,11 @@ export const QuillEditor = defineComponent({
8081
},
8182
},
8283
toolbar: {
83-
type: [String, Array, Object],
84+
type: [String, Array, Object, Boolean] as PropType<ToolbarPropType>,
8485
required: false,
86+
default: undefined,
8587
validator: (value: string | unknown) => {
88+
if (typeof value === 'boolean') return value === false
8689
if (typeof value === 'string' && value !== '') {
8790
return value.charAt(0) === '#'
8891
? true
@@ -192,7 +195,11 @@ export const QuillEditor = defineComponent({
192195
if (props.theme !== '') clientOptions.theme = props.theme
193196
if (props.readOnly) clientOptions.readOnly = props.readOnly
194197
if (props.placeholder) clientOptions.placeholder = props.placeholder
195-
if (props.toolbar && props.toolbar !== '') {
198+
if (props.toolbar === false) {
199+
clientOptions.modules = {
200+
toolbar: false,
201+
}
202+
} else if (props.toolbar && props.toolbar !== '') {
196203
clientOptions.modules = {
197204
toolbar: (() => {
198205
if (typeof props.toolbar === 'object') {

0 commit comments

Comments
 (0)