@coldsmirk/inkstone-core 0.18.0 → 0.19.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 +19 -1
- package/dist/index.d.ts +96 -2
- package/dist/index.js +83 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,9 @@ Part of [inkstone](https://github.com/coldsmirk/inkstone). The editor layers ([`
|
|
|
9
9
|
- **`getHighlighter()`** — the process-wide `HighlighterCore` promise. JavaScript / TypeScript / JSON / SQL grammars and the catppuccin theme pair load by default.
|
|
10
10
|
- **`configureHighlighter(config)`** — extend or replace the default grammar / theme set, once, before any editor mounts. `DEFAULT_HIGHLIGHTER_LANGS` is exported so extension is additive.
|
|
11
11
|
- **`shikiThemeId(dark)`** plus the `INKSTONE_LIGHT_THEME` / `INKSTONE_DARK_THEME` constants — the theme names to pass wherever a Shiki theme id is expected.
|
|
12
|
+
- **`configureEditorSurface(surfaces)`** — re-light the editors' own surfaces in your design language, once, before any editor mounts: per-scheme CSS color literals for `background` (content and gutter), `lineHighlight`, `lineNumber`, `widget` (completion, hover, parameter hints, the find widget and search panels), `widgetBorder`, and `widgetSelection`. The catppuccin pair keeps its syntax palette and gets these baked into its theme colors — Monaco, static rendering, and CodeMirror's chrome all read the same values — so an editor sits inside the app instead of bringing a second dark. A role or scheme left out keeps the flavor's own color, a later call replaces the schemes it names, and values must be hex colors (`#rrggbb`, `#rrggbbaa`) — Monaco parses theme colors as hex and paints red for anything else, so a `var()` reference or an `rgb(…)` is refused up front. Keep `lineHighlight` translucent: CodeMirror draws selections behind the content, so an opaque active line would hide them. `getEditorSurface(dark)` reads what was configured.
|
|
12
13
|
- **`CODE_FONT_FAMILY`** — the shared code font stack both editor engines render with: the page's `--inkstone-font-family-code` CSS token when defined, else the platform's native monospace.
|
|
14
|
+
- **`inkstoneRadius(size, fallback)` / `inkstoneShadow(size, fallback)`** — `var()` references to the host's `--inkstone-radius-{small,medium,large,xlarge}` and `--inkstone-shadow-{medium,large,xlarge}` tokens. Set them once on your root and both engines' chrome follows: the Monaco host maps them onto VS Code's `--vscode-cornerRadius-*` / `--vscode-shadow-*` design tokens (which the standalone editor never defines), CodeMirror's polish reads them directly; unset, each engine keeps the look it ships with.
|
|
13
15
|
|
|
14
16
|
## Install
|
|
15
17
|
|
|
@@ -22,12 +24,18 @@ pnpm add @coldsmirk/inkstone-core
|
|
|
22
24
|
## Quick start
|
|
23
25
|
|
|
24
26
|
```ts
|
|
25
|
-
import { configureHighlighter, DEFAULT_HIGHLIGHTER_LANGS, getHighlighter, shikiThemeId } from "@coldsmirk/inkstone-core";
|
|
27
|
+
import { configureEditorSurface, configureHighlighter, DEFAULT_HIGHLIGHTER_LANGS, getHighlighter, shikiThemeId } from "@coldsmirk/inkstone-core";
|
|
26
28
|
import yaml from "@shikijs/langs/yaml";
|
|
27
29
|
|
|
28
30
|
// Optional: add grammars/themes beyond the defaults — once, before any editor mounts.
|
|
29
31
|
configureHighlighter({ langs: [...DEFAULT_HIGHLIGHTER_LANGS, yaml] });
|
|
30
32
|
|
|
33
|
+
// Optional: paint the editors' surfaces in your own tokens (syntax colors stay catppuccin's).
|
|
34
|
+
configureEditorSurface({
|
|
35
|
+
light: { background: "#f7f7fa", lineHighlight: "#ffffff", widget: "#ffffff", widgetBorder: "#ced4da" },
|
|
36
|
+
dark: { background: "#1d1b22", lineHighlight: "#232129", widget: "#302e38", widgetBorder: "#423f4b" }
|
|
37
|
+
});
|
|
38
|
+
|
|
31
39
|
const highlighter = await getHighlighter();
|
|
32
40
|
const html = highlighter.codeToHtml("const x = 1;", {
|
|
33
41
|
lang: "javascript",
|
|
@@ -37,6 +45,16 @@ const html = highlighter.codeToHtml("const x = 1;", {
|
|
|
37
45
|
|
|
38
46
|
The same instance is the right one for non-editor surfaces (markdown code blocks, JSON inspectors, Mantine's `@mantine/code-highlight` adapter) — sharing it keeps their colors identical to the editors'.
|
|
39
47
|
|
|
48
|
+
Corners and elevation are CSS tokens rather than configuration — declare them once and both engines follow:
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
:root {
|
|
52
|
+
--inkstone-radius-medium: 8px; /* menu rows, completion rows */
|
|
53
|
+
--inkstone-radius-large: 8px; /* the floating widgets themselves */
|
|
54
|
+
--inkstone-shadow-large: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
40
58
|
## License
|
|
41
59
|
|
|
42
60
|
UNLICENSED — proprietary. All rights reserved; no use, copying, or redistribution without the author's permission.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HighlighterCore, HighlighterCore as HighlighterCore$1, LanguageInput, ThemeInput } from "shiki/core";
|
|
1
|
+
import { HighlighterCore, HighlighterCore as HighlighterCore$1, LanguageInput, ThemeInput, ThemeRegistration } from "shiki/core";
|
|
2
2
|
//#region src/code-font.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* The code font stack every inkstone editor host renders with: the page's
|
|
@@ -8,6 +8,82 @@ import { HighlighterCore, HighlighterCore as HighlighterCore$1, LanguageInput, T
|
|
|
8
8
|
*/
|
|
9
9
|
declare const CODE_FONT_FAMILY = "var(--inkstone-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)";
|
|
10
10
|
//#endregion
|
|
11
|
+
//#region src/surface.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* The surfaces an editor paints, as a host's design language names them. A host that
|
|
14
|
+
* configures these keeps the catppuccin flavors' syntax palette and gets the editor's own
|
|
15
|
+
* chrome — background, gutter, current line, the floating completion / hover / find widgets —
|
|
16
|
+
* in its own tokens, so an editor sits inside the app instead of bringing a second dark.
|
|
17
|
+
*
|
|
18
|
+
* Every value is a hex color (`#rrggbb`, `#rrggbbaa`): Monaco parses its theme colors itself,
|
|
19
|
+
* as hex only, and cannot follow a custom property. An omitted role keeps the flavor's own
|
|
20
|
+
* color.
|
|
21
|
+
*/
|
|
22
|
+
interface EditorSurface {
|
|
23
|
+
/**
|
|
24
|
+
* The editor's own background: the content area and the gutter.
|
|
25
|
+
*/
|
|
26
|
+
background?: string;
|
|
27
|
+
/**
|
|
28
|
+
* The current line's highlight. Prefer a translucent color: CodeMirror draws selections
|
|
29
|
+
* behind the content, so an opaque fill on the active line hides a selection there (Monaco
|
|
30
|
+
* paints selections above it and is indifferent).
|
|
31
|
+
*/
|
|
32
|
+
lineHighlight?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Line numbers.
|
|
35
|
+
*/
|
|
36
|
+
lineNumber?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Floating chrome: completion, hover and parameter hints, the find widget and the search
|
|
39
|
+
* panels.
|
|
40
|
+
*/
|
|
41
|
+
widget?: string;
|
|
42
|
+
/**
|
|
43
|
+
* The hairline around floating chrome and its fields.
|
|
44
|
+
*/
|
|
45
|
+
widgetBorder?: string;
|
|
46
|
+
/**
|
|
47
|
+
* A hovered or selected row inside floating chrome.
|
|
48
|
+
*/
|
|
49
|
+
widgetSelection?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* One surface per color scheme; an omitted scheme keeps the flavor's own surfaces.
|
|
53
|
+
*/
|
|
54
|
+
interface EditorSurfaces {
|
|
55
|
+
light?: EditorSurface;
|
|
56
|
+
dark?: EditorSurface;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The corner-radius sizes both editors read from the host: `--inkstone-radius-<size>`. Monaco
|
|
60
|
+
* maps them onto VS Code's own `--vscode-cornerRadius-*` design tokens (which the standalone
|
|
61
|
+
* editor never defines — its chrome ships square by omission), CodeMirror's chrome polish
|
|
62
|
+
* reads them directly; each falls back to the look it ships with when the host sets none.
|
|
63
|
+
*/
|
|
64
|
+
type RadiusSize = "small" | "medium" | "large" | "xlarge";
|
|
65
|
+
/**
|
|
66
|
+
* A `var()` reference to the host's `--inkstone-radius-<size>` token with the given fallback.
|
|
67
|
+
*/
|
|
68
|
+
declare function inkstoneRadius(size: RadiusSize, fallback: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* The elevation sizes floating chrome reads from the host: `--inkstone-shadow-<size>`, a full
|
|
71
|
+
* `box-shadow` value. Same contract as the radii: Monaco maps them onto VS Code's
|
|
72
|
+
* `--vscode-shadow-*` tokens, CodeMirror's tooltips read them directly, each with its own
|
|
73
|
+
* fallback.
|
|
74
|
+
*/
|
|
75
|
+
type ShadowSize = "medium" | "large" | "xlarge";
|
|
76
|
+
/**
|
|
77
|
+
* A `var()` reference to the host's `--inkstone-shadow-<size>` token with the given fallback.
|
|
78
|
+
*/
|
|
79
|
+
declare function inkstoneShadow(size: ShadowSize, fallback: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* A flavor with its surfaces repainted from `surface`: the token colors (the syntax palette)
|
|
82
|
+
* are untouched, only the theme colors behind each configured role change. Returns the theme
|
|
83
|
+
* itself when there is nothing to apply.
|
|
84
|
+
*/
|
|
85
|
+
declare function surfacedTheme(theme: ThemeRegistration, surface: EditorSurface | undefined): ThemeRegistration;
|
|
86
|
+
//#endregion
|
|
11
87
|
//#region src/shiki.d.ts
|
|
12
88
|
/**
|
|
13
89
|
* Shiki theme id inkstone editors use in light mode.
|
|
@@ -41,6 +117,24 @@ interface HighlighterConfig {
|
|
|
41
117
|
* {@link getHighlighter} call — afterwards the instance is already built and this throws.
|
|
42
118
|
*/
|
|
43
119
|
declare function configureHighlighter(options: HighlighterConfig): void;
|
|
120
|
+
/**
|
|
121
|
+
* Re-light the editors' surfaces in the host's own colors, once, before the first
|
|
122
|
+
* {@link getHighlighter} call — the catppuccin pair is registered with these surfaces baked in
|
|
123
|
+
* (Monaco reads them from the theme, static rendering too), and CodeMirror's chrome reads them
|
|
124
|
+
* at mount. A scheme left out keeps the flavor's own surfaces; a role left out keeps that
|
|
125
|
+
* role's flavor color; a later call replaces the schemes it names. Process-global like the
|
|
126
|
+
* highlighter itself, for the same reason: one palette across every editor and rendered block.
|
|
127
|
+
*
|
|
128
|
+
* Every value must be a hex color (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) — Monaco parses
|
|
129
|
+
* theme colors as hex and paints red for anything else, a custom property reference or an
|
|
130
|
+
* `rgb(…)` alike, so those are refused here instead of failing on screen.
|
|
131
|
+
*/
|
|
132
|
+
declare function configureEditorSurface(surfaces: EditorSurfaces): void;
|
|
133
|
+
/**
|
|
134
|
+
* The surface configured for a color scheme through {@link configureEditorSurface}, or
|
|
135
|
+
* undefined when the flavor's own surfaces stand.
|
|
136
|
+
*/
|
|
137
|
+
declare function getEditorSurface(dark: boolean): EditorSurface | undefined;
|
|
44
138
|
/**
|
|
45
139
|
* The shared Shiki highlighter, built lazily on first call.
|
|
46
140
|
*
|
|
@@ -60,4 +154,4 @@ declare function getHighlighter(): Promise<HighlighterCore$1>;
|
|
|
60
154
|
*/
|
|
61
155
|
declare function shikiThemeId(dark: boolean): string;
|
|
62
156
|
//#endregion
|
|
63
|
-
export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, type HighlighterConfig, type HighlighterCore, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, configureHighlighter, getHighlighter, shikiThemeId };
|
|
157
|
+
export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, type EditorSurface, type EditorSurfaces, type HighlighterConfig, type HighlighterCore, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, type RadiusSize, type ShadowSize, configureEditorSurface, configureHighlighter, getEditorSurface, getHighlighter, inkstoneRadius, inkstoneShadow, shikiThemeId, surfacedTheme };
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,63 @@ import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
|
9
9
|
//#region src/code-font.ts
|
|
10
10
|
const CODE_FONT_FAMILY = "var(--inkstone-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)";
|
|
11
11
|
//#endregion
|
|
12
|
+
//#region src/surface.ts
|
|
13
|
+
function inkstoneRadius(size, fallback) {
|
|
14
|
+
return `var(--inkstone-radius-${size}, ${fallback})`;
|
|
15
|
+
}
|
|
16
|
+
function inkstoneShadow(size, fallback) {
|
|
17
|
+
return `var(--inkstone-shadow-${size}, ${fallback})`;
|
|
18
|
+
}
|
|
19
|
+
const SURFACE_COLORS = {
|
|
20
|
+
background: [
|
|
21
|
+
"editor.background",
|
|
22
|
+
"editorGutter.background",
|
|
23
|
+
"editorCursor.background",
|
|
24
|
+
"editorOverviewRuler.background",
|
|
25
|
+
"editorGroup.emptyBackground",
|
|
26
|
+
"editorStickyScroll.background",
|
|
27
|
+
"minimap.background",
|
|
28
|
+
"input.background"
|
|
29
|
+
],
|
|
30
|
+
lineHighlight: ["editor.lineHighlightBackground", "editorStickyScrollHover.background"],
|
|
31
|
+
lineNumber: ["editorLineNumber.foreground"],
|
|
32
|
+
widget: [
|
|
33
|
+
"editorWidget.background",
|
|
34
|
+
"editorSuggestWidget.background",
|
|
35
|
+
"editorHoverWidget.background",
|
|
36
|
+
"dropdown.background"
|
|
37
|
+
],
|
|
38
|
+
widgetBorder: [
|
|
39
|
+
"editorWidget.border",
|
|
40
|
+
"editorWidget.resizeBorder",
|
|
41
|
+
"editorSuggestWidget.border",
|
|
42
|
+
"editorHoverWidget.border",
|
|
43
|
+
"dropdown.border"
|
|
44
|
+
],
|
|
45
|
+
widgetSelection: [
|
|
46
|
+
"editorSuggestWidget.selectedBackground",
|
|
47
|
+
"list.activeSelectionBackground",
|
|
48
|
+
"list.inactiveSelectionBackground",
|
|
49
|
+
"list.focusBackground",
|
|
50
|
+
"list.hoverBackground"
|
|
51
|
+
]
|
|
52
|
+
};
|
|
53
|
+
function surfacedTheme(theme, surface) {
|
|
54
|
+
const roles = Object.entries(SURFACE_COLORS);
|
|
55
|
+
const colors = { ...theme.colors };
|
|
56
|
+
let changed = false;
|
|
57
|
+
for (const [role, keys] of roles) {
|
|
58
|
+
const value = surface?.[role];
|
|
59
|
+
if (value === void 0) continue;
|
|
60
|
+
for (const key of keys) colors[key] = value;
|
|
61
|
+
changed = true;
|
|
62
|
+
}
|
|
63
|
+
return changed ? {
|
|
64
|
+
...theme,
|
|
65
|
+
colors
|
|
66
|
+
} : theme;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
12
69
|
//#region src/shiki.ts
|
|
13
70
|
const INKSTONE_LIGHT_THEME = "catppuccin-latte";
|
|
14
71
|
const INKSTONE_DARK_THEME = "catppuccin-macchiato";
|
|
@@ -25,28 +82,50 @@ function getHighlighterRegistry() {
|
|
|
25
82
|
if (!registry) {
|
|
26
83
|
registry = {
|
|
27
84
|
config: {},
|
|
85
|
+
surfaces: {},
|
|
28
86
|
promise: null
|
|
29
87
|
};
|
|
30
88
|
host[HIGHLIGHTER_REGISTRY_KEY] = registry;
|
|
31
89
|
}
|
|
90
|
+
registry.surfaces ??= {};
|
|
32
91
|
return registry;
|
|
33
92
|
}
|
|
93
|
+
function assertConfigurable(registry, caller) {
|
|
94
|
+
if (registry.promise) throw new Error(`${caller} must be called before the first getHighlighter()`);
|
|
95
|
+
}
|
|
34
96
|
function configureHighlighter(options) {
|
|
35
97
|
const registry = getHighlighterRegistry();
|
|
36
|
-
|
|
98
|
+
assertConfigurable(registry, "configureHighlighter");
|
|
37
99
|
registry.config = {
|
|
38
100
|
...registry.config,
|
|
39
101
|
...options
|
|
40
102
|
};
|
|
41
103
|
}
|
|
104
|
+
const HEX_COLOR = /^#(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i;
|
|
105
|
+
function configureEditorSurface(surfaces) {
|
|
106
|
+
const registry = getHighlighterRegistry();
|
|
107
|
+
assertConfigurable(registry, "configureEditorSurface");
|
|
108
|
+
for (const [scheme, surface] of Object.entries(surfaces)) {
|
|
109
|
+
const roles = Object.entries(surface ?? {});
|
|
110
|
+
for (const [role, value] of roles) if (typeof value === "string" && !HEX_COLOR.test(value)) throw new Error(`configureEditorSurface: ${scheme}.${role} must be a hex color, which is all Monaco parses (${value})`);
|
|
111
|
+
}
|
|
112
|
+
registry.surfaces = {
|
|
113
|
+
...registry.surfaces,
|
|
114
|
+
...surfaces
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function getEditorSurface(dark) {
|
|
118
|
+
const { surfaces } = getHighlighterRegistry();
|
|
119
|
+
return dark ? surfaces.dark : surfaces.light;
|
|
120
|
+
}
|
|
42
121
|
function getHighlighter() {
|
|
43
122
|
const registry = getHighlighterRegistry();
|
|
44
123
|
const existing = registry.promise;
|
|
45
124
|
if (existing) return existing;
|
|
46
125
|
const attempt = createHighlighterCore({
|
|
47
126
|
themes: [
|
|
48
|
-
catppuccinLatte,
|
|
49
|
-
catppuccinMacchiato,
|
|
127
|
+
surfacedTheme(catppuccinLatte, registry.surfaces.light),
|
|
128
|
+
surfacedTheme(catppuccinMacchiato, registry.surfaces.dark),
|
|
50
129
|
...registry.config.themes ?? []
|
|
51
130
|
],
|
|
52
131
|
langs: registry.config.langs ?? [...DEFAULT_HIGHLIGHTER_LANGS],
|
|
@@ -62,4 +141,4 @@ function shikiThemeId(dark) {
|
|
|
62
141
|
return dark ? INKSTONE_DARK_THEME : INKSTONE_LIGHT_THEME;
|
|
63
142
|
}
|
|
64
143
|
//#endregion
|
|
65
|
-
export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, configureHighlighter, getHighlighter, shikiThemeId };
|
|
144
|
+
export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, configureEditorSurface, configureHighlighter, getEditorSurface, getHighlighter, inkstoneRadius, inkstoneShadow, shikiThemeId, surfacedTheme };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldsmirk/inkstone-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Shared Shiki highlighter service for the inkstone editor toolkit: one fine-grained singleton (catppuccin themes, JS regex engine) reused by Monaco, static rendering, and markdown surfaces.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shiki",
|