@ashley-shrok/viewmodel-shell 0.2.0 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ashley-shrok/viewmodel-shell",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Server-driven UI framework. Server returns a JSON tree of typed nodes; a thin TypeScript adapter renders it to DOM. Backend-agnostic — a .NET reference backend ships with the repo, but any language can produce the JSON contract.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/browser.ts CHANGED
@@ -266,6 +266,33 @@ export class BrowserAdapter implements Adapter {
266
266
  if (n.value) ta.value = n.value;
267
267
  if (n.required) ta.required = true;
268
268
  wrapper.appendChild(ta);
269
+ } else if (n.inputType === "code") {
270
+ // Monospaced editable text. Tab inserts a literal tab instead of moving
271
+ // focus. Apps wanting syntax highlighting attach their own library
272
+ // (CodeMirror, Monaco) using the .vms-field--code-{language} class hook.
273
+ wrapper.classList.add("vms-field--code");
274
+ if (n.language) wrapper.classList.add(`vms-field--code-${n.language}`);
275
+ const ta = document.createElement("textarea");
276
+ ta.className = "vms-field__input vms-field__input--code";
277
+ ta.id = `vms-${n.name}`;
278
+ ta.name = n.name;
279
+ ta.spellcheck = false;
280
+ ta.autocapitalize = "off";
281
+ ta.autocomplete = "off";
282
+ ta.setAttribute("autocorrect", "off");
283
+ if (n.placeholder) ta.placeholder = n.placeholder;
284
+ if (n.value) ta.value = n.value;
285
+ if (n.required) ta.required = true;
286
+ ta.addEventListener("keydown", (e) => {
287
+ if (e.key === "Tab") {
288
+ e.preventDefault();
289
+ const start = ta.selectionStart ?? 0;
290
+ const end = ta.selectionEnd ?? 0;
291
+ ta.value = ta.value.slice(0, start) + "\t" + ta.value.slice(end);
292
+ ta.selectionStart = ta.selectionEnd = start + 1;
293
+ }
294
+ });
295
+ wrapper.appendChild(ta);
269
296
  } else {
270
297
  const inp = document.createElement("input");
271
298
  inp.className = "vms-field__input";
package/src/index.ts CHANGED
@@ -73,12 +73,18 @@ export interface FieldNode {
73
73
  | "text" | "email" | "password" | "number"
74
74
  | "date" | "time" | "datetime-local"
75
75
  | "textarea" | "hidden" | "file"
76
- | "select" | "select-multiple" | "checkbox";
76
+ | "select" | "select-multiple" | "checkbox"
77
+ | "code";
77
78
  label?: string;
78
79
  placeholder?: string;
79
80
  value?: string;
80
81
  required?: boolean;
81
82
  options?: Array<{ value: string; label: string }>;
83
+ /** Optional language hint for `inputType: "code"`. Emitted as a class
84
+ * (`vms-field--code-{language}`) so apps can attach a syntax-highlighter
85
+ * library (CodeMirror, Monaco, etc.) — the framework only ships
86
+ * monospaced editable text, no coloring. */
87
+ language?: string;
82
88
  /** Dispatched when Enter is pressed (text-like inputs only). Adapter merges { [name]: value } into context. */
83
89
  action?: ActionEvent;
84
90
  }
@@ -100,6 +100,18 @@
100
100
  textarea.vms-field__input { min-height: 80px; }
101
101
  select.vms-field__input { cursor: pointer; padding-right: 2.25rem; }
102
102
 
103
+ /* Code editor field — monospaced, tab-aware, no spell-check chrome.
104
+ Apps add syntax highlighting via .vms-field--code-{language} hooks. */
105
+ .vms-field__input--code {
106
+ font-family: var(--vms-font-body);
107
+ font-size: 13px;
108
+ line-height: 1.5;
109
+ tab-size: 2;
110
+ min-height: 140px;
111
+ white-space: pre;
112
+ overflow: auto;
113
+ }
114
+
103
115
  /* Form-collected checkbox (FieldNode inputType="checkbox") — inline label. */
104
116
  .vms-field--checkbox { flex-direction: row; align-items: center; gap: 0.5rem; }
105
117
  .vms-field--checkbox .vms-field__input {