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,67 @@
1
+ import {Div, Input, Span} from "../../../../../elements";
2
+ import {Button} from "../../../../components/button";
3
+ import {SelectField} from "../../../../components/form";
4
+
5
+ export const buildToolbar = ({ search, filters, exportBtn, columnsBtn }) => {
6
+ return Div({class: 'data-table-toolbar'}, [
7
+ Div({class: 'data-table-toolbar-left'}, [search, filters]),
8
+ Div({class: 'data-table-toolbar-right'}, [exportBtn, columnsBtn]),
9
+ ]);
10
+ };
11
+
12
+ export const buildSearch = ($desc, instance) => {
13
+ if(!$desc.searchable) {
14
+ return null;
15
+ }
16
+
17
+ return Div({class: 'data-table-search-wrapper'}, [
18
+ Span({class: 'data-table-search-icon'}, $desc.searchIcon),
19
+ Input({
20
+ class: 'data-table-search',
21
+ type: 'text',
22
+ placeholder: $desc.labels.searchPlaceholder,
23
+ value: $desc.$search,
24
+ }).nd.onInput((e) => instance.emit('search', e.target.value)),
25
+ ]);
26
+ };
27
+
28
+ export const buildFiltersBtn = ($desc, instance) => {
29
+ if(!$desc.filterable) {
30
+ return null;
31
+ }
32
+
33
+ const btn = Button($desc.labels.filters)
34
+ .secondary()
35
+ .small();
36
+
37
+ btn.nd.onClick(() => instance.emit('openFilters'));
38
+
39
+ return btn;
40
+ };
41
+
42
+ export const buildExportBtn = ($desc, instance) => {
43
+ if(!$desc.exports?.length) return null;
44
+
45
+ if($desc.exports.length === 1) {
46
+ const btn = Button($desc.labels.export)
47
+ .secondary()
48
+ .small();
49
+
50
+ return btn.nd.onClick(() => instance.emit('export', $desc.exports[0].format));
51
+ }
52
+
53
+ return SelectField()
54
+ .placeholder($desc.labels.export)
55
+ .options($desc.exports.map((item) => ({ label: item.label, value: item.format })))
56
+ .onChange((value) => instance.emit('export', value));
57
+ };
58
+
59
+ export const buildColumnsBtn = ($desc, instance) => {
60
+ const btn = Button($desc.labels.columns)
61
+ .secondary()
62
+ .small();
63
+
64
+ btn.nd.onClick(() => instance.emit('openColumns'));
65
+
66
+ return btn;
67
+ };
@@ -0,0 +1,191 @@
1
+ import {Table, THead, TBody, TRow, THeadCell, TBodyCell, Div, Span, ShowIf} from '../../../../../elements';
2
+ import './simple-table.css';
3
+
4
+ export default function SimpleTableRender($desc, instance) {
5
+ const props = instance.getEditableProps();
6
+ props.class.add('simple-table');
7
+
8
+ const visibleColumns = $desc.columns.filter(col =>
9
+ col.$description.visible !== false
10
+ );
11
+
12
+ return Table(instance.resolveProps(), [
13
+ $desc.noHeader ? null : buildHead($desc, visibleColumns),
14
+ buildBody($desc, instance, visibleColumns),
15
+ ]);
16
+ }
17
+
18
+ const buildGroupRow = ($desc) => {
19
+ return TRow({},
20
+ $desc.header.map(item => {
21
+ if(item.isGroup) {
22
+ const extraProps = $desc.headerProps?.(item) || {};
23
+ return THeadCell({
24
+ colspan: item.$description.columns.length,
25
+ class: item.$description.align ? `is-${item.$description.align}` : null,
26
+ ...extraProps,
27
+ }, item.$description.header);
28
+ }
29
+ const extraProps = $desc.headerProps?.(item) || {};
30
+ return THeadCell({
31
+ rowspan: 2,
32
+ class: item.$description.align ? `is-${item.$description.align}` : null,
33
+ ...extraProps,
34
+ }, item.$description.header);
35
+ })
36
+ );
37
+ };
38
+
39
+ const buildHeaderRow = ($desc, visibleColumns) => {
40
+ return TRow({},
41
+ visibleColumns.map(col => {
42
+ const extraProps = $desc.headerProps?.(col) || {};
43
+ return THeadCell({
44
+ class: col.$description.align ? `is-${col.$description.align}` : null,
45
+ colspan: col.$description.colspan || null,
46
+ rowspan: col.$description.rowspan || null,
47
+ ...extraProps,
48
+ }, col.$description.header);
49
+ })
50
+ );
51
+ };
52
+
53
+ const buildHead = ($desc, visibleColumns) => {
54
+ if($desc.hasGroups) {
55
+ return THead({}, [
56
+ buildGroupRow($desc),
57
+ buildHeaderRow($desc, visibleColumns),
58
+ ]);
59
+ }
60
+ return THead({}, buildHeaderRow($desc, visibleColumns));
61
+ };
62
+
63
+ const buildBody = ($desc, instance, visibleColumns) => {
64
+ const tbody = TBody({}, buildEmpty($desc, visibleColumns));
65
+
66
+ const createRow = (row) => buildRow($desc, visibleColumns, row);
67
+
68
+ const mutations = {
69
+ toFragment: (args) => {
70
+ const fragment = document.createDocumentFragment();
71
+
72
+ for(let i = 0, length = args.length; i < length; i++) {
73
+ fragment.append(createRow(args[i]));
74
+ }
75
+
76
+ return fragment;
77
+ },
78
+ push: (args) => {
79
+ tbody.append(mutations.toFragment(args));
80
+ },
81
+ unshift: (args) => {
82
+ const first = tbody.firstChild;
83
+ tbody.insertBefore(mutations.toFragment(args), first);
84
+ },
85
+ splice: (args) => {
86
+ const [start, deleteCount, ...newRows] = args;
87
+ const rows = [...tbody.children];
88
+ for(let i = 0; i < deleteCount; i++) {
89
+ rows[start + i]?.remove();
90
+ }
91
+ if(newRows.length === 0) {
92
+ return;
93
+ }
94
+ const ref = tbody.children[start] || null;
95
+ tbody.insertBefore(mutations.toFragment(newRows), ref);
96
+ },
97
+ remove: (args) => {
98
+ tbody.children[args[0]]?.remove();
99
+ },
100
+ swap: (args) => {
101
+ const [a, b] = args;
102
+ const rows = [...tbody.children];
103
+ const elA = rows[a];
104
+ const elB = rows[b];
105
+ if(!elA || !elB) {
106
+ return;
107
+ }
108
+ const refB = elB.nextSibling;
109
+ tbody.insertBefore(elA, refB);
110
+ tbody.insertBefore(elB, rows[a]);
111
+ },
112
+ clear: () => {
113
+ tbody.innerHTML = '';
114
+ },
115
+ merge: (args) => {
116
+ return mutations.push(args);
117
+ },
118
+ };
119
+
120
+ if(!$desc.data?.__$isObservableArray) {
121
+ const data = $desc.data || [];
122
+ for(let i = 0, length = data.length; i < length; i++) {
123
+ tbody.append(createRow(data[i]));
124
+ }
125
+ return tbody;
126
+ }
127
+
128
+ for(let i = 0, length = $desc.data.length; i < length; i++) {
129
+ tbody.append(createRow($desc.data.at(i)));
130
+ }
131
+
132
+ $desc.data.subscribe((data, _, operations) => {
133
+ const handler = mutations[operations.action];
134
+ if(handler) {
135
+ handler(operations.args);
136
+ }
137
+ });
138
+
139
+ return tbody;
140
+ };
141
+
142
+
143
+ const buildRow = ($desc, visibleColumns, row) => {
144
+ const cells = [];
145
+ for(let i = 0, length = visibleColumns.length; i < length; i++) {
146
+ const column = visibleColumns[i];
147
+
148
+ const key = column.$description.key;
149
+ const value = row[key];
150
+ const content = column.$description.render
151
+ ? column.$description.render(value, row)
152
+ : value ?? '';
153
+
154
+ const extraProps = $desc.cellProps?.(value, row, column) || {};
155
+ const cell = TBodyCell({ class: column.$description.align ? `is-${column.$description.align}` : null, ...extraProps,},
156
+ content
157
+ );
158
+ if(column.$description.onClick) {
159
+ cell.nd.onClick((event) => column.$description.onClick(row, event));
160
+ }
161
+ cells.push(cell);
162
+ }
163
+
164
+ const rowExtraProps = $desc.rowProps?.(row) || {};
165
+
166
+ const tr = TRow({ class: { 'has-click': !!$desc.onRowClick}, ...rowExtraProps,}, cells);
167
+
168
+ if($desc.onRowClick) {
169
+ tr.nd.onClick(() => $desc.onRowClick(row));
170
+ }
171
+
172
+ return tr;
173
+ };
174
+
175
+ const buildEmpty = ($desc, visibleColumns) => {
176
+ if(!$desc.empty) {
177
+ return null;
178
+ }
179
+
180
+ const content = typeof $desc.empty === 'function'
181
+ ? $desc.empty()
182
+ : Span({class: 'simple-table-empty-text'}, $desc.empty);
183
+
184
+ const row = TRow({class: 'simple-table-empty'}, [
185
+ TBodyCell({colspan: visibleColumns.length, class: 'simple-table-empty-cell'}, content),
186
+ ]);
187
+ if($desc.data?.__$isObservableArray) {
188
+ return ShowIf($desc.data.is((items) => items.length === 0), row);
189
+ }
190
+ return row;
191
+ };
@@ -0,0 +1,50 @@
1
+ :root {
2
+ --simple-table-font-size: var(--description-size);
3
+ --simple-table-cell-padding-v: var(--space-cozy);
4
+ --simple-table-cell-padding-h: var(--space-comfortable);
5
+ --simple-table-border-color: var(--color-border-tertiary);
6
+ --simple-table-header-color: var(--color-text-secondary);
7
+ --simple-table-header-bg: var(--color-background-secondary);
8
+ --simple-table-header-weight: 600;
9
+ --simple-table-hover-bg: var(--color-background-secondary);
10
+ --simple-table-empty-padding: var(--space-large);
11
+ --simple-table-empty-color: var(--color-text-secondary);
12
+ }
13
+
14
+ .simple-table {
15
+ width: 100%;
16
+ border-collapse: collapse;
17
+ font-size: var(--simple-table-font-size);
18
+
19
+ th, td {
20
+ padding: var(--simple-table-cell-padding-v) var(--simple-table-cell-padding-h);
21
+ text-align: left;
22
+ border-bottom: 1px solid var(--simple-table-border-color);
23
+
24
+ &.is-center { text-align: center; }
25
+ &.is-right { text-align: right; }
26
+ }
27
+
28
+ th {
29
+ font-weight: var(--simple-table-header-weight);
30
+ color: var(--simple-table-header-color);
31
+ background: var(--simple-table-header-bg);
32
+ white-space: nowrap;
33
+ }
34
+
35
+ tr.has-click {
36
+ cursor: pointer;
37
+
38
+ &:hover td {
39
+ background: var(--simple-table-hover-bg);
40
+ }
41
+ }
42
+ }
43
+
44
+ .simple-table-empty {
45
+ .simple-table-empty-cell {
46
+ text-align: center;
47
+ padding: var(--simple-table-empty-padding);
48
+ color: var(--simple-table-empty-color);
49
+ }
50
+ }
@@ -0,0 +1,226 @@
1
+ import {Div, ForEachArray, Match, Nav, ShowIf, Span} from '../../../core/elements';
2
+ import { $ } from '../../../../index';
3
+ import {Button} from "../../../components/button";
4
+ import {Dropdown} from '../../../components/dropdown';
5
+ import {nextTick} from "../../../core/utils/helpers";
6
+
7
+ import './tabs.css';
8
+
9
+ export default function TabsRender($desc, instance) {
10
+ const props = instance.getEditableProps();
11
+
12
+ props.class.add('tabs');
13
+ props.class.add('is-appearance-' + $desc.tabAppearance);
14
+ props.class.add('is-align-' + $desc.tabsAlignment);
15
+ props.class.add('is-overflow-' + $desc.overflow);
16
+
17
+ if($desc.stickyHeader) {
18
+ props.class.add('has-sticky-header');
19
+ }
20
+ if($desc.navigationBarPosition) {
21
+ props.class.add('is-navigation-at-' + $desc.navigationBarPosition);
22
+ }
23
+
24
+ if($desc.closable) {
25
+ props.class.add('is-closable');
26
+ }
27
+
28
+ const tabKeys = Object.keys($desc.tabs);
29
+
30
+ if(tabKeys.length && !$desc.active.val()) {
31
+ $desc.active.set(tabKeys[0]);
32
+ }
33
+
34
+ const $keys = $.array(tabKeys);
35
+ const panels = Match($desc.active, buildContentPanels($desc, instance, tabKeys));
36
+
37
+ instance.onCloseTab((key) => {
38
+ panels.remove(key);
39
+ $keys.removeItem(key);
40
+ });
41
+
42
+ instance.onAddTab((tab) => {
43
+ $keys.push(tab.key);
44
+ panels.add(tab.key, Div({ role: 'tabpanel', class: 'tabs-panel' }, tab.content));
45
+ if($desc.focusOnNewTab) {
46
+ $desc.active.set(tab.key);
47
+ }
48
+ });
49
+
50
+ return Div(instance.resolveProps(), [
51
+ Div({class: 'tabs-nav'}, buildNavContent($keys, $desc, instance)),
52
+ Div({class: 'tabs-content'}, panels),
53
+ ]);
54
+ }
55
+
56
+ const buildNavContent = ($keys, $desc, instance) => {
57
+ const tabItemWrapper = Nav({class: 'tabs-nav-wrap', role: 'tablist' },
58
+ ForEachArray($keys, (key) => buildTab(key, $keys, $desc, instance))
59
+ );
60
+
61
+ const navOptionsContent = [];
62
+
63
+ if($desc.addPlusButton) {
64
+ const btnPlusButton = $desc.renderPlusButton
65
+ ? $desc.renderPlusButton($desc, instance)
66
+ : Button('+').ghost();
67
+
68
+ navOptionsContent.push(
69
+ btnPlusButton
70
+ .nd.onClick(() => {
71
+ $desc.addPLusCallback && $desc.addPLusCallback($desc, instance);
72
+ })
73
+ );
74
+ }
75
+
76
+ if($desc.overflow) {
77
+ navOptionsContent.push(
78
+ Div({class: 'tab-nav-overflow'}, buildOverflowMenu(tabItemWrapper, $keys, $desc, instance))
79
+ );
80
+ }
81
+
82
+ return [
83
+ tabItemWrapper,
84
+ Div({ class: 'tab-nav-options'}, navOptionsContent)
85
+ ];
86
+ };
87
+
88
+ const buildContentPanels = ($desc, instance, keys) => {
89
+ const panels = {};
90
+
91
+ for(const key of keys) {
92
+ const tab = $desc.tabs[key];
93
+ panels[key] = Div({ role: 'tabpanel', class: 'tabs-panel' }, tab.content);
94
+ }
95
+
96
+ return panels;
97
+ };
98
+
99
+ const buildOverflowMenu = (tabItemWrapper, $keys, $desc, instance) => {
100
+ const $overflowKeys = $.array([]);
101
+
102
+ const isVerticalNavigationBar = $desc.navigationBarPosition === 'left' || $desc.navigationBarPosition === 'right';
103
+ const checkOverflowHandler = nextTick(() => {
104
+ const wrapperRect = tabItemWrapper.getBoundingClientRect();
105
+ const tabs = [...tabItemWrapper.children];
106
+ const overflow = [];
107
+
108
+ if(isVerticalNavigationBar) {
109
+ for(const tab of tabs) {
110
+ const rect = tab.getBoundingClientRect();
111
+ if(rect.top < wrapperRect.top || rect.bottom > wrapperRect.bottom) {
112
+ overflow.push(tab.dataset.key);
113
+ }
114
+ }
115
+ } else {
116
+ for(const tab of tabs) {
117
+ const rect = tab.getBoundingClientRect();
118
+ if(rect.left < wrapperRect.left || rect.right > wrapperRect.right) {
119
+ overflow.push(tab.dataset.key);
120
+ }
121
+ }
122
+ }
123
+
124
+ $overflowKeys.set(overflow);
125
+ });
126
+ const observer = new ResizeObserver(checkOverflowHandler);
127
+
128
+ instance.onChange(checkOverflowHandler);
129
+ tabItemWrapper.addEventListener('scroll', checkOverflowHandler);
130
+
131
+ observer.observe(tabItemWrapper);
132
+ const $hasOverflowItem = $overflowKeys.is(values => values.length > 0);
133
+
134
+ return ShowIf($hasOverflowItem, () => {
135
+ return Dropdown()
136
+ .bind($overflowKeys, (key) => {
137
+ const tab = $desc.tabs[key];
138
+ return { content: tab.label, icon: tab.icon || null, value: key};
139
+ })
140
+ .atBottomTrailing()
141
+ .trigger(Button('▾').ghost().small())
142
+ .onChange((key) => $desc.active.set(key))
143
+ });
144
+ };
145
+
146
+ const buildTab = (key, $keys, $desc, instance) => {
147
+ const tab = $desc.tabs[key];
148
+
149
+ if($desc.renderTab) {
150
+ return $desc.renderTab(tab, key, instance);
151
+ }
152
+
153
+ const isActive = $desc.active.is(key);
154
+
155
+ const tabEl = Div({
156
+ class: { 'tabs-tab': true, 'is-active': isActive },
157
+ 'aria-selected': isActive,
158
+ 'data-key': key,
159
+ draggable: true,
160
+ role: 'tab'
161
+ }, buildTabContent(tab, $desc, instance));
162
+
163
+
164
+ tabEl
165
+ .nd
166
+ .onClick(() => {
167
+ instance.emit('tabClick', key, tab);
168
+ instance.emit('beforeChange', key);
169
+ $desc.active.set(key);
170
+ instance.emit('change', key, tab);
171
+ });
172
+
173
+ if($desc.sortable) {
174
+ tabEl
175
+ .nd
176
+ .onDragStart((e) => {
177
+ e.dataTransfer.setData('text/plain', key);
178
+ setTimeout(() => tabEl.classList.add('is-dragging'), 0);
179
+ })
180
+ .onDragEnd(() => {
181
+ tabEl.classList.remove('is-dragging');
182
+ tabEl.classList.remove('is-drag-over');
183
+ })
184
+ .onDragOver((e) => {
185
+ e.preventDefault();
186
+ e.dataTransfer.dropEffect = 'move';
187
+ tabEl.classList.add('is-drag-over');
188
+ })
189
+ .onDragLeave(() => {
190
+ tabEl.classList.remove('is-drag-over');
191
+ })
192
+ .onDrop((e) => {
193
+ const draggedKey = e.dataTransfer.getData('text/plain');
194
+ tabEl.classList.remove('is-drag-over');
195
+ $keys.swapItems(draggedKey, key);
196
+ });
197
+ }
198
+
199
+ return tabEl;
200
+ };
201
+
202
+ const buildTabContent = (tab, $desc, instance) => {
203
+ const content = [];
204
+
205
+ if(tab.icon) {
206
+ content.push(Span({class: 'tabs-tab-icon'}, tab.icon));
207
+ }
208
+
209
+ content.push(Span({class: 'tabs-tab-label'}, tab.label));
210
+
211
+ if($desc.closable) {
212
+ const closeButton = $desc.renderCloseButton
213
+ ? $desc.renderCloseButton(tab)
214
+ : Span({ class: 'tabs-tab-closer' }, '×');
215
+
216
+ content.push(
217
+ closeButton
218
+ .nd.onClick((e) => {
219
+ e.stopPropagation();
220
+ instance.closeTab(tab.key);
221
+ })
222
+ );
223
+ }
224
+
225
+ return content;
226
+ };