@redneckz/wildless-cms-uni-blocks 0.8.10 → 0.8.12

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 (151) hide show
  1. package/bundle/bundle.umd.js +79 -93
  2. package/bundle/bundle.umd.min.js +1 -1
  3. package/bundle/services/BlockRouter/BlockRouter.d.ts +1 -3
  4. package/bundle/ui-kit/Img/ImgAsPicture.d.ts +0 -2
  5. package/bundle/utils/adjustHref.d.ts +3 -0
  6. package/bundle/utils/dirname.d.ts +1 -0
  7. package/bundle/utils/url.d.ts +2 -2
  8. package/dist/ProjectSettings.js +3 -4
  9. package/dist/ProjectSettings.js.map +1 -1
  10. package/dist/hooks/useLink.js +4 -16
  11. package/dist/hooks/useLink.js.map +1 -1
  12. package/dist/services/BlockRouter/BlockRouter.d.ts +1 -3
  13. package/dist/services/BlockRouter/BlockRouter.js +6 -9
  14. package/dist/services/BlockRouter/BlockRouter.js.map +1 -1
  15. package/dist/services/BlockRouter/useBlockRouterProvider.js +2 -10
  16. package/dist/services/BlockRouter/useBlockRouterProvider.js.map +1 -1
  17. package/dist/setup-fixture.js +3 -4
  18. package/dist/setup-fixture.js.map +1 -1
  19. package/dist/ui-kit/BlockWrapper.js +3 -2
  20. package/dist/ui-kit/BlockWrapper.js.map +1 -1
  21. package/dist/ui-kit/Icon/Icon.js +5 -1
  22. package/dist/ui-kit/Icon/Icon.js.map +1 -1
  23. package/dist/ui-kit/Img/ImgAsPicture.d.ts +0 -2
  24. package/dist/ui-kit/Img/ImgAsPicture.js +18 -21
  25. package/dist/ui-kit/Img/ImgAsPicture.js.map +1 -1
  26. package/dist/utils/adjustHref.d.ts +3 -0
  27. package/dist/utils/adjustHref.js +14 -0
  28. package/dist/utils/adjustHref.js.map +1 -0
  29. package/dist/utils/dirname.d.ts +1 -0
  30. package/dist/utils/dirname.js +5 -0
  31. package/dist/utils/dirname.js.map +1 -0
  32. package/dist/utils/url.d.ts +2 -2
  33. package/dist/utils/url.js +1 -1
  34. package/dist/utils/url.js.map +1 -1
  35. package/dist/wlc.json +0 -1
  36. package/lib/ProjectSettings.js +3 -4
  37. package/lib/ProjectSettings.js.map +1 -1
  38. package/lib/hooks/useLink.js +5 -17
  39. package/lib/hooks/useLink.js.map +1 -1
  40. package/lib/services/BlockRouter/BlockRouter.d.ts +1 -3
  41. package/lib/services/BlockRouter/BlockRouter.js +5 -7
  42. package/lib/services/BlockRouter/BlockRouter.js.map +1 -1
  43. package/lib/services/BlockRouter/useBlockRouterProvider.js +2 -10
  44. package/lib/services/BlockRouter/useBlockRouterProvider.js.map +1 -1
  45. package/lib/setup-fixture.js +3 -4
  46. package/lib/setup-fixture.js.map +1 -1
  47. package/lib/ui-kit/BlockWrapper.js +3 -2
  48. package/lib/ui-kit/BlockWrapper.js.map +1 -1
  49. package/lib/ui-kit/Icon/Icon.js +5 -1
  50. package/lib/ui-kit/Icon/Icon.js.map +1 -1
  51. package/lib/ui-kit/Img/ImgAsPicture.d.ts +0 -2
  52. package/lib/ui-kit/Img/ImgAsPicture.js +17 -19
  53. package/lib/ui-kit/Img/ImgAsPicture.js.map +1 -1
  54. package/lib/utils/adjustHref.d.ts +3 -0
  55. package/lib/utils/adjustHref.js +11 -0
  56. package/lib/utils/adjustHref.js.map +1 -0
  57. package/lib/utils/dirname.d.ts +1 -0
  58. package/lib/utils/dirname.js +2 -0
  59. package/lib/utils/dirname.js.map +1 -0
  60. package/lib/utils/url.d.ts +2 -2
  61. package/lib/utils/url.js +1 -1
  62. package/lib/utils/url.js.map +1 -1
  63. package/lib/wlc.json +0 -1
  64. package/mobile/bundle/bundle.umd.js +79 -93
  65. package/mobile/bundle/bundle.umd.min.js +1 -1
  66. package/mobile/bundle/services/BlockRouter/BlockRouter.d.ts +1 -3
  67. package/mobile/bundle/ui-kit/Img/ImgAsPicture.d.ts +0 -2
  68. package/mobile/bundle/utils/adjustHref.d.ts +3 -0
  69. package/mobile/bundle/utils/dirname.d.ts +1 -0
  70. package/mobile/bundle/utils/url.d.ts +2 -2
  71. package/mobile/dist/ProjectSettings.js +3 -4
  72. package/mobile/dist/ProjectSettings.js.map +1 -1
  73. package/mobile/dist/hooks/useLink.js +4 -16
  74. package/mobile/dist/hooks/useLink.js.map +1 -1
  75. package/mobile/dist/services/BlockRouter/BlockRouter.d.ts +1 -3
  76. package/mobile/dist/services/BlockRouter/BlockRouter.js +6 -9
  77. package/mobile/dist/services/BlockRouter/BlockRouter.js.map +1 -1
  78. package/mobile/dist/services/BlockRouter/useBlockRouterProvider.js +2 -10
  79. package/mobile/dist/services/BlockRouter/useBlockRouterProvider.js.map +1 -1
  80. package/mobile/dist/setup-fixture.js +3 -4
  81. package/mobile/dist/setup-fixture.js.map +1 -1
  82. package/mobile/dist/ui-kit/BlockWrapper.js +3 -2
  83. package/mobile/dist/ui-kit/BlockWrapper.js.map +1 -1
  84. package/mobile/dist/ui-kit/Icon/Icon.js +5 -1
  85. package/mobile/dist/ui-kit/Icon/Icon.js.map +1 -1
  86. package/mobile/dist/ui-kit/Img/ImgAsPicture.d.ts +0 -2
  87. package/mobile/dist/ui-kit/Img/ImgAsPicture.js +18 -21
  88. package/mobile/dist/ui-kit/Img/ImgAsPicture.js.map +1 -1
  89. package/mobile/dist/utils/adjustHref.d.ts +3 -0
  90. package/mobile/dist/utils/adjustHref.js +14 -0
  91. package/mobile/dist/utils/adjustHref.js.map +1 -0
  92. package/mobile/dist/utils/dirname.d.ts +1 -0
  93. package/mobile/dist/utils/dirname.js +5 -0
  94. package/mobile/dist/utils/dirname.js.map +1 -0
  95. package/mobile/dist/utils/url.d.ts +2 -2
  96. package/mobile/dist/utils/url.js +1 -1
  97. package/mobile/dist/utils/url.js.map +1 -1
  98. package/mobile/dist/wlc.json +0 -1
  99. package/mobile/lib/ProjectSettings.js +3 -4
  100. package/mobile/lib/ProjectSettings.js.map +1 -1
  101. package/mobile/lib/hooks/useLink.js +5 -17
  102. package/mobile/lib/hooks/useLink.js.map +1 -1
  103. package/mobile/lib/services/BlockRouter/BlockRouter.d.ts +1 -3
  104. package/mobile/lib/services/BlockRouter/BlockRouter.js +5 -7
  105. package/mobile/lib/services/BlockRouter/BlockRouter.js.map +1 -1
  106. package/mobile/lib/services/BlockRouter/useBlockRouterProvider.js +2 -10
  107. package/mobile/lib/services/BlockRouter/useBlockRouterProvider.js.map +1 -1
  108. package/mobile/lib/setup-fixture.js +3 -4
  109. package/mobile/lib/setup-fixture.js.map +1 -1
  110. package/mobile/lib/ui-kit/BlockWrapper.js +3 -2
  111. package/mobile/lib/ui-kit/BlockWrapper.js.map +1 -1
  112. package/mobile/lib/ui-kit/Icon/Icon.js +5 -1
  113. package/mobile/lib/ui-kit/Icon/Icon.js.map +1 -1
  114. package/mobile/lib/ui-kit/Img/ImgAsPicture.d.ts +0 -2
  115. package/mobile/lib/ui-kit/Img/ImgAsPicture.js +17 -19
  116. package/mobile/lib/ui-kit/Img/ImgAsPicture.js.map +1 -1
  117. package/mobile/lib/utils/adjustHref.d.ts +3 -0
  118. package/mobile/lib/utils/adjustHref.js +11 -0
  119. package/mobile/lib/utils/adjustHref.js.map +1 -0
  120. package/mobile/lib/utils/dirname.d.ts +1 -0
  121. package/mobile/lib/utils/dirname.js +2 -0
  122. package/mobile/lib/utils/dirname.js.map +1 -0
  123. package/mobile/lib/utils/url.d.ts +2 -2
  124. package/mobile/lib/utils/url.js +1 -1
  125. package/mobile/lib/utils/url.js.map +1 -1
  126. package/mobile/lib/wlc.json +0 -1
  127. package/mobile/src/ProjectSettings.ts +4 -4
  128. package/mobile/src/hooks/useLink.ts +5 -18
  129. package/mobile/src/services/BlockRouter/BlockRouter.ts +5 -8
  130. package/mobile/src/services/BlockRouter/useBlockRouterProvider.ts +4 -10
  131. package/mobile/src/setup-fixture.ts +5 -4
  132. package/mobile/src/ui-kit/BlockWrapper.tsx +3 -2
  133. package/mobile/src/ui-kit/Icon/Icon.tsx +5 -1
  134. package/mobile/src/ui-kit/Img/ImgAsPicture.tsx +23 -28
  135. package/mobile/src/utils/adjustHref.ts +17 -0
  136. package/mobile/src/utils/dirname.ts +1 -0
  137. package/mobile/src/utils/url.ts +2 -3
  138. package/mobile/src/wlc.json +0 -1
  139. package/package.json +1 -1
  140. package/src/ProjectSettings.ts +4 -4
  141. package/src/hooks/useLink.ts +5 -18
  142. package/src/services/BlockRouter/BlockRouter.ts +5 -8
  143. package/src/services/BlockRouter/useBlockRouterProvider.ts +4 -10
  144. package/src/setup-fixture.ts +5 -4
  145. package/src/ui-kit/BlockWrapper.tsx +3 -2
  146. package/src/ui-kit/Icon/Icon.tsx +5 -1
  147. package/src/ui-kit/Img/ImgAsPicture.tsx +23 -28
  148. package/src/utils/adjustHref.ts +17 -0
  149. package/src/utils/dirname.ts +1 -0
  150. package/src/utils/url.ts +2 -3
  151. package/src/wlc.json +0 -1
@@ -1,7 +1,6 @@
1
1
  import type { LinkProps } from '../model/LinkProps';
2
- import { projectSettings } from '../ProjectSettings';
3
- import { gotoBlock } from '../services/BlockRouter/BlockRouter';
4
- import { isHash, isLocalURL, joinPath } from '../utils/url';
2
+ import { adjustHref } from '../utils/adjustHref';
3
+ import { isLocalURL } from '../utils/url';
5
4
  import { handlerDecorator } from './handlerDecorator';
6
5
  import { useRouter } from './useRouter';
7
6
 
@@ -18,35 +17,23 @@ export function useLink(isRemote?: boolean) {
18
17
 
19
18
  return <L extends Partial<LinkProps & Clickable>>(props: L): L & Clickable => ({
20
19
  ...props,
21
- href: adjustHref(props.href),
20
+ href: isRemote ? props.href : adjustHref(router)(props.href),
22
21
  'aria-label': props.text,
23
22
  onClick: handlerDecorator(handleHref(props), props),
24
23
  });
25
24
 
26
- function adjustHref(href: string | undefined) {
27
- const isRelativeToBase = !isRemote && href?.startsWith('/');
28
-
29
- return projectSettings.BASE_PATH && href && isRelativeToBase
30
- ? joinPath(projectSettings.BASE_PATH, href)
31
- : href;
32
- }
33
-
34
25
  function handleHref({ href, target, onClick }: Partial<LinkProps & Clickable>) {
35
26
  return (ev?: PreventableEvent) => {
36
27
  onClick && onClick(ev);
37
28
 
38
- if (isRemote || !isLocalURL(href, target)) {
29
+ if (!href || isRemote || !isLocalURL(href, target)) {
39
30
  // Default routing
40
31
  return;
41
32
  }
42
33
 
43
34
  // Client routing
44
35
  ev?.preventDefault();
45
- if (isHash(href)) {
46
- gotoBlock(router, href);
47
- } else if (href) {
48
- router.push(href);
49
- }
36
+ router.push(href);
50
37
  };
51
38
  }
52
39
  }
@@ -1,14 +1,11 @@
1
- import type { Router } from '../../hooks/useRouter';
2
1
  import type { BlockDef } from '../../model/ContentPageDef';
3
2
 
4
3
  const normalizeAnchor = (anchor?: string) => anchor?.replace('#', '') || '';
5
4
 
6
- export function gotoBlock(router: Router, anchor?: string) {
7
- router.replace(`#${normalizeAnchor(anchor)}`);
8
- }
5
+ export function trackBlock(block?: BlockDef) {
6
+ const hash = `#${normalizeAnchor(block?.anchor)}`;
9
7
 
10
- export function trackBlock(router: Router, block?: BlockDef) {
11
- router.replace(`#${normalizeAnchor(block?.anchor)}`, undefined, {
12
- scroll: false,
13
- });
8
+ if (globalThis.location?.hash !== hash) {
9
+ globalThis.history?.replaceState(globalThis.history?.state, '', hash);
10
+ }
14
11
  }
@@ -1,5 +1,4 @@
1
1
  import { useEffect, useRef } from '@redneckz/uni-jsx/lib/hooks';
2
- import { useRouter } from '../../hooks/useRouter';
3
2
  import type { BlockDef } from '../../model/ContentPageDef';
4
3
  import { debounce } from '../../utils/debounce';
5
4
  import { trackBlock } from './BlockRouter';
@@ -9,8 +8,6 @@ import { findActiveBlock } from './findActiveBlock';
9
8
  const isScrolledEnough = () => globalThis.scrollY > (globalThis.innerHeight * 3) / 4;
10
9
 
11
10
  export function useBlockRouterProvider(scrollTarget: EventTarget = globalThis) {
12
- const router = useRouter();
13
-
14
11
  const intersectionsMapRef = useRef<Map<BlockDef, IntersectionObserverEntry>>(new Map());
15
12
 
16
13
  useEffect(
@@ -25,12 +22,9 @@ export function useBlockRouterProvider(scrollTarget: EventTarget = globalThis) {
25
22
 
26
23
  useEffect(() => {
27
24
  const handleScroll = debounce(() => {
28
- if (isScrolledEnough()) {
29
- const activeBlock = findActiveBlock([...(intersectionsMapRef.current || [])]);
30
- trackBlock(router, activeBlock);
31
- } else {
32
- trackBlock(router);
33
- }
25
+ trackBlock(
26
+ isScrolledEnough() ? findActiveBlock([...(intersectionsMapRef.current || [])]) : undefined,
27
+ );
34
28
  }, 100);
35
29
 
36
30
  scrollTarget.addEventListener('scroll', handleScroll);
@@ -39,5 +33,5 @@ export function useBlockRouterProvider(scrollTarget: EventTarget = globalThis) {
39
33
  handleScroll.dispose();
40
34
  scrollTarget.removeEventListener('scroll', handleScroll);
41
35
  };
42
- }, [router, scrollTarget]);
36
+ }, [scrollTarget]);
43
37
  }
@@ -3,13 +3,14 @@ import { useEffect, useState } from 'react';
3
3
  import { handlerDecorator } from './hooks/handlerDecorator';
4
4
  import { useRouter } from './hooks/useRouter';
5
5
  import { projectSettings } from './ProjectSettings';
6
+ import { joinPath } from './utils/url';
6
7
  import wlc from './wlc.json';
7
8
 
8
9
  projectSettings.setup(wlc);
9
10
 
10
11
  useRouter.setup(() => {
11
12
  const [href, setHref] = useState<string>(
12
- `${globalThis.location.origin}${projectSettings.BASE_PATH}cards-credit`,
13
+ joinPath(globalThis.location.origin, projectSettings.BASE_PATH, 'cards-credit'),
13
14
  );
14
15
 
15
16
  useEffect(() => {
@@ -26,9 +27,9 @@ useRouter.setup(() => {
26
27
 
27
28
  return {
28
29
  href,
29
- pathname: projectSettings.BASE_PATH
30
- ? new URL(href).pathname.substring(projectSettings.BASE_PATH.length - 1)
31
- : '',
30
+ pathname: new URL(href).pathname.substring(
31
+ projectSettings.BASE_PATH ? projectSettings.BASE_PATH.length - 1 : 0,
32
+ ),
32
33
  query: {},
33
34
  push: (url: string) => {
34
35
  globalThis.history.pushState(null, '', url);
@@ -30,9 +30,10 @@ export const BlockWrapper = JSX<BlockWrapperProps>(
30
30
  () =>
31
31
  defaultEventBus.subscribe('tab', (event) => {
32
32
  if (event.type === 'group') {
33
- const hasSettings = block?.labels?.length || block?.anchor;
34
33
  setVisible(
35
- event.label ? !hasSettings || Boolean(block?.labels?.includes(event.label)) : true,
34
+ !block?.labels?.length ||
35
+ !event.label ||
36
+ Boolean(block?.labels?.includes(event.label)),
36
37
  );
37
38
  } else {
38
39
  setVisible(true);
@@ -1,7 +1,10 @@
1
1
  import { JSX } from '@redneckz/uni-jsx';
2
+ import { useRouter } from '../../hooks/useRouter';
2
3
  import type { IconVersion } from '../../model/IconVersion';
3
4
  import { projectSettings } from '../../ProjectSettings';
5
+ import { adjustHref } from '../../utils/adjustHref';
4
6
  import { style } from '../../utils/style';
7
+ import { joinPath } from '../../utils/url';
5
8
  import type { IconProps } from './IconProps';
6
9
 
7
10
  const svgUseStyleMap: Record<IconVersion, string> = {
@@ -22,7 +25,8 @@ export const Icon = JSX<IconProps>(
22
25
  asSVG,
23
26
  ...imgProps
24
27
  }) => {
25
- const href = `${projectSettings.CDN || ''}icons/${name}.svg`;
28
+ const router = useRouter();
29
+ const href = adjustHref(router)(joinPath(projectSettings.CDN, '/icons', `${name}.svg`));
26
30
 
27
31
  if (asSVG && iconVersion !== 'normal') {
28
32
  return (
@@ -1,20 +1,16 @@
1
1
  import { JSX } from '@redneckz/uni-jsx';
2
+ import { Router, useRouter } from '../../hooks/useRouter';
2
3
  import type { ImgSource, Picture } from '../../model/Picture';
4
+ import { adjustHref } from '../../utils/adjustHref';
5
+ import { isURL, joinPath } from '../../utils/url';
3
6
  import type { ImageProps } from './ImgProps';
4
7
 
5
- const sourcesComparator = (a: Picture, b: Picture) => {
6
- if (a.media && b.media) {
7
- return a.media - b.media;
8
- }
9
-
10
- return 0;
11
- };
8
+ const sourcesComparator = (a: Picture, b: Picture) =>
9
+ a?.media && b?.media ? a.media - b.media : 0;
12
10
 
13
11
  export const ImgAsPicture = JSX<ImageProps>(
14
12
  ({ className = '', image, imageClassName = '', isMobile = false, pathPrefix }) => {
15
- if (!image || (!image?.sources && !image?.src)) {
16
- return null;
17
- }
13
+ const router = useRouter();
18
14
 
19
15
  const pictureStyles = isMobile ? 'flex' : 'flex-none';
20
16
 
@@ -22,22 +18,25 @@ export const ImgAsPicture = JSX<ImageProps>(
22
18
  <picture className={`${pictureStyles} ${className}`}>
23
19
  {image?.sources?.length
24
20
  ? image.sources
21
+ .filter((_) => _?.src)
25
22
  .sort(sourcesComparator)
26
23
  .map(({ src, format, media }, index) => (
27
24
  <source
28
25
  key={`${index}_${src}`}
29
- srcSet={addPathPrefixToSrcSet(src, pathPrefix)}
26
+ srcSet={adjustSrcset(router, pathPrefix)(src)}
30
27
  type={formatToMimeType(format)}
31
28
  media={media ? `(max-width: ${media}px)` : ''}
32
29
  {...image.size}
33
30
  />
34
31
  ))
35
32
  : null}
36
- {renderImg(
37
- { ...image, src: addPathPrefixToSrc(image.src, pathPrefix) },
38
- imageClassName,
39
- isMobile,
40
- )}
33
+ {image?.src
34
+ ? renderImg(
35
+ { ...image, src: adjustSrcset(router, pathPrefix)(image.src) },
36
+ imageClassName,
37
+ isMobile,
38
+ )
39
+ : null}
41
40
  </picture>
42
41
  );
43
42
  },
@@ -65,18 +64,14 @@ const renderImg = (image: Picture, imageClassName = '', isMobile = false) => {
65
64
  );
66
65
  };
67
66
 
68
- const normalizePathPrefix = (pathPrefix = '') =>
69
- pathPrefix && !pathPrefix.endsWith('/') ? `${pathPrefix}/` : pathPrefix;
70
-
71
- const addPathPrefixToSrc = (src?: string, pathPrefix?: string) =>
72
- !src || src?.startsWith('data:image') ? src : `${normalizePathPrefix(pathPrefix)}${src}`;
73
-
74
- const addPathPrefixToSrcSet = (srcset?: string, pathPrefix?: string) =>
67
+ const adjustSrcset = (router: Router, pathPrefix?: string) => (srcset: string | undefined) =>
75
68
  srcset
76
- ?.split(',')
77
- .map((src) => addPathPrefixToSrc(src.trim(), pathPrefix))
69
+ ?.split(/\s*,\s*/)
70
+ .map((src) => src.trim())
71
+ .filter(Boolean)
72
+ .map((src) => (isURL(src) ? src : joinPath(pathPrefix, src)))
73
+ .map(adjustHref(router))
78
74
  .join(', ');
79
75
 
80
- export function formatToMimeType(format: ImgSource['format']): string | undefined {
81
- return format ? `image/${String(format)}` : undefined;
82
- }
76
+ const formatToMimeType = (format: ImgSource['format']) =>
77
+ format ? `image/${String(format)}` : undefined;
@@ -0,0 +1,17 @@
1
+ import { projectSettings } from '../ProjectSettings';
2
+ import { dirname } from './dirname';
3
+ import { isURL, joinPath } from './url';
4
+
5
+ export const adjustHref = (router: { pathname: string }) => (href: string | undefined) => {
6
+ if (!href || isURL(href) || (projectSettings.CDN && href.startsWith(projectSettings.CDN))) {
7
+ return href;
8
+ }
9
+
10
+ const isRelativeToBase = href.startsWith('/');
11
+
12
+ return joinPath(
13
+ projectSettings.BASE_PATH,
14
+ isRelativeToBase ? '/' : dirname(router.pathname),
15
+ href,
16
+ );
17
+ };
@@ -0,0 +1 @@
1
+ export const dirname = (path: string | undefined) => path?.split('/').slice(0, -1).join('/');
@@ -1,7 +1,6 @@
1
1
  import type { Target } from '../model/LinkProps';
2
2
 
3
- export const isURL = (href?: string): href is `${string}//${string}` =>
4
- Boolean(href?.includes('//'));
3
+ export const isURL = (href?: string): href is `${string}:${string}` => Boolean(href?.includes(':'));
5
4
 
6
5
  export const isLocalURL = (href: string | undefined, target?: Target) =>
7
6
  Boolean(href && !isURL(href) && (!target || target === '_self'));
@@ -11,5 +10,5 @@ export const isHash = (href?: string): href is `#${string}` => Boolean(href?.sta
11
10
  export const withoutQuery = (href?: string): string =>
12
11
  (href || '').replace(/\?.*/, '').replace(/\/$/, '');
13
12
 
14
- export const joinPath = (...path: string[]): string =>
13
+ export const joinPath = (...path: (string | undefined)[]): string =>
15
14
  path.filter(Boolean).join('/').replace(/\/+/g, '/');
@@ -2,6 +2,5 @@
2
2
  "PROD_BRANCH": "master",
3
3
  "FORCED_DRAFT_FLOW": false,
4
4
  "YANDEX_MAP_API_KEY": "f4b40c1e-1891-45f2-b307-90c481af210b",
5
- "BASE_PATH": "/natural/",
6
5
  "SITEMAP": "sayt-rshb"
7
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redneckz/wildless-cms-uni-blocks",
3
- "version": "0.8.10",
3
+ "version": "0.8.12",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "ЦК",
@@ -43,12 +43,10 @@ export const projectSettings = new (class implements ProjectSettings {
43
43
  return this._.FOOTER;
44
44
  }
45
45
  get CDN() {
46
- return this._.CDN;
46
+ return appendSlash(this._.CDN);
47
47
  }
48
48
  get BASE_PATH() {
49
- return this._.BASE_PATH && !this._.BASE_PATH.endsWith('/')
50
- ? `${this._.BASE_PATH}/`
51
- : this._.BASE_PATH;
49
+ return appendSlash(this._.BASE_PATH);
52
50
  }
53
51
  get YANDEX_MAP_API_KEY() {
54
52
  return this._.YANDEX_MAP_API_KEY;
@@ -57,3 +55,5 @@ export const projectSettings = new (class implements ProjectSettings {
57
55
  return this._.YANDEX_METRIKA_ID;
58
56
  }
59
57
  })();
58
+
59
+ const appendSlash = (url: string | undefined) => (url && !url.endsWith('/') ? `${url}/` : url);
@@ -1,7 +1,6 @@
1
1
  import type { LinkProps } from '../model/LinkProps';
2
- import { projectSettings } from '../ProjectSettings';
3
- import { gotoBlock } from '../services/BlockRouter/BlockRouter';
4
- import { isHash, isLocalURL, joinPath } from '../utils/url';
2
+ import { adjustHref } from '../utils/adjustHref';
3
+ import { isLocalURL } from '../utils/url';
5
4
  import { handlerDecorator } from './handlerDecorator';
6
5
  import { useRouter } from './useRouter';
7
6
 
@@ -18,35 +17,23 @@ export function useLink(isRemote?: boolean) {
18
17
 
19
18
  return <L extends Partial<LinkProps & Clickable>>(props: L): L & Clickable => ({
20
19
  ...props,
21
- href: adjustHref(props.href),
20
+ href: isRemote ? props.href : adjustHref(router)(props.href),
22
21
  'aria-label': props.text,
23
22
  onClick: handlerDecorator(handleHref(props), props),
24
23
  });
25
24
 
26
- function adjustHref(href: string | undefined) {
27
- const isRelativeToBase = !isRemote && href?.startsWith('/');
28
-
29
- return projectSettings.BASE_PATH && href && isRelativeToBase
30
- ? joinPath(projectSettings.BASE_PATH, href)
31
- : href;
32
- }
33
-
34
25
  function handleHref({ href, target, onClick }: Partial<LinkProps & Clickable>) {
35
26
  return (ev?: PreventableEvent) => {
36
27
  onClick && onClick(ev);
37
28
 
38
- if (isRemote || !isLocalURL(href, target)) {
29
+ if (!href || isRemote || !isLocalURL(href, target)) {
39
30
  // Default routing
40
31
  return;
41
32
  }
42
33
 
43
34
  // Client routing
44
35
  ev?.preventDefault();
45
- if (isHash(href)) {
46
- gotoBlock(router, href);
47
- } else if (href) {
48
- router.push(href);
49
- }
36
+ router.push(href);
50
37
  };
51
38
  }
52
39
  }
@@ -1,14 +1,11 @@
1
- import type { Router } from '../../hooks/useRouter';
2
1
  import type { BlockDef } from '../../model/ContentPageDef';
3
2
 
4
3
  const normalizeAnchor = (anchor?: string) => anchor?.replace('#', '') || '';
5
4
 
6
- export function gotoBlock(router: Router, anchor?: string) {
7
- router.replace(`#${normalizeAnchor(anchor)}`);
8
- }
5
+ export function trackBlock(block?: BlockDef) {
6
+ const hash = `#${normalizeAnchor(block?.anchor)}`;
9
7
 
10
- export function trackBlock(router: Router, block?: BlockDef) {
11
- router.replace(`#${normalizeAnchor(block?.anchor)}`, undefined, {
12
- scroll: false,
13
- });
8
+ if (globalThis.location?.hash !== hash) {
9
+ globalThis.history?.replaceState(globalThis.history?.state, '', hash);
10
+ }
14
11
  }
@@ -1,5 +1,4 @@
1
1
  import { useEffect, useRef } from '@redneckz/uni-jsx/lib/hooks';
2
- import { useRouter } from '../../hooks/useRouter';
3
2
  import type { BlockDef } from '../../model/ContentPageDef';
4
3
  import { debounce } from '../../utils/debounce';
5
4
  import { trackBlock } from './BlockRouter';
@@ -9,8 +8,6 @@ import { findActiveBlock } from './findActiveBlock';
9
8
  const isScrolledEnough = () => globalThis.scrollY > (globalThis.innerHeight * 3) / 4;
10
9
 
11
10
  export function useBlockRouterProvider(scrollTarget: EventTarget = globalThis) {
12
- const router = useRouter();
13
-
14
11
  const intersectionsMapRef = useRef<Map<BlockDef, IntersectionObserverEntry>>(new Map());
15
12
 
16
13
  useEffect(
@@ -25,12 +22,9 @@ export function useBlockRouterProvider(scrollTarget: EventTarget = globalThis) {
25
22
 
26
23
  useEffect(() => {
27
24
  const handleScroll = debounce(() => {
28
- if (isScrolledEnough()) {
29
- const activeBlock = findActiveBlock([...(intersectionsMapRef.current || [])]);
30
- trackBlock(router, activeBlock);
31
- } else {
32
- trackBlock(router);
33
- }
25
+ trackBlock(
26
+ isScrolledEnough() ? findActiveBlock([...(intersectionsMapRef.current || [])]) : undefined,
27
+ );
34
28
  }, 100);
35
29
 
36
30
  scrollTarget.addEventListener('scroll', handleScroll);
@@ -39,5 +33,5 @@ export function useBlockRouterProvider(scrollTarget: EventTarget = globalThis) {
39
33
  handleScroll.dispose();
40
34
  scrollTarget.removeEventListener('scroll', handleScroll);
41
35
  };
42
- }, [router, scrollTarget]);
36
+ }, [scrollTarget]);
43
37
  }
@@ -3,13 +3,14 @@ import { useEffect, useState } from 'react';
3
3
  import { handlerDecorator } from './hooks/handlerDecorator';
4
4
  import { useRouter } from './hooks/useRouter';
5
5
  import { projectSettings } from './ProjectSettings';
6
+ import { joinPath } from './utils/url';
6
7
  import wlc from './wlc.json';
7
8
 
8
9
  projectSettings.setup(wlc);
9
10
 
10
11
  useRouter.setup(() => {
11
12
  const [href, setHref] = useState<string>(
12
- `${globalThis.location.origin}${projectSettings.BASE_PATH}cards-credit`,
13
+ joinPath(globalThis.location.origin, projectSettings.BASE_PATH, 'cards-credit'),
13
14
  );
14
15
 
15
16
  useEffect(() => {
@@ -26,9 +27,9 @@ useRouter.setup(() => {
26
27
 
27
28
  return {
28
29
  href,
29
- pathname: projectSettings.BASE_PATH
30
- ? new URL(href).pathname.substring(projectSettings.BASE_PATH.length - 1)
31
- : '',
30
+ pathname: new URL(href).pathname.substring(
31
+ projectSettings.BASE_PATH ? projectSettings.BASE_PATH.length - 1 : 0,
32
+ ),
32
33
  query: {},
33
34
  push: (url: string) => {
34
35
  globalThis.history.pushState(null, '', url);
@@ -30,9 +30,10 @@ export const BlockWrapper = JSX<BlockWrapperProps>(
30
30
  () =>
31
31
  defaultEventBus.subscribe('tab', (event) => {
32
32
  if (event.type === 'group') {
33
- const hasSettings = block?.labels?.length || block?.anchor;
34
33
  setVisible(
35
- event.label ? !hasSettings || Boolean(block?.labels?.includes(event.label)) : true,
34
+ !block?.labels?.length ||
35
+ !event.label ||
36
+ Boolean(block?.labels?.includes(event.label)),
36
37
  );
37
38
  } else {
38
39
  setVisible(true);
@@ -1,7 +1,10 @@
1
1
  import { JSX } from '@redneckz/uni-jsx';
2
+ import { useRouter } from '../../hooks/useRouter';
2
3
  import type { IconVersion } from '../../model/IconVersion';
3
4
  import { projectSettings } from '../../ProjectSettings';
5
+ import { adjustHref } from '../../utils/adjustHref';
4
6
  import { style } from '../../utils/style';
7
+ import { joinPath } from '../../utils/url';
5
8
  import type { IconProps } from './IconProps';
6
9
 
7
10
  const svgUseStyleMap: Record<IconVersion, string> = {
@@ -22,7 +25,8 @@ export const Icon = JSX<IconProps>(
22
25
  asSVG,
23
26
  ...imgProps
24
27
  }) => {
25
- const href = `${projectSettings.CDN || ''}icons/${name}.svg`;
28
+ const router = useRouter();
29
+ const href = adjustHref(router)(joinPath(projectSettings.CDN, '/icons', `${name}.svg`));
26
30
 
27
31
  if (asSVG && iconVersion !== 'normal') {
28
32
  return (
@@ -1,20 +1,16 @@
1
1
  import { JSX } from '@redneckz/uni-jsx';
2
+ import { Router, useRouter } from '../../hooks/useRouter';
2
3
  import type { ImgSource, Picture } from '../../model/Picture';
4
+ import { adjustHref } from '../../utils/adjustHref';
5
+ import { isURL, joinPath } from '../../utils/url';
3
6
  import type { ImageProps } from './ImgProps';
4
7
 
5
- const sourcesComparator = (a: Picture, b: Picture) => {
6
- if (a.media && b.media) {
7
- return a.media - b.media;
8
- }
9
-
10
- return 0;
11
- };
8
+ const sourcesComparator = (a: Picture, b: Picture) =>
9
+ a?.media && b?.media ? a.media - b.media : 0;
12
10
 
13
11
  export const ImgAsPicture = JSX<ImageProps>(
14
12
  ({ className = '', image, imageClassName = '', isMobile = false, pathPrefix }) => {
15
- if (!image || (!image?.sources && !image?.src)) {
16
- return null;
17
- }
13
+ const router = useRouter();
18
14
 
19
15
  const pictureStyles = isMobile ? 'flex' : 'flex-none';
20
16
 
@@ -22,22 +18,25 @@ export const ImgAsPicture = JSX<ImageProps>(
22
18
  <picture className={`${pictureStyles} ${className}`}>
23
19
  {image?.sources?.length
24
20
  ? image.sources
21
+ .filter((_) => _?.src)
25
22
  .sort(sourcesComparator)
26
23
  .map(({ src, format, media }, index) => (
27
24
  <source
28
25
  key={`${index}_${src}`}
29
- srcSet={addPathPrefixToSrcSet(src, pathPrefix)}
26
+ srcSet={adjustSrcset(router, pathPrefix)(src)}
30
27
  type={formatToMimeType(format)}
31
28
  media={media ? `(max-width: ${media}px)` : ''}
32
29
  {...image.size}
33
30
  />
34
31
  ))
35
32
  : null}
36
- {renderImg(
37
- { ...image, src: addPathPrefixToSrc(image.src, pathPrefix) },
38
- imageClassName,
39
- isMobile,
40
- )}
33
+ {image?.src
34
+ ? renderImg(
35
+ { ...image, src: adjustSrcset(router, pathPrefix)(image.src) },
36
+ imageClassName,
37
+ isMobile,
38
+ )
39
+ : null}
41
40
  </picture>
42
41
  );
43
42
  },
@@ -65,18 +64,14 @@ const renderImg = (image: Picture, imageClassName = '', isMobile = false) => {
65
64
  );
66
65
  };
67
66
 
68
- const normalizePathPrefix = (pathPrefix = '') =>
69
- pathPrefix && !pathPrefix.endsWith('/') ? `${pathPrefix}/` : pathPrefix;
70
-
71
- const addPathPrefixToSrc = (src?: string, pathPrefix?: string) =>
72
- !src || src?.startsWith('data:image') ? src : `${normalizePathPrefix(pathPrefix)}${src}`;
73
-
74
- const addPathPrefixToSrcSet = (srcset?: string, pathPrefix?: string) =>
67
+ const adjustSrcset = (router: Router, pathPrefix?: string) => (srcset: string | undefined) =>
75
68
  srcset
76
- ?.split(',')
77
- .map((src) => addPathPrefixToSrc(src.trim(), pathPrefix))
69
+ ?.split(/\s*,\s*/)
70
+ .map((src) => src.trim())
71
+ .filter(Boolean)
72
+ .map((src) => (isURL(src) ? src : joinPath(pathPrefix, src)))
73
+ .map(adjustHref(router))
78
74
  .join(', ');
79
75
 
80
- export function formatToMimeType(format: ImgSource['format']): string | undefined {
81
- return format ? `image/${String(format)}` : undefined;
82
- }
76
+ const formatToMimeType = (format: ImgSource['format']) =>
77
+ format ? `image/${String(format)}` : undefined;
@@ -0,0 +1,17 @@
1
+ import { projectSettings } from '../ProjectSettings';
2
+ import { dirname } from './dirname';
3
+ import { isURL, joinPath } from './url';
4
+
5
+ export const adjustHref = (router: { pathname: string }) => (href: string | undefined) => {
6
+ if (!href || isURL(href) || (projectSettings.CDN && href.startsWith(projectSettings.CDN))) {
7
+ return href;
8
+ }
9
+
10
+ const isRelativeToBase = href.startsWith('/');
11
+
12
+ return joinPath(
13
+ projectSettings.BASE_PATH,
14
+ isRelativeToBase ? '/' : dirname(router.pathname),
15
+ href,
16
+ );
17
+ };
@@ -0,0 +1 @@
1
+ export const dirname = (path: string | undefined) => path?.split('/').slice(0, -1).join('/');
package/src/utils/url.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import type { Target } from '../model/LinkProps';
2
2
 
3
- export const isURL = (href?: string): href is `${string}//${string}` =>
4
- Boolean(href?.includes('//'));
3
+ export const isURL = (href?: string): href is `${string}:${string}` => Boolean(href?.includes(':'));
5
4
 
6
5
  export const isLocalURL = (href: string | undefined, target?: Target) =>
7
6
  Boolean(href && !isURL(href) && (!target || target === '_self'));
@@ -11,5 +10,5 @@ export const isHash = (href?: string): href is `#${string}` => Boolean(href?.sta
11
10
  export const withoutQuery = (href?: string): string =>
12
11
  (href || '').replace(/\?.*/, '').replace(/\/$/, '');
13
12
 
14
- export const joinPath = (...path: string[]): string =>
13
+ export const joinPath = (...path: (string | undefined)[]): string =>
15
14
  path.filter(Boolean).join('/').replace(/\/+/g, '/');
package/src/wlc.json CHANGED
@@ -2,6 +2,5 @@
2
2
  "PROD_BRANCH": "master",
3
3
  "FORCED_DRAFT_FLOW": false,
4
4
  "YANDEX_MAP_API_KEY": "f4b40c1e-1891-45f2-b307-90c481af210b",
5
- "BASE_PATH": "/natural/",
6
5
  "SITEMAP": "sayt-rshb"
7
6
  }