jsmdcui 0.5.0 → 0.7.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/CHANGELOG.md CHANGED
@@ -2,6 +2,234 @@
2
2
 
3
3
  All notable user-visible changes to jsmdcui are documented here.
4
4
 
5
+ ## [0.7.0] - 2026-07-20
6
+
7
+ This update adds native Kitty image rendering, turns heading task lists into
8
+ Array-style collections in both interfaces, and keeps TUI layout, interaction,
9
+ and checkbox styling consistent at every terminal width.
10
+
11
+ ### Added
12
+
13
+ - Display local Markdown images at their rendered TUI positions with the
14
+ Kitty graphics protocol. Image rows are reserved according to intrinsic
15
+ dimensions, and placements follow scrolling, resizing, and split panes.
16
+ - With `--allow-url` and Kitty mode enabled, download HTTP(S) Markdown images
17
+ through the existing `curl`, `wget`, then Bun `fetch` fallback chain. Relative
18
+ image URLs in downloaded Markdown resolve against the original document URL.
19
+ - Keep Bun's normal linked `📷` fallback for missing, unsupported, and
20
+ unauthorized remote images, and scope Kitty cleanup to image IDs owned by
21
+ jsmdcui.
22
+ - Set Kitty's `C=1` placement flag so displaying an image cannot advance the
23
+ terminal cursor and trigger an unwanted scroll at the bottom of the screen.
24
+ - Add `.push()`, `.pop()`, `.shift()`, `.unshift()`, and `.splice()` to heading
25
+ selectors in both the TUI and WUI. The methods follow their
26
+ `Array.prototype` argument and return-value conventions, operate on direct
27
+ items in the first task list belonging to the heading, and remove nested
28
+ content together with its parent item.
29
+ - Allow inserted task items to be passed as strings for unchecked items or as
30
+ `{ value, checked }` objects, and preserve an emptied TUI list's insertion
31
+ point so later mutations still target the same list.
32
+ - Add read-only heading `.slice(start, end)`, returning fresh
33
+ `{ value, checked }` snapshots that include both checked and unchecked direct
34
+ task items.
35
+ - Add `demos/todo.md` and `demos/todo-zh.md`, runnable Todo examples that use
36
+ text controls and the new list methods to add and remove items and display
37
+ completed or pending tasks.
38
+ - Move secondary examples under `demos/` and add automatic
39
+ `--demo-<filename>` discovery, so newly bundled `demos/<filename>.md` files
40
+ need no parser changes. Keep `--demo` mapped to the root `testapp.md` and
41
+ retain the existing image-processor aliases.
42
+ - Add `--demo-list` to list the root demo and every automatically discovered
43
+ Markdown example from bundled assets or the source tree's `demos/` directory.
44
+ - Add `clean.sh` as a convenience helper for removing generated Markdown
45
+ companion files from the project directory.
46
+
47
+ ### Changed
48
+
49
+ - Document the Array-style heading task-list API, its return values, nested-item
50
+ behavior, existing-list requirement, and non-persistent rendered-state
51
+ semantics in the README and bundled help.
52
+ - Use the complete pane content width consistently for Markdown rendering,
53
+ soft wrapping, cursor and mouse mapping, and Kitty image sizing instead of
54
+ reserving the terminal's final column.
55
+
56
+ ### Fixed
57
+
58
+ - Fix soft wrapping at affected terminal widths shifting the visual cursor by
59
+ one row, which could activate the preceding Markdown action and leave the
60
+ final action unresponsive.
61
+ - Update the Bun Markdown ANSI glyph and style together when toggling a task
62
+ checkbox, so checked items become green and unchecked items no longer retain
63
+ the checked color.
64
+
65
+ ## [0.6.3] - 2026-07-18
66
+
67
+ This update enforces unique heading IDs at the Markdown source level and
68
+ clarifies the portable fenced-block identity contract shared by the TUI and
69
+ WUI.
70
+
71
+ ### Changed
72
+
73
+ - Treat duplicate Markdown headings that generate the same base ID as a
74
+ source-level collision. Later headings no longer pass `--check` merely
75
+ because Bun would silently assign generated suffixes such as `-1` or `-2`
76
+ that the Markdown author cannot see.
77
+ - Document that a selectable fenced-block declaration requires a tag and uses
78
+ the `tag#id.class` identity form. The officially supported portable control
79
+ tags are currently limited to `text` and `textarea` so the same Markdown
80
+ behaves consistently in both the TUI and WUI.
81
+ - Clarify that selector queries may omit the tag or classes after a valid
82
+ declaration.
83
+ - Expand checker and TUI selector regression coverage across tag/no-tag and
84
+ class/no-class combinations, heading-to-heading, heading-to-block, and
85
+ block-to-block ID collisions.
86
+
87
+ ### Fixed
88
+
89
+ - Fix duplicate source headings incorrectly passing the checker after Bun
90
+ automatically changed the generated ID of later headings.
91
+
92
+ ## [0.6.2] - 2026-07-18
93
+
94
+ This update makes Markdown ID-collision checks match the full TUI `$()` block
95
+ selector and gives check results clearer final status banners.
96
+
97
+ ### Changed
98
+
99
+ - Extend `--check FILE.md` from `text` and `textarea` controls to every
100
+ explicitly named fenced block accepted by the TUI `$()` selector, including
101
+ identities such as `hello#myid` and `json#config`.
102
+ - Report separate heading and fenced-block declaration counts, and describe
103
+ arbitrary block tags and their source lines in collision details.
104
+ - Replace the previous success label with a large green `PASSED` banner and
105
+ add a matching large red `FAILED` banner at the bottom of failed reports.
106
+ Both true-color foregrounds are generated with
107
+ `Bun.color(..., "ansi-16m")`, with standard ANSI fallbacks.
108
+ - Update the README and bundled help to clarify that generated heading IDs
109
+ share the selector namespace with all explicitly named fenced blocks, not
110
+ only editable text controls.
111
+
112
+ ### Fixed
113
+
114
+ - Fix `--check` overlooking collisions between a heading and a non-text
115
+ fenced block even though TUI `$().val()` could select both declarations.
116
+ - Add regression coverage for arbitrary fenced-block IDs and the colored
117
+ `PASSED` and `FAILED` terminal statuses.
118
+
119
+ ## [0.6.1] - 2026-07-18
120
+
121
+ This update adds Markdown UI ID-collision diagnostics and bundles a practical
122
+ Bun.Image processor demo in English and Traditional Chinese.
123
+
124
+ ### Added
125
+
126
+ - Add `--check FILE.md` to inspect Markdown heading and text-control IDs
127
+ without opening a UI or writing generated companion files. The report uses
128
+ `Bun.markdown.ansi()` headings and nested lists, identifies every collision
129
+ by ID, source type, line number, and original declaration, and exits with
130
+ status `0` for unique IDs, `1` for collisions, or `2` for usage and read
131
+ errors.
132
+ - Add `image-processor.md` and `image-processor.zh-TW.md`, runnable Bun.Image
133
+ tools for the TUI and WUI. They support image metadata inspection, resizing,
134
+ fit and resampling filters, enlargement prevention, EXIF auto-orientation,
135
+ rotation, vertical and horizontal mirroring, brightness and saturation
136
+ adjustment, and JPEG or PNG output options.
137
+ - Add detailed image-processing status fields. Successful writes show the
138
+ output path, dimensions, byte count, and all selected option values; failed
139
+ metadata reads and writes show the available error details and stack.
140
+ - Add `--demo-imgtool` and `--demo-imgtool-zh`. Each command preserves an
141
+ existing local processor Markdown file or writes its bundled language
142
+ version when missing, then opens it in the TUI.
143
+ - Bundle both image processor Markdown files in the single-executable asset
144
+ archive and add regression coverage for ID checks and both demo languages.
145
+
146
+ ### Changed
147
+
148
+ - Consolidate bundled demo Markdown loading behind one
149
+ `bundledMarkdownSource(filename)` implementation shared by `testapp.md`,
150
+ `select.md`, and both image processor variants.
151
+ - Document that heading selector values include the complete visible label.
152
+ Selection parsers should use deliberate substring, prefix, or token checks
153
+ when labels contain explanatory text instead of assuming exact identifiers.
154
+ - Document that generated heading IDs and explicitly named controls share the
155
+ same selector namespace and that every selectable ID should be unique.
156
+
157
+ ### Fixed
158
+
159
+ - Prevent explanatory text in image processor task-list labels from breaking
160
+ yes/no, fit, filter, and output-format selection parsing.
161
+ - Fix the English image processor status update silently targeting a heading
162
+ after `## Write Status` generated the same `#write-status` ID as its text
163
+ control.
164
+ - Catch image metadata and processing failures at both frontend and backend
165
+ boundaries so errors are displayed in the appropriate status field.
166
+
167
+ ## [0.6.0] - 2026-07-18
168
+
169
+ This update turns Markdown headings and task lists into cross-environment form
170
+ controls, improves the safety and consistency of the bundled demo workflow,
171
+ and adds a way to export the bundled README as a runnable Markdown app.
172
+
173
+ ### Added
174
+
175
+ - Add `--export-readme` to write or overwrite `./README.md` with the bundled
176
+ README source and exit.
177
+ - Add terminal task-checkbox activation. Activating a protected mdcui row at
178
+ or after its `☐` or `☒` toggles that checkbox and still allows the remaining
179
+ default cell callback to run. JavaScript links continue to take priority.
180
+ - Add hierarchical `<section>` wrappers to generated WUI HTML. Every h1-h6
181
+ opens a section; an equal or higher-level heading closes the applicable open
182
+ sections, while lower-level headings create nested sections. Content before
183
+ the first heading remains outside the generated sections.
184
+ - Add heading lookup to the TUI `$` API using the IDs generated by
185
+ `Bun.markdown.html(..., { headings: { ids: true } })`.
186
+ - Add `$('#heading-id').html()` in TUI to return a heading's inner HTML, and
187
+ `$('#heading-id').line()` to return its current 1-based terminal row or `0`
188
+ when it cannot be found. Line lookup follows text-block row additions,
189
+ removals, and multiline `.val(value)` replacements.
190
+ - Add `.html()` getters to WUI `$` selections. Any successfully selected DOM
191
+ element returns its `innerHTML`; missing or invalid selections return an
192
+ empty string.
193
+ - Add heading-based task-list values in both interfaces. `.val()` reads the
194
+ first task-list group directly following the selected heading, stops at the
195
+ next heading, and ignores nested task items. IDs beginning with `select`
196
+ return the first checked value or `null`; other IDs return all checked values
197
+ as an array or `[]`.
198
+ - Add `select.md`, a runnable multilevel heading and task-list example with
199
+ links that display single-select and multiple-select values through
200
+ `alert()`.
201
+ - Bundle `select.md` in packaged assets and add `--demo-select`. The command
202
+ preserves an existing `./select.md`, writes the bundled copy when missing,
203
+ opens it in the TUI, and generates its five companion files.
204
+
205
+ ### Changed
206
+
207
+ - Make `--demo` preserve an existing `./testapp.md`. The bundled source is now
208
+ written only when the file is missing, then opened in the terminal UI.
209
+ - Make `--wui` without a file follow the same source-file rule: use an existing
210
+ `./testapp.md`, or write the bundled demo there when missing, before creating
211
+ the generated companion files.
212
+ - Wrap generated WUI task-checkbox text in `<label>` so clicking the associated
213
+ text toggles the checkbox. Direct text and immediately following paragraph
214
+ elements are included; unrelated tags and nested lists remain outside.
215
+ - Extend the 0.5 `$().val()` contract: text and textarea controls retain their
216
+ string getter/setter behavior, while heading selections now return scalar,
217
+ array, or `null` task-list values according to the heading ID.
218
+ - Add a demo screenshot and expand the README and built-in help with clearer
219
+ TUI/WUI startup, demo preservation, and README export instructions.
220
+
221
+ ### Fixed
222
+
223
+ - Ensure WUI fallback to the bundled `testapp.md` materializes the Markdown
224
+ source in the current working directory instead of generating only its
225
+ companion files.
226
+ - Protect comments and `script`, `style`, `pre`, `code`, `textarea`, and
227
+ `template` regions while wrapping WUI headings, preventing heading-like HTML
228
+ strings inside those regions from changing the section hierarchy.
229
+ - Keep TUI heading lookup independent of ANSI heading text and duplicate
230
+ labels by mapping Bun-generated heading order and level to Bun's current
231
+ h1-h6 ANSI signatures.
232
+
5
233
  ## [0.5.0] - 2026-07-16
6
234
 
7
235
  This update adds cross-environment form-like text blocks and a small
package/README.md CHANGED
@@ -1,3 +1,20 @@
1
+ ![Demo](https://raw.githubusercontent.com/jjtseng93/jsmdcui/main/demo.jpg)
2
+
3
+ # Demo App
4
+ ## My app
5
+
6
+ - [Say hello](javascript:sayHello())
7
+ - [Get server time](javascript:showServerTime())
8
+ - [Update text box](javascript:updateText())
9
+ - [Show selected](javascript:alert(JSON.stringify($('#my-app').val())))
10
+ - [x] task1
11
+ - [x] task2
12
+ - [ ] unselected task
13
+
14
+ ```text#myid.myclass
15
+ Editable in both TUI and WUI
16
+ ```
17
+
1
18
  # Introduction
2
19
  - jsmdcui stands for:
3
20
  - JavaScript Markdown Cross-environment User Interface
@@ -10,6 +27,12 @@
10
27
  - Original projects:
11
28
  - https://github.com/jjtseng93/bunmicro
12
29
  - https://github.com/micro-editor/micro
30
+ - .
31
+ - This README is itself a runnable app.
32
+
33
+ ```sh
34
+ npx jsmdcui@latest README.md
35
+ ```
13
36
 
14
37
  ## Quick start
15
38
 
@@ -24,28 +47,54 @@ On other platforms, follow the [official Bun installation guide](https://bun.com
24
47
  Choose either of these two ways to run jsmdcui.
25
48
 
26
49
  > **Important:** Opening or rendering a local `.md` file writes or overwrites
27
- > five generated files beside it. Starting `--wui` without a file writes the
28
- > five files generated from `testapp.md` in the current directory. The source
29
- > Markdown is not changed, but you should run the demo in a directory where
50
+ > 5 generated files beside it.
51
+ > Starting `--wui` without a file or starting all the `--demo`s writes the
52
+ > 5 files generated from `testapp.md` in the current directory.
53
+ > The source Markdown is not changed, but you should run the demo in a directory where
30
54
  > overwriting generated files is safe.
31
55
 
32
56
  ### Route 1: Run with npx
33
57
 
34
- This route requires both `npx` and `bun` on your `PATH`; no source checkout is
35
- required. Open the normal terminal editor:
58
+ - This route requires both `npx` and `bun` on your `PATH`; no source checkout is
59
+ required.
60
+
61
+ #### Open the normal terminal editor
36
62
 
37
63
  ```sh
38
64
  npx jsmdcui
39
65
  ```
40
66
 
41
- Or start the default browser demo:
67
+ #### Start `testapp.md` as the TUI/WUI demo
68
+ - If `testapp.md` is missing, the bundled copy is written to the current working directory
69
+ - If `testapp.md` already exists, it will be used and won't be overwritten.
70
+
71
+ ```sh
72
+ # TUI(Terminal User Interface) Demo
73
+ npx jsmdcui --demo
74
+ ```
75
+
76
+ List every bundled demo and its command-line option:
42
77
 
43
78
  ```sh
79
+ npx jsmdcui --demo-list
80
+ ```
81
+
82
+ ```sh
83
+ # Bun.Image processor demo
84
+ npx jsmdcui --demo-imgtool
85
+ ```
86
+
87
+ ```sh
88
+ # Traditional Chinese Bun.Image processor demo
89
+ npx jsmdcui --demo-imgtool-zh
90
+ ```
91
+
92
+ ```sh
93
+ # WUI(Web User Interface) Demo
44
94
  npx jsmdcui --wui
45
95
  ```
46
96
 
47
- If the current directory already contains `testapp.md`, that local file is used
48
- instead of the bundled demo. To open your own Markdown UI, pass its path:
97
+ #### Open your own Markdown CUI App
49
98
 
50
99
  ```sh
51
100
  npx jsmdcui app.md
@@ -60,30 +109,46 @@ cd jsmdcui
60
109
  bun src/index.js testapp.md
61
110
  ```
62
111
 
63
- The last command opens the included demo in the terminal. Use the arrow keys to
64
- move, `Enter` or `Space` to activate an item, and `Ctrl-Q` to quit. To open the
65
- same demo in a browser instead:
112
+ - The last command opens the included demo in the terminal
113
+ - Use arrow keys to move around
114
+ - `Enter`, `Space`, or mouse click to activate an item, and `Ctrl-Q` to quit.
115
+ - To open the same demo in a browser instead:
66
116
 
67
117
  ```sh
68
118
  bun src/index.js --wui testapp.md
69
119
  ```
70
120
 
71
- After starting `--wui`, open the last printed `http://...` URL in a browser.
72
- Keep the command running while using the page, and press `Ctrl-C` in that
73
- terminal to stop the server.
121
+ - After starting `--wui`, open the last printed `http://...` URL in a browser.
122
+ - Keep the command running while using the CUI App, and press `Ctrl-C` in that terminal to stop the server.
123
+
124
+ ### Usage table
74
125
 
75
- The command table below uses the cloned-source form. If you use npx, replace
76
- `bun src/index.js` with `npx jsmdcui`.
126
+ - The command table below assumes you're running from a cloned repository
127
+ - If you use npx, replace `bun src/index.js` with `npx jsmdcui`
128
+
129
+ - I've also provided short aliases
130
+ * bun ./tui = bun src/index.js
131
+ * bun ./wui = bun src/index.js --wui
77
132
 
78
133
  | Command | Result |
79
134
  | --- | --- |
80
135
  | `bun src/index.js app.md` | Render `app.md` as a read-only terminal UI and write five generated files beside it. |
136
+ | `bun src/index.js --kitty app.md` | Display Markdown images with Kitty graphics and the jsgotty MIME extension. |
137
+ | `bun src/index.js --kitty-compat app.md` | Display Markdown images with Kitty graphics without the non-standard MIME `U` field. |
138
+ | `bun src/index.js --kitty --allow-url URL.md` | Download trusted HTTP(S) Markdown and its HTTP(S) images, then display supported images with Kitty graphics. |
139
+ | `JSMDCUI_KITTY_DEBUG=1 bun src/index.js --kitty app.md` | Enable Kitty image placement logging to `kitty-placement.log`. |
140
+ | `bun src/index.js --check app.md` | Check heading and fenced-block IDs for collisions, print line-by-line details, and exit. |
81
141
  | `bun src/index.js --edit app.md` | Open `app.md` as editable UTF-8 source, overriding automatic Markdown UI detection. |
82
142
  | `bun src/index.js --cat app.md` | Render the terminal version to stdout, write five generated files beside it, and exit. |
83
143
  | `bun src/index.js --testapp.md` | Write the bundled `testapp.md` source to stdout and exit. |
84
- | `bun src/index.js --demo` | Outputs & overwrites `./testapp.md`, opens it in the terminal UI, and writes 5 generated files beside it. |
85
- | `bun src/index.js --allow-url URL.md` | Download HTTP(S) Markdown to the current directory, write 5 generated files, and allow its embedded code to run. Only use trusted URLs. |
86
- | `bun src/index.js --wui` | Use local `testapp.md` when present, otherwise use the bundled demo; write five generated files in the current directory, then print and serve a random URL. |
144
+ | `bun src/index.js --export-readme` | Write or overwrite `./README.md` with the bundled README source and exit. |
145
+ | `bun src/index.js --demo-list` | List `testapp.md` and every bundled `demos/*.md` example with its command-line option, then exit. |
146
+ | `bun src/index.js --demo` | Use local `testapp.md` when present, otherwise write the bundled demo; open it in the terminal UI and write five generated files beside it. |
147
+ | `bun src/index.js --demo-<filename>` | Load `demos/<filename>.md`; preserve an existing local copy or write the bundled copy, then open it and generate its five companion files. New files added under `demos/` work automatically. |
148
+ | `bun src/index.js --demo-imgtool` | Compatibility alias for `--demo-image-processor`. |
149
+ | `bun src/index.js --demo-imgtool-zh` | Compatibility alias for `--demo-image-processor.zh-TW`. |
150
+ | `bun src/index.js --allow-url URL.md` | Download HTTP(S) Markdown to the current directory and, with Kitty mode enabled, download its HTTP(S) images; write 5 generated files and allow embedded code to run. Only use trusted URLs. |
151
+ | `bun src/index.js --wui` | Use local `testapp.md` when present, otherwise write the bundled demo; write five generated files in the current directory, then print and serve a random URL. |
87
152
  | `bun src/index.js --wui app.md` | Write five generated files beside `app.md`, then print and serve a random URL. |
88
153
  | `PORT=8080 bun src/index.js --wui app.md` | Start the browser UI on another port. |
89
154
  | `bun src/index.js` | Open the normal terminal editor with an empty buffer. |
@@ -96,11 +161,15 @@ options.
96
161
  Create `app.md`:
97
162
 
98
163
  ````md
99
- # My app
164
+ ## My app
100
165
 
101
166
  - [Say hello](javascript:sayHello())
102
167
  - [Get server time](javascript:showServerTime())
103
168
  - [Update text box](javascript:updateText())
169
+ - [Show selected](javascript:alert(JSON.stringify($('#my-app').val())))
170
+ - [x] task1
171
+ - [x] task2
172
+ - [ ] unselected task
104
173
 
105
174
  ```text#myid.myclass
106
175
  Editable in both TUI and WUI
@@ -136,6 +205,11 @@ bun src/index.js app.md
136
205
  bun src/index.js --wui app.md
137
206
  ```
138
207
 
208
+ - The resulting App UI is shown at the beginning of this README.md
209
+ - Run this demo app directly by:
210
+ * bun src/index.js README.md
211
+ * If you didn't clone the repo, use --export-readme to write README.md to the current folder
212
+
139
213
  ### Text blocks
140
214
 
141
215
  Both `text` and `textarea` fenced blocks define editable text fields:
@@ -146,6 +220,20 @@ Initial value
146
220
  ```
147
221
  ````
148
222
 
223
+ A fenced-block declaration must include a tag. Its supported identity syntax is
224
+ `tag`, optionally followed by `#id` and one or more `.class` names, for
225
+ example `text#message.note` or `textarea#notes.readonly`. Tags, IDs, and class
226
+ names must begin with an ASCII letter or underscore; their remaining
227
+ characters may also include digits, `_`, `-`, and `:`. Declarations such as
228
+ `#message` and `#message.note` have no tag and are therefore not recognized as
229
+ selectable fenced blocks.
230
+
231
+ The currently supported fenced-block tags are only `text` and `textarea` so
232
+ the same control works consistently in both the TUI and WUI. Selector queries
233
+ may omit the tag or classes after a valid declaration, so all of
234
+ `$('text#message.note')`, `$('text#message')`, `$('#message.note')`, and
235
+ `$('#message')` can select the example above.
236
+
149
237
  The same Markdown works in both interfaces. In the browser WUI it becomes a
150
238
  native `<textarea>` with the declared ID and classes. Long text wraps
151
239
  automatically, and the field height is recalculated when the user types, the
@@ -158,6 +246,157 @@ blocked. Activate the lower-left frame corner to add a row. Activate the
158
246
  upper-left frame corner to remove the trailing row only when it is empty;
159
247
  non-empty content is never removed.
160
248
 
249
+ ### Heading task lists and selector API
250
+
251
+ Headings can act as form-group selectors. jsmdcui uses the IDs generated by
252
+ `Bun.markdown.html(..., { headings: { ids: true } })`; for example,
253
+ `## Select Color` becomes `#select-color`. A heading selection reads direct
254
+ task items from the first list following that heading and stops at the next
255
+ heading. In the TUI, the first rendered `☐` or `☒` establishes that list and
256
+ its indentation. Nested task items are not included in the outer list's value.
257
+
258
+ Heading IDs share the same selector namespace as all explicitly named fenced
259
+ blocks, not only `text` and `textarea`, so avoid name collisions between them.
260
+ For example, `## Write Status` generates `#write-status` and must not be used
261
+ together with a block such as `text#write-status` or
262
+ `textarea#write-status`.
263
+ Otherwise, `$('#write-status')` may select the heading instead of the block and
264
+ updates can appear to do nothing. Rename either declaration so every
265
+ selectable ID is unique.
266
+
267
+ Duplicate source headings are also treated as collisions when they generate
268
+ the same base ID. Although Bun would automatically rename later headings with
269
+ suffixes such as `-1` and `-2`, those implicit selector names are not visible
270
+ in the Markdown source and should not be relied on. Give each heading a name
271
+ that produces a unique ID before rendering.
272
+
273
+ Run `bun src/index.js --check app.md` (or `jsmdcui --check app.md`) to
274
+ check these IDs without opening either UI or writing generated files. The
275
+ command prints each collision with its source type, line number, and original
276
+ declaration, then exits immediately. Its exit status is `0` when all IDs are
277
+ unique, `1` when collisions are found, and `2` for invalid arguments or read
278
+ errors.
279
+
280
+ If the heading ID begins with `select`, `.val()` behaves like a single select:
281
+ it returns the first checked item or `null`. Other heading IDs behave like a
282
+ multiple select and return all checked items as an array, or `[]` when none are
283
+ checked.
284
+
285
+ Heading values contain the complete visible label, including any explanatory
286
+ text. When interpreting a selection, prefer `value.includes(...)` (or another
287
+ deliberate prefix/token parser) unless labels are guaranteed to be exact,
288
+ stable identifiers. For example, `yes(flip vertically)` should not be tested
289
+ with `value === "yes"`.
290
+
291
+ ````md
292
+ ## Select Color
293
+
294
+ - [ ] Red
295
+ - [x] Green
296
+ - [ ] Blue
297
+
298
+ ## Features
299
+
300
+ - [x] Search
301
+ - [ ] Notifications
302
+ - [x] Offline mode
303
+
304
+ ```js front
305
+ export function showValues() {
306
+ alert(JSON.stringify({
307
+ color: $('#select-color').val(),
308
+ features: $('#features').val(),
309
+ }));
310
+ }
311
+ ```
312
+ ````
313
+
314
+ The same getter works in TUI and WUI:
315
+
316
+ ```js
317
+ $('#select-color').val() // "Green"
318
+ $('#features').val() // ["Search", "Offline mode"]
319
+ ```
320
+
321
+ The first direct task list belonging to a heading can also be changed with
322
+ Array-style methods. String arguments create unchecked items. Pass an object
323
+ to choose the initial checked state:
324
+
325
+ ```js
326
+ $('#features').push('Export')
327
+ $('#features').unshift({ value: 'Import', checked: true })
328
+ $('#features').splice(1, 2, 'Replacement')
329
+ $('#features').slice(0, 2)
330
+ $('#features').pop()
331
+ $('#features').shift()
332
+ ```
333
+
334
+ Like the corresponding `Array.prototype` methods, `.push(...items)` and
335
+ `.unshift(...items)` accept multiple items and return the new number of direct
336
+ items. `.pop()` and `.shift()` return the removed item's visible label, or
337
+ `undefined` when the list is empty. Nested task items are part of their parent
338
+ item: they are not counted separately, and are removed together with that
339
+ parent. These methods change the rendered TUI/WUI state; they do not rewrite
340
+ the source Markdown file. A heading must already have a task list before items
341
+ can be added.
342
+
343
+ `.splice(start, deleteCount, ...items)` follows `Array.prototype.splice()`:
344
+ negative indexes count from the end, omitting `deleteCount` removes through the
345
+ end, and the return value is an array containing the removed visible labels.
346
+
347
+ `.slice(start, end)` is read-only and follows `Array.prototype.slice()`. It
348
+ returns fresh item snapshots, including unchecked items, so changing the
349
+ returned array or its objects does not change the rendered list:
350
+
351
+ ```js
352
+ $('#features').slice()
353
+ // [
354
+ // { value: 'Search', checked: true },
355
+ // { value: 'Notifications', checked: false },
356
+ // ]
357
+ ```
358
+
359
+ `demos/todo.md` and `demos/todo-zh.md` are runnable Todo examples that
360
+ demonstrate `.push()`,
361
+ `.splice()`, `.slice()`, and `{ value, checked }` snapshots using editable text
362
+ controls instead of `prompt()` dialogs. Materialize one in the current
363
+ directory with its demo flag, or open the source-tree copy directly:
364
+
365
+ ```sh
366
+ bun src/index.js --demo-todo
367
+ bun src/index.js --demo-todo-zh
368
+ bun src/index.js demos/todo.md
369
+ bun src/index.js --wui demos/todo-zh.md
370
+ ```
371
+
372
+ The bundled `demos/select.md` is a multilevel runnable example. Use `--demo-select`
373
+ to write it into the current directory when missing and open it in the TUI, or
374
+ open it explicitly in either interface:
375
+
376
+ ```sh
377
+ bun src/index.js --demo-select
378
+ bun src/index.js demos/select.md
379
+ bun src/index.js --wui demos/select.md
380
+ ```
381
+
382
+ The available selector methods are:
383
+
384
+ | Method | TUI | WUI |
385
+ | --- | --- | --- |
386
+ | `.val()` | Read text blocks or heading task-list values. | Read textareas/controls or heading task-list values. |
387
+ | `.val(value)` | Replace text-block contents and resize multiline values. | Set textarea/control values and resize textareas. |
388
+ | `.html()` | Return a selected heading's inner HTML. | Return any successfully selected DOM element's `innerHTML`. |
389
+ | `.line()` | Return a heading's current 1-based TUI row, or `0` if missing. | Not available. |
390
+ | `.push(...items)` | Append unchecked strings or `{ value, checked }` task items; return the new direct-item count. | Same. |
391
+ | `.pop()` | Remove and return the last direct task item's label, or `undefined`. | Same. |
392
+ | `.shift()` | Remove and return the first direct task item's label, or `undefined`. | Same. |
393
+ | `.unshift(...items)` | Prepend unchecked strings or `{ value, checked }` task items; return the new direct-item count. | Same. |
394
+ | `.splice(start, deleteCount, ...items)` | Remove and insert direct task items; return the removed labels as an array. | Same. |
395
+ | `.slice(start, end)` | Return `{ value, checked }` snapshots without changing the direct task items. | Same. |
396
+
397
+ TUI heading rows are recalculated after text-block rows are added, removed, or
398
+ replaced with multiline `.val(value)` content.
399
+
161
400
  The three UI building blocks are:
162
401
 
163
402
  - Regular Markdown provides headings, text, lists, task checkboxes, code, and
@@ -213,8 +452,8 @@ selection, search, and copy remain available.
213
452
  | Input | Result |
214
453
  | --- | --- |
215
454
  | Arrow keys, `Home`, `End`, `PageUp`, `PageDown` | Move through the rendered UI. |
216
- | `Enter` or `Space` | Activate the cell under the cursor. Put the cursor on a `javascript:` link to run it. |
217
- | Left click | Move to and activate the clicked cell. A `javascript:` link runs immediately. |
455
+ | `Enter` or `Space` | Activate the cell under the cursor. Put the cursor on a `javascript:` link to run it, or on or to the right of `☐` or `☒` to toggle that task. |
456
+ | Left click | Move to and activate the clicked cell. A `javascript:` link runs immediately; clicking on or to the right of `☐` or `☒` toggles that task. |
218
457
  | Mouse wheel | Scroll three rows at a time. |
219
458
  | `Shift` + arrow keys | Select rendered text. |
220
459
  | `Ctrl-C` | Copy the selection, or the current line when nothing is selected. |
@@ -228,13 +467,27 @@ The terminal automatically reflows the Markdown when its width changes.
228
467
  Only `javascript:` links execute in the TUI; ordinary web links behave as
229
468
  normal links in the browser.
230
469
 
470
+ Local Markdown images are displayed automatically in terminals that support
471
+ the Kitty graphics protocol. Relative image paths are resolved from the
472
+ Markdown file's directory. jsmdcui reads the image dimensions, reserves the
473
+ corresponding terminal rows, and updates the placement when the document is
474
+ scrolled, resized, or shown in a split pane. Unsupported or missing images, as
475
+ well as remote images not authorized with `--allow-url`, retain Bun's normal
476
+ linked `📷` fallback. To download trusted remote Markdown and display its
477
+ supported HTTP(S) images with Kitty graphics, combine the options:
478
+
479
+ ```sh
480
+ bun src/index.js --kitty --allow-url https://example.com/app.md
481
+ ```
482
+
231
483
  ## Browser interaction
232
484
 
233
485
  The WUI uses normal browser mouse and keyboard behavior. Clicking a
234
486
  `javascript:` link calls its front-end function, regular links navigate
235
- normally, and task checkboxes can be toggled. `alert`, `confirm`, and `prompt`
236
- use the browser's built-in dialogs. Checkbox changes exist only in the current
237
- page: refreshing does not preserve them and does not update the Markdown file.
487
+ normally, and task checkboxes can be toggled by clicking either the checkbox or
488
+ its associated text. `alert`, `confirm`, and `prompt` use the browser's built-in
489
+ dialogs. Checkbox changes exist only in the current page: refreshing does not
490
+ preserve them and does not update the Markdown file.
238
491
 
239
492
  The WUI uses port `3000` by default and accepts connections through the
240
493
  machine's available network interfaces. The printed `localhost` URL is for the
@@ -260,6 +513,33 @@ app.md-server.js
260
513
  They are regenerated from `app.md`, so edit the Markdown source rather than the
261
514
  generated files. The source directory must be writable.
262
515
 
516
+ From the project directory, remove generated `*.md.*` and `*.md-*` companion
517
+ files while keeping the Markdown source files:
518
+
519
+ ```sh
520
+ bun ./clean.sh
521
+ ```
522
+
523
+ ### Generated heading sections
524
+
525
+ WUI output wraps each h1-h6 and its content in a hierarchical `<section>`.
526
+ Lower-level headings create nested sections; the next equal or higher-level
527
+ heading closes the applicable sections. Content before the first heading stays
528
+ outside all generated sections.
529
+
530
+ ```html
531
+ <section>
532
+ <h1 id="chapter">Chapter</h1>
533
+ <section>
534
+ <h2 id="topic">Topic</h2>
535
+ </section>
536
+ </section>
537
+ ```
538
+
539
+ This structure provides stable boundaries for CSS, DOM queries, and heading
540
+ task-list values. Heading-like text inside comments, scripts, styles, code,
541
+ textareas, and templates is protected and does not create sections.
542
+
263
543
  ## Security
264
544
 
265
545
  A Markdown UI is an executable application, not a passive document. Starting a
package/clean.sh ADDED
@@ -0,0 +1,9 @@
1
+ #!/bin/sh
2
+
3
+ sd=$(dirname "$0")
4
+
5
+ rm "$sd"/*.md.* "$sd"/*.md-* 2>/dev/null
6
+ rm "$sd"/demos/*.md.* "$sd"/demos/*.md-* 2>/dev/null
7
+ rm "$sd"/tests/*.md.* "$sd"/tests/*.md-* 2>/dev/null
8
+
9
+ echo "Removed all *.md.* *.md-* from repo root and demos/ folder"