smeditor 0.2.5 → 0.3.4

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.
@@ -1,15 +1,11 @@
1
1
  /* SMEditor default theme tokens.
2
2
  *
3
- * Two ways to pick a theme:
3
+ * Theme selection:
4
4
  *
5
- * 1. Do nothing → the editor follows `prefers-color-scheme`.
6
- * 2. Set `data-theme="light"` or `data-theme="dark"` on any element
7
- * that wraps the editor (or on <html>). The explicit attribute
8
- * wins over the media query.
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, OR via media query when
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
@@ -340,7 +310,7 @@
340
310
  /* Color swatch grid inside the color-picker dropdowns */
341
311
  .smeditor-color-grid {
342
312
  display: grid;
343
- grid-template-columns: repeat(8, 1fr);
313
+ grid-template-columns: repeat(10, 22px);
344
314
  gap: 4px;
345
315
  padding: 6px;
346
316
  }
@@ -1232,6 +1202,145 @@
1232
1202
  }
1233
1203
  }
1234
1204
 
1205
+ /* ===========================================================================
1206
+ * Colour pickers — current-colour indicator and labelled panel
1207
+ * ======================================================================== */
1208
+
1209
+ .smeditor-color-trigger {
1210
+ display: inline-flex;
1211
+ flex-direction: column;
1212
+ align-items: center;
1213
+ gap: 1px;
1214
+ }
1215
+
1216
+ .smeditor-color-trigger__bar {
1217
+ display: block;
1218
+ width: 14px;
1219
+ height: 3px;
1220
+ border-radius: 1px;
1221
+ }
1222
+
1223
+ .smeditor-color-trigger__bar[data-empty="true"] {
1224
+ background: transparent;
1225
+ box-shadow: inset 0 0 0 1px var(--sme-color-border-strong);
1226
+ }
1227
+
1228
+ .smeditor-color-trigger__bar[data-empty="false"] {
1229
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
1230
+ }
1231
+
1232
+ .smeditor-dropdown--color .smeditor-dropdown__menu {
1233
+ min-width: 0;
1234
+ max-width: none;
1235
+ }
1236
+
1237
+ .smeditor-color-panel {
1238
+ display: flex;
1239
+ flex-direction: column;
1240
+ gap: 6px;
1241
+ padding: 4px;
1242
+ }
1243
+
1244
+ .smeditor-color-panel .smeditor-color-grid {
1245
+ padding: 0;
1246
+ }
1247
+
1248
+ .smeditor-color-panel__title {
1249
+ font-size: 11px;
1250
+ font-weight: 600;
1251
+ letter-spacing: 0.04em;
1252
+ text-transform: uppercase;
1253
+ color: var(--sme-color-text-muted);
1254
+ }
1255
+
1256
+ .smeditor-color-panel__widths {
1257
+ display: flex;
1258
+ gap: 4px;
1259
+ }
1260
+
1261
+ .smeditor-color-panel__chip,
1262
+ .smeditor-color-panel__clear {
1263
+ appearance: none;
1264
+ font: inherit;
1265
+ font-size: var(--sme-text-sm);
1266
+ color: var(--sme-color-text);
1267
+ background: transparent;
1268
+ border: 1px solid var(--sme-color-border);
1269
+ border-radius: var(--sme-radius-sm);
1270
+ padding: 5px 8px;
1271
+ cursor: pointer;
1272
+ }
1273
+
1274
+ .smeditor-color-panel__chip {
1275
+ flex: 1 1 0;
1276
+ white-space: nowrap;
1277
+ }
1278
+
1279
+ .smeditor-color-panel__chip:hover,
1280
+ .smeditor-color-panel__clear:hover {
1281
+ background: var(--sme-color-surface-muted);
1282
+ }
1283
+
1284
+ .smeditor-color-panel__chip.is-active {
1285
+ color: var(--sme-color-accent);
1286
+ background: var(--sme-color-accent-soft);
1287
+ border-color: var(--sme-color-accent);
1288
+ }
1289
+
1290
+ .smeditor-color-panel__clear:disabled {
1291
+ opacity: 0.45;
1292
+ cursor: not-allowed;
1293
+ }
1294
+
1295
+ .smeditor-color-panel__clear:disabled:hover {
1296
+ background: transparent;
1297
+ }
1298
+
1299
+ /* Value pickers show the current value (font / size / spacing) */
1300
+ .smeditor-dropdown__label--text {
1301
+ max-width: 96px;
1302
+ overflow: hidden;
1303
+ text-overflow: ellipsis;
1304
+ white-space: nowrap;
1305
+ }
1306
+
1307
+ /* Bubble menu — one row, compact dividers */
1308
+ .smeditor-bubble-menu {
1309
+ flex-wrap: nowrap;
1310
+ white-space: nowrap;
1311
+ }
1312
+
1313
+ .smeditor-bubble-menu .smeditor-toolbar__divider {
1314
+ height: 18px;
1315
+ margin: 0 2px;
1316
+ }
1317
+
1318
+ /* Filled text (extension-background-color). `.smeditor-text-outline` is
1319
+ * the class the 0.3.2 Rails build wrote for the same thing. */
1320
+ .smeditor-editor :where(.smeditor-fill, .smeditor-text-outline),
1321
+ .smeditor-content :where(.smeditor-fill, .smeditor-text-outline) {
1322
+ padding: 0.04em 0.18em;
1323
+ border-radius: 0.22em;
1324
+ -webkit-box-decoration-break: clone;
1325
+ box-decoration-break: clone;
1326
+ }
1327
+
1328
+ /* Colour dot on the "text in outline" chips */
1329
+ .smeditor-color-panel__chip {
1330
+ display: inline-flex;
1331
+ align-items: center;
1332
+ justify-content: center;
1333
+ gap: 6px;
1334
+ }
1335
+ .smeditor-color-panel__chip::before {
1336
+ content: "";
1337
+ width: 10px;
1338
+ height: 10px;
1339
+ border-radius: 50%;
1340
+ background: var(--sme-chip-swatch, conic-gradient(#1a1a1f 0 50%, #ffffff 0));
1341
+ box-shadow: inset 0 0 0 1px var(--sme-color-border-strong);
1342
+ }
1343
+
1235
1344
 
1236
1345
  /* Rails self-contained adapter / style isolation */
1237
1346
  :host {
@@ -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
- return "".html_safe if defined?(@_smeditor_assets_rendered) && @_smeditor_assets_rendered
15
-
16
- @_smeditor_assets_rendered = true
17
- safe_join([
18
- stylesheet_link_tag("smeditor", "data-turbo-track": "reload"),
19
- javascript_include_tag("smeditor", defer: true, "data-turbo-track": "reload"),
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
- # :upload_url, :label, :include_assets, :min_height,
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
- return normalized if normalized.match?(CSS_LENGTH)
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
- raise ArgumentError, "#{option_name} must be a number (pixels) or a CSS length such as 320px, 24rem, or 45vh"
92
+ theme
77
93
  end
78
94
 
79
95
  def smeditor_upload_url
@@ -13,7 +13,7 @@ module SMEditor
13
13
  module_function
14
14
 
15
15
  # Attributes kept on surviving tags. `style` is included because
16
- # SMEditor serializes color, background, highlight, text stroke,
16
+ # SMEditor serializes color, background, highlight, underline colour, text stroke,
17
17
  # font size, font family and alignment as constrained inline CSS.
18
18
  ALLOWED_ATTRS = %w[
19
19
  href src alt title class style target rel
@@ -111,7 +111,7 @@ module SMEditor
111
111
  case name
112
112
  when "text-align"
113
113
  sanitize_text_align(value)
114
- when "color", "background-color", "background"
114
+ when "color", "background-color", "background", "text-decoration-color"
115
115
  sanitize_color(value)
116
116
  when "font-family"
117
117
  sanitize_font_family(value)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SMEditor
4
4
  module Rails
5
- VERSION = "0.2.5"
5
+ VERSION = "0.3.4"
6
6
  end
7
7
  end
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.2.5
4
+ version: 0.3.4
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.2.5
99
+ documentation_uri: https://rubydoc.info/gems/smeditor/0.3.4
100
100
  rubygems_mfa_required: 'true'
101
101
  rdoc_options: []
102
102
  require_paths: