@nan0web/ui 1.8.0 → 1.10.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 (107) hide show
  1. package/README.md +29 -10
  2. package/package.json +18 -22
  3. package/src/Model/index.js +32 -3
  4. package/src/core/Form/Form.js +8 -7
  5. package/src/core/Form/Message.js +1 -1
  6. package/src/core/GeneratorRunner.js +10 -0
  7. package/src/core/Intent.js +21 -5
  8. package/src/core/IntentErrorModel.js +6 -1
  9. package/src/core/Stream.js +16 -5
  10. package/src/core/index.js +1 -1
  11. package/src/domain/FooterModel.js +57 -0
  12. package/src/domain/HeaderModel.js +50 -0
  13. package/src/domain/HeroModel.js +48 -0
  14. package/src/domain/Navigation.js +11 -10
  15. package/src/domain/SandboxModel.js +66 -115
  16. package/src/domain/ShowcaseAppModel.js +133 -50
  17. package/src/domain/components/AccordionModel.js +38 -0
  18. package/src/domain/components/AutocompleteModel.js +11 -21
  19. package/src/domain/components/BannerModel.js +37 -0
  20. package/src/domain/components/BreadcrumbModel.js +11 -9
  21. package/src/domain/components/ButtonModel.js +31 -58
  22. package/src/domain/components/CommentModel.js +44 -0
  23. package/src/domain/components/ConfirmModel.js +26 -33
  24. package/src/domain/components/EmptyStateModel.js +45 -0
  25. package/src/domain/components/FAQModel.js +32 -0
  26. package/src/domain/components/FooterConfigModel.js +26 -0
  27. package/src/domain/components/FooterVisibilityModel.js +48 -0
  28. package/src/domain/components/GalleryModel.js +36 -0
  29. package/src/domain/components/HeaderConfigModel.js +26 -0
  30. package/src/domain/components/HeaderVisibilityModel.js +54 -0
  31. package/src/domain/components/InputModel.js +21 -41
  32. package/src/domain/components/PriceModel.js +30 -0
  33. package/src/domain/components/PricingModel.js +39 -0
  34. package/src/domain/components/PricingSectionModel.js +32 -0
  35. package/src/domain/components/ProfileDropdownModel.js +45 -0
  36. package/src/domain/components/SelectModel.js +11 -21
  37. package/src/domain/components/SpinnerModel.js +11 -26
  38. package/src/domain/components/StatsItemModel.js +38 -0
  39. package/src/domain/components/StatsModel.js +32 -0
  40. package/src/domain/components/TableModel.js +11 -24
  41. package/src/domain/components/TabsModel.js +30 -0
  42. package/src/domain/components/TestimonialModel.js +24 -0
  43. package/src/domain/components/TimelineItemModel.js +38 -0
  44. package/src/domain/components/TimelineModel.js +32 -0
  45. package/src/domain/components/ToastModel.js +24 -51
  46. package/src/domain/components/TreeModel.js +10 -26
  47. package/src/domain/components/index.js +34 -0
  48. package/src/domain/index.js +24 -0
  49. package/src/index.js +2 -0
  50. package/src/testing/GalleryGenerator.js +85 -0
  51. package/src/testing/LogicInspector.js +55 -0
  52. package/src/testing/SnapshotInspector.js +84 -0
  53. package/src/testing/VisualAdapter.js +41 -0
  54. package/src/testing/index.js +3 -0
  55. package/types/Model/index.d.ts +62 -4
  56. package/types/core/Form/Form.d.ts +2 -2
  57. package/types/core/GeneratorRunner.d.ts +4 -0
  58. package/types/core/Intent.d.ts +31 -3
  59. package/types/core/IntentErrorModel.d.ts +4 -0
  60. package/types/core/index.d.ts +1 -1
  61. package/types/domain/FooterModel.d.ts +52 -0
  62. package/types/domain/HeaderModel.d.ts +45 -0
  63. package/types/domain/HeroModel.d.ts +43 -0
  64. package/types/domain/Navigation.d.ts +10 -9
  65. package/types/domain/SandboxModel.d.ts +16 -40
  66. package/types/domain/ShowcaseAppModel.d.ts +26 -54
  67. package/types/domain/components/AccordionModel.d.ts +33 -0
  68. package/types/domain/components/AutocompleteModel.d.ts +10 -29
  69. package/types/domain/components/BannerModel.d.ts +32 -0
  70. package/types/domain/components/BreadcrumbModel.d.ts +13 -6
  71. package/types/domain/components/ButtonModel.d.ts +18 -54
  72. package/types/domain/components/CommentModel.d.ts +39 -0
  73. package/types/domain/components/ConfirmModel.d.ts +20 -35
  74. package/types/domain/components/EmptyStateModel.d.ts +40 -0
  75. package/types/domain/components/FAQModel.d.ts +27 -0
  76. package/types/domain/components/FooterConfigModel.d.ts +21 -0
  77. package/types/domain/components/FooterVisibilityModel.d.ts +43 -0
  78. package/types/domain/components/GalleryModel.d.ts +35 -0
  79. package/types/domain/components/HeaderConfigModel.d.ts +21 -0
  80. package/types/domain/components/HeaderVisibilityModel.d.ts +49 -0
  81. package/types/domain/components/HeroModel.d.ts +24 -0
  82. package/types/domain/components/InputModel.d.ts +19 -59
  83. package/types/domain/components/PriceModel.d.ts +25 -0
  84. package/types/domain/components/PricingModel.d.ts +34 -0
  85. package/types/domain/components/PricingSectionModel.d.ts +27 -0
  86. package/types/domain/components/ProfileDropdownModel.d.ts +40 -0
  87. package/types/domain/components/SelectModel.d.ts +13 -28
  88. package/types/domain/components/ShowcaseAppModel.d.ts +32 -0
  89. package/types/domain/components/SpinnerModel.d.ts +10 -27
  90. package/types/domain/components/StatsItemModel.d.ts +33 -0
  91. package/types/domain/components/StatsModel.d.ts +27 -0
  92. package/types/domain/components/TableModel.d.ts +10 -26
  93. package/types/domain/components/TabsModel.d.ts +28 -0
  94. package/types/domain/components/TestimonialModel.d.ts +18 -0
  95. package/types/domain/components/TimelineItemModel.d.ts +33 -0
  96. package/types/domain/components/TimelineModel.d.ts +27 -0
  97. package/types/domain/components/ToastModel.d.ts +16 -45
  98. package/types/domain/components/TreeModel.d.ts +13 -36
  99. package/types/domain/components/index.d.ts +20 -0
  100. package/types/domain/index.d.ts +4 -1
  101. package/types/index.d.ts +1 -0
  102. package/types/testing/GalleryGenerator.d.ts +1 -0
  103. package/types/testing/LogicInspector.d.ts +22 -0
  104. package/types/testing/SnapshotInspector.d.ts +17 -0
  105. package/types/testing/VisualAdapter.d.ts +15 -0
  106. package/types/testing/index.d.ts +3 -0
  107. package/src/README.md.js +0 -436
@@ -1,4 +1,6 @@
1
1
  // Exports for Component Models
2
+
3
+ // Interactive Components
2
4
  export { BreadcrumbModel } from './BreadcrumbModel.js'
3
5
  export { ButtonModel } from './ButtonModel.js'
4
6
  export { ConfirmModel } from './ConfirmModel.js'
@@ -9,3 +11,35 @@ export { ToastModel } from './ToastModel.js'
9
11
  export { SelectModel } from './SelectModel.js'
10
12
  export { AutocompleteModel } from './AutocompleteModel.js'
11
13
  export { TreeModel } from './TreeModel.js'
14
+ export { TabsModel } from './TabsModel.js'
15
+ export { AccordionModel } from './AccordionModel.js'
16
+ export { FAQModel } from './FAQModel.js'
17
+ export { GalleryModel } from './GalleryModel.js'
18
+
19
+ // Pricing
20
+ export { PriceModel } from './PriceModel.js'
21
+ export { PricingModel } from './PricingModel.js'
22
+ export { PricingSectionModel } from './PricingSectionModel.js'
23
+
24
+ // Hero
25
+
26
+ // Social / Feedback
27
+ export { CommentModel } from './CommentModel.js'
28
+ export { TestimonialModel } from './TestimonialModel.js'
29
+
30
+ // Data Display
31
+ export { StatsItemModel } from './StatsItemModel.js'
32
+ export { StatsModel } from './StatsModel.js'
33
+ export { TimelineItemModel } from './TimelineItemModel.js'
34
+ export { TimelineModel } from './TimelineModel.js'
35
+
36
+ // Visibility Configs
37
+ export { HeaderVisibilityModel } from './HeaderVisibilityModel.js'
38
+ export { HeaderConfigModel } from './HeaderConfigModel.js'
39
+ export { FooterVisibilityModel } from './FooterVisibilityModel.js'
40
+ export { FooterConfigModel } from './FooterConfigModel.js'
41
+
42
+ // Business Critical
43
+ export { EmptyStateModel } from './EmptyStateModel.js'
44
+ export { BannerModel } from './BannerModel.js'
45
+ export { ProfileDropdownModel } from './ProfileDropdownModel.js'
@@ -2,6 +2,12 @@
2
2
  export { SandboxModel } from './SandboxModel.js'
3
3
  export { ShowcaseAppModel } from './ShowcaseAppModel.js'
4
4
  export { default as Navigation } from './Navigation.js'
5
+ export { Language } from '@nan0web/i18n/src/domain/Language.js'
6
+
7
+ // Layout Models (Phase 1)
8
+ export { default as HeaderModel } from './HeaderModel.js'
9
+ export { default as FooterModel } from './FooterModel.js'
10
+ export { default as HeroModel } from './HeroModel.js'
5
11
 
6
12
  // Component Models
7
13
  export {
@@ -14,4 +20,22 @@ export {
14
20
  SelectModel,
15
21
  AutocompleteModel,
16
22
  TreeModel,
23
+ TabsModel,
24
+ AccordionModel,
25
+ GalleryModel,
26
+ PriceModel,
27
+ PricingModel,
28
+ CommentModel,
29
+ TestimonialModel,
30
+ StatsItemModel,
31
+ StatsModel,
32
+ TimelineItemModel,
33
+ TimelineModel,
34
+ HeaderVisibilityModel,
35
+ HeaderConfigModel,
36
+ FooterVisibilityModel,
37
+ FooterConfigModel,
38
+ EmptyStateModel,
39
+ BannerModel,
40
+ ProfileDropdownModel,
17
41
  } from './components/index.js'
package/src/index.js CHANGED
@@ -11,6 +11,8 @@ import App from './App/index.js'
11
11
 
12
12
  export { Frame, FrameProps, Locale, StdIn, StdOut, View, RenderOptions, Model, Component, App }
13
13
  export { format } from './format.js'
14
+ export { default as Navigation } from './domain/Navigation.js'
15
+ export { Language } from '@nan0web/i18n/src/domain/Language.js'
14
16
 
15
17
  // export default App
16
18
  export { default as FormMessage } from './core/Form/Message.js'
@@ -0,0 +1,85 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import { fileURLToPath } from 'url'
4
+ import yaml from 'js-yaml'
5
+ import { LogicInspector } from './LogicInspector.js'
6
+ import { VisualAdapter } from './VisualAdapter.js'
7
+ import * as Models from '../domain/index.js'
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
10
+ const rootDir = path.resolve(__dirname, '../../')
11
+ const dataDir = path.resolve(rootDir, 'docs/data')
12
+ const snapshotsDir = path.resolve(rootDir, 'snapshots/core')
13
+
14
+ // Clean before generation
15
+ if (fs.existsSync(snapshotsDir)) fs.rmSync(snapshotsDir, { recursive: true, force: true })
16
+ fs.mkdirSync(snapshotsDir, { recursive: true })
17
+
18
+ const groups = {
19
+ Actions: ['Button', 'Toggle'],
20
+ Forms: ['Input', 'Select', 'Slider', 'Autocomplete', 'Color', 'Shadow'],
21
+ Data: ['Accordion', 'Card', 'Sortable', 'Table', 'Tree', 'CodeBlock', 'Markdown', 'Badge'],
22
+ Feedback: ['Alert', 'Confirm', 'Modal', 'ProgressBar', 'Spinner', 'Toast'],
23
+ System: ['LangSelect', 'ThemeToggle'],
24
+ }
25
+
26
+ function getCategory(comp) {
27
+ for (const [cat, comps] of Object.entries(groups)) {
28
+ if (comps.includes(comp)) return cat
29
+ }
30
+ return 'Other'
31
+ }
32
+
33
+ async function generate() {
34
+ const langs = fs.readdirSync(dataDir).filter(d => fs.statSync(path.join(dataDir, d)).isDirectory() && d !== '_')
35
+
36
+ for (const lang of langs) {
37
+ const langDir = path.join(dataDir, lang)
38
+ const components = fs.readdirSync(langDir).filter(f => f.endsWith('.yaml'))
39
+
40
+ for (const file of components) {
41
+ const compName = file.replace('.yaml', '')
42
+ const category = getCategory(compName)
43
+ const text = fs.readFileSync(path.join(langDir, file), 'utf-8')
44
+ const data = yaml.load(text)
45
+
46
+ // Variations are in data.content
47
+ const variations = data.content || []
48
+
49
+ for (let i = 0; i < variations.length; i++) {
50
+ const varData = variations[i][compName] || variations[i]
51
+
52
+ // Get variation name from 'content', 'title', 'message', or fallback to index
53
+ let varName = varData.content || varData.title || varData.message || `var${i + 1}`
54
+ if (typeof varName !== 'string') varName = `var${i + 1}`
55
+
56
+ // Clean filename: allow Ukrainian, but replace spaces/special chars with single underscore
57
+ const safeVarName = varName
58
+ .trim()
59
+ .toLowerCase()
60
+ .replace(/[./\\:]/g, '_') // Replace paths/dots
61
+ .replace(/\s+/g, '_') // Replace spaces
62
+ .replace(/_{2,}/g, '_') // No double underscores
63
+ .slice(0, 50) // Max length
64
+
65
+ // Logic Capture
66
+ /** @type {() => AsyncGenerator<import('../core/Intent.js').Intent, import('../core/Intent.js').ResultIntent, any>} */
67
+ const modelStream = async function* () {
68
+ yield { type: 'render', component: `ui-${compName.toLowerCase()}`, props: varData }
69
+ return { type: 'result', data: { ok: true } }
70
+ }
71
+
72
+ const intents = await LogicInspector.capture(modelStream())
73
+ const snapshot = intents.map(it => VisualAdapter.render(it)).join('\n')
74
+
75
+ const outPath = path.join(snapshotsDir, lang, category, compName)
76
+ if (!fs.existsSync(outPath)) fs.mkdirSync(outPath, { recursive: true })
77
+
78
+ fs.writeFileSync(path.join(outPath, `${safeVarName}.txt`), snapshot)
79
+ console.log(`📸 Generated snapshot for ${lang}/${category}/${compName}/${safeVarName}`)
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ generate().catch(console.error)
@@ -0,0 +1,55 @@
1
+ import { runGenerator } from '../core/GeneratorRunner.js'
2
+
3
+ /**
4
+ * LogicInspector
5
+ *
6
+ * Базовий клас для захоплення "Логічних зліпків" (Intent Stream) будь-яких моделей OLMUI.
7
+ * Дозволяє виконувати чисто-логічне тестування без прив'язки до рендерингу.
8
+ */
9
+ export class LogicInspector {
10
+ /**
11
+ * Виконує генератор моделі та записує послідовність усіх інтенцій.
12
+ * @param {AsyncGenerator<import('../core/Intent.js').Intent, import('../core/Intent.js').ResultIntent, import('../core/Intent.js').IntentResponse>} modelStream - результат виклику model.run()
13
+ * @param {object} options
14
+ * @param {Array<any> | ((locale: string) => Array<any>)} [options.inputs] - черга вхідних значень для askIntent
15
+ * @param {string} [options.locale] - локаль для тестів
16
+ * @param {function} [options.t] - функція перекладу
17
+ * @returns {Promise<Array<any>>} Intent Stream Log
18
+ */
19
+ static async capture(modelStream, { inputs = [], locale = 'uk', t = (k) => k } = {}) {
20
+ const intents = []
21
+ let inputIdx = 0
22
+ const resolvedInputs = typeof inputs === 'function' ? inputs(locale) : inputs
23
+
24
+ const recordingAdapter = {
25
+ /** @param {import('../core/Intent.js').AskIntent} i */
26
+ ask: async (i) => {
27
+ const value = resolvedInputs[inputIdx++]
28
+ const entry = { type: 'ask', field: i.field, schema: i.schema, input: value }
29
+ intents.push(entry)
30
+ return { value }
31
+ },
32
+ /** @param {import('../core/Intent.js').LogIntent} i */
33
+ log: async (i) => {
34
+ intents.push({ type: 'log', level: i.level || 'info', message: i.message })
35
+ },
36
+ /** @param {import('../core/Intent.js').ProgressIntent} i */
37
+ progress: async (i) => {
38
+ intents.push({ type: 'progress', message: i.message })
39
+ },
40
+ /** @param {import('../core/Intent.js').RenderIntent} i */
41
+ render: async (i) => {
42
+ intents.push({ type: 'render', component: i.component, props: i.props })
43
+ },
44
+ /** @param {import('../core/Intent.js').ResultIntent} i */
45
+ result: async (i) => {
46
+ intents.push({ type: 'result', data: i.data })
47
+ },
48
+ t
49
+ }
50
+
51
+ // Викликаємо базовий раннер з нашим записуючим адаптером
52
+ await runGenerator(modelStream, recordingAdapter)
53
+ return intents
54
+ }
55
+ }
@@ -0,0 +1,84 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+ /**
5
+ * SnapshotInspector
6
+ *
7
+ * Рев'ювер для автоматичної перевірки Snapshot-зліпків на наявність артефактів,
8
+ * неперекладених ключів та структурних помилок.
9
+ * Реалізує правила "Zero-Hallucination Snapshot Validation".
10
+ */
11
+ export class SnapshotInspector {
12
+ /**
13
+ * Перевіряє вміст одного снепшоту.
14
+ * @param {string} content - Текстовий вміст .txt файлу галереї
15
+ * @param {string} locale - Локаль (uk, en)
16
+ * @param {string} [filename] - Ім'я файлу для перевірки на "глюки" (підкреслення)
17
+ * @returns {object} { score, errors }
18
+ */
19
+ static inspect(content, locale = 'uk', filename = '') {
20
+ const errors = []
21
+ const lines = content.split('\n')
22
+
23
+ // 0. Перевірка імені файлу (на прохання архітектора)
24
+ if (filename) {
25
+ if (/__|--/.test(filename)) {
26
+ errors.push(`Filename "${filename}" has multiple consecutive separators (glitch detected).`)
27
+ }
28
+ if (filename.length < 3) {
29
+ errors.push(`Filename "${filename}" is too short.`)
30
+ }
31
+ }
32
+
33
+ lines.forEach((line, index) => {
34
+ const lineNum = index + 1
35
+ const trimmed = line.trim()
36
+
37
+ // 1. Неперекладені i18n ключі (крапки в словах)
38
+ // Виключаємо імена компонентів, атрибути RENDER-тегів, та числа з крапкою (версії, координати)
39
+ const isAttribute = trimmed.includes('="')
40
+ const isDotNumber = /^-?\d+\.\d+$/.test(trimmed)
41
+
42
+ if (/\w+\.\w+/.test(line) && !line.includes('ui-') && !line.includes('http') && !isAttribute && !isDotNumber) {
43
+ errors.push(`Line ${lineNum}: Possible untranslated key found: "${trimmed}"`)
44
+ }
45
+
46
+ // 2. Технічні артефакти
47
+ if (line.includes('[object Object]')) {
48
+ errors.push(`Line ${lineNum}: Critical artifact "[object Object]" found.`)
49
+ }
50
+ if (line.includes('undefined')) {
51
+ errors.push(`Line ${lineNum}: Critical artifact "undefined" found.`)
52
+ }
53
+ if (line.includes('NaN')) {
54
+ errors.push(`Line ${lineNum}: Critical artifact "NaN" found.`)
55
+ }
56
+
57
+ // 3. Англійські слова в українській локалі (базові)
58
+ if (locale === 'uk') {
59
+ const enWords = ['Back', 'Select', 'Cancel', 'Submit', 'Confirm', 'Delete', 'Information', 'Success', 'Warning', 'Error']
60
+ enWords.forEach(word => {
61
+ const regex = new RegExp(`\\b${word}\\b`, 'i')
62
+ // Перевіряємо тільки якщо це не частина тегу <ui-...> або атрибут
63
+ if (regex.test(line)) {
64
+ const isTag = line.includes(`<ui-${word.toLowerCase()}`) || line.includes(`[RENDER] <ui-`)
65
+ const isAsk = line.includes(`[ASK] ${word}`)
66
+ if (!isTag && !isAsk && !isAttribute) {
67
+ errors.push(`Line ${lineNum}: English word "${word}" found in "uk" locale.`)
68
+ }
69
+ }
70
+ })
71
+ }
72
+
73
+ // 4. Помилки роутингу
74
+ if (line.includes('🚨 Path not found')) {
75
+ errors.push(`Line ${lineNum}: Routing error "Path not found".`)
76
+ }
77
+ })
78
+
79
+ return {
80
+ score: errors.length === 0 ? 100 : Math.max(0, 100 - errors.length * 10),
81
+ errors
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * VisualAdapter (Base)
3
+ *
4
+ * Базовий клас для візуальної трансформації інтенцій OLMUI.
5
+ * Використовувана у @nan0web/ui як фундамент для спеціалізованих рендерерів.
6
+ */
7
+ export class VisualAdapter {
8
+ /**
9
+ * Конвертує одну інтенцію у просте текстове представлення.
10
+ * @param {object} intent - Intent entry from LogicInspector
11
+ * @param {function} [t] - i18n translate function
12
+ * @returns {string} Raw description
13
+ */
14
+ static render(intent, t = (k) => k) {
15
+ switch (intent.type) {
16
+ case 'ask':
17
+ return `[ASK] ${intent.field}: ${intent.input !== undefined ? intent.input : '...'}`
18
+ case 'progress':
19
+ return `[PROGRESS] ${intent.message || ''}`
20
+ case 'log':
21
+ return `[LOG ${intent.level?.toUpperCase() || 'INFO'}] ${typeof intent.message === 'object' ? JSON.stringify(intent.message) : intent.message}`
22
+ case 'render': {
23
+ const { content, ...propsData } = intent.props || {}
24
+ const props = Object.entries(propsData)
25
+ .map(([k, v]) => ` ${k}="${typeof v === 'object' ? JSON.stringify(v) : v}"`)
26
+ .join('\n')
27
+
28
+ if (content) {
29
+ const attrs = props ? `\n${props}\n` : ' '
30
+ return `[RENDER] <${intent.component}${attrs}>${content}</${intent.component}>`
31
+ }
32
+
33
+ return `[RENDER] <${intent.component}${props ? '\n' + props + '\n' : ''}>`
34
+ }
35
+ case 'result':
36
+ return `[RESULT] ${JSON.stringify(intent.data)}`
37
+ default:
38
+ return `[UNKNOWN: ${intent.type}] ${JSON.stringify(intent)}`
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,3 @@
1
+ export * from './LogicInspector.js'
2
+ export * from './VisualAdapter.js'
3
+ export * from './SnapshotInspector.js'
@@ -1,6 +1,64 @@
1
1
  export { User };
2
- declare namespace _default {
3
- export { User };
4
- }
5
- export default _default;
2
+ export const HeaderModel: typeof DomainModels.HeaderModel;
3
+ export const FooterModel: typeof DomainModels.FooterModel;
4
+ export const HeroModel: typeof DomainModels.HeroModel;
5
+ export const ButtonModel: typeof DomainModels.ButtonModel;
6
+ export const ConfirmModel: typeof DomainModels.ConfirmModel;
7
+ export const InputModel: typeof DomainModels.InputModel;
8
+ export const SpinnerModel: typeof DomainModels.SpinnerModel;
9
+ export const TableModel: typeof DomainModels.TableModel;
10
+ export const ToastModel: typeof DomainModels.ToastModel;
11
+ export const SelectModel: typeof DomainModels.SelectModel;
12
+ export const AutocompleteModel: typeof DomainModels.AutocompleteModel;
13
+ export const TreeModel: typeof DomainModels.TreeModel;
14
+ export const TabsModel: typeof DomainModels.TabsModel;
15
+ export const AccordionModel: typeof DomainModels.AccordionModel;
16
+ export const GalleryModel: typeof DomainModels.GalleryModel;
17
+ export const PriceModel: typeof DomainModels.PriceModel;
18
+ export const PricingModel: typeof DomainModels.PricingModel;
19
+ export const CommentModel: typeof DomainModels.CommentModel;
20
+ export const TestimonialModel: typeof DomainModels.TestimonialModel;
21
+ export const StatsItemModel: typeof DomainModels.StatsItemModel;
22
+ export const StatsModel: typeof DomainModels.StatsModel;
23
+ export const TimelineItemModel: typeof DomainModels.TimelineItemModel;
24
+ export const TimelineModel: typeof DomainModels.TimelineModel;
25
+ export default Model;
6
26
  import User from './User/User.js';
27
+ import * as DomainModels from '../domain/index.js';
28
+ declare const Model: {
29
+ SandboxModel: typeof DomainModels.SandboxModel;
30
+ ShowcaseAppModel: typeof DomainModels.ShowcaseAppModel;
31
+ Navigation: typeof DomainModels.Navigation;
32
+ Language: any;
33
+ HeaderModel: typeof DomainModels.HeaderModel;
34
+ FooterModel: typeof DomainModels.FooterModel;
35
+ HeroModel: typeof DomainModels.HeroModel;
36
+ ButtonModel: typeof DomainModels.ButtonModel;
37
+ ConfirmModel: typeof DomainModels.ConfirmModel;
38
+ InputModel: typeof DomainModels.InputModel;
39
+ SpinnerModel: typeof DomainModels.SpinnerModel;
40
+ TableModel: typeof DomainModels.TableModel;
41
+ ToastModel: typeof DomainModels.ToastModel;
42
+ SelectModel: typeof DomainModels.SelectModel;
43
+ AutocompleteModel: typeof DomainModels.AutocompleteModel;
44
+ TreeModel: typeof DomainModels.TreeModel;
45
+ TabsModel: typeof DomainModels.TabsModel;
46
+ AccordionModel: typeof DomainModels.AccordionModel;
47
+ GalleryModel: typeof DomainModels.GalleryModel;
48
+ PriceModel: typeof DomainModels.PriceModel;
49
+ PricingModel: typeof DomainModels.PricingModel;
50
+ CommentModel: typeof DomainModels.CommentModel;
51
+ TestimonialModel: typeof DomainModels.TestimonialModel;
52
+ StatsItemModel: typeof DomainModels.StatsItemModel;
53
+ StatsModel: typeof DomainModels.StatsModel;
54
+ TimelineItemModel: typeof DomainModels.TimelineItemModel;
55
+ TimelineModel: typeof DomainModels.TimelineModel;
56
+ HeaderVisibilityModel: typeof DomainModels.HeaderVisibilityModel;
57
+ HeaderConfigModel: typeof DomainModels.HeaderConfigModel;
58
+ FooterVisibilityModel: typeof DomainModels.FooterVisibilityModel;
59
+ FooterConfigModel: typeof DomainModels.FooterConfigModel;
60
+ EmptyStateModel: typeof DomainModels.EmptyStateModel;
61
+ BannerModel: typeof DomainModels.BannerModel;
62
+ ProfileDropdownModel: typeof DomainModels.ProfileDropdownModel;
63
+ User: typeof User;
64
+ };
@@ -89,9 +89,9 @@ export default class UIForm extends FormMessage {
89
89
  /**
90
90
  * Validates the entire form.
91
91
  *
92
- * @returns {Map<string, string>} Map of validation errors, empty if valid.
92
+ * @returns {any}
93
93
  */
94
- validate(): Map<string, string>;
94
+ validate(): any;
95
95
  /**
96
96
  * Validates a single field.
97
97
  *
@@ -32,6 +32,10 @@ export type AdapterHandlers = {
32
32
  * Handler for 'log' intents. Optional (defaults to no-op).
33
33
  */
34
34
  log?: ((intent: import("./Intent.js").LogIntent) => void | Promise<void>) | undefined;
35
+ /**
36
+ * Handler for 'render' intents (visual component injection). Optional.
37
+ */
38
+ render?: ((intent: import("./Intent.js").RenderIntent) => void | Promise<void>) | undefined;
35
39
  /**
36
40
  * Handler for the final 'result'. Optional (defaults to no-op).
37
41
  */
@@ -53,9 +53,17 @@ export function validateIntent(intent: any): intent is Intent;
53
53
  * @property {'result'} type
54
54
  * @property {*} data - The raw result data (JSON-serializable).
55
55
  */
56
+ /**
57
+ * Model requests rendering of a pure UI component (Header, Footer, Static Map).
58
+ * No response expected from the logic loop.
59
+ * @typedef {Object} RenderIntent
60
+ * @property {'render'} type
61
+ * @property {string} component - Component name (e.g. 'App.Layout.Header').
62
+ * @property {object} props - Static props for the component.
63
+ */
56
64
  /**
57
65
  * Union of all possible yielded intents.
58
- * @typedef {AskIntent | ProgressIntent | LogIntent} Intent
66
+ * @typedef {AskIntent | ProgressIntent | LogIntent | RenderIntent} Intent
59
67
  */
60
68
  /**
61
69
  * Response to an AskIntent. Adapter provides the collected value.
@@ -82,7 +90,7 @@ export function validateIntent(intent: any): intent is Intent;
82
90
  * Union of all possible responses an Adapter can send back via iterator.next().
83
91
  * @typedef {AskResponse | AbortResponse | undefined} IntentResponse
84
92
  */
85
- export const INTENT_TYPES: readonly ["ask", "progress", "log"];
93
+ export const INTENT_TYPES: readonly ["ask", "progress", "log", "render"];
86
94
  export function ask(field: string, schema: object | Function): AskIntent;
87
95
  export function progress(message: any): {
88
96
  type: string;
@@ -93,6 +101,11 @@ export function log(level: any, message: any, data?: {}): {
93
101
  level: any;
94
102
  message: any;
95
103
  };
104
+ export function render(component: any, props?: {}): {
105
+ type: string;
106
+ component: any;
107
+ props: {};
108
+ };
96
109
  export function result(data: any): {
97
110
  type: string;
98
111
  data: any;
@@ -186,10 +199,25 @@ export type ResultIntent = {
186
199
  */
187
200
  data: any;
188
201
  };
202
+ /**
203
+ * Model requests rendering of a pure UI component (Header, Footer, Static Map).
204
+ * No response expected from the logic loop.
205
+ */
206
+ export type RenderIntent = {
207
+ type: "render";
208
+ /**
209
+ * - Component name (e.g. 'App.Layout.Header').
210
+ */
211
+ component: string;
212
+ /**
213
+ * - Static props for the component.
214
+ */
215
+ props: object;
216
+ };
189
217
  /**
190
218
  * Union of all possible yielded intents.
191
219
  */
192
- export type Intent = AskIntent | ProgressIntent | LogIntent;
220
+ export type Intent = AskIntent | ProgressIntent | LogIntent | RenderIntent;
193
221
  /**
194
222
  * Response to an AskIntent. Adapter provides the collected value.
195
223
  * The value MUST conform to the type described in the requested FieldSchema.
@@ -19,6 +19,10 @@ export class IntentErrorModel {
19
19
  help: string;
20
20
  error: string;
21
21
  };
22
+ static render_missing_component: {
23
+ help: string;
24
+ error: string;
25
+ };
22
26
  static adapter_missing_ask: {
23
27
  help: string;
24
28
  error: string;
@@ -13,4 +13,4 @@ import UIForm from './Form/Form.js';
13
13
  export { UIStream, UIStream as UiStream, StreamEntry, StreamEntry as UiStreamEntry, UIForm, UIForm as UiForm };
14
14
  export { default as Error, CancelError } from "./Error/index.js";
15
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";
16
+ export { validateIntent, ask, progress, log, render, result, INTENT_TYPES, isModelSchema } from "./Intent.js";
@@ -0,0 +1,52 @@
1
+ /**
2
+ * FooterModel — OLMUI Model-as-Schema
3
+ * Universal footer structure: copyright, version, license, navigation, sharing, languages.
4
+ */
5
+ export default class FooterModel extends Model {
6
+ static $id: string;
7
+ static copyright: {
8
+ help: string;
9
+ placeholder: string;
10
+ default: string;
11
+ };
12
+ static version: {
13
+ help: string;
14
+ placeholder: string;
15
+ default: string;
16
+ };
17
+ static license: {
18
+ help: string;
19
+ placeholder: string;
20
+ default: string;
21
+ };
22
+ static nav: {
23
+ help: string;
24
+ type: string;
25
+ hint: typeof Navigation;
26
+ default: never[];
27
+ };
28
+ static share: {
29
+ help: string;
30
+ type: string;
31
+ hint: typeof Navigation;
32
+ default: never[];
33
+ };
34
+ static langs: {
35
+ help: string;
36
+ type: string;
37
+ default: never[];
38
+ };
39
+ /**
40
+ * @param {Partial<FooterModel> | Record<string, any>} data Model input data.
41
+ * @param {object} [options] Extended options (db, etc.)
42
+ */
43
+ constructor(data?: Partial<FooterModel> | Record<string, any>, options?: object);
44
+ /** @type {string} Copyright text */ copyright: string;
45
+ /** @type {string} Application version string */ version: string;
46
+ /** @type {string} License type */ license: string;
47
+ /** @type {Navigation[]} Footer navigation links */ nav: Navigation[];
48
+ /** @type {Navigation[]} Social sharing links */ share: Navigation[];
49
+ /** @type {any[]} Available languages for switcher */ langs: any[];
50
+ }
51
+ import { Model } from '@nan0web/types';
52
+ import Navigation from './Navigation.js';
@@ -0,0 +1,45 @@
1
+ /**
2
+ * HeaderModel — OLMUI Model-as-Schema
3
+ * Universal header structure: logo, navigation, language switcher, actions.
4
+ */
5
+ export default class HeaderModel extends Model {
6
+ static $id: string;
7
+ static title: {
8
+ help: string;
9
+ placeholder: string;
10
+ default: string;
11
+ };
12
+ static logo: {
13
+ help: string;
14
+ placeholder: string;
15
+ default: string;
16
+ };
17
+ static actions: {
18
+ help: string;
19
+ type: string;
20
+ hint: typeof Navigation;
21
+ default: never[];
22
+ };
23
+ static lang: {
24
+ help: string;
25
+ type: string;
26
+ default: null;
27
+ };
28
+ static langs: {
29
+ help: string;
30
+ type: string;
31
+ default: never[];
32
+ };
33
+ /**
34
+ * @param {Partial<HeaderModel> | Record<string, any>} data Model input data.
35
+ * @param {object} [options] Extended options (db, etc.)
36
+ */
37
+ constructor(data?: Partial<HeaderModel> | Record<string, any>, options?: object);
38
+ /** @type {string} Site or app title displayed in the header */ title: string;
39
+ /** @type {string} Logo image URL or icon name */ logo: string;
40
+ /** @type {Navigation[]} Header action links (CTA, Sign In, etc.) */ actions: Navigation[];
41
+ /** @type {any|null} Currently active language */ lang: any | null;
42
+ /** @type {any[]} Available languages for switcher */ langs: any[];
43
+ }
44
+ import { Model } from '@nan0web/types';
45
+ import Navigation from './Navigation.js';