@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,92 +1,65 @@
1
- import { Model } from '@nan0web/core'
2
-
3
- /**
4
- * @typedef {'primary'|'secondary'|'info'|'ok'|'warn'|'err'|'ghost'} ButtonVariant
5
- * @typedef {'sm'|'md'|'lg'} ButtonSize
6
- * @typedef {Object} ButtonData
7
- * @property {string} [content]
8
- * @property {ButtonVariant} [variant]
9
- * @property {ButtonSize} [size]
10
- * @property {boolean} [outline]
11
- * @property {boolean} [disabled]
12
- * @property {boolean} [loading]
13
- */
1
+ import { Model } from '@nan0web/types'
14
2
 
15
3
  /**
16
4
  * Model-as-Schema for Button component.
17
- * Represents the intention and state of a Button interaction.
18
- * Used exclusively for schema definition and editor validation.
19
5
  */
20
6
  export class ButtonModel extends Model {
21
- // ==========================================
22
- // 1. MODEL AS SCHEMA (Static Definition)
23
- // ==========================================
24
-
25
- static content = {
26
- help: 'Text or content inside the button',
27
- default: 'Click Me',
28
- type: 'string',
29
- }
30
-
31
7
  static variant = {
32
- help: 'Visual importance and semantic meaning',
8
+ help: 'Button visual style',
33
9
  default: 'primary',
34
- options: ['primary', 'secondary', 'info', 'ok', 'warn', 'err', 'ghost'],
10
+ options: ['primary', 'secondary', 'danger', 'ghost'],
35
11
  }
36
12
 
37
- static size = {
38
- help: 'Size of the button',
39
- default: 'md',
40
- options: ['sm', 'md', 'lg'],
13
+ static content = {
14
+ help: 'Text displayed inside the button',
15
+ default: 'Click me',
16
+ type: 'string',
41
17
  }
42
18
 
43
- static outline = {
44
- help: 'Whether the button has a transparent background with border',
45
- default: false,
46
- type: 'boolean',
19
+ static href = {
20
+ help: 'Optional link URL',
21
+ default: '',
22
+ type: 'string',
47
23
  }
48
24
 
49
25
  static disabled = {
50
- help: 'Whether the button is disabled and unclickable',
26
+ help: 'Whether the button can be clicked',
51
27
  default: false,
52
28
  type: 'boolean',
53
29
  }
54
30
 
55
- static loading = {
56
- help: 'Whether the button shows a loading spinner instead of content',
31
+ static clicked = {
32
+ help: 'Interal flag: true if clicked',
57
33
  default: false,
58
34
  type: 'boolean',
59
35
  }
60
36
 
61
37
  /**
62
- * @param {ButtonData | any} [data]
38
+ * @param {Partial<ButtonModel> | Record<string, any>} data Model input data.
39
+ * @param {object} [options] Extended options (db, etc.)
63
40
  */
64
- constructor(data = {}) {
65
- super(data)
66
- /** @type {string|undefined} */ this.content
67
- /** @type {ButtonVariant|undefined} */ this.variant
68
- /** @type {ButtonSize|undefined} */ this.size
69
- /** @type {boolean|undefined} */ this.outline
70
- /** @type {boolean|undefined} */ this.disabled
71
- /** @type {boolean|undefined} */ this.loading
41
+ constructor(data = {}, options = {}) {
42
+ super(data, options)
43
+ /** @type {'primary'|'secondary'|'danger'|'ghost'} Button visual style */ this.variant
44
+ /** @type {string} Text displayed inside the button */ this.content
45
+ /** @type {string} Optional link URL */ this.href
46
+ /** @type {boolean} Whether the button can be clicked */ this.disabled
47
+ /** @type {boolean} Reactive flag set to true when user activates the button */ this.clicked
72
48
  }
73
49
 
74
- // ==========================================
75
- // 2. AGNOSTIC LOGIC (Async Generator)
76
- // ==========================================
77
-
50
+ /**
51
+ * @returns {AsyncGenerator<any, any, any>}
52
+ */
78
53
  async *run() {
79
- // A basic button interaction intention:
80
- // We simply yield ourselves as a 'button_click' intent.
81
- // Adaptors will render the button and wait for the click event.
82
54
  const response = yield {
83
55
  type: 'ask',
84
- field: 'action',
85
- schema: { help: 'Click the button to proceed' },
56
+ field: 'clicked',
57
+ schema: { help: 'Click the button' },
86
58
  component: 'Button',
87
- model: /** @type {any} */ (this),
59
+ model: this,
88
60
  }
89
61
 
90
- return { type: 'result', data: { clicked: true, ...response } }
62
+ this.clicked = response.value?.clicked || false
63
+ return { type: 'result', data: { clicked: this.clicked } }
91
64
  }
92
65
  }
@@ -0,0 +1,44 @@
1
+ import { Model } from '@nan0web/types'
2
+
3
+ /**
4
+ * CommentModel — OLMUI Model-as-Schema
5
+ * Base model for user-generated comments / reviews.
6
+ */
7
+ export class CommentModel extends Model {
8
+ static $id = '@nan0web/ui/CommentModel'
9
+
10
+ static author = {
11
+ help: 'Author name',
12
+ placeholder: 'Jane Doe',
13
+ default: '',
14
+ required: true,
15
+ }
16
+ static avatar = {
17
+ help: 'Author avatar image URL',
18
+ placeholder: 'https://...',
19
+ default: '',
20
+ }
21
+ static text = {
22
+ help: 'Comment body text',
23
+ placeholder: 'Great product!',
24
+ default: '',
25
+ required: true,
26
+ }
27
+ static date = {
28
+ help: 'Comment date (ISO 8601)',
29
+ placeholder: '2026-01-01',
30
+ default: '',
31
+ }
32
+
33
+ /**
34
+ * @param {Partial<CommentModel> | Record<string, any>} data Model input data.
35
+ * @param {object} [options] Extended options (db, etc.)
36
+ */
37
+ constructor(data = {}, options = {}) {
38
+ super(data, options)
39
+ /** @type {string} Author name */ this.author
40
+ /** @type {string} Author avatar image URL */ this.avatar
41
+ /** @type {string} Comment body text */ this.text
42
+ /** @type {string} Comment date (ISO 8601) */ this.date
43
+ }
44
+ }
@@ -1,64 +1,57 @@
1
- import { Model } from '@nan0web/core'
1
+ import { Model } from '@nan0web/types'
2
2
 
3
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.
4
+ * Model-as-Schema for Confirmation dialog.
12
5
  */
13
6
  export class ConfirmModel extends Model {
14
- // ==========================================
15
- // 1. MODEL AS SCHEMA (Static Definition)
16
- // ==========================================
7
+ static title = {
8
+ help: 'Short title for the action',
9
+ default: 'Confirm Action',
10
+ type: 'string',
11
+ }
17
12
 
18
13
  static message = {
19
- help: 'Dialog message displayed to the user',
14
+ help: 'The question asked to the user',
20
15
  default: 'Are you sure?',
21
16
  type: 'string',
22
17
  }
23
18
 
24
- static confirmText = {
25
- help: 'Label for the positive confirmation button',
19
+ static okLabel = {
20
+ help: 'Text for the confirm button',
26
21
  default: 'Yes',
27
22
  type: 'string',
28
23
  }
29
24
 
30
- static cancelText = {
31
- help: 'Label for the negative rejection button',
25
+ static cancelLabel = {
26
+ help: 'Text for the cancel button',
32
27
  default: 'No',
33
28
  type: 'string',
34
29
  }
35
30
 
36
31
  /**
37
- * @param {ConfirmData | any} [data]
32
+ * @param {Partial<ConfirmModel> | Record<string, any>} data Model input data.
33
+ * @param {object} [options] Extended options (db, etc.)
38
34
  */
39
- constructor(data = {}) {
40
- super(data)
41
- /** @type {string|undefined} */ this.message
42
- /** @type {string|undefined} */ this.confirmText
43
- /** @type {string|undefined} */ this.cancelText
35
+ constructor(data = {}, options = {}) {
36
+ super(data, options)
37
+ /** @type {string} Short title for the action */ this.title
38
+ /** @type {string} The question asked to the user */ this.message
39
+ /** @type {string} Text for the confirm button */ this.okLabel
40
+ /** @type {string} Text for the cancel button */ this.cancelLabel
44
41
  }
45
42
 
46
- // ==========================================
47
- // 2. AGNOSTIC LOGIC (Async Generator)
48
- // ==========================================
49
-
43
+ /**
44
+ * @returns {AsyncGenerator<any, any, any>}
45
+ */
50
46
  async *run() {
51
47
  const response = yield {
52
48
  type: 'ask',
53
49
  field: 'confirmed',
54
- schema: {
55
- help: this.message,
56
- type: 'boolean',
57
- },
50
+ schema: { type: 'boolean', help: this.message },
58
51
  component: 'Confirm',
59
- model: /** @type {any} */ (this), // Attached for richer UI metadata
52
+ model: this,
60
53
  }
61
54
 
62
- return { type: 'result', data: { confirmed: !!response.value } }
55
+ return { type: 'result', data: { confirmed: response.value === true } }
63
56
  }
64
57
  }
@@ -0,0 +1,45 @@
1
+ import { Model } from '@nan0web/types'
2
+ import Navigation from '../Navigation.js'
3
+
4
+ /**
5
+ * EmptyStateModel — OLMUI Model-as-Schema
6
+ * Onboarding placeholder for empty tables, lists, or dashboards.
7
+ */
8
+ export class EmptyStateModel extends Model {
9
+ static $id = '@nan0web/ui/EmptyStateModel'
10
+
11
+ static icon = {
12
+ help: 'Illustration or icon name for the empty state',
13
+ placeholder: 'inbox',
14
+ default: '',
15
+ }
16
+ static title = {
17
+ help: 'Empty state headline',
18
+ placeholder: 'No items yet',
19
+ default: '',
20
+ required: true,
21
+ }
22
+ static description = {
23
+ help: 'Helpful description guiding the user',
24
+ placeholder: 'Create your first item to get started',
25
+ default: '',
26
+ }
27
+ static action = {
28
+ help: 'Primary CTA action (Navigation link or button)',
29
+ type: 'Navigation',
30
+ hint: Navigation,
31
+ default: null,
32
+ }
33
+
34
+ /**
35
+ * @param {Partial<EmptyStateModel> | Record<string, any>} data Model input data.
36
+ * @param {object} [options] Extended options (db, etc.)
37
+ */
38
+ constructor(data = {}, options = {}) {
39
+ super(data, options)
40
+ /** @type {string} Illustration or icon name for the empty state */ this.icon
41
+ /** @type {string} Empty state headline */ this.title
42
+ /** @type {string} Helpful description guiding the user */ this.description
43
+ /** @type {Navigation|null} Primary CTA action (Navigation link or button) */ this.action
44
+ }
45
+ }
@@ -0,0 +1,32 @@
1
+ import { Model } from '@nan0web/types'
2
+ import { AccordionModel } from './AccordionModel.js'
3
+
4
+ /**
5
+ * FAQModel — OLMUI Model-as-Schema
6
+ * A section containing a title and a collection of FAQ (accordion) items.
7
+ */
8
+ export class FAQModel extends Model {
9
+ static $id = '@nan0web/ui/FAQModel'
10
+
11
+ static title = {
12
+ help: 'Section title',
13
+ placeholder: 'Frequently Asked Questions',
14
+ default: '',
15
+ }
16
+ static items = {
17
+ help: 'Array of FAQ items',
18
+ type: 'AccordionModel[]',
19
+ hint: AccordionModel,
20
+ default: [],
21
+ }
22
+
23
+ /**
24
+ * @param {Partial<FAQModel> | Record<string, any>} data Model input data.
25
+ * @param {object} [options] Extended options (db, etc.)
26
+ */
27
+ constructor(data = {}, options = {}) {
28
+ super(data, options)
29
+ /** @type {string} Section title */ this.title
30
+ /** @type {AccordionModel[]} Array of FAQ items */ this.items
31
+ }
32
+ }
@@ -0,0 +1,26 @@
1
+ import { Model } from '@nan0web/types'
2
+ import { FooterVisibilityModel } from './FooterVisibilityModel.js'
3
+
4
+ /**
5
+ * FooterConfigModel — OLMUI Model-as-Schema
6
+ * Configuration container mapping UI variant keys to FooterVisibilityModel instances.
7
+ */
8
+ export class FooterConfigModel extends Model {
9
+ static $id = '@nan0web/ui/FooterConfigModel'
10
+
11
+ static ui = {
12
+ help: 'Map of UI variant name → FooterVisibilityModel',
13
+ type: 'Record<string, FooterVisibilityModel>',
14
+ hint: FooterVisibilityModel,
15
+ default: {},
16
+ }
17
+
18
+ /**
19
+ * @param {Partial<FooterConfigModel> | Record<string, any>} data Model input data.
20
+ * @param {object} [options] Extended options (db, etc.)
21
+ */
22
+ constructor(data = {}, options = {}) {
23
+ super(data, options)
24
+ /** @type {Record<string, FooterVisibilityModel>} Map of UI variant name → FooterVisibilityModel */ this.ui
25
+ }
26
+ }
@@ -0,0 +1,48 @@
1
+ import { Model } from '@nan0web/types'
2
+
3
+ /**
4
+ * FooterVisibilityModel — OLMUI Model-as-Schema
5
+ * Boolean flags controlling which footer elements are visible.
6
+ */
7
+ export class FooterVisibilityModel extends Model {
8
+ static $id = '@nan0web/ui/FooterVisibilityModel'
9
+
10
+ static copyright = {
11
+ help: 'Show copyright text',
12
+ default: true,
13
+ type: 'boolean',
14
+ }
15
+ static version = {
16
+ help: 'Show version string',
17
+ default: true,
18
+ type: 'boolean',
19
+ }
20
+ static license = {
21
+ help: 'Show license info',
22
+ default: false,
23
+ type: 'boolean',
24
+ }
25
+ static nav = {
26
+ help: 'Show footer navigation',
27
+ default: true,
28
+ type: 'boolean',
29
+ }
30
+ static clock = {
31
+ help: 'Show clock widget',
32
+ default: false,
33
+ type: 'boolean',
34
+ }
35
+
36
+ /**
37
+ * @param {Partial<FooterVisibilityModel> | Record<string, any>} data Model input data.
38
+ * @param {object} [options] Extended options (db, etc.)
39
+ */
40
+ constructor(data = {}, options = {}) {
41
+ super(data, options)
42
+ /** @type {boolean} Show copyright text */ this.copyright
43
+ /** @type {boolean} Show version string */ this.version
44
+ /** @type {boolean} Show license info */ this.license
45
+ /** @type {boolean} Show footer navigation */ this.nav
46
+ /** @type {boolean} Show clock widget */ this.clock
47
+ }
48
+ }
@@ -0,0 +1,36 @@
1
+ import { Model } from '@nan0web/types'
2
+
3
+ /**
4
+ * GalleryModel — OLMUI Model-as-Schema
5
+ * Image gallery / media grid with optional captions.
6
+ */
7
+ export class GalleryModel extends Model {
8
+ static $id = '@nan0web/ui/GalleryModel'
9
+
10
+ static title = {
11
+ help: 'Gallery section title',
12
+ placeholder: 'Photo Gallery',
13
+ default: '',
14
+ }
15
+ static items = {
16
+ help: 'Gallery items (image URL + caption + alt)',
17
+ type: 'object[]',
18
+ default: [],
19
+ }
20
+ static columns = {
21
+ help: 'Number of columns in grid layout',
22
+ default: 3,
23
+ type: 'number',
24
+ }
25
+
26
+ /**
27
+ * @param {Partial<GalleryModel> | Record<string, any>} data Model input data.
28
+ * @param {object} [options] Extended options (db, etc.)
29
+ */
30
+ constructor(data = {}, options = {}) {
31
+ super(data, options)
32
+ /** @type {string} Gallery section title */ this.title
33
+ /** @type {Array<{src: string, caption?: string, alt?: string}>} Gallery items */ this.items
34
+ /** @type {number} Number of columns in grid layout */ this.columns
35
+ }
36
+ }
@@ -0,0 +1,26 @@
1
+ import { Model } from '@nan0web/types'
2
+ import { HeaderVisibilityModel } from './HeaderVisibilityModel.js'
3
+
4
+ /**
5
+ * HeaderConfigModel — OLMUI Model-as-Schema
6
+ * Configuration container mapping UI variant keys to HeaderVisibilityModel instances.
7
+ */
8
+ export class HeaderConfigModel extends Model {
9
+ static $id = '@nan0web/ui/HeaderConfigModel'
10
+
11
+ static ui = {
12
+ help: 'Map of UI variant name → HeaderVisibilityModel',
13
+ type: 'Record<string, HeaderVisibilityModel>',
14
+ hint: HeaderVisibilityModel,
15
+ default: {},
16
+ }
17
+
18
+ /**
19
+ * @param {Partial<HeaderConfigModel> | Record<string, any>} data Model input data.
20
+ * @param {object} [options] Extended options (db, etc.)
21
+ */
22
+ constructor(data = {}, options = {}) {
23
+ super(data, options)
24
+ /** @type {Record<string, HeaderVisibilityModel>} Map of UI variant name → HeaderVisibilityModel */ this.ui
25
+ }
26
+ }
@@ -0,0 +1,54 @@
1
+ import { Model } from '@nan0web/types'
2
+
3
+ /**
4
+ * HeaderVisibilityModel — OLMUI Model-as-Schema
5
+ * Boolean flags controlling which header elements are visible.
6
+ */
7
+ export class HeaderVisibilityModel extends Model {
8
+ static $id = '@nan0web/ui/HeaderVisibilityModel'
9
+
10
+ static logo = {
11
+ help: 'Show logo',
12
+ default: true,
13
+ type: 'boolean',
14
+ }
15
+ static theme = {
16
+ help: 'Show theme toggle (dark/light)',
17
+ default: true,
18
+ type: 'boolean',
19
+ }
20
+ static search = {
21
+ help: 'Show search input',
22
+ default: false,
23
+ type: 'boolean',
24
+ }
25
+ static share = {
26
+ help: 'Show share button',
27
+ default: false,
28
+ type: 'boolean',
29
+ }
30
+ static nav = {
31
+ help: 'Show navigation links',
32
+ default: true,
33
+ type: 'boolean',
34
+ }
35
+ static langs = {
36
+ help: 'Show language switcher',
37
+ default: true,
38
+ type: 'boolean',
39
+ }
40
+
41
+ /**
42
+ * @param {Partial<HeaderVisibilityModel> | Record<string, any>} data Model input data.
43
+ * @param {object} [options] Extended options (db, etc.)
44
+ */
45
+ constructor(data = {}, options = {}) {
46
+ super(data, options)
47
+ /** @type {boolean} Show logo */ this.logo
48
+ /** @type {boolean} Show theme toggle (dark/light) */ this.theme
49
+ /** @type {boolean} Show search input */ this.search
50
+ /** @type {boolean} Show share button */ this.share
51
+ /** @type {boolean} Show navigation links */ this.nav
52
+ /** @type {boolean} Show language switcher */ this.langs
53
+ }
54
+ }
@@ -1,30 +1,9 @@
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
- */
1
+ import { Model } from '@nan0web/types'
18
2
 
19
3
  /**
20
4
  * Model-as-Schema for Input component.
21
- * Used exclusively for schema definition, validation, and editor reflection.
22
5
  */
23
6
  export class InputModel extends Model {
24
- // ==========================================
25
- // 1. MODEL AS SCHEMA (Static Definition)
26
- // ==========================================
27
-
28
7
  static type = {
29
8
  help: 'HTML5 Input type attribute',
30
9
  default: 'text',
@@ -92,27 +71,27 @@ export class InputModel extends Model {
92
71
  }
93
72
 
94
73
  /**
95
- * @param {InputData | any} [data]
74
+ * @param {Partial<InputModel> | Record<string, any>} data Model input data.
75
+ * @param {object} [options] Extended options (db, etc.)
96
76
  */
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
77
+ constructor(data = {}, options = {}) {
78
+ super(data, options)
79
+ /** @type {string} HTML5 Input type attribute */ this.type
80
+ /** @type {string} Label displayed above the input */ this.label
81
+ /** @type {string} Placeholder text shown when empty */ this.placeholder
82
+ /** @type {boolean} Whether the field must be filled out */ this.required
83
+ /** @type {string} RegExp pattern for validation */ this.pattern
84
+ /** @type {string} Minimum value */ this.min
85
+ /** @type {string} Maximum value */ this.max
86
+ /** @type {string} Step interval */ this.step
87
+ /** @type {string} Helper text displayed below the input */ this.hint
88
+ /** @type {boolean} Whether the input is disabled */ this.disabled
89
+ /** @type {string} The actual value of the input */ this.content
110
90
  }
111
91
 
112
- // ==========================================
113
- // 2. AGNOSTIC LOGIC (Async Generator)
114
- // ==========================================
115
-
92
+ /**
93
+ * @returns {AsyncGenerator<any, any, any>}
94
+ */
116
95
  async *run() {
117
96
  const response = yield {
118
97
  type: 'ask',
@@ -127,13 +106,14 @@ export class InputModel extends Model {
127
106
  if (!re.test(val)) return 'Invalid format'
128
107
  } catch (e) {
129
108
  // fallback if pattern is malformed
109
+ return 'Invalid format'
130
110
  }
131
111
  }
132
112
  return true
133
113
  },
134
114
  },
135
115
  component: 'Input',
136
- model: /** @type {any} */ (this),
116
+ model: this,
137
117
  }
138
118
 
139
119
  this.content = response.value
@@ -0,0 +1,30 @@
1
+ import { Model } from '@nan0web/types'
2
+
3
+ /**
4
+ * PriceModel — OLMUI Model-as-Schema
5
+ * Represents a monetary value with currency.
6
+ */
7
+ export class PriceModel extends Model {
8
+ static $id = '@nan0web/ui/PriceModel'
9
+
10
+ static value = {
11
+ help: 'Numeric price value',
12
+ default: 0,
13
+ type: 'number',
14
+ }
15
+ static currency = {
16
+ help: 'Currency code (ISO 4217)',
17
+ placeholder: 'USD',
18
+ default: 'USD',
19
+ }
20
+
21
+ /**
22
+ * @param {Partial<PriceModel> | Record<string, any>} data Model input data.
23
+ * @param {object} [options] Extended options (db, etc.)
24
+ */
25
+ constructor(data = {}, options = {}) {
26
+ super(data, options)
27
+ /** @type {number} Numeric price value */ this.value
28
+ /** @type {string} Currency code (ISO 4217) */ this.currency
29
+ }
30
+ }