smeditor 0.2.5 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +3 -0
- data/app/assets/javascripts/smeditor.js +20 -10
- data/app/assets/stylesheets/smeditor.css +6 -36
- data/lib/generators/smeditor/templates/initializer.rb +3 -0
- data/lib/smeditor/rails/config.rb +3 -0
- data/lib/smeditor/rails/form_helper.rb +26 -10
- data/lib/smeditor/rails/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 37d69366d661f31b412b1225d656367136e26de3ac8ad98988ceeaf251ddc942
|
|
4
|
+
data.tar.gz: fbc0c5332adb77f6a42b1716c403a31e3dd21d8eb79919ee214073a69caab8ed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5db1e9fa62c9bf728776931b9276184d18b85c36e586efbe907fae818cd6ecf4785d8144e66b922a3e567f64db97a546d96ca3ee4ecd5b8aa3c655b7933bd496
|
|
7
|
+
data.tar.gz: 9426a009a1184a403397818a2f37600702dbf72c3ecaa73bd7c0ffff44ab0f638416b033cc8e3208bbce664fba1fca97182bb7410b61e5b69dcc9bbff4f4f4ec
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog — smeditor
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-09-13
|
|
4
|
+
|
|
5
|
+
- Added explicit `light` and `dark` theme selection across Core, React, and the Rails adapter. Rails now also supports a global `config.default_theme` and per-editor `theme` option.
|
|
6
|
+
- The editor now defaults to the light theme when no theme is configured; dark mode is enabled only when explicitly requested, instead of following `prefers-color-scheme`.
|
|
7
|
+
- Fixed React `EditorContent` overriding an editor created with `editable: false` back to an editable surface when the `editable` prop is omitted.
|
|
8
|
+
|
|
3
9
|
## 0.2.5 — 2026-09-09
|
|
4
10
|
|
|
5
11
|
- Fixed the Rails selected-text bubble toolbar being displaced to the right or vertically aligned with the text when the host application creates a CSS containing block (for example with `transform`, `filter`, `perspective`, or modal/animated wrappers).
|
data/README.md
CHANGED
|
@@ -42,6 +42,7 @@ SMEditor.configure do |config|
|
|
|
42
42
|
config.uploads = :none # or :active_storage
|
|
43
43
|
config.upload_path = "/smeditor/uploads"
|
|
44
44
|
config.default_kit = "starter" # or "full"
|
|
45
|
+
config.default_theme = "light" # or "dark"
|
|
45
46
|
config.min_height = 320 # desktop, px when numeric
|
|
46
47
|
config.tablet_min_height = 280 # <= 1024px
|
|
47
48
|
config.mobile_min_height = 220 # <= 640px
|
|
@@ -64,6 +65,7 @@ end
|
|
|
64
65
|
<%= form_with model: @article do |form| %>
|
|
65
66
|
<%= form.smeditor_editor :content,
|
|
66
67
|
kit: "full",
|
|
68
|
+
theme: "light",
|
|
67
69
|
placeholder: "Write…",
|
|
68
70
|
min_height: 420,
|
|
69
71
|
tablet_min_height: 340,
|
|
@@ -81,6 +83,7 @@ observe the value without CKEditor-specific integration.
|
|
|
81
83
|
Available options:
|
|
82
84
|
|
|
83
85
|
- `kit: "starter" | "full"`
|
|
86
|
+
- `theme: "light" | "dark"` — defaults to `config.default_theme` (`"light"`)
|
|
84
87
|
- `placeholder:`
|
|
85
88
|
- `class:`
|
|
86
89
|
- `label:` — editor ARIA label
|
|
@@ -595,10 +595,15 @@ function bootMount(mount) {
|
|
|
595
595
|
const kit = mount.dataset.smeditorKit === "full" ? "full" : "starter";
|
|
596
596
|
const uploadUrl = mount.dataset.smeditorUploadUrl || undefined;
|
|
597
597
|
const placeholder = mount.dataset.smeditorPlaceholder || undefined;
|
|
598
|
-
const
|
|
598
|
+
const configuredTheme = mount.dataset.smeditorTheme;
|
|
599
|
+
const inheritedTheme = ((_b = (_a = mount.parentElement) === null || _a === void 0 ? void 0 : _a.closest("[data-theme]")) === null || _b === void 0 ? void 0 : _b.dataset.theme)
|
|
599
600
|
|| document.documentElement.dataset.theme;
|
|
600
|
-
|
|
601
|
-
|
|
601
|
+
const theme = configuredTheme === "dark" || configuredTheme === "light"
|
|
602
|
+
? configuredTheme
|
|
603
|
+
: inheritedTheme === "dark" || inheritedTheme === "light"
|
|
604
|
+
? inheritedTheme
|
|
605
|
+
: "light";
|
|
606
|
+
mount.dataset.theme = theme;
|
|
602
607
|
const root = shadowRootFor(mount);
|
|
603
608
|
const shell = document.createElement("div");
|
|
604
609
|
shell.className = "smeditor";
|
|
@@ -621,6 +626,7 @@ function bootMount(mount) {
|
|
|
621
626
|
extensions: kitExtensions(kit, uploadUrl),
|
|
622
627
|
content: input.value || "<p></p>",
|
|
623
628
|
placeholder,
|
|
629
|
+
theme,
|
|
624
630
|
deepSelection: true,
|
|
625
631
|
onUpdate: ({ editor: current }) => {
|
|
626
632
|
input.value = current.getHTML();
|
|
@@ -800,7 +806,7 @@ function createEditor(options) {
|
|
|
800
806
|
}
|
|
801
807
|
class Editor {
|
|
802
808
|
constructor(options) {
|
|
803
|
-
var _a, _b, _c;
|
|
809
|
+
var _a, _b, _c, _d;
|
|
804
810
|
this.selection = null;
|
|
805
811
|
this.history = new history_js_1.History();
|
|
806
812
|
this.emitter = new events_js_1.EventEmitter();
|
|
@@ -830,10 +836,13 @@ class Editor {
|
|
|
830
836
|
// Capture the finished composed text in one shot.
|
|
831
837
|
this.handleDOMInput();
|
|
832
838
|
};
|
|
833
|
-
this.options =
|
|
834
|
-
|
|
839
|
+
this.options = {
|
|
840
|
+
...options,
|
|
841
|
+
theme: (_a = options.theme) !== null && _a !== void 0 ? _a : "light",
|
|
842
|
+
};
|
|
843
|
+
this.element = (_b = options.element) !== null && _b !== void 0 ? _b : null;
|
|
835
844
|
// 1. Resolve extensions
|
|
836
|
-
this.extensions = (0, schema_js_1.flattenExtensions)((
|
|
845
|
+
this.extensions = (0, schema_js_1.flattenExtensions)((_c = options.extensions) !== null && _c !== void 0 ? _c : []);
|
|
837
846
|
// 2. Compile schema
|
|
838
847
|
this.schema = (0, schema_js_1.compileSchema)(this.extensions);
|
|
839
848
|
// 3. Normalize initial content into JSON
|
|
@@ -842,7 +851,7 @@ class Editor {
|
|
|
842
851
|
this.commands = this.buildCommandMap();
|
|
843
852
|
// 5. Lifecycle: onCreate for each extension
|
|
844
853
|
for (const ext of this.extensions) {
|
|
845
|
-
(
|
|
854
|
+
(_d = ext.onCreate) === null || _d === void 0 ? void 0 : _d.call(ext, this);
|
|
846
855
|
}
|
|
847
856
|
// 6. Mount to DOM if an element was given
|
|
848
857
|
if (this.element) {
|
|
@@ -1129,9 +1138,10 @@ class Editor {
|
|
|
1129
1138
|
this.attachToElement();
|
|
1130
1139
|
}
|
|
1131
1140
|
attachToElement() {
|
|
1132
|
-
var _a;
|
|
1141
|
+
var _a, _b;
|
|
1133
1142
|
const el = this.element;
|
|
1134
1143
|
el.setAttribute("contenteditable", String(this.options.editable !== false));
|
|
1144
|
+
el.setAttribute("data-theme", (_a = this.options.theme) !== null && _a !== void 0 ? _a : "light");
|
|
1135
1145
|
el.classList.add("smeditor-editor");
|
|
1136
1146
|
el.addEventListener("input", this.onDomInput);
|
|
1137
1147
|
el.addEventListener("beforeinput", this.onDomBeforeInput);
|
|
@@ -1145,7 +1155,7 @@ class Editor {
|
|
|
1145
1155
|
// Keep the model selection in sync in both regular DOM and Shadow DOM.
|
|
1146
1156
|
// Chromium exposes the live shadow selection on ShadowRoot; listening to
|
|
1147
1157
|
// that root as well as Document avoids missing drag-selection events.
|
|
1148
|
-
const root = (
|
|
1158
|
+
const root = (_b = el.getRootNode) === null || _b === void 0 ? void 0 : _b.call(el);
|
|
1149
1159
|
const targets = [document];
|
|
1150
1160
|
if (root && root !== document && "addEventListener" in root)
|
|
1151
1161
|
targets.push(root);
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
/* SMEditor default theme tokens.
|
|
2
2
|
*
|
|
3
|
-
*
|
|
3
|
+
* Theme selection:
|
|
4
4
|
*
|
|
5
|
-
* 1. Do nothing →
|
|
6
|
-
* 2. Set `data-theme="light"` or `data-theme="dark"` on
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Why both: developers want auto for new users (matches the rest of
|
|
11
|
-
* their app), but a theme toggle in product UI needs explicit control
|
|
12
|
-
* that survives reloads. Supporting both lets either pattern work.
|
|
5
|
+
* 1. Do nothing → light theme.
|
|
6
|
+
* 2. Set `data-theme="light"` or `data-theme="dark"` on the editor or
|
|
7
|
+
* on an ancestor. SMEditor sets `data-theme="light"` by default when
|
|
8
|
+
* initialized without a theme option.
|
|
13
9
|
*/
|
|
14
10
|
|
|
15
11
|
/* ---------------------------------------------------------------------------
|
|
@@ -87,8 +83,7 @@
|
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
/* ---------------------------------------------------------------------------
|
|
90
|
-
* Dark theme — applied when explicitly tagged
|
|
91
|
-
* no explicit theme is set on the document.
|
|
86
|
+
* Dark theme — applied only when explicitly tagged.
|
|
92
87
|
* ------------------------------------------------------------------------ */
|
|
93
88
|
:host([data-theme="dark"]),
|
|
94
89
|
[data-theme="dark"] {
|
|
@@ -110,31 +105,6 @@
|
|
|
110
105
|
0 10px 20px -15px rgba(0, 0, 0, 0.45);
|
|
111
106
|
}
|
|
112
107
|
|
|
113
|
-
/* Auto-dark: only when the document root has no explicit override. The
|
|
114
|
-
* `:not([data-theme])` guard means a `data-theme="light"` setting on
|
|
115
|
-
* any ancestor wins, even at night. */
|
|
116
|
-
@media (prefers-color-scheme: dark) {
|
|
117
|
-
:root:not([data-theme="light"]),
|
|
118
|
-
:host(:not([data-theme="light"])) {
|
|
119
|
-
--sme-color-surface: #0f1115;
|
|
120
|
-
--sme-color-surface-muted: #1a1d23;
|
|
121
|
-
--sme-color-border: #2a2d35;
|
|
122
|
-
--sme-color-border-strong: #3a3f49;
|
|
123
|
-
--sme-color-text: #e7e9ee;
|
|
124
|
-
--sme-color-text-muted: #9aa0aa;
|
|
125
|
-
--sme-color-placeholder: #5c606b;
|
|
126
|
-
--sme-color-accent: #a78bfa;
|
|
127
|
-
--sme-color-accent-soft: #2a1d54;
|
|
128
|
-
--sme-color-primary: var(--sme-color-accent);
|
|
129
|
-
--sme-color-focus: #c4b5fd;
|
|
130
|
-
--sme-color-danger: #fca5a5;
|
|
131
|
-
--sme-color-danger-soft: #451a1a;
|
|
132
|
-
--sme-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
|
|
133
|
-
--sme-shadow-md: 0 10px 38px -10px rgba(0, 0, 0, 0.5),
|
|
134
|
-
0 10px 20px -15px rgba(0, 0, 0, 0.45);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
108
|
/* SMEditor default theme.
|
|
139
109
|
*
|
|
140
110
|
* Imports tokens, then styles the structural classes set by core
|
|
@@ -14,6 +14,9 @@ SMEditor.configure do |config|
|
|
|
14
14
|
# "starter" gives the MVP toolbar; "full" enables the larger extension set.
|
|
15
15
|
config.default_kit = "starter"
|
|
16
16
|
|
|
17
|
+
# "light" is the default. Set "dark" globally or pass theme: per editor.
|
|
18
|
+
config.default_theme = "light"
|
|
19
|
+
|
|
17
20
|
# Responsive minimum editor height. Numeric values are pixels. You can also
|
|
18
21
|
# use CSS lengths such as "24rem" or "45vh".
|
|
19
22
|
config.min_height = 320
|
|
@@ -18,6 +18,8 @@ module SMEditor
|
|
|
18
18
|
attr_accessor :allowed_tags
|
|
19
19
|
# Which bundle the form helper boots: "starter" or "full".
|
|
20
20
|
attr_accessor :default_kit
|
|
21
|
+
# Default visual theme: "light" or "dark".
|
|
22
|
+
attr_accessor :default_theme
|
|
21
23
|
# Upload endpoint used by the JavaScript adapter when uploads are enabled.
|
|
22
24
|
attr_accessor :upload_path
|
|
23
25
|
# Include the packaged JS/CSS automatically with the first editor field.
|
|
@@ -47,6 +49,7 @@ module SMEditor
|
|
|
47
49
|
table thead tbody tr td th
|
|
48
50
|
]
|
|
49
51
|
@default_kit = "starter"
|
|
52
|
+
@default_theme = "light"
|
|
50
53
|
@upload_path = "/smeditor/uploads"
|
|
51
54
|
@auto_include_assets = true
|
|
52
55
|
@min_height = "320px"
|
|
@@ -11,24 +11,28 @@ module SMEditor
|
|
|
11
11
|
# include assets in <head> can call `smeditor_assets` there and disable
|
|
12
12
|
# auto inclusion with config.auto_include_assets = false.
|
|
13
13
|
def smeditor_assets
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
if defined?(@_smeditor_assets_rendered) && @_smeditor_assets_rendered
|
|
15
|
+
"".html_safe
|
|
16
|
+
else
|
|
17
|
+
@_smeditor_assets_rendered = true
|
|
18
|
+
safe_join([
|
|
19
|
+
stylesheet_link_tag("smeditor", "data-turbo-track": "reload"),
|
|
20
|
+
javascript_include_tag("smeditor", defer: true, "data-turbo-track": "reload"),
|
|
21
|
+
])
|
|
22
|
+
end
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
# form - a Rails FormBuilder
|
|
24
26
|
# method - the model attribute (stored as an HTML string)
|
|
25
27
|
# options - :kit ("starter" | "full"), :class, :placeholder,
|
|
26
|
-
# :
|
|
28
|
+
# :theme ("light" | "dark"), :upload_url, :label,
|
|
29
|
+
# :include_assets, :min_height,
|
|
27
30
|
# :tablet_min_height, :mobile_min_height
|
|
28
31
|
def smeditor_editor(form, method, options = {})
|
|
29
32
|
object = form.object
|
|
30
33
|
current = object.respond_to?(method) ? object.public_send(method) : nil
|
|
31
34
|
kit = (options[:kit] || SMEditor.config.default_kit).to_s
|
|
35
|
+
theme = smeditor_theme(options.fetch(:theme, SMEditor.config.default_theme))
|
|
32
36
|
upload_url = options.fetch(:upload_url, smeditor_upload_url)
|
|
33
37
|
include_assets = options.fetch(:include_assets, SMEditor.config.auto_include_assets)
|
|
34
38
|
stylesheet_url = asset_path("smeditor.css")
|
|
@@ -49,6 +53,7 @@ module SMEditor
|
|
|
49
53
|
data: {
|
|
50
54
|
smeditor: true,
|
|
51
55
|
smeditor_kit: kit,
|
|
56
|
+
smeditor_theme: theme,
|
|
52
57
|
smeditor_placeholder: options[:placeholder],
|
|
53
58
|
smeditor_upload_url: upload_url,
|
|
54
59
|
smeditor_label: options[:label],
|
|
@@ -71,9 +76,20 @@ module SMEditor
|
|
|
71
76
|
|
|
72
77
|
def smeditor_css_length(value, option_name)
|
|
73
78
|
normalized = value.is_a?(Numeric) ? "#{value}px" : value.to_s.strip
|
|
74
|
-
|
|
79
|
+
if normalized.match?(CSS_LENGTH)
|
|
80
|
+
normalized
|
|
81
|
+
else
|
|
82
|
+
raise ArgumentError, "#{option_name} must be a number (pixels) or a CSS length such as 320px, 24rem, or 45vh"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def smeditor_theme(value)
|
|
87
|
+
theme = value.to_s
|
|
88
|
+
unless %w[light dark].include?(theme)
|
|
89
|
+
raise ArgumentError, 'theme must be "light" or "dark"'
|
|
90
|
+
end
|
|
75
91
|
|
|
76
|
-
|
|
92
|
+
theme
|
|
77
93
|
end
|
|
78
94
|
|
|
79
95
|
def smeditor_upload_url
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smeditor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- SMEditor contributors
|
|
@@ -96,7 +96,7 @@ metadata:
|
|
|
96
96
|
source_code_uri: https://github.com/sCruze/smeditor/tree/main/gems/smeditor
|
|
97
97
|
changelog_uri: https://github.com/sCruze/smeditor/blob/main/gems/smeditor/CHANGELOG.md
|
|
98
98
|
bug_tracker_uri: https://github.com/sCruze/smeditor/issues
|
|
99
|
-
documentation_uri: https://rubydoc.info/gems/smeditor/0.
|
|
99
|
+
documentation_uri: https://rubydoc.info/gems/smeditor/0.3.0
|
|
100
100
|
rubygems_mfa_required: 'true'
|
|
101
101
|
rdoc_options: []
|
|
102
102
|
require_paths:
|