native-document 1.0.169 → 1.0.173

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 (134) hide show
  1. package/CHANGELOG.md +100 -2
  2. package/docs/vitepress-conventions.md +2 -2
  3. package/index.d.ts +1 -1
  4. package/package.json +11 -4
  5. package/src/components/BaseComponent.js +43 -1
  6. package/src/components/accordion/Accordion.js +1 -0
  7. package/src/components/accordion/AccordionItem.js +1 -0
  8. package/src/components/alert/Alert.js +4 -0
  9. package/src/components/avatar/Avatar.js +1 -0
  10. package/src/components/avatar/AvatarGroup.js +1 -0
  11. package/src/components/badge/Badge.js +1 -0
  12. package/src/components/breadcrumb/BreadCrumb.js +4 -0
  13. package/src/components/button/Button.js +1 -0
  14. package/src/components/card/Card.js +1 -0
  15. package/src/components/context-menu/ContextMenu.js +2 -0
  16. package/src/components/context-menu/ContextMenuGroup.js +2 -0
  17. package/src/components/context-menu/ContextMenuItem.js +2 -0
  18. package/src/components/divider/Divider.js +2 -0
  19. package/src/components/dropdown/Dropdown.js +1 -0
  20. package/src/components/dropdown/DropdownDivider.js +1 -0
  21. package/src/components/dropdown/DropdownGroup.js +1 -0
  22. package/src/components/dropdown/DropdownItem.js +1 -0
  23. package/src/components/dropdown/DropdownTrigger.js +1 -0
  24. package/src/components/form/FormControl.js +1 -0
  25. package/src/components/form/field/Field.js +1 -0
  26. package/src/components/form/field/types/StringField.js +1 -1
  27. package/src/components/icon/Icon.js +1 -0
  28. package/src/components/list/ListItem.js +1 -0
  29. package/src/components/menu/Menu.js +3 -0
  30. package/src/components/menu/MenuDivider.js +1 -0
  31. package/src/components/menu/MenuGroup.js +1 -0
  32. package/src/components/menu/MenuItem.js +1 -0
  33. package/src/components/menu/MenuLink.js +1 -0
  34. package/src/components/modal/Modal.js +4 -0
  35. package/src/components/pagination/Pagination.js +1 -0
  36. package/src/components/popover/Popover.js +1 -0
  37. package/src/components/popover/PopoverFooter.js +1 -0
  38. package/src/components/popover/PopoverHeader.js +1 -0
  39. package/src/components/progress/Progress.js +5 -0
  40. package/src/components/skeleton/Skeleton.js +4 -0
  41. package/src/components/slider/Slider.js +1 -0
  42. package/src/components/spacer/Spacer.js +1 -0
  43. package/src/components/spinner/Spinner.js +1 -0
  44. package/src/components/splitter/Splitter.js +1 -0
  45. package/src/components/splitter/SplitterGutter.js +6 -0
  46. package/src/components/splitter/SplitterPanel.js +1 -0
  47. package/src/components/stacks/AbsoluteStack.js +1 -0
  48. package/src/components/stacks/FixedStack.js +1 -0
  49. package/src/components/stacks/HStack.js +1 -0
  50. package/src/components/stacks/PositionStack.js +1 -0
  51. package/src/components/stacks/RelativeStack.js +1 -0
  52. package/src/components/stacks/Stack.js +1 -0
  53. package/src/components/stacks/VStack.js +1 -0
  54. package/src/components/stepper/Stepper.js +1 -0
  55. package/src/components/stepper/StepperStep.js +1 -0
  56. package/src/components/switch/Switch.js +1 -0
  57. package/src/components/table/DataTable.js +1 -0
  58. package/src/components/table/SimpleTable.js +1 -0
  59. package/src/components/tabs/Tabs.js +1 -0
  60. package/src/components/toast/Toast.js +1 -0
  61. package/src/components/tooltip/Tooltip.js +1 -0
  62. package/src/core/data/MemoryManager.js +6 -1
  63. package/src/core/data/ObservableItem.js +33 -15
  64. package/src/core/data/ObservableObject.js +1 -2
  65. package/src/core/elements/anchor/anchor.js +4 -3
  66. package/src/core/elements/anchor/one-child-anchor-overwriting.js +4 -4
  67. package/src/core/elements/content-formatter.js +19 -0
  68. package/src/core/elements/control/for-each-array-cache.js +59 -0
  69. package/src/core/elements/control/for-each-array.js +15 -23
  70. package/src/core/wrappers/AttributesWrapper.js +12 -12
  71. package/src/core/wrappers/ElementCreator.js +33 -10
  72. package/src/core/wrappers/HtmlElementWrapper.js +17 -13
  73. package/src/core/wrappers/NDElement.js +23 -8
  74. package/src/core/wrappers/NdPrototype.js +64 -39
  75. package/src/core/wrappers/constants.js +12 -12
  76. package/src/core/wrappers/prototypes/nd-element-extensions.js +127 -57
  77. package/src/core/wrappers/template-cloner/NodeCloner.js +10 -6
  78. package/src/core/wrappers/template-cloner/TemplateCloner.js +7 -4
  79. package/src/fetch/NativeFetch.js +1 -0
  80. package/src/ui/components/accordion/AccordionItemRender.js +29 -7
  81. package/src/ui/components/alert/AlertRender.js +6 -0
  82. package/src/ui/components/breadcrumb/BreadcrumbRender.js +9 -1
  83. package/src/ui/components/button/ButtonRender.js +3 -0
  84. package/src/ui/components/contextmenu/ContextmenuRender.js +2 -0
  85. package/src/ui/components/dropdown/DropdownRender.js +3 -0
  86. package/src/ui/components/dropdown/item/DropdownItemRender.js +6 -1
  87. package/src/ui/components/form/FieldCollectionRender.js +4 -0
  88. package/src/ui/components/form/fields/CheckboxFieldRender.js +4 -0
  89. package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +4 -0
  90. package/src/ui/components/form/fields/FieldRender.js +1 -1
  91. package/src/ui/components/form/fields/RadioFieldRender.js +4 -0
  92. package/src/ui/components/form/fields/RangeFieldRender.js +4 -0
  93. package/src/ui/components/form/fields/SelectFieldRender.js +5 -0
  94. package/src/ui/components/form/fields/SliderFieldRender.js +3 -0
  95. package/src/ui/components/icon/tabler/TablerIconRender.js +0 -1
  96. package/src/ui/components/list/item/ListItemRender.js +4 -0
  97. package/src/ui/components/menu/MenuItemRender.js +8 -0
  98. package/src/ui/components/menu/MenuLinkRender.js +11 -0
  99. package/src/ui/components/menu/MenuRender.js +5 -0
  100. package/src/ui/components/menu/helpers.js +2 -1
  101. package/src/ui/components/modal/ModalRender.js +8 -2
  102. package/src/ui/components/progress/ProgressRender.js +9 -0
  103. package/src/ui/components/skeleton/SkeletonRender.js +2 -0
  104. package/src/ui/components/spinner/SpinnerRender.js +3 -0
  105. package/src/ui/components/splitter/SplitterGutterRender.js +4 -0
  106. package/src/ui/components/splitter/SplitterPanelRender.js +4 -0
  107. package/src/ui/components/splitter/SplitterRender.js +2 -0
  108. package/src/ui/components/stepper/StepperRender.js +2 -1
  109. package/src/ui/components/stepper/StepperStepRender.js +8 -1
  110. package/src/ui/components/switch/SwitchRender.js +3 -0
  111. package/src/ui/components/table/data-table/DataTableRender.js +4 -0
  112. package/src/ui/components/table/simple-table/SimpleTableRender.js +2 -0
  113. package/src/ui/components/toast/ToastRender.js +4 -0
  114. package/src/ui/utils/aria.js +19 -0
  115. package/tests/integration/ui/attributes-wrapper.test.js +177 -0
  116. package/tests/integration/ui/for-each-array.test.js +167 -0
  117. package/tests/integration/ui/lifecycle.test.js +146 -0
  118. package/tests/integration/ui/show-if.test.js +168 -0
  119. package/tests/unit/core/observable-array.test.js +404 -0
  120. package/tests/unit/core/observable-item.test.js +428 -0
  121. package/tests/unit/core/observable-object.test.js +239 -0
  122. package/tests/unit/core/observable-resource.test.js +323 -0
  123. package/tests/unit/core/store.test.js +347 -0
  124. package/tests/unit/router/route-matching.test.js +169 -0
  125. package/tests/unit/router/router-guards.test.js +189 -0
  126. package/tests/unit/utils/cache.test.js +120 -0
  127. package/tests/unit/utils/filters.test.js +394 -0
  128. package/types/elements.d.ts +5 -0
  129. package/types/native-fetch.d.ts +1 -1
  130. package/types/observable-resource.d.ts +2 -2
  131. package/types/observable.d.ts +137 -21
  132. package/types/service.d.ts +2 -1
  133. package/utils.js +7 -4
  134. package/vitest.config.js +15 -0
package/CHANGELOG.md CHANGED
@@ -11,6 +11,101 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ---
13
13
 
14
+ ## [1.0.173] - 2026-06-18
15
+
16
+ ### Fixed
17
+
18
+ - `ObservableItem` TypeScript definitions - `subscribe()` and `on()` no longer
19
+ typed as returning `Unsubscribe`; they return nothing in the actual
20
+ implementation. Use `.unsubscribe(callback)` / `.off(value, callback)` with
21
+ the same reference to remove a subscription.
22
+
23
+ ### Added
24
+
25
+ - `ObservableItem` type definitions - `interceptMutations`, `clone`, `valueOf`
26
+ - `ObservableItem` comparison helpers typed: `isEqualTo`, `isNotEqualTo`,
27
+ `isGreaterThan`, `isGreaterThanOrEqualTo`, `isLessThan`,
28
+ `isLessThanOrEqualTo`, `isBetween`, `isNull`, `isTruthy`, `isFalsy`,
29
+ `isStartingWith`, `isEndingWith`, `isMatchingPattern`, `isEmpty`,
30
+ `isNotEmpty`, `isIncludes`, `isIncludedIn`, `isOneOf`, `isHaving`
31
+ - `ObservableItem` transform helpers typed: `toUpperCase`, `toLowerCase`,
32
+ `toTrimmed`, `toBoolean`, `toLiteral`, `toFormatted`, `toProperty`,
33
+ `toLength`, `toClamped`, `toPercent`
34
+ - `ObservableArray` type definitions - `swapItems`, `insertAfter`, `sync`,
35
+ `clone`, `isNotEmpty`, `indexOf`, `includes`; `deepSubscribe` and `sync`
36
+ correctly typed to return `Unsubscribe`
37
+ - `ObservableObject` type definitions - `$observables()` and `configs()` typed
38
+ as callable methods; `subscribe()` documented as deep-subscribing nested
39
+ observables and observable arrays
40
+ - `ObservableResource` type definitions (previously entirely missing) -
41
+ `ResourceState`, `ObservableResourceConfig`, `data`, `error`, `state`,
42
+ `loading`, `fetch`, `refetch`, `mutate`, `into`, `apply`, `destroy`,
43
+ `isReady`, `isPending`, `isRefreshing`, `isErrored`, `isUnresolved`,
44
+ `onSuccess`, `onError`
45
+ - `ObservableStatic` type definitions - `resource()`, `setLocale()`,
46
+ `useValueProperty()`
47
+
48
+ ---
49
+
50
+ ## [1.0.172] - 2026-06-15
51
+
52
+ ### Added
53
+
54
+ - `Text(string)` - shorthand for `string.toNdChildren()`, parses Observable placeholders in template strings
55
+ - `String.prototype.toNdChildren()` - splits a string containing `{{obs:N}}` placeholders into a mixed array of strings and resolved Observables
56
+ - `ObservableItem.prototype.toString()` - auto-registers the Observable in MemoryManager and returns `{{obs:id}}`, enabling reactive interpolation via standard template literals
57
+ - `NDElement.prototype.className(classes)` - adds static classes, bypasses AttributesWrapper
58
+ - `NDElement.prototype.class(className, value)` - adds a reactive class binding, bypasses AttributesWrapper
59
+ - `__$isNativeNode` flag on DOM prototypes (`Element`, `Text`, `Comment`, `Document`, `DocumentFragment`) - faster alternative to `instanceof Node`
60
+ - `__$isValidNdChild` flag on all valid NdChild prototypes - single property check replaces multiple type guards
61
+ - `defineToNdElement`, `defineValidNdChild`, `defineNativeNode` - non-enumerable prototype helpers in `nd-element-extensions`
62
+ - camelCase variants added to `BOOLEAN_ATTRIBUTES` - removes `toLowerCase()` call on each attribute in the hot path
63
+
64
+ ### Changed
65
+
66
+ - `ElementCreator.processChildren` and `getChild` - refactored for better performance
67
+ - `nd-element-extensions` - all prototype extensions converted to non-enumerable `defineProperty`
68
+ - `AttributesWrapper` - `options` defaults to `null` instead of `{}`, fixes truthy check issue
69
+ - NDElement events - inline handler (`on*`) used when no existing handler and no options; falls back to `addEventListener` for subsequent handlers or when options are provided
70
+ - `_prevent`, `_stop`, `_preventStop` - updated with same inline handler strategy
71
+
72
+ ---
73
+
74
+ ## [1.0.170] - 2026-06-10
75
+
76
+ ### Added
77
+
78
+ - Vitest test suite - `vitest.config.js`, happy-dom environment, scripts `test`, `test:watch`, `test:ui`, `test:coverage`
79
+ - 372 tests passing across 13 files - 0 failures, 0 todo
80
+
81
+ #### Unit tests - core
82
+ - `observable-item` - 48 cases: set, val, subscribe, on/off, once, toggle, reset, transform, equals, clone, cleanup, intercept, assocTrigger
83
+ - `observable-array` - 48 cases: push, remove, clear, merge, swap, insertAfter, isIncludes, where, sync, clone, reset, deepSubscribe
84
+ - `observable-object` - 30 cases: constructor, val, get, set, subscribe, keys, observables, reset, clone
85
+ - `observable-resource` - 29 cases: states, fetch, refetch, mutate, abort, race condition, deps, onSuccess, onError, into, apply, destroy
86
+ - `store` - 43 cases: create, createResettable, createComposed, use, follow, reset, delete, group, protected, createPersistent
87
+
88
+ #### Unit tests - router
89
+ - `route-matching` - 26 cases: exact path, params, typed params, custom validators, url(), metadata
90
+ - `router-guards` - 14 cases: middleware execution, group middlewares, subscribe, resolve, currentState
91
+
92
+ #### Unit tests - utils
93
+ - `cache` - 12 cases: singleton, once, memoize
94
+ - `filters` - 60 cases: equals, comparison, inArray, isEmpty, match, and/or/not, custom, string filters, date/time filters
95
+
96
+ #### Integration tests - UI
97
+ - `attributes-wrapper` - 22 cases: string, class map, style, Observable, boolean, aria attributes
98
+ - `show-if` - 16 cases: static boolean, observable, factory child, HideIf, HideIfNot
99
+ - `for-each-array` - 13 cases: static array, push, removeItem, clear, set, swap, index observable, order preservation
100
+ - `lifecycle` - 11 cases: mounted, unmounted, destroy, destroyOnUnmount
101
+
102
+ ### Fixed
103
+
104
+ - `NDElement.prototype.destroy()` - guard against double call when `$element` is already null
105
+ - `NDElement.prototype.destroy()` - disconnect lifecycle observer to prevent callbacks from firing after destroy
106
+
107
+ ---
108
+
14
109
  ## [1.0.169] - 2026-06-06
15
110
 
16
111
  ### Added
@@ -39,7 +134,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
39
134
 
40
135
  #### UI (renders)
41
136
  - `CardRender` + `card.css` - Card renderer with 5 build slots and `layout(slots)` support
42
- - `ListRender` + `list.css` - `ForEachArray($desc.items)` items self-render
137
+ - `ListRender` + `list.css` - `ForEachArray($desc.items)` - items self-render
43
138
  - `ListItemRender` + `list-item.css` - reactive checkbox, select indicator, swipe gesture with pointer events, auto-close and stopPropagation
44
139
  - `ListGroupRender` + `list-group.css` - collapsible group with reactive chevron via `Switch`
45
140
  - `ListDividerRender` + `list-divider.css`
@@ -181,7 +276,10 @@ Entries use the following categories:
181
276
 
182
277
  ---
183
278
 
184
- [Unreleased]: https://github.com/afrocodeur/native-document/compare/v1.0.169...HEAD
279
+ [Unreleased]: https://github.com/afrocodeur/native-document/compare/v1.0.173...HEAD
280
+ [1.0.173]: https://github.com/afrocodeur/native-document/compare/v1.0.172...v1.0.173
281
+ [1.0.172]: https://github.com/afrocodeur/native-document/compare/v1.0.170...v1.0.172
282
+ [1.0.170]: https://github.com/afrocodeur/native-document/compare/v1.0.169...v1.0.170
185
283
  [1.0.169]: https://github.com/afrocodeur/native-document/compare/v1.0.167...v1.0.169
186
284
  [1.0.167]: https://github.com/afrocodeur/native-document/compare/v1.0.166...v1.0.167
187
285
  [1.0.166]: https://github.com/afrocodeur/native-document/releases/tag/v1.0.166
@@ -75,7 +75,7 @@ docs/
75
75
  ## Internal Links
76
76
 
77
77
  VitePress resolves links relative to the current file.
78
- Always use `.md` extension VitePress strips it at build time.
78
+ Always use `.md` extension - VitePress strips it at build time.
79
79
 
80
80
  ```markdown
81
81
  <!-- From docs/readme.md or docs/getting-started.md -->
@@ -93,7 +93,7 @@ Never use absolute paths (`/docs/...`) or paths without `.md`.
93
93
 
94
94
  ---
95
95
 
96
- ## `.vitepress/config.js` Sidebar & Nav
96
+ ## `.vitepress/config.js` - Sidebar & Nav
97
97
 
98
98
  ```javascript
99
99
  // .vitepress/config.js
package/index.d.ts CHANGED
@@ -18,4 +18,4 @@ export declare const Observable: ObservableStatic;
18
18
  export declare const $: ObservableStatic;
19
19
  export declare const obs: ObservableStatic;
20
20
  export declare const Store: StoreStatic;
21
- export declare const Router: RouterStatic;
21
+ // export declare const Router: RouterStatic;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-document",
3
- "version": "1.0.169",
3
+ "version": "1.0.173",
4
4
  "description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
5
5
  "author": "AfroCodeur <https://github.com/afrocodeur>",
6
6
  "license": "MIT",
@@ -41,7 +41,11 @@
41
41
  "build": "rollup --config rollup.config.js",
42
42
  "build:watch": "rollup --config rollup.config.js --watch",
43
43
  "lint": "eslint ./src",
44
- "lint:fix": "eslint ./src --fix"
44
+ "lint:fix": "eslint ./src --fix",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "test:ui": "vitest --ui",
48
+ "test:coverage": "vitest run --coverage"
45
49
  },
46
50
  "dependencies": {
47
51
  "@floating-ui/dom": "^1.7.6",
@@ -53,14 +57,17 @@
53
57
  "@rollup/plugin-alias": "^5.1.1",
54
58
  "@rollup/plugin-replace": "^6.0.2",
55
59
  "@rollup/plugin-terser": "^0.4.4",
60
+ "@vitest/coverage-v8": "^4.1.8",
56
61
  "eslint": "^9.33.0",
57
62
  "eslint-plugin-jsdoc": "^62.5.4",
63
+ "happy-dom": "^20.10.2",
58
64
  "magic-string": "^0.30.21",
59
65
  "postcss": "^8.5.12",
60
66
  "rollup": "^4.53.3",
61
- "rollup-plugin-postcss": "^4.0.2"
67
+ "rollup-plugin-postcss": "^4.0.2",
68
+ "vitest": "^4.1.8"
62
69
  },
63
70
  "engines": {
64
71
  "node": ">=18.0.0"
65
72
  }
66
- }
73
+ }
@@ -181,6 +181,12 @@ BaseComponent.prototype.getEditableProps = function() {
181
181
  class: classPropertyAccumulator(rawProps.class || {}),
182
182
  style: cssPropertyAccumulator(rawProps.style || {}),
183
183
  };
184
+
185
+ if (this.aria) {
186
+ for (const key in this.aria) {
187
+ this.$editableProps[resolveAriaKey(key)] = this.aria[key];
188
+ }
189
+ }
184
190
  }
185
191
 
186
192
  return this.$editableProps;
@@ -244,4 +250,40 @@ BaseComponent.prototype.context = function(context) {
244
250
  return this;
245
251
  };
246
252
 
247
- BaseComponent.prototype.visibility = BaseComponent.prototype.showIf;
253
+ BaseComponent.prototype.visibility = BaseComponent.prototype.showIf;
254
+
255
+ //------------------------------------------------------------------------------
256
+ //--Component Aria -------------------------------------------------------------
257
+ //------------------------------------------------------------------------------
258
+ const ARIA_NO_PREFIX = new Set(['role', 'id', 'tabindex']);
259
+
260
+ /**
261
+ * @param {string} key
262
+ * @returns {string}
263
+ */
264
+ const resolveAriaKey = (key) =>
265
+ ARIA_NO_PREFIX.has(key) || key.startsWith('aria-') ? key : `aria-${key}`;
266
+
267
+ /**
268
+ * Override or extend aria attributes on the root element.
269
+ * Automatically prefixes keys with 'aria-' unless they are in ARIA_NO_PREFIX.
270
+ *
271
+ * @example
272
+ * Modal()
273
+ * .setAria({ label: 'Confirmation dialog' })
274
+ * .setAria({ describedby: 'modal-desc' })
275
+ *
276
+ * @param {Record<string, string|boolean|Observable>} attrs
277
+ * @returns {this}
278
+ */
279
+ BaseComponent.prototype.setAria = function(attrs) {
280
+ if (!this.aria) {
281
+ this.aria = {};
282
+ }
283
+ for (const key in attrs) {
284
+ this.aria[resolveAriaKey(key)] = attrs[key];
285
+ }
286
+ return this;
287
+ };
288
+
289
+
@@ -36,6 +36,7 @@ export default function Accordion(props = {}) {
36
36
  renderIndicator: null,
37
37
  props,
38
38
  };
39
+ this.aria = {};
39
40
  }
40
41
 
41
42
  BaseComponent.extends(Accordion);
@@ -41,6 +41,7 @@ export default function AccordionItem(props = {}) {
41
41
  disabled: $(false),
42
42
  props,
43
43
  };
44
+ this.aria = { 'tabindex': '0' };
44
45
  }
45
46
 
46
47
  BaseComponent.extends(AccordionItem);
@@ -44,6 +44,10 @@ export default function Alert(content, props = {}) {
44
44
  actions: [],
45
45
  props,
46
46
  };
47
+ this.aria = {
48
+ 'role': 'alert',
49
+ 'aria-live': 'assertive'
50
+ };
47
51
  }
48
52
 
49
53
  Alert.defaultTemplate = null;
@@ -42,6 +42,7 @@ export default function Avatar(source, props = {}) {
42
42
  render: null,
43
43
  props,
44
44
  };
45
+ this.aria = { 'role': 'img' };
45
46
  }
46
47
 
47
48
  BaseComponent.extends(Avatar);
@@ -31,6 +31,7 @@ export default function AvatarGroup(props = {}) {
31
31
  props,
32
32
  };
33
33
 
34
+ this.aria = { 'role': 'group' };
34
35
  };
35
36
 
36
37
  BaseComponent.extends(AvatarGroup);
@@ -36,6 +36,7 @@ export default function Badge(content, props = {}) {
36
36
  content,
37
37
  props,
38
38
  };
39
+ this.aria = {};
39
40
  }
40
41
 
41
42
  BaseComponent.extends(Badge);
@@ -21,6 +21,10 @@ export default function Breadcrumb(props = {}) {
21
21
  renderItem: null,
22
22
  props,
23
23
  };
24
+ this.aria = {
25
+ 'role': 'navigation',
26
+ 'aria-label': 'Breadcrumb'
27
+ };
24
28
  }
25
29
 
26
30
  BaseComponent.extends(Breadcrumb);
@@ -55,6 +55,7 @@ export default function Button(label, props = {}) {
55
55
  outline: null,
56
56
  props,
57
57
  };
58
+ this.aria = { 'role': 'button' };
58
59
 
59
60
  this.$element = null;
60
61
  }
@@ -45,6 +45,7 @@ export default function Card(props = {}) {
45
45
  layout: null,
46
46
  props,
47
47
  };
48
+ this.aria = {};
48
49
  }
49
50
 
50
51
  BaseComponent.extends(Card);
@@ -35,6 +35,8 @@ export default function ContextMenu(props = {}) {
35
35
  trigger: null,
36
36
  data: null,
37
37
  });
38
+
39
+ this.aria = { 'role': 'menu' };
38
40
  }
39
41
 
40
42
  BaseComponent.extends(ContextMenu);
@@ -13,6 +13,8 @@ export default function ContextMenuGroup(label, config) {
13
13
  }
14
14
 
15
15
  MenuGroup.call(this, label, config);
16
+
17
+ this.aria = { 'role': 'group' };
16
18
  }
17
19
 
18
20
 
@@ -12,6 +12,8 @@ export default function ContextMenuItem(config) {
12
12
  }
13
13
 
14
14
  MenuItem.call(this, config);
15
+
16
+ this.aria = { 'role': 'menuitem' };
15
17
  }
16
18
 
17
19
 
@@ -41,6 +41,8 @@ export default function Divider(label, props = {}) {
41
41
  trailing: null,
42
42
  props,
43
43
  };
44
+
45
+ this.aria = { 'role': 'separator' };
44
46
  }
45
47
 
46
48
  BaseComponent.extends(Divider);
@@ -66,6 +66,7 @@ export default function Dropdown(props = {}) {
66
66
  includeTriggerIntoGhost: true,
67
67
  props,
68
68
  };
69
+ this.aria = { 'role': 'listbox' };
69
70
  }
70
71
 
71
72
  BaseComponent.extends(Dropdown);
@@ -18,6 +18,7 @@ export default function DropdownDivider(props = {}) {
18
18
  type: 'divider',
19
19
  props,
20
20
  };
21
+ this.aria = { 'role': 'separator' };
21
22
  }
22
23
 
23
24
  BaseComponent.extends(DropdownDivider);
@@ -27,6 +27,7 @@ export default function DropdownGroup(props) {
27
27
  Object.assign(this.$description, {
28
28
  items: $.array([]),
29
29
  });
30
+ this.aria = { 'role': 'group' };
30
31
  }
31
32
 
32
33
  BaseComponent.extends(DropdownGroup, DropdownItem);
@@ -38,6 +38,7 @@ export default function DropdownItem(props = {}) {
38
38
  renderContent: null,
39
39
  props,
40
40
  };
41
+ this.aria = { 'role': 'option', 'tabindex': '-1' };
41
42
  };
42
43
 
43
44
  BaseComponent.extends(DropdownItem);
@@ -26,6 +26,7 @@ export default function DropdownTrigger(config) {
26
26
  isOpen: null,
27
27
  ...config,
28
28
  };
29
+ this.aria = { 'aria-haspopup': 'listbox' };
29
30
  }
30
31
 
31
32
  BaseComponent.extends(DropdownTrigger);
@@ -47,6 +47,7 @@ export default function FormControl(props) {
47
47
  isValid: $(false),
48
48
  props,
49
49
  };
50
+ this.aria = { 'role': 'form' };
50
51
  }
51
52
 
52
53
  FormControl.defaultTemplate = null;
@@ -64,6 +64,7 @@ export default function Field(name, type, props) {
64
64
  slots: {},
65
65
  props,
66
66
  };
67
+ this.aria = { 'role': 'group' };
67
68
 
68
69
  this.$description.errors.intercept((nextValue) => nextValue === null ? [] : nextValue);
69
70
  }
@@ -26,7 +26,7 @@ import {Validation} from '../../validation/Validation';
26
26
  */
27
27
  export default function StringField(name, type = 'text', props = {}) {
28
28
  if(!(this instanceof StringField)) {
29
- return new StringField(name, props);
29
+ return new StringField(name, type, props);
30
30
  }
31
31
 
32
32
  Field.call(this, name, type, props);
@@ -20,6 +20,7 @@ export function Icon(name, props = {}) {
20
20
  size: null,
21
21
  ...props,
22
22
  };
23
+ this.aria = { 'aria-hidden': 'true' };
23
24
  }
24
25
 
25
26
  BaseComponent.extends(Icon);
@@ -49,6 +49,7 @@ export default function ListItem(props = {}) {
49
49
  render: null,
50
50
  props,
51
51
  };
52
+ this.aria = { 'role': 'listitem', 'tabindex': '-1' };
52
53
  }
53
54
 
54
55
  BaseComponent.extends(ListItem);
@@ -53,6 +53,9 @@ export default function Menu(props = {}) {
53
53
  props,
54
54
  };
55
55
 
56
+
57
+ this.aria = { 'role': 'menu' };
58
+
56
59
  }
57
60
 
58
61
  BaseComponent.extends(Menu);
@@ -19,6 +19,7 @@ export default function MenuDivider(props = {}) {
19
19
  this.$description = {
20
20
  props,
21
21
  };
22
+ this.aria = { 'role': 'separator' };
22
23
  }
23
24
 
24
25
  BaseComponent.extends(MenuDivider);
@@ -39,6 +39,7 @@ export default function MenuGroup(label, props = {}) {
39
39
  collapsableClosedIcon: null,
40
40
  props,
41
41
  };
42
+ this.aria = { 'role': 'group' };
42
43
  }
43
44
 
44
45
  HasMenuItem.components.MenuGroup = MenuGroup;
@@ -51,6 +51,7 @@ export default function MenuItem(props = {}) {
51
51
  visibility: null,
52
52
  props,
53
53
  };
54
+ this.aria = { 'role': 'menuitem', 'tabindex': '-1' };
54
55
 
55
56
  }
56
57
 
@@ -21,6 +21,7 @@ export default function MenuLink(props = {}) {
21
21
  return new MenuLink(props);
22
22
  }
23
23
  MenuItem.call(this, props);
24
+ this.aria = { 'role': 'menuitem' };
24
25
  }
25
26
 
26
27
  MenuLink.prototype = Object.create(MenuItem.prototype);
@@ -67,6 +67,10 @@ export default function Modal(content, props = {}) {
67
67
  variant: null,
68
68
  props,
69
69
  };
70
+ this.aria = {
71
+ 'role': 'dialog',
72
+ 'aria-modal': 'true'
73
+ };
70
74
  }
71
75
 
72
76
  BaseComponent.extends(Modal);
@@ -50,6 +50,7 @@ export default function Pagination(props = {}) {
50
50
  render: null,
51
51
  props,
52
52
  };
53
+ this.aria = { 'role': 'navigation', 'aria-label': 'Pagination' };
53
54
 
54
55
  this.$element = null;
55
56
  }
@@ -64,6 +64,7 @@ export default function Popover(content, props = {}) {
64
64
  includeTriggerIntoGhost: true,
65
65
  props,
66
66
  };
67
+ this.aria = { 'role': 'tooltip' };
67
68
 
68
69
  this.$element = null;
69
70
 
@@ -24,6 +24,7 @@ export default function PopoverFooter(content, config = {}) {
24
24
  render: null,
25
25
  ...config,
26
26
  };
27
+ this.aria = { };
27
28
  }
28
29
 
29
30
  BaseComponent.extends(PopoverFooter);
@@ -25,6 +25,7 @@ export default function PopoverHeader(content, config = {}) {
25
25
  render: null,
26
26
  ...config,
27
27
  };
28
+ this.aria = { 'role': 'heading' };
28
29
  }
29
30
 
30
31
  BaseComponent.extends(PopoverHeader);
@@ -50,6 +50,11 @@ export default function Progress(props = {}) {
50
50
  borderRadiusType: null,
51
51
  props,
52
52
  };
53
+ this.aria = {
54
+ 'role': 'progressbar',
55
+ 'aria-valuemin': '0',
56
+ 'aria-valuemax': '100'
57
+ };
53
58
  }
54
59
 
55
60
  BaseComponent.extends(Progress);
@@ -42,6 +42,10 @@ export default function Skeleton(props = {}) {
42
42
  repeat: null,
43
43
  props,
44
44
  };
45
+ this.aria = {
46
+ 'aria-busy': 'true',
47
+ 'aria-live': 'polite'
48
+ };
45
49
  }
46
50
 
47
51
  BaseComponent.extends(Skeleton);
@@ -61,6 +61,7 @@ export default function Slider(name, props = {}) {
61
61
  renderThumb: null,
62
62
  props,
63
63
  };
64
+ this.aria = { 'role': 'slider', 'tabindex': '0' };
64
65
  }
65
66
 
66
67
  Slider.prototype = Object.create(Field.prototype);
@@ -9,6 +9,7 @@ export default function Spacer(props = {}) {
9
9
  type: 'spacer',
10
10
  props,
11
11
  };
12
+ this.aria = { 'aria-hidden': 'true' };
12
13
  }
13
14
  BaseComponent.extends(Spacer);
14
15
 
@@ -42,6 +42,7 @@ export default function Spinner(props = {}) {
42
42
  fullScreenOverlay: null,
43
43
  props,
44
44
  };
45
+ this.aria = { 'role': 'status', 'aria-label': 'Loading' };
45
46
  }
46
47
 
47
48
  Spinner.defaultTemplate = null;
@@ -33,6 +33,7 @@ export default function Splitter(props = {}) {
33
33
  render: null,
34
34
  props,
35
35
  };
36
+ this.aria = { 'role': 'group' };
36
37
 
37
38
  this.$element = null;
38
39
  }
@@ -33,6 +33,10 @@ export default function SplitterGutter(leftPanel, rightPanel, props = {}) {
33
33
  isDragging: $(false),
34
34
  props,
35
35
  };
36
+ this.aria = {
37
+ 'role': 'separator',
38
+ 'aria-orientation': 'horizontal',
39
+ };
36
40
  }
37
41
 
38
42
  BaseComponent.extends(SplitterGutter);
@@ -62,6 +66,7 @@ SplitterGutter.use = function(template) {
62
66
  SplitterGutter.prototype.vertical = function() {
63
67
  this.$description.orientation = 'vertical';
64
68
  this.$description.cursor = 'row-resize';
69
+ this.aria['aria-orientation'] = 'vertical';
65
70
  return this;
66
71
  };
67
72
 
@@ -71,6 +76,7 @@ SplitterGutter.prototype.vertical = function() {
71
76
  SplitterGutter.prototype.horizontal = function() {
72
77
  this.$description.orientation = 'horizontal';
73
78
  this.$description.cursor = 'col-resize';
79
+ this.aria['aria-orientation'] = 'horizontal';
74
80
  return this;
75
81
  };
76
82