uikit 3.19.5-dev.8317c4705 → 3.19.5-dev.92ee0f0d9

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 (69) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/css/uikit-core-rtl.css +2 -2
  3. package/dist/css/uikit-core-rtl.min.css +1 -1
  4. package/dist/css/uikit-core.css +2 -2
  5. package/dist/css/uikit-core.min.css +1 -1
  6. package/dist/css/uikit-rtl.css +2 -2
  7. package/dist/css/uikit-rtl.min.css +1 -1
  8. package/dist/css/uikit.css +2 -2
  9. package/dist/css/uikit.min.css +1 -1
  10. package/dist/js/components/countdown.js +1 -1
  11. package/dist/js/components/countdown.min.js +1 -1
  12. package/dist/js/components/filter.js +2 -2
  13. package/dist/js/components/filter.min.js +1 -1
  14. package/dist/js/components/lightbox-panel.js +55 -55
  15. package/dist/js/components/lightbox-panel.min.js +1 -1
  16. package/dist/js/components/lightbox.js +55 -55
  17. package/dist/js/components/lightbox.min.js +1 -1
  18. package/dist/js/components/notification.js +1 -1
  19. package/dist/js/components/notification.min.js +1 -1
  20. package/dist/js/components/parallax.js +40 -40
  21. package/dist/js/components/parallax.min.js +1 -1
  22. package/dist/js/components/slider-parallax.js +41 -41
  23. package/dist/js/components/slider-parallax.min.js +1 -1
  24. package/dist/js/components/slider.js +41 -42
  25. package/dist/js/components/slider.min.js +1 -1
  26. package/dist/js/components/slideshow-parallax.js +41 -41
  27. package/dist/js/components/slideshow-parallax.min.js +1 -1
  28. package/dist/js/components/slideshow.js +41 -41
  29. package/dist/js/components/slideshow.min.js +1 -1
  30. package/dist/js/components/sortable.js +2 -2
  31. package/dist/js/components/sortable.min.js +1 -1
  32. package/dist/js/components/tooltip.js +1 -1
  33. package/dist/js/components/tooltip.min.js +1 -1
  34. package/dist/js/components/upload.js +1 -1
  35. package/dist/js/components/upload.min.js +1 -1
  36. package/dist/js/uikit-core.js +128 -103
  37. package/dist/js/uikit-core.min.js +1 -1
  38. package/dist/js/uikit-icons.js +1 -1
  39. package/dist/js/uikit-icons.min.js +1 -1
  40. package/dist/js/uikit.js +137 -110
  41. package/dist/js/uikit.min.js +1 -1
  42. package/package.json +1 -1
  43. package/src/js/api/boot.js +6 -7
  44. package/src/js/api/component.js +4 -4
  45. package/src/js/api/computed.js +20 -26
  46. package/src/js/api/observer.js +17 -5
  47. package/src/js/components/slider-parallax.js +2 -2
  48. package/src/js/components/slider.js +1 -1
  49. package/src/js/core/drop.js +1 -2
  50. package/src/js/core/height-placeholder.js +4 -1
  51. package/src/js/core/height-viewport.js +1 -1
  52. package/src/js/core/icon.js +2 -3
  53. package/src/js/core/img.js +1 -1
  54. package/src/js/core/inverse.js +22 -5
  55. package/src/js/core/modal.js +5 -6
  56. package/src/js/core/sticky.js +1 -1
  57. package/src/js/core/switcher.js +4 -1
  58. package/src/js/core/toggle.js +6 -3
  59. package/src/js/mixin/internal/animate-fade.js +1 -3
  60. package/src/js/mixin/parallax.js +7 -3
  61. package/src/js/mixin/slider.js +0 -3
  62. package/src/js/mixin/slideshow.js +3 -0
  63. package/src/js/util/filter.js +7 -14
  64. package/src/js/util/lang.js +1 -1
  65. package/src/js/util/selector.js +33 -24
  66. package/src/js/util/svg.js +1 -12
  67. package/src/less/components/utility.less +1 -1
  68. package/src/scss/components/utility.scss +1 -1
  69. package/tests/js/index.js +12 -10
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "uikit",
3
3
  "title": "UIkit",
4
4
  "description": "UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.",
5
- "version": "3.19.5-dev.8317c4705",
5
+ "version": "3.19.5-dev.92ee0f0d9",
6
6
  "main": "dist/js/uikit.js",
7
7
  "style": "dist/css/uikit.css",
8
8
  "sideEffects": [
@@ -1,4 +1,4 @@
1
- import { apply, hasAttr, inBrowser, isPlainObject, startsWith, trigger } from 'uikit-util';
1
+ import { apply, hasAttr, inBrowser, startsWith, trigger } from 'uikit-util';
2
2
  import { components, createComponent, getComponent, getComponents } from './component';
3
3
  import { callConnected, callDisconnected } from './hooks';
4
4
 
@@ -53,16 +53,15 @@ function applyAttributeMutation({ target, attributeName }) {
53
53
  if (name) {
54
54
  if (hasAttr(target, attributeName)) {
55
55
  createComponent(name, target);
56
- return;
56
+ } else {
57
+ getComponent(target, name)?.$destroy();
57
58
  }
58
-
59
- getComponent(target, name)?.$destroy();
60
59
  }
61
60
  }
62
61
 
63
62
  function connect(node) {
64
63
  const components = getComponents(node);
65
- for (const name in getComponents(node)) {
64
+ for (const name in components) {
66
65
  callConnected(components[name]);
67
66
  }
68
67
 
@@ -74,7 +73,7 @@ function connect(node) {
74
73
 
75
74
  function disconnect(node) {
76
75
  const components = getComponents(node);
77
- for (const name in getComponents(node)) {
76
+ for (const name in components) {
78
77
  callDisconnected(components[name]);
79
78
  }
80
79
  }
@@ -85,5 +84,5 @@ function getComponentName(attribute) {
85
84
  }
86
85
 
87
86
  const cmp = components[attribute];
88
- return cmp && (isPlainObject(cmp) ? cmp : cmp.options).name;
87
+ return cmp && (cmp.options || cmp).name;
89
88
  }
@@ -1,4 +1,4 @@
1
- import { $$, camelize, hyphenate, isEmpty, isPlainObject } from 'uikit-util';
1
+ import { camelize, findAll, hyphenate, isEmpty, isPlainObject } from 'uikit-util';
2
2
  import App from './app';
3
3
 
4
4
  const PREFIX = 'uk-';
@@ -10,7 +10,7 @@ export function component(name, options) {
10
10
  const id = PREFIX + hyphenate(name);
11
11
 
12
12
  if (!options) {
13
- if (isPlainObject(components[id])) {
13
+ if (!components[id].options) {
14
14
  components[id] = App.extend(components[id]);
15
15
  }
16
16
 
@@ -21,7 +21,7 @@ export function component(name, options) {
21
21
 
22
22
  App[name] = (element, data) => createComponent(name, element, data);
23
23
 
24
- const opt = isPlainObject(options) ? { ...options } : options.options;
24
+ const opt = options.options ?? { ...options };
25
25
 
26
26
  opt.id = id;
27
27
  opt.name = name;
@@ -41,7 +41,7 @@ export function createComponent(name, element, data, ...args) {
41
41
  return Component.options.functional
42
42
  ? new Component({ data: isPlainObject(element) ? element : [element, data, ...args] })
43
43
  : element
44
- ? $$(element).map(init)[0]
44
+ ? findAll(element).map(init)[0]
45
45
  : init();
46
46
 
47
47
  function init(element) {
@@ -1,6 +1,6 @@
1
- import { hasOwn, isUndefined } from 'uikit-util';
2
- import { callUpdate, prependUpdate } from './update';
3
- import { runWatches } from './watch';
1
+ import { hasOwn, isUndefined, observeMutation } from 'uikit-util';
2
+ import { callUpdate, prependUpdate } from './update.js';
3
+ import { runWatches } from './watch.js';
4
4
 
5
5
  export function initComputed(instance) {
6
6
  const { computed } = instance.$options;
@@ -13,7 +13,7 @@ export function initComputed(instance) {
13
13
  }
14
14
  }
15
15
  }
16
-
16
+ const mutationOptions = { subtree: true, childList: true };
17
17
  export function registerComputed(instance, key, cb) {
18
18
  instance._hasComputed = true;
19
19
  Object.defineProperty(instance, key, {
@@ -24,6 +24,15 @@ export function registerComputed(instance, key, cb) {
24
24
 
25
25
  if (!hasOwn(_computed, key)) {
26
26
  _computed[key] = (cb.get || cb).call(instance, $props, $el);
27
+ if (cb.observe && instance._computedObserver) {
28
+ const selector = cb.observe.call(instance, $props);
29
+ instance._computedObserver.observe(
30
+ ['~', '+', '-'].includes(selector[0])
31
+ ? $el.parentElement
32
+ : $el.getRootNode(),
33
+ mutationOptions,
34
+ );
35
+ }
27
36
  }
28
37
 
29
38
  return _computed[key];
@@ -51,12 +60,16 @@ export function initComputedUpdates(instance) {
51
60
  events: ['resize', 'computed'],
52
61
  });
53
62
 
54
- registerComputedObserver();
55
- instances.add(instance);
63
+ instance._computedObserver = observeMutation(
64
+ instance.$el,
65
+ () => callUpdate(instance, 'computed'),
66
+ mutationOptions,
67
+ );
56
68
  }
57
69
 
58
70
  export function disconnectComputedUpdates(instance) {
59
- instances?.delete(instance);
71
+ instance._computedObserver?.disconnect();
72
+ delete instance._computedObserver;
60
73
  resetComputed(instance);
61
74
  }
62
75
 
@@ -65,22 +78,3 @@ function resetComputed(instance) {
65
78
  instance._computed = {};
66
79
  return values;
67
80
  }
68
-
69
- let observer;
70
- let instances;
71
- function registerComputedObserver() {
72
- if (observer) {
73
- return;
74
- }
75
-
76
- instances = new Set();
77
- observer = new MutationObserver(() => {
78
- for (const instance of instances) {
79
- callUpdate(instance, 'computed');
80
- }
81
- });
82
- observer.observe(document, {
83
- subtree: true,
84
- childList: true,
85
- });
86
- }
@@ -46,21 +46,33 @@ function registerObservable(instance, observable) {
46
46
  const targets = hasOwn(instance, key) ? instance[key] : target;
47
47
  const observer = observe(targets, handler, options, args);
48
48
 
49
- if (isFunction(target) && isArray(instance[key]) && observer.unobserve) {
50
- registerWatch(instance, { handler: updateTargets(observer), immediate: false }, key);
49
+ if (isFunction(target) && isArray(instance[key])) {
50
+ registerWatch(
51
+ instance,
52
+ { handler: updateTargets(observer, options), immediate: false },
53
+ key,
54
+ );
51
55
  }
52
56
 
53
57
  registerObserver(instance, observer);
54
58
  }
55
59
 
56
- function updateTargets(observer) {
60
+ function updateTargets(observer, options) {
57
61
  return (targets, prev) => {
58
62
  for (const target of prev) {
59
- !includes(targets, target) && observer.unobserve(target);
63
+ if (!includes(targets, target)) {
64
+ if (observer.unobserve) {
65
+ observer.unobserve(target);
66
+ } else if (observer.observe) {
67
+ observer.disconnect();
68
+ }
69
+ }
60
70
  }
61
71
 
62
72
  for (const target of targets) {
63
- !includes(prev, target) && observer.observe(target);
73
+ if (!includes(prev, target) || !observer.unobserve) {
74
+ observer.observe(target, options);
75
+ }
64
76
  }
65
77
  };
66
78
  }
@@ -1,11 +1,11 @@
1
- import { closest, css, endsWith, fastdom, noop, Transition } from 'uikit-util';
1
+ import { css, endsWith, fastdom, noop, Transition } from 'uikit-util';
2
2
  import Parallax from '../mixin/parallax';
3
3
 
4
4
  export default {
5
5
  mixins: [Parallax],
6
6
 
7
7
  beforeConnect() {
8
- this.item = closest(this.$el, `.${this.$options.id.replace('parallax', 'items')} > *`);
8
+ this.item = this.$el.closest(`.${this.$options.id.replace('parallax', 'items')} > *`);
9
9
  },
10
10
 
11
11
  disconnected() {
@@ -129,7 +129,7 @@ export default {
129
129
  },
130
130
 
131
131
  observe: resize({
132
- target: ({ slides }) => slides,
132
+ target: ({ slides, $el }) => [$el, ...slides],
133
133
  }),
134
134
 
135
135
  update: {
@@ -27,7 +27,6 @@ import {
27
27
  pointerUp,
28
28
  query,
29
29
  removeClass,
30
- within,
31
30
  } from 'uikit-util';
32
31
  import Container from '../mixin/container';
33
32
  import Position from '../mixin/position';
@@ -513,7 +512,7 @@ function listenForBackgroundClose(drop) {
513
512
  !defaultPrevented &&
514
513
  type === pointerUp &&
515
514
  target === newTarget &&
516
- !(drop.targetEl && within(target, drop.targetEl))
515
+ !drop.targetEl?.contains(target)
517
516
  ) {
518
517
  drop.hide(false);
519
518
  }
@@ -13,7 +13,10 @@ export default {
13
13
  },
14
14
 
15
15
  computed: {
16
- target: ({ target }, $el) => query(target, $el),
16
+ target: {
17
+ get: ({ target }, $el) => query(target, $el),
18
+ observe: ({ target }) => target,
19
+ },
17
20
  },
18
21
 
19
22
  observe: resize({ target: ({ target }) => target }),
@@ -68,7 +68,7 @@ export default {
68
68
  offsetPosition(offsetTopEl)[0] - offsetPosition(scrollElement)[0];
69
69
  minHeight += top > 0 && top < viewportHeight / 2 ? ` - ${top}px` : '';
70
70
  } else {
71
- minHeight += ` - ${css(scrollElement, 'paddingTop')}`;
71
+ minHeight += ` - ${boxModelAdjust(scrollElement, 'height', css(scrollElement, 'boxSizing'))}px`;
72
72
  }
73
73
  }
74
74
 
@@ -3,7 +3,6 @@ import {
3
3
  addClass,
4
4
  apply,
5
5
  attr,
6
- closest,
7
6
  css,
8
7
  each,
9
8
  hasAttr,
@@ -126,9 +125,9 @@ export const Search = {
126
125
  hasClass(this.$el, 'uk-search-toggle') || hasClass(this.$el, 'uk-navbar-toggle');
127
126
  this.icon = isToggle
128
127
  ? 'search-toggle-icon'
129
- : hasClass(this.$el, 'uk-search-icon') && closest(this.$el, '.uk-search-large')
128
+ : hasClass(this.$el, 'uk-search-icon') && this.$el.closest('.uk-search-large')
130
129
  ? 'search-large'
131
- : closest(this.$el, '.uk-search-navbar')
130
+ : this.$el.closest('.uk-search-navbar')
132
131
  ? 'search-navbar'
133
132
  : this.$props.icon;
134
133
 
@@ -56,13 +56,13 @@ export default {
56
56
  },
57
57
 
58
58
  observe: intersection({
59
- target: ({ $el, $props }) => [$el, ...queryAll($props.target, $el)],
60
59
  handler(entries, observer) {
61
60
  this.load();
62
61
  observer.disconnect();
63
62
  },
64
63
  options: ({ margin }) => ({ rootMargin: margin }),
65
64
  filter: ({ loading }) => loading === 'lazy',
65
+ target: ({ $el, $props }) => ($props.target ? [$el, ...queryAll($props.target, $el)] : $el),
66
66
  }),
67
67
 
68
68
  methods: {
@@ -1,5 +1,5 @@
1
- import { $$, css, dimensions, matches, observeResize, on, replaceClass } from 'uikit-util';
2
- import { mutation } from '../api/observables';
1
+ import { $$, css, dimensions, matches, observeResize, on, replaceClass, toNodes } from 'uikit-util';
2
+ import { intersection, mutation } from '../api/observables';
3
3
 
4
4
  export default {
5
5
  props: {
@@ -13,10 +13,18 @@ export default {
13
13
  },
14
14
 
15
15
  computed: {
16
- target: ({ target }, $el) => (target ? $$(target, $el) : [$el]),
16
+ target: ({ target }, $el) => (target ? $$(target, $el) : $el),
17
17
  },
18
18
 
19
19
  observe: [
20
+ intersection({
21
+ handler(entries) {
22
+ this.isIntersecting = entries.some(({ isIntersecting }) => isIntersecting);
23
+ this.$emit();
24
+ },
25
+ target: ({ target }) => target,
26
+ args: { intersecting: false },
27
+ }),
20
28
  mutation({
21
29
  target: ({ target }) => target,
22
30
  options: { attributes: true, attributeFilter: ['class'], attributeOldValue: true },
@@ -24,7 +32,10 @@ export default {
24
32
  {
25
33
  target: ({ target }) => target,
26
34
  observe: (target, handler) => {
27
- const observer = observeResize([...target, document.documentElement], handler);
35
+ const observer = observeResize(
36
+ [...toNodes(target), document.documentElement],
37
+ handler,
38
+ );
28
39
  const listener = [
29
40
  on(document, 'scroll itemshown itemhidden', handler, {
30
41
  passive: true,
@@ -41,6 +52,8 @@ export default {
41
52
  ];
42
53
 
43
54
  return {
55
+ observe: observer.observe.bind(observer),
56
+ unobserve: observer.unobserve.bind(observer),
44
57
  disconnect() {
45
58
  observer.disconnect();
46
59
  listener.map((off) => off());
@@ -55,7 +68,11 @@ export default {
55
68
 
56
69
  update: {
57
70
  read() {
58
- for (const target of this.target) {
71
+ if (!this.isIntersecting) {
72
+ return false;
73
+ }
74
+
75
+ for (const target of toNodes(this.target)) {
59
76
  replaceClass(
60
77
  target,
61
78
  'uk-light,uk-dark',
@@ -70,12 +70,11 @@ export default {
70
70
 
71
71
  function install({ modal }) {
72
72
  modal.dialog = function (content, options) {
73
- const dialog = modal(
74
- `<div class="uk-modal">
75
- <div class="uk-modal-dialog">${content}</div>
76
- </div>`,
77
- { stack: true, role: 'alertdialog', ...options },
78
- );
73
+ const dialog = modal($(`<div><div class="uk-modal-dialog">${content}</div></div>`), {
74
+ stack: true,
75
+ role: 'alertdialog',
76
+ ...options,
77
+ });
79
78
 
80
79
  dialog.show();
81
80
 
@@ -109,7 +109,7 @@ export default {
109
109
  target: () => document.scrollingElement,
110
110
  options: { box: 'content-box' },
111
111
  }),
112
- resize({ target: ({ $el }) => $el }),
112
+ resize(),
113
113
  ],
114
114
 
115
115
  events: [
@@ -50,7 +50,10 @@ export default {
50
50
  },
51
51
 
52
52
  computed: {
53
- connects: ({ connect }, $el) => queryAll(connect, $el),
53
+ connects: {
54
+ get: ({ connect }, $el) => queryAll(connect, $el),
55
+ observe: ({ connect }) => connect,
56
+ },
54
57
 
55
58
  connectChildren() {
56
59
  return this.connects.map((el) => children(el)).flat();
@@ -41,9 +41,12 @@ export default {
41
41
  },
42
42
 
43
43
  computed: {
44
- target({ target }, $el) {
45
- target = queryAll(target || $el.hash, $el);
46
- return target.length ? target : [$el];
44
+ target: {
45
+ get: ({ target }, $el) => {
46
+ target = queryAll(target || $el.hash, $el);
47
+ return target.length ? target : [$el];
48
+ },
49
+ observe: ({ target }) => target,
47
50
  },
48
51
  },
49
52
 
@@ -117,9 +117,7 @@ function waitTransitionend(target) {
117
117
  }
118
118
 
119
119
  function getTransitionNodes(target) {
120
- return getRows(children(target))
121
- .flat()
122
- .filter((node) => isVisible(node));
120
+ return getRows(children(target)).flat().filter(isVisible);
123
121
  }
124
122
 
125
123
  function awaitFrame() {
@@ -7,6 +7,7 @@ import {
7
7
  isString,
8
8
  isUndefined,
9
9
  noop,
10
+ once,
10
11
  propName,
11
12
  toFloat,
12
13
  toPx,
@@ -271,6 +272,7 @@ function setBackgroundPosFn(bgProps, positions, props) {
271
272
  };
272
273
  }
273
274
 
275
+ const loading = {};
274
276
  const dimensions = {};
275
277
  function getBackgroundImageDimensions(el) {
276
278
  const src = css(el, 'backgroundImage').replace(/^none|url\(["']?(.+?)["']?\)$/, '$1');
@@ -283,11 +285,13 @@ function getBackgroundImageDimensions(el) {
283
285
  if (src) {
284
286
  image.src = src;
285
287
 
286
- if (!image.naturalWidth) {
287
- image.onload = () => {
288
+ if (!image.naturalWidth && !loading[src]) {
289
+ once(image, 'error load', () => {
288
290
  dimensions[src] = toDimensions(image);
289
291
  trigger(el, createEvent('load', false));
290
- };
292
+ });
293
+ loading[src] = true;
294
+
291
295
  return toDimensions(image);
292
296
  }
293
297
  }
@@ -10,7 +10,6 @@ import {
10
10
  removeClass,
11
11
  trigger,
12
12
  } from 'uikit-util';
13
- import { resize } from '../api/observables';
14
13
  import I18n from './i18n';
15
14
  import SliderAutoplay from './slider-autoplay';
16
15
  import SliderDrag from './slider-drag';
@@ -80,8 +79,6 @@ export default {
80
79
  },
81
80
  },
82
81
 
83
- observe: resize(),
84
-
85
82
  events: {
86
83
  itemshow({ target }) {
87
84
  addClass(target, this.clsEnter, this.clsSlideActive);
@@ -1,4 +1,5 @@
1
1
  import { addClass, removeClass } from 'uikit-util';
2
+ import { resize } from '../api/observables.js';
2
3
  import Animations from './internal/slideshow-animations';
3
4
  import Transitioner from './internal/slideshow-transitioner';
4
5
  import Slider from './slider.js';
@@ -27,6 +28,8 @@ export default {
27
28
  },
28
29
  },
29
30
 
31
+ observe: resize(),
32
+
30
33
  events: {
31
34
  beforeitemshow({ target }) {
32
35
  addClass(target, this.clsActive);
@@ -1,4 +1,4 @@
1
- import { isString, startsWith, toArray, toNode, toNodes } from './lang';
1
+ import { toArray, toNode, toNodes } from './lang';
2
2
 
3
3
  const voidElements = {
4
4
  area: true,
@@ -21,10 +21,13 @@ export function isVoidElement(element) {
21
21
  return toNodes(element).some((element) => voidElements[element.tagName.toLowerCase()]);
22
22
  }
23
23
 
24
+ const isVisibleFn =
25
+ Element.prototype.checkVisibility ||
26
+ function () {
27
+ return this.offsetWidth || this.offsetHeight || this.getClientRects().length;
28
+ };
24
29
  export function isVisible(element) {
25
- return toNodes(element).some(
26
- (element) => element.offsetWidth || element.offsetHeight || element.getClientRects().length,
27
- );
30
+ return toNodes(element).some((element) => isVisibleFn.call(element));
28
31
  }
29
32
 
30
33
  export const selInput = 'input,select,textarea,button';
@@ -49,16 +52,6 @@ export function matches(element, selector) {
49
52
  return toNodes(element).some((element) => element.matches(selector));
50
53
  }
51
54
 
52
- export function closest(element, selector) {
53
- return toNode(element)?.closest(startsWith(selector, '>') ? selector.slice(1) : selector);
54
- }
55
-
56
- export function within(element, selector) {
57
- return isString(selector)
58
- ? !!closest(element, selector)
59
- : toNode(selector).contains(toNode(element));
60
- }
61
-
62
55
  export function parents(element, selector) {
63
56
  const elements = [];
64
57
 
@@ -111,7 +111,7 @@ export function toFloat(value) {
111
111
  }
112
112
 
113
113
  export function toNode(element) {
114
- return toNodes(element)[0];
114
+ return element && toNodes(element)[0];
115
115
  }
116
116
 
117
117
  export function toNodes(element) {
@@ -1,5 +1,5 @@
1
1
  import { attr } from './attr';
2
- import { index, matches, parent } from './filter';
2
+ import { index, matches } from './filter';
3
3
  import { isDocument, isString, memoize, toNode, toNodes } from './lang';
4
4
 
5
5
  export function query(selector, context) {
@@ -33,12 +33,9 @@ const parseSelector = memoize((selector) => {
33
33
  let isContextSelector = false;
34
34
 
35
35
  const selectors = [];
36
- for (let sel of selector.match(splitSelectorRe)) {
36
+ for (let sel of selector.match(splitSelectorRe) ?? []) {
37
37
  sel = sel.replace(trailingCommaRe, '').trim();
38
- if (sel[0] === '>') {
39
- sel = `:scope ${sel}`;
40
- }
41
- isContextSelector ||= ['!', '+', '~', '-'].includes(sel[0]);
38
+ isContextSelector ||= ['!', '+', '~', '-', '>'].includes(sel[0]);
42
39
  selectors.push(sel);
43
40
  }
44
41
 
@@ -49,6 +46,12 @@ const parseSelector = memoize((selector) => {
49
46
  };
50
47
  });
51
48
 
49
+ const parsePositionSelector = memoize((selector) => {
50
+ selector = selector.substr(1).trim();
51
+ const index = selector.indexOf(' ');
52
+ return ~index ? [selector.substring(0, index), selector.substring(index + 1)] : [selector, ''];
53
+ });
54
+
52
55
  function _query(selector, context = document, queryFn) {
53
56
  if (!selector || !isString(selector)) {
54
57
  return selector;
@@ -63,36 +66,42 @@ function _query(selector, context = document, queryFn) {
63
66
  selector = '';
64
67
  const isSingle = parsed.selectors.length === 1;
65
68
  for (let sel of parsed.selectors) {
69
+ let positionSel;
66
70
  let ctx = context;
67
71
 
68
72
  if (sel[0] === '!') {
69
- const selectors = sel.substr(1).trim().split(' ');
70
- ctx = parent(context).closest(selectors[0]);
71
- sel = selectors.slice(1).join(' ').trim();
72
- if (!sel.length && isSingle) {
73
+ [positionSel, sel] = parsePositionSelector(sel);
74
+ ctx = context.parentElement.closest(positionSel);
75
+ if (!sel && isSingle) {
73
76
  return ctx;
74
77
  }
75
78
  }
76
79
 
77
- if (sel[0] === '-') {
78
- const selectors = sel.substr(1).trim().split(' ');
79
- const prev = (ctx || context).previousElementSibling;
80
- ctx = matches(prev, sel.substr(1)) ? prev : null;
81
- sel = selectors.slice(1).join(' ');
82
- if (!sel.length && isSingle) {
80
+ if (ctx && sel[0] === '-') {
81
+ [positionSel, sel] = parsePositionSelector(sel);
82
+ ctx = ctx.previousElementSibling;
83
+ ctx = matches(ctx, positionSel) ? ctx : null;
84
+ if (!sel && isSingle) {
83
85
  return ctx;
84
86
  }
85
- } else if (sel[0] === '~' || (sel[0] === '+' && isSingle)) {
86
- return _doQuery(
87
- parent(context),
88
- queryFn,
89
- `:scope :nth-child(${index(context) + 1}) ${sel}`,
90
- );
91
87
  }
92
88
 
93
- if (ctx) {
94
- selector += `${selector ? ',' : ''}${domPath(ctx)} ${sel}`;
89
+ if (!ctx) {
90
+ continue;
91
+ }
92
+
93
+ if (isSingle) {
94
+ if (sel[0] === '~' || sel[0] === '+') {
95
+ sel = `:scope :nth-child(${index(ctx) + 1}) ${sel}`;
96
+ ctx = ctx.parentElement;
97
+ } else if (sel[0] === '>') {
98
+ sel = `:scope ${sel}`;
99
+ }
100
+
101
+ return _doQuery(ctx, queryFn, sel);
95
102
  }
103
+
104
+ selector += `${selector ? ',' : ''}${domPath(ctx)} ${sel}`;
96
105
  }
97
106
 
98
107
  if (!isDocument(context)) {
@@ -1,16 +1,5 @@
1
1
  import { $$ } from './dom';
2
2
 
3
3
  export function getMaxPathLength(el) {
4
- return Math.ceil(
5
- Math.max(
6
- 0,
7
- ...$$('[stroke]', el).map((stroke) => {
8
- try {
9
- return stroke.getTotalLength();
10
- } catch (e) {
11
- return 0;
12
- }
13
- }),
14
- ),
15
- );
4
+ return Math.ceil(Math.max(0, ...$$('[stroke]', el).map((stroke) => stroke.getTotalLength?.())));
16
5
  }