@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.
- package/README.md +36 -1
- package/package.json +89 -84
- package/src/ArchitectureMap/ArchitectureMap.js +111 -0
- package/src/ArchitectureMap/index.js +1 -0
- package/src/InterfaceTemplate/InterfaceTemplate.js +95 -0
- package/src/InterfaceTemplate/index.js +1 -0
- package/src/README.md.js +42 -1
- package/src/core/GeneratorRunner.js +213 -0
- package/src/core/Intent.js +168 -0
- package/src/core/IntentErrorModel.js +94 -0
- package/src/core/MaskHandler.js +125 -0
- package/src/core/index.js +7 -0
- package/src/domain/SandboxModel.js +193 -0
- package/src/domain/ShowcaseAppModel.js +88 -0
- package/src/domain/components/AutocompleteModel.js +58 -0
- package/src/domain/components/BreadcrumbModel.js +265 -0
- package/src/domain/components/ButtonModel.js +92 -0
- package/src/domain/components/ConfirmModel.js +64 -0
- package/src/domain/components/InputModel.js +142 -0
- package/src/domain/components/SelectModel.js +59 -0
- package/src/domain/components/SpinnerModel.js +58 -0
- package/src/domain/components/TableModel.js +60 -0
- package/src/domain/components/ToastModel.js +77 -0
- package/src/domain/components/TreeModel.js +53 -0
- package/src/domain/components/index.js +11 -0
- package/src/domain/index.js +16 -0
- package/src/format.js +21 -0
- package/src/index.js +6 -0
- package/types/ArchitectureMap/ArchitectureMap.d.ts +70 -0
- package/types/ArchitectureMap/index.d.ts +1 -0
- package/types/InterfaceTemplate/InterfaceTemplate.d.ts +67 -0
- package/types/InterfaceTemplate/index.d.ts +1 -0
- package/types/core/GeneratorRunner.d.ts +51 -0
- package/types/core/Intent.d.ts +227 -85
- package/types/core/IntentErrorModel.d.ts +55 -0
- package/types/core/MaskHandler.d.ts +33 -0
- package/types/core/index.d.ts +4 -0
- package/types/domain/SandboxModel.d.ts +59 -0
- package/types/domain/ShowcaseAppModel.d.ts +62 -0
- package/types/domain/components/AutocompleteModel.d.ts +47 -0
- package/types/domain/components/BreadcrumbModel.d.ts +164 -0
- package/types/domain/components/ButtonModel.d.ts +81 -0
- package/types/domain/components/ConfirmModel.d.ts +54 -0
- package/types/domain/components/InputModel.d.ts +121 -0
- package/types/domain/components/SelectModel.d.ts +48 -0
- package/types/domain/components/SpinnerModel.d.ts +45 -0
- package/types/domain/components/TableModel.d.ts +44 -0
- package/types/domain/components/ToastModel.d.ts +62 -0
- package/types/domain/components/TreeModel.d.ts +49 -0
- package/types/domain/components/index.d.ts +10 -0
- package/types/domain/index.d.ts +3 -0
- package/types/format.d.ts +5 -0
- package/types/index.d.ts +4 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Model } from '@nan0web/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} ConfirmData
|
|
5
|
+
* @property {string} [message]
|
|
6
|
+
* @property {string} [confirmText]
|
|
7
|
+
* @property {string} [cancelText]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Model-as-Schema for Confirm component.
|
|
12
|
+
*/
|
|
13
|
+
export class ConfirmModel extends Model {
|
|
14
|
+
// ==========================================
|
|
15
|
+
// 1. MODEL AS SCHEMA (Static Definition)
|
|
16
|
+
// ==========================================
|
|
17
|
+
|
|
18
|
+
static message = {
|
|
19
|
+
help: 'Dialog message displayed to the user',
|
|
20
|
+
default: 'Are you sure?',
|
|
21
|
+
type: 'string',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static confirmText = {
|
|
25
|
+
help: 'Label for the positive confirmation button',
|
|
26
|
+
default: 'Yes',
|
|
27
|
+
type: 'string',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static cancelText = {
|
|
31
|
+
help: 'Label for the negative rejection button',
|
|
32
|
+
default: 'No',
|
|
33
|
+
type: 'string',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {ConfirmData | any} [data]
|
|
38
|
+
*/
|
|
39
|
+
constructor(data = {}) {
|
|
40
|
+
super(data)
|
|
41
|
+
/** @type {string|undefined} */ this.message
|
|
42
|
+
/** @type {string|undefined} */ this.confirmText
|
|
43
|
+
/** @type {string|undefined} */ this.cancelText
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ==========================================
|
|
47
|
+
// 2. AGNOSTIC LOGIC (Async Generator)
|
|
48
|
+
// ==========================================
|
|
49
|
+
|
|
50
|
+
async *run() {
|
|
51
|
+
const response = yield {
|
|
52
|
+
type: 'ask',
|
|
53
|
+
field: 'confirmed',
|
|
54
|
+
schema: {
|
|
55
|
+
help: this.message,
|
|
56
|
+
type: 'boolean',
|
|
57
|
+
},
|
|
58
|
+
component: 'Confirm',
|
|
59
|
+
model: /** @type {any} */ (this), // Attached for richer UI metadata
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { type: 'result', data: { confirmed: !!response.value } }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Model } from '@nan0web/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {'text'|'email'|'password'|'number'|'tel'|'url'|'date'} InputType
|
|
5
|
+
* @typedef {Object} InputData
|
|
6
|
+
* @property {InputType} [type]
|
|
7
|
+
* @property {string} [label]
|
|
8
|
+
* @property {string} [placeholder]
|
|
9
|
+
* @property {boolean} [required]
|
|
10
|
+
* @property {string} [pattern]
|
|
11
|
+
* @property {string} [min]
|
|
12
|
+
* @property {string} [max]
|
|
13
|
+
* @property {string} [step]
|
|
14
|
+
* @property {string} [hint]
|
|
15
|
+
* @property {boolean} [disabled]
|
|
16
|
+
* @property {string} [content]
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Model-as-Schema for Input component.
|
|
21
|
+
* Used exclusively for schema definition, validation, and editor reflection.
|
|
22
|
+
*/
|
|
23
|
+
export class InputModel extends Model {
|
|
24
|
+
// ==========================================
|
|
25
|
+
// 1. MODEL AS SCHEMA (Static Definition)
|
|
26
|
+
// ==========================================
|
|
27
|
+
|
|
28
|
+
static type = {
|
|
29
|
+
help: 'HTML5 Input type attribute',
|
|
30
|
+
default: 'text',
|
|
31
|
+
options: ['text', 'email', 'password', 'number', 'tel', 'url', 'date'],
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static label = {
|
|
35
|
+
help: 'Label displayed above the input',
|
|
36
|
+
default: '',
|
|
37
|
+
type: 'string',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static placeholder = {
|
|
41
|
+
help: 'Placeholder text shown when empty',
|
|
42
|
+
default: '',
|
|
43
|
+
type: 'string',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static required = {
|
|
47
|
+
help: 'Whether the field must be filled out',
|
|
48
|
+
default: false,
|
|
49
|
+
type: 'boolean',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static pattern = {
|
|
53
|
+
help: 'RegExp pattern for validation (e.g. [A-Z]{3})',
|
|
54
|
+
default: '',
|
|
55
|
+
type: 'string',
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static min = {
|
|
59
|
+
help: 'Minimum value (for number/date types)',
|
|
60
|
+
default: '',
|
|
61
|
+
type: 'string',
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static max = {
|
|
65
|
+
help: 'Maximum value (for number/date types)',
|
|
66
|
+
default: '',
|
|
67
|
+
type: 'string',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static step = {
|
|
71
|
+
help: 'Step interval (for number/date types)',
|
|
72
|
+
default: '',
|
|
73
|
+
type: 'string',
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static hint = {
|
|
77
|
+
help: 'Helper text displayed below the input',
|
|
78
|
+
default: '',
|
|
79
|
+
type: 'string',
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static disabled = {
|
|
83
|
+
help: 'Whether the input is greyed out and uneditable',
|
|
84
|
+
default: false,
|
|
85
|
+
type: 'boolean',
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static content = {
|
|
89
|
+
help: 'The actual value of the input',
|
|
90
|
+
default: '',
|
|
91
|
+
type: 'string',
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {InputData | any} [data]
|
|
96
|
+
*/
|
|
97
|
+
constructor(data = {}) {
|
|
98
|
+
super(data)
|
|
99
|
+
/** @type {InputType|undefined} */ this.type
|
|
100
|
+
/** @type {string|undefined} */ this.label
|
|
101
|
+
/** @type {string|undefined} */ this.placeholder
|
|
102
|
+
/** @type {boolean|undefined} */ this.required
|
|
103
|
+
/** @type {string|undefined} */ this.pattern
|
|
104
|
+
/** @type {string|undefined} */ this.min
|
|
105
|
+
/** @type {string|undefined} */ this.max
|
|
106
|
+
/** @type {string|undefined} */ this.step
|
|
107
|
+
/** @type {string|undefined} */ this.hint
|
|
108
|
+
/** @type {boolean|undefined} */ this.disabled
|
|
109
|
+
/** @type {string|undefined} */ this.content
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ==========================================
|
|
113
|
+
// 2. AGNOSTIC LOGIC (Async Generator)
|
|
114
|
+
// ==========================================
|
|
115
|
+
|
|
116
|
+
async *run() {
|
|
117
|
+
const response = yield {
|
|
118
|
+
type: 'ask',
|
|
119
|
+
field: 'content',
|
|
120
|
+
schema: {
|
|
121
|
+
help: this.label || this.placeholder || 'Enter value',
|
|
122
|
+
validate: (val) => {
|
|
123
|
+
if (this.required && !val) return 'This field is required'
|
|
124
|
+
if (this.pattern && val) {
|
|
125
|
+
try {
|
|
126
|
+
const re = new RegExp(`^${this.pattern}$`)
|
|
127
|
+
if (!re.test(val)) return 'Invalid format'
|
|
128
|
+
} catch (e) {
|
|
129
|
+
// fallback if pattern is malformed
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return true
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
component: 'Input',
|
|
136
|
+
model: /** @type {any} */ (this),
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.content = response.value
|
|
140
|
+
return { type: 'result', data: { value: this.content } }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Model } from '@nan0web/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} SelectData
|
|
5
|
+
* @property {string} [content]
|
|
6
|
+
* @property {string[]} [options]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Model-as-Schema for Select component.
|
|
11
|
+
* Represents a dropdown choice selection.
|
|
12
|
+
*/
|
|
13
|
+
export class SelectModel extends Model {
|
|
14
|
+
// ==========================================
|
|
15
|
+
// 1. MODEL AS SCHEMA (Static Definition)
|
|
16
|
+
// ==========================================
|
|
17
|
+
|
|
18
|
+
static content = {
|
|
19
|
+
help: 'Currently selected item or default placeholder',
|
|
20
|
+
default: 'Choose option',
|
|
21
|
+
type: 'string',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static options = {
|
|
25
|
+
help: 'List of available options for selection',
|
|
26
|
+
default: ['Alpha', 'Beta', 'Gamma'],
|
|
27
|
+
type: 'string[]',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {SelectData | any} [data]
|
|
32
|
+
*/
|
|
33
|
+
constructor(data = {}) {
|
|
34
|
+
super(data)
|
|
35
|
+
/** @type {string|undefined} */ this.content
|
|
36
|
+
/** @type {string[]|undefined} */ this.options
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ==========================================
|
|
40
|
+
// 2. AGNOSTIC LOGIC (Async Generator)
|
|
41
|
+
// ==========================================
|
|
42
|
+
|
|
43
|
+
async *run() {
|
|
44
|
+
const response = yield {
|
|
45
|
+
type: 'ask',
|
|
46
|
+
field: 'content',
|
|
47
|
+
schema: {
|
|
48
|
+
help: 'Select an option',
|
|
49
|
+
options: this.options,
|
|
50
|
+
validate: (val) => this.options?.includes(val) || 'Invalid option selected',
|
|
51
|
+
},
|
|
52
|
+
component: 'Select',
|
|
53
|
+
model: /** @type {any} */ (this),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.content = response.value
|
|
57
|
+
return { type: 'result', data: { selected: this.content } }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Model } from '@nan0web/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {'sm'|'md'|'lg'} SpinnerSize
|
|
5
|
+
* @typedef {Object} SpinnerData
|
|
6
|
+
* @property {SpinnerSize} [size]
|
|
7
|
+
* @property {string} [color]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Model-as-Schema for Spinner component.
|
|
12
|
+
* Represents a loading or progress state without user interaction.
|
|
13
|
+
*/
|
|
14
|
+
export class SpinnerModel extends Model {
|
|
15
|
+
// ==========================================
|
|
16
|
+
// 1. MODEL AS SCHEMA (Static Definition)
|
|
17
|
+
// ==========================================
|
|
18
|
+
|
|
19
|
+
static size = {
|
|
20
|
+
help: 'Spinner diameter',
|
|
21
|
+
default: 'md',
|
|
22
|
+
options: ['sm', 'md', 'lg'],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static color = {
|
|
26
|
+
help: 'Override for base color token',
|
|
27
|
+
type: 'color',
|
|
28
|
+
default: '',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {SpinnerData | any} [data]
|
|
33
|
+
*/
|
|
34
|
+
constructor(data = {}) {
|
|
35
|
+
super(data)
|
|
36
|
+
/** @type {SpinnerSize|undefined} */ this.size
|
|
37
|
+
/** @type {string|undefined} */ this.color
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ==========================================
|
|
41
|
+
// 2. AGNOSTIC LOGIC (Async Generator)
|
|
42
|
+
// ==========================================
|
|
43
|
+
|
|
44
|
+
async *run() {
|
|
45
|
+
// A spinner does not ask for anything, it simply indicates progress.
|
|
46
|
+
// However, as a pure component it doesn't do any work itself,
|
|
47
|
+
// so running it just means declaring its state.
|
|
48
|
+
yield {
|
|
49
|
+
type: 'progress',
|
|
50
|
+
message: 'Loading...',
|
|
51
|
+
component: 'Spinner',
|
|
52
|
+
model: /** @type {any} */ (this),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Instant exit since it performs no async task internally
|
|
56
|
+
return { type: 'result', data: { completed: true } }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Model } from '@nan0web/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} TableData
|
|
5
|
+
* @property {string[]} [columns]
|
|
6
|
+
* @property {string[][]} [rows]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Model-as-Schema for Table Data component.
|
|
11
|
+
* Displays tabular string data in rows and columns.
|
|
12
|
+
*/
|
|
13
|
+
export class TableModel extends Model {
|
|
14
|
+
// ==========================================
|
|
15
|
+
// 1. MODEL AS SCHEMA (Static Definition)
|
|
16
|
+
// ==========================================
|
|
17
|
+
|
|
18
|
+
static columns = {
|
|
19
|
+
help: 'Array of column headers',
|
|
20
|
+
type: 'string[]',
|
|
21
|
+
default: ['Header 1', 'Header 2'],
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static rows = {
|
|
25
|
+
help: '2D Array of table cells matching column length',
|
|
26
|
+
type: 'string[][]',
|
|
27
|
+
default: [
|
|
28
|
+
['Cell 1.1', 'Cell 1.2'],
|
|
29
|
+
['Cell 2.1', 'Cell 2.2'],
|
|
30
|
+
],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {TableData | any} [data]
|
|
35
|
+
*/
|
|
36
|
+
constructor(data = {}) {
|
|
37
|
+
super(data)
|
|
38
|
+
/** @type {string[]|undefined} */ this.columns
|
|
39
|
+
/** @type {string[][]|undefined} */ this.rows
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ==========================================
|
|
43
|
+
// 2. AGNOSTIC LOGIC (Async Generator)
|
|
44
|
+
// ==========================================
|
|
45
|
+
|
|
46
|
+
async *run() {
|
|
47
|
+
// Tables are naturally result or log displays.
|
|
48
|
+
// For an interactive flow, we could ask the user to 'select' a row,
|
|
49
|
+
// but by default a table simply presents data.
|
|
50
|
+
yield {
|
|
51
|
+
type: 'log',
|
|
52
|
+
level: 'info',
|
|
53
|
+
message: `Displaying table with ${this.rows?.length || 0} rows`,
|
|
54
|
+
component: 'Table',
|
|
55
|
+
model: /** @type {any} */ (this),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { type: 'result', data: { rowsCount: this.rows?.length || 0 } }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Model } from '@nan0web/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {'success'|'error'|'info'|'warning'} ToastVariant
|
|
5
|
+
* @typedef {Object} ToastData
|
|
6
|
+
* @property {string} [message]
|
|
7
|
+
* @property {ToastVariant} [variant]
|
|
8
|
+
* @property {number} [duration]
|
|
9
|
+
* @property {boolean} [open]
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Model-as-Schema for Toast notification component.
|
|
14
|
+
* Represents a transient message displayed to the user.
|
|
15
|
+
*/
|
|
16
|
+
export class ToastModel extends Model {
|
|
17
|
+
// ==========================================
|
|
18
|
+
// 1. MODEL AS SCHEMA (Static Definition)
|
|
19
|
+
// ==========================================
|
|
20
|
+
|
|
21
|
+
static message = {
|
|
22
|
+
help: 'The message content of the toast',
|
|
23
|
+
default: 'Saved successfully!',
|
|
24
|
+
type: 'string',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static variant = {
|
|
28
|
+
help: 'Visual styling representing the message severity',
|
|
29
|
+
default: 'success',
|
|
30
|
+
options: ['success', 'error', 'info', 'warning'],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static duration = {
|
|
34
|
+
help: 'Time in ms before auto-dismissal. 0 to keep open indefinitely.',
|
|
35
|
+
default: 3000,
|
|
36
|
+
type: 'number',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static open = {
|
|
40
|
+
help: 'Controls visibility state',
|
|
41
|
+
default: true,
|
|
42
|
+
type: 'boolean',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {ToastData | any} [data]
|
|
47
|
+
*/
|
|
48
|
+
constructor(data = {}) {
|
|
49
|
+
super(data)
|
|
50
|
+
/** @type {string|undefined} */ this.message
|
|
51
|
+
/** @type {ToastVariant|undefined} */ this.variant
|
|
52
|
+
/** @type {number|undefined} */ this.duration
|
|
53
|
+
/** @type {boolean|undefined} */ this.open
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ==========================================
|
|
57
|
+
// 2. AGNOSTIC LOGIC (Async Generator)
|
|
58
|
+
// ==========================================
|
|
59
|
+
|
|
60
|
+
async *run() {
|
|
61
|
+
// Maps naturally to the 'log' intent for OLMUI runners.
|
|
62
|
+
yield {
|
|
63
|
+
type: 'log',
|
|
64
|
+
level: this.variant === 'error' ? 'error' : this.variant === 'warning' ? 'warn' : 'info',
|
|
65
|
+
message: this.message,
|
|
66
|
+
component: 'Toast', // Hint for specific UI visual rendering
|
|
67
|
+
model: /** @type {any} */ (this),
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Wait exactly 'duration' ms before completing (unless duration is 0)
|
|
71
|
+
if (this.duration && this.duration > 0) {
|
|
72
|
+
await new Promise((resolve) => setTimeout(resolve, this.duration))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { type: 'result', data: { closed: true } }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Model } from '@nan0web/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} TreeNode
|
|
5
|
+
* @property {string} label
|
|
6
|
+
* @property {boolean} [expanded]
|
|
7
|
+
* @property {TreeNode[]} [children]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} TreeData
|
|
12
|
+
* @property {TreeNode[]} [data]
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Model-as-Schema for Tree component.
|
|
17
|
+
* Represents a hierarchical selection or navigation structure.
|
|
18
|
+
*/
|
|
19
|
+
export class TreeModel extends Model {
|
|
20
|
+
// ==========================================
|
|
21
|
+
// 1. MODEL AS SCHEMA (Static Definition)
|
|
22
|
+
// ==========================================
|
|
23
|
+
|
|
24
|
+
static data = {
|
|
25
|
+
help: 'Tree nodes defining the hierarchy',
|
|
26
|
+
type: 'TreeNode[]',
|
|
27
|
+
default: [],
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {TreeData | any} [data]
|
|
32
|
+
*/
|
|
33
|
+
constructor(data = {}) {
|
|
34
|
+
super(data)
|
|
35
|
+
/** @type {TreeNode[]|undefined} */ this.data
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ==========================================
|
|
39
|
+
// 2. AGNOSTIC LOGIC (Async Generator)
|
|
40
|
+
// ==========================================
|
|
41
|
+
|
|
42
|
+
async *run() {
|
|
43
|
+
const response = yield {
|
|
44
|
+
type: 'ask',
|
|
45
|
+
field: 'selectedNode',
|
|
46
|
+
schema: { help: 'Select a node from the tree' },
|
|
47
|
+
component: 'Tree',
|
|
48
|
+
model: /** @type {any} */ (this),
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { type: 'result', data: { selected: response.value } }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Exports for Component Models
|
|
2
|
+
export { BreadcrumbModel } from './BreadcrumbModel.js'
|
|
3
|
+
export { ButtonModel } from './ButtonModel.js'
|
|
4
|
+
export { ConfirmModel } from './ConfirmModel.js'
|
|
5
|
+
export { InputModel } from './InputModel.js'
|
|
6
|
+
export { SpinnerModel } from './SpinnerModel.js'
|
|
7
|
+
export { TableModel } from './TableModel.js'
|
|
8
|
+
export { ToastModel } from './ToastModel.js'
|
|
9
|
+
export { SelectModel } from './SelectModel.js'
|
|
10
|
+
export { AutocompleteModel } from './AutocompleteModel.js'
|
|
11
|
+
export { TreeModel } from './TreeModel.js'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Domain Models — OLMUI Model-as-Schema
|
|
2
|
+
export { SandboxModel } from './SandboxModel.js'
|
|
3
|
+
export { ShowcaseAppModel } from './ShowcaseAppModel.js'
|
|
4
|
+
|
|
5
|
+
// Component Models
|
|
6
|
+
export {
|
|
7
|
+
ButtonModel,
|
|
8
|
+
ConfirmModel,
|
|
9
|
+
InputModel,
|
|
10
|
+
SpinnerModel,
|
|
11
|
+
TableModel,
|
|
12
|
+
ToastModel,
|
|
13
|
+
SelectModel,
|
|
14
|
+
AutocompleteModel,
|
|
15
|
+
TreeModel,
|
|
16
|
+
} from './components/index.js'
|
package/src/format.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const format = {
|
|
2
|
+
currency: (value, currency = 'UAH', locale = 'uk-UA') => {
|
|
3
|
+
return new Intl.NumberFormat(locale, {
|
|
4
|
+
style: 'currency',
|
|
5
|
+
currency,
|
|
6
|
+
maximumFractionDigits: 0
|
|
7
|
+
}).format(value).replace(/,/g, ' ')
|
|
8
|
+
},
|
|
9
|
+
rate: (value, locale = 'uk-UA') => {
|
|
10
|
+
const rate = value < 1 ? value * 100 : value
|
|
11
|
+
return new Intl.NumberFormat(locale, {
|
|
12
|
+
style: 'percent',
|
|
13
|
+
maximumFractionDigits: 2
|
|
14
|
+
}).format(rate / 100)
|
|
15
|
+
},
|
|
16
|
+
number: (value, locale = 'uk-UA') => {
|
|
17
|
+
return new Intl.NumberFormat(locale, {
|
|
18
|
+
maximumFractionDigits: 2
|
|
19
|
+
}).format(value).replace(/,/g, ' ')
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import Component from './Component/index.js'
|
|
|
10
10
|
import App from './App/index.js'
|
|
11
11
|
|
|
12
12
|
export { Frame, FrameProps, Locale, StdIn, StdOut, View, RenderOptions, Model, Component, App }
|
|
13
|
+
export { format } from './format.js'
|
|
13
14
|
|
|
14
15
|
// export default App
|
|
15
16
|
export { default as FormMessage } from './core/Form/Message.js'
|
|
@@ -22,3 +23,8 @@ export { default as UiMessage } from './core/Message/Message.js'
|
|
|
22
23
|
export { default as UiStream } from './core/Stream.js'
|
|
23
24
|
export { default as Error, CancelError } from './core/Error/index.js'
|
|
24
25
|
export { default as UiAdapter } from './core/UiAdapter.js'
|
|
26
|
+
|
|
27
|
+
// OLMUI Generator Engine
|
|
28
|
+
export { validateIntent, ask, progress, log, result, INTENT_TYPES, isModelSchema } from './core/Intent.js'
|
|
29
|
+
export { IntentErrorModel } from './core/IntentErrorModel.js'
|
|
30
|
+
export { runGenerator } from './core/GeneratorRunner.js'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ArchitectureMap — a cross-package component readiness registry.
|
|
3
|
+
*
|
|
4
|
+
* Tracks which UI components are implemented in which packages
|
|
5
|
+
* (ui-lit, ui-cli, ui-react-bootstrap, etc.) and provides
|
|
6
|
+
* a programmatic readiness matrix.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* const map = new ArchitectureMap()
|
|
10
|
+
* map.register('ui-lit', ['Button', 'Input', 'Select'])
|
|
11
|
+
* map.register('ui-cli', ['Button', 'Input'])
|
|
12
|
+
* map.getMatrix()
|
|
13
|
+
* // → { Button: { 'ui-lit': true, 'ui-cli': true },
|
|
14
|
+
* // Input: { 'ui-lit': true, 'ui-cli': true },
|
|
15
|
+
* // Select: { 'ui-lit': true, 'ui-cli': false } }
|
|
16
|
+
* map.getReadiness('Button') // → true (in all packages)
|
|
17
|
+
* map.getReadiness('Select') // → false (missing from ui-cli)
|
|
18
|
+
*/
|
|
19
|
+
export default class ArchitectureMap {
|
|
20
|
+
/**
|
|
21
|
+
* Register a package and its exported components.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} packageName — e.g. 'ui-lit', 'ui-cli', 'ui-react-bootstrap'
|
|
24
|
+
* @param {string[]} componentsList — e.g. ['Button', 'Input', 'Select']
|
|
25
|
+
*/
|
|
26
|
+
register(packageName: string, componentsList?: string[]): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get the list of all registered package names.
|
|
29
|
+
*
|
|
30
|
+
* @returns {string[]}
|
|
31
|
+
*/
|
|
32
|
+
getPackages(): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Get all known component names (union of all packages).
|
|
35
|
+
*
|
|
36
|
+
* @returns {string[]}
|
|
37
|
+
*/
|
|
38
|
+
getComponents(): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Build a readiness matrix: { componentName → { packageName → boolean } }.
|
|
41
|
+
*
|
|
42
|
+
* Every known component gets an entry for every registered package.
|
|
43
|
+
*
|
|
44
|
+
* @returns {Object<string, Object<string, boolean>>}
|
|
45
|
+
*/
|
|
46
|
+
getMatrix(): {
|
|
47
|
+
[x: string]: {
|
|
48
|
+
[x: string]: boolean;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Check if a component is implemented in ALL registered packages.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} componentName
|
|
55
|
+
* @returns {boolean}
|
|
56
|
+
*/
|
|
57
|
+
getReadiness(componentName: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Get a summary: { total, ready, notReady, readyPercent }.
|
|
60
|
+
*
|
|
61
|
+
* @returns {{ total: number, ready: number, notReady: number, readyPercent: number }}
|
|
62
|
+
*/
|
|
63
|
+
getSummary(): {
|
|
64
|
+
total: number;
|
|
65
|
+
ready: number;
|
|
66
|
+
notReady: number;
|
|
67
|
+
readyPercent: number;
|
|
68
|
+
};
|
|
69
|
+
#private;
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, ArchitectureMap } from "./ArchitectureMap.js";
|