@orz/ui-hex 0.0.0-stage → 0.0.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.
Files changed (84) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +536 -2
  3. package/dist/column-fit.d.ts +16 -0
  4. package/dist/column-fit.d.ts.map +1 -0
  5. package/dist/column-fit.js +22 -0
  6. package/dist/column-fit.js.map +1 -0
  7. package/dist/decode.d.ts +11 -0
  8. package/dist/decode.d.ts.map +1 -0
  9. package/dist/decode.js +63 -0
  10. package/dist/decode.js.map +1 -0
  11. package/dist/document.d.ts +75 -0
  12. package/dist/document.d.ts.map +1 -0
  13. package/dist/document.js +523 -0
  14. package/dist/document.js.map +1 -0
  15. package/dist/editing.d.ts +66 -0
  16. package/dist/editing.d.ts.map +1 -0
  17. package/dist/editing.js +202 -0
  18. package/dist/editing.js.map +1 -0
  19. package/dist/encoding-picker.d.ts +6 -0
  20. package/dist/encoding-picker.d.ts.map +1 -0
  21. package/dist/encoding-picker.js +84 -0
  22. package/dist/encoding-picker.js.map +1 -0
  23. package/dist/encodings.d.ts +19 -0
  24. package/dist/encodings.d.ts.map +1 -0
  25. package/dist/encodings.js +106 -0
  26. package/dist/encodings.js.map +1 -0
  27. package/dist/format.d.ts +29 -0
  28. package/dist/format.d.ts.map +1 -0
  29. package/dist/format.js +73 -0
  30. package/dist/format.js.map +1 -0
  31. package/dist/hex-editor.d.ts +27 -0
  32. package/dist/hex-editor.d.ts.map +1 -0
  33. package/dist/hex-editor.js +270 -0
  34. package/dist/hex-editor.js.map +1 -0
  35. package/dist/hex-grid.d.ts +102 -0
  36. package/dist/hex-grid.d.ts.map +1 -0
  37. package/dist/hex-grid.js +860 -0
  38. package/dist/hex-grid.js.map +1 -0
  39. package/dist/hex-inspector.d.ts +12 -0
  40. package/dist/hex-inspector.d.ts.map +1 -0
  41. package/dist/hex-inspector.js +68 -0
  42. package/dist/hex-inspector.js.map +1 -0
  43. package/dist/hex-paste.d.ts +26 -0
  44. package/dist/hex-paste.d.ts.map +1 -0
  45. package/dist/hex-paste.js +42 -0
  46. package/dist/hex-paste.js.map +1 -0
  47. package/dist/hex-view.d.ts +4 -0
  48. package/dist/hex-view.d.ts.map +1 -0
  49. package/dist/hex-view.js +6 -0
  50. package/dist/hex-view.js.map +1 -0
  51. package/dist/index.d.ts +11 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +10 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/navigation.d.ts +25 -0
  56. package/dist/navigation.d.ts.map +1 -0
  57. package/dist/navigation.js +100 -0
  58. package/dist/navigation.js.map +1 -0
  59. package/dist/page-cache.d.ts +45 -0
  60. package/dist/page-cache.d.ts.map +1 -0
  61. package/dist/page-cache.js +334 -0
  62. package/dist/page-cache.js.map +1 -0
  63. package/dist/source.d.ts +22 -0
  64. package/dist/source.d.ts.map +1 -0
  65. package/dist/source.js +31 -0
  66. package/dist/source.js.map +1 -0
  67. package/dist/text-decoding-multibyte.d.ts +17 -0
  68. package/dist/text-decoding-multibyte.d.ts.map +1 -0
  69. package/dist/text-decoding-multibyte.js +448 -0
  70. package/dist/text-decoding-multibyte.js.map +1 -0
  71. package/dist/text-decoding.d.ts +45 -0
  72. package/dist/text-decoding.d.ts.map +1 -0
  73. package/dist/text-decoding.js +106 -0
  74. package/dist/text-decoding.js.map +1 -0
  75. package/dist/types.d.ts +15 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +10 -0
  78. package/dist/types.js.map +1 -0
  79. package/dist/use-hex-document-state.d.ts +10 -0
  80. package/dist/use-hex-document-state.d.ts.map +1 -0
  81. package/dist/use-hex-document-state.js +22 -0
  82. package/dist/use-hex-document-state.js.map +1 -0
  83. package/package.json +53 -3
  84. package/styles.css +456 -0
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ /** Equal field by field, so a field added later (an editing caret's nibble) counts too. */
2
+ export function sameSelection(a, b) {
3
+ if (a === b)
4
+ return true;
5
+ if (!a || !b)
6
+ return false;
7
+ const keys = Object.keys(a);
8
+ return (keys.length === Object.keys(b).length && keys.every((k) => a[k] === b[k]));
9
+ }
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAeA,2FAA2F;AAC3F,MAAM,UAAU,aAAa,CAC3B,CAAsB,EACtB,CAAsB;IAEtB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAA2B,CAAC;IACtD,OAAO,CACL,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAC1E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type HexDocument } from "./document.ts";
2
+ export interface HexDocumentState {
3
+ size: number;
4
+ dirty: boolean;
5
+ canUndo: boolean;
6
+ canRedo: boolean;
7
+ }
8
+ /** What a toolbar or a title shows about a document; a new object only after it changes. */
9
+ export declare function useHexDocumentState(doc: HexDocument): HexDocumentState;
10
+ //# sourceMappingURL=use-hex-document-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hex-document-state.d.ts","sourceRoot":"","sources":["../src/use-hex-document-state.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAElE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,4FAA4F;AAC5F,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,gBAAgB,CAoBtE"}
@@ -0,0 +1,22 @@
1
+ import { useCallback, useRef, useSyncExternalStore } from "react";
2
+ import { documentVersion } from "./document.js";
3
+ /** What a toolbar or a title shows about a document; a new object only after it changes. */
4
+ export function useHexDocumentState(doc) {
5
+ const cached = useRef(null);
6
+ const getSnapshot = useCallback(() => {
7
+ const version = documentVersion(doc);
8
+ const last = cached.current;
9
+ if (last?.doc === doc && last.version === version)
10
+ return last.state;
11
+ const state = {
12
+ size: doc.size,
13
+ dirty: doc.dirty,
14
+ canUndo: doc.canUndo,
15
+ canRedo: doc.canRedo,
16
+ };
17
+ cached.current = { doc, version, state };
18
+ return state;
19
+ }, [doc]);
20
+ return useSyncExternalStore(doc.subscribe, getSnapshot, getSnapshot);
21
+ }
22
+ //# sourceMappingURL=use-hex-document-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-hex-document-state.js","sourceRoot":"","sources":["../src/use-hex-document-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAElE,OAAO,EAAE,eAAe,EAAoB,MAAM,eAAe,CAAC;AASlE,4FAA4F;AAC5F,MAAM,UAAU,mBAAmB,CAAC,GAAgB;IAClD,MAAM,MAAM,GAAG,MAAM,CAIX,IAAI,CAAC,CAAC;IAChB,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;QAC5B,IAAI,IAAI,EAAE,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QACrE,MAAM,KAAK,GAAG;YACZ,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAC;QACF,MAAM,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACV,OAAO,oBAAoB,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AACvE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,56 @@
1
1
  {
2
2
  "name": "@orz/ui-hex",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.0.0",
4
+ "description": "Virtualised hex viewer and data inspector over in-memory or paged byte sources",
5
+ "license": "BSD-3-Clause",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/orzFly/ui.git",
9
+ "directory": "packages/ui-hex"
10
+ },
11
+ "type": "module",
12
+ "sideEffects": [
13
+ "**/*.css"
14
+ ],
15
+ "exports": {
16
+ ".": {
17
+ "@orz/source": "./src/index.ts",
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./styles.css": "./styles.css"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "styles.css"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "peerDependencies": {
31
+ "lucide-react": "^1",
32
+ "radix-ui": "^1",
33
+ "react": "^19",
34
+ "react-dom": "^19",
35
+ "@orz/ui": "^0.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@testing-library/react": "^16.3.2",
39
+ "@types/node": "^22.20.5",
40
+ "@types/react": "^19.2.18",
41
+ "@types/react-dom": "^19.2.4",
42
+ "happy-dom": "^21.0.3",
43
+ "lucide-react": "^1.31.0",
44
+ "radix-ui": "^1.6.7",
45
+ "react": "^19.2.8",
46
+ "react-dom": "^19.2.8",
47
+ "sonner": "^2.0.8",
48
+ "vitest": "^5.0.5",
49
+ "@orz/ui": "0.0.0"
50
+ },
51
+ "scripts": {
52
+ "build": "tsc -p tsconfig.build.json",
53
+ "typecheck": "tsc --noEmit",
54
+ "test": "vitest run"
55
+ }
6
56
  }
package/styles.css ADDED
@@ -0,0 +1,456 @@
1
+ /* Load after @orz/ui/styles.css. The --hex-* defaults are declared on the
2
+ components' own roots, so their var(--primary) and friends resolve
3
+ against whichever theme class sits above them; an override therefore has
4
+ to target .orz-hex or .orz-hex-inspector itself, not an ancestor. */
5
+
6
+ .orz-hex,
7
+ .orz-hex-inspector {
8
+ --hex-font: var(
9
+ --font-mono,
10
+ ui-monospace,
11
+ SFMono-Regular,
12
+ Menlo,
13
+ Consolas,
14
+ monospace
15
+ );
16
+ --hex-row-height: 1.375rem;
17
+ --hex-fill: color-mix(in oklch, var(--primary) 32%, var(--card));
18
+ --hex-edge: var(--primary);
19
+ --hex-twin-fill: color-mix(in oklch, var(--foreground) 6%, var(--card));
20
+ --hex-twin-edge: var(--muted-foreground);
21
+ --hex-hover: var(--accent);
22
+ --hex-label: var(--muted-foreground);
23
+ --hex-faded: color-mix(in oklch, var(--muted-foreground) 70%, transparent);
24
+ --hex-modified: var(--destructive);
25
+ /* Not documented as tokens: cell geometry the panes and header share. */
26
+ --hex-cell-pad: 0.25rem;
27
+ --hex-group-gap: 0.6rem;
28
+ --hex-text-cell: 1.6ch;
29
+ }
30
+
31
+ .orz-hex {
32
+ position: relative;
33
+ display: flex;
34
+ flex-direction: column;
35
+ min-width: 0;
36
+ max-width: 100%;
37
+ width: max-content;
38
+ box-sizing: border-box;
39
+ overflow: hidden;
40
+ border: 1px solid var(--border);
41
+ border-radius: var(--radius, 0.5rem);
42
+ background: var(--card);
43
+ color: var(--card-foreground);
44
+ font-family: var(--hex-font);
45
+ font-size: 0.8125rem;
46
+ font-variant-numeric: tabular-nums;
47
+ line-height: var(--hex-row-height);
48
+ outline: none;
49
+ user-select: none;
50
+ -webkit-user-select: none;
51
+ touch-action: pan-x pan-y;
52
+ }
53
+ .orz-hex[data-fill] {
54
+ height: 100%;
55
+ }
56
+ /* As wide as the most columns need, so that a narrower width is the limit
57
+ the columns are fitted to. */
58
+ .orz-hex[data-columns-auto] {
59
+ width: var(--hex-auto-width, max-content);
60
+ }
61
+ .orz-hex[data-resizable] {
62
+ min-width: 10rem;
63
+ min-height: 6rem;
64
+ }
65
+ .orz-hex[data-resizable="both"] {
66
+ resize: both;
67
+ }
68
+ .orz-hex[data-resizable="horizontal"] {
69
+ resize: horizontal;
70
+ }
71
+ .orz-hex[data-resizable="vertical"] {
72
+ resize: vertical;
73
+ }
74
+ .orz-hex:focus {
75
+ border-color: var(--ring);
76
+ }
77
+
78
+ .orz-hex-measure {
79
+ position: absolute;
80
+ visibility: hidden;
81
+ pointer-events: none;
82
+ }
83
+
84
+ .orz-hex-probe {
85
+ position: absolute;
86
+ visibility: hidden;
87
+ pointer-events: none;
88
+ width: 0;
89
+ height: var(--hex-row-height);
90
+ }
91
+
92
+ .orz-hex-scroller {
93
+ position: relative;
94
+ overflow: auto;
95
+ overscroll-behavior: contain;
96
+ /* Firefox leaves a vertical scrollbar that appears after layout out of the
97
+ max-content width, so the rows overflow by its width; a reserved gutter
98
+ is counted up front. */
99
+ scrollbar-gutter: stable;
100
+ padding-inline: 0.625rem;
101
+ }
102
+ .orz-hex[data-fill] .orz-hex-scroller {
103
+ flex: 1 1 0;
104
+ min-height: 0;
105
+ }
106
+
107
+ .orz-hex-header {
108
+ position: sticky;
109
+ top: 0;
110
+ z-index: 3;
111
+ background: var(--card);
112
+ color: var(--hex-label);
113
+ }
114
+
115
+ .orz-hex-spacer {
116
+ position: relative;
117
+ width: max-content;
118
+ /* A selected cell's 1px contour may overhang the edge. */
119
+ overflow: clip;
120
+ overflow-clip-margin: 1px;
121
+ }
122
+ /* Pinned under the header while the spacer scrolls: the scroll position only
123
+ picks the top row, so the view moves by whole rows like the reference. */
124
+ .orz-hex-layer {
125
+ position: sticky;
126
+ }
127
+
128
+ .orz-hex-row {
129
+ display: flex;
130
+ height: var(--hex-row-height);
131
+ white-space: pre;
132
+ }
133
+
134
+ .orz-hex-addr {
135
+ flex: none;
136
+ box-sizing: content-box;
137
+ min-width: 4ch;
138
+ padding-right: 0.75rem;
139
+ color: var(--hex-label);
140
+ }
141
+
142
+ .orz-hex-pane-gap {
143
+ flex: none;
144
+ width: 1rem;
145
+ }
146
+
147
+ .orz-hex-text-label {
148
+ flex: none;
149
+ display: flex;
150
+ align-items: center;
151
+ min-width: 0;
152
+ padding-left: 0.2ch;
153
+ }
154
+ /* Wraps the aria-hidden column labels without joining the header's flex row,
155
+ so the picker beside them stays reachable. */
156
+ .orz-hex-header-labels {
157
+ display: contents;
158
+ }
159
+
160
+ /* The encoding picker's trigger, @orz/ui's FilterMenu behind it, sized to
161
+ the header row. Unlayered, so it wins over any layered utilities. */
162
+ .orz-hex-encoding {
163
+ display: inline-flex;
164
+ align-items: center;
165
+ box-sizing: border-box;
166
+ white-space: nowrap;
167
+ max-width: 100%;
168
+ height: var(--hex-row-height);
169
+ gap: 0.25rem;
170
+ margin-left: -0.2ch;
171
+ padding: 0 0.25rem 0 0.2ch;
172
+ border: 1px solid transparent;
173
+ border-radius: calc(var(--radius, 0.5rem) - 0.25rem);
174
+ background: transparent;
175
+ box-shadow: none;
176
+ color: var(--hex-label);
177
+ font: inherit;
178
+ line-height: inherit;
179
+ cursor: pointer;
180
+ }
181
+ .orz-hex-encoding:hover,
182
+ .orz-hex-encoding[data-state="open"] {
183
+ background: var(--hex-hover);
184
+ }
185
+ .orz-hex-encoding:focus-visible {
186
+ border-color: var(--ring);
187
+ box-shadow: none;
188
+ outline: none;
189
+ }
190
+ .orz-hex-encoding-value {
191
+ display: block;
192
+ min-width: 0;
193
+ overflow: hidden;
194
+ text-overflow: ellipsis;
195
+ }
196
+ .orz-hex-encoding svg {
197
+ flex-shrink: 0;
198
+ width: 0.875rem;
199
+ height: 0.875rem;
200
+ }
201
+ /* The menu is portalled out of .orz-hex, and this sheet is plain CSS that
202
+ Tailwind never scans, so its rows are styled here rather than by utilities. */
203
+ .orz-hex-encoding-menu {
204
+ width: 20rem;
205
+ }
206
+ .orz-hex-encoding-label {
207
+ min-width: 0;
208
+ overflow: hidden;
209
+ text-overflow: ellipsis;
210
+ white-space: nowrap;
211
+ }
212
+ .orz-hex-encoding-alias {
213
+ flex-shrink: 0;
214
+ margin-left: auto;
215
+ color: var(--muted-foreground);
216
+ font-size: 0.75rem;
217
+ }
218
+
219
+ /* Cells have no margins: the contour depends on neighbours touching. Each
220
+ state sets variables on the cell, and the content box reads them once. */
221
+ .orz-hex-cell {
222
+ --cell-pad: var(--hex-cell-pad);
223
+ --cell-pad-end: var(--cell-pad);
224
+ --cell-fill: var(--hex-twin-fill);
225
+ --cell-edge: var(--hex-twin-edge);
226
+ position: relative;
227
+ display: block;
228
+ flex: none;
229
+ height: var(--hex-row-height);
230
+ }
231
+ .orz-hex-text-cell {
232
+ --cell-pad: 0;
233
+ width: var(--hex-text-cell);
234
+ text-align: center;
235
+ }
236
+ .orz-hex-cell[data-group-end] {
237
+ --cell-pad-end: var(--hex-group-gap);
238
+ }
239
+ .orz-hex:focus[data-active-pane="hex"] [data-pane="hex"],
240
+ .orz-hex:focus[data-active-pane="text"] [data-pane="text"] {
241
+ --cell-fill: var(--hex-fill);
242
+ --cell-edge: var(--hex-edge);
243
+ }
244
+
245
+ /* One contour per range: an edge layer 1px larger behind every selected
246
+ cell, and fills above all of them that cover the inner edges. */
247
+ .orz-hex-cell[data-sel] {
248
+ --cell-bg: var(--cell-fill);
249
+ }
250
+ .orz-hex-cell[data-sel]::before {
251
+ content: "";
252
+ position: absolute;
253
+ inset: -1px;
254
+ z-index: 0;
255
+ background: var(--cell-edge);
256
+ }
257
+ .orz-hex:not([data-dragging]) [data-hover] {
258
+ --cell-bg: var(--hex-hover);
259
+ }
260
+ .orz-hex:not([data-dragging]) [data-hover][data-sel] {
261
+ --cell-bg: color-mix(in oklch, var(--cell-fill) 60%, var(--hex-hover));
262
+ }
263
+ .orz-hex:focus [data-caret] {
264
+ --cell-caret: inset 0 -2px 0 var(--cell-edge);
265
+ }
266
+
267
+ .orz-hex-cell-content {
268
+ position: relative;
269
+ z-index: 1;
270
+ display: block;
271
+ box-sizing: border-box;
272
+ height: 100%;
273
+ padding-inline: var(--cell-pad) var(--cell-pad-end);
274
+ background: var(--cell-bg, transparent);
275
+ box-shadow: var(--cell-caret, none);
276
+ }
277
+
278
+ /* Two stacked letters, drawn as text: no monospace webfont covers the
279
+ U+2400 control pictures, and a fallback glyph would break the grid. */
280
+ .orz-hex-control {
281
+ display: grid;
282
+ grid-template-rows: 1fr 1fr;
283
+ align-content: center;
284
+ padding-block: 0.15em;
285
+ font-size: 0.55em;
286
+ font-weight: 500;
287
+ line-height: 1;
288
+ }
289
+ .orz-hex-control b {
290
+ display: block;
291
+ padding-inline: 0.15em;
292
+ font-weight: inherit;
293
+ text-align: left;
294
+ }
295
+ .orz-hex-control b + b {
296
+ text-align: right;
297
+ }
298
+
299
+ /* Above every cell's fill, so a neighbour's selection or hover cannot cover
300
+ the part of the glyph over it; hit-testing still lands on the cells
301
+ beneath. */
302
+ .orz-hex-glyph {
303
+ position: absolute;
304
+ inset-block: 0;
305
+ left: 0;
306
+ z-index: 2;
307
+ display: flex;
308
+ align-items: center;
309
+ justify-content: center;
310
+ width: calc(var(--hex-glyph-span) * 100%);
311
+ pointer-events: none;
312
+ white-space: pre;
313
+ }
314
+ .orz-hex-glyph > span {
315
+ transform: scaleX(var(--hex-glyph-squeeze, 1));
316
+ }
317
+
318
+ .orz-hex-cell[data-faded]:not([data-sel]):not([data-hover]),
319
+ .orz-hex-cell[data-state="loading"] {
320
+ color: var(--hex-faded);
321
+ }
322
+ .orz-hex-cell[data-state="error"] {
323
+ color: var(--destructive);
324
+ }
325
+
326
+ /* HexEditor */
327
+
328
+ /* Wins over the faded rule above: a typed 00 is an edit, not padding. */
329
+ .orz-hex .orz-hex-cell[data-modified]:not([data-state]) {
330
+ color: var(--hex-modified);
331
+ }
332
+
333
+ /* In the hex pane the caret marks the digit the next keystroke writes. */
334
+ .orz-hex:focus [data-pane="hex"][data-caret="0"],
335
+ .orz-hex:focus [data-pane="hex"][data-caret="1"] {
336
+ --cell-caret: none;
337
+ }
338
+ .orz-hex-nibble {
339
+ display: inline-block;
340
+ }
341
+ .orz-hex:focus [data-caret="0"] .orz-hex-nibble:first-child,
342
+ .orz-hex:focus [data-caret="1"] .orz-hex-nibble:last-child {
343
+ box-shadow: inset 0 -2px 0 var(--cell-edge);
344
+ }
345
+
346
+ /* Insert mode: a bar before the cell, where the next byte goes. Mid-byte,
347
+ the low digit is still overwritten, so it keeps the digit underline. */
348
+ .orz-hex[data-mode="insert"]:focus [data-caret]:not([data-caret="1"]) {
349
+ --cell-caret: inset 2px 0 0 var(--cell-edge);
350
+ }
351
+ .orz-hex[data-mode="insert"]:focus [data-caret="0"] .orz-hex-nibble {
352
+ box-shadow: none;
353
+ }
354
+
355
+ /* Hex cells take their width from their digits, so a cell with none has to
356
+ reserve two, or a short last row pulls its text pane left. */
357
+ .orz-hex-cell[data-append][data-pane="hex"] .orz-hex-cell-content,
358
+ .orz-hex-cell[data-empty]:not(.orz-hex-text-cell) .orz-hex-cell-content {
359
+ width: calc(2ch + var(--cell-pad) + var(--cell-pad-end));
360
+ }
361
+ .orz-hex:focus [data-append][data-caret] {
362
+ --cell-caret: inset 0 -2px 0 var(--cell-edge);
363
+ }
364
+
365
+ .orz-hex-status-end {
366
+ display: flex;
367
+ align-items: center;
368
+ gap: 0.75rem;
369
+ }
370
+ .orz-hex-mode {
371
+ padding: 0 0.375rem;
372
+ border: 1px solid var(--border);
373
+ border-radius: calc(var(--radius, 0.5rem) - 0.25rem);
374
+ background: transparent;
375
+ color: inherit;
376
+ font: inherit;
377
+ line-height: 1rem;
378
+ cursor: pointer;
379
+ }
380
+ .orz-hex-mode[aria-pressed="true"] {
381
+ background: var(--background);
382
+ color: var(--foreground);
383
+ }
384
+ .orz-hex-mode:disabled {
385
+ cursor: default;
386
+ opacity: 0.6;
387
+ }
388
+ .orz-hex-mode:focus-visible {
389
+ outline: 2px solid var(--ring);
390
+ outline-offset: 1px;
391
+ }
392
+
393
+ .orz-hex-status {
394
+ display: flex;
395
+ flex: none;
396
+ justify-content: space-between;
397
+ gap: 1rem;
398
+ padding: 0.25rem 0.625rem;
399
+ border-top: 1px solid var(--border);
400
+ background: var(--muted);
401
+ color: var(--muted-foreground);
402
+ font-size: 0.6875rem;
403
+ line-height: 1.25rem;
404
+ white-space: nowrap;
405
+ }
406
+ /* Clear of the resize handle in the corner. */
407
+ .orz-hex[data-resizable] .orz-hex-status {
408
+ padding-right: 1.25rem;
409
+ }
410
+
411
+ .orz-hex-live {
412
+ position: absolute;
413
+ width: 1px;
414
+ height: 1px;
415
+ margin: -1px;
416
+ overflow: hidden;
417
+ clip-path: inset(50%);
418
+ white-space: nowrap;
419
+ }
420
+
421
+ /* HexInspector */
422
+
423
+ .orz-hex-inspector {
424
+ display: flex;
425
+ flex-direction: column;
426
+ gap: 0.5rem;
427
+ font-size: 0.8125rem;
428
+ color: var(--foreground);
429
+ }
430
+ .orz-hex-inspector-heading {
431
+ margin: 0;
432
+ font-weight: 600;
433
+ }
434
+ .orz-hex-inspector-list {
435
+ display: grid;
436
+ grid-template-columns: max-content minmax(0, 1fr);
437
+ column-gap: 1rem;
438
+ row-gap: 0.125rem;
439
+ margin: 0;
440
+ }
441
+ .orz-hex-inspector-list dt {
442
+ color: var(--muted-foreground);
443
+ }
444
+ .orz-hex-inspector-list dd {
445
+ margin: 0;
446
+ font-family: var(--hex-font);
447
+ overflow-wrap: anywhere;
448
+ }
449
+ .orz-hex-inspector-list [data-dimmed] {
450
+ opacity: 0.45;
451
+ }
452
+ .orz-hex-inspector-endian {
453
+ display: flex;
454
+ align-items: center;
455
+ gap: 0.5rem;
456
+ }