{"id":22446957,"url":"https://github.com/cloudcreativity/ember-quill","last_synced_at":"2025-06-21T05:36:22.980Z","repository":{"id":57102607,"uuid":"319718386","full_name":"cloudcreativity/ember-quill","owner":"cloudcreativity","description":"The Quill rich-text editor for Ember.","archived":false,"fork":false,"pushed_at":"2021-03-30T16:55:26.000Z","size":477,"stargazers_count":4,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-06-03T02:15:20.919Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudcreativity.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-08T17:56:19.000Z","updated_at":"2021-03-31T12:01:13.000Z","dependencies_parsed_at":"2022-08-20T18:40:48.840Z","dependency_job_id":null,"html_url":"https://github.com/cloudcreativity/ember-quill","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/cloudcreativity/ember-quill","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudcreativity%2Fember-quill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudcreativity%2Fember-quill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudcreativity%2Fember-quill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudcreativity%2Fember-quill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudcreativity","download_url":"https://codeload.github.com/cloudcreativity/ember-quill/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudcreativity%2Fember-quill/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261070524,"owners_count":23105421,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-06T04:13:12.738Z","updated_at":"2025-06-21T05:36:17.943Z","avatar_url":"https://github.com/cloudcreativity.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @cloudcreativity/ember-quill\n\nThe [Quill](https://quilljs.com/) rich text editor for Ember.\n\n\n## Compatibility\n\n* Ember.js v3.16 or above\n* Ember CLI v2.13 or above\n* Node.js v10 or above\n\n\n## Installation\n\n```\nember install @cloudcreativity/ember-quill\n```\n\n## Usage\n\n### Contents\n\n- [Introduction](#introduction)\n- [Examples](#examples)\n- [`\u003cQuill\u003e` Component](#quill-component)\n- [`\u003cQuillEditor\u003e` Component](#quill-editor-component)\n- [Quill Service](#quill-service)\n- [Quill Static Methods](#quill-static-methods)\n- [Testing](#testing)\n\n### Introduction\n\nThis addon provides components for working with the [Quill](https://quilljs.com)\nrich text editor in Ember.\n\n### Examples\n\nUse the `\u003cQuill\u003e` component to create your toolbar and editor:\n\n```hbs\n\u003cQuill as |Ql|\u003e\n  \u003cQl.toolbar as |Tb|\u003e\n    \u003cTb.group\u003e\n      \u003cTb.bold /\u003e\n      \u003cTb.italic /\u003e\n      \u003cTb.underline /\u003e\n    \u003c/Tb.group\u003e\n    \u003cTb.group\u003e\n      \u003cTb.list value=\"ordered\" /\u003e\n      \u003cTb.list value=\"bullet\" /\u003e\n    \u003c/Tb.group\u003e\n  \u003c/Ql.toolbar\u003e\n\n  \u003cQl.editor\n    @delta={{this.delta}}\n    @focused={{true}}\n    @onChange={{this.setDelta}}\n    @placeholder=\"Tell us your story.\"\n    @theme=\"snow\"\n  /\u003e\n\n  \u003cdiv\u003e\n    Characters: {{Ql.characters}}\u003cbr\u003e\n    Words: {{Ql.words}}\n  \u003c/div\u003e\n\u003c/Quill\u003e\n```\n\nOr just use the `\u003cQuillEditor\u003e` component by itself:\n\n```hbs\n\u003cQuillEditor\n  @delta={{this.delta}}\n  @onChange={{this.setDelta}}\n  @placeholder=\"Tell us your story.\"\n  @theme=\"snow\"\n/\u003e\n```\n\n### Quill Component\n\nThe `\u003cQuill\u003e` component is a wrapper component that allows you to create the\neditor's toolbar via HTML. It ensures that the editor is wired correctly\nto use the HTML toolbar.\n\nIn addition, the `\u003cQuill\u003e` component yields the length and number of words\nof the editor contents, so that you can display these to the user if\ndesired.\n\n#### Toolbar\n\nUse the yielded `toolbar` to build your\n[editor's toolbar](https://quilljs.com/docs/modules/toolbar/),\nfor example:\n\n```hbs\n\u003cQuill as |Ql|\u003e\n  \u003cQl.toolbar as |Tb|\u003e\n    \u003cTb.bold /\u003e\n    \u003cTb.italic /\u003e\n  \u003c/Ql.toolbar\u003e\n\u003c/Quill\u003e\n```\n\nThe toolbar yields components for all the toolbar controls supported by\nQuill. These are either `\u003cbutton\u003e` and/or `\u003cselect\u003e` elements. The\nsupported controls are:\n\n| Control | Type |\n| --- | --- |\n| `align` | `\u003cbutton\u003e` or `\u003cselect\u003e` |\n| `background` | `\u003cselect\u003e` |\n| `blockquote` | `\u003cbutton\u003e` |\n| `bold` | `\u003cbutton\u003e` |\n| `clean` | `\u003cbutton\u003e` |\n| `code-block` | `\u003cbutton\u003e` |\n| `code` | `\u003cbutton\u003e` |\n| `color` | `\u003cselect\u003e` |\n| `direction` | `\u003cbutton\u003e` |\n| `font` | `\u003cselect\u003e` |\n| `formula` | `\u003cbutton\u003e` |\n| `header` | `\u003cbutton\u003e` or `\u003cselect\u003e` |\n| `image` | `\u003cbutton\u003e` |\n| `indent` | `\u003cbutton\u003e` |\n| `italic` | `\u003cbutton\u003e` |\n| `link` | `\u003cbutton\u003e` |\n| `list` | `\u003cbutton\u003e` |\n| `script` | `\u003cbutton\u003e` |\n| `size` | `\u003cselect\u003e` |\n| `strike` | `\u003cbutton\u003e` |\n| `underline` | `\u003cbutton\u003e` |\n| `video` | `\u003cbutton\u003e` |\n\nFor `\u003cbutton\u003e` elements, set the `value` attribute if required. For example,\nthe `bold` button does not need a `value`, but the `list` button does:\n\n```hbs\n\u003cTb.bold /\u003e\n\u003cTb.list value=\"ordered\" /\u003e\n\u003cTb.list value=\"bullet\" /\u003e\n```\n\nFor `\u003cselect\u003e` elements, provide the list of values using the `@value`\nargument with the `{{array}}` helper:\n\n```hbs\n\u003cTb.size @values={{array \"small\" false \"large\" \"huge\"}} /\u003e\n```\n\nProvide an empty value if you want to use the theme's default values.\nFor example, the *Snow* theme provides a list of 35 colors for the\n`color` and `background` toolbar options. To use the defaults:\n\n```hbs\n\u003cTb.color /\u003e\n\u003cTb.background /\u003e\n```\n\nSome controls, e.g. `header`, work as either `\u003cbutton\u003e` or `\u003cselect\u003e`\nelements. For these, you **must** provide a `@values` argument if you\nwant to use a `\u003cselect\u003e`. Otherwise a `\u003cbutton\u003e` will be used. For example:\n\n```hbs\n\u003c!-- Header Buttons --\u003e\n\u003cTb.header value=\"1\" /\u003e\n\u003cTb.header value=\"2\" /\u003e\n\n\u003c!-- Header Select --\u003e\n\u003cTb.header @values={{array 1 2 3 4}} /\u003e\n\n\u003c!-- Header Select with Theme Defaults --\u003e\n\u003cTb.header @values={{array}} /\u003e\n```\n\nThe `group` component allows you to group controls, i.e. add space between\nsets of controls. This is done by using a `\u003cspan\u003e` with the `ql-formats`\nclass:\n\n```hbs\n\u003cTb.group\u003e\n  \u003cTb.bold /\u003e\n  \u003cTb.italic /\u003e\n\u003c/Tb.group\u003e\n\u003cTb.group\u003e\n  \u003cTb.list value=\"ordered\" /\u003e\n  \u003cTb.list value=\"bullet\" /\u003e\n\u003c/Tb.group\u003e\n```\n\n#### Editor\n\nUse the yielded `editor` to create the container `\u003cdiv\u003e` for the Quill Editor.\nThis is automatically configured with the selector for your HTML toolbar:\n\n```hbs\n\u003cQuill as |Ql|\u003e\n  \u003cQl.toolbar\u003e\n    \u003c!-- toolbar --\u003e\n  \u003c/Ql.toolbar\u003e\n  \u003cQl.editor @theme=\"snow\" /\u003e\n\u003c/Quill\u003e\n```\n\nThe yielded `\u003cQl.editor\u003e` is an instance of the `\u003cQuillEditor\u003e` component.\nThis component, along with all of its options,\n[is described below.](#quill-editor-component)\n\n#### Values\n\nThe `\u003cQuill\u003e` components also yields the following values:\n\n| Value | Description |\n| --- | --- |\n| `length` | The length of editor content, provided by Quill's `getLength` method. |\n| `characters` | The length minus one. |\n| `words` | The number of words in the editor content. |\n\n\u003e When the Quill Editor is empty, there is always a blank line representated by\n\u003e `\\n`. This means Quill's `getLength` method always returns `1` for an empty\n\u003e editor. Typically if you want to display the length to users, you would need\n\u003e to subtract 1 from the length. This is why we yield both the `length` and\n\u003e the `characters` values.\n\nFor example, to display the number of words to the user:\n\n```hbs\n\u003cQuill as |Ql|\u003e\n  \u003c!-- Toolbar and Editor --\u003e\n\n  Words: {{Ql.words}}\n\u003c/Quill\u003e\n```\n\n### Quill Editor Component\n\nThe `\u003cQuillEditor\u003e` component can be used by itself if you do not want to\ndefine your toolbar in HTML. All the options described here can also be used\nwhen displaying the editor within the `\u003cQuill\u003e` component.\n\n#### Configuration\n\nThe following [Quill configuration](https://quilljs.com/docs/configuration/)\noptions are supported when initialising Quill:\n\n- `bounds`\n- `debug`\n- `formats`\n- `modules`\n- `placeholder`\n- `readOnly`\n- `scrollingContainer`\n- `theme`\n\nFor example:\n\n```hbs\n\u003cQuillEditor @formats={{array \"bold\" \"italic\"}} @theme=\"snow\" /\u003e\n```\n\n\u003e Quill does not provide a way of changing these values *after* initialisation.\n\u003e Therefore, changing these values after the component has been rendered is\n\u003e not supported.\n\n#### Enabled\n\nThe `\u003cQuillEditor\u003e` component accepts an `@enabled` argument. Changing this\nvalue allows you to toggle whether the editor is enabled or not.\n\nFor example:\n\n```hbs\n\u003cQuillEditor @enabled={{not this.formIsDisabled}} /\u003e\n```\n\n\u003e The `{{not}}` helper is provided by the\n[Ember Truth Helpers addon.](https://github.com/jmurphyau/ember-truth-helpers)\n\n#### Focused\n\nThe `@focused` argument allows you to give the editor focus when it is\nrendered. For example:\n\n```hbs\n\u003cQuillEditor @focused={{true}} /\u003e\n```\n\n#### Delta\n\nUse the `@delta` argument to provide the initial value of the editor using\na Quill Delta. This is one-way bound: to subscribe to changes to the\ndelta, use the `onChange` action:\n\n```hbs\n\u003cQuillEditor @delta={{this.delta}} @onChange={{this.setDelta}} /\u003e\n```\n\n\u003e The value you provide for the `@delta` argument does not need to be a\nQuill Delta instance. The editor's `setContents` method that is used to\nset the delta does accept the delta JSON.\n\n#### Text\n\nIf you want to use plain text to set the initial value of the editor, use\nthe `@text` argument. This is one-way bound: to subscribe to changes to\nthe text, use the `onText` action:\n\n```hbs\n\u003cQuillEditor @text={{this.text}} @onText={{this.setText}} /\u003e\n```\n\n\u003e If you provide a value to the `@delta` argument, the `@text` argument\nwill be ignored.\n\n#### Events\n\nTo subscribe to [Quill events](https://quilljs.com/docs/api/#events),\nuse the following actions:\n\n| Quill Event | Action |\n| --- | --- |\n| `text-change` | `@onTextChange` |\n| `selection-change` | `@onSelectionChange` |\n| `editor-change` | `@onEditorChange` |\n\nWe also provide the following custom events:\n\n| Action | Description |\n| --- | --- |\n| `@onChange` | Provides the updated delta for the editor, provided by Quill's `getContents` method. |\n| `@onText` | Provides the updated editor text, provided by Quill's `getText` method. |\n| `@onLength` | Provides the length of the editor content, provided by Quill's `getLength` method. |\n| `@onWords` | Provides the number of words in the editor content. |\n\n\u003e **Warning**: If you are using the `\u003cQuill\u003e` component, the `@onLength` and\n`@onWords` actions are already wired up to provide the yielded `length`,\n`characters` and `words` values. If you use the `@onLength` or `@onWords`\nactions, the yielded values will NOT update.\n\n### Quill Service\n\nIf you need to interact with a Quill editor programmatically, you can do this\nvia the Quill service.\n\nAll Quill instances are registered with the service using a name. To interact\nwith an instance, provide the `@name` argument to the `\u003cQuillEditor\u003e` component,\nmaking sure that the name is unique for each editor you have rendered.\n\nFor example:\n\n```hbs\n\u003cQuill as |Ql|\u003e\n  \u003c!-- Toolbar --\u003e\n  \u003cQl.editor @name=\"my-editor\" /\u003e\n\u003c/Quill\u003e\n\n\u003cQuillEditor @name=\"other-editor\" /\u003e\n```\n\nThen inject the service, for example:\n\n```js\nimport Component from '@glimmer/component';\nimport { inject as service } from '@ember/service';\nimport { action } from '@ember/object';\n\nexport default class CustomComponent extends Component {\n  @service('quill') quillService;\n\n  @action\n  resetEditor() {\n    this.quillService.setText('my-editor', '');\n  }\n}\n```\n\nThe service provides all the following Quill methods. Each takes the name\nof the editor instance, followed by the arguments as defined in the\n[Quill API documentation.](https://quilljs.com/docs/api/)\n\n- `deleteText`\n- `getContents`\n- `getLength`\n- `insertEmbed`\n- `insertText`\n- `setContents`\n- `setText`\n- `updateContents`\n- `format`\n- `formatLine`\n- `formatText`\n- `getFormat`\n- `removeFormat`\n- `getBounds`\n- `getSelection`\n- `blur`\n- `disable`\n- `enable`\n- `focus`\n- `hasFocus`\n- `update`\n\n\u003e If you use the `disable` or `enable` methods, the `@enabled` argument\non the `\u003cQuillEditor\u003e` component will get out-of-sync. We recommend using\nthe `@enabled` argument rather than the methods via the service.\n\nAs Quill editor instances are deregistered from the service when the\n`\u003cQuillEditor\u003e` component is being destroyed, any methods that return values\nwill return `null` if the named editor does not exist on the Quill service.\n\nIf you need to call multiple methods on a Quill instance, you can use the\nservice's `instance` method to retrieve the named editor. This will return\n`null` if the editor is no longer registered:\n\n```js\nconst quill = this.quillService.instance('my-editor');\n\nif (quill) {\n  // ...\n}\n```\n\n### Quill Static Methods\n\nTo call static Quill methods, import Quill as follows:\n\n```js\nimport Quill from 'quill';\n\nvar Module = Quill.import('core/module');\n\nclass CustomModule extends Module {}\n\nQuill.register('modules/custom-module', CustomModule);\n```\n\n### Testing\n\nAll Quill event handlers are executed via the Ember runloop, to ensure that\nyou can easily use your Quill components in tests.\n\nUse the `fillIn` test helper with the `.ql-editor` selector:\n\n```js\ntest('it renders', async function (assert) {\n  this.set('delta', {\n    ops: [\n      { insert: 'This is my story.\\n'}\n    ],\n  });\n\n  await render(hbs`\n    \u003cQuillEditor\n      @delta={{this.delta}}\n      @onChange={{action (mut this.delta)}}\n    /\u003e\n  `);\n\n  assert.dom('.ql-editor').hasText('This is my story.');\n\n  await fillIn('.ql-editor', 'This is my other story.');\n\n  assert.deepEqual(this.delta.ops, [\n    { insert: 'This is my other story.\\n' },\n  ]);\n});\n```\n\n## Contributing\n\nSee the [Contributing](CONTRIBUTING.md) guide for details.\n\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudcreativity%2Fember-quill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudcreativity%2Fember-quill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudcreativity%2Fember-quill/lists"}