vuehex 0.5.8 → 0.6.1

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/README.md CHANGED
@@ -1,10 +1,15 @@
1
1
  # VueHex
2
2
 
3
- VueHex is a fast, virtualized hex viewer component for Vue 3. It can be used both for cleanly displaying binary data and for efficiently viewing very large datasets.
3
+ [![Live Demo](https://img.shields.io/badge/Live_Demo-2da44e?style=for-the-badge)](https://vvollers.github.io/vuehex/demo/)
4
+ [![Documentation](https://img.shields.io/badge/Documentation-0969da?style=for-the-badge)](https://vvollers.github.io/vuehex/docs/)
5
+
6
+ ## Description
7
+
8
+ VueHex is a fast, virtualized hex viewer/editor component for Vue 3. It can be used both for cleanly viewing and editing binary data and for efficiently handling very large datasets.
4
9
 
5
10
  * No dependencies
6
- * Small package (~64KB minimized / ~15KB zipped)
7
- * Render local and remote data
11
+ * Small package (~72KB minimized / ~18KB zipped)
12
+ * Render any local or remote data
8
13
  * Can handle extremely large data sizes
9
14
  * Very flexible and themeable, can be as simple or as complicated as you wish
10
15
 
@@ -16,7 +21,7 @@ VueHex is a fast, virtualized hex viewer component for Vue 3. It can be used bot
16
21
  npm install vuehex
17
22
  ```
18
23
 
19
- Optionally register the plugin once to make the `<VueHex>` component available everywhere and load the bundled styles:
24
+ Register the plugin once to make the `<VueHex>` component available everywhere and load the bundled styles:
20
25
 
21
26
  ```ts
22
27
  import { createApp } from "vue";
@@ -68,6 +73,7 @@ const windowData = ref(backingFile.slice(0, 16 * 48));
68
73
  | `statusbar` | `null` | Status bar placement: `'top'`, `'bottom'`, or `null` to hide. Shows byte info on hover and selection details. |
69
74
  | `statusbarLayout` | — | Configuration object controlling which items appear in the status bar and their placement (`left`, `middle`, `right` sections). |
70
75
  | `cursor` | `false` | Enable keyboard/click cursor navigation. Navigate with arrow keys when focused or click bytes to move cursor. |
76
+ | `editable` | `false` | Enable editor mode. Typing/paste/cut emit `edit` intents. Cursor is automatically enabled while editing. |
71
77
 
72
78
  ## Models
73
79
 
@@ -86,12 +92,101 @@ VueHex emits several events to enable interactive features:
86
92
  | Event | Payload | Description |
87
93
  |-------|---------|-------------|
88
94
  | `updateVirtualData` | `{ offset: number, length: number }` | Emitted when the component needs more data in windowed mode. Load the requested byte range and update `v-model` with the new data. |
95
+ | `edit` | `VueHexEditIntent` | Emitted when `editable` is enabled and the user types, deletes, pastes, or cuts. In windowed mode, the parent should apply the intent to the backing store and refresh `v-model`. |
89
96
  | `byte-click` | `{ index: number, byte: number, kind: 'hex' \| 'ascii' }` | Emitted when a user clicks on a specific byte cell. `index` is the absolute byte position, `byte` is the value (0-255), and `kind` indicates whether the hex or ASCII column was clicked. |
90
97
  | `selection-change` | `{ start: number \| null, end: number \| null, length: number }` | Emitted when the selection range changes. `start` and `end` are absolute byte positions (inclusive), or `null` if nothing is selected. `length` is the number of selected bytes. |
91
98
  | `row-hover-on` / `row-hover-off` | `{ offset: number }` | Emitted when hovering over/leaving a row. |
92
99
  | `hex-hover-on` / `hex-hover-off` | `{ index: number, byte: number }` | Emitted when hovering over/leaving a hex cell. |
93
100
  | `ascii-hover-on` / `ascii-hover-off` | `{ index: number, byte: number }` | Emitted when hovering over/leaving an ASCII cell. |
94
101
 
102
+ ## Editable mode
103
+
104
+ Set `editable` to turn VueHex into a hex editor. VueHex emits a single `edit` event describing user intent.
105
+
106
+ Editing highlights:
107
+
108
+ - Click hex vs ASCII to choose the active column (or press `Tab` to toggle).
109
+ - Press `Insert` to toggle insert/overwrite mode.
110
+ - Hex typing commits after two nibbles.
111
+ - Selection integrates with editing: typing/paste replaces the selection; `Delete`/`Backspace` delete the selection.
112
+ - Clipboard shortcuts:
113
+ - `Ctrl/Cmd+C` copy selection
114
+ - `Ctrl/Cmd+V` paste (hex column treats clipboard as hex bytes; whitespace is ignored)
115
+ - `Ctrl/Cmd+X` cut (copy + delete selection)
116
+ - Undo/redo shortcuts:
117
+ - `Ctrl/Cmd+Z` undo
118
+ - `Ctrl/Cmd+Y` redo (also `Ctrl/Cmd+Shift+Z`)
119
+
120
+ ### Buffer mode (self-managed)
121
+
122
+ In `data-mode="buffer"`, VueHex will apply edits to `v-model` automatically. Listening to `@edit` is optional.
123
+
124
+ Undo/redo is built-in in this mode and is implemented as a compact history of edit diffs (not full buffer snapshots).
125
+
126
+ ```vue
127
+ <template>
128
+ <VueHex v-model="bytes" data-mode="buffer" editable style="height: 320px" />
129
+ </template>
130
+
131
+ <script setup lang="ts">
132
+ import { ref } from "vue";
133
+ import VueHex from "vuehex";
134
+
135
+ const bytes = ref(new Uint8Array(await file.arrayBuffer()));
136
+ </script>
137
+ ```
138
+
139
+ ### Window mode (parent-managed)
140
+
141
+ In `data-mode="window"`, VueHex does not own the full dataset. The parent is responsible for applying `edit` intents to the backing store and then refreshing `windowData`.
142
+
143
+ For undo/redo in windowed mode, VueHex emits `{ kind: "undo" }` / `{ kind: "redo" }` intents on the `edit` event and the parent should implement history.
144
+
145
+ ```vue
146
+ <template>
147
+ <VueHex
148
+ v-model="windowData"
149
+ data-mode="window"
150
+ :window-offset="windowOffset"
151
+ :total-size="store.length"
152
+ :get-selection-data="getSelectionData"
153
+ editable
154
+ style="height: 320px"
155
+ @updateVirtualData="handleUpdateVirtualData"
156
+ @edit="handleEdit"
157
+ />
158
+ </template>
159
+
160
+ <script setup lang="ts">
161
+ import { ref } from "vue";
162
+ import VueHex, { type VueHexEditIntent, type VueHexWindowRequest } from "vuehex";
163
+
164
+ const store = ref(new Uint8Array(await file.arrayBuffer()));
165
+ const windowOffset = ref(0);
166
+ const windowData = ref(new Uint8Array());
167
+ let windowLength = 0x4000;
168
+
169
+ function handleUpdateVirtualData(request: VueHexWindowRequest) {
170
+ windowOffset.value = request.offset;
171
+ windowLength = request.length ?? windowLength;
172
+ windowData.value = store.value.slice(windowOffset.value, windowOffset.value + windowLength);
173
+ }
174
+
175
+ function getSelectionData(start: number, end: number) {
176
+ const from = Math.min(start, end);
177
+ const to = Math.max(start, end);
178
+ return store.value.slice(from, to + 1);
179
+ }
180
+
181
+ function handleEdit(intent: VueHexEditIntent) {
182
+ // Apply the intent to your backing store, then refresh windowData.
183
+ // (See Storybook "Editable (windowed)" / docs guide for a complete apply function.)
184
+ store.value = applyEditIntent(store.value, intent);
185
+ windowData.value = store.value.slice(windowOffset.value, windowOffset.value + windowLength);
186
+ }
187
+ </script>
188
+ ```
189
+
95
190
  ## Styling options
96
191
 
97
192
  1. Import `vuehex/styles` for the default look.
@@ -117,7 +212,7 @@ VueHex solves this with optimized **virtual scrolling**:
117
212
 
118
213
  The above technique works very well, but unfortunately it has a limit. Browsers impose limits on element dimensions to prevent rendering engine crashes. Most modern browsers cap `max-height` at around **33,554,432 pixels** (Chrome/Edge) or **17,895,698 pixels** (Firefox). Once your calculated scroll container height exceeds this limit, virtualization breaks—the scrollbar becomes inaccurate, and you can't reach data beyond the cap.
119
214
 
120
- For a hex viewer with 16 bytes per row and 24px row height:
215
+ For a hex viewer/editor with 16 bytes per row and 24px row height:
121
216
  - **Firefox limit:** ~746,000 rows = ~11.4 MB of data
122
217
  - **Chrome limit:** ~1.4 million rows = ~21.4 MB of data
123
218
 
@@ -358,17 +453,72 @@ Customize individual chunk items with access to chunk data and active state:
358
453
 
359
454
  Both slots are optional. If not provided, VueHex uses the default chunk navigator appearance.
360
455
 
361
- ## Status Bar Slots
456
+ ## Status bar
457
+
458
+ Enable the status bar by setting `statusbar="top"` or `statusbar="bottom"`. You can control which items appear (and where) using `statusbarLayout`.
459
+
460
+ ### Layout
461
+
462
+ `statusbarLayout` splits the status bar into three sections:
362
463
 
363
- When using the status bar (`statusbar="top"` or `statusbar="bottom"`), you can provide custom content via slots. Use the `statusbarLayout` prop with the `"slot"` component name to control where your custom content appears.
464
+ - `left` (left-aligned)
465
+ - `middle` (centered)
466
+ - `right` (right-aligned)
364
467
 
365
- ### Available slots
468
+ Each section is an array of **status bar components** (strings or `{ name, config }` objects). Unknown component names are ignored.
366
469
 
367
- - `#statusbar-left` - Content for the left section
368
- - `#statusbar-middle` - Content for the middle section
369
- - `#statusbar-right` - Content for the right section
470
+ When `statusbarLayout` is omitted, VueHex defaults to:
370
471
 
371
- ### Example
472
+ - `left: ["offset", "hex", "ascii"]`
473
+ - `right: ["selection"]`
474
+
475
+ ### Built-in components
476
+
477
+ - `offset`: hovered byte offset (respects `uppercase` + `isPrintable`/`renderAscii` where relevant)
478
+ - `hex`: hovered byte value as a 2-digit hex string
479
+ - `ascii`: hovered byte rendered as ASCII (or `nonPrintableChar`)
480
+ - `selection`: selection summary (`"<count> bytes (start–end)"`)
481
+ - `editable`: editor state label (`VIEW` / `EDIT`)
482
+ - `mode`: editor mode (`INS` / `OVR`) or placeholder when not available
483
+ - `column`: active editor column (`HEX` / `ASCII`) or placeholder when not available
484
+ - `total`: total size in bytes (derived from `totalSize` when provided; otherwise `v-model.length`). Does not include the EOF "ghost" cell.
485
+ - `slot`: renders one of the status bar slots (see below)
486
+
487
+ Notes:
488
+
489
+ - The hover-driven items (`offset`, `hex`, `ascii`) reflect the cell under the mouse, not the keyboard cursor.
490
+ - Editor items (`editable`, `mode`, `column`) render whenever they are included in the layout (they do not auto-hide when `editable` is false).
491
+
492
+ ### Per-component configuration (`config`)
493
+
494
+ All built-ins support:
495
+
496
+ - `label` (string): overrides the label text
497
+ - `valueMinWidth` (string): CSS length (e.g. `"10ch"`) for stable widths
498
+ - `valueWidth` (string): CSS length (e.g. `"120px"`)
499
+
500
+ Component-specific keys:
501
+
502
+ - `offset`: `format` (`"hex"` or `"decimal"`), `pad` (number), `prefix` (boolean)
503
+ - `hex`: `prefix` (boolean)
504
+ - `ascii`: `quote` (boolean)
505
+ - `selection`: `showWhenEmpty` (boolean)
506
+ - `editable`: `short` (boolean)
507
+ - `mode`: `short` (boolean), `placeholder` (string)
508
+ - `column`: `short` (boolean), `placeholder` (string)
509
+ - `total`: `format` (`"human"` or `"hex"`), `decimals` (number, for `"human"`), `unit` (boolean), `pad` (number, for `"hex"`), `prefix` (boolean, for `"hex"`)
510
+
511
+ ### Slot components
512
+
513
+ Use the built-in `"slot"` component name to render your own custom content inside the status bar.
514
+
515
+ Available slots:
516
+
517
+ - `#statusbar-left`
518
+ - `#statusbar-middle`
519
+ - `#statusbar-right`
520
+
521
+ Example:
372
522
 
373
523
  ```vue
374
524
  <VueHex
@@ -377,20 +527,20 @@ When using the status bar (`statusbar="top"` or `statusbar="bottom"`), you can p
377
527
  :statusbar-layout="{
378
528
  left: ['offset', 'slot', 'hex'],
379
529
  middle: ['ascii'],
380
- right: ['selection', 'slot']
530
+ right: ['selection', 'slot'],
381
531
  }"
382
532
  >
383
533
  <template #statusbar-left>
384
534
  <span>Mode: RO</span>
385
535
  </template>
386
-
536
+
387
537
  <template #statusbar-right>
388
538
  <span>Endian: LE</span>
389
539
  </template>
390
540
  </VueHex>
391
541
  ```
392
542
 
393
- The `"slot"` entry in `statusbarLayout` determines where your custom content renders relative to built-in status bar items. You can place it at any position within each section array.
543
+ The `"slot"` entry controls where your slot content renders relative to built-in items.
394
544
 
395
545
  ## License
396
546