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 +165 -15
- package/dist/index.js +1160 -343
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# VueHex
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://vvollers.github.io/vuehex/demo/)
|
|
4
|
+
[](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 (~
|
|
7
|
-
* Render local
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
464
|
+
- `left` (left-aligned)
|
|
465
|
+
- `middle` (centered)
|
|
466
|
+
- `right` (right-aligned)
|
|
364
467
|
|
|
365
|
-
|
|
468
|
+
Each section is an array of **status bar components** (strings or `{ name, config }` objects). Unknown component names are ignored.
|
|
366
469
|
|
|
367
|
-
|
|
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
|
-
|
|
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
|
|
543
|
+
The `"slot"` entry controls where your slot content renders relative to built-in items.
|
|
394
544
|
|
|
395
545
|
## License
|
|
396
546
|
|