@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.
- package/LICENSE +29 -0
- package/README.md +536 -2
- package/dist/column-fit.d.ts +16 -0
- package/dist/column-fit.d.ts.map +1 -0
- package/dist/column-fit.js +22 -0
- package/dist/column-fit.js.map +1 -0
- package/dist/decode.d.ts +11 -0
- package/dist/decode.d.ts.map +1 -0
- package/dist/decode.js +63 -0
- package/dist/decode.js.map +1 -0
- package/dist/document.d.ts +75 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +523 -0
- package/dist/document.js.map +1 -0
- package/dist/editing.d.ts +66 -0
- package/dist/editing.d.ts.map +1 -0
- package/dist/editing.js +202 -0
- package/dist/editing.js.map +1 -0
- package/dist/encoding-picker.d.ts +6 -0
- package/dist/encoding-picker.d.ts.map +1 -0
- package/dist/encoding-picker.js +84 -0
- package/dist/encoding-picker.js.map +1 -0
- package/dist/encodings.d.ts +19 -0
- package/dist/encodings.d.ts.map +1 -0
- package/dist/encodings.js +106 -0
- package/dist/encodings.js.map +1 -0
- package/dist/format.d.ts +29 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +73 -0
- package/dist/format.js.map +1 -0
- package/dist/hex-editor.d.ts +27 -0
- package/dist/hex-editor.d.ts.map +1 -0
- package/dist/hex-editor.js +270 -0
- package/dist/hex-editor.js.map +1 -0
- package/dist/hex-grid.d.ts +102 -0
- package/dist/hex-grid.d.ts.map +1 -0
- package/dist/hex-grid.js +860 -0
- package/dist/hex-grid.js.map +1 -0
- package/dist/hex-inspector.d.ts +12 -0
- package/dist/hex-inspector.d.ts.map +1 -0
- package/dist/hex-inspector.js +68 -0
- package/dist/hex-inspector.js.map +1 -0
- package/dist/hex-paste.d.ts +26 -0
- package/dist/hex-paste.d.ts.map +1 -0
- package/dist/hex-paste.js +42 -0
- package/dist/hex-paste.js.map +1 -0
- package/dist/hex-view.d.ts +4 -0
- package/dist/hex-view.d.ts.map +1 -0
- package/dist/hex-view.js +6 -0
- package/dist/hex-view.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation.d.ts +25 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +100 -0
- package/dist/navigation.js.map +1 -0
- package/dist/page-cache.d.ts +45 -0
- package/dist/page-cache.d.ts.map +1 -0
- package/dist/page-cache.js +334 -0
- package/dist/page-cache.js.map +1 -0
- package/dist/source.d.ts +22 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +31 -0
- package/dist/source.js.map +1 -0
- package/dist/text-decoding-multibyte.d.ts +17 -0
- package/dist/text-decoding-multibyte.d.ts.map +1 -0
- package/dist/text-decoding-multibyte.js +448 -0
- package/dist/text-decoding-multibyte.js.map +1 -0
- package/dist/text-decoding.d.ts +45 -0
- package/dist/text-decoding.d.ts.map +1 -0
- package/dist/text-decoding.js +106 -0
- package/dist/text-decoding.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/use-hex-document-state.d.ts +10 -0
- package/dist/use-hex-document-state.d.ts.map +1 -0
- package/dist/use-hex-document-state.js +22 -0
- package/dist/use-hex-document-state.js.map +1 -0
- package/package.json +53 -3
- 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
|
|
4
|
-
"
|
|
5
|
-
"
|
|
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
|
+
}
|