native-document 1.0.290 → 1.0.292

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-document",
3
- "version": "1.0.290",
3
+ "version": "1.0.292",
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",
@@ -33,10 +33,8 @@ export interface BreadCrumbInterface extends BaseComponent {
33
33
  export declare function BreadCrumb(props?: Record<string, unknown>): BreadCrumbInterface;
34
34
  export declare namespace BreadCrumb {
35
35
 
36
-
37
36
  function use(template: (description: BreadCrumbDescription, instance: BreadCrumbInterface) => ValidChild): void;
38
37
  function preset(name: string, callback: (instance: BreadCrumbInterface) => BreadCrumbInterface): void;
39
38
  function presets(presets: Record<string, (instance: BreadCrumbInterface) => BreadCrumbInterface>): void;
40
39
 
41
-
42
40
  }
@@ -319,3 +319,21 @@ Button.prototype.block = function() {
319
319
  this.$description.block = true;
320
320
  return this;
321
321
  };
322
+
323
+
324
+ // /**
325
+ // * @param {{name: string, params?: *}} route
326
+ // */
327
+ // Button.prototype.linkTo = function(route) {
328
+ // this.$description.linkTo = route;
329
+ // return this;
330
+ // };
331
+ //
332
+ // /**
333
+ // * @param {string} url
334
+ // */
335
+ // Button.prototype.link = function(url, target = null) {
336
+ // this.$description.link = url;
337
+ // this.$description.linkTarget = target;
338
+ // return this;
339
+ // };
@@ -47,6 +47,8 @@ export interface ButtonInterface extends BaseComponent {
47
47
  circle(): this;
48
48
  smooth(): this;
49
49
  block(): this;
50
+ // linkTo(route: {name: string, params?: object}): this;
51
+ // link(url: string, target?: string): this;
50
52
  }
51
53
 
52
54
 
@@ -35,11 +35,11 @@ export default function Field(name, type, props) {
35
35
  type: type,
36
36
  key: name,
37
37
  label: null,
38
- placeholder: null,
38
+ placeholder: props?.placeholder ?? null,
39
39
  help: null,
40
40
  defaultValue: null,
41
- disabled: false,
42
- readonly: false,
41
+ disabled: props?.disabled ?? null,
42
+ readonly: props?.readonly ?? null,
43
43
  rules: [],
44
44
  clearErrorOn: 'focus',
45
45
  validateOn: 'blur',
@@ -75,6 +75,7 @@ BaseComponent.extends(Field);
75
75
  BaseComponent.use(Field, HasEventEmitter);
76
76
  BaseComponent.use(Field, HasValidation);
77
77
 
78
+
78
79
  /**
79
80
  * Registers the render template for Field.
80
81
  * @param {(description: {
@@ -34,6 +34,7 @@ export const RouteParamPatterns = {
34
34
  * @param {boolean} [$options.shouldRebuild] - Whether to rebuild component on each navigation
35
35
  * @param {Object} [$options.with] - Custom parameter validation patterns
36
36
  * @param {Function} [$options.layout] - Layout component wrapper function
37
+ * @param {Function[]} [$options.layouts] - All prent Layouts component wrapper function
37
38
  */
38
39
  export function Route($path, $component, $options = {}) {
39
40
 
@@ -46,6 +47,7 @@ export function Route($path, $component, $options = {}) {
46
47
  const $shouldRebuild = $options.shouldRebuild || false;
47
48
  const $paramsValidators = $options.with || {};
48
49
  const $layout = $options.layout || null;
50
+ const $layouts = $options.layouts || null;
49
51
 
50
52
  const $params = {};
51
53
  const $paramsNames = [];
@@ -91,6 +93,7 @@ export function Route($path, $component, $options = {}) {
91
93
  this.shouldRebuild = () => $shouldRebuild;
92
94
  this.path = () => $path;
93
95
  this.layout = () => $layout;
96
+ this.layouts = () => $layouts;
94
97
 
95
98
  /**
96
99
  *
@@ -57,4 +57,9 @@ export const RouteGroupHelper = {
57
57
  }
58
58
  return null;
59
59
  },
60
+ layouts($groupTree) {
61
+ return $groupTree
62
+ .map(g => g.options?.layout)
63
+ .filter(Boolean);
64
+ },
60
65
  };
@@ -63,6 +63,10 @@ export default function Router($options = {}) {
63
63
  middlewares: RouteGroupHelper.fullMiddlewares($groupTree, options?.middlewares || []),
64
64
  name: options?.name ? RouteGroupHelper.fullName($groupTree, options.name) : null,
65
65
  layout: options?.layout || RouteGroupHelper.layout($groupTree),
66
+ layouts: [
67
+ ...RouteGroupHelper.layouts($groupTree),
68
+ ...(options?.layout ? [options.layout] : []),
69
+ ],
66
70
  });
67
71
  $routes.push(route);
68
72
  if(route.name()) {
@@ -219,6 +223,10 @@ export default function Router($options = {}) {
219
223
  return middlewares[currentIndex](request, next);
220
224
  };
221
225
 
226
+ this.currentRouteName = function() {
227
+ return $currentState.route.name();
228
+ };
229
+
222
230
  }
223
231
 
224
232
  Router.routers = {};
@@ -267,6 +275,10 @@ Router.create = function(options, callback) {
267
275
  return router;
268
276
  };
269
277
 
278
+ Router.currentRouteName = function(name = null) {
279
+ return Router.get(name).currentRouteName();
280
+ };
281
+
270
282
  Router.get = function(name) {
271
283
  const router = Router.routers[name || DEFAULT_ROUTER_NAME];
272
284
  if(!router) {
@@ -275,6 +287,10 @@ Router.get = function(name) {
275
287
  return router;
276
288
  };
277
289
 
290
+ Router.currentRoute = function(name = null) {
291
+ return Router.get(name).currentState().route;
292
+ }
293
+
278
294
  Router.push = function(target, name = null) {
279
295
  return Router.get(name).push(target);
280
296
  };
@@ -18,6 +18,7 @@ export function RouterComponent(router, container) {
18
18
 
19
19
  const $lifecycles = new Map();
20
20
  let $currentPath = null;
21
+ let $mountedChain = [];
21
22
 
22
23
  const getNodeAnchorForLayout = (node, path) => {
23
24
  const existingAnchor = $routeInstanceAnchors.get(node);
@@ -55,39 +56,65 @@ export function RouterComponent(router, container) {
55
56
  return nodeToInsert;
56
57
  };
57
58
 
58
- const updateContainerByLayout = (layout, node, route, path) => {
59
+ const updateContainerByLayout = (layouts, node, route, path) => {
60
+
59
61
  const nodeToInsert = getNodeToInsert(node);
62
+ let matchDepth = 0;
60
63
 
61
- const cachedLayout = $layoutCache.get(nodeToInsert);
62
- if(cachedLayout) {
63
- if(cachedLayout === $currentLayout) {
64
- const layoutAnchor = getNodeAnchorForLayout(nodeToInsert, path);
65
- removeLastNodeInserted();
66
- $lastNodeInserted = nodeToInsert;
67
- layoutAnchor.replaceContent(nodeToInsert);
68
- return;
69
- }
70
- cleanContainer();
64
+ while (matchDepth < $mountedChain.length && matchDepth < layouts.length && $mountedChain[matchDepth].layoutFn === layouts[matchDepth]) {
65
+ matchDepth++;
66
+ }
67
+
68
+ if (matchDepth === layouts.length && matchDepth === $mountedChain.length) {
69
+ removeLastNodeInserted();
71
70
  $lastNodeInserted = nodeToInsert;
72
- $currentLayout = cachedLayout;
73
- const layoutAnchor = getNodeAnchorForLayout(nodeToInsert, path);
74
- layoutAnchor.replaceContent(nodeToInsert);
75
- container.appendChild($currentLayout);
71
+ $mountedChain[matchDepth - 1]?.anchor?.replaceContent(nodeToInsert);
76
72
  return;
77
73
  }
78
- cleanContainer();
74
+
75
+
76
+ if ($mountedChain[matchDepth]) {
77
+ $mountedChain[matchDepth].element.remove();
78
+ }
79
+
80
+ const $mountedChainKeep = $mountedChain.slice(0, matchDepth);
81
+ const newLayers = [];
82
+ let slot = nodeToInsert;
79
83
  $lastNodeInserted = nodeToInsert;
80
- const anchor = getNodeAnchorForLayout(nodeToInsert, path);
81
84
 
82
- $currentLayout = ElementCreator.getChild(layout(anchor));
83
- $layoutCache.set(nodeToInsert, $currentLayout);
84
- container.appendChild($currentLayout);
85
+ for(let i = layouts.length - 1; i >= matchDepth; i -= 1) {
86
+ const layout = layouts[i];
87
+ let cached = $layoutCache.get(layout);
88
+ if(!cached) {
89
+ const anchor = getNodeAnchorForLayout(slot, `${path}:layout:${i}`);
90
+ const element = ElementCreator.getChild(layout(anchor));
91
+ cached = { element, anchor };
92
+ $layoutCache.set(layout, cached);
93
+ }
94
+ else {
95
+ cached.anchor.replaceContent(slot);
96
+ }
97
+
98
+ newLayers.unshift({ layoutFn: layout, anchor: cached.anchor, element: cached.element });
99
+ slot = cached.element;
100
+ }
101
+
102
+ $mountedChain = [...$mountedChainKeep, ...newLayers];
103
+
104
+ if (matchDepth === 0) {
105
+ container.appendChild(newLayers[0].element);
106
+ } else {
107
+ $mountedChainKeep[matchDepth - 1].anchor.replaceContent(newLayers[0].element);
108
+ }
109
+
85
110
  };
86
111
 
87
112
  const updateContainer = function(node, route, path) {
88
- const layout = route.layout();
89
- if(layout) {
90
- updateContainerByLayout(layout, node, route, path);
113
+ const layouts = route.layouts();
114
+
115
+
116
+ if(layouts.length) {
117
+ updateContainerByLayout(layouts, node, route, path);
91
118
  return;
92
119
  }
93
120
  const nodeToInsert = getNodeToInsert(node);
@@ -1,5 +1,6 @@
1
1
  import {Button as NativeButton, ShowIf, Span} from '../../../core/elements';
2
2
  import {Spinner} from '../../../components/spinner';
3
+ import {Router} from '../../../../router';
3
4
 
4
5
  import './button.css';
5
6
 
@@ -32,7 +33,7 @@ export default function ButtonRender($desc, instance) {
32
33
 
33
34
  const content = buildContent($desc);
34
35
 
35
- return NativeButton({
36
+ const button = NativeButton({
36
37
  ...instance.resolveProps(),
37
38
  type: $desc.type || 'button',
38
39
  disabled: $desc.disabled,
@@ -40,6 +41,8 @@ export default function ButtonRender($desc, instance) {
40
41
  ...($desc.loading ? { 'aria-busy': $desc.loading } : {}),
41
42
  ...($desc.disabled ? { 'aria-disabled': $desc.disabled } : {}),
42
43
  }, content);
44
+
45
+ return button;
43
46
  }
44
47
 
45
48
  function buildContent($desc) {
@@ -8,6 +8,6 @@ export default function CopyButtonRender($desc, instance) {
8
8
  return;
9
9
  }
10
10
 
11
- navigator.clipboard.writeText($desc.target.val());
11
+ navigator.clipboard.writeText($desc.target.valueOf());
12
12
  });
13
13
  }
@@ -35,18 +35,21 @@
35
35
  border-radius: var(--dropdown-radius);
36
36
  box-shadow: var(--dropdown-shadow);
37
37
  min-width: var(--dropdown-min-width);
38
- max-width: var(--dropdown-max-width);
39
38
  font-size: var(--dropdown-font-size);
40
39
  box-sizing: border-box;
41
40
  margin: 0;
42
41
  padding: var(--space-cozy) 0;
43
- inset: unset;
42
+ /*inset: unset;*/
44
43
  overflow: hidden;
45
44
 
46
45
  &:popover-open {
47
46
  animation: dropdown-in var(--dropdown-animation-duration) ease forwards;
48
47
  }
49
48
 
49
+ &.has-max-width {
50
+ max-width: var(--dropdown-max-width);
51
+ }
52
+
50
53
  &.has-max-height {
51
54
  overflow-y: auto;
52
55
  }
@@ -29,6 +29,7 @@ export default function FormControlRender($desc, instance) {
29
29
  fields: fieldsObject,
30
30
  errors: errorsSummary,
31
31
  form: instance,
32
+ data: dataProxy(fieldsObject),
32
33
  }, instance);
33
34
 
34
35
  if(!((form instanceof HTMLFormElement) || form?.$element instanceof HTMLFormElement)) {
@@ -44,6 +45,17 @@ export default function FormControlRender($desc, instance) {
44
45
  return form;
45
46
  }
46
47
 
48
+ const dataProxy = (fieldsObject) => {
49
+ const data = {};
50
+ for(const name in fieldsObject) {
51
+ if(!fieldsObject[name]?.$model) {
52
+ continue;
53
+ }
54
+ data[name] = fieldsObject[name].$model();
55
+ }
56
+ return data;
57
+ };
58
+
47
59
  const buildDefaultLayout = ({ fields, errors, form }) => {
48
60
  return Form({ class: 'form-control-default', ...form.resolveProps() }, [
49
61
  ...Object.values(fields),
@@ -35,17 +35,20 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
35
35
  : $desc.trigger).toNdElement();
36
36
 
37
37
  const editableProps = instance.getEditableProps();
38
- const toUnit = v => v + 'px';
39
38
 
40
39
  const popoverId = classPrefix+'-nd-' + (++$popoverId);
40
+ const toUnit = v => v + 'px';
41
41
  const $x = Observable(10).intercept(toUnit);
42
42
  const $y = Observable(0).intercept(toUnit);
43
43
 
44
- const popoverArrow = $desc.arrow ? Span({class: classPrefix+'-arrow'}) : null;
44
+ const popoverArrow = $desc.arrow ? Span({class: classPrefix+'-arrow popover-arrow'}) : null;
45
45
 
46
- editableProps.class.add(classPrefix);
46
+ editableProps.class.add('popover');
47
+ if(classPrefix !== 'popover') {
48
+ editableProps.class.add(classPrefix);
49
+ }
47
50
  editableProps.class.add('is-'+$desc.variant);
48
- editableProps.style.add({left: $x, top: $y});
51
+ editableProps.style.add({ '--popover-left-position': $x, '--popover-top-position': $y});
49
52
 
50
53
  const popover = Div({
51
54
  popover: 'manual',
@@ -62,12 +65,23 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
62
65
 
63
66
  let position;
64
67
  const isSupportsPopover = supportsPopover();
68
+
69
+ let targetElement = trigger;
70
+ if($desc.matchTargetWidth) {
71
+ if($desc.matchTargetWidth.$element) {
72
+ targetElement = $desc.matchTargetWidth.$element;
73
+ }
74
+ else if($desc.matchTargetWidth.tagName) {
75
+ targetElement = $desc.matchTargetWidth;
76
+ }
77
+ }
78
+
65
79
  const updatePosition = (state) => {
66
80
  if(!state) {
67
81
  return;
68
82
  }
69
83
 
70
- let targetElement = trigger;
84
+ targetElement = trigger;
71
85
  if($desc.matchTargetWidth) {
72
86
  if($desc.matchTargetWidth.$element) {
73
87
  targetElement = $desc.matchTargetWidth.$element;
@@ -111,12 +125,13 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
111
125
  }
112
126
 
113
127
  const arrowData = middlewareData.arrow;
128
+ const side = placement.split('-')[0];
114
129
  const staticSide = {
115
130
  top: 'bottom',
116
131
  right: 'left',
117
132
  bottom: 'top',
118
133
  left: 'right',
119
- }[placement.split('-')[0]];
134
+ }[side];
120
135
 
121
136
  Object.assign(popoverArrow.style, {
122
137
  left: arrowData.x != null ? arrowData.x + 'px' : '',
@@ -148,7 +163,7 @@ export default function PopoverRender($desc, instance, classPrefix = 'popover')
148
163
 
149
164
  const observer = new ResizeObserver(updatePositionHandler);
150
165
 
151
- observer.observe(trigger);
166
+ observer.observe(targetElement);
152
167
  window.addEventListener('resize', updatePositionHandler);
153
168
  window.addEventListener('scroll', updatePositionHandler);
154
169
 
@@ -1,5 +1,6 @@
1
1
  :root {
2
2
  --popover-bg: var(--background);
3
+ --popover-color: var(--text-color, black);
3
4
  --popover-border: var(--gray-lite-3);
4
5
  --popover-radius: var(--radius-card);
5
6
  --popover-shadow: var(--shadow-lg);
@@ -12,6 +13,24 @@
12
13
  --popover-header-weight: 600;
13
14
  --popover-arrow-size: 8px;
14
15
  --popover-animation-duration: 0.15s;
16
+
17
+ --popover-left-offset: 0px;
18
+ --popover-top-offset: 0px;
19
+
20
+ --popover-top-position: 0px;
21
+ --popover-left-position: 0px;
22
+ }
23
+
24
+
25
+ .popover-arrow {
26
+ position: absolute;
27
+ width: var(--popover-arrow-size);
28
+ height: var(--popover-arrow-size);
29
+ background: var(--popover-bg);
30
+ color: var(--popover-color);
31
+ transform: rotate(45deg);
32
+ pointer-events: none;
33
+ z-index: -1;
15
34
  }
16
35
 
17
36
  .popover {
@@ -29,6 +48,8 @@
29
48
  padding: 0;
30
49
  inset: unset;
31
50
  overflow: initial;
51
+ top: calc(var(--popover-top-position) + var(--popover-top-offset));
52
+ left: calc(var(--popover-left-position) + var(--popover-left-offset));
32
53
 
33
54
  &.is-primary {
34
55
  --popover-bg: var(--color-primary);
@@ -27,7 +27,6 @@
27
27
  padding: var(--tooltip-padding);
28
28
  box-sizing: border-box;
29
29
  margin: 0;
30
- inset: unset;
31
30
  overflow: initial;
32
31
  line-height: 1.5;
33
32
  pointer-events: none;
@@ -68,37 +67,6 @@
68
67
  width: var(--tooltip-arrow-size);
69
68
  height: var(--tooltip-arrow-size);
70
69
  background: var(--tooltip-bg);
71
- transform: rotate(45deg);
72
- pointer-events: none;
73
- z-index: -1;
74
- }
75
-
76
- .tooltip[data-placement^='top'] {
77
- .tooltip-arrow {
78
- border-top: none;
79
- border-left: none;
80
- }
81
- }
82
-
83
- .tooltip[data-placement^='bottom'] {
84
- .tooltip-arrow {
85
- border-bottom: none;
86
- border-right: none;
87
- }
88
- }
89
-
90
- .tooltip[data-placement^='left'] {
91
- .tooltip-arrow {
92
- border-left: none;
93
- border-bottom: none;
94
- }
95
- }
96
-
97
- .tooltip[data-placement^='right'] {
98
- .tooltip-arrow {
99
- border-right: none;
100
- border-top: none;
101
- }
102
70
  }
103
71
 
104
72
  @keyframes tooltip-in {