@nan0web/ui 1.10.0 → 1.11.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 +69 -3
- package/package.json +61 -29
- package/src/App/Command/DepsCommand.js +3 -4
- package/src/Frame/Props.js +12 -18
- package/src/InterfaceTemplate/InterfaceTemplate.js +9 -7
- package/src/Model/index.js +61 -6
- package/src/StdIn.js +2 -6
- package/src/cli.js +1 -0
- package/src/core/GeneratorRunner.js +67 -7
- package/src/core/InputAdapter.js +3 -1
- package/src/core/Intent.js +200 -17
- package/src/core/Message/Message.js +4 -7
- package/src/core/Message/OutputMessage.js +4 -9
- package/src/core/StreamEntry.js +20 -28
- package/src/core/index.js +1 -0
- package/src/domain/Content.js +196 -0
- package/src/domain/Document.js +17 -0
- package/src/domain/FooterModel.js +37 -19
- package/src/domain/HeaderModel.js +47 -21
- package/src/domain/HeroModel.js +24 -22
- package/src/domain/LayoutModel.js +43 -0
- package/src/domain/ModelAsApp.js +46 -0
- package/src/domain/SandboxModel.js +19 -16
- package/src/domain/app/GalleryCommand.js +53 -0
- package/src/domain/app/GalleryRenderIntent.js +77 -0
- package/src/domain/app/SnapshotAuditor.js +401 -0
- package/src/domain/app/SnapshotRunner.js +264 -0
- package/src/domain/app/UIApp.js +78 -0
- package/src/domain/components/BreadcrumbModel.js +10 -6
- package/src/domain/components/FeatureGridModel.js +62 -0
- package/src/domain/components/MarkdownModel.js +24 -0
- package/src/domain/components/ShellModel.js +243 -0
- package/src/domain/components/TableModel.js +10 -6
- package/src/domain/components/ToastModel.js +10 -6
- package/src/domain/components/index.js +3 -1
- package/src/domain/index.js +14 -4
- package/src/index.js +21 -2
- package/src/inspect.js +2 -0
- package/src/test/ScenarioAdapter.js +59 -0
- package/src/test/ScenarioTest.js +51 -0
- package/src/test/ScenarioTest.story.js +56 -0
- package/src/testing/CrashReporter.js +56 -0
- package/src/testing/GalleryGenerator.js +15 -71
- package/src/testing/LogicInspector.js +3 -3
- package/src/testing/SnapshotRunner.js +22 -0
- package/src/testing/SpecAdapter.js +115 -0
- package/src/testing/SpecRunner.js +121 -0
- package/src/testing/VisualAdapter.js +24 -19
- package/src/testing/index.js +5 -1
- package/src/testing/verifySnapshot.js +17 -0
- package/types/App/Command/DepsCommand.d.ts +0 -2
- package/types/Model/index.d.ts +56 -62
- package/types/StdIn.d.ts +3 -3
- package/types/cli.d.ts +1 -0
- package/types/core/GeneratorRunner.d.ts +14 -1
- package/types/core/InputAdapter.d.ts +2 -1
- package/types/core/Intent.d.ts +209 -31
- package/types/core/Message/Message.d.ts +2 -2
- package/types/core/Message/OutputMessage.d.ts +0 -2
- package/types/core/index.d.ts +1 -0
- package/types/domain/Content.d.ts +340 -0
- package/types/domain/Document.d.ts +21 -0
- package/types/domain/FooterModel.d.ts +22 -12
- package/types/domain/HeaderModel.d.ts +36 -13
- package/types/domain/HeroModel.d.ts +19 -17
- package/types/domain/LayoutModel.d.ts +34 -0
- package/types/domain/ModelAsApp.d.ts +23 -0
- package/types/domain/SandboxModel.d.ts +10 -0
- package/types/domain/app/GalleryCommand.d.ts +55 -0
- package/types/domain/app/GalleryRenderIntent.d.ts +31 -0
- package/types/domain/app/SnapshotAuditor.d.ts +99 -0
- package/types/domain/app/SnapshotRunner.d.ts +45 -0
- package/types/domain/app/UIApp.d.ts +60 -0
- package/types/domain/components/BreadcrumbModel.d.ts +6 -8
- package/types/domain/components/FeatureGridModel.d.ts +50 -0
- package/types/domain/components/MarkdownModel.d.ts +19 -0
- package/types/domain/components/ShellModel.d.ts +56 -0
- package/types/domain/components/TableModel.d.ts +4 -0
- package/types/domain/components/ToastModel.d.ts +4 -0
- package/types/domain/components/index.d.ts +3 -0
- package/types/domain/index.d.ts +10 -4
- package/types/index.d.ts +19 -1
- package/types/inspect.d.ts +2 -0
- package/types/test/ScenarioAdapter.d.ts +43 -0
- package/types/test/ScenarioTest.d.ts +24 -0
- package/types/test/ScenarioTest.story.d.ts +1 -0
- package/types/testing/CrashReporter.d.ts +13 -0
- package/types/testing/SnapshotRunner.d.ts +7 -0
- package/types/testing/SpecAdapter.d.ts +57 -0
- package/types/testing/SpecRunner.d.ts +41 -0
- package/types/testing/VisualAdapter.d.ts +0 -6
- package/types/testing/index.d.ts +5 -1
- package/types/testing/verifySnapshot.d.ts +14 -0
- package/src/testing/SnapshotInspector.js +0 -84
- package/types/App/Command/Options.d.ts +0 -43
- package/types/App/Command/index.d.ts +0 -8
- package/types/App/User/Command/Options.d.ts +0 -34
- package/types/core/Message/InputMessage.d.ts +0 -71
- package/types/domain/components/HeroModel.d.ts +0 -24
- package/types/domain/components/ShowcaseAppModel.d.ts +0 -32
- package/types/testing/SnapshotInspector.d.ts +0 -17
package/src/core/Intent.js
CHANGED
|
@@ -38,17 +38,32 @@ import { IntentErrorModel } from './IntentErrorModel.js'
|
|
|
38
38
|
* @typedef {Object} ProgressIntent
|
|
39
39
|
* @property {'progress'} type
|
|
40
40
|
* @property {number} [value] - Progress value (0-1).
|
|
41
|
-
* @property {
|
|
41
|
+
* @property {number} [total] - Absolute total (if value is absolute).
|
|
42
|
+
* @property {string} [id] - Progress ID for tracking by Adapter to calculate speed/eta.
|
|
42
43
|
* @property {string} message - Status message from Model (i18n static field value).
|
|
43
44
|
*/
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
|
-
*
|
|
47
|
+
* @typedef {'info' | 'warn' | 'error' | 'success'} ShowLevel
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/** @typedef {ShowLevel} LogLevel */
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Model emits a show message. No response expected.
|
|
47
54
|
* Message MUST come from the Model (i18n static field value).
|
|
55
|
+
* @typedef {Object} ShowIntent
|
|
56
|
+
* @property {'show'} type
|
|
57
|
+
* @property {ShowLevel} level
|
|
58
|
+
* @property {string} message - Show message from Model (i18n static field value).
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Model emits a log message intended for debugging/developer (Not UI).
|
|
48
63
|
* @typedef {Object} LogIntent
|
|
49
64
|
* @property {'log'} type
|
|
50
|
-
* @property {
|
|
51
|
-
* @property {string} message -
|
|
65
|
+
* @property {LogLevel} level
|
|
66
|
+
* @property {string} message - Internal log message.
|
|
52
67
|
*/
|
|
53
68
|
|
|
54
69
|
/**
|
|
@@ -67,9 +82,33 @@ import { IntentErrorModel } from './IntentErrorModel.js'
|
|
|
67
82
|
* @property {object} props - Static props for the component.
|
|
68
83
|
*/
|
|
69
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Contextual data and attachments for the AI subagent.
|
|
87
|
+
* @typedef {Object} AgentContext
|
|
88
|
+
* @property {string[]} [instructions] - List of instructions or guidelines (e.g. ['Use 1-char emojis only']).
|
|
89
|
+
* @property {Record<string, string>} [files] - Hash map of file paths to their string contents.
|
|
90
|
+
* @property {Record<string, any>} [data] - Any arbitrary JSON data (e.g. parsed errors, ASTs, metadata) useful for the task.
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Model delegates a task to an AI subagent. The Adapter should launch the agent
|
|
95
|
+
* with the provided task and context, and return the result. If the agent is skipped,
|
|
96
|
+
* it returns { success: false } but allows user to generate a prompt.
|
|
97
|
+
* @typedef {Object} AgentIntent
|
|
98
|
+
* @property {'agent'} type
|
|
99
|
+
* @property {string} task - The instructional task for the AI agent.
|
|
100
|
+
* @property {AgentContext} context - Contextual data, files, and instructions for the task.
|
|
101
|
+
* @property {() => string} toPrompt - Helper to format task and context as an LLM prompt.
|
|
102
|
+
*/
|
|
103
|
+
|
|
70
104
|
/**
|
|
71
105
|
* Union of all possible yielded intents.
|
|
72
|
-
* @typedef {AskIntent | ProgressIntent | LogIntent | RenderIntent
|
|
106
|
+
* @typedef {(AskIntent | ProgressIntent | LogIntent | ShowIntent | RenderIntent | AgentIntent | ResultIntent) & {
|
|
107
|
+
* $value?: any;
|
|
108
|
+
* $success?: boolean;
|
|
109
|
+
* $files?: Record<string, string>;
|
|
110
|
+
* $message?: string;
|
|
111
|
+
* }} Intent
|
|
73
112
|
*/
|
|
74
113
|
|
|
75
114
|
// ─── Response Types (Adapter → Model) ───
|
|
@@ -82,6 +121,21 @@ import { IntentErrorModel } from './IntentErrorModel.js'
|
|
|
82
121
|
* @property {boolean} [cancelled] - Whether the user cancelled this interaction (e.g. pressed ESC).
|
|
83
122
|
*/
|
|
84
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Response to an AgentIntent.
|
|
126
|
+
* The underlying Adapter (Orchestrator) is responsible for communicating with the LLM,
|
|
127
|
+
* enforcing output formats (e.g. Unified Diff or Tool Calls like `updateFile`),
|
|
128
|
+
* and resolving common LLM hallucinations (like Grok truncating code with `// ...`).
|
|
129
|
+
*
|
|
130
|
+
* The Model (e.g. IconsAuditor) receives this clean, resolved response and does not
|
|
131
|
+
* need to parse Markdown or interpret diffs itself.
|
|
132
|
+
*
|
|
133
|
+
* @typedef {Object} AgentResponse
|
|
134
|
+
* @property {boolean} success - True if the agent successfully processed the task.
|
|
135
|
+
* @property {Record<string, string>} [files] - Hash map of fully resolved, updated file contents.
|
|
136
|
+
* @property {string} [message] - Optional summary or explanation returned by the AI.
|
|
137
|
+
*/
|
|
138
|
+
|
|
85
139
|
// ─── Abort Support ───
|
|
86
140
|
|
|
87
141
|
/**
|
|
@@ -101,10 +155,14 @@ import { IntentErrorModel } from './IntentErrorModel.js'
|
|
|
101
155
|
|
|
102
156
|
/**
|
|
103
157
|
* Union of all possible responses an Adapter can send back via iterator.next().
|
|
104
|
-
* @typedef {AskResponse | AbortResponse | undefined} IntentResponse
|
|
158
|
+
* @typedef {AskResponse | AgentResponse | AbortResponse | undefined} IntentResponse
|
|
159
|
+
*/
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @typedef {'ask' | 'show' | 'progress' | 'render' | 'agent'} IntentType
|
|
105
163
|
*/
|
|
106
164
|
|
|
107
|
-
export const INTENT_TYPES = /** @type {const} */ (['ask', 'progress', 'log', 'render'])
|
|
165
|
+
export const INTENT_TYPES = /** @type {const} */ (['ask', 'progress', 'show', 'log', 'render', 'agent'])
|
|
108
166
|
|
|
109
167
|
/**
|
|
110
168
|
* Detects if a value is a Model-as-Schema class (has static fields with `help`).
|
|
@@ -113,7 +171,7 @@ export const INTENT_TYPES = /** @type {const} */ (['ask', 'progress', 'log', 're
|
|
|
113
171
|
*/
|
|
114
172
|
export function isModelSchema(schema) {
|
|
115
173
|
if (typeof schema !== 'function') return false
|
|
116
|
-
return Object.
|
|
174
|
+
return Object.getOwnPropertyNames(schema).some((key) => {
|
|
117
175
|
const meta = schema[key]
|
|
118
176
|
return meta && typeof meta === 'object' && 'help' in meta
|
|
119
177
|
})
|
|
@@ -142,13 +200,16 @@ export function validateIntent(intent) {
|
|
|
142
200
|
}
|
|
143
201
|
// Accept both: plain schema {help: '...'} and Model-as-Schema class/instance
|
|
144
202
|
const isModel = !!intent.model
|
|
145
|
-
if (
|
|
203
|
+
if (
|
|
204
|
+
!isModel &&
|
|
205
|
+
(!intent.schema || typeof intent.schema !== 'object' || !('help' in intent.schema))
|
|
206
|
+
) {
|
|
146
207
|
throw IntentErrorModel.error('ask_missing_schema_help')
|
|
147
208
|
}
|
|
148
209
|
}
|
|
149
|
-
if (intent.type === 'progress' || intent.type === 'log') {
|
|
150
|
-
const
|
|
151
|
-
if (!
|
|
210
|
+
if (intent.type === 'progress' || intent.type === 'show' || intent.type === 'log') {
|
|
211
|
+
const isComponentShow = (intent.type === 'show' || intent.type === 'log') && intent.component
|
|
212
|
+
if (!isComponentShow && typeof intent.message !== 'string') {
|
|
152
213
|
throw IntentErrorModel.error('intent_missing_message', { type: intent.type })
|
|
153
214
|
}
|
|
154
215
|
}
|
|
@@ -157,6 +218,11 @@ export function validateIntent(intent) {
|
|
|
157
218
|
throw IntentErrorModel.error('render_missing_component')
|
|
158
219
|
}
|
|
159
220
|
}
|
|
221
|
+
if (intent.type === 'agent') {
|
|
222
|
+
if (typeof intent.task !== 'string' || !intent.task) {
|
|
223
|
+
throw IntentErrorModel.error('agent_missing_task')
|
|
224
|
+
}
|
|
225
|
+
}
|
|
160
226
|
return true
|
|
161
227
|
}
|
|
162
228
|
|
|
@@ -171,14 +237,131 @@ export function validateIntent(intent) {
|
|
|
171
237
|
* @param {object | Function} schema - Field descriptor or Model-as-Schema class.
|
|
172
238
|
* @returns {AskIntent}
|
|
173
239
|
*/
|
|
174
|
-
export
|
|
240
|
+
export function ask(field, schema) {
|
|
175
241
|
if (isModelSchema(schema)) {
|
|
176
242
|
return { type: 'ask', field, schema, model: true }
|
|
177
243
|
}
|
|
178
244
|
return { type: 'ask', field, schema }
|
|
179
245
|
}
|
|
180
246
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Create a progress intent.
|
|
249
|
+
* @param {string} message - Status message from Model (i18n static field value).
|
|
250
|
+
* @param {number} [value=0] - Progress value (current step or percentage).
|
|
251
|
+
* @param {number|string} [totalOrId] - Absolute total steps (number) OR progress tracking ID (string).
|
|
252
|
+
* @param {string} [id='default'] - Progress ID (if total is provided).
|
|
253
|
+
* @returns {ProgressIntent}
|
|
254
|
+
*/
|
|
255
|
+
export function progress(message, value = 0, totalOrId, id) {
|
|
256
|
+
let total = undefined
|
|
257
|
+
let progressId = 'default'
|
|
258
|
+
|
|
259
|
+
if (typeof totalOrId === 'number') {
|
|
260
|
+
total = totalOrId
|
|
261
|
+
if (typeof id === 'string') progressId = id
|
|
262
|
+
} else if (typeof totalOrId === 'string') {
|
|
263
|
+
progressId = totalOrId
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return { type: 'progress', message, value, total, id: progressId }
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function log(level, message, data = {}) {
|
|
270
|
+
return { type: 'log', level, message, ...data }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Create a render intent.
|
|
275
|
+
* @param {string} component - Component name (e.g. 'App.Layout.Header').
|
|
276
|
+
* @param {object} [props] - Static props for the component.
|
|
277
|
+
* @returns {RenderIntent}
|
|
278
|
+
*/
|
|
279
|
+
export function render(component, props = {}) {
|
|
280
|
+
return { type: 'render', component, props }
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Create a result intent.
|
|
285
|
+
* @param {*} data - The raw result data.
|
|
286
|
+
* @returns {ResultIntent}
|
|
287
|
+
*/
|
|
288
|
+
export function result(data) {
|
|
289
|
+
return { type: 'result', data }
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @typedef {Object} ShowData
|
|
294
|
+
* @property {any} [component]
|
|
295
|
+
* @property {import('@nan0web/types').Model} [model]
|
|
296
|
+
*/
|
|
297
|
+
/**
|
|
298
|
+
* Create a show intent.
|
|
299
|
+
* @param {string | any} message Message to display.
|
|
300
|
+
* @param {ShowLevel|ShowData} [level='info'] Level of message or additional data then `level = 'info'`.
|
|
301
|
+
* @param {ShowData} [data={}] Additional data to display.
|
|
302
|
+
* @returns {ShowIntent}
|
|
303
|
+
*/
|
|
304
|
+
export function show(message, level = 'info', data = {}) {
|
|
305
|
+
if ('string' === typeof level) {
|
|
306
|
+
return { type: 'show', level, message, ...data }
|
|
307
|
+
}
|
|
308
|
+
return { type: 'show', level: 'info', message, ...level, ...data }
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Create an agent intent to delegate a task to an AI subagent.
|
|
313
|
+
* @param {string} task - The instructional task for the AI agent.
|
|
314
|
+
* @param {AgentContext} [context={}] - Contextual data (files, errors, docs).
|
|
315
|
+
* @returns {AgentIntent}
|
|
316
|
+
*/
|
|
317
|
+
export function agent(task, context = {}) {
|
|
318
|
+
return {
|
|
319
|
+
type: 'agent',
|
|
320
|
+
task,
|
|
321
|
+
context,
|
|
322
|
+
toPrompt() {
|
|
323
|
+
let ctxStr = ''
|
|
324
|
+
if (this.context.data) {
|
|
325
|
+
try {
|
|
326
|
+
ctxStr = JSON.stringify(this.context.data, null, 2)
|
|
327
|
+
} catch (e) {
|
|
328
|
+
ctxStr = String(this.context.data)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Format input files for the LLM using the boundary concept
|
|
333
|
+
const filesStr = Object.entries(this.context.files || {})
|
|
334
|
+
.map(([path, content]) => `---boundary:${path}---\n${content}\n---boundary---`)
|
|
335
|
+
.join('\n\n')
|
|
336
|
+
|
|
337
|
+
const outputRules = `
|
|
338
|
+
[Output Format Rules]
|
|
339
|
+
You must return your code modifications using the following strictly parsable boundary format. Do NOT use markdown code blocks (\`\`\`) or JSON for your code outputs.
|
|
340
|
+
|
|
341
|
+
To replace an ENTIRE file:
|
|
342
|
+
---boundary:path/to/file.js---
|
|
343
|
+
<full new file content here>
|
|
344
|
+
---boundary---
|
|
345
|
+
|
|
346
|
+
To replace a SPECIFIC SNIPPET (e.g. replacing 3 lines starting at line 33):
|
|
347
|
+
---boundary:path/to/file.js:33:3---
|
|
348
|
+
<new snippet content here>
|
|
349
|
+
---boundary---
|
|
350
|
+
`
|
|
351
|
+
const inst = Array.isArray(this.context.instructions)
|
|
352
|
+
? this.context.instructions.join('\n')
|
|
353
|
+
: this.context.instructions
|
|
354
|
+
|
|
355
|
+
return [
|
|
356
|
+
`[Subagent Task]`,
|
|
357
|
+
this.task,
|
|
358
|
+
inst ? `\n[Instructions]\n${inst}` : '',
|
|
359
|
+
ctxStr ? `\n[Context]\n${ctxStr}` : '',
|
|
360
|
+
filesStr ? `\n[Files]\n${filesStr}` : '',
|
|
361
|
+
outputRules,
|
|
362
|
+
]
|
|
363
|
+
.filter(Boolean)
|
|
364
|
+
.join('\n')
|
|
365
|
+
},
|
|
366
|
+
}
|
|
367
|
+
}
|
|
@@ -43,11 +43,6 @@ export default class UiMessage extends Message {
|
|
|
43
43
|
NAVIGATION: 'navigation',
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/** @type {string} */
|
|
47
|
-
type = ''
|
|
48
|
-
/** @type {string} */
|
|
49
|
-
id = ''
|
|
50
|
-
|
|
51
46
|
/**
|
|
52
47
|
* Creates a UiMessage.
|
|
53
48
|
*
|
|
@@ -56,9 +51,11 @@ export default class UiMessage extends Message {
|
|
|
56
51
|
constructor(input = {}) {
|
|
57
52
|
super(input)
|
|
58
53
|
|
|
59
|
-
const { type
|
|
54
|
+
const { type, id } = input
|
|
55
|
+
/** @type {string} */
|
|
60
56
|
this.id = id || `ui-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
61
|
-
|
|
57
|
+
/** @type {string} */
|
|
58
|
+
this.type = type ? String(type) : ''
|
|
62
59
|
|
|
63
60
|
if (!('body' in input) && 'content' in input) {
|
|
64
61
|
this.body = Array.isArray(input.content) ? input.content : [input.content]
|
|
@@ -14,15 +14,6 @@ export default class OutputMessage extends UiMessage {
|
|
|
14
14
|
CRITICAL: 3,
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/** @type {string[]} */
|
|
18
|
-
body
|
|
19
|
-
/** @type {Object} */
|
|
20
|
-
meta = {}
|
|
21
|
-
/** @type {Error|null} */
|
|
22
|
-
error = null
|
|
23
|
-
/** @type {number} */
|
|
24
|
-
priority = OutputMessage.PRIORITY.NORMAL
|
|
25
|
-
|
|
26
17
|
/**
|
|
27
18
|
* Creates an OutputMessage.
|
|
28
19
|
*
|
|
@@ -41,14 +32,18 @@ export default class OutputMessage extends UiMessage {
|
|
|
41
32
|
|
|
42
33
|
const contentSource = 'body' in input ? body : 'content' in input ? content : []
|
|
43
34
|
|
|
35
|
+
/** @type {string[]} */
|
|
44
36
|
this.body = Array.isArray(contentSource)
|
|
45
37
|
? contentSource
|
|
46
38
|
: contentSource
|
|
47
39
|
? [String(contentSource)]
|
|
48
40
|
: []
|
|
49
41
|
|
|
42
|
+
/** @type {Object} */
|
|
50
43
|
this.meta = meta
|
|
44
|
+
/** @type {Error|null} */
|
|
51
45
|
this.error = error instanceof Error ? error : error ? new Error(String(error)) : null
|
|
46
|
+
/** @type {number} */
|
|
52
47
|
this.priority = Number(priority)
|
|
53
48
|
|
|
54
49
|
if (!this.type && this.error) {
|
package/src/core/StreamEntry.js
CHANGED
|
@@ -2,30 +2,6 @@
|
|
|
2
2
|
* Represents an entry in a stream with value, completion status, cancellation status, and error message.
|
|
3
3
|
*/
|
|
4
4
|
export default class StreamEntry {
|
|
5
|
-
/**
|
|
6
|
-
* The value of the stream entry.
|
|
7
|
-
* @type {any}
|
|
8
|
-
*/
|
|
9
|
-
value = undefined
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Indicates if the stream entry is done (completed).
|
|
13
|
-
* @type {boolean}
|
|
14
|
-
*/
|
|
15
|
-
done = false
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Indicates if the stream entry has been cancelled.
|
|
19
|
-
* @type {boolean}
|
|
20
|
-
*/
|
|
21
|
-
cancelled = false
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Error message associated with the stream entry.
|
|
25
|
-
* @type {string}
|
|
26
|
-
*/
|
|
27
|
-
error = ''
|
|
28
|
-
|
|
29
5
|
/**
|
|
30
6
|
* Creates a new StreamEntry instance.
|
|
31
7
|
* @param {Object} [input={}] - Input object to initialize the stream entry.
|
|
@@ -36,14 +12,30 @@ export default class StreamEntry {
|
|
|
36
12
|
*/
|
|
37
13
|
constructor(input = {}) {
|
|
38
14
|
const {
|
|
39
|
-
value =
|
|
40
|
-
done =
|
|
41
|
-
cancelled =
|
|
42
|
-
error =
|
|
15
|
+
value = undefined,
|
|
16
|
+
done = false,
|
|
17
|
+
cancelled = false,
|
|
18
|
+
error = '',
|
|
43
19
|
} = input
|
|
20
|
+
/**
|
|
21
|
+
* The value of the stream entry.
|
|
22
|
+
* @type {any}
|
|
23
|
+
*/
|
|
44
24
|
this.value = value
|
|
25
|
+
/**
|
|
26
|
+
* Indicates if the stream entry is done (completed).
|
|
27
|
+
* @type {boolean}
|
|
28
|
+
*/
|
|
45
29
|
this.done = Boolean(done)
|
|
30
|
+
/**
|
|
31
|
+
* Indicates if the stream entry has been cancelled.
|
|
32
|
+
* @type {boolean}
|
|
33
|
+
*/
|
|
46
34
|
this.cancelled = Boolean(cancelled)
|
|
35
|
+
/**
|
|
36
|
+
* Error message associated with the stream entry.
|
|
37
|
+
* @type {string}
|
|
38
|
+
*/
|
|
47
39
|
this.error = String(error)
|
|
48
40
|
}
|
|
49
41
|
|
package/src/core/index.js
CHANGED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} HTML5Elements
|
|
5
|
+
* @property {string|ContentData[]} [a]
|
|
6
|
+
* @property {string|ContentData[]} [abbr]
|
|
7
|
+
* @property {string|ContentData[]} [address]
|
|
8
|
+
* @property {string|ContentData[]} [area]
|
|
9
|
+
* @property {string|ContentData[]} [article]
|
|
10
|
+
* @property {string|ContentData[]} [aside]
|
|
11
|
+
* @property {string|ContentData[]} [audio]
|
|
12
|
+
* @property {string|ContentData[]} [b]
|
|
13
|
+
* @property {string|ContentData[]} [base]
|
|
14
|
+
* @property {string|ContentData[]} [bdi]
|
|
15
|
+
* @property {string|ContentData[]} [bdo]
|
|
16
|
+
* @property {string|ContentData[]} [blockquote]
|
|
17
|
+
* @property {string|ContentData[]} [body]
|
|
18
|
+
* @property {boolean|object} [br]
|
|
19
|
+
* @property {string|ContentData[]} [canvas]
|
|
20
|
+
* @property {string|ContentData[]} [caption]
|
|
21
|
+
* @property {string|ContentData[]} [cite]
|
|
22
|
+
* @property {string|ContentData[]} [code]
|
|
23
|
+
* @property {string|ContentData[]} [col]
|
|
24
|
+
* @property {string|ContentData[]} [colgroup]
|
|
25
|
+
* @property {string|ContentData[]} [data]
|
|
26
|
+
* @property {string|ContentData[]} [datalist]
|
|
27
|
+
* @property {string|ContentData[]} [dd]
|
|
28
|
+
* @property {string|ContentData[]} [del]
|
|
29
|
+
* @property {string|ContentData[]} [details]
|
|
30
|
+
* @property {string|ContentData[]} [dfn]
|
|
31
|
+
* @property {string|ContentData[]} [dialog]
|
|
32
|
+
* @property {string|ContentData[]} [div]
|
|
33
|
+
* @property {string|ContentData[]} [dl]
|
|
34
|
+
* @property {string|ContentData[]} [dt]
|
|
35
|
+
* @property {string|ContentData[]} [em]
|
|
36
|
+
* @property {string|ContentData[]} [embed]
|
|
37
|
+
* @property {string|ContentData[]} [fieldset]
|
|
38
|
+
* @property {string|ContentData[]} [figcaption]
|
|
39
|
+
* @property {string|ContentData[]} [figure]
|
|
40
|
+
* @property {string|ContentData[]} [footer]
|
|
41
|
+
* @property {string|ContentData[]} [form]
|
|
42
|
+
* @property {string|ContentData[]} [h1]
|
|
43
|
+
* @property {string|ContentData[]} [h2]
|
|
44
|
+
* @property {string|ContentData[]} [h3]
|
|
45
|
+
* @property {string|ContentData[]} [h4]
|
|
46
|
+
* @property {string|ContentData[]} [h5]
|
|
47
|
+
* @property {string|ContentData[]} [h6]
|
|
48
|
+
* @property {string|ContentData[]} [head]
|
|
49
|
+
* @property {string|ContentData[]} [header]
|
|
50
|
+
* @property {string|ContentData[]} [hgroup]
|
|
51
|
+
* @property {boolean|object} [hr]
|
|
52
|
+
* @property {string|ContentData[]} [html]
|
|
53
|
+
* @property {string|ContentData[]} [i]
|
|
54
|
+
* @property {string|ContentData[]} [iframe]
|
|
55
|
+
* @property {string|ContentData[]} [img]
|
|
56
|
+
* @property {string|ContentData[]} [ins]
|
|
57
|
+
* @property {string|ContentData[]} [kbd]
|
|
58
|
+
* @property {string|ContentData[]} [label]
|
|
59
|
+
* @property {string|ContentData[]} [legend]
|
|
60
|
+
* @property {string|ContentData[]} [li]
|
|
61
|
+
* @property {string|ContentData[]} [link]
|
|
62
|
+
* @property {string|ContentData[]} [main]
|
|
63
|
+
* @property {string|ContentData[]} [map]
|
|
64
|
+
* @property {string|ContentData[]} [mark]
|
|
65
|
+
* @property {string|ContentData[]} [meta]
|
|
66
|
+
* @property {string|ContentData[]} [meter]
|
|
67
|
+
* @property {boolean|any} [input]
|
|
68
|
+
* @property {boolean|any} [button]
|
|
69
|
+
* @property {boolean|any} [select]
|
|
70
|
+
* @property {string|ContentData[]} [nav]
|
|
71
|
+
* @property {string|ContentData[]} [noscript]
|
|
72
|
+
* @property {string|ContentData[]} [object]
|
|
73
|
+
* @property {string|ContentData[]} [ol]
|
|
74
|
+
* @property {string|ContentData[]} [optgroup]
|
|
75
|
+
* @property {string|ContentData[]} [option]
|
|
76
|
+
* @property {string|ContentData[]} [output]
|
|
77
|
+
* @property {string|ContentData[]} [p]
|
|
78
|
+
* @property {string|ContentData[]} [picture]
|
|
79
|
+
* @property {string|ContentData[]} [pre]
|
|
80
|
+
* @property {string|ContentData[]} [progress]
|
|
81
|
+
* @property {string|ContentData[]} [q]
|
|
82
|
+
* @property {string|ContentData[]} [rp]
|
|
83
|
+
* @property {string|ContentData[]} [rt]
|
|
84
|
+
* @property {string|ContentData[]} [ruby]
|
|
85
|
+
* @property {string|ContentData[]} [s]
|
|
86
|
+
* @property {string|ContentData[]} [samp]
|
|
87
|
+
* @property {string|ContentData[]} [script]
|
|
88
|
+
* @property {string|ContentData[]} [section]
|
|
89
|
+
* @property {string|ContentData[]} [slot]
|
|
90
|
+
* @property {string|ContentData[]} [small]
|
|
91
|
+
* @property {string|ContentData[]} [source]
|
|
92
|
+
* @property {string|ContentData[]} [span]
|
|
93
|
+
* @property {string|ContentData[]} [strong]
|
|
94
|
+
* @property {string|ContentData[]} [style]
|
|
95
|
+
* @property {string|ContentData[]} [sub]
|
|
96
|
+
* @property {string|ContentData[]} [summary]
|
|
97
|
+
* @property {string|ContentData[]} [sup]
|
|
98
|
+
* @property {string|ContentData[]} [table]
|
|
99
|
+
* @property {string|ContentData[]} [tbody]
|
|
100
|
+
* @property {string|ContentData[]} [td]
|
|
101
|
+
* @property {string|ContentData[]} [template]
|
|
102
|
+
* @property {string|ContentData[]} [textarea]
|
|
103
|
+
* @property {string|ContentData[]} [tfoot]
|
|
104
|
+
* @property {string|ContentData[]} [th]
|
|
105
|
+
* @property {string|ContentData[]} [thead]
|
|
106
|
+
* @property {string|ContentData[]} [time]
|
|
107
|
+
* @property {string|ContentData[]} [title]
|
|
108
|
+
* @property {string|ContentData[]} [tr]
|
|
109
|
+
* @property {string|ContentData[]} [track]
|
|
110
|
+
* @property {string|ContentData[]} [u]
|
|
111
|
+
* @property {string|ContentData[]} [ul]
|
|
112
|
+
* @property {string|ContentData[]} [var]
|
|
113
|
+
* @property {string|ContentData[]} [video]
|
|
114
|
+
* @property {string|ContentData[]} [wbr]
|
|
115
|
+
* @property {string|ContentData[]} [svg]
|
|
116
|
+
* @property {string|ContentData[]} [path]
|
|
117
|
+
* @property {string|ContentData[]} [circle]
|
|
118
|
+
* @property {string|ContentData[]} [rect]
|
|
119
|
+
* @property {string|ContentData[]} [line]
|
|
120
|
+
* @property {string|ContentData[]} [polyline]
|
|
121
|
+
* @property {string|ContentData[]} [polygon]
|
|
122
|
+
* @property {string|ContentData[]} [g]
|
|
123
|
+
* @property {string|ContentData[]} [defs]
|
|
124
|
+
* @property {string|ContentData[]} [symbol]
|
|
125
|
+
* @property {string|ContentData[]} [use]
|
|
126
|
+
* @property {string|ContentData[]} [text]
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @typedef {Object} CoreUIElements
|
|
131
|
+
* @property {import('./components/AccordionModel.js').AccordionModel} [accordion]
|
|
132
|
+
* @property {import('./components/AutocompleteModel.js').AutocompleteModel} [autocomplete]
|
|
133
|
+
* @property {import('./components/BannerModel.js').BannerModel} [banner]
|
|
134
|
+
* @property {import('./components/BreadcrumbModel.js').BreadcrumbModel} [breadcrumb]
|
|
135
|
+
* @property {import('./components/ButtonModel.js').ButtonModel} [button]
|
|
136
|
+
* @property {import('./components/CommentModel.js').CommentModel} [comment]
|
|
137
|
+
* @property {import('./components/ConfirmModel.js').ConfirmModel} [confirm]
|
|
138
|
+
* @property {import('./components/EmptyStateModel.js').EmptyStateModel} [emptyState]
|
|
139
|
+
* @property {import('./components/FAQModel.js').FAQModel} [faq]
|
|
140
|
+
* @property {import('./components/FeatureGridModel.js').FeatureGridModel} [featureGrid]
|
|
141
|
+
* @property {import('./components/GalleryModel.js').GalleryModel} [gallery]
|
|
142
|
+
* @property {import('./components/InputModel.js').InputModel} [input]
|
|
143
|
+
* @property {import('./components/MarkdownModel.js').MarkdownModel} [markdown]
|
|
144
|
+
* @property {import('./components/PriceModel.js').PriceModel} [price]
|
|
145
|
+
* @property {import('./components/PricingModel.js').PricingModel} [pricing]
|
|
146
|
+
* @property {import('./components/PricingSectionModel.js').PricingSectionModel} [pricingSection]
|
|
147
|
+
* @property {import('./components/ProfileDropdownModel.js').ProfileDropdownModel} [profileDropdown]
|
|
148
|
+
* @property {import('./components/SelectModel.js').SelectModel} [select]
|
|
149
|
+
* @property {import('./components/ShellModel.js').ShellModel} [shell]
|
|
150
|
+
* @property {import('./components/SpinnerModel.js').SpinnerModel} [spinner]
|
|
151
|
+
* @property {import('./components/StatsItemModel.js').StatsItemModel} [statsItem]
|
|
152
|
+
* @property {import('./components/StatsModel.js').StatsModel} [stats]
|
|
153
|
+
* @property {import('./components/TableModel.js').TableModel} [tableUI]
|
|
154
|
+
* @property {import('./components/TabsModel.js').TabsModel} [tabs]
|
|
155
|
+
* @property {import('./components/TestimonialModel.js').TestimonialModel} [testimonial]
|
|
156
|
+
* @property {import('./components/TimelineItemModel.js').TimelineItemModel} [timelineItem]
|
|
157
|
+
* @property {import('./components/TimelineModel.js').TimelineModel} [timeline]
|
|
158
|
+
* @property {import('./components/ToastModel.js').ToastModel} [toast]
|
|
159
|
+
* @property {import('./components/TreeModel.js').TreeModel} [tree]
|
|
160
|
+
* @property {ContentData[]} [sortable] - Інтерактивний Drag-n-Drop контейнер
|
|
161
|
+
*/
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @typedef {Partial<Content & HTML5Elements & CoreUIElements> & Record<string, any>} ContentData
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
export class Content extends Model {
|
|
168
|
+
static content = { type: 'string', help: 'Content' }
|
|
169
|
+
static children = { type: 'array', model: Content, help: 'Children' }
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @param {ContentData | string} [data={}]
|
|
173
|
+
* @param {import('@nan0web/types').ModelOptions} [options={}]
|
|
174
|
+
*/
|
|
175
|
+
constructor(data = {}, options = {}) {
|
|
176
|
+
if ('string' === typeof data) {
|
|
177
|
+
data = { content: data }
|
|
178
|
+
}
|
|
179
|
+
super(data, options)
|
|
180
|
+
|
|
181
|
+
// ── Base Fields ──
|
|
182
|
+
/** @type {string|undefined} Content */ this.content
|
|
183
|
+
/** @type {Array<Content>|undefined} Children */ this.children
|
|
184
|
+
|
|
185
|
+
// ── Hydration ──
|
|
186
|
+
if (Array.isArray(this.children)) {
|
|
187
|
+
this.children = this.children.map((child) => new Content(child, options))
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const { content, children, ...rest } = /** @type {any} */ (data)
|
|
191
|
+
|
|
192
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
193
|
+
/** @type {any} */ (this)[key] = value
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import { Content } from './Content.js'
|
|
3
|
+
|
|
4
|
+
export class Document extends Model {
|
|
5
|
+
static title = { type: 'string', help: 'Title' }
|
|
6
|
+
static content = { type: 'array', model: Content, help: 'Content' }
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param {Partial<Document>} [data]
|
|
10
|
+
* @param {import('@nan0web/types').ModelOptions} [options]
|
|
11
|
+
*/
|
|
12
|
+
constructor(data = {}, options = {}) {
|
|
13
|
+
super(data, options)
|
|
14
|
+
/** @type {string} Title */ this.title
|
|
15
|
+
/** @type {Array<Content>} Content */ this.content
|
|
16
|
+
}
|
|
17
|
+
}
|