native-document 1.0.166 → 1.0.168

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 (108) hide show
  1. package/.vitepress/config.js +166 -0
  2. package/CHANGELOG.md +153 -0
  3. package/components.js +2 -1
  4. package/dist/native-document.components.min.js +495 -228
  5. package/dist/native-document.dev.js +7 -0
  6. package/dist/native-document.dev.js.map +1 -1
  7. package/dist/native-document.min.js +1 -1
  8. package/docs/advanced-components.md +213 -608
  9. package/docs/anchor.md +173 -312
  10. package/docs/cache.md +95 -803
  11. package/docs/cli.md +179 -0
  12. package/docs/components/accordion.md +172 -0
  13. package/docs/components/alert.md +99 -0
  14. package/docs/components/avatar.md +160 -0
  15. package/docs/components/badge.md +102 -0
  16. package/docs/components/breadcrumb.md +89 -0
  17. package/docs/components/button.md +183 -0
  18. package/docs/components/card.md +69 -0
  19. package/docs/components/context-menu.md +118 -0
  20. package/docs/components/data-table.md +345 -0
  21. package/docs/components/dropdown.md +214 -0
  22. package/docs/components/form/autocomplete-field.md +81 -0
  23. package/docs/components/form/checkbox-field.md +41 -0
  24. package/docs/components/form/checkbox-group-field.md +54 -0
  25. package/docs/components/form/color-field.md +64 -0
  26. package/docs/components/form/date-field.md +92 -0
  27. package/docs/components/form/field-collection.md +63 -0
  28. package/docs/components/form/file-field.md +203 -0
  29. package/docs/components/form/form-control.md +87 -0
  30. package/docs/components/form/image-field.md +90 -0
  31. package/docs/components/form/index.md +115 -0
  32. package/docs/components/form/number-field.md +65 -0
  33. package/docs/components/form/radio-field.md +51 -0
  34. package/docs/components/form/select-field.md +123 -0
  35. package/docs/components/form/slider.md +136 -0
  36. package/docs/components/form/string-field.md +134 -0
  37. package/docs/components/form/textarea-field.md +65 -0
  38. package/docs/components/form-fields.md +372 -0
  39. package/docs/components/getting-started.md +264 -0
  40. package/docs/components/index.md +337 -0
  41. package/docs/components/layout.md +279 -0
  42. package/docs/components/list.md +73 -0
  43. package/docs/components/menu.md +215 -0
  44. package/docs/components/modal.md +156 -0
  45. package/docs/components/pagination.md +95 -0
  46. package/docs/components/popover.md +131 -0
  47. package/docs/components/progress.md +111 -0
  48. package/docs/components/shortcut-manager.md +221 -0
  49. package/docs/components/simple-table.md +107 -0
  50. package/docs/components/skeleton.md +155 -0
  51. package/docs/components/spinner.md +100 -0
  52. package/docs/components/splitter.md +133 -0
  53. package/docs/components/stepper.md +163 -0
  54. package/docs/components/switch.md +113 -0
  55. package/docs/components/tabs.md +153 -0
  56. package/docs/components/toast.md +119 -0
  57. package/docs/components/tooltip.md +151 -0
  58. package/docs/components/traits.md +261 -0
  59. package/docs/conditional-rendering.md +170 -588
  60. package/docs/contributing.md +300 -25
  61. package/docs/core-concepts.md +205 -374
  62. package/docs/elements.md +251 -367
  63. package/docs/extending-native-document-element.md +192 -207
  64. package/docs/filters.md +153 -1122
  65. package/docs/getting-started.md +193 -267
  66. package/docs/i18n.md +241 -0
  67. package/docs/index.md +76 -0
  68. package/docs/lifecycle-events.md +143 -75
  69. package/docs/list-rendering.md +227 -852
  70. package/docs/memory-management.md +134 -47
  71. package/docs/native-document-element.md +337 -186
  72. package/docs/native-fetch.md +99 -630
  73. package/docs/observable-resource.md +364 -0
  74. package/docs/observables.md +592 -526
  75. package/docs/routing.md +244 -653
  76. package/docs/state-management.md +134 -241
  77. package/docs/svg-elements.md +231 -0
  78. package/docs/theming.md +409 -0
  79. package/docs/tutorials/.gitkeep +0 -0
  80. package/docs/validation.md +95 -97
  81. package/docs/vitepress-conventions.md +219 -0
  82. package/package.json +34 -13
  83. package/readme.md +269 -89
  84. package/src/components/card/Card.js +93 -39
  85. package/src/components/card/index.js +1 -1
  86. package/src/components/list/HasListItem.js +171 -0
  87. package/src/components/list/List.js +41 -107
  88. package/src/components/list/ListDivider.js +39 -0
  89. package/src/components/list/ListGroup.js +76 -59
  90. package/src/components/list/ListItem.js +117 -69
  91. package/src/components/list/index.js +3 -1
  92. package/src/components/list/types/ListItem.d.ts +45 -34
  93. package/src/components/spacer/Spacer.js +1 -1
  94. package/src/core/data/ObservableResource.js +5 -0
  95. package/src/core/data/observable-helpers/observable.prototypes.js +2 -0
  96. package/src/ui/components/card/CardRender.js +133 -0
  97. package/src/ui/components/card/card.css +169 -0
  98. package/src/ui/components/contextmenu/ContextmenuRender.js +1 -1
  99. package/src/ui/components/list/ListRender.js +18 -0
  100. package/src/ui/components/list/divider/ListDividerRender.js +10 -0
  101. package/src/ui/components/list/divider/list-divider.css +12 -0
  102. package/src/ui/components/list/group/ListGroupRender.js +61 -0
  103. package/src/ui/components/list/group/list-group.css +62 -0
  104. package/src/ui/components/list/item/ListItemRender.js +238 -0
  105. package/src/ui/components/list/item/list-item.css +191 -0
  106. package/src/ui/components/list/list.css +24 -0
  107. package/src/ui/components/spacer/SpacerRender.js +10 -0
  108. package/src/ui/index.js +8 -0
@@ -0,0 +1,133 @@
1
+ import { Div, Img, Span } from '../../../core/elements';
2
+
3
+ import './card.css';
4
+ import {Button} from '../../../components/button';
5
+
6
+ export default function CardRender($desc, instance) {
7
+ const imageSlot = buildImage($desc, instance);
8
+ const headerSlot = buildHeader($desc, instance);
9
+ const contentSlot = buildContent($desc, instance);
10
+ const actionsSlot = buildActions($desc, instance);
11
+ const footerSlot = buildFooter($desc, instance, actionsSlot);
12
+
13
+ if ($desc.layout) {
14
+ return $desc.layout(
15
+ { image: imageSlot, header: headerSlot, content: contentSlot, actions: actionsSlot, footer: footerSlot },
16
+ instance,
17
+ );
18
+ }
19
+
20
+ const props = instance.getEditableProps();
21
+
22
+ props.class.add('card');
23
+
24
+ if ($desc.variant) {
25
+ props.class.add('is-' + $desc.variant);
26
+ }
27
+
28
+ props.class.add({
29
+ 'is-horizontal': $desc.horizontal,
30
+ 'is-hoverable': $desc.hoverable,
31
+ 'is-clickable': instance.hasListeners('click'),
32
+ });
33
+
34
+ if ($desc.loading) {
35
+ props.class.add({ 'is-loading': $desc.loading });
36
+ }
37
+
38
+ const children = [
39
+ imageSlot,
40
+ Div({ class: 'card-content'}, [
41
+ Div({ class: 'card-body' }, [headerSlot, contentSlot]),
42
+ footerSlot,
43
+ ]),
44
+ ];
45
+
46
+ const el = Div(instance.resolveProps(), children);
47
+
48
+ el.nd.onClick((e) => instance.emit('click', e));
49
+ el.nd.onMouseEnter((e) => instance.emit('hover', e));
50
+
51
+ return el;
52
+ }
53
+
54
+ function buildImage($desc, instance) {
55
+ if ($desc.renderImage) {
56
+ return $desc.renderImage($desc, instance);
57
+ }
58
+
59
+ if (!$desc.image) {
60
+ return null;
61
+ }
62
+
63
+ return Div({ class: 'card-image-wrapper' }, [
64
+ Img($desc.image, {
65
+ class: `card-image is-${$desc.imagePosition}`,
66
+ alt: '',
67
+ })
68
+ ]);
69
+ }
70
+
71
+ function buildHeader($desc, instance) {
72
+ if ($desc.renderHeader) {
73
+ return $desc.renderHeader($desc, instance);
74
+ }
75
+
76
+ const parts = [];
77
+
78
+ if ($desc.title) {
79
+ parts.push(Span({ class: 'card-title' }, $desc.title));
80
+ }
81
+
82
+ if ($desc.subtitle) {
83
+ parts.push(Span({ class: 'card-subtitle' }, $desc.subtitle));
84
+ }
85
+
86
+ if (!parts.length) {
87
+ return null;
88
+ }
89
+
90
+ return Div({ class: 'card-header' }, parts);
91
+ }
92
+
93
+ function buildContent($desc, instance) {
94
+ if ($desc.renderContent) {
95
+ return $desc.renderContent($desc, instance);
96
+ }
97
+
98
+ if (!$desc.content) {
99
+ return null;
100
+ }
101
+
102
+ return Div({ class: 'card-content' }, $desc.content);
103
+ }
104
+
105
+ function buildActions($desc, instance) {
106
+ if ($desc.renderActions) {
107
+ return $desc.renderActions($desc, instance);
108
+ }
109
+
110
+ if (!$desc.actions?.length) {
111
+ return null;
112
+ }
113
+
114
+ const buttons = $desc.actions.map(({ label, callback }) => {
115
+ const btn = (typeof label === 'string') ? Button(label, { class: 'card-action' }) : label;
116
+ btn.nd.onClick(() => callback?.());
117
+ return btn;
118
+ });
119
+
120
+ return Div({ class: 'card-actions' }, buttons);
121
+ }
122
+
123
+ function buildFooter($desc, instance, actionsSlot) {
124
+ if ($desc.renderFooter) {
125
+ return $desc.renderFooter($desc, instance);
126
+ }
127
+
128
+ if (!actionsSlot) {
129
+ return null;
130
+ }
131
+
132
+ return Div({ class: 'card-footer' }, actionsSlot);
133
+ }
@@ -0,0 +1,169 @@
1
+ :root {
2
+ --card-bg: var(--background);
3
+ --card-border: var(--gray-lite-3);
4
+ --card-radius: var(--radius-card);
5
+ --card-shadow: var(--shadow-card);
6
+ --card-shadow-elevated: var(--shadow-lg);
7
+ --card-shadow-hover: var(--shadow-md);
8
+ --card-font-size: var(--description-size);
9
+ --card-padding: var(--space-comfortable);
10
+ --card-img-height: 200px;
11
+ --card-title-size: var(--text-size);
12
+ --card-title-weight: 600;
13
+ --card-title-color: var(--text-color);
14
+ --card-subtitle-size: var(--note-size);
15
+ --card-subtitle-color: var(--gray);
16
+ --card-footer-padding: var(--space-cozy) var(--space-comfortable);
17
+ --card-footer-border: var(--gray-lite-3);
18
+ --card-footer-gap: var(--space-cozy);
19
+ --card-transition: box-shadow 0.2s ease;
20
+ --card-loading-bg: var(--gray-lite-5);
21
+ --card-horizontal-img-width: 175px;
22
+ --card-clickable-cursor: pointer;
23
+ --card-header-row-gap: .5rem;
24
+ }
25
+
26
+
27
+ .card {
28
+ background: var(--card-bg);
29
+ border: 1px solid var(--card-border);
30
+ border-radius: var(--card-radius);
31
+ overflow: hidden;
32
+ font-size: var(--card-font-size);
33
+ transition: var(--card-transition);
34
+ display: inline-flex;
35
+ flex-direction: column;
36
+
37
+ &.is-elevated {
38
+ border: none;
39
+ box-shadow: var(--card-shadow-elevated);
40
+ }
41
+
42
+ &.is-flat {
43
+ border: none;
44
+ box-shadow: none;
45
+ }
46
+
47
+ &.is-outlined {
48
+ border-width: 2px;
49
+ }
50
+
51
+ &.is-hoverable:hover {
52
+ box-shadow: var(--card-shadow-hover);
53
+ }
54
+
55
+ &.is-clickable {
56
+ cursor: var(--card-clickable-cursor);
57
+
58
+ &:hover {
59
+ box-shadow: var(--card-shadow-hover);
60
+ }
61
+
62
+ &:active {
63
+ opacity: 0.95;
64
+ }
65
+ }
66
+
67
+ &.is-horizontal {
68
+ flex-direction: row;
69
+
70
+ .card-image-wrapper {
71
+ width: var(--card-horizontal-img-width);
72
+ }
73
+ .card-image {
74
+ flex-shrink: 0;
75
+ }
76
+ .card-content {
77
+ display: flex;
78
+ flex-direction: column;
79
+ justify-content: center;
80
+ align-items: flex-start;
81
+ }
82
+ }
83
+
84
+ &.is-loading {
85
+ .card-title,
86
+ .card-subtitle,
87
+ .card-content {
88
+ background: var(--card-loading-bg);
89
+ border-radius: 4px;
90
+ color: transparent;
91
+ user-select: none;
92
+
93
+ * {
94
+ visibility: hidden;
95
+ }
96
+ }
97
+
98
+ .card-title { width: 60%; }
99
+ .card-subtitle { width: 40%; }
100
+ .card-image { background: var(--card-loading-bg); }
101
+ }
102
+ }
103
+ .card-header {
104
+ display: flex;
105
+ flex-direction: column;
106
+ align-items: flex-start;
107
+ justify-content: flex-start;
108
+ row-gap: var(--card-header-row-gap);
109
+ }
110
+ .card-actions {
111
+ width: 100%;
112
+ display: flex;
113
+ justify-content: space-between;
114
+ column-gap: var(--space-tiny);
115
+ > * {
116
+ flex: 1;
117
+ }
118
+ }
119
+ .card-image-wrapper {
120
+ width: 100%;
121
+ height: var(--card-img-height);
122
+ }
123
+ .card-image {
124
+ width: 100%;
125
+ height: 100%;
126
+ object-fit: cover;
127
+ display: block;
128
+
129
+ &.is-top { order: -1; }
130
+ &.is-bottom { order: 10; }
131
+
132
+ .card.is-horizontal &.is-left { order: -1; }
133
+ .card.is-horizontal &.is-right { order: 10; }
134
+ }
135
+
136
+ .card-body {
137
+ padding: var(--card-padding);
138
+ flex: 1;
139
+ display: flex;
140
+ flex-direction: column;
141
+ gap: var(--space-cozy);
142
+ }
143
+
144
+ .card-title {
145
+ font-size: var(--card-title-size);
146
+ font-weight: var(--card-title-weight);
147
+ color: var(--card-title-color);
148
+ margin: 0;
149
+ }
150
+
151
+ .card-subtitle {
152
+ font-size: var(--card-subtitle-size);
153
+ color: var(--card-subtitle-color);
154
+ margin: 0;
155
+ }
156
+
157
+ .card-content {
158
+ flex: 1;
159
+ }
160
+
161
+ .card-footer {
162
+ width: 100%;
163
+ display: flex;
164
+ align-items: center;
165
+ justify-content: flex-end;
166
+ gap: var(--card-footer-gap);
167
+ padding: var(--card-footer-padding);
168
+ border-top: 1px solid var(--card-footer-border);
169
+ }
@@ -18,7 +18,7 @@ export default function ContextMenuRender($desc, instance) {
18
18
 
19
19
  createPortal(container, {name: 'context-menu'});
20
20
 
21
- if($desc.trigger) {
21
+ if($desc.trigger && instance) {
22
22
  contextMenuHandler($desc.trigger, instance);
23
23
  }
24
24
 
@@ -0,0 +1,18 @@
1
+ import { Ul, ForEachArray } from '../../../core/elements';
2
+
3
+ import './list.css';
4
+
5
+ export default function ListRender($desc, instance) {
6
+ const props = instance.getEditableProps();
7
+
8
+ props.class.add({ list: true, 'with-divider': $desc.divider });
9
+
10
+ if ($desc.inset) {
11
+ props.style.add(
12
+ '--list-inset-padding',
13
+ $desc.inset.transform((v) => v > 0 ? `${v}px` : null),
14
+ );
15
+ }
16
+
17
+ return Ul(instance.resolveProps(), ForEachArray($desc.items, $desc.itemBuilder));
18
+ }
@@ -0,0 +1,10 @@
1
+ import { Li } from '../../../../core/elements';
2
+
3
+ import './list-divider.css';
4
+
5
+ export default function ListDividerRender($desc, instance) {
6
+ const props = instance.getEditableProps();
7
+ props.class.add('list-divider');
8
+
9
+ return Li(instance.resolveProps());
10
+ }
@@ -0,0 +1,12 @@
1
+ :root {
2
+ --list-divider-color: var(--gray-lite-3);
3
+ --list-divider-margin: 0;
4
+ }
5
+
6
+ .list-divider {
7
+ height: 1px;
8
+ background: var(--list-divider-color);
9
+ margin: var(--list-divider-margin);
10
+ list-style: none;
11
+ pointer-events: none;
12
+ }
@@ -0,0 +1,61 @@
1
+ import { Li, Div, Span, ForEachArray, ShowIf, Switch } from '../../../../core/elements';
2
+
3
+ import './list-group.css';
4
+
5
+ export default function ListGroupRender($desc, instance) {
6
+ if ($desc.render) {
7
+ return $desc.render($desc, instance);
8
+ }
9
+
10
+ const props = instance.getEditableProps();
11
+ props.class.add('list-group');
12
+
13
+ if ($desc.collapsable) {
14
+ props.class.add('is-collapsable');
15
+ }
16
+
17
+ const content = [];
18
+
19
+ if ($desc.label || $desc.icon) {
20
+ content.push(buildGroupHeader($desc, instance));
21
+ }
22
+
23
+ if ($desc.collapsable && $desc.collapsed) {
24
+ content.push(ShowIf($desc.collapsed, () => Div({ class: 'list-group-items' }, ForEachArray($desc.items))));
25
+ } else {
26
+ content.push(Div({ class: 'list-group-items' }, ForEachArray($desc.items)));
27
+ }
28
+
29
+ return Li(instance.resolveProps(), content);
30
+ }
31
+
32
+ function buildGroupHeader($desc, instance) {
33
+ const content = [];
34
+
35
+ if ($desc.icon) {
36
+ content.push(Span({ class: 'list-group-icon' }, $desc.icon));
37
+ }
38
+
39
+ if ($desc.label) {
40
+ content.push(Span({ class: 'list-group-label' }, $desc.label));
41
+ }
42
+
43
+ if ($desc.collapsable && $desc.collapsed) {
44
+ const openedIcon = $desc.collapsableOpenedIcon || '▾';
45
+ const closedIcon = $desc.collapsableClosedIcon || '▸';
46
+
47
+ content.push(
48
+ Span({ class: $desc.collapsed.transform((c) => 'list-group-chevron' + (c ? '' : ' is-open')) },
49
+ Switch($desc.collapsed, closedIcon, openedIcon),
50
+ ),
51
+ );
52
+ }
53
+
54
+ const header = Div({ class: 'list-group-header' }, content);
55
+
56
+ if ($desc.collapsable && $desc.collapsed) {
57
+ header.nd.onStopClick(() => $desc.collapsed.toggle());
58
+ }
59
+
60
+ return header;
61
+ }
@@ -0,0 +1,62 @@
1
+ :root {
2
+ --list-group-header-padding: 6px 14px 4px;
3
+ --list-group-header-font-size: var(--note-size);
4
+ --list-group-header-weight: 500;
5
+ --list-group-header-color: var(--gray);
6
+ --list-group-header-color-hover: var(--text-color);
7
+ --list-group-header-letter-spacing: 0.05em;
8
+ --list-group-icon-size: 14px;
9
+ --list-group-icon-color: var(--gray);
10
+ --list-group-chevron-size: 11px;
11
+ --list-group-items-indent: 14px;
12
+ }
13
+
14
+ .list-group {
15
+ list-style: none;
16
+ }
17
+
18
+ .list-group-header {
19
+ display: flex;
20
+ align-items: center;
21
+ gap: 8px;
22
+ padding: var(--list-group-header-padding);
23
+ font-size: var(--list-group-header-font-size);
24
+ font-weight: var(--list-group-header-weight);
25
+ color: var(--list-group-header-color);
26
+ letter-spacing: var(--list-group-header-letter-spacing);
27
+ user-select: none;
28
+
29
+ .is-collapsable & {
30
+ cursor: pointer;
31
+
32
+ &:hover {
33
+ color: var(--list-group-header-color-hover);
34
+ }
35
+ }
36
+ }
37
+
38
+ .list-group-icon {
39
+ font-size: var(--list-group-icon-size);
40
+ color: var(--list-group-icon-color);
41
+ flex-shrink: 0;
42
+ }
43
+
44
+ .list-group-label {
45
+ flex: 1;
46
+ }
47
+
48
+ .list-group-chevron {
49
+ font-size: var(--list-group-chevron-size);
50
+ transition: transform 0.15s ease;
51
+ flex-shrink: 0;
52
+
53
+ &.is-open {
54
+ transform: rotate(90deg);
55
+ }
56
+ }
57
+
58
+ .list-group-items {
59
+ .list-item {
60
+ padding-left: calc(var(--list-group-items-indent) + 14px);
61
+ }
62
+ }