feat(storage-plugin): add hex-first UI for binary entries#262
Open
burczu wants to merge 7 commits into
Open
Conversation
Adds pure helpers in src/ui/binary.ts for the upcoming hex-first
buffer UI: grouped hex (16/line, gap after byte 8), full hexdump
with offsets and an ASCII column, ASCII previews, base64 round-trip
via btoa/atob, a compact table-cell preview, and a lenient hex parser
that strips hexdump offsets, trailing ASCII columns, "0x" prefixes,
and whitespace before validating even-length hex.
All helpers are unit-tested with the spec error messages
("Enter at least one byte.", "Hex input contains invalid characters.",
"Hex input must contain complete bytes.", "Base64 input is invalid.").
Refs callstackincubator#248
Pure reducer for the binary editor: initialState encodes initial bytes into the chosen mode, set-text re-parses without rewriting, normalize-paste replaces user text with the canonical encoding on success, and switch-mode converts in place when bytes are valid or clears to a fresh editor otherwise. The reducer is fully testable without React. Validate surfaces the parse error, the canonical "Enter at least one byte." for empty input, or returns the parsed bytes when ready to save. Refs callstackincubator#248
CodeMirror-backed React component that wraps the editor reducer. Detects paste transactions and dispatches normalize-paste so canonical grouped hex (or base64) replaces the raw paste, while typed input passes through unchanged. A doc-sync effect pushes reducer text back into CodeMirror only when they diverge (after paste normalization or mode switch), with the update listener short-circuiting on round-trips to avoid loops. Adds @codemirror/state, view, and commands as devDependencies. Theme matches the panel's dark UI; gutters hidden, line-wrapping on. Component is binding-only; behavior tests live on the reducer. Refs callstackincubator#248
Switches the table cell, detail dialog, edit dialog, and add dialog to the new hex-first surfaces: - Table: compact preview "89 50 4E 47 0D 0A 1A 0A ... 128 B" replaces the decimal array. - Detail dialog: hexdump view with offsets and ASCII column, byte count in the header. - Edit/Add dialogs: BinaryValueEditor (CodeMirror, paste-normalized, Hex/Base64 toggle) replaces the JSON-array textarea when type is buffer. Save is gated on pendingBytes; the editor's onChange routes parsed bytes directly to the existing number[] write path. Enter-to- save is excluded for buffer so editor newlines work as expected. Modals widened to w-[32rem] to fit the editor comfortably. No changes to runtime, adapters, or the StorageEntry contract. Refs callstackincubator#248
Adds a "Binary entries (buffer type)" section to the storage plugin docs covering the new hex-first surfaces: compact table preview, hexdump detail view, the CodeMirror-backed editor (Hex and Base64 modes), the canonical 16-byte-per-line format, paste normalization (raw hex, grouped, multiline, hexdump rows with offsets/ASCII columns, optional 0x prefixes), incomplete-input semantics, validation messages, and a cross-adapter buffer-support matrix. Refs callstackincubator#248
Bumps @rozenite/storage-plugin as minor for the hex-first UI for binary (buffer) storage entries. Refs callstackincubator#248
6239231 to
bb10330
Compare
…preview Two small fixes around buffer editing surfaced by manual testing on the hex-first UI: - MMKV stores raw bytes per key without a type tag. After setting a buffer whose bytes decode to valid printable ASCII (e.g. hex 68 65 6c 6c 6f = "hello"), the existing getEntry heuristic called getString first and classified the result as a string, flipping the type field in the panel. Each MMKV storage now keeps an in-memory map of last-known types for keys it has set; getEntry consults the override before falling back to the heuristic. Scoped to the round-trip (edit -> save -> re-read) case within a session. - The binary editor's ASCII preview was rendered unlabeled, so for an all-ASCII buffer it visually read as the entry's value rather than a derived preview. Now prefixed with "ASCII:" to make the role explicit. Refs callstackincubator#248
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #248.
Summary
bufferentries with a hex-first UI across the storage plugin.89 50 4E 47 0D 0A 1A 0A … 128 B.0x20–0x7Eprintable, others as.).BinaryValueEditorforbuffervalues. Hex is the default mode; Base64 is available for copy/paste workflows. Bytes are the source of truth — switching modes converts in place when the input parses, or clears to a fresh editor when it doesn't.|ascii|columns, optional0xprefixes, mixed case.Enter at least one byte.,Hex input contains invalid characters.,Hex input must contain complete bytes.,Base64 input is invalid.bufferis stillnumber[]. No changes toStorageEntry,storage-view.ts, adapters, the runtime hook, or the bridge wire format.@codemirror/state,@codemirror/view,@codemirror/commands. Matches the version pins used by sqlite-plugin.@rozenite/storage-plugin.Architecture
A pure-function-first posture keeps the spec behavior tests exercisable without RTL/jsdom (which the repo doesn't have set up):
src/ui/binary.ts— pure helpers:bytesToGroupedHex,bytesToHexdump,bytesToAsciiPreview,bytesToBase64,base64ToBytes,compactBufferPreview,hexInputToBytes(lenient parser stripping hexdump offsets, ASCII columns,0xprefixes, whitespace).src/ui/binary-value-editor-state.ts— pure reducer:initialState,reduce,validate. Handlesset-text(preserves user text, re-parses),normalize-paste(rewrites text on success),switch-mode(convert in place / clear on invalid).src/ui/binary-value-editor.tsx— thin React wrapper:useReducer+ CodeMirror wiring. The update listener short-circuits on round-trips (comparing doc tostateRef.current.text) to avoid loops between the reducer and the editor.Test plan
Automated (49 tests covering the spec bullets):
binary.test.ts(30 tests): grouped hex spacing including post-byte-8 gap, hexdump offsets + ASCII column + trailing-line padding, ASCII printable boundary checks, base64 round-trip with arbitrary bytes, compact preview with/without ellipsis, hex parser accepting raw / grouped / multiline / hexdump rows / colon offsets /0xprefixes / mixed case, hex parser rejecting empty / non-hex / odd-length.binary-value-editor-state.test.ts(19 tests):initialStatefor all input shapes;set-textfor valid / invalid chars / partial nibble / cleared / non-canonical-but-valid (verifies text is not rewritten);normalize-pasterewrites hexdump → canonical, base64 → canonical, keeps raw on invalid;switch-modeconverts valid in place, clears on invalid, no-op on same mode;validatefor empty / invalid / valid.pnpm --filter @rozenite/storage-plugin test— 53/53 passing.pnpm --filter @rozenite/storage-plugin typecheck— clean.pnpm --filter @rozenite/storage-plugin lint— 0 errors (1 pre-existing unrelated warning).pnpm --filter @rozenite/docs build— website builds.Manual (playground, MMKV — others are string-only):
89 50 4E 47 0D 0A 1A 0A … N Bfor buffer entries.|ascii|) normalizes immediately into grouped hex.Out of scope
StorageEntrycontract, adapter APIs, or the storage write pipeline.