smeditor 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2fa2dffff9ec8a5d1b502cbcba1c44420d778f0e5377db886812922fb9fd543c
4
- data.tar.gz: f2892ee2d34a3b726d7e726acb5bca9de6a1973f18c8b06257dd425945f193a3
3
+ metadata.gz: bd12092236abeb99040e428490e6ef352721d4bb266b0a2933ca22a413350941
4
+ data.tar.gz: 8f3e32940dc8fdc7e37a26765d9925b8a0755319714a2d623ea1b8f8fd046091
5
5
  SHA512:
6
- metadata.gz: 9a0923f3f4a6d7c51826a5e93e0853d3b9e452cbb46aa2a7027392a9fdfd9af6ed604a03e3224e6e4f86f10742f02b8dc0989441461890bd03842b388bcfa7a5
7
- data.tar.gz: 8b4a6d29c7f033da64c91127d1a3a2a5b00f19607b60b10294972abff6137a7940a5464313231193cff23c83e516a971a3568a860e01c4555f0edfba915b6559
6
+ metadata.gz: 4fc1cb9a65be6f82544f1be230cb860fd0525df94a401b76921c2664e40a5e4587978cf9d3a2c0d011b230d0a9e7f1b89547cf38063d52ffb8614ef5ad7961b6
7
+ data.tar.gz: 4d72b4392ec27c3a13c46510da58a7266dbeeebaef74ef422c9ff7c2b15e7fff4ef499ad3d6cb839f9b31631b334d166af18c2e84f43ec5e22efc8609f4688a1
data/CHANGELOG.md CHANGED
@@ -9,6 +9,29 @@ Cross-cutting product changes live in the repository root
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ### Changed
13
+
14
+ - The Rails gem is now self-contained. It ships a precompiled browser bundle
15
+ containing SMEditor core, StarterKit and FullKit plus the default CSS theme.
16
+ Consuming Rails applications no longer need npm, React, esbuild, Vite,
17
+ importmap pins, or `jsbundling-rails`.
18
+ - The Rails browser adapter mounts directly on `@smeditor/core`, removing React
19
+ from the gem runtime bundle while keeping the React package available for
20
+ normal npm consumers.
21
+ - `smeditor:install` now creates only the initializer; it no longer copies a
22
+ host-app JavaScript entrypoint or prints npm installation steps.
23
+ - `smeditor_editor` includes the packaged JS/CSS automatically once per view by
24
+ default. `config.auto_include_assets = false` + `smeditor_assets` provides an
25
+ explicit-layout mode.
26
+ - The hidden input now emits bubbling `input` and `smeditor:change` events on editor
27
+ updates and exposes `smeditorInstance` for autosave/AI/DOCX integrations.
28
+ - Turbo teardown is handled on `turbo:before-cache`.
29
+
30
+ ### Added
31
+
32
+ - `scripts/build-gem-assets.mjs` creates the vendored browser JS and CSS from
33
+ the monorepo sources.
34
+
12
35
  ### Fixed
13
36
 
14
37
  - The boot script no longer imports `@smeditor/theme-default/index.css`, a
@@ -24,9 +47,6 @@ Cross-cutting product changes live in the repository root
24
47
 
25
48
  ### Added
26
49
 
27
- - `smeditor:install` copies the boot script into `app/javascript/smeditor.js`
28
- so the host app's bundler resolves the `@smeditor/*` imports.
29
- Pass `--skip-javascript` to opt out.
30
50
  - `config.max_upload_size` (10 MB default) and `config.allowed_upload_types`
31
51
  are enforced by the upload endpoint.
32
52
  - `LICENSE` and `CHANGELOG.md` ship in the gem; the internal `PLAN.md` no
data/README.md CHANGED
@@ -1,21 +1,15 @@
1
1
  # smeditor
2
2
 
3
- Rails integration for the [SMEditor](https://github.com/sCruze/smeditor)
4
- rich-text editor.
3
+ Self-contained Rails integration for [SMEditor](https://github.com/sCruze/smeditor).
5
4
 
6
- This gem is a **thin adapter**. The editor is the upstream npm
7
- packages (`@smeditor/react`, `@smeditor/starter-kit`, …); the gem
8
- adds a form helper, a safe server-side renderer, and an optional
9
- upload endpoint. It holds no schema, no commands and no rendering
10
- pipeline of its own.
5
+ The gem ships the **editor core, StarterKit, FullKit, browser bundle and default
6
+ CSS theme inside the gem itself**. A Rails application does not need npm,
7
+ React, esbuild, Vite, importmap pins, or `jsbundling-rails` to use SMEditor.
11
8
 
12
9
  ## Requirements
13
10
 
14
- - Ruby >= 3.0, Rails >= 7.0
15
- - A JavaScript bundler in the host app — `jsbundling-rails` (esbuild,
16
- rollup, webpack, bun) or Vite. The boot script imports the npm
17
- packages by bare specifier, which Sprockets and importmap cannot
18
- resolve on their own.
11
+ - Ruby >= 3.0
12
+ - Rails >= 7.0
19
13
 
20
14
  ## Install
21
15
 
@@ -29,113 +23,158 @@ bundle install
29
23
  bin/rails generate smeditor:install
30
24
  ```
31
25
 
32
- The generator writes `config/initializers/smeditor.rb` and copies the
33
- boot script to `app/javascript/smeditor.js`. Then install the editor
34
- itself and import the script:
26
+ That is enough for normal editor usage. The generator only creates
27
+ `config/initializers/smeditor.rb`; it does not copy JavaScript into the host
28
+ application and does not ask you to install frontend packages.
35
29
 
36
- ```bash
37
- npm install @smeditor/react @smeditor/starter-kit \
38
- @smeditor/full-kit @smeditor/theme-default react react-dom
39
- ```
40
-
41
- ```js
42
- // app/javascript/application.js
43
- import "./smeditor";
44
- ```
45
-
46
- Mount the engine if you want the upload endpoint:
30
+ For ActiveStorage-backed image uploads, mount the engine:
47
31
 
48
32
  ```ruby
49
33
  # config/routes.rb
50
34
  mount SMEditor::Rails::Engine => "/smeditor"
51
35
  ```
52
36
 
53
- ## Namespace
54
-
55
- Константа гема — `SMEditor` (не `Smeditor`). Каталоги называются `smeditor/`,
56
- поэтому движок сам регистрирует переопределение в обоих автозагрузчиках
57
- Zeitwerk (`smeditor` → `SMEditor`) до сканирования autoload-путей, а генератор
58
- объявляет namespace явно. Настроек в приложении не требуется, и глобальные
59
- inflections ActiveSupport не трогаются.
60
-
61
37
  ## Configure
62
38
 
63
39
  ```ruby
64
40
  # config/initializers/smeditor.rb
65
- SMEditor.configure do |c|
66
- c.uploads = :active_storage # or :none (default)
67
- c.sanitize_output = true
68
- c.default_kit = "starter" # or "full"
69
- c.upload_path = "/smeditor/uploads"
70
- c.allowed_tags = %w[p h1 h2 h3 strong em a img]
71
- c.max_upload_size = 10 * 1024 * 1024
72
- c.allowed_upload_types = %w[image/png image/jpeg image/webp]
41
+ SMEditor.configure do |config|
42
+ config.uploads = :none # or :active_storage
43
+ config.upload_path = "/smeditor/uploads"
44
+ config.default_kit = "starter" # or "full"
45
+ config.sanitize_output = true
46
+
47
+ # true by default: the first editor field includes smeditor.js/css.
48
+ # Set false if you prefer calling `smeditor_assets` in your layout.
49
+ config.auto_include_assets = true
50
+
51
+ config.max_upload_size = 10 * 1024 * 1024
52
+ config.allowed_upload_types = %w[
53
+ image/png image/jpeg image/gif image/webp image/avif image/bmp
54
+ ]
73
55
  end
74
56
  ```
75
57
 
76
58
  ## Use
77
59
 
78
- The form helper mounts an editor and persists its HTML through a
79
- hidden field — a normal form submit saves the content:
80
-
81
60
  ```erb
82
61
  <%= form_with model: @article do |form| %>
83
- <%= form.smeditor_editor :content %>
62
+ <%= form.smeditor_editor :content,
63
+ kit: "full",
64
+ placeholder: "Write…" %>
65
+
84
66
  <%= form.submit %>
85
67
  <% end %>
86
68
  ```
87
69
 
88
- Options: `:kit` (`"starter"` / `"full"`), `:placeholder`, `:class`,
89
- `:upload_url`.
70
+ The helper renders a hidden Rails field plus the editor mount. The packaged
71
+ browser bundle updates the hidden field on every editor change, including a
72
+ normal bubbling `input` event and a `smeditor:change` custom event, so form submit and autosave code can
73
+ observe the value without CKEditor-specific integration.
90
74
 
91
- Display saved content on a public page — always sanitized:
75
+ Available options:
76
+
77
+ - `kit: "starter" | "full"`
78
+ - `placeholder:`
79
+ - `class:`
80
+ - `label:` — editor ARIA label
81
+ - `upload_url:` — custom image upload endpoint
82
+ - `include_assets: false` — skip automatic asset tags for this field
83
+
84
+ ### Assets in the layout (optional)
85
+
86
+ By default the first `smeditor_editor` call includes the packaged assets once.
87
+ If you prefer explicit layout assets:
88
+
89
+ ```ruby
90
+ # config/initializers/smeditor.rb
91
+ SMEditor.configure { |config| config.auto_include_assets = false }
92
+ ```
92
93
 
93
94
  ```erb
94
- <%= smeditor_render(@article.content) %>
95
+ <head>
96
+ <%= smeditor_assets %>
97
+ </head>
95
98
  ```
96
99
 
97
- ## How it works
100
+ The files still come from the gem; this only changes where the tags are
101
+ rendered.
98
102
 
99
- `smeditor_editor` renders a hidden field (seeded with the stored
100
- HTML) and an empty mount point. The boot script finds each mount,
101
- attaches a real editor from the npm packages, and writes
102
- `editor.getHTML()` back into the hidden field on every change. The
103
- model attribute is a plain HTML string — SMEditor's transport format —
104
- so no special column type or serializer is needed.
103
+ ## Programmatic access
105
104
 
106
- Booting runs on `DOMContentLoaded`, on `turbo:load` and on
107
- `turbo:frame-load`; each mount is booted at most once.
105
+ After boot, the editor instance is available on both the hidden input and the
106
+ mount element:
108
107
 
109
- ## Rendering and trust
108
+ ```js
109
+ const input = document.querySelector("[data-smeditor-input]")
110
+ const editor = input.smeditorInstance
110
111
 
111
- Stored editor HTML is treated as untrusted input. `smeditor_render`
112
- passes it through `SMEditor::Rails::Sanitizer`, which applies the tag
113
- allow-list, strips unsafe URLs and `style` declarations, and adds
114
- `rel="noopener noreferrer"` to `target="_blank"` links.
112
+ editor.getHTML()
113
+ editor.setContent("<p>New content</p>")
114
+ editor.commands.toggleBold?.()
115
+ ```
116
+
117
+ The bundle also exposes `window.SMEditor.boot()` and
118
+ `window.SMEditor.destroy()` for advanced integrations.
119
+
120
+ ## Turbo
121
+
122
+ SMEditor boots on `DOMContentLoaded`, `turbo:load`, and `turbo:frame-load`.
123
+ Before Turbo caches a page, editor instances are destroyed and their mounts are
124
+ reset, preventing stale contenteditable state after navigation.
125
+
126
+ ## Rendering saved content
127
+
128
+ ```erb
129
+ <%= smeditor_render(@article.content) %>
130
+ ```
115
131
 
116
- Setting `config.sanitize_output = false` marks stored content
117
- `html_safe` without sanitizing it. Only do that when the content is
118
- already trusted upstream.
132
+ Stored editor HTML is treated as untrusted input. `smeditor_render` sanitizes
133
+ allowed tags, URLs and inline formatting and hardens `_blank` links by default.
134
+
135
+ Set `config.sanitize_output = false` only if the stored HTML is already trusted.
119
136
 
120
137
  ## Uploads
121
138
 
122
139
  With `config.uploads = :active_storage`, the engine exposes
123
- `POST /smeditor/uploads`. It stores image files via ActiveStorage and
124
- responds with `{ src, alt, title }` for the editor to embed.
140
+ `POST /smeditor/uploads`. It stores the image through ActiveStorage and returns
141
+ `{ src, alt, title }` to the editor.
142
+
143
+ The default upload endpoint is unauthenticated. It enforces the configured file
144
+ size and MIME allow-list, but public applications should add their own
145
+ authorization policy.
146
+
147
+ ## What the gem contains
125
148
 
126
- The endpoint is **unauthenticated by default** and only enforces the
127
- content-type allow-list and `max_upload_size`. Subclass
128
- `SMEditor::UploadsController` and add your own authorization before
129
- exposing it to the public internet.
149
+ The published `.gem` includes:
130
150
 
131
- With `:none`, no endpoint is mounted wire your own.
151
+ - SMEditor browser bundle (core + StarterKit + FullKit)
152
+ - default SMEditor theme
153
+ - Rails form helper and FormBuilder extension
154
+ - safe renderer/sanitizer
155
+ - optional ActiveStorage upload endpoint
156
+ - install generator
157
+
158
+ The source monorepo still uses TypeScript/pnpm to develop and rebuild the
159
+ frontend packages. Those are **build-time tools for SMEditor maintainers only**;
160
+ they are not runtime dependencies of applications that install the gem.
132
161
 
133
162
  ## Development
134
163
 
164
+ Rebuild the vendored Rails assets after changing core/extensions or the Rails
165
+ browser adapter:
166
+
167
+ ```bash
168
+ node scripts/build-gem-assets.mjs
169
+ ```
170
+
171
+ Then test/build the gem:
172
+
135
173
  ```bash
136
174
  cd gems/smeditor
137
175
  bundle install
138
176
  bundle exec rspec
177
+ gem build smeditor.gemspec
139
178
  ```
140
179
 
141
180
  ## License