@nan0web/ui 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -10
- package/src/core/Intent.js +4 -3
- package/src/domain/FooterModel.js +57 -0
- package/src/domain/HeaderModel.js +50 -0
- package/src/domain/HeroModel.js +48 -0
- package/src/domain/Navigation.js +11 -10
- package/src/domain/SandboxModel.js +66 -115
- package/src/domain/ShowcaseAppModel.js +133 -50
- package/src/domain/components/AccordionModel.js +38 -0
- package/src/domain/components/AutocompleteModel.js +11 -21
- package/src/domain/components/BannerModel.js +37 -0
- package/src/domain/components/BreadcrumbModel.js +11 -9
- package/src/domain/components/ButtonModel.js +31 -58
- package/src/domain/components/CommentModel.js +44 -0
- package/src/domain/components/ConfirmModel.js +26 -33
- package/src/domain/components/EmptyStateModel.js +45 -0
- package/src/domain/components/FAQModel.js +32 -0
- package/src/domain/components/FooterConfigModel.js +26 -0
- package/src/domain/components/FooterVisibilityModel.js +48 -0
- package/src/domain/components/GalleryModel.js +36 -0
- package/src/domain/components/HeaderConfigModel.js +26 -0
- package/src/domain/components/HeaderVisibilityModel.js +54 -0
- package/src/domain/components/InputModel.js +21 -41
- package/src/domain/components/PriceModel.js +30 -0
- package/src/domain/components/PricingModel.js +39 -0
- package/src/domain/components/PricingSectionModel.js +32 -0
- package/src/domain/components/ProfileDropdownModel.js +45 -0
- package/src/domain/components/SelectModel.js +11 -21
- package/src/domain/components/SpinnerModel.js +11 -26
- package/src/domain/components/StatsItemModel.js +38 -0
- package/src/domain/components/StatsModel.js +32 -0
- package/src/domain/components/TableModel.js +11 -24
- package/src/domain/components/TabsModel.js +30 -0
- package/src/domain/components/TestimonialModel.js +24 -0
- package/src/domain/components/TimelineItemModel.js +38 -0
- package/src/domain/components/TimelineModel.js +32 -0
- package/src/domain/components/ToastModel.js +24 -51
- package/src/domain/components/TreeModel.js +10 -26
- package/src/domain/components/index.js +34 -0
- package/src/domain/index.js +24 -0
- package/src/index.js +2 -0
- package/types/domain/FooterModel.d.ts +52 -0
- package/types/domain/HeaderModel.d.ts +45 -0
- package/types/domain/HeroModel.d.ts +43 -0
- package/types/domain/Navigation.d.ts +10 -9
- package/types/domain/SandboxModel.d.ts +16 -40
- package/types/domain/ShowcaseAppModel.d.ts +26 -54
- package/types/domain/components/AccordionModel.d.ts +33 -0
- package/types/domain/components/AutocompleteModel.d.ts +10 -29
- package/types/domain/components/BannerModel.d.ts +32 -0
- package/types/domain/components/BreadcrumbModel.d.ts +13 -6
- package/types/domain/components/ButtonModel.d.ts +18 -54
- package/types/domain/components/CommentModel.d.ts +39 -0
- package/types/domain/components/ConfirmModel.d.ts +20 -35
- package/types/domain/components/EmptyStateModel.d.ts +40 -0
- package/types/domain/components/FAQModel.d.ts +27 -0
- package/types/domain/components/FooterConfigModel.d.ts +21 -0
- package/types/domain/components/FooterVisibilityModel.d.ts +43 -0
- package/types/domain/components/GalleryModel.d.ts +35 -0
- package/types/domain/components/HeaderConfigModel.d.ts +21 -0
- package/types/domain/components/HeaderVisibilityModel.d.ts +49 -0
- package/types/domain/components/HeroModel.d.ts +24 -0
- package/types/domain/components/InputModel.d.ts +19 -59
- package/types/domain/components/PriceModel.d.ts +25 -0
- package/types/domain/components/PricingModel.d.ts +34 -0
- package/types/domain/components/PricingSectionModel.d.ts +27 -0
- package/types/domain/components/ProfileDropdownModel.d.ts +40 -0
- package/types/domain/components/SelectModel.d.ts +13 -28
- package/types/domain/components/ShowcaseAppModel.d.ts +32 -0
- package/types/domain/components/SpinnerModel.d.ts +10 -27
- package/types/domain/components/StatsItemModel.d.ts +33 -0
- package/types/domain/components/StatsModel.d.ts +27 -0
- package/types/domain/components/TableModel.d.ts +10 -26
- package/types/domain/components/TabsModel.d.ts +28 -0
- package/types/domain/components/TestimonialModel.d.ts +18 -0
- package/types/domain/components/TimelineItemModel.d.ts +33 -0
- package/types/domain/components/TimelineModel.d.ts +27 -0
- package/types/domain/components/ToastModel.d.ts +16 -45
- package/types/domain/components/TreeModel.d.ts +13 -36
- package/types/domain/components/index.d.ts +20 -0
- package/types/domain/index.d.ts +4 -1
- package/types/index.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nan0web/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "NaN•Web UI. One application logic (algorithm) and many UI.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"author": "YaRaSLove (ЯRаСлав) <support@yaro.page>",
|
|
38
38
|
"license": "ISC",
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@nan0web/event": "
|
|
40
|
+
"@nan0web/event": "^1.0.1",
|
|
41
41
|
"@nan0web/i18n": "^1.1.0",
|
|
42
42
|
"@nan0web/release": "^1.0.2",
|
|
43
43
|
"@nan0web/test": "^1.1.3",
|
|
44
|
-
"@nan0web/ui-cli": "^2.
|
|
44
|
+
"@nan0web/ui-cli": "^2.9.0",
|
|
45
|
+
"@nan0web/ui-lit": "^1.1.0",
|
|
45
46
|
"@playwright/test": "^1.58.2",
|
|
46
47
|
"@rollup/plugin-yaml": "^4.1.2",
|
|
47
48
|
"@vitest/coverage-v8": "^3.2.4",
|
|
@@ -50,16 +51,14 @@
|
|
|
50
51
|
"knip": "^5.86.0",
|
|
51
52
|
"lit": "^3.3.2",
|
|
52
53
|
"vite": "^6.4.1",
|
|
53
|
-
"vitest": "^3.2.4"
|
|
54
|
-
"@nan0web/ui-lit": "1.1.0"
|
|
54
|
+
"vitest": "^3.2.4"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@nan0web/co": "^2.0.0",
|
|
58
|
-
"@nan0web/event": "^1.0.1",
|
|
59
58
|
"@nan0web/log": "^1.1.1",
|
|
60
59
|
"@nan0web/types": "^1.4.0",
|
|
61
60
|
"string-width": "^7.2.0",
|
|
62
|
-
"@nan0web/core": "1.1.
|
|
61
|
+
"@nan0web/core": "1.1.2"
|
|
63
62
|
},
|
|
64
63
|
"scripts": {
|
|
65
64
|
"build": "tsc",
|
|
@@ -74,9 +73,9 @@
|
|
|
74
73
|
"test:release": "node --test \"releases/**/*.test.js\"",
|
|
75
74
|
"test:status": "nan0test status --hide-name",
|
|
76
75
|
"test:play": "node --test --test-timeout=3333 \"play/**/*.test.js\"",
|
|
77
|
-
"test:ssg": "node --test --test-timeout=5000 \"
|
|
78
|
-
"test:e2e": "playwright test --ignore-snapshots e2e/components.spec.js e2e/debug-label.spec.js",
|
|
79
|
-
"test:e2e:slow": "E2E_SLOW=1 playwright test e2e/visual.spec.js",
|
|
76
|
+
"test:ssg": "node --test --test-timeout=5000 \"src/test/ssg.test.js\"",
|
|
77
|
+
"test:e2e": "playwright test --ignore-snapshots test/e2e/components.spec.js test/e2e/debug-label.spec.js",
|
|
78
|
+
"test:e2e:slow": "E2E_SLOW=1 playwright test test/e2e/visual.spec.js",
|
|
80
79
|
"test:all": "npm run test && npm run test:docs && npm run test:play && npm run test:e2e && npm run knip",
|
|
81
80
|
"knip": "knip --production",
|
|
82
81
|
"precommit": "npm test",
|
package/src/core/Intent.js
CHANGED
|
@@ -131,14 +131,15 @@ export function validateIntent(intent) {
|
|
|
131
131
|
if (typeof intent.field !== 'string' || !intent.field) {
|
|
132
132
|
throw IntentErrorModel.error('ask_missing_field')
|
|
133
133
|
}
|
|
134
|
-
// Accept both: plain schema {help: '...'} and Model-as-Schema class
|
|
135
|
-
const isModel = intent.model
|
|
134
|
+
// Accept both: plain schema {help: '...'} and Model-as-Schema class/instance
|
|
135
|
+
const isModel = !!intent.model
|
|
136
136
|
if (!isModel && (!intent.schema || typeof intent.schema !== 'object' || !('help' in intent.schema))) {
|
|
137
137
|
throw IntentErrorModel.error('ask_missing_schema_help')
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
if (intent.type === 'progress' || intent.type === 'log') {
|
|
141
|
-
|
|
141
|
+
const isComponentLog = intent.type === 'log' && intent.component
|
|
142
|
+
if (!isComponentLog && typeof intent.message !== 'string') {
|
|
142
143
|
throw IntentErrorModel.error('intent_missing_message', { type: intent.type })
|
|
143
144
|
}
|
|
144
145
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import Navigation from './Navigation.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* FooterModel — OLMUI Model-as-Schema
|
|
6
|
+
* Universal footer structure: copyright, version, license, navigation, sharing, languages.
|
|
7
|
+
*/
|
|
8
|
+
export default class FooterModel extends Model {
|
|
9
|
+
static $id = '@nan0web/ui/FooterModel'
|
|
10
|
+
|
|
11
|
+
static copyright = {
|
|
12
|
+
help: 'Copyright text',
|
|
13
|
+
placeholder: '© 2026 Company',
|
|
14
|
+
default: '',
|
|
15
|
+
}
|
|
16
|
+
static version = {
|
|
17
|
+
help: 'Application version string',
|
|
18
|
+
placeholder: '1.0.0',
|
|
19
|
+
default: '',
|
|
20
|
+
}
|
|
21
|
+
static license = {
|
|
22
|
+
help: 'License type',
|
|
23
|
+
placeholder: 'ISC',
|
|
24
|
+
default: '',
|
|
25
|
+
}
|
|
26
|
+
static nav = {
|
|
27
|
+
help: 'Footer navigation links',
|
|
28
|
+
type: 'Navigation[]',
|
|
29
|
+
hint: Navigation,
|
|
30
|
+
default: [],
|
|
31
|
+
}
|
|
32
|
+
static share = {
|
|
33
|
+
help: 'Social sharing links',
|
|
34
|
+
type: 'Navigation[]',
|
|
35
|
+
hint: Navigation,
|
|
36
|
+
default: [],
|
|
37
|
+
}
|
|
38
|
+
static langs = {
|
|
39
|
+
help: 'Available languages for switcher',
|
|
40
|
+
type: 'Language[]',
|
|
41
|
+
default: [],
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {Partial<FooterModel> | Record<string, any>} data Model input data.
|
|
46
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
47
|
+
*/
|
|
48
|
+
constructor(data = {}, options = {}) {
|
|
49
|
+
super(data, options)
|
|
50
|
+
/** @type {string} Copyright text */ this.copyright
|
|
51
|
+
/** @type {string} Application version string */ this.version
|
|
52
|
+
/** @type {string} License type */ this.license
|
|
53
|
+
/** @type {Navigation[]} Footer navigation links */ this.nav
|
|
54
|
+
/** @type {Navigation[]} Social sharing links */ this.share
|
|
55
|
+
/** @type {any[]} Available languages for switcher */ this.langs
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import Navigation from './Navigation.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HeaderModel — OLMUI Model-as-Schema
|
|
6
|
+
* Universal header structure: logo, navigation, language switcher, actions.
|
|
7
|
+
*/
|
|
8
|
+
export default class HeaderModel extends Model {
|
|
9
|
+
static $id = '@nan0web/ui/HeaderModel'
|
|
10
|
+
|
|
11
|
+
static title = {
|
|
12
|
+
help: 'Site or app title displayed in the header',
|
|
13
|
+
placeholder: 'My App',
|
|
14
|
+
default: '',
|
|
15
|
+
}
|
|
16
|
+
static logo = {
|
|
17
|
+
help: 'Logo image URL or icon name',
|
|
18
|
+
placeholder: 'https://...',
|
|
19
|
+
default: '',
|
|
20
|
+
}
|
|
21
|
+
static actions = {
|
|
22
|
+
help: 'Header action links (CTA, Sign In, etc.)',
|
|
23
|
+
type: 'Navigation[]',
|
|
24
|
+
hint: Navigation,
|
|
25
|
+
default: [],
|
|
26
|
+
}
|
|
27
|
+
static lang = {
|
|
28
|
+
help: 'Currently active language',
|
|
29
|
+
type: 'Language',
|
|
30
|
+
default: null,
|
|
31
|
+
}
|
|
32
|
+
static langs = {
|
|
33
|
+
help: 'Available languages for switcher',
|
|
34
|
+
type: 'Language[]',
|
|
35
|
+
default: [],
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {Partial<HeaderModel> | Record<string, any>} data Model input data.
|
|
40
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
41
|
+
*/
|
|
42
|
+
constructor(data = {}, options = {}) {
|
|
43
|
+
super(data, options)
|
|
44
|
+
/** @type {string} Site or app title displayed in the header */ this.title
|
|
45
|
+
/** @type {string} Logo image URL or icon name */ this.logo
|
|
46
|
+
/** @type {Navigation[]} Header action links (CTA, Sign In, etc.) */ this.actions
|
|
47
|
+
/** @type {any|null} Currently active language */ this.lang
|
|
48
|
+
/** @type {any[]} Available languages for switcher */ this.langs
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
|
+
import Navigation from './Navigation.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HeroModel — OLMUI Model-as-Schema
|
|
6
|
+
* Universal hero/banner section for landing pages.
|
|
7
|
+
* Uses Navigation[] for actions instead of a single CTA.
|
|
8
|
+
*/
|
|
9
|
+
export default class HeroModel extends Model {
|
|
10
|
+
static $id = '@nan0web/ui/HeroModel'
|
|
11
|
+
|
|
12
|
+
static title = {
|
|
13
|
+
help: 'Hero main headline',
|
|
14
|
+
placeholder: 'Welcome to Our Platform',
|
|
15
|
+
default: '',
|
|
16
|
+
required: true,
|
|
17
|
+
}
|
|
18
|
+
static description = {
|
|
19
|
+
help: 'Hero sub-headline or description text',
|
|
20
|
+
placeholder: 'Build something amazing...',
|
|
21
|
+
default: '',
|
|
22
|
+
}
|
|
23
|
+
static image = {
|
|
24
|
+
help: 'Hero background or feature image URL',
|
|
25
|
+
placeholder: 'https://...',
|
|
26
|
+
hint: 'image',
|
|
27
|
+
upload: true,
|
|
28
|
+
default: '',
|
|
29
|
+
}
|
|
30
|
+
static actions = {
|
|
31
|
+
help: 'Call-to-action buttons (multiple CTA support)',
|
|
32
|
+
type: 'Navigation[]',
|
|
33
|
+
hint: Navigation,
|
|
34
|
+
default: [],
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {Partial<HeroModel> | Record<string, any>} data Model input data.
|
|
39
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
40
|
+
*/
|
|
41
|
+
constructor(data = {}, options = {}) {
|
|
42
|
+
super(data, options)
|
|
43
|
+
/** @type {string} Hero main headline */ this.title
|
|
44
|
+
/** @type {string} Hero sub-headline or description text */ this.description
|
|
45
|
+
/** @type {string} Hero background or feature image URL */ this.image
|
|
46
|
+
/** @type {Navigation[]} Call-to-action buttons (multiple CTA support) */ this.actions
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/domain/Navigation.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Model } from '@nan0web/
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Navigation Model — OLMUI Model-as-Schema
|
|
@@ -41,16 +41,17 @@ export default class Navigation extends Model {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* @param {Partial<Navigation>} data
|
|
44
|
+
* @param {Partial<Navigation> | Record<string, any>} data Model input data.
|
|
45
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
45
46
|
*/
|
|
46
|
-
constructor(data = {}) {
|
|
47
|
-
super(data)
|
|
48
|
-
/** @type {string
|
|
49
|
-
/** @type {string
|
|
50
|
-
/** @type {string
|
|
51
|
-
/** @type {string
|
|
52
|
-
/** @type {Navigation[]
|
|
53
|
-
/** @type {boolean
|
|
47
|
+
constructor(data = {}, options = {}) {
|
|
48
|
+
super(data, options)
|
|
49
|
+
/** @type {string} Label for the menu item */ this.title
|
|
50
|
+
/** @type {string} URL or internal app route */ this.href
|
|
51
|
+
/** @type {string} Icon name/ID */ this.icon
|
|
52
|
+
/** @type {string} Display image or thumbnail */ this.image
|
|
53
|
+
/** @type {Navigation[]} Nested sub-menu navigation */ this.children
|
|
54
|
+
/** @type {boolean} Hide from lists/menus */ this.hidden
|
|
54
55
|
|
|
55
56
|
if (this.children) {
|
|
56
57
|
this.children = this.children.map((item) => new Navigation(item))
|
|
@@ -1,192 +1,143 @@
|
|
|
1
|
-
import { Model } from '@nan0web/
|
|
2
|
-
import * as ComponentModels from './components/index.js'
|
|
1
|
+
import { Model } from '@nan0web/types'
|
|
3
2
|
import { BreadcrumbModel } from './components/BreadcrumbModel.js'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @property {string} [selectedComponent]
|
|
9
|
-
* @property {string} [themeFormat]
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Model-as-Schema for the UI Sandbox environment.
|
|
14
|
-
* Represents a tool wrapping standard OLMUI components, allowing
|
|
15
|
-
* users to inspect their models, tweak variables interactively,
|
|
16
|
-
* and export the configuration as themes for the Marketplace.
|
|
17
|
-
*
|
|
18
|
-
* Navigation uses BreadcrumbModel:
|
|
19
|
-
* ESC = pop one level (if stack has no parent → exit app)
|
|
20
|
-
* Ctrl+C = always exit (handled by prompts.js wrapper)
|
|
21
|
-
*
|
|
22
|
-
* URL mapping:
|
|
23
|
-
* /sandbox → Select Component
|
|
24
|
-
* /sandbox/button → Edit Button properties
|
|
25
|
-
* /sandbox/button/export → Choose export format
|
|
5
|
+
* SandboxModel — OLMUI Model-as-Schema
|
|
6
|
+
* Environment for testing and previewing UI components with dynamic property editing.
|
|
26
7
|
*/
|
|
27
8
|
export class SandboxModel extends Model {
|
|
28
|
-
|
|
29
|
-
// 1. MODEL AS SCHEMA (Static Definition)
|
|
30
|
-
// ==========================================
|
|
9
|
+
static $id = '@nan0web/ui/SandboxModel'
|
|
31
10
|
|
|
32
11
|
static components = {
|
|
33
12
|
help: 'List of registered UI components available for inspection',
|
|
34
13
|
type: 'string[]',
|
|
35
|
-
default: []
|
|
14
|
+
default: [],
|
|
36
15
|
}
|
|
37
16
|
|
|
38
17
|
static selectedComponent = {
|
|
39
|
-
help: 'The
|
|
40
|
-
|
|
18
|
+
help: 'The component currently being inspected in the sandbox',
|
|
19
|
+
placeholder: 'Button',
|
|
20
|
+
default: '',
|
|
41
21
|
}
|
|
42
22
|
|
|
43
23
|
static themeFormat = {
|
|
44
24
|
help: 'The file format chosen to export the custom theme configuration',
|
|
45
25
|
options: ['yaml', 'css', 'json'],
|
|
46
|
-
default: 'yaml'
|
|
26
|
+
default: 'yaml',
|
|
47
27
|
}
|
|
48
28
|
|
|
49
29
|
/**
|
|
50
|
-
* @param {
|
|
30
|
+
* @param {Partial<SandboxModel> | Record<string, any>} data Model input data.
|
|
31
|
+
* @param {object} [options] Extended options (db, etc.)
|
|
51
32
|
*/
|
|
52
|
-
constructor(data = {}) {
|
|
53
|
-
super(data)
|
|
54
|
-
/** @type {string[]
|
|
55
|
-
|
|
56
|
-
/** @type {string
|
|
33
|
+
constructor(data = {}, options = {}) {
|
|
34
|
+
super(data, options)
|
|
35
|
+
/** @type {string[]} List of registered UI components available for inspection */ this
|
|
36
|
+
.components
|
|
37
|
+
/** @type {string} The component currently being inspected in the sandbox */ this
|
|
38
|
+
.selectedComponent
|
|
39
|
+
/** @type {'yaml'|'css'|'json'} The file format chosen to export the custom theme configuration */ this
|
|
40
|
+
.themeFormat
|
|
57
41
|
}
|
|
58
42
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
/**
|
|
44
|
+
* @returns {AsyncGenerator<any, any, any>}
|
|
45
|
+
*/
|
|
63
46
|
async *run() {
|
|
64
47
|
/** @type {any} */
|
|
65
|
-
let
|
|
66
|
-
|
|
67
|
-
// ── BreadcrumbModel as navigation stack ──
|
|
68
|
-
const nav = new BreadcrumbModel()
|
|
69
|
-
nav.push('🏖 Sandbox', 'sandbox')
|
|
48
|
+
let lastResponse = null
|
|
70
49
|
|
|
71
50
|
while (true) {
|
|
72
|
-
|
|
51
|
+
const nav = new BreadcrumbModel({ items: ['Sandbox'] })
|
|
52
|
+
|
|
73
53
|
if (!this.selectedComponent) {
|
|
74
54
|
// Show breadcrumb
|
|
75
|
-
yield
|
|
76
|
-
type: 'log',
|
|
55
|
+
yield {
|
|
56
|
+
type: 'log',
|
|
57
|
+
level: 'info',
|
|
77
58
|
message: `\n${nav}`,
|
|
78
59
|
component: 'Breadcrumbs',
|
|
79
|
-
model:
|
|
80
|
-
}
|
|
60
|
+
model: nav,
|
|
61
|
+
}
|
|
81
62
|
|
|
82
|
-
|
|
83
|
-
const listResponse = yield {
|
|
63
|
+
const response = yield {
|
|
84
64
|
type: 'ask',
|
|
85
65
|
field: 'selectedComponent',
|
|
86
66
|
schema: {
|
|
87
|
-
help: 'Select a component to inspect
|
|
67
|
+
help: 'Select a component to inspect',
|
|
88
68
|
options: this.components || [],
|
|
89
|
-
validate: (/** @type {string} */ val) =>
|
|
90
|
-
(this.components || []).includes(val) || 'Component not found in sandbox registry',
|
|
91
69
|
},
|
|
92
70
|
component: 'Select',
|
|
93
|
-
model:
|
|
71
|
+
model: this,
|
|
94
72
|
}
|
|
95
|
-
this.selectedComponent =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Instantiate the selected model class
|
|
99
|
-
const Ctor = ComponentModels[`${this.selectedComponent}Model`]
|
|
100
|
-
targetInstance = Ctor ? new Ctor() : this
|
|
73
|
+
this.selectedComponent = response.value
|
|
74
|
+
if (!this.selectedComponent) break
|
|
101
75
|
}
|
|
102
76
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
77
|
+
nav.push(this.selectedComponent, this.selectedComponent)
|
|
78
|
+
|
|
79
|
+
// 2. Component Configuration Mode
|
|
106
80
|
let configResponse
|
|
107
81
|
try {
|
|
108
|
-
yield
|
|
109
|
-
type: 'log',
|
|
82
|
+
yield {
|
|
83
|
+
type: 'log',
|
|
84
|
+
level: 'info',
|
|
110
85
|
message: `\n${nav}`,
|
|
111
86
|
component: 'Breadcrumbs',
|
|
112
|
-
model:
|
|
113
|
-
}
|
|
87
|
+
model: nav,
|
|
88
|
+
}
|
|
114
89
|
|
|
115
90
|
configResponse = yield {
|
|
116
91
|
type: 'ask',
|
|
117
|
-
field: '
|
|
118
|
-
schema:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
component: 'SandboxWrapper',
|
|
122
|
-
model: true,
|
|
123
|
-
instance: /** @type {any} */ (targetInstance),
|
|
92
|
+
field: 'config',
|
|
93
|
+
schema: { help: `Configure ${this.selectedComponent} properties` },
|
|
94
|
+
component: 'PropertyEditor',
|
|
95
|
+
model: this, // Passes the whole Sandbox context
|
|
124
96
|
}
|
|
125
97
|
} catch (e) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
// Pop: Level 2 → Level 1
|
|
129
|
-
nav.pop()
|
|
130
|
-
this.selectedComponent = undefined
|
|
131
|
-
continue
|
|
132
|
-
}
|
|
133
|
-
throw e
|
|
98
|
+
this.selectedComponent = ''
|
|
99
|
+
continue
|
|
134
100
|
}
|
|
135
101
|
|
|
136
|
-
|
|
137
|
-
|
|
102
|
+
if (configResponse.cancelled) {
|
|
103
|
+
this.selectedComponent = ''
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
138
106
|
|
|
139
|
-
//
|
|
140
|
-
// URL: /sandbox/button/export Data: data/sandbox/button/export/index.yaml
|
|
141
|
-
/** @type {any} */
|
|
142
|
-
let formatResponse
|
|
107
|
+
// 3. Theme Export Mode
|
|
143
108
|
try {
|
|
144
109
|
nav.push('Export', 'export')
|
|
145
|
-
yield
|
|
146
|
-
type: 'log',
|
|
110
|
+
yield {
|
|
111
|
+
type: 'log',
|
|
112
|
+
level: 'info',
|
|
147
113
|
message: `\n${nav}`,
|
|
148
114
|
component: 'Breadcrumbs',
|
|
149
|
-
model:
|
|
150
|
-
}
|
|
115
|
+
model: nav,
|
|
116
|
+
}
|
|
151
117
|
|
|
152
|
-
|
|
118
|
+
const themeResponse = yield {
|
|
153
119
|
type: 'ask',
|
|
154
120
|
field: 'themeFormat',
|
|
155
121
|
schema: {
|
|
156
|
-
help: 'Choose
|
|
122
|
+
help: 'Choose export format',
|
|
157
123
|
options: SandboxModel.themeFormat.options,
|
|
158
124
|
},
|
|
159
125
|
component: 'Select',
|
|
160
|
-
model:
|
|
126
|
+
model: this,
|
|
161
127
|
}
|
|
128
|
+
this.themeFormat = themeResponse.value
|
|
162
129
|
} catch (e) {
|
|
163
|
-
|
|
164
|
-
if (err.name === 'CancelError') {
|
|
165
|
-
// Pop: Level 3 → Level 2 (same targetInstance preserved)
|
|
166
|
-
nav.pop()
|
|
167
|
-
continue
|
|
168
|
-
}
|
|
169
|
-
throw e
|
|
130
|
+
// stay on results
|
|
170
131
|
}
|
|
171
132
|
|
|
172
|
-
this.themeFormat = formatResponse.value
|
|
173
|
-
|
|
174
|
-
// 4. Success notification
|
|
175
|
-
yield /** @type {any} */ ({
|
|
176
|
-
type: 'log',
|
|
177
|
-
level: 'success',
|
|
178
|
-
message: `Theme exported as ${(this.themeFormat || 'json').toUpperCase()}! Path: ${nav.path}`,
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
// 5. Return result with navigation context
|
|
182
133
|
return {
|
|
183
134
|
type: 'result',
|
|
184
135
|
data: {
|
|
185
|
-
|
|
136
|
+
component: this.selectedComponent,
|
|
186
137
|
themeConfig: configResponse.value,
|
|
187
138
|
exportFormat: this.themeFormat,
|
|
188
139
|
breadcrumb: nav.path,
|
|
189
|
-
}
|
|
140
|
+
},
|
|
190
141
|
}
|
|
191
142
|
}
|
|
192
143
|
}
|