native-document 1.0.166 → 1.0.169

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 (139) hide show
  1. package/.vitepress/config.js +166 -0
  2. package/CHANGELOG.md +187 -0
  3. package/components.js +4 -1
  4. package/dist/native-document.components.min.js +593 -300
  5. package/dist/native-document.dev.js +99 -75
  6. package/dist/native-document.dev.js.map +1 -1
  7. package/dist/native-document.min.js +1 -1
  8. package/docs/advanced-components.md +213 -608
  9. package/docs/anchor.md +173 -312
  10. package/docs/cache.md +95 -803
  11. package/docs/cli.md +179 -0
  12. package/docs/components/accordion.md +172 -0
  13. package/docs/components/alert.md +99 -0
  14. package/docs/components/avatar.md +160 -0
  15. package/docs/components/badge.md +102 -0
  16. package/docs/components/breadcrumb.md +89 -0
  17. package/docs/components/button.md +183 -0
  18. package/docs/components/card.md +69 -0
  19. package/docs/components/context-menu.md +118 -0
  20. package/docs/components/data-table.md +345 -0
  21. package/docs/components/dropdown.md +214 -0
  22. package/docs/components/form/autocomplete-field.md +81 -0
  23. package/docs/components/form/checkbox-field.md +41 -0
  24. package/docs/components/form/checkbox-group-field.md +54 -0
  25. package/docs/components/form/color-field.md +64 -0
  26. package/docs/components/form/date-field.md +92 -0
  27. package/docs/components/form/field-collection.md +63 -0
  28. package/docs/components/form/file-field.md +203 -0
  29. package/docs/components/form/form-control.md +87 -0
  30. package/docs/components/form/image-field.md +90 -0
  31. package/docs/components/form/index.md +115 -0
  32. package/docs/components/form/number-field.md +65 -0
  33. package/docs/components/form/radio-field.md +51 -0
  34. package/docs/components/form/select-field.md +123 -0
  35. package/docs/components/form/slider.md +136 -0
  36. package/docs/components/form/string-field.md +134 -0
  37. package/docs/components/form/textarea-field.md +65 -0
  38. package/docs/components/form-fields.md +372 -0
  39. package/docs/components/getting-started.md +264 -0
  40. package/docs/components/icons.md +321 -0
  41. package/docs/components/index.md +337 -0
  42. package/docs/components/layout.md +279 -0
  43. package/docs/components/list.md +73 -0
  44. package/docs/components/menu.md +215 -0
  45. package/docs/components/modal.md +156 -0
  46. package/docs/components/pagination.md +95 -0
  47. package/docs/components/popover.md +131 -0
  48. package/docs/components/progress.md +111 -0
  49. package/docs/components/shortcut-manager.md +221 -0
  50. package/docs/components/simple-table.md +107 -0
  51. package/docs/components/skeleton.md +155 -0
  52. package/docs/components/spinner.md +100 -0
  53. package/docs/components/splitter.md +133 -0
  54. package/docs/components/stepper.md +163 -0
  55. package/docs/components/switch.md +113 -0
  56. package/docs/components/tabs.md +153 -0
  57. package/docs/components/toast.md +119 -0
  58. package/docs/components/tooltip.md +151 -0
  59. package/docs/components/traits.md +261 -0
  60. package/docs/conditional-rendering.md +170 -588
  61. package/docs/contributing.md +300 -25
  62. package/docs/core-concepts.md +205 -374
  63. package/docs/elements.md +251 -367
  64. package/docs/extending-native-document-element.md +192 -207
  65. package/docs/filters.md +153 -1122
  66. package/docs/getting-started.md +193 -267
  67. package/docs/i18n.md +241 -0
  68. package/docs/index.md +76 -0
  69. package/docs/lifecycle-events.md +143 -75
  70. package/docs/list-rendering.md +227 -852
  71. package/docs/memory-management.md +134 -47
  72. package/docs/native-document-element.md +337 -186
  73. package/docs/native-fetch.md +99 -630
  74. package/docs/observable-resource.md +364 -0
  75. package/docs/observables.md +592 -526
  76. package/docs/routing.md +244 -653
  77. package/docs/state-management.md +134 -241
  78. package/docs/svg-elements.md +231 -0
  79. package/docs/theming.md +409 -0
  80. package/docs/tutorials/.gitkeep +0 -0
  81. package/docs/validation.md +95 -97
  82. package/docs/vitepress-conventions.md +219 -0
  83. package/package.json +34 -13
  84. package/readme.md +269 -89
  85. package/src/components/card/Card.js +93 -39
  86. package/src/components/card/index.js +1 -1
  87. package/src/components/form/field/types/FileField.js +3 -3
  88. package/src/components/icon/Icon.js +107 -0
  89. package/src/components/icon/icon-getters.js +142 -0
  90. package/src/components/icon/icons.js +171 -0
  91. package/src/components/icon/index.js +17 -0
  92. package/src/components/icon/types/Icon.d.ts +191 -0
  93. package/src/components/index.d.ts +6 -1
  94. package/src/components/list/HasListItem.js +171 -0
  95. package/src/components/list/List.js +41 -107
  96. package/src/components/list/ListDivider.js +39 -0
  97. package/src/components/list/ListGroup.js +76 -59
  98. package/src/components/list/ListItem.js +117 -69
  99. package/src/components/list/index.js +3 -1
  100. package/src/components/list/types/List.d.ts +45 -32
  101. package/src/components/list/types/ListDivider.ts +16 -0
  102. package/src/components/list/types/ListGroup.d.ts +51 -29
  103. package/src/components/list/types/ListItem.d.ts +40 -30
  104. package/src/components/spacer/Spacer.js +1 -1
  105. package/src/core/data/ObservableResource.js +5 -0
  106. package/src/core/data/observable-helpers/observable.prototypes.js +2 -0
  107. package/src/core/elements/content-formatter.js +16 -2
  108. package/src/core/elements/form.js +1 -1
  109. package/src/core/elements/img.js +1 -1
  110. package/src/core/elements/medias.js +2 -2
  111. package/src/core/elements/meta-data.js +1 -1
  112. package/src/core/wrappers/AttributesWrapper.js +37 -22
  113. package/src/core/wrappers/ElementCreator.js +9 -16
  114. package/src/core/wrappers/HtmlElementWrapper.js +26 -7
  115. package/src/core/wrappers/NDElement.js +12 -1
  116. package/src/core/wrappers/prototypes/attributes-extensions.js +24 -24
  117. package/src/core/wrappers/prototypes/nd-element-extensions.js +1 -8
  118. package/src/ui/components/card/CardRender.js +133 -0
  119. package/src/ui/components/card/card.css +169 -0
  120. package/src/ui/components/contextmenu/ContextmenuRender.js +1 -1
  121. package/src/ui/components/icon/material/MaterialIconRender.js +71 -0
  122. package/src/ui/components/icon/material/material.css +15 -0
  123. package/src/ui/components/icon/material/material.map.js +170 -0
  124. package/src/ui/components/icon/phosphor/PhosphorIconRender.js +71 -0
  125. package/src/ui/components/icon/phosphor/phosphor.css +17 -0
  126. package/src/ui/components/icon/phosphor/phosphor.map.js +165 -0
  127. package/src/ui/components/icon/tabler/TablerIconRender.js +59 -0
  128. package/src/ui/components/icon/tabler/tabler.css +14 -0
  129. package/src/ui/components/icon/tabler/tabler.map.js +165 -0
  130. package/src/ui/components/list/ListRender.js +18 -0
  131. package/src/ui/components/list/divider/ListDividerRender.js +10 -0
  132. package/src/ui/components/list/divider/list-divider.css +12 -0
  133. package/src/ui/components/list/group/ListGroupRender.js +61 -0
  134. package/src/ui/components/list/group/list-group.css +62 -0
  135. package/src/ui/components/list/item/ListItemRender.js +238 -0
  136. package/src/ui/components/list/item/list-item.css +191 -0
  137. package/src/ui/components/list/list.css +24 -0
  138. package/src/ui/components/spacer/SpacerRender.js +10 -0
  139. package/src/ui/index.js +13 -0
@@ -2525,6 +2525,8 @@ var NativeComponents = (function (exports) {
2525
2525
  * // Reacts to locale changes automatically
2526
2526
  * Store.setLocale('en-US');
2527
2527
  */
2528
+
2529
+
2528
2530
  ObservableItem.prototype.format = function(type, options = {}) {
2529
2531
  const self = this;
2530
2532
 
@@ -2665,6 +2667,11 @@ var NativeComponents = (function (exports) {
2665
2667
  });
2666
2668
  };
2667
2669
 
2670
+ ObservableResource.prototype.into = function($observable) {
2671
+ this.data = $observable;
2672
+ return this;
2673
+ };
2674
+
2668
2675
  ObservableResource.prototype.$run = function(isRefetch = false) {
2669
2676
  const needsSignal = this.$fn.length > this.$dependencies.length;
2670
2677
  if(needsSignal) {
@@ -3136,27 +3143,31 @@ var NativeComponents = (function (exports) {
3136
3143
  const bindClassAttribute = (element, data) => {
3137
3144
  for(const className in data) {
3138
3145
  const value = data[className];
3139
- if(value.__$Observable) {
3140
- if(value.__$isObservableChecker) {
3141
- let lastClass = value.val();
3142
- if(typeof lastClass === 'string') {
3143
- element.classes.toggle(lastClass, true);
3144
- value.subscribe((currentValue) => {
3145
- element.classes.remove(lastClass);
3146
- element.classes.toggle(currentValue, true);
3147
- lastClass = currentValue;
3148
- });
3149
- continue;
3150
- }
3146
+
3147
+ if (value.__$isObservableChecker) {
3148
+ let lastClass = value.val();
3149
+ if (typeof lastClass === 'string') {
3150
+ element.classes.toggle(lastClass, true);
3151
+ value.subscribe((currentValue) => {
3152
+ element.classes.remove(lastClass);
3153
+ element.classes.toggle(currentValue, true);
3154
+ lastClass = currentValue;
3155
+ });
3156
+ continue;
3151
3157
  }
3158
+ }
3159
+
3160
+ if (value.__$Observable) {
3152
3161
  element.classes.toggle(className, value.val());
3153
3162
  value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
3154
3163
  continue;
3155
3164
  }
3156
- if(value.$hydrate) {
3165
+
3166
+ if (value.$hydrate) {
3157
3167
  value.$hydrate(element, className);
3158
3168
  continue;
3159
3169
  }
3170
+
3160
3171
  element.classes.toggle(className, value);
3161
3172
  }
3162
3173
  };
@@ -3214,12 +3225,12 @@ var NativeComponents = (function (exports) {
3214
3225
  * @param {boolean|number|Observable} value
3215
3226
  */
3216
3227
  const bindBooleanAttribute = (element, attributeName, value) => {
3217
- const isObservable = value.__$isObservable;
3228
+ const isObservable = value.__$Observable;
3218
3229
  const defaultValue = isObservable? value.val() : value;
3219
3230
 
3220
3231
  const attributeRealName = BOOL_ATTRIBUTES_NAME[attributeName];
3221
3232
 
3222
- if(Validator.isBoolean(defaultValue)) {
3233
+ if(typeof defaultValue === 'boolean') {
3223
3234
  element[attributeRealName] = defaultValue;
3224
3235
  }
3225
3236
  else {
@@ -3248,15 +3259,14 @@ var NativeComponents = (function (exports) {
3248
3259
  * @param {Observable} value
3249
3260
  */
3250
3261
  const bindAttributeWithObservable = (element, attributeName, value) => {
3251
- const applyValue = attributeName === 'value' ? (newValue) => element.value = newValue : (newValue) => element.setAttribute(attributeName, newValue);
3252
- value.subscribe(applyValue);
3253
-
3254
3262
  if(attributeName === 'value') {
3255
3263
  element.value = value.val();
3256
3264
  element.addEventListener('input', () => value.set(element.value));
3265
+ value.subscribe((newValue) => element.value = newValue);
3257
3266
  return;
3258
3267
  }
3259
3268
  element.setAttribute(attributeName, value.val());
3269
+ value.subscribe((newValue) => element.setAttribute(attributeName, newValue));
3260
3270
  };
3261
3271
 
3262
3272
  /**
@@ -3267,16 +3277,25 @@ var NativeComponents = (function (exports) {
3267
3277
  const AttributesWrapper = (element, attributes) => {
3268
3278
 
3269
3279
  for(const originalAttributeName in attributes) {
3270
- const attributeName = originalAttributeName.toLowerCase();
3271
3280
  const value = attributes[originalAttributeName];
3272
3281
  if(value == null) {
3273
3282
  continue;
3274
3283
  }
3275
- if(value.handleNdAttribute) {
3276
- value.handleNdAttribute(element, attributeName, value);
3284
+ const type = typeof value;
3285
+ if(type === 'string' || type === 'number') {
3286
+ element.setAttribute(originalAttributeName, value);
3277
3287
  continue;
3278
3288
  }
3279
- if(typeof value === 'object') {
3289
+ const attributeName = originalAttributeName.toLowerCase();
3290
+ if(value.__$Observable) {
3291
+ if(BOOLEAN_ATTRIBUTES.has(attributeName)) {
3292
+ bindBooleanAttribute(element, attributeName, value);
3293
+ continue;
3294
+ }
3295
+ bindAttributeWithObservable(element, originalAttributeName, value);
3296
+ continue;
3297
+ }
3298
+ if(type === 'object') {
3280
3299
  if(attributeName === 'class') {
3281
3300
  bindClassAttribute(element, value);
3282
3301
  continue;
@@ -3290,6 +3309,9 @@ var NativeComponents = (function (exports) {
3290
3309
  bindBooleanAttribute(element, attributeName, value);
3291
3310
  continue;
3292
3311
  }
3312
+ if(value.__$isTemplateBinding) {
3313
+ value.$hydrate(element, attributeName);
3314
+ }
3293
3315
 
3294
3316
  element.setAttribute(attributeName, value);
3295
3317
  }
@@ -3377,30 +3399,23 @@ var NativeComponents = (function (exports) {
3377
3399
 
3378
3400
  },
3379
3401
  getChild: (child) => {
3380
- if(child == null) {
3381
- return null;
3382
- }
3383
- if(child.toNdElement) {
3384
- do {
3385
- child = child.toNdElement();
3386
- if(Validator.isElement(child)) {
3387
- return child;
3388
- }
3389
- } while (child.toNdElement);
3402
+ if (child == null) return null;
3403
+
3404
+ child = child.toNdElement();
3405
+ if (child instanceof Node) return child;
3406
+
3407
+ while (child != null && !(child instanceof Node)) {
3408
+ child = child.toNdElement?.();
3390
3409
  }
3391
3410
 
3392
- return ElementCreator.createStaticTextNode(null, child);
3411
+ return child instanceof Node ? child : null;
3393
3412
  },
3394
3413
  /**
3395
3414
  *
3396
3415
  * @param {HTMLElement} element
3397
3416
  * @param {Object} attributes
3398
3417
  */
3399
- processAttributes: (element, attributes) => {
3400
- if (attributes) {
3401
- AttributesWrapper(element, attributes);
3402
- }
3403
- },
3418
+ processAttributes: AttributesWrapper,
3404
3419
  /**
3405
3420
  *
3406
3421
  * @param {HTMLElement} element
@@ -3992,8 +4007,19 @@ var NativeComponents = (function (exports) {
3992
4007
  NDElement.prototype.ghostDom = function(element) {
3993
4008
  if(!this.$attachements) {
3994
4009
  this.$attachements = document.createDocumentFragment();
4010
+ this.toNdElement = () => {
4011
+ const fragment = document.createDocumentFragment();
4012
+ if(!this.$attachements.contains(this.$element)) {
4013
+ fragment.appendChild(this.$element);
4014
+ }
4015
+ fragment.appendChild(this.$attachements);
4016
+ return fragment;
4017
+ };
4018
+ }
4019
+ const child = NDElement.$getChild(element);
4020
+ if(child) {
4021
+ this.$attachements.appendChild(child);
3995
4022
  }
3996
- this.$attachements.appendChild(NDElement.$getChild(element));
3997
4023
  return this;
3998
4024
  };
3999
4025
 
@@ -6942,7 +6968,6 @@ var NativeComponents = (function (exports) {
6942
6968
  /**
6943
6969
  * Versatile content container with optional image, header, footer, actions. Supports clickable, hoverable, loading, and horizontal layouts.
6944
6970
  *
6945
- *
6946
6971
  * @example
6947
6972
  * const card = new Card()
6948
6973
  * .title(Span('Card title'))
@@ -6958,42 +6983,80 @@ var NativeComponents = (function (exports) {
6958
6983
  * });
6959
6984
  *
6960
6985
  * @constructor
6961
- * @param {GlobalAttributes} [config={}]
6986
+ * @param {GlobalAttributes} [props={}]
6962
6987
  */
6963
- function Card(config = {}) {
6964
- if(!(this instanceof Card)) {
6965
- return new Card(config);
6988
+ function Card(props = {}) {
6989
+ if (!(this instanceof Card)) {
6990
+ return new Card(props);
6966
6991
  }
6992
+
6967
6993
  this.$description = {
6968
- ...config,
6994
+ title: null,
6995
+ subtitle: null,
6996
+ image: null,
6997
+ imagePosition: 'top',
6998
+ content: null,
6999
+ variant: null,
7000
+ loading: null,
7001
+ horizontal: false,
7002
+ hoverable: false,
7003
+ actions: [],
7004
+ renderImage: null,
7005
+ renderHeader: null,
7006
+ renderContent: null,
7007
+ renderFooter: null,
7008
+ renderActions: null,
7009
+ layout: null,
7010
+ props,
6969
7011
  };
6970
7012
  }
7013
+
6971
7014
  BaseComponent.extends(Card);
7015
+ BaseComponent.use(Card, HasEventEmitter);
6972
7016
 
6973
7017
  Card.defaultTemplate = null;
6974
7018
 
6975
7019
  /**
6976
7020
  * Registers the render template for Card.
6977
7021
  * @param {(description: {
6978
- * [key: string]: unknown,
7022
+ * title: NdChild|null,
7023
+ * subtitle: NdChild|null,
7024
+ * image: string|null,
7025
+ * imagePosition: 'top'|'bottom'|'left'|'right',
7026
+ * content: NdChild|null,
7027
+ * variant: 'elevated'|'outlined'|'flat'|string|null,
7028
+ * loading: Observable<boolean>|null,
7029
+ * horizontal: boolean,
7030
+ * hoverable: boolean,
7031
+ * actions: { label: NdChild, callback: () => void }[],
7032
+ * renderImage: ((desc: *, instance: Card) => NdChild)|null,
7033
+ * renderHeader: ((desc: *, instance: Card) => NdChild)|null,
7034
+ * renderContent: ((desc: *, instance: Card) => NdChild)|null,
7035
+ * renderFooter: ((desc: *, instance: Card) => NdChild)|null,
7036
+ * renderActions: ((desc: *, instance: Card) => NdChild)|null,
7037
+ * layout: ((slots: { header: NdChild, content: NdChild, footer: NdChild, image: NdChild, actions: NdChild }, instance: Card) => NdChild)|null,
6979
7038
  * props: GlobalAttributes,
6980
7039
  * }, instance: Card) => NdChild} template
6981
7040
  */
6982
- Card.use = function(template) {};
7041
+ Card.use = function(template) {
7042
+ Card.defaultTemplate = template;
7043
+ };
6983
7044
 
6984
7045
  /**
6985
7046
  * @param {NdChild} title
6986
7047
  * @returns {this}
6987
7048
  */
6988
7049
  Card.prototype.title = function(title) {
7050
+ this.$description.title = title;
6989
7051
  return this;
6990
7052
  };
6991
7053
 
6992
7054
  /**
6993
- * @param {NdChild} title
7055
+ * @param {NdChild} subtitle
6994
7056
  * @returns {this}
6995
7057
  */
6996
- Card.prototype.subtitle = function(title) {
7058
+ Card.prototype.subtitle = function(subtitle) {
7059
+ this.$description.subtitle = subtitle;
6997
7060
  return this;
6998
7061
  };
6999
7062
 
@@ -7003,6 +7066,8 @@ var NativeComponents = (function (exports) {
7003
7066
  * @returns {this}
7004
7067
  */
7005
7068
  Card.prototype.image = function(src, position = 'top') {
7069
+ this.$description.image = src;
7070
+ this.$description.imagePosition = position;
7006
7071
  return this;
7007
7072
  };
7008
7073
 
@@ -7011,6 +7076,7 @@ var NativeComponents = (function (exports) {
7011
7076
  * @returns {this}
7012
7077
  */
7013
7078
  Card.prototype.content = function(content) {
7079
+ this.$description.content = content;
7014
7080
  return this;
7015
7081
  };
7016
7082
 
@@ -7021,51 +7087,55 @@ var NativeComponents = (function (exports) {
7021
7087
  * @returns {this}
7022
7088
  */
7023
7089
  Card.prototype.variant = function(name) {
7090
+ this.$description.variant = name;
7024
7091
  return this;
7025
7092
  };
7026
7093
 
7027
7094
  /**
7028
7095
  * @returns {this}
7029
7096
  */
7030
- Card.prototype.outlined = function() {
7031
- return this;
7097
+ Card.prototype.elevated = function() {
7098
+ return this.variant('elevated');
7032
7099
  };
7033
7100
 
7034
7101
  /**
7035
7102
  * @returns {this}
7036
7103
  */
7037
- Card.prototype.elevated = function() {
7038
- return this;
7104
+ Card.prototype.outlined = function() {
7105
+ return this.variant('outlined');
7039
7106
  };
7040
7107
 
7041
7108
  /**
7042
7109
  * @returns {this}
7043
7110
  */
7044
7111
  Card.prototype.flat = function() {
7045
- return this;
7112
+ return this.variant('flat');
7046
7113
  };
7047
7114
 
7048
7115
  // Behavior
7116
+
7049
7117
  /**
7050
7118
  * @param {Function} handler
7051
7119
  * @returns {this}
7052
7120
  */
7053
7121
  Card.prototype.clickable = function(handler) {
7054
- return this;
7122
+ return this.onClick(handler);
7055
7123
  };
7056
7124
 
7057
7125
  /**
7058
7126
  * @returns {this}
7059
7127
  */
7060
7128
  Card.prototype.hoverable = function() {
7129
+ this.$description.hoverable = true;
7061
7130
  return this;
7062
7131
  };
7063
7132
 
7064
7133
  /**
7065
- * @param {boolean|Observable<boolean>} [isLoading]
7134
+ * @param {boolean|Observable<boolean>} [isLoading=true]
7066
7135
  * @returns {this}
7067
7136
  */
7068
7137
  Card.prototype.loading = function(isLoading = true) {
7138
+ this.$description.loading = BaseComponent.obs(isLoading);
7069
7139
  return this;
7070
7140
  };
7071
7141
 
@@ -7075,46 +7145,54 @@ var NativeComponents = (function (exports) {
7075
7145
  * @returns {this}
7076
7146
  */
7077
7147
  Card.prototype.horizontal = function() {
7148
+ this.$description.horizontal = true;
7078
7149
  return this;
7079
7150
  };
7080
7151
 
7081
- // Events
7152
+ // Actions
7153
+
7082
7154
  /**
7083
- * @param {Function} handler
7155
+ * @param {NdChild} label
7156
+ * @param {() => void} callback
7084
7157
  * @returns {this}
7085
7158
  */
7086
- Card.prototype.onClick = function(handler) {
7159
+ Card.prototype.action = function(label, callback) {
7160
+ this.$description.actions.push({ label, callback });
7087
7161
  return this;
7088
7162
  };
7089
7163
 
7090
7164
  /**
7091
- * @param {Function} handler
7092
7165
  * @returns {this}
7093
7166
  */
7094
- Card.prototype.onHover = function(handler) {
7167
+ Card.prototype.clearActions = function() {
7168
+ this.$description.actions = [];
7095
7169
  return this;
7096
7170
  };
7097
7171
 
7172
+ // Events
7173
+
7098
7174
  /**
7175
+ * @param {Function} handler
7099
7176
  * @returns {this}
7100
7177
  */
7101
- Card.prototype.clearActions = function() {
7102
- this.$description.actions = [];
7178
+ Card.prototype.onClick = function(handler) {
7179
+ this.on('click', handler);
7103
7180
  return this;
7104
7181
  };
7105
7182
 
7106
7183
  /**
7107
- * @param {NdChild} label
7108
- * @param {() => void} callback
7184
+ * @param {Function} handler
7109
7185
  * @returns {this}
7110
7186
  */
7111
- Card.prototype.action = function(label, callback) {
7112
- this.$description.actions.push({ label, callback });
7187
+ Card.prototype.onHover = function(handler) {
7188
+ this.on('hover', handler);
7113
7189
  return this;
7114
7190
  };
7115
7191
 
7192
+ // Custom renderers
7193
+
7116
7194
  /**
7117
- * @param {(desc: *, instance: *) => NdChild} renderFn
7195
+ * @param {(desc: *, instance: Card) => NdChild} renderFn
7118
7196
  * @returns {this}
7119
7197
  */
7120
7198
  Card.prototype.renderImage = function(renderFn) {
@@ -7123,7 +7201,7 @@ var NativeComponents = (function (exports) {
7123
7201
  };
7124
7202
 
7125
7203
  /**
7126
- * @param {(desc: *, instance: *) => NdChild} renderFn
7204
+ * @param {(desc: *, instance: Card) => NdChild} renderFn
7127
7205
  * @returns {this}
7128
7206
  */
7129
7207
  Card.prototype.renderHeader = function(renderFn) {
@@ -7132,7 +7210,7 @@ var NativeComponents = (function (exports) {
7132
7210
  };
7133
7211
 
7134
7212
  /**
7135
- * @param {(desc: *, instance: *) => NdChild} renderFn
7213
+ * @param {(desc: *, instance: Card) => NdChild} renderFn
7136
7214
  * @returns {this}
7137
7215
  */
7138
7216
  Card.prototype.renderContent = function(renderFn) {
@@ -7141,7 +7219,7 @@ var NativeComponents = (function (exports) {
7141
7219
  };
7142
7220
 
7143
7221
  /**
7144
- * @param {(desc: *, instance: *) => NdChild} renderFn
7222
+ * @param {(desc: *, instance: Card) => NdChild} renderFn
7145
7223
  * @returns {this}
7146
7224
  */
7147
7225
  Card.prototype.renderFooter = function(renderFn) {
@@ -7150,18 +7228,20 @@ var NativeComponents = (function (exports) {
7150
7228
  };
7151
7229
 
7152
7230
  /**
7153
- * @param {(desc: *, instance: *) => NdChild} layoutFn
7231
+ * @param {(desc: *, instance: Card) => NdChild} renderFn
7154
7232
  * @returns {this}
7155
7233
  */
7156
- Card.prototype.layout = function(layoutFn) {
7157
- this.$description.layout = layoutFn;
7234
+ Card.prototype.renderActions = function(renderFn) {
7235
+ this.$description.renderActions = renderFn;
7158
7236
  return this;
7159
7237
  };
7160
7238
 
7161
7239
  /**
7162
- * @returns {HTMLElement|DocumentFragment}
7240
+ * @param {(slots: { header: NdChild, content: NdChild, footer: NdChild, image: NdChild, actions: NdChild }, instance: Card) => NdChild} layoutFn
7241
+ * @returns {this}
7163
7242
  */
7164
- Card.prototype.toNdElement = function() {
7243
+ Card.prototype.layout = function(layoutFn) {
7244
+ this.$description.layout = layoutFn;
7165
7245
  return this;
7166
7246
  };
7167
7247
 
@@ -15006,158 +15086,295 @@ var NativeComponents = (function (exports) {
15006
15086
  };
15007
15087
 
15008
15088
  /**
15009
- * Flexible list container supporting single/multi selection, checkbox or click-to-select modes, dividers, and inset styling.
15010
- *
15089
+ * Visual separator between items in a List.
15011
15090
  *
15012
15091
  * @example
15013
- * const list = new List()
15014
- * .selectable(true)
15015
- * .multiSelect(true)
15016
- * .withDivider(true)
15017
- * .onItemClick((item, e) => console.log(item))
15018
- * .onItemSelect((item) => console.log('selected', item));
15092
+ * List()
15093
+ * .item('Dashboard')
15094
+ * .divider()
15095
+ * .item('Settings')
15019
15096
  *
15020
- * List.use((description, instance) => {
15021
- * return Ul({ class: 'list' });
15097
+ * ListDivider.use((description, instance) => {
15098
+ * return Li({ class: 'list-divider', role: 'separator' });
15022
15099
  * });
15023
15100
  *
15024
15101
  * @constructor
15025
- * @param {GlobalAttributes} [config]
15102
+ * @param {GlobalAttributes} [props={}]
15026
15103
  */
15027
- function List(config = {}) {
15028
- if(!(this instanceof List)) {
15029
- return new List(config);
15104
+ function ListDivider(props = {}) {
15105
+ if (!(this instanceof ListDivider)) {
15106
+ return new ListDivider(props);
15030
15107
  }
15031
15108
 
15032
- this.$description = {
15033
- selectable: false,
15034
- multiSelect: false,
15035
- selectedValues: null,
15036
- inset: false,
15037
- divider: false,
15038
- data: null,
15039
- render: null,
15040
- selectByCheckbox: false,
15041
- selectByClick: false,
15042
- loopOnKeyboard: true,
15043
- ...config,
15044
- };
15109
+ BaseComponent.call(this, props);
15045
15110
 
15111
+ this.$description = { props };
15046
15112
  }
15047
15113
 
15048
- List.defaultTemplate = null;
15114
+ BaseComponent.extends(ListDivider);
15115
+
15116
+ ListDivider.defaultTemplate = null;
15049
15117
 
15050
15118
  /**
15051
- * Registers the render template for List.
15052
- * @param {(description: {
15053
- * selectable: boolean,
15054
- * multiSelect: boolean,
15055
- * selectedValues: Observable<*[]>|null,
15056
- * inset: boolean,
15057
- * divider: boolean,
15058
- * data: *|null,
15059
- * render: ((desc: *, instance: List) => NdChild)|null,
15060
- * selectByCheckbox: boolean,
15061
- * selectByClick: boolean,
15062
- * loopOnKeyboard: boolean,
15063
- * props: GlobalAttributes,
15064
- * }, instance: List) => NdChild} template
15119
+ * Registers the render template for ListDivider.
15120
+ * @param {(description: { props: GlobalAttributes }, instance: ListDivider) => NdChild} template
15065
15121
  */
15066
- List.use = function(template) {
15067
- List.defaultTemplate = template.list;
15122
+ ListDivider.use = function(template) {
15123
+ ListDivider.defaultTemplate = template;
15068
15124
  };
15069
15125
 
15070
- BaseComponent.extends(List);
15071
- BaseComponent.use(List, HasItems, HasEventEmitter);
15126
+ /**
15127
+ * Trait that adds item/group/divider management to List and ListGroup.
15128
+ * Mirrors the HasMenuItem pattern.
15129
+ *
15130
+ * @constructor
15131
+ */
15132
+ function HasListItem() {}
15072
15133
 
15073
- List.defaultTemplate = null;
15134
+ HasListItem.components = {
15135
+ ListItem: null,
15136
+ ListGroup: null,
15137
+ };
15074
15138
 
15075
- List.use = function(template) {
15076
- List.defaultTemplate = template.list;
15139
+
15140
+ /**
15141
+ * @param {ObservableArray<*>|*[]} list
15142
+ * @returns {this}
15143
+ */
15144
+ HasListItem.prototype.selectInto = function(list) {
15145
+ this.$description.selectedValues = list;
15146
+ return this;
15077
15147
  };
15078
15148
 
15079
15149
  /**
15080
- * @param {*} [selectable]
15150
+ * @param {boolean|Observable<boolean>} [selectable=true]
15081
15151
  * @returns {this}
15082
15152
  */
15083
- List.prototype.selectable = function(selectable = true) {
15084
- this.$description.selectable = selectable;
15153
+ HasListItem.prototype.selectable = function(selectable = true) {
15154
+ this.$description.selectable = BaseComponent.obs(selectable);
15085
15155
  return this;
15086
15156
  };
15087
15157
 
15088
15158
  /**
15159
+ * Select items on click. Mutually exclusive with selectByCheckbox.
15089
15160
  * @returns {this}
15090
15161
  */
15091
- List.prototype.selectByClick = function() {
15092
- this.$description.selectByClick = true;
15093
- this.$description.selectByCheckbox = false;
15162
+ HasListItem.prototype.selectByClick = function() {
15163
+ this.$description.selectByClick.set(true);
15164
+ this.$description.selectByCheckbox.set(false);
15094
15165
  return this;
15095
15166
  };
15096
15167
 
15097
15168
  /**
15169
+ * Select items via a checkbox. Mutually exclusive with selectByClick.
15098
15170
  * @returns {this}
15099
15171
  */
15100
- List.prototype.selectByCheckbox = function() {
15101
- this.$description.selectByClick = false;
15102
- this.$description.selectByCheckbox = true;
15172
+ HasListItem.prototype.selectByCheckbox = function() {
15173
+ this.$description.selectByClick.set(false);
15174
+ this.$description.selectByCheckbox.set(true);
15103
15175
  return this;
15104
15176
  };
15105
15177
 
15106
15178
  /**
15107
- * @param {*} [multi]
15179
+ * @param {boolean|Observable<boolean>} [multi=true]
15108
15180
  * @returns {this}
15109
15181
  */
15110
- List.prototype.multiSelect = function(multi = true) {
15111
- this.$description.multiSelect = multi;
15112
- this.$description.selectable = true;
15182
+ HasListItem.prototype.multiSelect = function(multi = true) {
15183
+ this.$description.multiSelect = BaseComponent.obs(multi);
15184
+ this.$description.selectable.set(true);
15113
15185
  return this;
15114
15186
  };
15115
15187
 
15116
15188
  /**
15117
- * @param {Observable<*[]>} observable
15189
+ * @param {boolean} loopOnKeyboard
15118
15190
  * @returns {this}
15119
15191
  */
15120
- List.prototype.selectedValuesModel = function(observable) {
15121
- this.$description.selectedValues = observable;
15192
+ HasListItem.prototype.loopOnKeyboard = function(loopOnKeyboard) {
15193
+ this.$description.loopOnKeyboard = loopOnKeyboard;
15122
15194
  return this;
15123
15195
  };
15124
15196
 
15125
15197
  /**
15126
- * @param {number} [inset]
15198
+ * @param {ListItem|ListGroup|ListDivider} item
15127
15199
  * @returns {this}
15128
15200
  */
15129
- List.prototype.inset = function(inset = true) {
15130
- this.$description.inset = inset;
15201
+ HasListItem.prototype.add = function(item) {
15202
+ if (item === this) {
15203
+ return this;
15204
+ }
15205
+ item.$parent = this;
15206
+ this.$description.items.push(item);
15131
15207
  return this;
15132
15208
  };
15133
15209
 
15134
15210
  /**
15211
+ * @param {NdChild} label
15212
+ * @param {NdChild|((item: ListItem) => void)} [iconOrBuilder]
15213
+ * @param {((item: ListItem) => void)} [builder]
15135
15214
  * @returns {this}
15136
15215
  */
15137
- List.prototype.next = function() {
15138
- // TODO:
15216
+ HasListItem.prototype.item = function(label, iconOrBuilder, builder) {
15217
+ const ListItem = HasListItem.components.ListItem;
15218
+ const item = new ListItem();
15219
+ item.$parent = this;
15220
+
15221
+ item.label(label);
15222
+
15223
+ if (typeof iconOrBuilder === 'function') {
15224
+ iconOrBuilder(item);
15225
+ } else if (iconOrBuilder) {
15226
+ item.icon(iconOrBuilder);
15227
+ if (typeof builder === 'function') {
15228
+ builder(item);
15229
+ }
15230
+ }
15231
+
15232
+ this.$description.items.push(item);
15139
15233
  return this;
15140
15234
  };
15141
15235
 
15142
15236
  /**
15237
+ * @param {NdChild} label
15238
+ * @param {NdChild|((group: ListGroup) => void)} [iconOrBuilder]
15239
+ * @param {((group: ListGroup) => void)} [builder]
15143
15240
  * @returns {this}
15144
15241
  */
15145
- List.prototype.preview = function() {
15146
- // TODO:
15242
+ HasListItem.prototype.group = function(label, iconOrBuilder, builder) {
15243
+ const ListGroup = HasListItem.components.ListGroup;
15244
+ const group = new ListGroup(label);
15245
+ group.$parent = this;
15246
+
15247
+ if (typeof iconOrBuilder === 'function') {
15248
+ iconOrBuilder(group);
15249
+ } else if (iconOrBuilder) {
15250
+ group.icon(iconOrBuilder);
15251
+ if (typeof builder === 'function') {
15252
+ builder(group);
15253
+ }
15254
+ }
15255
+
15256
+ this.$description.items.push(group);
15147
15257
  return this;
15148
15258
  };
15149
15259
 
15150
15260
  /**
15151
- * @param {*} loopOnKeyboard
15152
15261
  * @returns {this}
15153
15262
  */
15154
- List.prototype.loopOnKeyboard = function(loopOnKeyboard) {
15155
- this.$description.loopOnKeyboard = loopOnKeyboard;
15263
+ HasListItem.prototype.divider = function() {
15264
+ const divider = new ListDivider();
15265
+ divider.$parent = this;
15266
+ this.$description.items.push(divider);
15156
15267
  return this;
15157
15268
  };
15158
15269
 
15270
+
15159
15271
  /**
15160
- * @param {*} [divider]
15272
+ * Populate items from a data source using a builder function.
15273
+ * The builder receives each data item and must return a ListItem or ListGroup.
15274
+ *
15275
+ * @param {ObservableArray<*>|*[]} source
15276
+ * @param {(item: *) => ListItem|ListGroup} builder
15277
+ * @returns {this}
15278
+ */
15279
+ HasListItem.prototype.from = function(source, builder) {
15280
+ this.$description.items = source;
15281
+ this.$description.itemBuilder = (...args) => {
15282
+ if(args[0].__$ListInstance) {
15283
+ return args[0];
15284
+ }
15285
+ const item = builder(...args);
15286
+ item.$parent = this;
15287
+ return item;
15288
+ };
15289
+ return this;
15290
+ };
15291
+
15292
+ /**
15293
+ * Flexible list container supporting single/multi selection, checkbox or click-to-select modes, dividers, and inset styling.
15294
+ *
15295
+ * @example
15296
+ * const list = new List()
15297
+ * .selectable(true)
15298
+ * .multiSelect(true)
15299
+ * .withDivider(true)
15300
+ * .onItemClick((item, e) => console.log(item))
15301
+ * .onItemSelect((item) => console.log('selected', item));
15302
+ *
15303
+ * List.use((description, instance) => {
15304
+ * return Ul({ class: 'list' });
15305
+ * });
15306
+ *
15307
+ * @constructor
15308
+ * @param {GlobalAttributes} [props]
15309
+ */
15310
+ function List(props = {}) {
15311
+ if (!(this instanceof List)) {
15312
+ return new List(props);
15313
+ }
15314
+
15315
+ this.$description = {
15316
+ selectable: $(false),
15317
+ multiSelect: $(false),
15318
+ selectedValues: $.array(),
15319
+ inset: $(0),
15320
+ divider: false,
15321
+ items: $.array(),
15322
+ render: null,
15323
+ selectByCheckbox: $(false),
15324
+ selectByClick: $(false),
15325
+ loopOnKeyboard: $(false),
15326
+ props,
15327
+ };
15328
+ }
15329
+
15330
+ List.defaultTemplate = null;
15331
+
15332
+ /**
15333
+ * Registers the render template for List.
15334
+ * @param {(description: {
15335
+ * selectable: ObservableItem<boolean>,
15336
+ * multiSelect: ObservableItem<boolean>,
15337
+ * selectedValues: ObservableArray<*>,
15338
+ * inset: ObservableItem<number>,
15339
+ * divider: boolean,
15340
+ * data: *|null,
15341
+ * render: ((desc: *, instance: List) => NdChild)|null,
15342
+ * selectByCheckbox: ObservableItem<boolean>,
15343
+ * selectByClick: ObservableItem<boolean>,
15344
+ * loopOnKeyboard: ObservableItem<boolean>,
15345
+ * items: ObservableArray<*>,
15346
+ * props: GlobalAttributes,
15347
+ * }, instance: List) => NdChild} template
15348
+ */
15349
+ List.use = function(template) {
15350
+ List.defaultTemplate = template;
15351
+ };
15352
+
15353
+ BaseComponent.extends(List);
15354
+ BaseComponent.use(List, HasItems, HasEventEmitter, HasListItem);
15355
+
15356
+
15357
+ /**
15358
+ * @param {ObservableArray<*>|Observable<*[]>} observable
15359
+ * @returns {this}
15360
+ */
15361
+ List.prototype.selectedValuesModel = function(observable) {
15362
+ this.$description.selectedValues = observable;
15363
+ return this;
15364
+ };
15365
+
15366
+ /**
15367
+ * Inset padding in px applied to all items.
15368
+ * @param {number} [inset=0]
15369
+ * @returns {this}
15370
+ */
15371
+ List.prototype.inset = function(inset = 0) {
15372
+ this.$description.inset.set(inset);
15373
+ return this;
15374
+ };
15375
+
15376
+ /**
15377
+ * @param {boolean} [divider=true]
15161
15378
  * @returns {this}
15162
15379
  */
15163
15380
  List.prototype.withDivider = function(divider = true) {
@@ -15170,12 +15387,12 @@ var NativeComponents = (function (exports) {
15170
15387
  * @returns {this}
15171
15388
  */
15172
15389
  List.prototype.data = function(data) {
15173
- this.$description.data = data;
15390
+ this.$description.items = data;
15174
15391
  return this;
15175
15392
  };
15176
15393
 
15177
15394
  /**
15178
- * @param {(item: ListItem, event: MouseEvent) => void} handler
15395
+ * @param {(item: *, event: MouseEvent) => void} handler
15179
15396
  * @returns {this}
15180
15397
  */
15181
15398
  List.prototype.onItemClick = function(handler) {
@@ -15184,7 +15401,7 @@ var NativeComponents = (function (exports) {
15184
15401
  };
15185
15402
 
15186
15403
  /**
15187
- * @param {(item: ListItem) => void} handler
15404
+ * @param {(item: *) => void} handler
15188
15405
  * @returns {this}
15189
15406
  */
15190
15407
  List.prototype.onItemSelect = function(handler) {
@@ -15193,62 +15410,79 @@ var NativeComponents = (function (exports) {
15193
15410
  };
15194
15411
 
15195
15412
  /**
15196
- * A single row inside a List. Supports leading/trailing slots, icon, selection, divider, and disabled state.
15197
- *
15413
+ * A single item in a List. Supports icon, label, subtitle, trailing slot,
15414
+ * disabled/selected states, swipe actions (mobile), and custom render.
15198
15415
  *
15199
15416
  * @example
15200
- * const item = new ListItem(Span('Item label'))
15201
- * .icon(StarIcon())
15202
- * .trailing(Span('chevron >'))
15203
- * .selectable()
15204
- * .divider(true);
15417
+ * ListItem()
15418
+ * .label('Dashboard')
15419
+ * .icon(DashboardIcon())
15420
+ * .subtitle('View your metrics')
15421
+ * .trailing(Badge('New').primary())
15422
+ * .value('dashboard')
15423
+ * .selected(isActive)
15424
+ * .swipeLeading([Button('Archive').success()])
15425
+ * .swipeTrailing([Button('Delete').danger()])
15426
+ * .onClick(() => navigate('/dashboard'));
15205
15427
  *
15206
15428
  * ListItem.use((description, instance) => {
15207
- * return Li(description.leading, description.content, description.trailing);
15429
+ * return Li({ class: 'list-item' }, description.label);
15208
15430
  * });
15209
15431
  *
15210
15432
  * @constructor
15211
- * @param {NdChild} [content]
15212
- * @param {GlobalAttributes} [config={}]
15433
+ * @param {GlobalAttributes} [props={}]
15213
15434
  */
15214
- function ListItem(content, config = {}) {
15215
- if(!(this instanceof ListItem)) {
15216
- return new ListItem(content, config);
15435
+ function ListItem(props = {}) {
15436
+ if (!(this instanceof ListItem)) {
15437
+ return new ListItem(props);
15217
15438
  }
15218
15439
 
15440
+ BaseComponent.call(this, props);
15441
+
15219
15442
  this.$description = {
15220
- content: content || null,
15221
- icon: null,
15222
- trailing: null,
15223
- leading: null,
15224
- disabled: false,
15225
- selectable: false,
15226
- selected: false,
15227
- divider: false,
15228
- data: null,
15229
- render: null,
15230
- ...config,
15443
+ label: null,
15444
+ subtitle: null,
15445
+ icon: null,
15446
+ trailing: null,
15447
+ value: null,
15448
+ data: null,
15449
+ key: null,
15450
+ disabled: null,
15451
+ selected: null,
15452
+ visibility: null,
15453
+ isSelectedIcon: null,
15454
+ swipeLeading: [],
15455
+ swipeTrailing: [],
15456
+ render: null,
15457
+ props,
15231
15458
  };
15232
15459
  }
15233
15460
 
15234
15461
  BaseComponent.extends(ListItem);
15462
+ BaseComponent.use(ListItem, HasEventEmitter);
15463
+
15464
+ HasListItem.components.ListItem = ListItem;
15235
15465
 
15236
15466
  ListItem.defaultTemplate = null;
15237
15467
 
15238
15468
  /**
15239
15469
  * Registers the render template for ListItem.
15240
15470
  * @param {(description: {
15241
- * content: NdChild|null,
15242
- * icon: NdChild|null,
15243
- * trailing: NdChild|null,
15244
- * leading: NdChild|null,
15245
- * disabled: boolean,
15246
- * selectable: boolean,
15247
- * selected: boolean|Observable<boolean>,
15248
- * divider: boolean,
15249
- * data: *|null,
15250
- * render: ((desc: *, instance: ListItem) => NdChild)|null,
15251
- * props: GlobalAttributes,
15471
+ * label: NdChild|null,
15472
+ * subtitle: NdChild|null,
15473
+ * icon: NdChild|null,
15474
+ * trailing: NdChild|null,
15475
+ * value: *,
15476
+ * data: *|null,
15477
+ * key: string|null,
15478
+ * disabled: Observable<boolean>|null,
15479
+ * selected: Observable<boolean>|null,
15480
+ * visibility: Observable<boolean>|null,
15481
+ * isSelectedIcon: NdChild|null,
15482
+ * swipeLeading: NdChild[],
15483
+ * swipeTrailing: NdChild[],
15484
+ * render: ((desc: *, instance: ListItem) => NdChild)|null,
15485
+ * props: GlobalAttributes,
15252
15486
  * }, instance: ListItem) => NdChild} template
15253
15487
  */
15254
15488
  ListItem.use = function(template) {
@@ -15256,20 +15490,20 @@ var NativeComponents = (function (exports) {
15256
15490
  };
15257
15491
 
15258
15492
  /**
15259
- * @param {NdChild} content
15493
+ * @param {NdChild} label
15260
15494
  * @returns {this}
15261
15495
  */
15262
- ListItem.prototype.content = function(content) {
15263
- this.$description.content = content;
15496
+ ListItem.prototype.label = function(label) {
15497
+ this.$description.label = label;
15264
15498
  return this;
15265
15499
  };
15266
15500
 
15267
15501
  /**
15268
- * @param {NdChild} label
15502
+ * @param {NdChild} subtitle
15269
15503
  * @returns {this}
15270
15504
  */
15271
- ListItem.prototype.label = function(label) {
15272
- this.$description.content = label;
15505
+ ListItem.prototype.subtitle = function(subtitle) {
15506
+ this.$description.subtitle = subtitle;
15273
15507
  return this;
15274
15508
  };
15275
15509
 
@@ -15283,124 +15517,177 @@ var NativeComponents = (function (exports) {
15283
15517
  };
15284
15518
 
15285
15519
  /**
15286
- * @param {NdChild} leading
15520
+ * @param {NdChild} trailing
15287
15521
  * @returns {this}
15288
15522
  */
15289
- ListItem.prototype.leading = function(leading) {
15290
- this.$description.leading = leading;
15523
+ ListItem.prototype.trailing = function(trailing) {
15524
+ this.$description.trailing = trailing;
15291
15525
  return this;
15292
15526
  };
15293
15527
 
15294
15528
  /**
15295
- * @param {NdChild} trailing
15529
+ * @param {*} value
15296
15530
  * @returns {this}
15297
15531
  */
15298
- ListItem.prototype.trailing = function(trailing) {
15299
- this.$description.trailing = trailing;
15532
+ ListItem.prototype.value = function(value) {
15533
+ this.$description.value = value;
15300
15534
  return this;
15301
15535
  };
15302
15536
 
15537
+ /**
15538
+ * @param {*} data
15539
+ * @returns {this}
15540
+ */
15541
+ ListItem.prototype.data = function(data) {
15542
+ this.$description.data = data;
15543
+ return this;
15544
+ };
15545
+
15546
+ /**
15547
+ * @param {string} key
15548
+ * @returns {this}
15549
+ */
15550
+ ListItem.prototype.key = function(key) {
15551
+ this.$description.key = key;
15552
+ return this;
15553
+ };
15303
15554
 
15304
15555
  /**
15305
15556
  * @param {boolean|Observable<boolean>} [disabled=true]
15306
15557
  * @returns {this}
15307
15558
  */
15308
15559
  ListItem.prototype.disabled = function(disabled = true) {
15309
- this.$description.disabled = disabled;
15560
+ this.$description.disabled = BaseComponent.obs(disabled);
15310
15561
  return this;
15311
15562
  };
15312
15563
 
15313
15564
  /**
15565
+ * @param {boolean|Observable<boolean>} [selected=true]
15314
15566
  * @returns {this}
15315
15567
  */
15316
- ListItem.prototype.selectable = function() {
15317
- this.$description.selectable = true;
15318
- if(Validator.isObservable(this.$description.selected)) {
15319
- return this;
15320
- }
15321
- this.$description.selected = $(false);
15568
+ ListItem.prototype.selected = function(selected = true) {
15569
+ this.$description.selected = BaseComponent.obs(selected);
15322
15570
  return this;
15323
15571
  };
15324
15572
 
15325
15573
  /**
15326
- * @param {boolean|Observable<boolean>} [selected]
15574
+ * @param {boolean|Observable<boolean>} mode
15327
15575
  * @returns {this}
15328
15576
  */
15329
- ListItem.prototype.selected = function(selected = true) {
15330
- if(Validator.isObservable(this.$description.selected)) {
15331
- this.$description.selected.set(selected);
15332
- return this;
15333
- }
15334
- this.$description.selected = selected;
15577
+ ListItem.prototype.visibility = function(mode) {
15578
+ this.$description.visibility = BaseComponent.obs(mode);
15335
15579
  return this;
15336
15580
  };
15337
15581
 
15338
15582
  /**
15339
- * @param {NdChild} [show]
15583
+ * Icon displayed when the item is selected (selectByClick mode).
15584
+ * @param {NdChild} icon
15340
15585
  * @returns {this}
15341
15586
  */
15342
- ListItem.prototype.divider = function(show = true) {
15343
- this.$description.divider = show;
15587
+ ListItem.prototype.isSelectedIcon = function(icon) {
15588
+ this.$description.isSelectedIcon = icon;
15344
15589
  return this;
15345
15590
  };
15346
15591
 
15347
15592
  /**
15348
- * @param {*} data
15593
+ * Swipe actions revealed on the leading (left) side — mobile swipe gesture.
15594
+ * @param {NdChild[]} actions
15349
15595
  * @returns {this}
15350
15596
  */
15351
- ListItem.prototype.data = function(data) {
15352
- this.$description.data = data;
15597
+ ListItem.prototype.swipeLeading = function(actions) {
15598
+ this.$description.swipeLeading = Array.isArray(actions) ? actions : [actions];
15353
15599
  return this;
15354
15600
  };
15355
15601
 
15356
15602
  /**
15357
- * Groups ListItem instances under a header/footer inside a List.
15358
- *
15603
+ * Swipe actions revealed on the trailing (right) side — mobile swipe gesture.
15604
+ * @param {NdChild[]} actions
15605
+ * @returns {this}
15606
+ */
15607
+ ListItem.prototype.swipeTrailing = function(actions) {
15608
+ this.$description.swipeTrailing = Array.isArray(actions) ? actions : [actions];
15609
+ return this;
15610
+ };
15611
+
15612
+ /**
15613
+ * @param {Function} handler
15614
+ * @returns {this}
15615
+ */
15616
+ ListItem.prototype.onClick = function(handler) {
15617
+ this.on('click', handler);
15618
+ return this;
15619
+ };
15620
+
15621
+ /**
15622
+ * A collapsible group of ListItems inside a List. Can hold items, dividers, and nested groups.
15359
15623
  *
15360
15624
  * @example
15361
- * const group = new ListGroup(Span('Favourites'))
15362
- * .inset(true)
15363
- * .renderHeader((desc, instance) => H3(desc.header));
15625
+ * ListGroup('Workspace')
15626
+ * .icon(FolderIcon())
15627
+ * .collapsable()
15628
+ * .item('Dashboard', DashboardIcon())
15629
+ * .item('Analytics', ChartIcon());
15630
+ *
15631
+ * // From data
15632
+ * ListGroup('Reports')
15633
+ * .from(reports, (report) =>
15634
+ * ListItem().label(report.name).value(report.id)
15635
+ * );
15636
+ *
15637
+ * ListGroup.use((description, instance) => {
15638
+ * return Div({ class: 'list-group' });
15639
+ * });
15364
15640
  *
15365
15641
  * @constructor
15366
- * @param {NdChild} [label]
15367
- * @param {GlobalAttributes} [config={}]
15642
+ * @param {NdChild} label
15643
+ * @param {GlobalAttributes} [props={}]
15368
15644
  */
15369
- function ListGroup(label, config = {}) {
15370
- if(!(this instanceof ListGroup)) {
15371
- return new ListGroup(label, config);
15645
+ function ListGroup(label, props = {}) {
15646
+ if (!(this instanceof ListGroup)) {
15647
+ return new ListGroup(label, props);
15372
15648
  }
15373
15649
 
15650
+ BaseComponent.call(this, props);
15651
+
15374
15652
  this.$description = {
15375
- header: label || null,
15376
- footer: null,
15377
- items: [],
15378
- inset: false,
15379
- data: null,
15380
- renderHeader: null,
15381
- renderFooter: null,
15382
- render: null,
15383
- ...config,
15653
+ selectable: $(false),
15654
+ multiSelect: $(false),
15655
+ selectedValues: $.array(),
15656
+ label: label,
15657
+ icon: null,
15658
+ items: $.array(),
15659
+ render: null,
15660
+ collapsable: false,
15661
+ collapsed: null,
15662
+ visibility: $(true),
15663
+ selectByCheckbox: $(false),
15664
+ selectByClick: $(false),
15665
+ loopOnKeyboard: $(false),
15666
+ props,
15384
15667
  };
15385
15668
  }
15386
15669
 
15387
15670
  BaseComponent.extends(ListGroup);
15388
- BaseComponent.use(ListGroup, HasItems);
15671
+ BaseComponent.use(ListGroup, HasItems, HasEventEmitter, HasListItem);
15672
+
15673
+ HasListItem.components.ListGroup = ListGroup;
15389
15674
 
15390
15675
  ListGroup.defaultTemplate = null;
15676
+ ListGroup.prototype.__$ListInstance = true;
15391
15677
 
15392
15678
  /**
15393
15679
  * Registers the render template for ListGroup.
15394
15680
  * @param {(description: {
15395
- * header: NdChild|null,
15396
- * footer: NdChild|null,
15397
- * items: *[],
15398
- * inset: boolean,
15399
- * data: *|null,
15400
- * renderHeader: ((desc: *, instance: ListGroup) => NdChild)|null,
15401
- * renderFooter: ((desc: *, instance: ListGroup) => NdChild)|null,
15402
- * render: ((desc: *, instance: ListGroup) => NdChild)|null,
15403
- * props: GlobalAttributes,
15681
+ * label: NdChild,
15682
+ * icon: NdChild|null,
15683
+ * items: ObservableArray<ListItem|ListGroup|ListDivider>,
15684
+ * itemBuilder: (item: *) => ListItem|ListGroup|ListDivider,
15685
+ * data: *|null,
15686
+ * render: ((desc: *, instance: ListGroup) => NdChild)|null,
15687
+ * collapsable: boolean,
15688
+ * collapsed: ObservableItem<boolean>|null,
15689
+ * visibility: ObservableItem<boolean>,
15690
+ * props: GlobalAttributes,
15404
15691
  * }, instance: ListGroup) => NdChild} template
15405
15692
  */
15406
15693
  ListGroup.use = function(template) {
@@ -15408,37 +15695,47 @@ var NativeComponents = (function (exports) {
15408
15695
  };
15409
15696
 
15410
15697
  /**
15411
- * @param {NdChild} header
15698
+ * @param {NdChild} icon
15412
15699
  * @returns {this}
15413
15700
  */
15414
- ListGroup.prototype.header = function(header) {
15415
- this.$description.header = header;
15701
+ ListGroup.prototype.icon = function(icon) {
15702
+ this.$description.icon = icon;
15416
15703
  return this;
15417
15704
  };
15418
15705
 
15419
15706
  /**
15420
- * @param {NdChild} title
15707
+ * @param {boolean} [mode=true]
15708
+ * @param {NdChild} [openedIcon]
15709
+ * @param {NdChild} [closedIcon]
15421
15710
  * @returns {this}
15422
15711
  */
15423
- ListGroup.prototype.title = function(title) {
15424
- return this.header(title);
15712
+ ListGroup.prototype.collapsable = function(mode = true, openedIcon, closedIcon) {
15713
+ this.$description.collapsable = mode;
15714
+ this.$description.collapsed = this.$description.collapsed || $(false);
15715
+ this.$description.collapsableOpenedIcon = openedIcon || null;
15716
+ this.$description.collapsableClosedIcon = closedIcon || null;
15717
+ return this;
15425
15718
  };
15426
15719
 
15427
15720
  /**
15428
- * @param {NdChild} footer
15721
+ * @param {boolean} [mode=true]
15429
15722
  * @returns {this}
15430
15723
  */
15431
- ListGroup.prototype.footer = function(footer) {
15432
- this.$description.footer = footer;
15724
+ ListGroup.prototype.collapsed = function(mode = true) {
15725
+ if (!this.$description.collapsed) {
15726
+ this.$description.collapsed = $(mode);
15727
+ } else {
15728
+ this.$description.collapsed.set(mode);
15729
+ }
15433
15730
  return this;
15434
15731
  };
15435
15732
 
15436
15733
  /**
15437
- * @param {number} [inset]
15734
+ * @param {boolean|Observable<boolean>} mode
15438
15735
  * @returns {this}
15439
15736
  */
15440
- ListGroup.prototype.inset = function(inset = true) {
15441
- this.$description.inset = inset;
15737
+ ListGroup.prototype.visibility = function(mode) {
15738
+ this.$description.visibility = BaseComponent.obs(mode);
15442
15739
  return this;
15443
15740
  };
15444
15741
 
@@ -15451,24 +15748,6 @@ var NativeComponents = (function (exports) {
15451
15748
  return this;
15452
15749
  };
15453
15750
 
15454
- /**
15455
- * @param {(desc: *, instance: *) => NdChild} renderFn
15456
- * @returns {this}
15457
- */
15458
- ListGroup.prototype.renderHeader = function(renderFn) {
15459
- this.$description.renderHeader = renderFn;
15460
- return this;
15461
- };
15462
-
15463
- /**
15464
- * @param {(desc: *, instance: *) => NdChild} renderFn
15465
- * @returns {this}
15466
- */
15467
- ListGroup.prototype.renderFooter = function(renderFn) {
15468
- this.$description.renderFooter = renderFn;
15469
- return this;
15470
- };
15471
-
15472
15751
  /**
15473
15752
  * A MenuItem that renders as an anchor (<a>). Inherits all MenuItem methods and adds target control.
15474
15753
  *
@@ -20710,14 +20989,7 @@ var NativeComponents = (function (exports) {
20710
20989
  * @returns {HTMLElement|DocumentFragment} The underlying DOM node
20711
20990
  */
20712
20991
  NDElement.prototype.toNdElement = function () {
20713
- const element = this.$element ?? this.$build?.() ?? this.build?.() ?? null;
20714
- if(this.$attachements) {
20715
- if(!this.$attachements.contains(this.$element)) {
20716
- this.$attachements.append(this.$element);
20717
- }
20718
- return this.$attachements;
20719
- }
20720
- return element;
20992
+ return this.$element;
20721
20993
  };
20722
20994
 
20723
20995
  /**
@@ -20873,17 +21145,6 @@ var NativeComponents = (function (exports) {
20873
21145
  return this;
20874
21146
  };
20875
21147
 
20876
- ObservableItem.prototype.handleNdAttribute = function(element, attributeName) {
20877
- if(BOOLEAN_ATTRIBUTES.has(attributeName)) {
20878
- bindBooleanAttribute(element, attributeName, this);
20879
- return;
20880
- }
20881
-
20882
- bindAttributeWithObservable(element, attributeName, this);
20883
- };
20884
-
20885
- ObservableChecker.prototype.handleNdAttribute = ObservableItem.prototype.handleNdAttribute;
20886
-
20887
21148
  /**
20888
21149
  * Groups multiple columns under a shared header in SimpleTable/DataTable.
20889
21150
  *
@@ -23497,6 +23758,32 @@ var NativeComponents = (function (exports) {
23497
23758
  const Row = HStack;
23498
23759
  const Col = VStack;
23499
23760
 
23761
+ function Spacer(props = {}) {
23762
+ if (!(this instanceof Spacer)) {
23763
+ return new Spacer(props);
23764
+ }
23765
+ BaseComponent.call(this, props);
23766
+ this.$description = {
23767
+ type: 'spacer',
23768
+ props,
23769
+ };
23770
+ }
23771
+ BaseComponent.extends(Spacer);
23772
+
23773
+ Spacer.defaultTemplate = null;
23774
+ /**
23775
+ *
23776
+ *
23777
+ * Registers the render template for Spacer.
23778
+ * @param {(description: {
23779
+ * type: 'spacer',
23780
+ * props: GlobalAttributes,
23781
+ * }, instance: Spacer) => NdChild} template
23782
+ */
23783
+ Spacer.use = function(template) {
23784
+ Spacer.defaultTemplate = template;
23785
+ };
23786
+
23500
23787
  exports.AbsoluteStack = AbsoluteStack;
23501
23788
  exports.Accordion = Accordion;
23502
23789
  exports.AccordionItem = AccordionItem;
@@ -23507,6 +23794,7 @@ var NativeComponents = (function (exports) {
23507
23794
  exports.Badge = Badge;
23508
23795
  exports.Breadcrumb = Breadcrumb;
23509
23796
  exports.Button = Button;
23797
+ exports.Card = Card;
23510
23798
  exports.CheckboxField = CheckboxField;
23511
23799
  exports.CheckboxGroupField = CheckboxGroupField;
23512
23800
  exports.Col = Col;
@@ -23536,6 +23824,10 @@ var NativeComponents = (function (exports) {
23536
23824
  exports.HStack = HStack;
23537
23825
  exports.HiddenField = HiddenField;
23538
23826
  exports.ImageField = ImageField;
23827
+ exports.List = List;
23828
+ exports.ListDivider = ListDivider;
23829
+ exports.ListGroup = ListGroup;
23830
+ exports.ListItem = ListItem;
23539
23831
  exports.Menu = Menu;
23540
23832
  exports.MenuDivider = MenuDivider;
23541
23833
  exports.MenuGroup = MenuGroup;
@@ -23557,6 +23849,7 @@ var NativeComponents = (function (exports) {
23557
23849
  exports.SimpleTable = SimpleTable;
23558
23850
  exports.Skeleton = Skeleton;
23559
23851
  exports.Slider = Slider;
23852
+ exports.Spacer = Spacer;
23560
23853
  exports.Spinner = Spinner;
23561
23854
  exports.Splitter = Splitter;
23562
23855
  exports.SplitterGutter = SplitterGutter;