@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.
Files changed (82) hide show
  1. package/package.json +9 -10
  2. package/src/core/Intent.js +4 -3
  3. package/src/domain/FooterModel.js +57 -0
  4. package/src/domain/HeaderModel.js +50 -0
  5. package/src/domain/HeroModel.js +48 -0
  6. package/src/domain/Navigation.js +11 -10
  7. package/src/domain/SandboxModel.js +66 -115
  8. package/src/domain/ShowcaseAppModel.js +133 -50
  9. package/src/domain/components/AccordionModel.js +38 -0
  10. package/src/domain/components/AutocompleteModel.js +11 -21
  11. package/src/domain/components/BannerModel.js +37 -0
  12. package/src/domain/components/BreadcrumbModel.js +11 -9
  13. package/src/domain/components/ButtonModel.js +31 -58
  14. package/src/domain/components/CommentModel.js +44 -0
  15. package/src/domain/components/ConfirmModel.js +26 -33
  16. package/src/domain/components/EmptyStateModel.js +45 -0
  17. package/src/domain/components/FAQModel.js +32 -0
  18. package/src/domain/components/FooterConfigModel.js +26 -0
  19. package/src/domain/components/FooterVisibilityModel.js +48 -0
  20. package/src/domain/components/GalleryModel.js +36 -0
  21. package/src/domain/components/HeaderConfigModel.js +26 -0
  22. package/src/domain/components/HeaderVisibilityModel.js +54 -0
  23. package/src/domain/components/InputModel.js +21 -41
  24. package/src/domain/components/PriceModel.js +30 -0
  25. package/src/domain/components/PricingModel.js +39 -0
  26. package/src/domain/components/PricingSectionModel.js +32 -0
  27. package/src/domain/components/ProfileDropdownModel.js +45 -0
  28. package/src/domain/components/SelectModel.js +11 -21
  29. package/src/domain/components/SpinnerModel.js +11 -26
  30. package/src/domain/components/StatsItemModel.js +38 -0
  31. package/src/domain/components/StatsModel.js +32 -0
  32. package/src/domain/components/TableModel.js +11 -24
  33. package/src/domain/components/TabsModel.js +30 -0
  34. package/src/domain/components/TestimonialModel.js +24 -0
  35. package/src/domain/components/TimelineItemModel.js +38 -0
  36. package/src/domain/components/TimelineModel.js +32 -0
  37. package/src/domain/components/ToastModel.js +24 -51
  38. package/src/domain/components/TreeModel.js +10 -26
  39. package/src/domain/components/index.js +34 -0
  40. package/src/domain/index.js +24 -0
  41. package/src/index.js +2 -0
  42. package/types/domain/FooterModel.d.ts +52 -0
  43. package/types/domain/HeaderModel.d.ts +45 -0
  44. package/types/domain/HeroModel.d.ts +43 -0
  45. package/types/domain/Navigation.d.ts +10 -9
  46. package/types/domain/SandboxModel.d.ts +16 -40
  47. package/types/domain/ShowcaseAppModel.d.ts +26 -54
  48. package/types/domain/components/AccordionModel.d.ts +33 -0
  49. package/types/domain/components/AutocompleteModel.d.ts +10 -29
  50. package/types/domain/components/BannerModel.d.ts +32 -0
  51. package/types/domain/components/BreadcrumbModel.d.ts +13 -6
  52. package/types/domain/components/ButtonModel.d.ts +18 -54
  53. package/types/domain/components/CommentModel.d.ts +39 -0
  54. package/types/domain/components/ConfirmModel.d.ts +20 -35
  55. package/types/domain/components/EmptyStateModel.d.ts +40 -0
  56. package/types/domain/components/FAQModel.d.ts +27 -0
  57. package/types/domain/components/FooterConfigModel.d.ts +21 -0
  58. package/types/domain/components/FooterVisibilityModel.d.ts +43 -0
  59. package/types/domain/components/GalleryModel.d.ts +35 -0
  60. package/types/domain/components/HeaderConfigModel.d.ts +21 -0
  61. package/types/domain/components/HeaderVisibilityModel.d.ts +49 -0
  62. package/types/domain/components/HeroModel.d.ts +24 -0
  63. package/types/domain/components/InputModel.d.ts +19 -59
  64. package/types/domain/components/PriceModel.d.ts +25 -0
  65. package/types/domain/components/PricingModel.d.ts +34 -0
  66. package/types/domain/components/PricingSectionModel.d.ts +27 -0
  67. package/types/domain/components/ProfileDropdownModel.d.ts +40 -0
  68. package/types/domain/components/SelectModel.d.ts +13 -28
  69. package/types/domain/components/ShowcaseAppModel.d.ts +32 -0
  70. package/types/domain/components/SpinnerModel.d.ts +10 -27
  71. package/types/domain/components/StatsItemModel.d.ts +33 -0
  72. package/types/domain/components/StatsModel.d.ts +27 -0
  73. package/types/domain/components/TableModel.d.ts +10 -26
  74. package/types/domain/components/TabsModel.d.ts +28 -0
  75. package/types/domain/components/TestimonialModel.d.ts +18 -0
  76. package/types/domain/components/TimelineItemModel.d.ts +33 -0
  77. package/types/domain/components/TimelineModel.d.ts +27 -0
  78. package/types/domain/components/ToastModel.d.ts +16 -45
  79. package/types/domain/components/TreeModel.d.ts +13 -36
  80. package/types/domain/components/index.d.ts +20 -0
  81. package/types/domain/index.d.ts +4 -1
  82. package/types/index.d.ts +1 -0
@@ -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
+ }
@@ -0,0 +1,39 @@
1
+ import { Model } from '@nan0web/types'
2
+ import { PriceModel } from './PriceModel.js'
3
+
4
+ /**
5
+ * PricingModel — OLMUI Model-as-Schema
6
+ * A pricing tier/plan with title, price, and feature list.
7
+ */
8
+ export class PricingModel extends Model {
9
+ static $id = '@nan0web/ui/PricingModel'
10
+
11
+ static title = {
12
+ help: 'Pricing plan name',
13
+ placeholder: 'Pro Plan',
14
+ default: '',
15
+ required: true,
16
+ }
17
+ static price = {
18
+ help: 'Price object (value + currency)',
19
+ type: 'PriceModel',
20
+ hint: PriceModel,
21
+ default: null,
22
+ }
23
+ static features = {
24
+ help: 'List of features included in this plan',
25
+ type: 'string[]',
26
+ default: [],
27
+ }
28
+
29
+ /**
30
+ * @param {Partial<PricingModel> | Record<string, any>} data Model input data.
31
+ * @param {object} [options] Extended options (db, etc.)
32
+ */
33
+ constructor(data = {}, options = {}) {
34
+ super(data, options)
35
+ /** @type {string} Pricing plan name */ this.title
36
+ /** @type {PriceModel|null} Price object (value + currency) */ this.price
37
+ /** @type {string[]} List of features included in this plan */ this.features
38
+ }
39
+ }
@@ -0,0 +1,32 @@
1
+ import { Model } from '@nan0web/types'
2
+ import { PricingModel } from './PricingModel.js'
3
+
4
+ /**
5
+ * PricingSectionModel — OLMUI Model-as-Schema
6
+ * A section containing a title and a collection of pricing tiers.
7
+ */
8
+ export class PricingSectionModel extends Model {
9
+ static $id = '@nan0web/ui/PricingSectionModel'
10
+
11
+ static title = {
12
+ help: 'Section title',
13
+ placeholder: 'Pricing Plans',
14
+ default: '',
15
+ }
16
+ static items = {
17
+ help: 'Array of pricing tiers',
18
+ type: 'PricingModel[]',
19
+ hint: PricingModel,
20
+ default: [],
21
+ }
22
+
23
+ /**
24
+ * @param {Partial<PricingSectionModel> | 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 {PricingModel[]} Array of pricing tiers */ this.items
31
+ }
32
+ }
@@ -0,0 +1,45 @@
1
+ import { Model } from '@nan0web/types'
2
+ import Navigation from '../Navigation.js'
3
+
4
+ /**
5
+ * ProfileDropdownModel — OLMUI Model-as-Schema
6
+ * Account/profile dropdown in the header (user menu).
7
+ */
8
+ export class ProfileDropdownModel extends Model {
9
+ static $id = '@nan0web/ui/ProfileDropdownModel'
10
+
11
+ static profileName = {
12
+ alias: 'name',
13
+ help: 'Display name of the user',
14
+ placeholder: 'Jane Doe',
15
+ default: '',
16
+ }
17
+ static email = {
18
+ help: 'User email address',
19
+ placeholder: 'jane@example.com',
20
+ default: '',
21
+ }
22
+ static avatar = {
23
+ help: 'User avatar image URL',
24
+ placeholder: 'https://...',
25
+ default: '',
26
+ }
27
+ static actions = {
28
+ help: 'Dropdown menu items (Settings, Logout, etc.)',
29
+ type: 'Navigation[]',
30
+ hint: Navigation,
31
+ default: [],
32
+ }
33
+
34
+ /**
35
+ * @param {Partial<ProfileDropdownModel> | 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} Display name of the user */ this.profileName
41
+ /** @type {string} User email address */ this.email
42
+ /** @type {string} User avatar image URL */ this.avatar
43
+ /** @type {Navigation[]} Dropdown menu items */ this.actions
44
+ }
45
+ }
@@ -1,20 +1,10 @@
1
- import { Model } from '@nan0web/core'
2
-
3
- /**
4
- * @typedef {Object} SelectData
5
- * @property {string} [content]
6
- * @property {string[]} [options]
7
- */
1
+ import { Model } from '@nan0web/types'
8
2
 
9
3
  /**
10
4
  * Model-as-Schema for Select component.
11
5
  * Represents a dropdown choice selection.
12
6
  */
13
7
  export class SelectModel extends Model {
14
- // ==========================================
15
- // 1. MODEL AS SCHEMA (Static Definition)
16
- // ==========================================
17
-
18
8
  static content = {
19
9
  help: 'Currently selected item or default placeholder',
20
10
  default: 'Choose option',
@@ -28,18 +18,18 @@ export class SelectModel extends Model {
28
18
  }
29
19
 
30
20
  /**
31
- * @param {SelectData | any} [data]
21
+ * @param {Partial<SelectModel> | Record<string, any>} data Model input data.
22
+ * @param {object} [options] Extended options (db, etc.)
32
23
  */
33
- constructor(data = {}) {
34
- super(data)
35
- /** @type {string|undefined} */ this.content
36
- /** @type {string[]|undefined} */ this.options
24
+ constructor(data = {}, options = {}) {
25
+ super(data, options)
26
+ /** @type {string} Currently selected item or default placeholder */ this.content
27
+ /** @type {string[]} List of available options for selection */ this.options
37
28
  }
38
29
 
39
- // ==========================================
40
- // 2. AGNOSTIC LOGIC (Async Generator)
41
- // ==========================================
42
-
30
+ /**
31
+ * @returns {AsyncGenerator<any, { type: 'result', data: { selected: string } }, any>}
32
+ */
43
33
  async *run() {
44
34
  const response = yield {
45
35
  type: 'ask',
@@ -50,7 +40,7 @@ export class SelectModel extends Model {
50
40
  validate: (val) => this.options?.includes(val) || 'Invalid option selected',
51
41
  },
52
42
  component: 'Select',
53
- model: /** @type {any} */ (this),
43
+ model: this,
54
44
  }
55
45
 
56
46
  this.content = response.value
@@ -1,21 +1,10 @@
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
- */
1
+ import { Model } from '@nan0web/types'
9
2
 
10
3
  /**
11
4
  * Model-as-Schema for Spinner component.
12
5
  * Represents a loading or progress state without user interaction.
13
6
  */
14
7
  export class SpinnerModel extends Model {
15
- // ==========================================
16
- // 1. MODEL AS SCHEMA (Static Definition)
17
- // ==========================================
18
-
19
8
  static size = {
20
9
  help: 'Spinner diameter',
21
10
  default: 'md',
@@ -29,30 +18,26 @@ export class SpinnerModel extends Model {
29
18
  }
30
19
 
31
20
  /**
32
- * @param {SpinnerData | any} [data]
21
+ * @param {Partial<SpinnerModel> | Record<string, any>} data Model input data.
22
+ * @param {object} [options] Extended options (db, etc.)
33
23
  */
34
- constructor(data = {}) {
35
- super(data)
36
- /** @type {SpinnerSize|undefined} */ this.size
37
- /** @type {string|undefined} */ this.color
24
+ constructor(data = {}, options = {}) {
25
+ super(data, options)
26
+ /** @type {'sm'|'md'|'lg'} Spinner diameter */ this.size
27
+ /** @type {string} Override for base color token */ this.color
38
28
  }
39
29
 
40
- // ==========================================
41
- // 2. AGNOSTIC LOGIC (Async Generator)
42
- // ==========================================
43
-
30
+ /**
31
+ * @returns {AsyncGenerator<any, any, any>}
32
+ */
44
33
  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
34
  yield {
49
35
  type: 'progress',
50
36
  message: 'Loading...',
51
37
  component: 'Spinner',
52
- model: /** @type {any} */ (this),
38
+ model: this,
53
39
  }
54
40
 
55
- // Instant exit since it performs no async task internally
56
41
  return { type: 'result', data: { completed: true } }
57
42
  }
58
43
  }
@@ -0,0 +1,38 @@
1
+ import { Model } from '@nan0web/types'
2
+
3
+ /**
4
+ * StatsItemModel — OLMUI Model-as-Schema
5
+ * A single stat entry (e.g. "Users: 10,000 ↑12%").
6
+ */
7
+ export class StatsItemModel extends Model {
8
+ static $id = '@nan0web/ui/StatsItemModel'
9
+
10
+ static label = {
11
+ help: 'Stat label (e.g. "Active Users")',
12
+ placeholder: 'Users',
13
+ default: '',
14
+ required: true,
15
+ }
16
+ static value = {
17
+ help: 'Stat value (number or formatted string)',
18
+ placeholder: '10,000',
19
+ default: '',
20
+ required: true,
21
+ }
22
+ static trend = {
23
+ help: 'Trend indicator (e.g. "+12%", "-3%", or empty)',
24
+ placeholder: '+12%',
25
+ default: '',
26
+ }
27
+
28
+ /**
29
+ * @param {Partial<StatsItemModel> | Record<string, any>} data Model input data.
30
+ * @param {object} [options] Extended options (db, etc.)
31
+ */
32
+ constructor(data = {}, options = {}) {
33
+ super(data, options)
34
+ /** @type {string} Stat label (e.g. "Active Users") */ this.label
35
+ /** @type {string} Stat value (number or formatted string) */ this.value
36
+ /** @type {string} Trend indicator (e.g. "+12%", "-3%", or empty) */ this.trend
37
+ }
38
+ }