@golemui/gui-mcp 1.1.0 → 1.1.1-rc.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/CHANGELOG.md +33 -0
- package/README.md +16 -0
- package/cli-commands.d.ts +18 -0
- package/cli.js +87 -2
- package/dx/dx-specs.d.ts +12 -0
- package/{get-concept-e_HDPrW1.js → get-concept-DRFSt-XX.js} +34 -34
- package/json.js +1 -1
- package/lib.js +2 -2
- package/{list-dx-factories-BlB_usDm.js → list-dx-factories-U8ZsqQy-.js} +292 -5
- package/package.json +8 -5
package/json.js
CHANGED
package/lib.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { G, J, a, b, c, g, d, e, f, v } from "./get-concept-
|
|
2
|
-
import { D, a as a2, b as b2, c as c2, d as d2, e as e2, g as g2, l, f as f2, t } from "./list-dx-factories-
|
|
1
|
+
import { G, J, a, b, c, g, d, e, f, v } from "./get-concept-DRFSt-XX.js";
|
|
2
|
+
import { D, a as a2, b as b2, c as c2, d as d2, e as e2, g as g2, l, f as f2, t } from "./list-dx-factories-U8ZsqQy-.js";
|
|
3
3
|
export {
|
|
4
4
|
D as DX_CHECK_CODE_TOOL,
|
|
5
5
|
a2 as DX_GET_SPEC_TOOL,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { h as checkReactiveExpression } from "./get-concept-
|
|
1
|
+
import { h as checkReactiveExpression } from "./get-concept-DRFSt-XX.js";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { resolve, join, dirname } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { Decoder, err, ok, object, array, string, oneOf, boolean, optional, succeed, number, literal, lazy, discriminatedUnion, record } from "ts.data.json";
|
|
7
|
+
import "subscript/justin";
|
|
8
|
+
import { pipe, map, distinctUntilChanged, filter } from "rxjs";
|
|
6
9
|
const CONFIG_FIELDS = ["include", "exclude", "disabled", "readonly"];
|
|
7
10
|
function lintDxSnippet(ts, sourceText, lineOffset) {
|
|
8
11
|
const sf = ts.createSourceFile("__dx_lint__.ts", sourceText, ts.ScriptTarget.ES2020, true);
|
|
@@ -67,8 +70,8 @@ const GOLEMUI_TYPE_PACKAGES = [
|
|
|
67
70
|
{ spec: "@golemui/gui-shared", rel: "gui/shared/index.d.ts" },
|
|
68
71
|
{ spec: "@golemui/gui-shared/internals", rel: "gui/shared/internals.d.ts" },
|
|
69
72
|
{ spec: "@golemui/gui-validators", rel: "gui/validators/index.d.ts" },
|
|
70
|
-
{ spec: "@golemui/
|
|
71
|
-
{ spec: "@golemui/core
|
|
73
|
+
{ spec: "@golemui/dx", rel: "dx/index.d.ts" },
|
|
74
|
+
{ spec: "@golemui/core", rel: "core/index.d.ts" }
|
|
72
75
|
];
|
|
73
76
|
const DIST_SEARCH_DEPTH = 8;
|
|
74
77
|
const SNIPPET_FILE = "__dx_snippet__.ts";
|
|
@@ -217,6 +220,249 @@ const DX_CHECK_CODE_TOOL = {
|
|
|
217
220
|
required: ["code"]
|
|
218
221
|
}
|
|
219
222
|
};
|
|
223
|
+
function objectWithSuffix(specs) {
|
|
224
|
+
return new Decoder((json) => {
|
|
225
|
+
if (typeof json !== "object" || json === null) {
|
|
226
|
+
return err([{ message: `Expected object literal, got "${typeof json}"`, path: [] }]);
|
|
227
|
+
}
|
|
228
|
+
const out = {};
|
|
229
|
+
for (const [specKey, spec] of Object.entries(specs)) {
|
|
230
|
+
const res = spec.decoder.decode(json[specKey]);
|
|
231
|
+
if (!res.isOk()) {
|
|
232
|
+
return err(
|
|
233
|
+
res.issues.map((issue) => ({
|
|
234
|
+
message: issue.message,
|
|
235
|
+
path: [specKey, ...issue.path]
|
|
236
|
+
}))
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
out[specKey] = res.value;
|
|
240
|
+
if (spec.suffixed) {
|
|
241
|
+
for (const [jsonKey, jsonValue] of Object.entries(json)) {
|
|
242
|
+
if (jsonKey.startsWith(specKey + ".")) {
|
|
243
|
+
const res2 = spec.decoder.decode(jsonValue);
|
|
244
|
+
if (!res2.isOk()) {
|
|
245
|
+
return err(
|
|
246
|
+
res2.issues.map((issue) => ({
|
|
247
|
+
message: issue.message,
|
|
248
|
+
path: [jsonKey, ...issue.path]
|
|
249
|
+
}))
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
out[jsonKey] = res2.value;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return ok(out);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
const shortUUID = () => crypto.randomUUID().slice(0, 8);
|
|
261
|
+
const isInputWidget = (widget) => typeof widget !== "function" && widget.kind === "input";
|
|
262
|
+
const isLayoutWidget = (widget) => typeof widget !== "function" && widget.kind === "layout";
|
|
263
|
+
const isFunctionWidget = (widget) => typeof widget === "function";
|
|
264
|
+
const inDecoder = object({ in: array(string()) });
|
|
265
|
+
const whenDecoder = object({ when: string() });
|
|
266
|
+
const includeDecoder = oneOf([inDecoder, whenDecoder]);
|
|
267
|
+
const fromDecoder = object({ from: array(string()) });
|
|
268
|
+
const excludeDecoder = oneOf([fromDecoder, whenDecoder]);
|
|
269
|
+
const boolWhenDecoder = oneOf([boolean(), whenDecoder]);
|
|
270
|
+
const widgetPropFnDecoder = new Decoder((json) => {
|
|
271
|
+
const jsonTypeof = typeof json;
|
|
272
|
+
if (jsonTypeof === "function") {
|
|
273
|
+
return ok(json);
|
|
274
|
+
} else {
|
|
275
|
+
return err([{ message: `Expected a function, got '${jsonTypeof}'`, path: [] }]);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
const decodeWidgetPropOrWidgetPropFn = (decoder) => oneOf([decoder, widgetPropFnDecoder]);
|
|
279
|
+
const onDecoder = objectWithSuffix({
|
|
280
|
+
load: { suffixed: true, decoder: decodeWidgetPropOrWidgetPropFn(optional(string())) },
|
|
281
|
+
click: { suffixed: true, decoder: decodeWidgetPropOrWidgetPropFn(optional(string())) },
|
|
282
|
+
change: { suffixed: true, decoder: decodeWidgetPropOrWidgetPropFn(optional(string())) },
|
|
283
|
+
filter: { suffixed: true, decoder: decodeWidgetPropOrWidgetPropFn(optional(string())) },
|
|
284
|
+
blur: { suffixed: true, decoder: decodeWidgetPropOrWidgetPropFn(optional(string())) }
|
|
285
|
+
});
|
|
286
|
+
const translationConfigDecoder = object({
|
|
287
|
+
key: string(),
|
|
288
|
+
default: optional(string()),
|
|
289
|
+
params: optional(succeed())
|
|
290
|
+
});
|
|
291
|
+
const localizableDecoder = oneOf([string(), translationConfigDecoder]);
|
|
292
|
+
const uidDecoder = optional(string());
|
|
293
|
+
const displayWidgetDecoder = objectWithSuffix({
|
|
294
|
+
kind: { decoder: literal("display") },
|
|
295
|
+
uid: { decoder: uidDecoder },
|
|
296
|
+
type: { decoder: string() },
|
|
297
|
+
size: { suffixed: true, decoder: optional(number()) },
|
|
298
|
+
include: { decoder: optional(includeDecoder) },
|
|
299
|
+
exclude: { decoder: optional(excludeDecoder) },
|
|
300
|
+
props: { decoder: optional(succeed()) }
|
|
301
|
+
});
|
|
302
|
+
const actionWidgetDecoder = objectWithSuffix({
|
|
303
|
+
kind: { decoder: literal("action") },
|
|
304
|
+
uid: { decoder: uidDecoder },
|
|
305
|
+
type: { decoder: string() },
|
|
306
|
+
actionType: {
|
|
307
|
+
decoder: optional(oneOf([literal("button"), literal("submit")]))
|
|
308
|
+
},
|
|
309
|
+
size: { suffixed: true, decoder: optional(number()) },
|
|
310
|
+
include: { decoder: optional(includeDecoder) },
|
|
311
|
+
exclude: { decoder: optional(excludeDecoder) },
|
|
312
|
+
label: {
|
|
313
|
+
suffixed: true,
|
|
314
|
+
decoder: decodeWidgetPropOrWidgetPropFn(optional(localizableDecoder))
|
|
315
|
+
},
|
|
316
|
+
disabled: { suffixed: true, decoder: optional(boolWhenDecoder) },
|
|
317
|
+
on: { decoder: optional(onDecoder) },
|
|
318
|
+
props: { decoder: optional(succeed()) }
|
|
319
|
+
});
|
|
320
|
+
const functionWidgetDecoder = new Decoder((json) => {
|
|
321
|
+
const jsonTypeof = typeof json;
|
|
322
|
+
if (jsonTypeof === "function") {
|
|
323
|
+
const fnWidget = json;
|
|
324
|
+
const widget = fnWidget({
|
|
325
|
+
$form: {},
|
|
326
|
+
errors: void 0,
|
|
327
|
+
touched: void 0,
|
|
328
|
+
translate: void 0
|
|
329
|
+
});
|
|
330
|
+
fnWidget.uid = fnWidget.uid || widget.uid || shortUUID();
|
|
331
|
+
fnWidget.type = widget.type;
|
|
332
|
+
fnWidget.path = widget.path;
|
|
333
|
+
return ok(fnWidget);
|
|
334
|
+
} else {
|
|
335
|
+
return err([{ message: `Expected a function, got '${jsonTypeof}'`, path: [] }]);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
const inputWidgetDecoder = objectWithSuffix({
|
|
339
|
+
kind: { decoder: literal("input") },
|
|
340
|
+
uid: { decoder: optional(string()) },
|
|
341
|
+
type: { decoder: string() },
|
|
342
|
+
size: { suffixed: true, decoder: optional(number()) },
|
|
343
|
+
include: { decoder: optional(includeDecoder) },
|
|
344
|
+
exclude: { decoder: optional(excludeDecoder) },
|
|
345
|
+
disabled: { suffixed: true, decoder: optional(boolWhenDecoder) },
|
|
346
|
+
readonly: { suffixed: true, decoder: optional(boolWhenDecoder) },
|
|
347
|
+
on: { decoder: optional(onDecoder) },
|
|
348
|
+
props: { decoder: optional(succeed()) },
|
|
349
|
+
label: {
|
|
350
|
+
suffixed: true,
|
|
351
|
+
decoder: decodeWidgetPropOrWidgetPropFn(optional(localizableDecoder))
|
|
352
|
+
},
|
|
353
|
+
path: { decoder: string() },
|
|
354
|
+
defaultValue: { decoder: optional(succeed()) },
|
|
355
|
+
validator: {
|
|
356
|
+
suffixed: true,
|
|
357
|
+
decoder: decodeWidgetPropOrWidgetPropFn(optional(succeed()))
|
|
358
|
+
}
|
|
359
|
+
}).map((ctrl) => {
|
|
360
|
+
const transformed = { ...ctrl };
|
|
361
|
+
if (!ctrl.uid) {
|
|
362
|
+
transformed.uid = `${ctrl.path}-${ctrl.type}`;
|
|
363
|
+
}
|
|
364
|
+
if (ctrl.type === "repeater") {
|
|
365
|
+
const props = ctrl["props"];
|
|
366
|
+
transformed.props = { ...props, template: layoutWidgetDecoder.parse(props["template"]) };
|
|
367
|
+
}
|
|
368
|
+
return transformed;
|
|
369
|
+
});
|
|
370
|
+
const formWidgetDecoder = lazy(() => {
|
|
371
|
+
const objectWidgetDecoder = discriminatedUnion("kind", {
|
|
372
|
+
input: inputWidgetDecoder,
|
|
373
|
+
layout: layoutWidgetDecoder,
|
|
374
|
+
display: displayWidgetDecoder,
|
|
375
|
+
action: actionWidgetDecoder
|
|
376
|
+
});
|
|
377
|
+
return new Decoder(
|
|
378
|
+
(json) => typeof json === "function" ? functionWidgetDecoder.decode(json) : objectWidgetDecoder.decode(json)
|
|
379
|
+
);
|
|
380
|
+
});
|
|
381
|
+
const layoutWidgetDecoder = objectWithSuffix({
|
|
382
|
+
kind: { decoder: literal("layout") },
|
|
383
|
+
uid: { decoder: uidDecoder },
|
|
384
|
+
type: { decoder: string() },
|
|
385
|
+
size: { suffixed: true, decoder: optional(number()) },
|
|
386
|
+
include: { decoder: optional(includeDecoder) },
|
|
387
|
+
exclude: { decoder: optional(excludeDecoder) },
|
|
388
|
+
props: { decoder: optional(succeed()) },
|
|
389
|
+
on: { decoder: optional(onDecoder) },
|
|
390
|
+
children: { decoder: array(formWidgetDecoder) }
|
|
391
|
+
});
|
|
392
|
+
function assignDeterministicUids(root) {
|
|
393
|
+
assignUidByPosition(root, "#0");
|
|
394
|
+
}
|
|
395
|
+
function assignUidByPosition(widget, positionUid) {
|
|
396
|
+
if (isFunctionWidget(widget)) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
if (!widget.uid) {
|
|
400
|
+
widget.uid = positionUid;
|
|
401
|
+
}
|
|
402
|
+
if (isLayoutWidget(widget)) {
|
|
403
|
+
widget.children.forEach((child, index) => {
|
|
404
|
+
assignUidByPosition(child, `${positionUid}.${index}`);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
if (isInputWidget(widget) && widget.type === "repeater") {
|
|
408
|
+
const template = widget.props?.["template"];
|
|
409
|
+
if (template) {
|
|
410
|
+
assignUidByPosition(template, `${positionUid}.t`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
object({
|
|
415
|
+
states: optional(record(string())),
|
|
416
|
+
form: lazy(() => layoutWidgetDecoder)
|
|
417
|
+
}).map((formDef) => {
|
|
418
|
+
assignDeterministicUids(formDef.form);
|
|
419
|
+
return formDef;
|
|
420
|
+
});
|
|
421
|
+
const formEventNames = {
|
|
422
|
+
submit: "formSubmit"
|
|
423
|
+
};
|
|
424
|
+
pipe(
|
|
425
|
+
map((store) => store.data),
|
|
426
|
+
distinctUntilChanged()
|
|
427
|
+
);
|
|
428
|
+
pipe(
|
|
429
|
+
filter((store) => store.touched === true),
|
|
430
|
+
map((store) => store.validations),
|
|
431
|
+
distinctUntilChanged()
|
|
432
|
+
);
|
|
433
|
+
pipe(
|
|
434
|
+
filter((store) => store.touched === true),
|
|
435
|
+
map((store) => store.injectedValidations),
|
|
436
|
+
distinctUntilChanged()
|
|
437
|
+
);
|
|
438
|
+
pipe(
|
|
439
|
+
map((store) => store.lang),
|
|
440
|
+
distinctUntilChanged()
|
|
441
|
+
);
|
|
442
|
+
pipe(
|
|
443
|
+
map((store) => store.calculatedWidgets),
|
|
444
|
+
distinctUntilChanged()
|
|
445
|
+
);
|
|
446
|
+
pipe(
|
|
447
|
+
map((store) => store.widgetFlags),
|
|
448
|
+
distinctUntilChanged()
|
|
449
|
+
);
|
|
450
|
+
pipe(
|
|
451
|
+
map((store) => store.touchedControls),
|
|
452
|
+
distinctUntilChanged()
|
|
453
|
+
);
|
|
454
|
+
pipe(
|
|
455
|
+
map((store) => store.formHealth),
|
|
456
|
+
distinctUntilChanged((prev, current) => {
|
|
457
|
+
if (prev.status !== current.status) {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
if (prev.status === "errored" && current.status === "errored") {
|
|
461
|
+
return prev.message === current.message && prev.code === current.code;
|
|
462
|
+
}
|
|
463
|
+
return true;
|
|
464
|
+
})
|
|
465
|
+
);
|
|
220
466
|
const DX_FRAMEWORKS = ["react", "angular", "vue", "lit", "vanilla"];
|
|
221
467
|
function resolveDxFramework() {
|
|
222
468
|
const raw = typeof process !== "undefined" ? process.env?.["GOLEMUI_FRAMEWORK"]?.toLowerCase() : void 0;
|
|
@@ -226,8 +472,8 @@ const FRAMEWORK_SETUP = {
|
|
|
226
472
|
react: "RENDER (React) — `import { gui } from '@golemui/gui-shared'; import { GuiForm } from '@golemui/gui-react'; import type { FormSubmitEvent } from '@golemui/core';`, then render `<GuiForm config={{ formDef: form }} formSubmit={(e: FormSubmitEvent) => { /* e.data is the form data */ }} />`. A `gui.displays.display(() => <h2>…</h2>)` returns React JSX.",
|
|
227
473
|
angular: "RENDER (Angular) — `import { gui } from '@golemui/gui-shared'; import { FormComponent } from '@golemui/gui-angular';`, add `FormComponent` to the standalone component's `imports`, then in the template `<gui-form [config]=\"{ formDef: form }\" (formSubmit)=\"onSubmit($event)\"></gui-form>` — `$event` is a `FormSubmitEvent` (type from `@golemui/core`), `$event.data` is the form data.",
|
|
228
474
|
vue: "RENDER (Vue) — `import { gui } from '@golemui/gui-shared'; import { GuiForm } from '@golemui/gui-vue';`, then `<GuiForm :config=\"{ formDef: form }\" @form-submit=\"onSubmit\" />` — the handler receives a `FormSubmitEvent` (`.data` is the form data). The event is `form-submit` (kebab-case), not `formSubmit`.",
|
|
229
|
-
lit: "RENDER (Lit) — `import { gui } from '@golemui/gui-shared'; import '@golemui/gui-lit';` (registers the `<gui-form>` custom element), then `<gui-form .config=${{ formDef: form }} @
|
|
230
|
-
vanilla: "RENDER (vanilla JS) — `import { gui } from '@golemui/gui-shared'; import '@golemui/gui-lit';` (registers `<gui-form>`), then `const el = document.querySelector('gui-form'); el.config = { formDef: form }; el.addEventListener('
|
|
475
|
+
lit: "RENDER (Lit) — `import { gui } from '@golemui/gui-shared'; import '@golemui/gui-lit';` (registers the `<gui-form>` custom element), then `<gui-form .config=${{ formDef: form }} @" + formEventNames.submit + "=${(e: CustomEvent) => { /* e.detail is the FormSubmitEvent; e.detail.data */ }}></gui-form>`. The event name is `" + formEventNames.submit + "` (camelCase) — Lit dispatches a raw CustomEvent, so there is no kebab-case alias.",
|
|
476
|
+
vanilla: "RENDER (vanilla JS) — `import { gui } from '@golemui/gui-shared'; import '@golemui/gui-lit';` (registers `<gui-form>`), then `const el = document.querySelector('gui-form'); el.config = { formDef: form }; el.addEventListener('" + formEventNames.submit + "', (e) => { /* e.detail.data */ });`. In TypeScript, type the element — `import type { FormElement } from '@golemui/gui-lit'; const el = document.querySelector<FormElement>('gui-form');` — the published types do not register `gui-form` in `HTMLElementTagNameMap`, so an untyped `querySelector` yields `Element` and `el.config` fails to compile."
|
|
231
477
|
};
|
|
232
478
|
function commonNote(fw = "react") {
|
|
233
479
|
return "GolemUI builds FORMS — data collection and validation. It is NOT a general-purpose UI toolkit: it never renders documents, page content, or markdown for display. A form is just an array of these items: `export const form = [ /* items */ ];`. " + FRAMEWORK_SETUP[fw] + " Import the component stylesheet ONCE — `@golemui/gui-components/index.css` — or the form renders unstyled. To RECEIVE A SUBMIT: add a `gui.actions.button({ label, actionType: 'submit' })` to the form and listen for the submit on the host component (the RENDER line above shows how for your framework) — the handler gets a `FormSubmitEvent` whose `.data` is the collected form data. To DISABLE submit until the form is valid, add `disabled: { when: '$formIsInvalid' }` to that button (`$formIsInvalid` is a built-in validity flag) — see the conditional-and-state-props pattern. The SAME `formDef` renders in every framework (React/Angular/Vue/Lit/vanilla) — only the host wrapper changes. FORM-LEVEL CONFIG — `formDef` is ALWAYS the bare array. Anything form-wide (named `states`, `validateOn`) goes in a sibling `formConfig` on the config (`config={{ formDef: form, formConfig: { states, validateOn } }}`), NEVER inside `formDef`. Do NOT wrap the array as `{ states, form: [...] }` and pass THAT as `formDef` — `formDef` is typed `Record<string, any>` so it COMPILES, but the `gui.*` items are never resolved and the form renders BLANK with no error. See the form-level-states pattern. Common fields like `include`/`exclude` (conditional visibility) go INSIDE a factory’s config argument — never spread them onto the result (`{ ...gui.inputs.x(...), include }` compiles but silently does nothing). See the conditional-visibility pattern. STATIC CONTENT — a section heading or any non-input text/block is the HOST’s job, not GolemUI’s: use `gui.displays.display(() => <h2>…</h2>)` returning your framework’s own node (React JSX, Vue/Angular/Lit node) — it needs no dependency and always renders. MARKDOWN has exactly ONE use: `gui.inputs.markdown`, an INPUT where the user EDITS markdown (its value is their markdown string). There is NO markdown-for-display widget — never use markdown to render a heading or content; use `display` for that. VALIDATOR `type` — one rule, three cases (so you never have to guess): (1) choice widgets (`dropdown`, `radiogroup`, `select`) REQUIRE an explicit `type`: `validator: { type: 'string', required: true }`. (2) `repeater` (array) validators auto-supply `type: 'array'` — supply only the rules, e.g. `validator: { required: true, minItems: 1 }`, never `type`. (3) everything else (text, number, date) takes the loose validator with NO `type`: `validator: { required: true }`. EVENT HANDLERS — `onChange`/`onLoad`/`onFilter`/`onBlur` (inputs/layouts) and `onClick` (actions) are FUNCTIONS, never bare strings: return a string to dispatch a host event by that name (`onChange: () => 'languageChanged'`), or take the event to push live changes (`onChange: (event) => event.update({ path: 'city', options: [...] })`).";
|
|
@@ -268,6 +514,7 @@ const INPUTS = [
|
|
|
268
514
|
{
|
|
269
515
|
factory: "textInput",
|
|
270
516
|
namespace: "inputs",
|
|
517
|
+
docSlug: "textinput",
|
|
271
518
|
call: "gui.inputs.textInput(path, { label, placeholder?, defaultValue?, validator? })",
|
|
272
519
|
example: "gui.inputs.textInput('fullName', { label: 'Full name', validator: { required: true, minLength: 2 } })",
|
|
273
520
|
notes: [
|
|
@@ -278,6 +525,7 @@ const INPUTS = [
|
|
|
278
525
|
{
|
|
279
526
|
factory: "numberInput",
|
|
280
527
|
namespace: "inputs",
|
|
528
|
+
docSlug: "number",
|
|
281
529
|
call: "gui.inputs.numberInput(path, { label, defaultValue?, validator? })",
|
|
282
530
|
example: "gui.inputs.numberInput('age', { label: 'Age', validator: { required: true, minimum: 0, maximum: 120 } })",
|
|
283
531
|
notes: [
|
|
@@ -287,6 +535,7 @@ const INPUTS = [
|
|
|
287
535
|
{
|
|
288
536
|
factory: "booleanInput",
|
|
289
537
|
namespace: "inputs",
|
|
538
|
+
docSlug: "toggle",
|
|
290
539
|
call: "gui.inputs.booleanInput(path, { label, defaultValue? })",
|
|
291
540
|
example: "gui.inputs.booleanInput('newsletter', { label: 'Subscribe to newsletter', defaultValue: false })",
|
|
292
541
|
notes: ["The on/off toggle for a single boolean. Use `checkbox` for a checkbox presentation."]
|
|
@@ -294,6 +543,7 @@ const INPUTS = [
|
|
|
294
543
|
{
|
|
295
544
|
factory: "checkbox",
|
|
296
545
|
namespace: "inputs",
|
|
546
|
+
docSlug: "checkbox",
|
|
297
547
|
call: "gui.inputs.checkbox(path, { label, defaultValue? })",
|
|
298
548
|
example: "gui.inputs.checkbox('terms', { label: 'I accept the terms', defaultValue: false })",
|
|
299
549
|
notes: ["A single boolean rendered as a checkbox."]
|
|
@@ -301,6 +551,7 @@ const INPUTS = [
|
|
|
301
551
|
{
|
|
302
552
|
factory: "textarea",
|
|
303
553
|
namespace: "inputs",
|
|
554
|
+
docSlug: "textarea",
|
|
304
555
|
call: "gui.inputs.textarea(path, { label, placeholder?, validator? })",
|
|
305
556
|
example: "gui.inputs.textarea('bio', { label: 'Bio', validator: { maxLength: 500 } })",
|
|
306
557
|
notes: ["Multi-line text; same loose string validator as `textInput`."]
|
|
@@ -308,6 +559,7 @@ const INPUTS = [
|
|
|
308
559
|
{
|
|
309
560
|
factory: "password",
|
|
310
561
|
namespace: "inputs",
|
|
562
|
+
docSlug: "password",
|
|
311
563
|
call: "gui.inputs.password(path, { label, validator? })",
|
|
312
564
|
example: "gui.inputs.password('password', { label: 'Password', validator: { required: true, minLength: 8 } })",
|
|
313
565
|
notes: ["Masked text input; loose string validator."]
|
|
@@ -315,6 +567,7 @@ const INPUTS = [
|
|
|
315
567
|
{
|
|
316
568
|
factory: "dropdown",
|
|
317
569
|
namespace: "inputs",
|
|
570
|
+
docSlug: "dropdown",
|
|
318
571
|
call: "gui.inputs.dropdown(path, { label, items, validator? })",
|
|
319
572
|
example: "gui.inputs.dropdown('country', { label: 'Country', items: [{ value: 'us', label: 'United States' }, { value: 'ca', label: 'Canada' }], validator: { type: 'string', required: true } })",
|
|
320
573
|
notes: [
|
|
@@ -325,6 +578,7 @@ const INPUTS = [
|
|
|
325
578
|
{
|
|
326
579
|
factory: "radiogroup",
|
|
327
580
|
namespace: "inputs",
|
|
581
|
+
docSlug: "radiogroup",
|
|
328
582
|
call: "gui.inputs.radiogroup(path, { label, options, defaultValue?, validator? })",
|
|
329
583
|
example: "gui.inputs.radiogroup('accountType', { label: 'Account type', defaultValue: 'personal', options: [{ value: 'personal', label: 'Personal' }, { value: 'business', label: 'Business' }] })",
|
|
330
584
|
notes: [
|
|
@@ -335,6 +589,7 @@ const INPUTS = [
|
|
|
335
589
|
{
|
|
336
590
|
factory: "datePicker",
|
|
337
591
|
namespace: "inputs",
|
|
592
|
+
docSlug: "date-picker",
|
|
338
593
|
call: "gui.inputs.datePicker(path, { label, minDate?, maxDate?, validator? })",
|
|
339
594
|
example: "gui.inputs.datePicker('startDate', { label: 'Coverage start', minDate: '2025-01-01', validator: { required: true } })",
|
|
340
595
|
notes: [
|
|
@@ -345,6 +600,7 @@ const INPUTS = [
|
|
|
345
600
|
{
|
|
346
601
|
factory: "currency",
|
|
347
602
|
namespace: "inputs",
|
|
603
|
+
docSlug: "currency",
|
|
348
604
|
call: "gui.inputs.currency(path, { label, validator? })",
|
|
349
605
|
example: "gui.inputs.currency('price', { label: 'Price', validator: { required: true, minimum: 0 } })",
|
|
350
606
|
notes: ["Numeric money input; number-style validator."]
|
|
@@ -352,6 +608,7 @@ const INPUTS = [
|
|
|
352
608
|
{
|
|
353
609
|
factory: "select",
|
|
354
610
|
namespace: "inputs",
|
|
611
|
+
docSlug: "select",
|
|
355
612
|
call: "gui.inputs.select(path, { label, options, validator? })",
|
|
356
613
|
example: "gui.inputs.select('plan', { label: 'Plan', options: [{ value: 'free', label: 'Free' }, { value: 'pro', label: 'Pro' }], validator: { type: 'string', required: true } })",
|
|
357
614
|
notes: [
|
|
@@ -362,6 +619,7 @@ const INPUTS = [
|
|
|
362
619
|
{
|
|
363
620
|
factory: "dateInput",
|
|
364
621
|
namespace: "inputs",
|
|
622
|
+
docSlug: "dateinput",
|
|
365
623
|
call: "gui.inputs.dateInput(path, { label, minDate?, maxDate?, validator? })",
|
|
366
624
|
example: "gui.inputs.dateInput('startDate', { label: 'Start date', validator: { required: true } })",
|
|
367
625
|
notes: [
|
|
@@ -372,6 +630,7 @@ const INPUTS = [
|
|
|
372
630
|
{
|
|
373
631
|
factory: "timeInput",
|
|
374
632
|
namespace: "inputs",
|
|
633
|
+
docSlug: "timeinput",
|
|
375
634
|
call: "gui.inputs.timeInput(path, { label, hourFormat?, minuteStep?, validator? })",
|
|
376
635
|
example: "gui.inputs.timeInput('meetingTime', { label: 'Meeting time', minuteStep: 15 })",
|
|
377
636
|
notes: [
|
|
@@ -381,6 +640,7 @@ const INPUTS = [
|
|
|
381
640
|
{
|
|
382
641
|
factory: "timePicker",
|
|
383
642
|
namespace: "inputs",
|
|
643
|
+
docSlug: "timepicker",
|
|
384
644
|
call: "gui.inputs.timePicker(path, { label, minTime?, maxTime?, minuteStep?, disabledRanges?, allowCustomTime?, validator? })",
|
|
385
645
|
example: "gui.inputs.timePicker('meetingTime', { label: 'Meeting time', minTime: '09:00', maxTime: '18:00', minuteStep: 30 })",
|
|
386
646
|
notes: [
|
|
@@ -390,6 +650,7 @@ const INPUTS = [
|
|
|
390
650
|
{
|
|
391
651
|
factory: "dateTimeInput",
|
|
392
652
|
namespace: "inputs",
|
|
653
|
+
docSlug: "datetimeinput",
|
|
393
654
|
call: "gui.inputs.dateTimeInput(path, { label, hourFormat?, minuteStep?, validator? })",
|
|
394
655
|
example: "gui.inputs.dateTimeInput('meetingAt', { label: 'Meeting at' })",
|
|
395
656
|
notes: [
|
|
@@ -399,6 +660,7 @@ const INPUTS = [
|
|
|
399
660
|
{
|
|
400
661
|
factory: "calendar",
|
|
401
662
|
namespace: "inputs",
|
|
663
|
+
docSlug: "calendar",
|
|
402
664
|
call: "gui.inputs.calendar(path, { label, minDate?, maxDate? })",
|
|
403
665
|
example: "gui.inputs.calendar('day', { label: 'Pick a day', minDate: '2025-01-01' })",
|
|
404
666
|
notes: [
|
|
@@ -409,6 +671,7 @@ const INPUTS = [
|
|
|
409
671
|
{
|
|
410
672
|
factory: "dateTimeCalendar",
|
|
411
673
|
namespace: "inputs",
|
|
674
|
+
docSlug: "datetimecalendar",
|
|
412
675
|
call: "gui.inputs.dateTimeCalendar(path, { label, minDate?, maxDate?, minTime?, maxTime?, minuteStep?, disabledTimeRanges?, allowCustomTime? })",
|
|
413
676
|
example: "gui.inputs.dateTimeCalendar('appointmentAt', { label: 'Appointment', minTime: '09:00', maxTime: '18:00' })",
|
|
414
677
|
notes: [
|
|
@@ -420,6 +683,7 @@ const INPUTS = [
|
|
|
420
683
|
{
|
|
421
684
|
factory: "dateTimePicker",
|
|
422
685
|
namespace: "inputs",
|
|
686
|
+
docSlug: "datetimepicker",
|
|
423
687
|
call: "gui.inputs.dateTimePicker(path, { label, minDate?, maxDate?, minTime?, maxTime?, minuteStep?, disabledTimeRanges?, allowCustomTime? })",
|
|
424
688
|
example: "gui.inputs.dateTimePicker('appointmentAt', { label: 'Appointment', minTime: '09:00', maxTime: '18:00' })",
|
|
425
689
|
notes: [
|
|
@@ -431,6 +695,7 @@ const INPUTS = [
|
|
|
431
695
|
{
|
|
432
696
|
factory: "markdown",
|
|
433
697
|
namespace: "inputs",
|
|
698
|
+
docSlug: "markdown",
|
|
434
699
|
call: "gui.inputs.markdown(path, { label })",
|
|
435
700
|
example: "gui.inputs.markdown('notes', { label: 'Notes (markdown)' })",
|
|
436
701
|
notes: [
|
|
@@ -440,6 +705,7 @@ const INPUTS = [
|
|
|
440
705
|
{
|
|
441
706
|
factory: "tags",
|
|
442
707
|
namespace: "inputs",
|
|
708
|
+
docSlug: "tags",
|
|
443
709
|
call: "gui.inputs.tags(path, { label })",
|
|
444
710
|
example: "gui.inputs.tags('skills', { label: 'Skills' })",
|
|
445
711
|
notes: ["Free-form multi-value tag input; the value is a string array."]
|
|
@@ -447,6 +713,7 @@ const INPUTS = [
|
|
|
447
713
|
{
|
|
448
714
|
factory: "repeater",
|
|
449
715
|
namespace: "inputs",
|
|
716
|
+
docSlug: "repeater",
|
|
450
717
|
call: "gui.inputs.repeater(path, { label?, addLabel?, removeLabel?, limit?, template })",
|
|
451
718
|
example: "gui.inputs.repeater('attendees', { label: 'Attendees', addLabel: 'Add attendee', template: [ gui.inputs.textInput('attendees.items.name', { label: 'Name' }) ] })",
|
|
452
719
|
notes: [
|
|
@@ -458,6 +725,7 @@ const INPUTS = [
|
|
|
458
725
|
{
|
|
459
726
|
factory: "list",
|
|
460
727
|
namespace: "inputs",
|
|
728
|
+
docSlug: "list",
|
|
461
729
|
call: "gui.inputs.list(path, { label, items, height?, itemHeight? })",
|
|
462
730
|
example: "gui.inputs.list('selection', { label: 'Pick an option', items: ['Option 1', 'Option 2', 'Option 3'], height: 200, itemHeight: 40 })",
|
|
463
731
|
notes: [
|
|
@@ -468,6 +736,7 @@ const INPUTS = [
|
|
|
468
736
|
{
|
|
469
737
|
factory: "rangeCalendar",
|
|
470
738
|
namespace: "inputs",
|
|
739
|
+
docSlug: "range-calendar",
|
|
471
740
|
call: "gui.inputs.rangeCalendar(path, { label? })",
|
|
472
741
|
example: "gui.inputs.rangeCalendar('stayDates', { label: 'Stay dates' })",
|
|
473
742
|
notes: [
|
|
@@ -477,6 +746,7 @@ const INPUTS = [
|
|
|
477
746
|
{
|
|
478
747
|
factory: "rangeDateInput",
|
|
479
748
|
namespace: "inputs",
|
|
749
|
+
docSlug: "range-date-input",
|
|
480
750
|
call: "gui.inputs.rangeDateInput(path, { label? })",
|
|
481
751
|
example: "gui.inputs.rangeDateInput('stayDates', { label: 'Stay dates' })",
|
|
482
752
|
notes: ["Typed start–end date **range** entry (the range sibling of `dateInput`)."]
|
|
@@ -484,6 +754,7 @@ const INPUTS = [
|
|
|
484
754
|
{
|
|
485
755
|
factory: "rangeTimeInput",
|
|
486
756
|
namespace: "inputs",
|
|
757
|
+
docSlug: "range-time-input",
|
|
487
758
|
call: "gui.inputs.rangeTimeInput(path, { label?, minTime?, maxTime? })",
|
|
488
759
|
example: "gui.inputs.rangeTimeInput('shift', { label: 'Shift', minTime: '06:00:00', maxTime: '22:00:00' })",
|
|
489
760
|
notes: [
|
|
@@ -493,6 +764,7 @@ const INPUTS = [
|
|
|
493
764
|
{
|
|
494
765
|
factory: "rangeDateTimeInput",
|
|
495
766
|
namespace: "inputs",
|
|
767
|
+
docSlug: "range-datetime-input",
|
|
496
768
|
call: "gui.inputs.rangeDateTimeInput(path, { label?, minDateTime?, maxDateTime? })",
|
|
497
769
|
example: "gui.inputs.rangeDateTimeInput('window', { label: 'Window', minDateTime: '2026-03-01T06:00:00', maxDateTime: '2026-03-31T22:00:00' })",
|
|
498
770
|
notes: [
|
|
@@ -503,6 +775,7 @@ const INPUTS = [
|
|
|
503
775
|
{
|
|
504
776
|
factory: "rangeDateTimeCalendar",
|
|
505
777
|
namespace: "inputs",
|
|
778
|
+
docSlug: "range-datetime-calendar",
|
|
506
779
|
call: "gui.inputs.rangeDateTimeCalendar(path, { label?, minDateTime?, maxDateTime?, disabledRanges?, startTimeLabel?, endTimeLabel? })",
|
|
507
780
|
example: "gui.inputs.rangeDateTimeCalendar('stay', { label: 'Stay', startTimeLabel: 'Check-in', endTimeLabel: 'Check-out' })",
|
|
508
781
|
notes: [
|
|
@@ -513,6 +786,7 @@ const INPUTS = [
|
|
|
513
786
|
{
|
|
514
787
|
factory: "rangeDateTimePicker",
|
|
515
788
|
namespace: "inputs",
|
|
789
|
+
docSlug: "range-datetime-picker",
|
|
516
790
|
call: "gui.inputs.rangeDateTimePicker(path, { label?, minDateTime?, maxDateTime?, disabledRanges?, startTimeLabel?, endTimeLabel? })",
|
|
517
791
|
example: "gui.inputs.rangeDateTimePicker('stay', { label: 'Stay', startTimeLabel: 'Check-in', endTimeLabel: 'Check-out' })",
|
|
518
792
|
notes: [
|
|
@@ -523,6 +797,7 @@ const INPUTS = [
|
|
|
523
797
|
{
|
|
524
798
|
factory: "rangeDatePicker",
|
|
525
799
|
namespace: "inputs",
|
|
800
|
+
docSlug: "range-date-picker",
|
|
526
801
|
call: "gui.inputs.rangeDatePicker(path, { label? })",
|
|
527
802
|
example: "gui.inputs.rangeDatePicker('stayDates', { label: 'Stay dates' })",
|
|
528
803
|
notes: ["Popover calendar for a start–end date **range** (the range sibling of `datePicker`)."]
|
|
@@ -530,6 +805,7 @@ const INPUTS = [
|
|
|
530
805
|
{
|
|
531
806
|
factory: "rangeTimePicker",
|
|
532
807
|
namespace: "inputs",
|
|
808
|
+
docSlug: "range-time-picker",
|
|
533
809
|
call: "gui.inputs.rangeTimePicker(path, { label?, minTime?, maxTime? })",
|
|
534
810
|
example: "gui.inputs.rangeTimePicker('shift', { label: 'Shift', minTime: '06:00:00', maxTime: '22:00:00' })",
|
|
535
811
|
notes: [
|
|
@@ -541,6 +817,7 @@ const ACTIONS = [
|
|
|
541
817
|
{
|
|
542
818
|
factory: "button",
|
|
543
819
|
namespace: "actions",
|
|
820
|
+
docSlug: "button",
|
|
544
821
|
call: "gui.actions.button({ label, actionType?: 'submit', onClick? })",
|
|
545
822
|
example: "gui.actions.button({ label: 'Sign up', actionType: 'submit' })",
|
|
546
823
|
notes: [
|
|
@@ -554,6 +831,7 @@ const DISPLAYS = [
|
|
|
554
831
|
{
|
|
555
832
|
factory: "alert",
|
|
556
833
|
namespace: "displays",
|
|
834
|
+
docSlug: "alert",
|
|
557
835
|
call: "gui.displays.alert({ text })",
|
|
558
836
|
example: "gui.displays.alert({ text: 'Please review your details before submitting.' })",
|
|
559
837
|
notes: [
|
|
@@ -563,6 +841,7 @@ const DISPLAYS = [
|
|
|
563
841
|
{
|
|
564
842
|
factory: "display",
|
|
565
843
|
namespace: "displays",
|
|
844
|
+
docSlug: "renderer",
|
|
566
845
|
call: "gui.displays.display(render)",
|
|
567
846
|
example: "gui.displays.display(() => 'Order summary')",
|
|
568
847
|
notes: [
|
|
@@ -575,6 +854,7 @@ const LAYOUTS = [
|
|
|
575
854
|
{
|
|
576
855
|
factory: "flex",
|
|
577
856
|
namespace: "layouts",
|
|
857
|
+
docSlug: "flex",
|
|
578
858
|
call: "gui.layouts.flex(children, props?)",
|
|
579
859
|
example: "gui.layouts.flex([ gui.inputs.textInput('firstName', { label: 'First name' }), gui.inputs.textInput('lastName', { label: 'Last name' }) ])",
|
|
580
860
|
notes: [
|
|
@@ -585,6 +865,7 @@ const LAYOUTS = [
|
|
|
585
865
|
{
|
|
586
866
|
factory: "verticalFlex",
|
|
587
867
|
namespace: "layouts",
|
|
868
|
+
docSlug: "flex",
|
|
588
869
|
call: "gui.layouts.verticalFlex(children, props?)",
|
|
589
870
|
example: "gui.layouts.verticalFlex([ gui.inputs.textInput('a', { label: 'A' }), gui.inputs.textInput('b', { label: 'B' }) ])",
|
|
590
871
|
notes: ["A `flex` with direction fixed to vertical."]
|
|
@@ -592,6 +873,7 @@ const LAYOUTS = [
|
|
|
592
873
|
{
|
|
593
874
|
factory: "horizontalFlex",
|
|
594
875
|
namespace: "layouts",
|
|
876
|
+
docSlug: "flex",
|
|
595
877
|
call: "gui.layouts.horizontalFlex(children, props?)",
|
|
596
878
|
example: "gui.layouts.horizontalFlex([ gui.inputs.textInput('a', { label: 'A' }), gui.inputs.textInput('b', { label: 'B' }) ])",
|
|
597
879
|
notes: ["A `flex` with direction fixed to horizontal."]
|
|
@@ -599,6 +881,7 @@ const LAYOUTS = [
|
|
|
599
881
|
{
|
|
600
882
|
factory: "grid",
|
|
601
883
|
namespace: "layouts",
|
|
884
|
+
docSlug: "grid",
|
|
602
885
|
call: "gui.layouts.grid(children, props?)",
|
|
603
886
|
example: "gui.layouts.grid([ gui.inputs.textInput('a', { label: 'A' }), gui.inputs.textInput('b', { label: 'B' }) ])",
|
|
604
887
|
notes: ["Grid layout; `horizontalGrid` / `verticalGrid` lock the direction."]
|
|
@@ -606,6 +889,7 @@ const LAYOUTS = [
|
|
|
606
889
|
{
|
|
607
890
|
factory: "verticalGrid",
|
|
608
891
|
namespace: "layouts",
|
|
892
|
+
docSlug: "grid",
|
|
609
893
|
call: "gui.layouts.verticalGrid(children, props?)",
|
|
610
894
|
example: "gui.layouts.verticalGrid([ gui.inputs.textInput('a', { label: 'A' }), gui.inputs.textInput('b', { label: 'B' }) ])",
|
|
611
895
|
notes: ["A `grid` with direction fixed to vertical."]
|
|
@@ -613,6 +897,7 @@ const LAYOUTS = [
|
|
|
613
897
|
{
|
|
614
898
|
factory: "horizontalGrid",
|
|
615
899
|
namespace: "layouts",
|
|
900
|
+
docSlug: "grid",
|
|
616
901
|
call: "gui.layouts.horizontalGrid(children, props?)",
|
|
617
902
|
example: "gui.layouts.horizontalGrid([ gui.inputs.textInput('a', { label: 'A' }), gui.inputs.textInput('b', { label: 'B' }) ])",
|
|
618
903
|
notes: ["A `grid` with direction fixed to horizontal."]
|
|
@@ -620,6 +905,7 @@ const LAYOUTS = [
|
|
|
620
905
|
{
|
|
621
906
|
factory: "tabs",
|
|
622
907
|
namespace: "layouts",
|
|
908
|
+
docSlug: "tabs",
|
|
623
909
|
call: "gui.layouts.tabs(sections)",
|
|
624
910
|
example: "gui.layouts.tabs([ { label: 'Account', children: [ gui.inputs.textInput('email', { label: 'Email' }) ] }, { label: 'Profile', children: [ gui.inputs.textInput('name', { label: 'Name' }) ] } ])",
|
|
625
911
|
notes: [
|
|
@@ -629,6 +915,7 @@ const LAYOUTS = [
|
|
|
629
915
|
{
|
|
630
916
|
factory: "accordion",
|
|
631
917
|
namespace: "layouts",
|
|
918
|
+
docSlug: "accordion",
|
|
632
919
|
call: "gui.layouts.accordion(sections)",
|
|
633
920
|
example: "gui.layouts.accordion([ { label: 'Billing', children: [ gui.inputs.textInput('card', { label: 'Card' }) ] } ])",
|
|
634
921
|
notes: [
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@golemui/gui-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1-rc.1",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
5
8
|
"description": "Model Context Protocol server for GolemUI — gives AI coding assistants deterministic schema validation and form generation for GolemUI form definitions.",
|
|
6
9
|
"type": "module",
|
|
7
10
|
"main": "./lib.js",
|
|
@@ -40,10 +43,10 @@
|
|
|
40
43
|
"ajv": "^8.17.1",
|
|
41
44
|
"ajv-formats": "^3.0.1",
|
|
42
45
|
"typescript": "^5.9.2",
|
|
43
|
-
"@golemui/gui-schemas": "1.1.
|
|
44
|
-
"@golemui/gui-shared": "1.1.
|
|
45
|
-
"@golemui/gui-validators": "1.1.
|
|
46
|
-
"@golemui/core": "1.1.
|
|
46
|
+
"@golemui/gui-schemas": "1.1.1-rc.1",
|
|
47
|
+
"@golemui/gui-shared": "1.1.1-rc.1",
|
|
48
|
+
"@golemui/gui-validators": "1.1.1-rc.1",
|
|
49
|
+
"@golemui/core": "1.1.1-rc.1",
|
|
47
50
|
"zod": "^4.0.0",
|
|
48
51
|
"@standard-schema/spec": "^1.0.0"
|
|
49
52
|
},
|