@coldsmirk/inkstone-sql 0.31.0 → 0.32.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/README.md +1 -1
- package/dist/react.d.ts +15 -90
- package/dist/react.js +39 -128
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Part of [inkstone](https://github.com/coldsmirk/inkstone). Extracted from dragom
|
|
|
8
8
|
|
|
9
9
|
- **`@coldsmirk/inkstone-sql`** — the framework-free core. Zero editor dependencies; runs anywhere.
|
|
10
10
|
- **`@coldsmirk/inkstone-sql/monaco`** — `registerSqlLanguage(monaco, modelPath, hooks)`: the Monaco providers (completion, hover, signature help, formatting) over an assist read per-request through a hook. Peer: `monaco-editor`.
|
|
11
|
-
- **`@coldsmirk/inkstone-sql/react`** — `<SqlEditor>`: a controlled SQL editor built on `@coldsmirk/inkstone-react`'s `<
|
|
11
|
+
- **`@coldsmirk/inkstone-sql/react`** — `<SqlEditor>`: a controlled SQL editor built on `@coldsmirk/inkstone-react`'s `<MonacoConsoleEditor>`, with a run key (Ctrl/Cmd-Enter handing over the live caret), a runnable-statement gutter mark, caret tracking, and an insert/focus/format handle for schema trees and toolbars. Peers: `monaco-editor`, `react`.
|
|
12
12
|
|
|
13
13
|
## The shape
|
|
14
14
|
|
package/dist/react.d.ts
CHANGED
|
@@ -1,92 +1,33 @@
|
|
|
1
1
|
import { t as SqlAssist } from "./assist-BM4bNDhw.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ConsoleCaret, ConsoleEditorHandle, ConsoleEditorProps } from "@coldsmirk/inkstone-react/monaco";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
|
-
import { editor } from "monaco-editor";
|
|
5
4
|
//#region src/react.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* What a host needs to reach into the editor for: inserting at the caret (a schema tree is an
|
|
8
|
-
* input device, not a browser), and reformatting from a toolbar — which goes through
|
|
9
|
-
* formatting action, so the button and `Shift+Alt+F` are one path and one undo.
|
|
7
|
+
* input device, not a browser), the focus, and reformatting from a toolbar — which goes through
|
|
8
|
+
* Monaco's own formatting action, so the button and `Shift+Alt+F` are one path and one undo.
|
|
10
9
|
*/
|
|
11
|
-
export interface SqlEditorHandle {
|
|
12
|
-
insert: (text: string) => void;
|
|
10
|
+
export interface SqlEditorHandle extends ConsoleEditorHandle {
|
|
13
11
|
format: () => void;
|
|
14
12
|
}
|
|
15
13
|
/**
|
|
16
14
|
* Where the operator is in the document, in offsets — everything a host needs to decide which
|
|
17
|
-
* statement a run should send, and nothing about SQL.
|
|
18
|
-
* bounds and are equal where nothing is selected: a caret is a selection of nothing.
|
|
19
|
-
*
|
|
20
|
-
* It rides with the text rather than beside it because the two must belong to the same instant.
|
|
21
|
-
* The controlled `value` is one React render behind the keystroke that triggered a run, and a
|
|
22
|
-
* console must run the statement the operator is looking at.
|
|
15
|
+
* statement a run should send, and nothing about SQL.
|
|
23
16
|
*/
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
from: number;
|
|
27
|
-
to: number;
|
|
28
|
-
}
|
|
29
|
-
export interface SqlEditorProps {
|
|
30
|
-
value: string;
|
|
31
|
-
onChange: (value: string) => void;
|
|
32
|
-
/**
|
|
33
|
-
* Render with the dark theme. Like every inkstone editor, the component never reads the OS
|
|
34
|
-
* `prefers-color-scheme`; wire this to the app's color-scheme state.
|
|
35
|
-
*
|
|
36
|
-
* @default false
|
|
37
|
-
*/
|
|
38
|
-
dark?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Editor height in px, or `"fill"` to consume the parent's resolved height (the parent must be
|
|
41
|
-
* a `min-height: 0` flex item). Monaco's loading placeholder is `height: 100%`, so a height
|
|
42
|
-
* that resolves to nothing collapses the field to one line while the editor loads.
|
|
43
|
-
*/
|
|
44
|
-
height?: number | "fill";
|
|
45
|
-
/**
|
|
46
|
-
* Editor font size in px. Omit to keep the inkstone default.
|
|
47
|
-
*/
|
|
48
|
-
fontSize?: number;
|
|
49
|
-
/**
|
|
50
|
-
* UI locale for Monaco's built-in chrome — page-global and locked by the first editor to
|
|
51
|
-
* mount, exactly as on `<MonacoEditor>`.
|
|
52
|
-
*/
|
|
53
|
-
locale?: "en" | "zh-cn";
|
|
54
|
-
placeholder?: string;
|
|
55
|
-
/**
|
|
56
|
-
* The editor's accessible name, set on Monaco's own input surface — several SQL editors on one
|
|
57
|
-
* page are indistinguishable to assistive tech without one.
|
|
58
|
-
*/
|
|
59
|
-
ariaLabel: string;
|
|
17
|
+
export type SqlCaret = ConsoleCaret;
|
|
18
|
+
export interface SqlEditorProps extends ConsoleEditorProps<SqlEditorHandle> {
|
|
60
19
|
/**
|
|
61
20
|
* The Monaco language id the model registers under.
|
|
62
21
|
*
|
|
63
22
|
* @default "sql"
|
|
64
23
|
*/
|
|
65
24
|
languageId?: string;
|
|
66
|
-
/**
|
|
67
|
-
* Shown while the Monaco host loads / when it fails to load — passed through to
|
|
68
|
-
* `<MonacoEditor>`, whose English defaults apply when omitted.
|
|
69
|
-
*/
|
|
70
|
-
loading?: ReactNode;
|
|
71
|
-
failure?: ReactNode;
|
|
72
|
-
/**
|
|
73
|
-
* Ctrl/Cmd-Enter — the run key, bound inside the editor because that is where the operator's
|
|
74
|
-
* hands are. It is handed the editor's live caret, from which the host works out what to send.
|
|
75
|
-
* Read through a ref at every press, so it always runs against the connection the *current*
|
|
76
|
-
* render is bound to.
|
|
77
|
-
*/
|
|
78
|
-
onRun?: (caret: SqlCaret) => void;
|
|
79
25
|
/**
|
|
80
26
|
* The label the run action shows in Monaco's own chrome (command palette, context menu).
|
|
81
27
|
*
|
|
82
28
|
* @default "Run statement"
|
|
83
29
|
*/
|
|
84
30
|
runActionLabel?: string;
|
|
85
|
-
/**
|
|
86
|
-
* The caret moved, or the text under it changed. The host tracks it to show what a run would
|
|
87
|
-
* send; the run key does not depend on that tracking having caught up.
|
|
88
|
-
*/
|
|
89
|
-
onCaret?: (caret: SqlCaret) => void;
|
|
90
31
|
/**
|
|
91
32
|
* The span to mark as the one a run would send. Null leaves the gutter clean, which is the
|
|
92
33
|
* right answer while there is nothing to choose between.
|
|
@@ -108,35 +49,19 @@ export interface SqlEditorProps {
|
|
|
108
49
|
* says so — a deliberate keystroke that changes nothing needs to explain itself.
|
|
109
50
|
*/
|
|
110
51
|
onFormatRefused?: () => void;
|
|
111
|
-
onReady?: (handle: SqlEditorHandle) => void;
|
|
112
|
-
/**
|
|
113
|
-
* Runs after this component's own mount wiring, with the live editor and the monaco module —
|
|
114
|
-
* the escape hatch for host-specific concerns (focus shields, extra actions).
|
|
115
|
-
*/
|
|
116
|
-
onMount?: (instance: editor.IStandaloneCodeEditor, monaco: MonacoModule) => void;
|
|
117
|
-
/**
|
|
118
|
-
* Extra construction options, merged under this editor's own (`ariaLabel`): the escape hatch
|
|
119
|
-
* a host reaches for a construction option no prop names — `overflowWidgetsDomNode`, where
|
|
120
|
-
* the page's own layers would otherwise stand over the editor's floating widgets (hover,
|
|
121
|
-
* completion, parameter hints) left inside it.
|
|
122
|
-
*/
|
|
123
|
-
options?: editor.IStandaloneEditorConstructionOptions;
|
|
124
52
|
/**
|
|
125
53
|
* What the editor's language features answer from — the schema and dialect of the connection
|
|
126
|
-
* being edited (`createSqlAssist`). Read
|
|
127
|
-
*
|
|
54
|
+
* being edited (`createSqlAssist`). Read at every request, so the host can swap it without
|
|
55
|
+
* re-registering anything with Monaco.
|
|
128
56
|
*/
|
|
129
57
|
assist?: SqlAssist;
|
|
130
58
|
}
|
|
131
59
|
/**
|
|
132
|
-
* The SQL editing surface:
|
|
133
|
-
* other inkstone surface uses. It is deliberately not a script editor — a
|
|
134
|
-
* service and an ambient profile have no meaning for a vendor's SQL. Its
|
|
135
|
-
* the host's: the `assist` knows the catalog and the dialect and this
|
|
136
|
-
* Monaco (`registerSqlLanguage`) — it never guesses at SQL itself.
|
|
137
|
-
*
|
|
138
|
-
* The editor draws no chrome of its own: it is a band of its host's surface, and the separation
|
|
139
|
-
* is the host's hairline rules — a border here would dress a pane up as a form input.
|
|
60
|
+
* The SQL editing surface: `<MonacoConsoleEditor>` in `sql`, highlighted by the same shared Shiki
|
|
61
|
+
* grammar every other inkstone surface uses. It is deliberately not a script editor — a
|
|
62
|
+
* TypeScript language service and an ambient profile have no meaning for a vendor's SQL. Its
|
|
63
|
+
* language features are the host's: the `assist` knows the catalog and the dialect and this
|
|
64
|
+
* component only wires it to Monaco (`registerSqlLanguage`) — it never guesses at SQL itself.
|
|
140
65
|
*/
|
|
141
|
-
export declare function SqlEditor({
|
|
66
|
+
export declare function SqlEditor({ languageId, runActionLabel, assist, onFormatRefused, onReady, options, ...props }: SqlEditorProps): ReactNode;
|
|
142
67
|
//#endregion
|
package/dist/react.js
CHANGED
|
@@ -1,135 +1,46 @@
|
|
|
1
1
|
import { t as registerSqlLanguage } from "./monaco-DEMsSuzD.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { MonacoConsoleEditor } from "@coldsmirk/inkstone-react/monaco";
|
|
3
|
+
import { useMemo, useRef } from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/react.tsx
|
|
6
|
-
const EDITOR_ID_KEY = Symbol.for("coldsmirk.inkstone.sql.editorId");
|
|
7
|
-
function nextEditorId() {
|
|
8
|
-
const holder = globalThis;
|
|
9
|
-
const id = holder[EDITOR_ID_KEY] ?? 0;
|
|
10
|
-
holder[EDITOR_ID_KEY] = id + 1;
|
|
11
|
-
return id;
|
|
12
|
-
}
|
|
13
6
|
const FORMAT_CHORD_CONTEXT_KEY = "inkstoneSqlFormatChord";
|
|
14
|
-
function
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const caretChangedRef = useLatest(onCaret);
|
|
52
|
-
const readyRef = useLatest(onReady);
|
|
53
|
-
const mountRef = useLatest(onMount);
|
|
54
|
-
const instance = useRef(null);
|
|
55
|
-
const marked = useRef(null);
|
|
56
|
-
const [mounted, setMounted] = useState(false);
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
const model = instance.current?.getModel();
|
|
59
|
-
if (model === null || model === void 0) return;
|
|
60
|
-
marked.current?.clear();
|
|
61
|
-
marked.current = highlight === null ? null : instance.current.createDecorationsCollection([{
|
|
62
|
-
range: monacoRange(model, highlight),
|
|
63
|
-
options: {
|
|
64
|
-
linesDecorationsClassName: highlightClassName,
|
|
65
|
-
isWholeLine: true
|
|
66
|
-
}
|
|
67
|
-
}]);
|
|
68
|
-
}, [
|
|
69
|
-
highlight,
|
|
70
|
-
highlightClassName,
|
|
71
|
-
mounted
|
|
72
|
-
]);
|
|
73
|
-
useEffect(() => () => {
|
|
74
|
-
for (const binding of bindings.current) binding.dispose();
|
|
75
|
-
bindings.current = [];
|
|
76
|
-
}, []);
|
|
77
|
-
const fill = height === "fill";
|
|
78
|
-
return /* @__PURE__ */ jsx("div", {
|
|
79
|
-
style: fill ? {
|
|
80
|
-
height: "100%",
|
|
81
|
-
minHeight: 0
|
|
82
|
-
} : { height },
|
|
83
|
-
children: /* @__PURE__ */ jsx(MonacoEditor, {
|
|
84
|
-
showLineNumbers: true,
|
|
85
|
-
dark,
|
|
86
|
-
failure,
|
|
87
|
-
fontSize,
|
|
88
|
-
height: fill ? "100%" : height,
|
|
89
|
-
language: languageId,
|
|
90
|
-
loading,
|
|
91
|
-
locale,
|
|
92
|
-
path: modelPath,
|
|
93
|
-
placeholder,
|
|
94
|
-
value,
|
|
95
|
-
options: {
|
|
96
|
-
...options,
|
|
97
|
-
ariaLabel,
|
|
98
|
-
suggest: { snippetsPreventQuickSuggestions: false }
|
|
99
|
-
},
|
|
100
|
-
onChange,
|
|
101
|
-
onMount: (live, monaco) => {
|
|
102
|
-
instance.current = live;
|
|
103
|
-
live.createContextKey(FORMAT_CHORD_CONTEXT_KEY, true);
|
|
104
|
-
bindings.current.push(live.onDidChangeCursorSelection(() => caretChangedRef.current?.(caretOf(live))), live.addAction({
|
|
105
|
-
id: "inkstone-sql.run",
|
|
106
|
-
label: runActionLabel,
|
|
107
|
-
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter],
|
|
108
|
-
run: (current) => runRef.current?.(caretOf(current))
|
|
109
|
-
}), monaco.editor.addKeybindingRule({
|
|
110
|
-
keybinding: monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.KeyF,
|
|
111
|
-
command: "editor.action.formatDocument",
|
|
112
|
-
when: `${FORMAT_CHORD_CONTEXT_KEY} && editorTextFocus && !editorReadonly`
|
|
113
|
-
}), ...registerSqlLanguage(monaco, modelPath, {
|
|
114
|
-
assist: () => assistRef.current,
|
|
115
|
-
onFormatRefused: () => formatRefusedRef.current?.()
|
|
116
|
-
}, languageId));
|
|
117
|
-
readyRef.current?.({
|
|
118
|
-
format: () => void live.getAction("editor.action.formatDocument")?.run(),
|
|
119
|
-
insert: (text) => {
|
|
120
|
-
const selection = live.getSelection();
|
|
121
|
-
if (selection) live.executeEdits("inkstone-sql-insert", [{
|
|
122
|
-
range: selection,
|
|
123
|
-
text,
|
|
124
|
-
forceMoveMarkers: true
|
|
125
|
-
}]);
|
|
126
|
-
live.focus();
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
mountRef.current?.(live, monaco);
|
|
130
|
-
setMounted(true);
|
|
131
|
-
}
|
|
132
|
-
})
|
|
7
|
+
function SqlEditor({ languageId = "sql", runActionLabel = "Run statement", assist, onFormatRefused, onReady, options, ...props }) {
|
|
8
|
+
const live = useRef(null);
|
|
9
|
+
const sqlOptions = useMemo(() => {
|
|
10
|
+
return {
|
|
11
|
+
...options,
|
|
12
|
+
suggest: { snippetsPreventQuickSuggestions: false }
|
|
13
|
+
};
|
|
14
|
+
}, [options]);
|
|
15
|
+
return /* @__PURE__ */ jsx(MonacoConsoleEditor, {
|
|
16
|
+
...props,
|
|
17
|
+
context: {
|
|
18
|
+
assist,
|
|
19
|
+
onFormatRefused
|
|
20
|
+
},
|
|
21
|
+
extension: "sql",
|
|
22
|
+
language: languageId,
|
|
23
|
+
namespace: "inkstone-sql",
|
|
24
|
+
options: sqlOptions,
|
|
25
|
+
runActionLabel,
|
|
26
|
+
register: ({ monaco, editor: instance, path, context }) => {
|
|
27
|
+
live.current = instance;
|
|
28
|
+
instance.createContextKey(FORMAT_CHORD_CONTEXT_KEY, true);
|
|
29
|
+
return [monaco.editor.addKeybindingRule({
|
|
30
|
+
keybinding: monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.KeyF,
|
|
31
|
+
command: "editor.action.formatDocument",
|
|
32
|
+
when: `${FORMAT_CHORD_CONTEXT_KEY} && editorTextFocus && !editorReadonly`
|
|
33
|
+
}), ...registerSqlLanguage(monaco, path, {
|
|
34
|
+
assist: () => context().assist ?? null,
|
|
35
|
+
onFormatRefused: () => context().onFormatRefused?.()
|
|
36
|
+
}, languageId)];
|
|
37
|
+
},
|
|
38
|
+
onReady: (handle) => {
|
|
39
|
+
onReady?.({
|
|
40
|
+
...handle,
|
|
41
|
+
format: () => void live.current?.getAction("editor.action.formatDocument")?.run()
|
|
42
|
+
});
|
|
43
|
+
}
|
|
133
44
|
});
|
|
134
45
|
}
|
|
135
46
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldsmirk/inkstone-sql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Schema-aware SQL editing intelligence for Monaco: lexical statement reading under per-dialect noise profiles, catalog-driven completion/hover/signature help, unified-placeholder awareness, formatting, and a drop-in React SQL editor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sql",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"monaco-editor": "^0.57.0",
|
|
50
50
|
"react": "^19.3.0",
|
|
51
|
-
"@coldsmirk/inkstone-react": "^0.
|
|
51
|
+
"@coldsmirk/inkstone-react": "^0.32.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"monaco-editor": "^0.57.0",
|
|
55
55
|
"react": ">=19",
|
|
56
|
-
"@coldsmirk/inkstone-react": "^0.
|
|
56
|
+
"@coldsmirk/inkstone-react": "^0.32.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"@coldsmirk/inkstone-react": {
|