native-document 1.0.139 → 1.0.141

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 (259) hide show
  1. package/components.js +1 -1
  2. package/devtools/ComponentRegistry.js +3 -2
  3. package/dist/native-document.components.min.css +1 -0
  4. package/dist/native-document.components.min.js +11639 -8757
  5. package/dist/native-document.dev.js +2645 -2166
  6. package/dist/native-document.dev.js.map +1 -1
  7. package/dist/native-document.min.js +1 -1
  8. package/index.js +1 -0
  9. package/package.json +5 -2
  10. package/rollup.config.js +5 -2
  11. package/src/components/$traits/has-draggable/HasDraggable.js +69 -0
  12. package/src/components/$traits/has-draggable/has-draggable.css +8 -0
  13. package/src/components/$traits/{HasItems.js → has-items/HasItems.js} +2 -11
  14. package/src/components/$traits/has-position/HasFullPosition.js +51 -0
  15. package/src/components/$traits/has-position/HasPosition.js +23 -0
  16. package/src/components/$traits/has-resizable/HasResizable.js +113 -0
  17. package/src/components/$traits/has-resizable/has-resizable.css +121 -0
  18. package/src/components/$traits/has-validation/HasValidation.js +86 -0
  19. package/src/components/BaseComponent.js +82 -7
  20. package/src/components/accordion/Accordion.js +37 -31
  21. package/src/components/accordion/AccordionItem.js +14 -21
  22. package/src/components/alert/Alert.js +48 -40
  23. package/src/components/avatar/Avatar.js +4 -3
  24. package/src/components/avatar/AvatarGroup.js +8 -2
  25. package/src/components/badge/Badge.js +7 -7
  26. package/src/components/base-component.css +0 -0
  27. package/src/components/breadcrumb/BreadCrumb.js +30 -21
  28. package/src/components/button/Button.js +3 -14
  29. package/src/components/context-menu/ContextMenu.js +49 -26
  30. package/src/components/dropdown/Dropdown.js +172 -34
  31. package/src/components/dropdown/DropdownDivider.js +4 -3
  32. package/src/components/dropdown/DropdownGroup.js +19 -19
  33. package/src/components/dropdown/DropdownItem.js +24 -18
  34. package/src/components/dropdown/helpers.js +52 -0
  35. package/src/components/form/FormControl.js +207 -108
  36. package/src/components/form/field/Field.js +106 -174
  37. package/src/components/form/field/FieldCollection.js +110 -203
  38. package/src/components/form/field/types/AutocompleteField.js +26 -5
  39. package/src/components/form/field/types/CheckboxField.js +4 -4
  40. package/src/components/form/field/types/CheckboxGroupField.js +11 -5
  41. package/src/components/form/field/types/ColorField.js +4 -4
  42. package/src/components/form/field/types/DateField.js +110 -18
  43. package/src/components/form/field/types/EmailField.js +2 -2
  44. package/src/components/form/field/types/FileField.js +87 -21
  45. package/src/components/form/field/types/HiddenField.js +4 -4
  46. package/src/components/form/field/types/ImageField.js +4 -4
  47. package/src/components/form/field/types/NumberField.js +5 -5
  48. package/src/components/form/field/types/PasswordField.js +28 -6
  49. package/src/components/form/field/types/RadioField.js +12 -8
  50. package/src/components/form/field/types/RangeField.js +29 -5
  51. package/src/components/form/field/types/SearchField.js +4 -4
  52. package/src/components/form/field/types/SelectField.js +75 -8
  53. package/src/components/form/field/types/StringField.js +4 -4
  54. package/src/components/form/field/types/TelField.js +4 -4
  55. package/src/components/form/field/types/TextAreaField.js +7 -5
  56. package/src/components/form/field/types/TimeField.js +52 -6
  57. package/src/components/form/field/types/UrlField.js +4 -5
  58. package/src/components/form/field/types/file-field-mode/FileAvatarMode.js +104 -0
  59. package/src/components/form/field/types/file-field-mode/FileDropzoneMode.js +59 -0
  60. package/src/components/form/field/types/file-field-mode/FileItemPreview.js +74 -0
  61. package/src/components/form/field/types/file-field-mode/FileNativeMode.js +21 -0
  62. package/src/components/form/field/types/file-field-mode/FileUploadButtonMode.js +59 -0
  63. package/src/components/form/field/types/file-field-mode/FileWallMode.js +53 -0
  64. package/src/components/form/index.js +14 -2
  65. package/src/components/form/validation/Validation.js +9 -0
  66. package/src/components/list/List.js +1 -1
  67. package/src/components/list/ListGroup.js +1 -1
  68. package/src/components/menu/HasMenuItem.js +133 -0
  69. package/src/components/menu/Menu.js +47 -56
  70. package/src/components/menu/MenuGroup.js +36 -8
  71. package/src/components/menu/MenuItem.js +24 -10
  72. package/src/components/menu/MenuLink.js +2 -0
  73. package/src/components/modal/Modal.js +153 -23
  74. package/src/components/pagination/Pagination.js +55 -21
  75. package/src/components/popover/Popover.js +127 -40
  76. package/src/components/progress/Progress.js +14 -24
  77. package/src/components/skeleton/Skeleton.js +36 -13
  78. package/src/components/slider/Slider.js +96 -70
  79. package/src/components/spinner/Spinner.js +4 -2
  80. package/src/components/splitter/Splitter.js +15 -8
  81. package/src/components/splitter/SplitterGutter.js +28 -7
  82. package/src/components/splitter/SplitterPanel.js +9 -15
  83. package/src/components/splitter/index.js +3 -1
  84. package/src/components/stacks/AbsoluteStack.js +33 -0
  85. package/src/components/stacks/FixedStack.js +33 -0
  86. package/src/components/stacks/PositionStack.js +146 -0
  87. package/src/components/stacks/RelativeStack.js +33 -0
  88. package/src/components/{layouts → stacks}/Stack.js +22 -3
  89. package/src/components/{layouts → stacks}/index.js +6 -4
  90. package/src/components/stepper/Stepper.js +159 -67
  91. package/src/components/stepper/StepperStep.js +49 -12
  92. package/src/components/switch/Switch.js +59 -29
  93. package/src/components/switch/index.js +6 -0
  94. package/src/components/table/Column.js +26 -24
  95. package/src/components/table/ColumnGroup.js +4 -13
  96. package/src/components/table/DataTable.js +388 -103
  97. package/src/components/table/SimpleTable.js +31 -140
  98. package/src/components/tabs/Tabs.js +142 -44
  99. package/src/components/toast/Toast.js +40 -35
  100. package/src/components/tooltip/Tooltip.js +152 -35
  101. package/src/core/data/ObservableArray.js +94 -30
  102. package/src/core/data/ObservableChecker.js +20 -75
  103. package/src/core/data/ObservableItem.js +35 -3
  104. package/src/core/data/observable-helpers/computed.js +2 -1
  105. package/src/core/data/observable-helpers/object.js +13 -8
  106. package/src/core/data/observable-helpers/observable.is-to.js +196 -0
  107. package/src/core/elements/anchor/anchor.js +3 -2
  108. package/src/core/elements/control/for-each-array.js +44 -30
  109. package/src/core/elements/control/for-each.js +6 -3
  110. package/src/core/elements/control/show-if.js +11 -6
  111. package/src/core/elements/control/switch.js +2 -1
  112. package/src/core/elements/index.js +1 -1
  113. package/src/core/elements/svg.js +61 -0
  114. package/src/core/utils/HasEventEmitter.js +6 -0
  115. package/src/core/utils/debug-manager.js +2 -5
  116. package/src/core/utils/filters/standard.js +2 -1
  117. package/src/core/utils/property-accumulator.js +35 -6
  118. package/src/core/utils/shortcut-manager.js +242 -0
  119. package/src/core/utils/validator.js +1 -1
  120. package/src/core/wrappers/AttributesWrapper.js +41 -4
  121. package/src/core/wrappers/DocumentObserver.js +0 -1
  122. package/src/core/wrappers/HtmlElementWrapper.js +1 -1
  123. package/src/core/wrappers/NDElement.js +15 -2
  124. package/src/core/wrappers/SvgElementWrapper.js +15 -0
  125. package/src/core/wrappers/prototypes/attributes-extensions.js +4 -1
  126. package/src/core/wrappers/prototypes/nd-element-extensions.js +8 -1
  127. package/src/router/Router.js +0 -1
  128. package/src/ui/components/accordion/AccordionItemRender.js +63 -0
  129. package/src/ui/components/accordion/AccordionRender.js +34 -0
  130. package/src/ui/components/accordion/accordion.css +121 -0
  131. package/src/ui/components/alert/AlertRender.js +80 -0
  132. package/src/ui/components/alert/alert.css +163 -0
  133. package/src/ui/components/avatar/avata-group/AvatarGroupRender.js +49 -0
  134. package/src/ui/components/avatar/avata-group/avatar-group.css +38 -0
  135. package/src/ui/components/avatar/avatar/AvatarRender.js +87 -0
  136. package/src/ui/components/avatar/avatar/avatar.css +189 -0
  137. package/src/ui/components/badge/BadgeRender.js +24 -0
  138. package/src/ui/components/badge/badge.css +168 -0
  139. package/src/ui/components/breadcrumb/BreadcrumbRender.js +43 -0
  140. package/src/ui/components/breadcrumb/breadcrumb.css +55 -0
  141. package/src/ui/components/button/ButtonRender.js +65 -0
  142. package/src/ui/components/button/button.css +288 -354
  143. package/src/ui/components/contextmenu/ContextmenuRender.js +70 -0
  144. package/src/ui/components/contextmenu/contextmenu.css +36 -0
  145. package/src/ui/components/divider/DividerRender.js +70 -0
  146. package/src/ui/components/divider/divider.css +70 -0
  147. package/src/ui/components/dropdown/DropdownRender.js +92 -0
  148. package/src/ui/components/dropdown/divider/DropdownDividerRender.js +9 -0
  149. package/src/ui/components/dropdown/divider/dropdown-divider.css +0 -0
  150. package/src/ui/components/dropdown/dropdown.css +179 -0
  151. package/src/ui/components/dropdown/group/DropdownGroupRender.js +23 -0
  152. package/src/ui/components/dropdown/group/dropdown-group.css +0 -0
  153. package/src/ui/components/dropdown/item/DropdownItemRender.js +29 -0
  154. package/src/ui/components/dropdown/item/dropdown-item.css +0 -0
  155. package/src/ui/components/form/FieldCollectionRender.js +110 -0
  156. package/src/ui/components/form/FormControlRender.js +84 -0
  157. package/src/ui/components/form/field-collection.css +55 -0
  158. package/src/ui/components/form/fields/AutocompleteFieldRender.js +143 -0
  159. package/src/ui/components/form/fields/CheckboxFieldRender.js +59 -0
  160. package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +92 -0
  161. package/src/ui/components/form/fields/ColorFieldRender.js +30 -0
  162. package/src/ui/components/form/fields/DateFieldRender.js +154 -0
  163. package/src/ui/components/form/fields/EmailFieldRender.js +5 -0
  164. package/src/ui/components/form/fields/FieldRender.js +117 -0
  165. package/src/ui/components/form/fields/FileFieldRender.js +41 -0
  166. package/src/ui/components/form/fields/HiddenFieldRender.js +14 -0
  167. package/src/ui/components/form/fields/ImageFieldRender.js +0 -0
  168. package/src/ui/components/form/fields/NumberFieldRender.js +52 -0
  169. package/src/ui/components/form/fields/PasswordFieldRender.js +65 -0
  170. package/src/ui/components/form/fields/RadioFieldRender.js +77 -0
  171. package/src/ui/components/form/fields/RangeFieldRender.js +121 -0
  172. package/src/ui/components/form/fields/SelectFieldRender.js +248 -0
  173. package/src/ui/components/form/fields/SliderFieldRender.js +359 -0
  174. package/src/ui/components/form/fields/StringFieldRender.js +6 -0
  175. package/src/ui/components/form/fields/TelFieldRender.js +6 -0
  176. package/src/ui/components/form/fields/TextAreaFieldRender.js +96 -0
  177. package/src/ui/components/form/fields/TimeFieldRender.js +141 -0
  178. package/src/ui/components/form/fields/UrlFieldRender.js +6 -0
  179. package/src/ui/components/form/fields/date-field.css +32 -0
  180. package/src/ui/components/form/fields/field.css +402 -0
  181. package/src/ui/components/form/fields/file-field.css +79 -0
  182. package/src/ui/components/form/fields/password-field.css +50 -0
  183. package/src/ui/components/form/fields/range-field.css +120 -0
  184. package/src/ui/components/form/fields/slider.css +195 -0
  185. package/src/ui/components/form/file-upload-mode/FileAvatarModeRender.js +143 -0
  186. package/src/ui/components/form/file-upload-mode/FileDropzoneModeRender.js +108 -0
  187. package/src/ui/components/form/file-upload-mode/FileNativeModeRender.js +22 -0
  188. package/src/ui/components/form/file-upload-mode/FileUploadButtonModeRender.js +89 -0
  189. package/src/ui/components/form/file-upload-mode/FileWallModeRender.js +91 -0
  190. package/src/ui/components/form/file-upload-mode/file-avatar-mode.css +139 -0
  191. package/src/ui/components/form/file-upload-mode/file-dropzone-mode.css +88 -0
  192. package/src/ui/components/form/file-upload-mode/file-upload-button-mode.css +44 -0
  193. package/src/ui/components/form/file-upload-mode/file-wall-mode.css +88 -0
  194. package/src/ui/components/form/form-control.css +40 -0
  195. package/src/ui/components/form/helpers.js +112 -0
  196. package/src/ui/components/form/index.js +61 -0
  197. package/src/ui/components/menu/MenuDividerRender.js +12 -0
  198. package/src/ui/components/menu/MenuGroupRender.js +60 -0
  199. package/src/ui/components/menu/MenuItemRender.js +57 -0
  200. package/src/ui/components/menu/MenuLinkRender.js +55 -0
  201. package/src/ui/components/menu/MenuRender.js +21 -0
  202. package/src/ui/components/menu/helpers.js +121 -0
  203. package/src/ui/components/menu/menu.css +308 -0
  204. package/src/ui/components/modal/ModalRender.js +119 -0
  205. package/src/ui/components/modal/modal.css +156 -0
  206. package/src/ui/components/pagination/PaginationRender.js +112 -0
  207. package/src/ui/components/pagination/pagination.css +63 -0
  208. package/src/ui/components/popover/PopoverRender.js +234 -0
  209. package/src/ui/components/popover/popover.css +139 -0
  210. package/src/ui/components/progress/ProgressRender.js +168 -0
  211. package/src/ui/components/progress/progress.css +197 -0
  212. package/src/ui/components/skeleton/SkeletonRender.js +79 -0
  213. package/src/ui/components/skeleton/skeleton.css +154 -0
  214. package/src/ui/components/spinner/SpinnerRender.js +46 -0
  215. package/src/ui/components/spinner/spinner.css +152 -0
  216. package/src/ui/components/splitter/SplitterGutterRender.js +94 -0
  217. package/src/ui/components/splitter/SplitterPanelRender.js +38 -0
  218. package/src/ui/components/splitter/SplitterRender.js +74 -0
  219. package/src/ui/components/splitter/splitter.css +128 -0
  220. package/src/ui/components/stacks/PositionStackRender.js +38 -0
  221. package/src/ui/components/stacks/StackRender.js +42 -0
  222. package/src/ui/components/stacks/absolute-stack/AbsoluteStackRender.js +5 -0
  223. package/src/ui/components/stacks/fixed-stack/FixedStackRender.js +5 -0
  224. package/src/ui/components/stacks/h-stack/HStackRender.js +7 -0
  225. package/src/ui/components/stacks/h-stack/h-stack.css +4 -0
  226. package/src/ui/components/stacks/index.js +15 -0
  227. package/src/ui/components/stacks/position-stack.css +62 -0
  228. package/src/ui/components/stacks/relative-stack/RelativeStackRender.js +7 -0
  229. package/src/ui/components/stacks/relative-stack/relative-stack.css +3 -0
  230. package/src/ui/components/stacks/stack.css +78 -0
  231. package/src/ui/components/stacks/v-stack/VStackRender.js +5 -0
  232. package/src/ui/components/stacks/v-stack/v-stack.css +4 -0
  233. package/src/ui/components/stepper/StepperRender.js +70 -0
  234. package/src/ui/components/stepper/StepperStepRender.js +67 -0
  235. package/src/ui/components/stepper/stepper.css +359 -0
  236. package/src/ui/components/switch/SwitchRender.js +82 -0
  237. package/src/ui/components/switch/switch.css +143 -0
  238. package/src/ui/components/table/data-table/DataTableRender.js +49 -0
  239. package/src/ui/components/table/data-table/bulk-actions.js +35 -0
  240. package/src/ui/components/table/data-table/data-table.css +246 -0
  241. package/src/ui/components/table/data-table/pagination.js +56 -0
  242. package/src/ui/components/table/data-table/tables.js +367 -0
  243. package/src/ui/components/table/data-table/toolbar.js +67 -0
  244. package/src/ui/components/table/simple-table/SimpleTableRender.js +191 -0
  245. package/src/ui/components/table/simple-table/simple-table.css +50 -0
  246. package/src/ui/components/tabs/TabsRender.js +226 -0
  247. package/src/ui/components/tabs/tabs.css +253 -0
  248. package/src/ui/components/toast/ToastRender.js +98 -0
  249. package/src/ui/components/toast/toast.css +201 -0
  250. package/src/ui/components/tooltip/TooltipRender.js +8 -0
  251. package/src/ui/components/tooltip/tooltip.css +113 -0
  252. package/src/ui/index.js +82 -0
  253. package/src/ui/tokens/colors-dark.scss +2 -1
  254. package/src/ui/tokens/reset.scss +3 -0
  255. package/types/control-flow.d.ts +2 -2
  256. package/src/components/layouts/ZStack.js +0 -41
  257. package/src/ui/components/button/button.render.js +0 -63
  258. /package/src/components/{layouts → stacks}/HStack.js +0 -0
  259. /package/src/components/{layouts → stacks}/VStack.js +0 -0
@@ -0,0 +1,84 @@
1
+ import {Div, Span, ShowIf, Form} from '../../../../elements';
2
+ import './form-control.css';
3
+ import {Button} from "../../../components/button";
4
+
5
+ export default function FormControlRender($desc, instance) {
6
+ const props = instance.getEditableProps();
7
+ props.class.add('form-control');
8
+
9
+ const fieldsObject = $desc.fieldBuilder
10
+ ? $desc.fieldBuilder()
11
+ : instance.$fields;
12
+
13
+ if($desc.errorsMode === 'summary') {
14
+ for(const [_, field] of Object.entries(instance.$fields)) {
15
+ field.forceShowErrors(false);
16
+ }
17
+ }
18
+
19
+ const errorsSummary = buildErrorsSummary($desc, instance);
20
+
21
+ const layoutFn = $desc.layout || buildDefaultLayout;
22
+
23
+ if(!layoutFn) {
24
+ throw new Error('FormControl: layout() must be defined');
25
+ }
26
+
27
+ const form = layoutFn({
28
+ fields: fieldsObject,
29
+ errors: errorsSummary,
30
+ form: instance,
31
+ }, instance);
32
+
33
+ if(!((form instanceof HTMLFormElement) || form?.$element instanceof HTMLFormElement)) {
34
+ throw new Error('FormControl: layout must return an HtmlFormElement');
35
+ }
36
+
37
+ instance.$element = form;
38
+
39
+ form.nd.onSubmit(async (event) => {
40
+ return await instance.submit(event);
41
+ });
42
+
43
+ return form;
44
+ }
45
+
46
+ const buildDefaultLayout = ({ fields, errors, form }) => {
47
+ return Form({ class: 'form-control-default', ...form.resolveProps() }, [
48
+ ...Object.values(fields),
49
+ errors,
50
+ Div({ class: 'form-actions' }, [
51
+ Button('Reset').type('reset'),
52
+ Button('Submit').type('submit'),
53
+ ])
54
+ ]);
55
+ };
56
+
57
+
58
+ const buildErrorsSummary = ($desc, instance) => {
59
+ if($desc.errorsMode === 'dispatch') {
60
+ return null;
61
+ }
62
+
63
+ return ShowIf($desc.errors, () => {
64
+ const errors = $desc.errors.val();
65
+ if(!errors) {
66
+ return null;
67
+ }
68
+
69
+ if($desc.renderErrors) {
70
+ return $desc.renderErrors(errors);
71
+ }
72
+
73
+ return Div({class: 'form-errors'},
74
+ Object.entries(errors).map(([field, msgs]) =>
75
+ Div({class: 'form-error-group'}, [
76
+ Span({class: 'form-error-field'}, field),
77
+ Div({class: 'form-error-messages'},
78
+ msgs.map(msg => Span({class: 'form-error-message'}, msg))
79
+ ),
80
+ ])
81
+ )
82
+ );
83
+ });
84
+ };
@@ -0,0 +1,55 @@
1
+ .field-collection {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--space-comfortable);
5
+ }
6
+
7
+ .field-collection-list {
8
+ display: flex;
9
+ flex-direction: column;
10
+ gap: var(--space-cozy);
11
+ }
12
+
13
+ .field-collection-item {
14
+ display: flex;
15
+ align-items: flex-start;
16
+ gap: var(--space-cozy);
17
+ padding: var(--space-comfortable);
18
+ border: 1px solid var(--field-input-border);
19
+ border-radius: var(--field-input-radius);
20
+ }
21
+
22
+ /* Transitions */
23
+ .fade-enter-from {
24
+ opacity: 0;
25
+ transform: translateY(-8px);
26
+ }
27
+
28
+ .fade-enter-to {
29
+ opacity: 1;
30
+ transform: translateY(0);
31
+ transition: opacity 0.3s ease, transform 0.3s ease;
32
+ }
33
+
34
+ .fade-exit {
35
+ opacity: 0;
36
+ transform: translateY(8px);
37
+ transition: opacity 0.2s ease, transform 0.2s ease;
38
+ }
39
+
40
+ .slide-enter-from {
41
+ opacity: 0;
42
+ transform: translateX(-16px);
43
+ }
44
+
45
+ .slide-enter-to {
46
+ opacity: 1;
47
+ transform: translateX(0);
48
+ transition: opacity 0.3s ease, transform 0.3s ease;
49
+ }
50
+
51
+ .slide-exit {
52
+ opacity: 0;
53
+ transform: translateX(16px);
54
+ transition: opacity 0.2s ease, transform 0.2s ease;
55
+ }
@@ -0,0 +1,143 @@
1
+ import {Div, Input, Span, ShowIf} from '../../../../../elements';
2
+ import {Dropdown} from '../../../../../components';
3
+ import FieldRender from './FieldRender';
4
+ import { $ } from '../../../../../index';
5
+ import {debounce} from "../../../../core/utils/helpers";
6
+
7
+ export default function AutocompleteFieldRender($desc, instance) {
8
+ const $suggestions = $.array([]);
9
+ const $loading = $(false);
10
+
11
+ instance.trailing(ShowIf($loading, Span({class: 'field-loading-spinner'}) ));
12
+
13
+ const input = buildInput($desc, instance, $suggestions, $loading);
14
+ const field = FieldRender($desc, instance, input);
15
+ const dropdown = buildDropdown($desc, instance, field, input, $suggestions);
16
+
17
+ return field.nd.ghostDom(dropdown);
18
+ }
19
+
20
+ const buildInput = ($desc, instance, $suggestions, $loading) => {
21
+ const inputProps = {
22
+ class: 'field-input',
23
+ type: 'text',
24
+ name: $desc.name,
25
+ id: $desc.id || $desc.name,
26
+ placeholder: $desc.placeholder,
27
+ disabled: $desc.disabled,
28
+ readonly: $desc.readonly,
29
+ value: $desc.value,
30
+ autocomplete: 'off',
31
+ ...($desc.elementsProps.input || {}),
32
+ };
33
+
34
+ const input = Input(inputProps);
35
+
36
+ instance.$input = input;
37
+
38
+ const handleSuggestions = debounce(async (query) => {
39
+ if(query.length < ($desc.minChars || 2)) {
40
+ $suggestions.set([]);
41
+ return;
42
+ }
43
+
44
+ $loading.set(true);
45
+ const results = await fetchSuggestions($desc, query);
46
+ $suggestions.set(results.slice(0, $desc.maxResults || 10));
47
+ $loading.set(false);
48
+ }, $desc.debounce || 300);
49
+
50
+
51
+ if($desc.value?.__$Observable) {
52
+ $desc.value.subscribe((val) => handleSuggestions(val));
53
+ } else {
54
+ input.nd.onInput((e) => {
55
+ const query = e.target.value;
56
+ handleSuggestions(query)
57
+ });
58
+ }
59
+
60
+ input.nd.onFocus(() => {
61
+ $desc.focus.set(true);
62
+ if($desc.clearErrorOn === 'focus') {
63
+ $desc.showErrors.set(false);
64
+ }
65
+ });
66
+
67
+ input.nd.onBlur(() => {
68
+ $desc.focus.set(false);
69
+ $desc.showErrors.set(true);
70
+
71
+ if($desc.validateOn === 'blur') {
72
+ instance.validate();
73
+ }
74
+ });
75
+
76
+ $desc.focus.subscribe((focused) => {
77
+ if(focused) {
78
+ input.focus();
79
+ return;
80
+ }
81
+ input.blur();
82
+ });
83
+
84
+ return input;
85
+ };
86
+
87
+ const fetchSuggestions = async ($desc, query) => {
88
+ let source = $desc.source;
89
+ if(!source) {
90
+ return [];
91
+ }
92
+
93
+ if(typeof source === 'function') {
94
+ const results = await source(query);
95
+ return Array.isArray(results) ? results : [];
96
+ }
97
+
98
+ if(source.__$Observable) {
99
+ source = source.val();
100
+ }
101
+
102
+ if(Array.isArray(source)) {
103
+ const labelKey = $desc.labelKey || 'label';
104
+ const q = query.toLowerCase();
105
+ return source.filter(item => {
106
+ const label = typeof item === 'string' ? item : item[labelKey] ?? '';
107
+ return label.toLowerCase().includes(q);
108
+ });
109
+ }
110
+
111
+ return [];
112
+ };
113
+
114
+ const buildDropdown = ($desc, instance, field, trigger, $suggestions) => {
115
+ return Dropdown()
116
+ .trigger(trigger, false)
117
+ .matchTargetWidth(field)
118
+ .atBottomLeading()
119
+ .onFocused()
120
+ .showIf($suggestions.is((value) => value.length > 0))
121
+ .closeOnSelect(false)
122
+ .renderItem($desc.renderItem)
123
+ .bind($suggestions, (item) => {
124
+ const valueKey = $desc.valueKey || 'value';
125
+ const labelKey = $desc.labelKey || 'label';
126
+
127
+ const optValue = typeof item === 'string' ? item : (item[valueKey] ?? item);
128
+ const optLabel = typeof item === 'string' ? item : (item[labelKey] ?? item);
129
+
130
+ return {
131
+ value: optValue,
132
+ label: optLabel,
133
+ data: item,
134
+ action: () => {
135
+ if($desc.value?.__$isObservable) {
136
+ $desc.value.set(optLabel);
137
+ }
138
+ instance.emit('select', item);
139
+ instance.validate();
140
+ },
141
+ };
142
+ });
143
+ };
@@ -0,0 +1,59 @@
1
+ import {Div, Label, Input, Span, ShowIf, ForEachArray} from '../../../../../elements';
2
+ import {buildErrors} from "../helpers";
3
+
4
+ export default function CheckboxFieldRender($desc, instance) {
5
+ const props = instance.getEditableProps();
6
+
7
+ props.class.add('field');
8
+ props.class.add('is-checkbox-field');
9
+ props.class.add({'is-disabled': $desc.disabled});
10
+
11
+ const input = buildCheckbox($desc, instance);
12
+ const label = buildLabel(input, $desc);
13
+
14
+ const content = [
15
+ Div({class: 'field-checkbox-wrapper'}, [input, label]),
16
+ ];
17
+
18
+ if($desc.help) {
19
+ content.push(Span({class: 'field-hint', ...($desc.elementsProps.hint || {})}, $desc.help));
20
+ }
21
+
22
+ content.push(buildErrors($desc));
23
+
24
+ return Div(instance.resolveProps(), content).nd.with({input});
25
+ }
26
+
27
+ const buildCheckbox = ($desc, instance) => {
28
+ const input = Input({
29
+ class: 'field-checkbox',
30
+ type: 'checkbox',
31
+ name: $desc.name,
32
+ id: $desc.id || $desc.name,
33
+ disabled: $desc.disabled,
34
+ checked: $desc.checked,
35
+ ...($desc.elementsProps.input || {}),
36
+ });
37
+
38
+ instance.$input = input;
39
+
40
+ input.nd.onChange((e) => {
41
+ if($desc.validateOn === 'change') {
42
+ instance.validate();
43
+ }
44
+ });
45
+
46
+ return input;
47
+ };
48
+
49
+ const buildLabel = (input, $desc) => {
50
+ if(!$desc.label) {
51
+ return null;
52
+ }
53
+
54
+ return Label({
55
+ class: 'field-checkbox-label',
56
+ for: $desc.id || $desc.name,
57
+ ...($desc.elementsProps.label || {}),
58
+ }, $desc.label);
59
+ };
@@ -0,0 +1,92 @@
1
+ import {Div, Label, Input, Span, ShowIf, ForEachArray} from '../../../../../elements';
2
+ import {buildErrors} from "../helpers";
3
+
4
+ export default function CheckboxGroupFieldRender($desc, instance) {
5
+ const props = instance.getEditableProps();
6
+
7
+ props.class.add('field');
8
+ props.class.add('is-checkbox-group-field');
9
+ props.class.add({'is-disabled': $desc.disabled});
10
+
11
+ const content = [];
12
+
13
+ if($desc.label) {
14
+ content.push(Span({
15
+ class: 'field-label',
16
+ ...($desc.elementsProps.label || {}),
17
+ }, $desc.label));
18
+ }
19
+
20
+ content.push(buildOptions($desc, instance));
21
+
22
+ if($desc.help) {
23
+ content.push(Span({class: 'field-hint', ...($desc.elementsProps.hint || {})}, $desc.help));
24
+ }
25
+
26
+ content.push(buildErrors($desc));
27
+
28
+ return Div(instance.resolveProps(), content);
29
+ }
30
+
31
+ const buildOptions = ($desc, instance) => {
32
+ const options = $desc.options || [];
33
+ const $selected = $desc.value;
34
+
35
+ const isSelected = (optValue) => {
36
+ if(!$selected?.__$Observable) {
37
+ return false;
38
+ }
39
+ return $selected.check(v => Array.isArray(v) && v.includes(optValue));
40
+ };
41
+
42
+ let onToggle = () => {};
43
+
44
+ if($selected?.__$Observable) {
45
+ onToggle = (optValue) => {
46
+ const current = $selected.val() || [];
47
+
48
+ if(current.includes(optValue)) {
49
+ $selected.set(current.filter(v => v !== optValue));
50
+ }
51
+ else {
52
+ $selected.set([...current, optValue]);
53
+ }
54
+
55
+ if($desc.validateOn === 'change') {
56
+ instance.validate();
57
+ }
58
+ };
59
+ }
60
+
61
+ const buildItem = (option) => {
62
+ const optValue = option.value ?? option;
63
+ const optLabel = option.label ?? option;
64
+ const optId = ($desc.id || $desc.name) + '-' + optValue;
65
+ const $checked = isSelected(optValue);
66
+
67
+ const input = Input({
68
+ class: 'field-checkbox',
69
+ type: 'checkbox',
70
+ id: optId,
71
+ name: $desc.name,
72
+ value: optValue,
73
+ checked: $checked,
74
+ disabled: $desc.disabled,
75
+ });
76
+
77
+ input.nd.onChange(() => onToggle(optValue));
78
+
79
+ return Div({class: 'field-checkbox-wrapper'}, [
80
+ input,
81
+ Label({
82
+ class: 'field-checkbox-label',
83
+ for: optId,
84
+ }, optLabel),
85
+ ]);
86
+ };
87
+
88
+ return Div({
89
+ class: 'field-checkbox-group is-' + ($desc.layout || 'vertical'),
90
+ ...($desc.elementsProps.wrapper || {}),
91
+ }, ForEachArray($desc.options, buildItem));
92
+ };
@@ -0,0 +1,30 @@
1
+ import FieldRender from './FieldRender';
2
+ import {Input, Span} from '../../../../../elements';
3
+
4
+ export default function ColorFieldRender($desc, instance) {
5
+ const $colorPreview = Span({
6
+ class: 'field-color-preview',
7
+ style: {
8
+ background: $desc.value?.__$isObservable
9
+ ? $desc.value
10
+ : $desc.value || 'transparent',
11
+ },
12
+ });
13
+
14
+ instance.leading($colorPreview);
15
+
16
+ const input = Input({
17
+ class: 'field-input field-color-input',
18
+ type: 'color',
19
+ name: $desc.name,
20
+ id: $desc.id || $desc.name,
21
+ disabled: $desc.disabled,
22
+ value: $desc.value,
23
+ ...($desc.elementsProps.input || {}),
24
+ });
25
+
26
+ instance.$input = input;
27
+ $colorPreview.nd.onClick(() => input.click());
28
+
29
+ return FieldRender($desc, instance, input);
30
+ }
@@ -0,0 +1,154 @@
1
+ import {Div, Input, Label, Span, ShowIf, Switch} from '../../../../../elements';
2
+ import {buildErrors, buildInputWithSlots} from '../helpers';
3
+ import './date-field.css';
4
+
5
+ export default function DateFieldRender($desc, instance) {
6
+ const props = instance.getEditableProps();
7
+
8
+ props.class.add('field');
9
+ props.class.add('is-date-field');
10
+ props.class.add({ 'is-disabled': $desc.disabled, 'has-error': $desc.hasErrors });
11
+
12
+ const content = [];
13
+
14
+ if($desc.label) {
15
+ content.push(buildLabel($desc));
16
+ }
17
+
18
+ const inputType = ($desc.withTime?.__$isObservable
19
+ ? $desc.withTime.transform((hasTime) => (hasTime ? 'datetime-local' : 'date'))
20
+ : ($desc.withTime ? 'datetime-local' : 'date'));
21
+
22
+ if($desc.range?.__$Observable) {
23
+ content.push(
24
+ Switch($desc.range,
25
+ () => buildRangeWrapper($desc, instance, inputType),
26
+ () => buildSingleWrapper($desc, instance, inputType)
27
+ )
28
+ );
29
+ }
30
+ else {
31
+ content.push(buildSingleWrapper($desc, instance, inputType));
32
+ }
33
+
34
+ if($desc.help) {
35
+ content.push(
36
+ Span({ class: 'field-hint', ...($desc.elementsProps.hint || {}) }, $desc.help)
37
+ );
38
+ }
39
+
40
+ content.push(buildErrors($desc));
41
+
42
+ return Div(instance.resolveProps(), content);
43
+ }
44
+
45
+ const buildLabel = ($desc) => {
46
+ return Label({
47
+ class: 'field-label',
48
+ for: $desc.id || $desc.name,
49
+ ...($desc.elementsProps.label || {}),
50
+ }, $desc.label);
51
+ };
52
+
53
+ const buildSingleWrapper = ($desc, instance, inputType) => {
54
+ const input = buildInput($desc, instance, inputType, $desc.value, $desc.name);
55
+
56
+ const controls = [];
57
+
58
+ let callback = null;
59
+ if($desc.clearable) {
60
+ if($desc.value?.__$isObservable) {
61
+ callback = () => {
62
+ instance.emit('clear');
63
+ $desc.value.set(null);
64
+ }
65
+ } else {
66
+ callback = (e) => {
67
+ e.target.value = '';
68
+ instance.emit('clear');
69
+ };
70
+ }
71
+ }
72
+
73
+ return Div({class: 'date-field-single'}, [
74
+ buildInputWithSlots(input, $desc, instance, { onClear: callback } ),
75
+ controls.length ? Div({class: 'date-field-controls'}, controls) : null,
76
+ ]);
77
+ };
78
+
79
+ const buildRangeWrapper = ($desc, instance, inputType) => {
80
+ const startInput = buildInput($desc, instance, inputType, $desc.valueStart, $desc.name + '_start');
81
+ const endInput = buildInput($desc, instance, inputType, $desc.valueEnd, $desc.name + '_end');
82
+
83
+ let callback;
84
+ if($desc.valueStart?.__$Observable && $desc.valueEnd?.__$Observable) {
85
+ callback = () => {
86
+ instance.emit('change', { start: $desc.valueStart.val(), end: $desc.valueEnd?.val() });
87
+
88
+ if((new Date($desc.valueEnd.val())) < (new Date($desc.valueStart.val()))) {
89
+ $desc.valueEnd.set($desc.valueStart.val());
90
+ }
91
+ }
92
+ } else {
93
+ callback = () => {
94
+ if((new Date(endInput.value)) < (new Date(startInput.value))) {
95
+ endInput.value = startInput.value;
96
+ }
97
+ };
98
+ }
99
+
100
+ startInput.nd.onChange(callback);
101
+ endInput.nd.onChange(callback);
102
+
103
+ if($desc.valueEnd?.__$Observable) {
104
+ endInput.nd.onChange((e) => {
105
+ instance.emit('change', { start: $desc.valueStart?.val(), end: $desc.valueEnd.val() });
106
+ });
107
+ }
108
+ else {
109
+ endInput.nd.onChange((e) => {
110
+ instance.emit('change', { start: startInput.value, end: endInput.value });
111
+ });
112
+ }
113
+
114
+ return Div({class: 'date-field-range'}, [
115
+ Div({class: 'date-field-range-start'}, [
116
+ Span({class: 'date-field-range-label'}, 'From'),
117
+ buildInputWithSlots(startInput, $desc, instance, { source: 'valueStart', onClear: null } )
118
+ ]),
119
+ Span({class: 'date-field-range-separator'}, $desc.rangeSeparator),
120
+ Div({class: 'date-field-range-end'}, [
121
+ Span({class: 'date-field-range-label'}, 'To'),
122
+ buildInputWithSlots(endInput, $desc, instance, { source: 'valueEnd', onClear: null } )
123
+ ]),
124
+ ]);
125
+ };
126
+
127
+ const buildInput = ($desc, instance, inputType, $value, name) => {
128
+
129
+ const input = Input({
130
+ class: 'field-input',
131
+ type: inputType,
132
+ name: name,
133
+ id: $desc.id || $desc.name,
134
+ disabled: $desc.disabled,
135
+ readonly: $desc.readonly,
136
+ min: $desc.minDate || null,
137
+ max: $desc.maxDate || null,
138
+ step: $desc.timeStep || null,
139
+ value: $value,
140
+ ...($desc.elementsProps.input || {}),
141
+ });
142
+
143
+ instance.$input = input;
144
+
145
+ input.nd.onChange($value?.__$Observable ? (e) => {
146
+ instance.emit('change', $value.val());
147
+ instance.validate();
148
+ }: (e) => {
149
+ instance.emit('change', e.target.value);
150
+ instance.validate();
151
+ });
152
+
153
+ return input;
154
+ };
@@ -0,0 +1,5 @@
1
+ import FieldRender from "./FieldRender";
2
+
3
+ const EmailFieldRender = FieldRender;
4
+
5
+ export default EmailFieldRender;