@nan0web/ui 1.5.2 → 1.7.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.
Files changed (53) hide show
  1. package/README.md +36 -1
  2. package/package.json +89 -84
  3. package/src/ArchitectureMap/ArchitectureMap.js +111 -0
  4. package/src/ArchitectureMap/index.js +1 -0
  5. package/src/InterfaceTemplate/InterfaceTemplate.js +95 -0
  6. package/src/InterfaceTemplate/index.js +1 -0
  7. package/src/README.md.js +42 -1
  8. package/src/core/GeneratorRunner.js +213 -0
  9. package/src/core/Intent.js +168 -0
  10. package/src/core/IntentErrorModel.js +94 -0
  11. package/src/core/MaskHandler.js +125 -0
  12. package/src/core/index.js +7 -0
  13. package/src/domain/SandboxModel.js +193 -0
  14. package/src/domain/ShowcaseAppModel.js +88 -0
  15. package/src/domain/components/AutocompleteModel.js +58 -0
  16. package/src/domain/components/BreadcrumbModel.js +265 -0
  17. package/src/domain/components/ButtonModel.js +92 -0
  18. package/src/domain/components/ConfirmModel.js +64 -0
  19. package/src/domain/components/InputModel.js +142 -0
  20. package/src/domain/components/SelectModel.js +59 -0
  21. package/src/domain/components/SpinnerModel.js +58 -0
  22. package/src/domain/components/TableModel.js +60 -0
  23. package/src/domain/components/ToastModel.js +77 -0
  24. package/src/domain/components/TreeModel.js +53 -0
  25. package/src/domain/components/index.js +11 -0
  26. package/src/domain/index.js +16 -0
  27. package/src/format.js +21 -0
  28. package/src/index.js +6 -0
  29. package/types/ArchitectureMap/ArchitectureMap.d.ts +70 -0
  30. package/types/ArchitectureMap/index.d.ts +1 -0
  31. package/types/InterfaceTemplate/InterfaceTemplate.d.ts +67 -0
  32. package/types/InterfaceTemplate/index.d.ts +1 -0
  33. package/types/core/GeneratorRunner.d.ts +51 -0
  34. package/types/core/Intent.d.ts +227 -85
  35. package/types/core/IntentErrorModel.d.ts +55 -0
  36. package/types/core/MaskHandler.d.ts +33 -0
  37. package/types/core/index.d.ts +4 -0
  38. package/types/domain/SandboxModel.d.ts +59 -0
  39. package/types/domain/ShowcaseAppModel.d.ts +62 -0
  40. package/types/domain/components/AutocompleteModel.d.ts +47 -0
  41. package/types/domain/components/BreadcrumbModel.d.ts +164 -0
  42. package/types/domain/components/ButtonModel.d.ts +81 -0
  43. package/types/domain/components/ConfirmModel.d.ts +54 -0
  44. package/types/domain/components/InputModel.d.ts +121 -0
  45. package/types/domain/components/SelectModel.d.ts +48 -0
  46. package/types/domain/components/SpinnerModel.d.ts +45 -0
  47. package/types/domain/components/TableModel.d.ts +44 -0
  48. package/types/domain/components/ToastModel.d.ts +62 -0
  49. package/types/domain/components/TreeModel.d.ts +49 -0
  50. package/types/domain/components/index.d.ts +10 -0
  51. package/types/domain/index.d.ts +3 -0
  52. package/types/format.d.ts +5 -0
  53. package/types/index.d.ts +4 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * InterfaceTemplate — base class for defining new UI interfaces.
3
+ *
4
+ * Establishes the inheritance pattern for the "One Logic, Many UI" architecture.
5
+ * Each UI interface (CLI, Web, Mobile, Chat, Audio) extends this template
6
+ * and overrides the required methods.
7
+ *
8
+ * @example
9
+ * class CliInterface extends InterfaceTemplate {
10
+ * render(data) { return formatForTerminal(data) }
11
+ * async ask(prompt) { return readlinePrompt(prompt) }
12
+ * }
13
+ *
14
+ * @abstract
15
+ */
16
+ export default class InterfaceTemplate {
17
+ /**
18
+ * List of methods that MUST be overridden by concrete implementations.
19
+ * Used for documentation and runtime validation.
20
+ *
21
+ * @type {string[]}
22
+ */
23
+ static requiredMethods: string[];
24
+ /**
25
+ * The name of this interface (e.g. 'cli', 'web', 'mobile').
26
+ * Override in subclass.
27
+ *
28
+ * @type {string}
29
+ */
30
+ name: string;
31
+ /**
32
+ * Render data to the user through the interface.
33
+ * Must be overridden by each concrete implementation.
34
+ *
35
+ * @param {any} [data] - data to render
36
+ * @returns {any} rendered output (string for CLI, DOM for web, etc.)
37
+ * @throws {Error} if not overridden
38
+ */
39
+ render(data?: any): any;
40
+ /**
41
+ * Request input from the user through the interface.
42
+ * Must be overridden by each concrete implementation.
43
+ *
44
+ * @param {string} prompt - question or label for the input
45
+ * @param {object} [options] - options (type, choices, default, etc.)
46
+ * @returns {Promise<any>} user's response
47
+ * @throws {Error} if not overridden
48
+ */
49
+ ask(prompt: string, options?: object): Promise<any>;
50
+ /**
51
+ * Validate that all required methods have been overridden.
52
+ * Call this in the subclass constructor to get early feedback.
53
+ *
54
+ * @returns {string[]} list of missing method overrides (empty = valid)
55
+ */
56
+ validate(): string[];
57
+ /**
58
+ * Get interface capabilities info.
59
+ *
60
+ * @returns {{ name: string, requiredMethods: string[], isComplete: boolean }}
61
+ */
62
+ info(): {
63
+ name: string;
64
+ requiredMethods: string[];
65
+ isComplete: boolean;
66
+ };
67
+ }
@@ -0,0 +1 @@
1
+ export { default, InterfaceTemplate } from "./InterfaceTemplate.js";
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Runs an OLMUI async generator through the provided adapter handlers.
3
+ *
4
+ * This function is the SINGLE point of execution for all adapters.
5
+ * It guarantees:
6
+ * - Every yielded intent is validated (contract enforcement).
7
+ * - Every 'ask' intent gets a response or times out (if timeoutMs > 0).
8
+ * - External abort signals are respected.
9
+ * - The final result is returned.
10
+ *
11
+ * @template T
12
+ * @param {AsyncGenerator<import('./Intent.js').Intent, import('./Intent.js').ResultIntent, import('./Intent.js').IntentResponse>} generator
13
+ * The model's async generator (from Model.run()).
14
+ * @param {AdapterHandlers} handlers
15
+ * Platform-specific handlers for each intent type.
16
+ * @param {RunnerOptions} [options={}]
17
+ * Runner configuration (timeout, abort signal).
18
+ * @returns {Promise<T>}
19
+ * The final result data from the generator.
20
+ */
21
+ export function runGenerator<T>(generator: AsyncGenerator<import("./Intent.js").Intent, import("./Intent.js").ResultIntent, import("./Intent.js").IntentResponse>, handlers: AdapterHandlers, options?: RunnerOptions): Promise<T>;
22
+ export type AdapterHandlers = {
23
+ /**
24
+ * Handler for 'ask' intents. Must return { value: ... }.
25
+ */
26
+ ask: (intent: import("./Intent.js").AskIntent) => Promise<import("./Intent.js").AskResponse>;
27
+ /**
28
+ * Handler for 'progress' intents. Optional (defaults to no-op).
29
+ */
30
+ progress?: ((intent: import("./Intent.js").ProgressIntent) => void | Promise<void>) | undefined;
31
+ /**
32
+ * Handler for 'log' intents. Optional (defaults to no-op).
33
+ */
34
+ log?: ((intent: import("./Intent.js").LogIntent) => void | Promise<void>) | undefined;
35
+ /**
36
+ * Handler for the final 'result'. Optional (defaults to no-op).
37
+ */
38
+ result?: ((intent: import("./Intent.js").ResultIntent) => void | Promise<void>) | undefined;
39
+ };
40
+ export type RunnerOptions = {
41
+ /**
42
+ * Maximum milliseconds to wait for an adapter handler to respond.
43
+ * Default is 0 (disabled) — web forms may wait indefinitely.
44
+ * Set to a positive value for CLI/Chat adapters where hanging is unacceptable.
45
+ */
46
+ timeoutMs?: number | undefined;
47
+ /**
48
+ * External AbortSignal for cancellation from outside.
49
+ */
50
+ signal?: AbortSignal | undefined;
51
+ };
@@ -1,88 +1,230 @@
1
1
  /**
2
- * Intent represents the user's declared will to perform an action.
3
- * It is interface-agnostic and can be validated or executed without
4
- * any UI, CLI, or external dependencies.
2
+ * Detects if a value is a Model-as-Schema class (has static fields with `help`).
3
+ * @param {*} schema
4
+ * @returns {boolean}
5
+ */
6
+ export function isModelSchema(schema: any): boolean;
7
+ /**
8
+ * Validates that an object is a well-formed Intent.
9
+ * Throws ModelError if the intent is malformed (the "Judge").
5
10
  *
6
- * An Intent may be:
7
- * - Ready: all required data is valid → can be executed immediately
8
- * - Partial: some data missing or invalid → requires user action
9
- * - Invalid: cannot be fulfilled under any interface (e.g., restricted field)
11
+ * @param {*} intent
12
+ * @returns {intent is Intent}
13
+ */
14
+ export function validateIntent(intent: any): intent is Intent;
15
+ /**
16
+ * @typedef {Object} FieldSchema
17
+ * @property {string} help - Human-readable label / i18n key.
18
+ * @property {*} default - Default value for the field.
19
+ * @property {string} [type] - Field type hint ('text', 'number', 'text/markdown').
20
+ * @property {Array<{value: *, label: string}>} [options] - Enum options for select.
21
+ * @property {(val: *) => true | string} [validate] - Validator: true = ok, string = error key from Model.
22
+ * @property {boolean} [hidden] - If true, field is excluded from UI forms.
23
+ */
24
+ /**
25
+ * Model needs data from the environment (user input, LLM extraction, test fixture).
26
+ * Adapter MUST return an `AskResponse`.
27
+ * @typedef {Object} AskIntent
28
+ * @property {'ask'} type
29
+ * @property {string} field - Property name on the model.
30
+ * @property {FieldSchema | Function} schema - Field metadata or Model-as-Schema class constructor.
31
+ * @property {true} [model] - When true, schema is a Model-as-Schema class (full form).
32
+ */
33
+ /**
34
+ * Model informs about a long-running operation. No response expected.
35
+ * Message MUST come from the Model (i18n static field value).
36
+ * @typedef {Object} ProgressIntent
37
+ * @property {'progress'} type
38
+ * @property {number} [value] - Progress value (0-1).
39
+ * @property {string} [id] - Progress ID for tracking multiple parallel operations.
40
+ * @property {string} message - Status message from Model (i18n static field value).
41
+ */
42
+ /**
43
+ * Model emits a log message. No response expected.
44
+ * Message MUST come from the Model (i18n static field value).
45
+ * @typedef {Object} LogIntent
46
+ * @property {'log'} type
47
+ * @property {'info' | 'warn' | 'error' | 'success'} level
48
+ * @property {string} message - Log message from Model (i18n static field value).
49
+ */
50
+ /**
51
+ * Final return value from the generator.
52
+ * @typedef {Object} ResultIntent
53
+ * @property {'result'} type
54
+ * @property {*} data - The raw result data (JSON-serializable).
55
+ */
56
+ /**
57
+ * Union of all possible yielded intents.
58
+ * @typedef {AskIntent | ProgressIntent | LogIntent} Intent
59
+ */
60
+ /**
61
+ * Response to an AskIntent. Adapter provides the collected value.
62
+ * The value MUST conform to the type described in the requested FieldSchema.
63
+ * @typedef {Object} AskResponse
64
+ * @property {*} value - The value matching schema.type (collected from user / LLM / test fixture).
65
+ * @property {boolean} [cancelled] - Whether the user cancelled this interaction (e.g. pressed ESC).
66
+ */
67
+ /**
68
+ * Special response that Adapters can send to abort the generator.
69
+ *
70
+ * The `reason` is a KEY from the Model's static `abort` dictionary,
71
+ * not a freeform message. This enables proper i18n translation:
10
72
  *
11
- * @example
12
- * const intent = new Intent({
13
- * target: LoginMessage,
14
- * body: { username: "alice" }
15
- * })
16
- * if (!intent.isReady()) {
17
- * const validMsg = await handleIntent(intent, adapter)
18
- * }
19
- */
20
- declare class Intent extends Message {
21
- /**
22
- * Create a new Intent.
23
- *
24
- * @param {object} input
25
- * @param {typeof Message} input.target - message class this intent wants to create
26
- * @param {any} [input.context] - execution context
27
- * @param {object} [body] - partial or complete data for the target message
28
- */
29
- constructor({ target, context, ...body }?: { target: typeof Message; context?: any })
30
- /**
31
- * The target Message class this Intent aims to produce.
32
- * Must be a class with a static `.Body` schema.
33
- *
34
- * @type {typeof Message | null}
35
- */
36
- target: typeof Message | null
37
- /**
38
- * Optional context for execution (session, locale, state, etc.).
39
- *
40
- * @type {any}
41
- */
42
- context: any
43
- /**
44
- * Validates all fields in the Intent's body against the target's schema.
45
- *
46
- * Checks:
47
- * - Required fields presence and non-emptiness
48
- * - Pattern matching (RegExp)
49
- * - Value within allowed options (if defined)
50
- * - Custom validation logic (if `validate` function is defined)
51
- *
52
- * @returns {Map<string, string>} Map of field → error message, empty if valid
53
- */
54
- validateIntent(): Map<string, string>
55
- /**
56
- * Executes the Intent by creating a valid instance of the target message.
57
- *
58
- * If the Intent is not ready (has validation errors), returns null.
59
- *
60
- * @returns {Message | null} the created message, or null if invalid
61
- */
62
- execute(): Message | null
63
- /**
64
- * Checks if the Intent can be executed immediately, without user input.
65
- *
66
- * @returns {boolean} true if all required fields are valid
67
- */
68
- isReady(): boolean
69
- /**
70
- * Converts the Intent to a plain object for logging or inspection.
71
- *
72
- * @returns {object} serializable object with intent, body, and context
73
- */
74
- toObject(): object
75
- }
76
- declare namespace Intent {
77
- /**
78
- * Handles an Intent by fulfilling missing or invalid fields.
79
- *
80
- * @param {Intent} intent - the declared intent to handle
81
- * @param {object} inputAdapter - must have `.ask(prompt)`
82
- * @returns {Promise<Message | null>} resolved when intent is fulfilled
83
- * @throws {CancelError} if user cancels
84
- */
85
- function handleIntent(intent: Intent, inputAdapter: object): Promise<Message | null>
86
- }
87
- export default Intent
88
- import { Message } from '@nan0web/co'
73
+ * Model defines: static abort = { user_cancelled: 'Скасовано', timeout: 'Час вичерпано' }
74
+ * Adapter sends: { abort: true, reason: 'user_cancelled' }
75
+ * UI translates: t(Model.abort[reason])
76
+ *
77
+ * @typedef {Object} AbortResponse
78
+ * @property {true} abort - Signal to the model that execution was cancelled.
79
+ * @property {string} [reason] - Key from Model's static abort dictionary (not a freeform message).
80
+ */
81
+ /**
82
+ * Union of all possible responses an Adapter can send back via iterator.next().
83
+ * @typedef {AskResponse | AbortResponse | undefined} IntentResponse
84
+ */
85
+ export const INTENT_TYPES: readonly ["ask", "progress", "log"];
86
+ export function ask(field: string, schema: object | Function): AskIntent;
87
+ export function progress(message: any): {
88
+ type: string;
89
+ message: any;
90
+ };
91
+ export function log(level: any, message: any, data?: {}): {
92
+ type: string;
93
+ level: any;
94
+ message: any;
95
+ };
96
+ export function result(data: any): {
97
+ type: string;
98
+ data: any;
99
+ };
100
+ export type FieldSchema = {
101
+ /**
102
+ * - Human-readable label / i18n key.
103
+ */
104
+ help: string;
105
+ /**
106
+ * - Default value for the field.
107
+ */
108
+ default: any;
109
+ /**
110
+ * - Field type hint ('text', 'number', 'text/markdown').
111
+ */
112
+ type?: string | undefined;
113
+ /**
114
+ * - Enum options for select.
115
+ */
116
+ options?: {
117
+ value: any;
118
+ label: string;
119
+ }[] | undefined;
120
+ /**
121
+ * - Validator: true = ok, string = error key from Model.
122
+ */
123
+ validate?: ((val: any) => true | string) | undefined;
124
+ /**
125
+ * - If true, field is excluded from UI forms.
126
+ */
127
+ hidden?: boolean | undefined;
128
+ };
129
+ /**
130
+ * Model needs data from the environment (user input, LLM extraction, test fixture).
131
+ * Adapter MUST return an `AskResponse`.
132
+ */
133
+ export type AskIntent = {
134
+ type: "ask";
135
+ /**
136
+ * - Property name on the model.
137
+ */
138
+ field: string;
139
+ /**
140
+ * - Field metadata or Model-as-Schema class constructor.
141
+ */
142
+ schema: FieldSchema | Function;
143
+ /**
144
+ * - When true, schema is a Model-as-Schema class (full form).
145
+ */
146
+ model?: true | undefined;
147
+ };
148
+ /**
149
+ * Model informs about a long-running operation. No response expected.
150
+ * Message MUST come from the Model (i18n static field value).
151
+ */
152
+ export type ProgressIntent = {
153
+ type: "progress";
154
+ /**
155
+ * - Progress value (0-1).
156
+ */
157
+ value?: number | undefined;
158
+ /**
159
+ * - Progress ID for tracking multiple parallel operations.
160
+ */
161
+ id?: string | undefined;
162
+ /**
163
+ * - Status message from Model (i18n static field value).
164
+ */
165
+ message: string;
166
+ };
167
+ /**
168
+ * Model emits a log message. No response expected.
169
+ * Message MUST come from the Model (i18n static field value).
170
+ */
171
+ export type LogIntent = {
172
+ type: "log";
173
+ level: "info" | "warn" | "error" | "success";
174
+ /**
175
+ * - Log message from Model (i18n static field value).
176
+ */
177
+ message: string;
178
+ };
179
+ /**
180
+ * Final return value from the generator.
181
+ */
182
+ export type ResultIntent = {
183
+ type: "result";
184
+ /**
185
+ * - The raw result data (JSON-serializable).
186
+ */
187
+ data: any;
188
+ };
189
+ /**
190
+ * Union of all possible yielded intents.
191
+ */
192
+ export type Intent = AskIntent | ProgressIntent | LogIntent;
193
+ /**
194
+ * Response to an AskIntent. Adapter provides the collected value.
195
+ * The value MUST conform to the type described in the requested FieldSchema.
196
+ */
197
+ export type AskResponse = {
198
+ /**
199
+ * - The value matching schema.type (collected from user / LLM / test fixture).
200
+ */
201
+ value: any;
202
+ /**
203
+ * - Whether the user cancelled this interaction (e.g. pressed ESC).
204
+ */
205
+ cancelled?: boolean | undefined;
206
+ };
207
+ /**
208
+ * Special response that Adapters can send to abort the generator.
209
+ *
210
+ * The `reason` is a KEY from the Model's static `abort` dictionary,
211
+ * not a freeform message. This enables proper i18n translation:
212
+ *
213
+ * Model defines: static abort = { user_cancelled: 'Скасовано', timeout: 'Час вичерпано' }
214
+ * Adapter sends: { abort: true, reason: 'user_cancelled' }
215
+ * UI translates: t(Model.abort[reason])
216
+ */
217
+ export type AbortResponse = {
218
+ /**
219
+ * - Signal to the model that execution was cancelled.
220
+ */
221
+ abort: true;
222
+ /**
223
+ * - Key from Model's static abort dictionary (not a freeform message).
224
+ */
225
+ reason?: string | undefined;
226
+ };
227
+ /**
228
+ * Union of all possible responses an Adapter can send back via iterator.next().
229
+ */
230
+ export type IntentResponse = AskResponse | AbortResponse | undefined;
@@ -0,0 +1,55 @@
1
+ export class IntentErrorModel {
2
+ static intent_not_object: {
3
+ help: string;
4
+ error: string;
5
+ };
6
+ static intent_unknown_type: {
7
+ help: string;
8
+ error: string;
9
+ };
10
+ static ask_missing_field: {
11
+ help: string;
12
+ error: string;
13
+ };
14
+ static ask_missing_schema_help: {
15
+ help: string;
16
+ error: string;
17
+ };
18
+ static intent_missing_message: {
19
+ help: string;
20
+ error: string;
21
+ };
22
+ static adapter_missing_ask: {
23
+ help: string;
24
+ error: string;
25
+ };
26
+ static ask_wrong_response: {
27
+ help: string;
28
+ error: string;
29
+ };
30
+ static validation_failed: {
31
+ help: string;
32
+ error: string;
33
+ };
34
+ static unhandled_intent: {
35
+ help: string;
36
+ error: string;
37
+ };
38
+ static timeout: {
39
+ help: string;
40
+ error: string;
41
+ };
42
+ static aborted: {
43
+ help: string;
44
+ error: string;
45
+ };
46
+ /**
47
+ * Build a ModelError for a specific error field.
48
+ *
49
+ * @param {string} field - Static field name on IntentErrorModel.
50
+ * @param {Record<string, *>} [params] - Template parameters to substitute {key} placeholders.
51
+ * @returns {ModelError}
52
+ */
53
+ static error(field: string, params?: Record<string, any>): ModelError;
54
+ }
55
+ import { ModelError } from '@nan0web/types';
@@ -0,0 +1,33 @@
1
+ export class MaskHandler {
2
+ constructor(mask: any);
3
+ mask: any;
4
+ raw: string;
5
+ /** How many placeholder positions the mask has */
6
+ get _slotCount(): number;
7
+ /** Static prefix of the mask (literal characters before first placeholder) */
8
+ get _prefix(): string;
9
+ get isComplete(): boolean;
10
+ get formatted(): string;
11
+ /**
12
+ * Append a digit/letter character.
13
+ * Only accepts characters that fit into placeholders.
14
+ *
15
+ * @param {string} char
16
+ * @returns {boolean} true if accepted
17
+ */
18
+ input(char: string): boolean;
19
+ /**
20
+ * Remove last character
21
+ */
22
+ backspace(): boolean;
23
+ /**
24
+ * Set a full value, intelligently stripping the mask's static prefix
25
+ * if the user pasted or injected the full formatted number.
26
+ *
27
+ * e.g. setValue('+380660848404') with mask '+38 (099) 999 9999'
28
+ * strips "+38" → raw = '0660848404'
29
+ *
30
+ * @param {string} val
31
+ */
32
+ setValue(val: string): void;
33
+ }
@@ -4,9 +4,13 @@ export { default as UiMessage } from "./Message/Message.js";
4
4
  export { default as FormMessage } from "./Form/Message.js";
5
5
  export { default as FormInput } from "./Form/Input.js";
6
6
  export { default as UiAdapter } from "./UiAdapter.js";
7
+ export { IntentErrorModel } from "./IntentErrorModel.js";
8
+ export { runGenerator } from "./GeneratorRunner.js";
9
+ export { MaskHandler } from "./MaskHandler.js";
7
10
  import UIStream from './Stream.js';
8
11
  import StreamEntry from './StreamEntry.js';
9
12
  import UIForm from './Form/Form.js';
10
13
  export { UIStream, UIStream as UiStream, StreamEntry, StreamEntry as UiStreamEntry, UIForm, UIForm as UiForm };
11
14
  export { default as Error, CancelError } from "./Error/index.js";
12
15
  export { runFlow, flow, View, Prompt, Stream, Alert, Toast, Badge, Text, Table, Input, Select, Confirm, Multiselect, Mask, Password, Spinner, Progress, default as Flow } from "./Flow.js";
16
+ export { validateIntent, ask, progress, log, result, INTENT_TYPES, isModelSchema } from "./Intent.js";
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @typedef {Object} SandboxData
3
+ * @property {string[]} [components]
4
+ * @property {string} [selectedComponent]
5
+ * @property {string} [themeFormat]
6
+ */
7
+ /**
8
+ * Model-as-Schema for the UI Sandbox environment.
9
+ * Represents a tool wrapping standard OLMUI components, allowing
10
+ * users to inspect their models, tweak variables interactively,
11
+ * and export the configuration as themes for the Marketplace.
12
+ *
13
+ * Navigation uses BreadcrumbModel:
14
+ * ESC = pop one level (if stack has no parent → exit app)
15
+ * Ctrl+C = always exit (handled by prompts.js wrapper)
16
+ *
17
+ * URL mapping:
18
+ * /sandbox → Select Component
19
+ * /sandbox/button → Edit Button properties
20
+ * /sandbox/button/export → Choose export format
21
+ */
22
+ export class SandboxModel extends Model {
23
+ static components: {
24
+ help: string;
25
+ type: string;
26
+ default: never[];
27
+ };
28
+ static selectedComponent: {
29
+ help: string;
30
+ type: string;
31
+ };
32
+ static themeFormat: {
33
+ help: string;
34
+ options: string[];
35
+ default: string;
36
+ };
37
+ /**
38
+ * @param {SandboxData | any} [data]
39
+ */
40
+ constructor(data?: SandboxData | any);
41
+ /** @type {string[]|undefined} */ components: string[] | undefined;
42
+ /** @type {string|undefined} */ selectedComponent: string | undefined;
43
+ /** @type {string|undefined} */ themeFormat: string | undefined;
44
+ run(): AsyncGenerator<any, {
45
+ type: string;
46
+ data: {
47
+ targetComponent: string | undefined;
48
+ themeConfig: any;
49
+ exportFormat: string | undefined;
50
+ breadcrumb: string;
51
+ };
52
+ }, any>;
53
+ }
54
+ export type SandboxData = {
55
+ components?: string[] | undefined;
56
+ selectedComponent?: string | undefined;
57
+ themeFormat?: string | undefined;
58
+ };
59
+ import { Model } from '@nan0web/core';
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Model-as-Schema for the entire UI Sandbox Showcase.
3
+ * Represents a complete User Journey demonstrating all components.
4
+ * Showcases OLMUI Scenario Testing capabilities.
5
+ */
6
+ export class ShowcaseAppModel {
7
+ static appName: {
8
+ help: string;
9
+ default: string;
10
+ type: string;
11
+ };
12
+ appName: string;
13
+ run(): AsyncGenerator<{
14
+ type: string;
15
+ field: string;
16
+ schema: {
17
+ help: string;
18
+ };
19
+ component: string;
20
+ model: any;
21
+ } | {
22
+ type: string;
23
+ field: string;
24
+ schema: {
25
+ help: string | undefined;
26
+ type: string;
27
+ };
28
+ component: string;
29
+ model: any;
30
+ } | {
31
+ type: string;
32
+ level: string;
33
+ message: string | undefined;
34
+ component: string;
35
+ model: any;
36
+ } | {
37
+ type: string;
38
+ message: string;
39
+ component: string;
40
+ model: any;
41
+ }, {
42
+ type: string;
43
+ data: {
44
+ success: boolean;
45
+ reason: string;
46
+ profile?: undefined;
47
+ rowsDisplayed?: undefined;
48
+ };
49
+ } | {
50
+ type: string;
51
+ data: {
52
+ success: boolean;
53
+ profile: {
54
+ userName: string;
55
+ role: string;
56
+ tool: string;
57
+ };
58
+ rowsDisplayed: number;
59
+ reason?: undefined;
60
+ };
61
+ }, unknown>;
62
+ }