@open-wysiwyg-editor/angular 0.0.0-stage → 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 alhassan-ahmed and open-wysiwyg-editor contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,226 @@
1
- # Temporary Holding Version
1
+ <p align="center"><a href="https://alhassan73.github.io/open-wysiwyg-editor/"><img src="https://raw.githubusercontent.com/alhassan73/open-wysiwyg-editor/main/.github/assets/banner.png" alt="Open WYSIWYG Editor — accessible, RTL-first rich text editor for every framework" width="100%"></a></p>
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # @open-wysiwyg-editor/angular
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@open-wysiwyg-editor/angular)](https://www.npmjs.com/package/@open-wysiwyg-editor/angular)
6
+ [![license](https://img.shields.io/npm/l/@open-wysiwyg-editor/angular)](https://github.com/alhassan73/open-wysiwyg-editor/blob/main/LICENSE)
7
+
8
+ **[Live demo →](https://alhassan73.github.io/open-wysiwyg-editor/)** · [GitHub](https://github.com/alhassan73/open-wysiwyg-editor) · [npm](https://www.npmjs.com/package/@open-wysiwyg-editor/angular)
9
+
10
+ Angular component for [open-wysiwyg-editor](https://github.com/alhassan73/open-wysiwyg-editor#readme): an accessible (WCAG 2.2 AA), RTL-first, CSP-safe rich text editor. It is a standalone component that works with `[(ngModel)]`, reactive forms, signals and Angular SSR.
11
+
12
+ Requires **Angular 21+**.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @open-wysiwyg-editor/angular
18
+ ```
19
+
20
+ This also installs the core package `open-wysiwyg-editor`. The package re-exports the whole core API (`createEditor`, `StarterKit`, types…), so you don't need to import from the core package yourself.
21
+
22
+ ## Setup
23
+
24
+ Add the stylesheet to `angular.json`:
25
+
26
+ ```json
27
+ "styles": [
28
+ "node_modules/@open-wysiwyg-editor/angular/style.css",
29
+ "src/styles.css"
30
+ ]
31
+ ```
32
+
33
+ Or import it in your global `styles.css`:
34
+
35
+ ```css
36
+ @import "@open-wysiwyg-editor/angular/style.css";
37
+ ```
38
+
39
+ `style.css` styles the toolbar and the editor. If you render saved HTML outside the editor, add `content.css` (the same content styles) to that page. Minified `style.min.css` and `content.min.css` are included.
40
+
41
+ ## Usage
42
+
43
+ ### Standalone component with `[(ngModel)]`
44
+
45
+ ```ts
46
+ import { Component } from "@angular/core";
47
+ import { FormsModule } from "@angular/forms";
48
+ import { RichTextEditorComponent } from "@open-wysiwyg-editor/angular";
49
+
50
+ @Component({
51
+ selector: "app-post",
52
+ imports: [FormsModule, RichTextEditorComponent],
53
+ template: `
54
+ <owe-rich-text-editor [(ngModel)]="html" placeholder="Write something…" />
55
+ <pre>{{ html }}</pre>
56
+ `,
57
+ })
58
+ export class PostComponent {
59
+ html = "<p>Hello <strong>world</strong></p>";
60
+ }
61
+ ```
62
+
63
+ ### Reactive forms
64
+
65
+ ```ts
66
+ import { Component, inject } from "@angular/core";
67
+ import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
68
+ import { RichTextEditorComponent } from "@open-wysiwyg-editor/angular";
69
+
70
+ @Component({
71
+ selector: "app-compose",
72
+ imports: [ReactiveFormsModule, RichTextEditorComponent],
73
+ template: `
74
+ <form [formGroup]="form" (ngSubmit)="save()">
75
+ <owe-rich-text-editor formControlName="body" />
76
+ @if (form.controls.body.touched && form.controls.body.errors) {
77
+ <p role="alert">Write something first.</p>
78
+ }
79
+ <button>Save</button>
80
+ </form>
81
+ `,
82
+ })
83
+ export class ComposeComponent {
84
+ form = inject(FormBuilder).nonNullable.group({
85
+ body: ["", [Validators.required, Validators.minLength(10)]],
86
+ });
87
+
88
+ save() {
89
+ console.log(this.form.getRawValue().body);
90
+ }
91
+ }
92
+ ```
93
+
94
+ The control is marked touched when the editor loses focus. `form.controls.body.disable()` makes the editor read-only.
95
+
96
+ ### Without forms: `[(value)]`
97
+
98
+ ```html
99
+ <owe-rich-text-editor [(value)]="html" />
100
+ ```
101
+
102
+ ### Signals
103
+
104
+ `value` is a regular input and `valueChange` is a regular output, so `[(value)]` works with a `model()` or `signal()`:
105
+
106
+ ```ts
107
+ import { Component, signal } from "@angular/core";
108
+ import { RichTextEditorComponent } from "@open-wysiwyg-editor/angular";
109
+
110
+ @Component({
111
+ selector: "app-note",
112
+ imports: [RichTextEditorComponent],
113
+ template: `
114
+ <owe-rich-text-editor [(value)]="html" />
115
+ <p>{{ html().length }} characters of HTML</p>
116
+ `,
117
+ })
118
+ export class NoteComponent {
119
+ html = signal("<p>Start here</p>");
120
+ }
121
+ ```
122
+
123
+ ### Options
124
+
125
+ `[options]` takes anything `createEditor()` accepts, except `element`. It is read **once, when the editor starts**. `placeholder` and `readonly` follow changes.
126
+
127
+ ```html
128
+ <owe-rich-text-editor
129
+ [(ngModel)]="html"
130
+ [options]="{ language: 'ar', dir: 'rtl', autofocus: true }"
131
+ placeholder="اكتب هنا…"
132
+ />
133
+ ```
134
+
135
+ See the [core docs](https://github.com/alhassan73/open-wysiwyg-editor#readme) for all options (extensions, labels, languages, URL policy, input rules…).
136
+
137
+ ### Get the editor: `(ready)`
138
+
139
+ ```ts
140
+ import type { Editor } from "@open-wysiwyg-editor/angular";
141
+
142
+ onReady(editor: Editor) {
143
+ editor.focus();
144
+ console.log(editor.getJSON());
145
+ }
146
+ ```
147
+
148
+ ```html
149
+ <owe-rich-text-editor [(ngModel)]="html" (ready)="onReady($event)" />
150
+ ```
151
+
152
+ You can also read it with a `viewChild`: `editor()?.editor` is `null` until the editor has started.
153
+
154
+ ### Read-only and disabled
155
+
156
+ ```html
157
+ <owe-rich-text-editor [value]="html" readonly />
158
+ ```
159
+
160
+ With forms, `FormControl.disable()` or `[disabled]` on the control does the same.
161
+
162
+ ### Server-side rendering
163
+
164
+ Nothing to configure. The editor starts in `afterNextRender`, so it never runs on the server, and it works with Angular SSR and hydration. The server renders an empty container, and the editor mounts in the browser. Its DOM listeners run outside the Angular zone, so typing doesn't trigger change detection except when the value changes.
165
+
166
+ ## API
167
+
168
+ ### Inputs
169
+
170
+ | Input | Type | Default | Notes |
171
+ | --- | --- | --- | --- |
172
+ | `value` | `string` | `undefined` | HTML content. Two-way with `[(value)]`. |
173
+ | `options` | `RichTextEditorOptions` | `{}` | `createEditor()` options without `element`. Read once at start. |
174
+ | `placeholder` | `string` | `undefined` | Overrides `options.placeholder`. Updates live. |
175
+ | `readonly` | `boolean` | `false` | Disables editing. Updates live. |
176
+
177
+ ### Outputs
178
+
179
+ | Output | Payload | Notes |
180
+ | --- | --- | --- |
181
+ | `valueChange` | `string` | The HTML after every change. |
182
+ | `ready` | `Editor` | Emitted once, in the browser, after the editor starts. |
183
+
184
+ ### Members
185
+
186
+ | Member | Notes |
187
+ | --- | --- |
188
+ | `editor` | The live `Editor`, or `null` before it starts (and on the server). |
189
+
190
+ Forms: implements `ControlValueAccessor` (value, disabled state, touched on blur).
191
+
192
+ ## Alternative: the `<owe-editor>` web component
193
+
194
+ The core package also ships a form-associated custom element. Use it if you prefer no Angular wrapper. Angular binds it with `ngDefaultControl`.
195
+
196
+ ```ts
197
+ // main.ts
198
+ import "open-wysiwyg-editor/element";
199
+ ```
200
+
201
+ ```ts
202
+ import { CUSTOM_ELEMENTS_SCHEMA, Component } from "@angular/core";
203
+ import { FormsModule } from "@angular/forms";
204
+
205
+ @Component({
206
+ selector: "app-post",
207
+ imports: [FormsModule],
208
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
209
+ template: `<owe-editor ngDefaultControl [(ngModel)]="html" language="ar"></owe-editor>`,
210
+ })
211
+ export class PostComponent {
212
+ html = "";
213
+ }
214
+ ```
215
+
216
+ You still need `style.css` from the setup above. See the core docs for the element's attributes and events.
217
+
218
+ ## Links
219
+
220
+ - [Core docs and options](https://github.com/alhassan73/open-wysiwyg-editor#readme)
221
+ - [Live demo and website](https://alhassan73.github.io/open-wysiwyg-editor/)
222
+ - [Report an issue](https://github.com/alhassan73/open-wysiwyg-editor/issues)
223
+
224
+ ## License
225
+
226
+ MIT © alhassan-ahmed
package/content.css ADDED
@@ -0,0 +1,323 @@
1
+ /*! open-wysiwyg-editor | MIT License */
2
+ /*
3
+ * Design tokens. Everything lives in the `owe` cascade layer, so any unlayered host CSS wins
4
+ * without !important. Override tokens on .owe (or :root) to theme the editor.
5
+ * Contrast: text >= 4.5:1, borders/focus/states >= 3:1 against --owe-bg (WCAG 1.4.3 / 1.4.11).
6
+ *
7
+ * Tokens added in 1.0 (existing names keep working):
8
+ * --owe-radius card radius (24px) --owe-radius-sm inner controls (10px)
9
+ * --owe-radius-md menus (12px) --owe-radius-lg dialogs (16px)
10
+ * --owe-btn-size toolbar button (40px) --owe-pad-x/-y editing-area padding
11
+ * --owe-chrome toolbar / status bar surface
12
+ * --owe-field-bg inputs and source view --owe-popup-border menu / dialog edge
13
+ * --owe-body paragraph text --owe-text-2 secondary text (quotes)
14
+ * --owe-icon toolbar icon color --owe-caret caret color
15
+ * --owe-primary(-hover) solid fills: pressed buttons, primary buttons (white text, 4.8:1)
16
+ * --owe-gradient bottom edge of the card --owe-backdrop dialog backdrop
17
+ * --owe-accent is the TEXT/link/focus blue; --owe-primary is the FILL blue.
18
+ * Set --owe-font (e.g. "Almarai", system-ui) to change the typeface; no web fonts are bundled.
19
+ */
20
+ @layer owe {
21
+ .owe,
22
+ .owe-content-root {
23
+ --owe-font: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans Arabic", "Noto Sans", Tahoma, sans-serif;
24
+ --owe-font-mono: ui-monospace, "JetBrains Mono", "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;
25
+ --owe-font-size: 1rem;
26
+ --owe-line-height: 1.65;
27
+ --owe-radius: 24px;
28
+ --owe-radius-sm: 10px;
29
+ --owe-radius-md: 12px;
30
+ --owe-radius-lg: 16px;
31
+ --owe-space: 8px;
32
+ --owe-target: 32px; /* >= 24px (WCAG 2.5.8); 32px is comfortable */
33
+ --owe-btn-size: 40px;
34
+ --owe-pad-x: clamp(16px, 4vw, 32px);
35
+ --owe-pad-y: 28px;
36
+ --owe-gradient: linear-gradient(90deg, #0066ff, #9644ff, #af47c0);
37
+
38
+ --owe-bg: #ffffff;
39
+ --owe-chrome: #fafbfc;
40
+ --owe-surface: #f4f6f8;
41
+ --owe-surface-2: #f1f3f5;
42
+ --owe-field-bg: #ffffff;
43
+ --owe-text: #101112;
44
+ --owe-body: #1b1f24;
45
+ --owe-text-2: #3d434a;
46
+ --owe-muted: #54595f; /* 7:1 on white */
47
+ --owe-icon: #3a3f45;
48
+ --owe-border: #8a929a; /* 3.2:1 on white */
49
+ --owe-border-subtle: #e3e6ea;
50
+ --owe-popup-border: #d5d9de;
51
+ --owe-accent: #0057d9; /* 6.2:1 on white */
52
+ --owe-on-accent: #ffffff;
53
+ --owe-primary: #0066ff;
54
+ --owe-primary-hover: #0057d9;
55
+ --owe-accent-soft: #d3e3fd;
56
+ --owe-focus: #0066ff;
57
+ --owe-caret: #0066ff;
58
+ --owe-danger: #b3261e;
59
+ --owe-warning: #8a5300;
60
+ --owe-success: #146c2e;
61
+ --owe-selection: rgb(0 102 255 / 0.22);
62
+ --owe-code-bg: #f4f6f8;
63
+ --owe-mark: #fff2a8;
64
+ --owe-shadow: 0 16px 40px rgb(16 17 18 / 0.16), 0 2px 8px rgb(16 17 18 / 0.08);
65
+ --owe-backdrop: rgb(16 17 18 / 0.45);
66
+ --owe-z-popover: 1000;
67
+
68
+ color-scheme: light;
69
+ }
70
+
71
+ @media (prefers-color-scheme: dark) {
72
+ .owe:not([data-theme="light"]),
73
+ .owe-content-root:not([data-theme="light"]) {
74
+ --owe-bg: #17191b;
75
+ --owe-chrome: #131517;
76
+ --owe-surface: #1e2124;
77
+ --owe-surface-2: #25282b;
78
+ --owe-field-bg: #101214;
79
+ --owe-text: #ffffff;
80
+ --owe-body: #dcdedf;
81
+ --owe-text-2: #c3c7cb;
82
+ --owe-muted: #a1a7ad;
83
+ --owe-icon: #d2d4d5;
84
+ --owe-border: #6b7279;
85
+ --owe-border-subtle: #25282b;
86
+ --owe-popup-border: #33383d;
87
+ --owe-accent: #4d94ff;
88
+ --owe-on-accent: #ffffff;
89
+ --owe-primary: #0066ff;
90
+ --owe-primary-hover: #0057d9;
91
+ --owe-accent-soft: #14315e;
92
+ --owe-focus: #4d94ff;
93
+ --owe-caret: #5b9dff;
94
+ --owe-danger: #f2b8b5;
95
+ --owe-warning: #f6c66b;
96
+ --owe-success: #8bd6a0;
97
+ --owe-selection: rgb(0 102 255 / 0.55);
98
+ --owe-code-bg: #0f1112;
99
+ --owe-mark: #4a35b8;
100
+ --owe-shadow: 0 16px 40px rgb(0 0 0 / 0.55), 0 2px 8px rgb(0 0 0 / 0.4);
101
+ --owe-backdrop: rgb(4 5 16 / 0.65);
102
+ color-scheme: dark;
103
+ }
104
+ }
105
+
106
+ .owe[data-theme="dark"],
107
+ .owe-content-root[data-theme="dark"] {
108
+ --owe-bg: #17191b;
109
+ --owe-chrome: #131517;
110
+ --owe-surface: #1e2124;
111
+ --owe-surface-2: #25282b;
112
+ --owe-field-bg: #101214;
113
+ --owe-text: #ffffff;
114
+ --owe-body: #dcdedf;
115
+ --owe-text-2: #c3c7cb;
116
+ --owe-muted: #a1a7ad;
117
+ --owe-icon: #d2d4d5;
118
+ --owe-border: #6b7279;
119
+ --owe-border-subtle: #25282b;
120
+ --owe-popup-border: #33383d;
121
+ --owe-accent: #4d94ff;
122
+ --owe-on-accent: #ffffff;
123
+ --owe-primary: #0066ff;
124
+ --owe-primary-hover: #0057d9;
125
+ --owe-accent-soft: #14315e;
126
+ --owe-focus: #4d94ff;
127
+ --owe-caret: #5b9dff;
128
+ --owe-danger: #f2b8b5;
129
+ --owe-warning: #f6c66b;
130
+ --owe-success: #8bd6a0;
131
+ --owe-selection: rgb(0 102 255 / 0.55);
132
+ --owe-code-bg: #0f1112;
133
+ --owe-mark: #4a35b8;
134
+ --owe-shadow: 0 16px 40px rgb(0 0 0 / 0.55), 0 2px 8px rgb(0 0 0 / 0.4);
135
+ --owe-backdrop: rgb(4 5 16 / 0.65);
136
+ color-scheme: dark;
137
+ }
138
+
139
+ @media (prefers-contrast: more) {
140
+ .owe {
141
+ --owe-border: currentColor;
142
+ --owe-border-subtle: var(--owe-border);
143
+ --owe-popup-border: var(--owe-border);
144
+ --owe-muted: var(--owe-text);
145
+ --owe-text-2: var(--owe-text);
146
+ }
147
+ }
148
+ }
149
+
150
+ /*
151
+ * Content styles — shared by the editing area (.owe-content) and published pages
152
+ * (wrap saved HTML in <div class="owe-content-root">), so what authors see is what readers get.
153
+ */
154
+ @layer owe {
155
+ :is(.owe-content, .owe-content-root) {
156
+ font-family: var(--owe-font);
157
+ font-size: var(--owe-font-size);
158
+ line-height: var(--owe-line-height);
159
+ color: var(--owe-body);
160
+ overflow-wrap: break-word;
161
+ }
162
+
163
+ :is(.owe-content, .owe-content-root) > :first-child {
164
+ margin-block-start: 0;
165
+ }
166
+
167
+ :is(.owe-content, .owe-content-root) :is(p, ul, ol, blockquote, pre, table, figure, hr) {
168
+ margin-block: 0 0.85em;
169
+ }
170
+
171
+ :is(.owe-content, .owe-content-root) :is(h1, h2, h3, h4, h5, h6) {
172
+ line-height: 1.2;
173
+ margin-block: 1.3em 0.5em;
174
+ font-weight: 700;
175
+ letter-spacing: -0.02em;
176
+ color: var(--owe-text);
177
+ }
178
+ /* Negative tracking breaks Arabic joining: reset for RTL / Arabic-script content. */
179
+ :is(.owe-content, .owe-content-root) :is(h1, h2, h3, h4, h5, h6):is([dir="rtl"], :lang(ar), :lang(fa), :lang(ur), :lang(he)),
180
+ :is([dir="rtl"], :lang(ar), :lang(fa), :lang(ur), :lang(he)) :is(.owe-content, .owe-content-root) :is(h1, h2, h3, h4, h5, h6),
181
+ :is(.owe-content, .owe-content-root):is([dir="rtl"], :lang(ar), :lang(fa), :lang(ur), :lang(he)) :is(h1, h2, h3, h4, h5, h6) {
182
+ letter-spacing: 0;
183
+ }
184
+ :is(.owe-content, .owe-content-root) h1 { font-size: 2.1em; }
185
+ :is(.owe-content, .owe-content-root) h2 { font-size: 1.5em; }
186
+ :is(.owe-content, .owe-content-root) h3 { font-size: 1.25em; }
187
+ :is(.owe-content, .owe-content-root) h4 { font-size: 1.1em; }
188
+ :is(.owe-content, .owe-content-root) h5 { font-size: 1em; }
189
+ :is(.owe-content, .owe-content-root) h6 { font-size: 0.9em; }
190
+
191
+ :is(.owe-content, .owe-content-root) a {
192
+ color: var(--owe-accent);
193
+ text-decoration: underline; /* never colour alone (WCAG 1.4.1) */
194
+ text-underline-offset: 0.15em;
195
+ }
196
+
197
+ :is(.owe-content, .owe-content-root) :is(ul, ol) {
198
+ padding-inline-start: 1.6em;
199
+ }
200
+ :is(.owe-content, .owe-content-root) li > :is(p, ul, ol) {
201
+ margin-block: 0.15em;
202
+ }
203
+
204
+ :is(.owe-content, .owe-content-root) ul[data-type="taskList"] {
205
+ list-style: none;
206
+ padding-inline-start: 0.25em;
207
+ }
208
+ :is(.owe-content, .owe-content-root) li[data-type="taskItem"] {
209
+ display: flex;
210
+ align-items: flex-start;
211
+ gap: 0.5em;
212
+ }
213
+ :is(.owe-content, .owe-content-root) li[data-type="taskItem"] > input,
214
+ .owe-task-control > input {
215
+ inline-size: 1.1em;
216
+ block-size: 1.1em;
217
+ margin-block-start: 0.3em;
218
+ accent-color: var(--owe-primary);
219
+ flex: none;
220
+ }
221
+ :is(.owe-content, .owe-content-root) li[data-type="taskItem"] > div {
222
+ flex: 1;
223
+ min-inline-size: 0;
224
+ }
225
+ :is(.owe-content, .owe-content-root) li[data-checked="true"] > div {
226
+ text-decoration: line-through;
227
+ color: var(--owe-muted);
228
+ }
229
+
230
+ :is(.owe-content, .owe-content-root) blockquote {
231
+ margin-inline: 0;
232
+ padding-inline-start: 1em;
233
+ border-inline-start: 3px solid var(--owe-accent);
234
+ border-start-start-radius: 2px;
235
+ border-end-start-radius: 2px;
236
+ color: var(--owe-text-2);
237
+ }
238
+
239
+ :is(.owe-content, .owe-content-root) code {
240
+ font-family: var(--owe-font-mono);
241
+ font-size: 0.9em;
242
+ background: var(--owe-code-bg);
243
+ border: 1px solid var(--owe-border-subtle);
244
+ border-radius: 6px;
245
+ padding: 0.1em 0.35em;
246
+ }
247
+ :is(.owe-content, .owe-content-root) pre {
248
+ font-family: var(--owe-font-mono);
249
+ background: var(--owe-code-bg);
250
+ border: 1px solid var(--owe-border-subtle);
251
+ border-radius: var(--owe-radius-md);
252
+ padding: 1em 1.25em;
253
+ overflow-x: auto;
254
+ direction: ltr; /* code is left-to-right even in RTL documents */
255
+ text-align: start;
256
+ tab-size: 2;
257
+ }
258
+ :is(.owe-content, .owe-content-root) pre code {
259
+ background: none;
260
+ border: 0;
261
+ padding: 0;
262
+ font-size: 0.9em;
263
+ }
264
+
265
+ :is(.owe-content, .owe-content-root) hr {
266
+ border: none;
267
+ border-block-start: 2px solid var(--owe-border-subtle);
268
+ margin-block: 1.5em;
269
+ }
270
+
271
+ :is(.owe-content, .owe-content-root) img {
272
+ max-inline-size: 100%;
273
+ block-size: auto;
274
+ display: block;
275
+ }
276
+ :is(.owe-content, .owe-content-root) figure {
277
+ margin-inline: 0;
278
+ }
279
+ :is(.owe-content, .owe-content-root) figcaption {
280
+ color: var(--owe-muted);
281
+ font-size: 0.9em;
282
+ margin-block-start: 0.4em;
283
+ }
284
+
285
+ :is(.owe-content, .owe-content-root) table {
286
+ border-collapse: collapse;
287
+ inline-size: 100%;
288
+ table-layout: fixed;
289
+ }
290
+ :is(.owe-content, .owe-content-root) caption {
291
+ caption-side: top;
292
+ text-align: start;
293
+ font-weight: 600;
294
+ padding-block-end: 0.4em;
295
+ }
296
+ :is(.owe-content, .owe-content-root) :is(td, th) {
297
+ border: 1px solid var(--owe-border-subtle);
298
+ padding: 0.55em 0.8em;
299
+ vertical-align: top;
300
+ text-align: start;
301
+ min-inline-size: 3em;
302
+ }
303
+ :is(.owe-content, .owe-content-root) th {
304
+ background: var(--owe-surface);
305
+ color: var(--owe-text);
306
+ font-weight: 700;
307
+ }
308
+ :is(.owe-content, .owe-content-root) :is(td, th) > :last-child {
309
+ margin-block-end: 0;
310
+ }
311
+
312
+ :is(.owe-content, .owe-content-root) mark {
313
+ background-color: var(--owe-mark);
314
+ color: inherit;
315
+ border-radius: 0.2em;
316
+ padding-inline: 0.15em;
317
+ }
318
+
319
+ /* Alignment classes (used by the editor always, and by output when TextAlign output: "class"). */
320
+ .owe-align-center { text-align: center; }
321
+ .owe-align-end { text-align: end; }
322
+ .owe-align-justify { text-align: justify; }
323
+ }
@@ -0,0 +1,2 @@
1
+ /*! open-wysiwyg-editor | MIT License */
2
+ /*! open-wysiwyg-editor | MIT License */ @layer owe{.owe,.owe-content-root{--owe-font:system-ui,-apple-system,"Segoe UI",Roboto,"Noto Sans Arabic","Noto Sans",Tahoma,sans-serif;--owe-font-mono:ui-monospace,"JetBrains Mono","SFMono-Regular",Menlo,Consolas,"Liberation Mono",monospace;--owe-font-size:1rem;--owe-line-height:1.65;--owe-radius:24px;--owe-radius-sm:10px;--owe-radius-md:12px;--owe-radius-lg:16px;--owe-space:8px;--owe-target:32px;--owe-btn-size:40px;--owe-pad-x:clamp(16px,4vw,32px);--owe-pad-y:28px;--owe-gradient:linear-gradient(90deg,#0066ff,#9644ff,#af47c0);--owe-bg:#ffffff;--owe-chrome:#fafbfc;--owe-surface:#f4f6f8;--owe-surface-2:#f1f3f5;--owe-field-bg:#ffffff;--owe-text:#101112;--owe-body:#1b1f24;--owe-text-2:#3d434a;--owe-muted:#54595f;--owe-icon:#3a3f45;--owe-border:#8a929a;--owe-border-subtle:#e3e6ea;--owe-popup-border:#d5d9de;--owe-accent:#0057d9;--owe-on-accent:#ffffff;--owe-primary:#0066ff;--owe-primary-hover:#0057d9;--owe-accent-soft:#d3e3fd;--owe-focus:#0066ff;--owe-caret:#0066ff;--owe-danger:#b3261e;--owe-warning:#8a5300;--owe-success:#146c2e;--owe-selection:rgb(0 102 255 / 0.22);--owe-code-bg:#f4f6f8;--owe-mark:#fff2a8;--owe-shadow:0 16px 40px rgb(16 17 18 / 0.16),0 2px 8px rgb(16 17 18 / 0.08);--owe-backdrop:rgb(16 17 18 / 0.45);--owe-z-popover:1000;color-scheme:light}@media (prefers-color-scheme:dark){.owe:not([data-theme="light"]),.owe-content-root:not([data-theme="light"]){--owe-bg:#17191b;--owe-chrome:#131517;--owe-surface:#1e2124;--owe-surface-2:#25282b;--owe-field-bg:#101214;--owe-text:#ffffff;--owe-body:#dcdedf;--owe-text-2:#c3c7cb;--owe-muted:#a1a7ad;--owe-icon:#d2d4d5;--owe-border:#6b7279;--owe-border-subtle:#25282b;--owe-popup-border:#33383d;--owe-accent:#4d94ff;--owe-on-accent:#ffffff;--owe-primary:#0066ff;--owe-primary-hover:#0057d9;--owe-accent-soft:#14315e;--owe-focus:#4d94ff;--owe-caret:#5b9dff;--owe-danger:#f2b8b5;--owe-warning:#f6c66b;--owe-success:#8bd6a0;--owe-selection:rgb(0 102 255 / 0.55);--owe-code-bg:#0f1112;--owe-mark:#4a35b8;--owe-shadow:0 16px 40px rgb(0 0 0 / 0.55),0 2px 8px rgb(0 0 0 / 0.4);--owe-backdrop:rgb(4 5 16 / 0.65);color-scheme:dark}}.owe[data-theme="dark"],.owe-content-root[data-theme="dark"]{--owe-bg:#17191b;--owe-chrome:#131517;--owe-surface:#1e2124;--owe-surface-2:#25282b;--owe-field-bg:#101214;--owe-text:#ffffff;--owe-body:#dcdedf;--owe-text-2:#c3c7cb;--owe-muted:#a1a7ad;--owe-icon:#d2d4d5;--owe-border:#6b7279;--owe-border-subtle:#25282b;--owe-popup-border:#33383d;--owe-accent:#4d94ff;--owe-on-accent:#ffffff;--owe-primary:#0066ff;--owe-primary-hover:#0057d9;--owe-accent-soft:#14315e;--owe-focus:#4d94ff;--owe-caret:#5b9dff;--owe-danger:#f2b8b5;--owe-warning:#f6c66b;--owe-success:#8bd6a0;--owe-selection:rgb(0 102 255 / 0.55);--owe-code-bg:#0f1112;--owe-mark:#4a35b8;--owe-shadow:0 16px 40px rgb(0 0 0 / 0.55),0 2px 8px rgb(0 0 0 / 0.4);--owe-backdrop:rgb(4 5 16 / 0.65);color-scheme:dark}@media (prefers-contrast:more){.owe{--owe-border:currentColor;--owe-border-subtle:var(--owe-border);--owe-popup-border:var(--owe-border);--owe-muted:var(--owe-text);--owe-text-2:var(--owe-text)}}}@layer owe{:is(.owe-content,.owe-content-root){font-family:var(--owe-font);font-size:var(--owe-font-size);line-height:var(--owe-line-height);color:var(--owe-body);overflow-wrap:break-word}:is(.owe-content,.owe-content-root)>:first-child{margin-block-start:0}:is(.owe-content,.owe-content-root) :is(p,ul,ol,blockquote,pre,table,figure,hr){margin-block:0 0.85em}:is(.owe-content,.owe-content-root) :is(h1,h2,h3,h4,h5,h6){line-height:1.2;margin-block:1.3em 0.5em;font-weight:700;letter-spacing:-0.02em;color:var(--owe-text)}:is(.owe-content,.owe-content-root) :is(h1,h2,h3,h4,h5,h6):is([dir="rtl"],:lang(ar),:lang(fa),:lang(ur),:lang(he)),:is([dir="rtl"],:lang(ar),:lang(fa),:lang(ur),:lang(he)) :is(.owe-content,.owe-content-root) :is(h1,h2,h3,h4,h5,h6),:is(.owe-content,.owe-content-root):is([dir="rtl"],:lang(ar),:lang(fa),:lang(ur),:lang(he)) :is(h1,h2,h3,h4,h5,h6){letter-spacing:0}:is(.owe-content,.owe-content-root) h1{font-size:2.1em}:is(.owe-content,.owe-content-root) h2{font-size:1.5em}:is(.owe-content,.owe-content-root) h3{font-size:1.25em}:is(.owe-content,.owe-content-root) h4{font-size:1.1em}:is(.owe-content,.owe-content-root) h5{font-size:1em}:is(.owe-content,.owe-content-root) h6{font-size:0.9em}:is(.owe-content,.owe-content-root) a{color:var(--owe-accent);text-decoration:underline;text-underline-offset:0.15em}:is(.owe-content,.owe-content-root) :is(ul,ol){padding-inline-start:1.6em}:is(.owe-content,.owe-content-root) li>:is(p,ul,ol){margin-block:0.15em}:is(.owe-content,.owe-content-root) ul[data-type="taskList"]{list-style:none;padding-inline-start:0.25em}:is(.owe-content,.owe-content-root) li[data-type="taskItem"]{display:flex;align-items:flex-start;gap:0.5em}:is(.owe-content,.owe-content-root) li[data-type="taskItem"]>input,.owe-task-control>input{inline-size:1.1em;block-size:1.1em;margin-block-start:0.3em;accent-color:var(--owe-primary);flex:none}:is(.owe-content,.owe-content-root) li[data-type="taskItem"]>div{flex:1;min-inline-size:0}:is(.owe-content,.owe-content-root) li[data-checked="true"]>div{text-decoration:line-through;color:var(--owe-muted)}:is(.owe-content,.owe-content-root) blockquote{margin-inline:0;padding-inline-start:1em;border-inline-start:3px solid var(--owe-accent);border-start-start-radius:2px;border-end-start-radius:2px;color:var(--owe-text-2)}:is(.owe-content,.owe-content-root) code{font-family:var(--owe-font-mono);font-size:0.9em;background:var(--owe-code-bg);border:1px solid var(--owe-border-subtle);border-radius:6px;padding:0.1em 0.35em}:is(.owe-content,.owe-content-root) pre{font-family:var(--owe-font-mono);background:var(--owe-code-bg);border:1px solid var(--owe-border-subtle);border-radius:var(--owe-radius-md);padding:1em 1.25em;overflow-x:auto;direction:ltr;text-align:start;tab-size:2}:is(.owe-content,.owe-content-root) pre code{background:none;border:0;padding:0;font-size:0.9em}:is(.owe-content,.owe-content-root) hr{border:none;border-block-start:2px solid var(--owe-border-subtle);margin-block:1.5em}:is(.owe-content,.owe-content-root) img{max-inline-size:100%;block-size:auto;display:block}:is(.owe-content,.owe-content-root) figure{margin-inline:0}:is(.owe-content,.owe-content-root) figcaption{color:var(--owe-muted);font-size:0.9em;margin-block-start:0.4em}:is(.owe-content,.owe-content-root) table{border-collapse:collapse;inline-size:100%;table-layout:fixed}:is(.owe-content,.owe-content-root) caption{caption-side:top;text-align:start;font-weight:600;padding-block-end:0.4em}:is(.owe-content,.owe-content-root) :is(td,th){border:1px solid var(--owe-border-subtle);padding:0.55em 0.8em;vertical-align:top;text-align:start;min-inline-size:3em}:is(.owe-content,.owe-content-root) th{background:var(--owe-surface);color:var(--owe-text);font-weight:700}:is(.owe-content,.owe-content-root) :is(td,th)>:last-child{margin-block-end:0}:is(.owe-content,.owe-content-root) mark{background-color:var(--owe-mark);color:inherit;border-radius:0.2em;padding-inline:0.15em}.owe-align-center{text-align:center}.owe-align-end{text-align:end}.owe-align-justify{text-align:justify}}