@redneckz/wildless-cms-uni-blocks 0.14.58 → 0.14.60

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 (136) hide show
  1. package/bundle/blocks.schema.json +1 -1
  2. package/bundle/bundle.umd.js +559 -569
  3. package/bundle/bundle.umd.min.js +1 -1
  4. package/bundle/components/AdTile/AdTile.d.ts +6 -0
  5. package/bundle/components/AdTile/AdTileContent.d.ts +5 -0
  6. package/bundle/components/AdTile/useAdTile.d.ts +2 -0
  7. package/bundle/components/ExchangeRateTile/useFetchExchangeRateData.d.ts +2 -10
  8. package/bundle/model/ContentPageDef.d.ts +1 -0
  9. package/bundle/utils/isOdd.d.ts +1 -0
  10. package/dist/components/AdTile/AdTile.d.ts +6 -0
  11. package/dist/components/AdTile/AdTile.js +12 -0
  12. package/dist/components/AdTile/AdTile.js.map +1 -0
  13. package/dist/components/AdTile/AdTileContent.d.ts +5 -0
  14. package/dist/components/AdTile/AdTileContent.js +2 -0
  15. package/dist/components/AdTile/AdTileContent.js.map +1 -0
  16. package/dist/components/AdTile/useAdTile.d.ts +2 -0
  17. package/dist/components/AdTile/useAdTile.js +12 -0
  18. package/dist/components/AdTile/useAdTile.js.map +1 -0
  19. package/dist/components/Blocks.js +4 -2
  20. package/dist/components/Blocks.js.map +1 -1
  21. package/dist/components/Blocks.mobile.js +2 -0
  22. package/dist/components/Blocks.mobile.js.map +1 -1
  23. package/dist/components/ExchangeRateTile/ExchangeRateTile.js +3 -1
  24. package/dist/components/ExchangeRateTile/ExchangeRateTile.js.map +1 -1
  25. package/dist/components/ExchangeRateTile/useFetchExchangeRateData.d.ts +2 -10
  26. package/dist/components/ExchangeRateTile/useFetchExchangeRateData.js +4 -35
  27. package/dist/components/ExchangeRateTile/useFetchExchangeRateData.js.map +1 -1
  28. package/dist/model/ContentPageDef.d.ts +1 -0
  29. package/dist/ui-kit/BaseFiltration/BaseFiltrationInner.js +4 -2
  30. package/dist/ui-kit/BaseFiltration/BaseFiltrationInner.js.map +1 -1
  31. package/dist/utils/isOdd.d.ts +1 -0
  32. package/dist/utils/isOdd.js +5 -0
  33. package/dist/utils/isOdd.js.map +1 -0
  34. package/lib/components/AdTile/AdTile.d.ts +6 -0
  35. package/lib/components/AdTile/AdTile.fixture.d.ts +6 -0
  36. package/lib/components/AdTile/AdTile.js +10 -0
  37. package/lib/components/AdTile/AdTile.js.map +1 -0
  38. package/lib/components/AdTile/AdTileContent.d.ts +5 -0
  39. package/lib/components/AdTile/AdTileContent.js +2 -0
  40. package/lib/components/AdTile/AdTileContent.js.map +1 -0
  41. package/lib/components/AdTile/useAdTile.d.ts +2 -0
  42. package/lib/components/AdTile/useAdTile.js +9 -0
  43. package/lib/components/AdTile/useAdTile.js.map +1 -0
  44. package/lib/components/Blocks.js +4 -2
  45. package/lib/components/Blocks.js.map +1 -1
  46. package/lib/components/Blocks.mobile.js +2 -0
  47. package/lib/components/Blocks.mobile.js.map +1 -1
  48. package/lib/components/ExchangeRateTile/ExchangeRateTile.js +3 -1
  49. package/lib/components/ExchangeRateTile/ExchangeRateTile.js.map +1 -1
  50. package/lib/components/ExchangeRateTile/useFetchExchangeRateData.d.ts +2 -10
  51. package/lib/components/ExchangeRateTile/useFetchExchangeRateData.js +3 -33
  52. package/lib/components/ExchangeRateTile/useFetchExchangeRateData.js.map +1 -1
  53. package/lib/model/ContentPageDef.d.ts +1 -0
  54. package/lib/ui-kit/BaseFiltration/BaseFiltrationInner.js +4 -2
  55. package/lib/ui-kit/BaseFiltration/BaseFiltrationInner.js.map +1 -1
  56. package/lib/utils/isOdd.d.ts +1 -0
  57. package/lib/utils/isOdd.js +2 -0
  58. package/lib/utils/isOdd.js.map +1 -0
  59. package/mobile/bundle/bundle.umd.js +560 -570
  60. package/mobile/bundle/bundle.umd.min.js +1 -1
  61. package/mobile/bundle/components/AdTile/AdTile.d.ts +6 -0
  62. package/mobile/bundle/components/AdTile/AdTileContent.d.ts +5 -0
  63. package/mobile/bundle/components/AdTile/useAdTile.d.ts +2 -0
  64. package/mobile/bundle/components/ExchangeRateTile/useFetchExchangeRateData.d.ts +2 -10
  65. package/mobile/bundle/model/ContentPageDef.d.ts +1 -0
  66. package/mobile/bundle/utils/isOdd.d.ts +1 -0
  67. package/mobile/dist/components/AdTile/AdTile.d.ts +6 -0
  68. package/mobile/dist/components/AdTile/AdTile.js +12 -0
  69. package/mobile/dist/components/AdTile/AdTile.js.map +1 -0
  70. package/mobile/dist/components/AdTile/AdTileContent.d.ts +5 -0
  71. package/mobile/dist/components/AdTile/AdTileContent.js +2 -0
  72. package/mobile/dist/components/AdTile/AdTileContent.js.map +1 -0
  73. package/mobile/dist/components/AdTile/useAdTile.d.ts +2 -0
  74. package/mobile/dist/components/AdTile/useAdTile.js +12 -0
  75. package/mobile/dist/components/AdTile/useAdTile.js.map +1 -0
  76. package/mobile/dist/components/Blocks.js +2 -0
  77. package/mobile/dist/components/Blocks.js.map +1 -1
  78. package/mobile/dist/components/ExchangeRateTile/ExchangeRateTile.js +3 -1
  79. package/mobile/dist/components/ExchangeRateTile/ExchangeRateTile.js.map +1 -1
  80. package/mobile/dist/components/ExchangeRateTile/useFetchExchangeRateData.d.ts +2 -10
  81. package/mobile/dist/components/ExchangeRateTile/useFetchExchangeRateData.js +4 -35
  82. package/mobile/dist/components/ExchangeRateTile/useFetchExchangeRateData.js.map +1 -1
  83. package/mobile/dist/model/ContentPageDef.d.ts +1 -0
  84. package/mobile/dist/ui-kit/BaseFiltration/BaseFiltrationInner.js +4 -2
  85. package/mobile/dist/ui-kit/BaseFiltration/BaseFiltrationInner.js.map +1 -1
  86. package/mobile/dist/utils/isOdd.d.ts +1 -0
  87. package/mobile/dist/utils/isOdd.js +5 -0
  88. package/mobile/dist/utils/isOdd.js.map +1 -0
  89. package/mobile/lib/common.css +1 -1
  90. package/mobile/lib/components/AdTile/AdTile.d.ts +6 -0
  91. package/mobile/lib/components/AdTile/AdTile.js +10 -0
  92. package/mobile/lib/components/AdTile/AdTile.js.map +1 -0
  93. package/mobile/lib/components/AdTile/AdTileContent.d.ts +5 -0
  94. package/mobile/lib/components/AdTile/AdTileContent.js +2 -0
  95. package/mobile/lib/components/AdTile/AdTileContent.js.map +1 -0
  96. package/mobile/lib/components/AdTile/useAdTile.d.ts +2 -0
  97. package/mobile/lib/components/AdTile/useAdTile.js +9 -0
  98. package/mobile/lib/components/AdTile/useAdTile.js.map +1 -0
  99. package/mobile/lib/components/Blocks.js +2 -0
  100. package/mobile/lib/components/Blocks.js.map +1 -1
  101. package/mobile/lib/components/ExchangeRateTile/ExchangeRateTile.js +3 -1
  102. package/mobile/lib/components/ExchangeRateTile/ExchangeRateTile.js.map +1 -1
  103. package/mobile/lib/components/ExchangeRateTile/useFetchExchangeRateData.d.ts +2 -10
  104. package/mobile/lib/components/ExchangeRateTile/useFetchExchangeRateData.js +3 -33
  105. package/mobile/lib/components/ExchangeRateTile/useFetchExchangeRateData.js.map +1 -1
  106. package/mobile/lib/model/ContentPageDef.d.ts +1 -0
  107. package/mobile/lib/ui-kit/BaseFiltration/BaseFiltrationInner.js +4 -2
  108. package/mobile/lib/ui-kit/BaseFiltration/BaseFiltrationInner.js.map +1 -1
  109. package/mobile/lib/utils/isOdd.d.ts +1 -0
  110. package/mobile/lib/utils/isOdd.js +2 -0
  111. package/mobile/lib/utils/isOdd.js.map +1 -0
  112. package/mobile/src/components/AdTile/AdTile.example.json +1 -0
  113. package/mobile/src/components/AdTile/AdTile.tsx +18 -0
  114. package/mobile/src/components/AdTile/AdTile.ui.json +1 -0
  115. package/mobile/src/components/AdTile/AdTileContent.ts +6 -0
  116. package/mobile/src/components/AdTile/useAdTile.ts +17 -0
  117. package/mobile/src/components/Blocks.ts +3 -0
  118. package/mobile/src/components/ExchangeRateTile/ExchangeRateTile.tsx +3 -1
  119. package/mobile/src/components/ExchangeRateTile/useFetchExchangeRateData.ts +7 -54
  120. package/mobile/src/model/ContentPageDef.ts +1 -0
  121. package/mobile/src/ui-kit/BaseFiltration/BaseFiltrationInner.tsx +4 -0
  122. package/mobile/src/utils/isOdd.ts +1 -0
  123. package/package.json +1 -1
  124. package/src/components/AdTile/AdTile.example.json +1 -0
  125. package/src/components/AdTile/AdTile.fixture.tsx +11 -0
  126. package/src/components/AdTile/AdTile.tsx +18 -0
  127. package/src/components/AdTile/AdTile.ui.json +1 -0
  128. package/src/components/AdTile/AdTileContent.ts +6 -0
  129. package/src/components/AdTile/useAdTile.ts +17 -0
  130. package/src/components/Blocks.mobile.ts +3 -0
  131. package/src/components/Blocks.ts +5 -2
  132. package/src/components/ExchangeRateTile/ExchangeRateTile.tsx +3 -1
  133. package/src/components/ExchangeRateTile/useFetchExchangeRateData.ts +7 -54
  134. package/src/model/ContentPageDef.ts +1 -0
  135. package/src/ui-kit/BaseFiltration/BaseFiltrationInner.tsx +4 -0
  136. package/src/utils/isOdd.ts +1 -0
@@ -243,30 +243,10 @@
243
243
  return JSXTmpl;
244
244
  };
245
245
 
246
- function LeadServiceAPI() {
247
- async function send(body, isIndividualType) {
248
- const url = isIndividualType ? '/api/v1/lead' : '/api/v1/sendcorporatelead';
249
- try {
250
- const response = await fetch(url, {
251
- method: 'POST',
252
- headers: { 'Content-Type': 'application/json' },
253
- mode: 'cors',
254
- body: JSON.stringify(body),
255
- });
256
- if (!response?.ok) {
257
- return null;
258
- }
259
- const data = await response.json();
260
- return data;
261
- }
262
- catch (e) {
263
- return null;
264
- }
265
- }
266
- return {
267
- send,
268
- };
269
- }
246
+ const isSSR = () => Boolean(typeof globalThis.process === 'object' && globalThis.process && globalThis.process.version);
247
+
248
+ const isClient = !isSSR();
249
+ const ClientOnly = JSX(({ children }) => (isClient ? children : null));
270
250
 
271
251
  class EventBus {
272
252
  subscribers = {};
@@ -374,154 +354,52 @@
374
354
  return (jsx(Tag, { className: style('font-sans m-0', styles$3[headingType], className), children: title || children }));
375
355
  });
376
356
 
377
- const identity = (_) => _;
378
-
379
- const useForm = (initialState, onSubmit) => {
380
- const [formState, setFormState] = useState(initialState);
381
- const [isDirtyForm, setDirtyForm] = useState(false);
382
- const [dirtyFieldsMap, setDirtyFieldsMap] = useState({});
383
- const handlersMap = useRef({});
384
- const field = useCallback((fieldName, options) => {
385
- const { parse = identity, format = identity } = options || {};
386
- if (!handlersMap.current) {
387
- handlersMap.current = {};
388
- }
389
- handlersMap.current[fieldName] ||= (value) => {
390
- setFormState((prev) => ({ ...prev, [fieldName]: parse(value) }));
391
- setDirtyFieldsMap((prev) => ({ ...prev, [fieldName]: true }));
392
- };
393
- return {
394
- value: format(formState[fieldName]),
395
- isDirty: isDirtyForm || dirtyFieldsMap[fieldName],
396
- onChange: handlersMap.current[fieldName],
397
- };
398
- }, [formState, isDirtyForm, dirtyFieldsMap]);
399
- const update = useCallback((_) => {
400
- setFormState(_);
401
- setDirtyFieldsMap(_);
402
- }, []);
403
- const reset = useCallback(() => {
404
- setFormState(initialState);
405
- setDirtyForm(false);
406
- setDirtyFieldsMap({});
407
- }, [initialState]);
408
- const handleSubmit = useCallback((e) => {
409
- e.preventDefault();
410
- setDirtyForm(true);
411
- onSubmit && onSubmit(formState);
412
- }, [onSubmit, formState]);
413
- return [
414
- formState,
415
- {
416
- isDirty: isDirtyForm || Object.values(dirtyFieldsMap).some(Boolean),
417
- field,
418
- update,
419
- reset,
420
- onSubmit: handleSubmit,
421
- },
422
- ];
423
- };
424
-
425
- const objectValidator = (validatorsMap) => (o) => (o &&
426
- Object.entries(validatorsMap).flatMap(([key, validator]) => validator(o[key]))) ||
427
- [];
428
-
429
- const isValidationSuccess = (info) => !info?.length;
430
- const validator = (predicate) => (message) => (_) => predicate(_) ? [] : [message];
431
-
432
- const isFilled = (_) => _ !== null && _ !== undefined;
357
+ const Paragraph = JSX(({ children, ...styleProps }) => (jsx("p", { className: style('font-sans', Object.values(styleProps)), children: children })));
433
358
 
434
- const defaultCache = new Map();
435
- const applyCache = (fetcher, cache = defaultCache) => (key) => {
436
- const cachedData = cache.get(key);
437
- if (isFilled(cachedData)) {
438
- return cachedData;
439
- }
440
- const data = fetcher(key);
441
- if (isFilled(data)) {
442
- cache.set(key, Promise.resolve(data));
443
- }
444
- else {
445
- cache.delete(key);
446
- }
447
- return data;
359
+ const headlineVersionStyles = {
360
+ XXL: {
361
+ title: { headingType: 'h0', as: 'h1' },
362
+ descriptionSize: 'text-h5',
363
+ descriptionWeight: 'font-normal',
364
+ descriptionStyle: 'mt-xl',
365
+ },
366
+ XL: {
367
+ title: { headingType: 'h1', as: 'h1' },
368
+ descriptionSize: 'text-xl',
369
+ descriptionWeight: 'font-light',
370
+ descriptionStyle: 'mt-m',
371
+ },
372
+ L: {
373
+ title: { headingType: 'h2', as: 'h2' },
374
+ descriptionSize: 'text-xl',
375
+ descriptionWeight: 'font-light',
376
+ descriptionStyle: 'mt-m',
377
+ },
378
+ M: {
379
+ title: { headingType: 'h3', as: 'h2' },
380
+ descriptionSize: 'text-xl',
381
+ descriptionWeight: 'font-light',
382
+ descriptionStyle: 'mt-s',
383
+ },
384
+ S: {
385
+ title: { headingType: 'h4', as: 'h2' },
386
+ descriptionSize: 'text-xl',
387
+ descriptionWeight: 'font-light',
388
+ descriptionStyle: 'mt-xs',
389
+ },
390
+ XS: {
391
+ title: { headingType: 'h5', as: 'h2' },
392
+ descriptionSize: 'text-m',
393
+ descriptionWeight: 'font-light',
394
+ descriptionStyle: 'mt-xs',
395
+ },
448
396
  };
449
397
 
450
- const isSimpleKey = (args) => Boolean(args && Array.isArray(args) && args.length === 1 && typeof args[0] === 'string');
451
- function useAsyncData(key, fetcher, { fallback, cache } = {}) {
452
- const args = useMemo(() => keyToArgs(key), [key]);
453
- const [simpleKey] = isSimpleKey(args) ? args : [];
454
- const [data, setData] = useState(undefined);
455
- const [error, setError] = useState(undefined);
456
- useEffect(() => {
457
- const isEmptyKey = !args.some(isFilled);
458
- if (isEmptyKey) {
459
- return;
460
- }
461
- let canceled = false;
462
- const setResult = (newData, err) => {
463
- if (!canceled) {
464
- setData(newData);
465
- setError(err);
466
- }
467
- };
468
- (async () => {
469
- try {
470
- setResult(await (simpleKey ? applyCache(fetcher, cache)(simpleKey) : fetcher(...args)));
471
- }
472
- catch (err) {
473
- setResult(undefined, err);
474
- }
475
- })();
476
- return () => {
477
- canceled = true;
478
- };
479
- }, [fetcher, cache, args]);
480
- const fallbackData = fallback && simpleKey && fallback[simpleKey];
481
- return {
482
- data: !data && fallbackData ? fallbackData : data,
483
- error,
484
- mutate: () => Promise.resolve(undefined) // TODO Clean up cache
485
- };
486
- }
487
- function keyToArgs(key) {
488
- if (Array.isArray(key)) {
489
- return key;
490
- }
491
- else if (key instanceof Function) {
492
- return keyToArgs(key());
493
- }
494
- else {
495
- return [key];
496
- }
497
- }
498
-
499
- async function fetchJSON(url, options) {
500
- try {
501
- return url ? await fetchJSONUnsafe(url, options) : null;
502
- }
503
- catch (err) {
504
- console.error(err);
505
- }
506
- return null;
507
- }
508
- async function fetchJSONUnsafe(url, options) {
509
- const response = await fetch(url, {
510
- ...options,
511
- headers: {
512
- ...options?.headers,
513
- 'Content-Type': 'application/json',
514
- },
515
- });
516
- return response.json();
517
- }
518
-
519
- const REGIONS_URL$1 = '/api/v1/regions';
520
- const EMPTY_VALUE$5 = [];
521
- function useGetRegions() {
522
- const { data } = useAsyncData(REGIONS_URL$1, fetchJSONUnsafe);
523
- return data || EMPTY_VALUE$5;
524
- }
398
+ const Headline = JSX(({ className, version = '', headlineVersion = 'XL', title, description, align = 'text-center', as, isEmbedded = false, isTheme = false, ...rest }) => {
399
+ const versionStyle = headlineVersionStyles[headlineVersion];
400
+ const descriptionStyle = { marginTop: versionStyle.descriptionStyle };
401
+ return (jsxs(BlockWrapper, { className: style(isEmbedded ? '@container-normal' : '', className), defaultPadding: isEmbedded ? '' : 'p-6xl', version: version, isTheme: isTheme, ...rest, children: [title ? (jsx(Heading, { className: style('whitespace-pre-wrap', align), ...versionStyle?.title, as: as || versionStyle?.title.as, title: title })) : null, description ? (jsx(Paragraph, { size: versionStyle.descriptionSize, font: versionStyle.descriptionWeight, align: align, ...descriptionStyle, children: description })) : null] }));
402
+ });
525
403
 
526
404
  const useDialogManager = () => ({
527
405
  open: (dialog, options = {}) => defaultEventBus.fire('dialog', { type: 'open', dialog, ...options }),
@@ -692,19 +570,407 @@
692
570
  form.submit();
693
571
  }, []);
694
572
 
695
- const Button = JSX(({ disabled, children, method = 'LINK', href, ...rest }) => {
696
- const handleFormSubmit = useFormSubmit({ method, href });
697
- const link = useLink();
698
- const adjustedProps = link({ onClick: handleFormSubmit, href, ...rest });
699
- const buttonInner = children ?? jsx(ButtonInner, { ...adjustedProps });
700
- return disabled ? (jsx(DisabledButton, { ...adjustedProps, children: buttonInner })) : (jsx(RegularButton, { ...adjustedProps, children: buttonInner }));
701
- });
702
- const RegularButton = JSX(({ className = '', href, rel, target, ariaLabel, version, rounded, onClick, children }) => (jsx("a", { className: getRegularButtonClasses({ className, version, rounded }), href: href, rel: rel, target: target, "aria-label": ariaLabel, role: href ? 'link' : 'button', onClick: onClick, children: children })));
703
- const DisabledButton = JSX(({ className, ariaLabel, version, rounded, children }) => (jsx("div", { role: "button", "aria-disabled": "true", "aria-label": ariaLabel, tabIndex: -1, className: getDisabledButtonClasses({ className, rounded, version }), children: children })));
573
+ const Button = JSX(({ disabled, children, method = 'LINK', href, ...rest }) => {
574
+ const handleFormSubmit = useFormSubmit({ method, href });
575
+ const link = useLink();
576
+ const adjustedProps = link({ onClick: handleFormSubmit, href, ...rest });
577
+ const buttonInner = children ?? jsx(ButtonInner, { ...adjustedProps });
578
+ return disabled ? (jsx(DisabledButton, { ...adjustedProps, children: buttonInner })) : (jsx(RegularButton, { ...adjustedProps, children: buttonInner }));
579
+ });
580
+ const RegularButton = JSX(({ className = '', href, rel, target, ariaLabel, version, rounded, onClick, children }) => (jsx("a", { className: getRegularButtonClasses({ className, version, rounded }), href: href, rel: rel, target: target, "aria-label": ariaLabel, role: href ? 'link' : 'button', onClick: onClick, children: children })));
581
+ const DisabledButton = JSX(({ className, ariaLabel, version, rounded, children }) => (jsx("div", { role: "button", "aria-disabled": "true", "aria-label": ariaLabel, tabIndex: -1, className: getDisabledButtonClasses({ className, rounded, version }), children: children })));
582
+
583
+ const isOnlyDigits = (str) => str && !/\D/.test(str);
584
+
585
+ const svgUseStyleMap = {
586
+ normal: '',
587
+ color: 'text-primary-main',
588
+ black: 'text-black',
589
+ white: 'text-black',
590
+ };
591
+ const Icon = JSX(({ className = '', imageClassName = '', name = '', alt = `Иконка ${name}`, title = alt, iconVersion = 'color', width, height, }) => {
592
+ const router = useRouter();
593
+ const href = adjustHref(router)(joinPath(projectSettings.CDN, '/icons', `${name}.svg`));
594
+ if (iconVersion !== 'normal') {
595
+ return (jsx(Background, { className: className, children: jsxs("svg", { className: style(getSvgSize(width), svgUseStyleMap[iconVersion], iconVersion === 'white' ? 'invert' : '', imageClassName), width: width, height: height, "aria-hidden": "true", children: [title ? jsx("title", { children: title }) : null, alt ? jsx("desc", { children: alt }) : null, jsx("use", { href: `${href}#icon`, xlinkHref: `${href}#icon` })] }) }));
596
+ }
597
+ return (jsx("img", { className: className, src: href, alt: alt, title: title, "aria-hidden": "true", width: width, height: height, style: getInlineStyle(className, height) }));
598
+ });
599
+ const getInlineStyle = (className, height) => {
600
+ if (className?.includes('h-')) {
601
+ return {};
602
+ }
603
+ return { height: isOnlyDigits(height) ? `${height}px` : height, width: 'auto' };
604
+ };
605
+ const getSvgSize = (width) => (width ? '' : 'w-full h-full');
606
+ const Background = JSX(({ className, children }) => className ? jsx("div", { className: className, children: children }) : children);
607
+
608
+ const sourcesComparator = (a, b) => a?.media && b?.media ? a.media - b.media : 0;
609
+ const ImgAsPicture = JSX(({ className = '', image, imageClassName = '', pathPrefix }) => {
610
+ const router = useRouter();
611
+ return (jsxs("picture", { className: className, children: [image?.sources?.length
612
+ ? image.sources
613
+ .filter((_) => _?.src)
614
+ .sort(sourcesComparator)
615
+ .map(({ src, format, media }, index) => (jsx("source", { srcSet: adjustSrc(router, pathPrefix)(src), type: formatToMimeType(format), media: media ? `(max-width: ${media}px)` : '', width: image.size?.width, height: image.size?.height }, `${index}_${src}`)))
616
+ : null, image?.src
617
+ ? renderImg({ ...image, src: adjustSrc(router, pathPrefix)(image.src) }, imageClassName)
618
+ : null] }));
619
+ });
620
+ const renderImg = (image, imageClassName = '') => (jsx("img", { src: image.src, className: style('object-contain', imageClassName), alt: image.alt || image.title, title: image.title || '', style: {
621
+ width: image.size?.width ? `${image.size?.width}px` : '100%',
622
+ height: image.size?.height ? `${image.size?.height}px` : 'auto',
623
+ }, width: image.size?.width, height: image.size?.height }));
624
+ const adjustSrc = (router, pathPrefix) => (src) => src && !isURL(src) ? adjustHref(router)(joinPath(pathPrefix, src)) : src;
625
+ const formatToMimeType = (format) => format ? `image/${String(format)}` : undefined;
626
+
627
+ const Img = JSX(({ className = '', image, imageClassName = '', pathPrefix, ...iconProps }) => {
628
+ if (!image?.src && !image?.icon) {
629
+ return null;
630
+ }
631
+ return image.icon ? (jsx(Icon, { className: className, imageClassName: imageClassName, iconVersion: image?.iconVersion, name: image.icon, ...iconProps })) : (jsx(ImgAsPicture, { className: className, imageClassName: imageClassName, image: image, pathPrefix: pathPrefix }));
632
+ });
633
+
634
+ function renderBackwardButton(version, handleClick) {
635
+ const iconVersion = version === 'primary' ? 'white' : 'black';
636
+ const className = 'w-12 h-12 min-h-12 min-w-12 flex items-center justify-center';
637
+ const text = 'Вернуться назад';
638
+ return (jsxs("div", { className: "hidden sm:flex items-center gap-s", children: [jsx("div", { className: getRegularButtonClasses({ className, version, rounded: true }), onClick: handleClick, children: jsx(Img, { className: "w-4 h-4", image: {
639
+ icon: 'ArrowLeftIcon',
640
+ iconVersion: iconVersion,
641
+ } }) }), jsx(Button, { version: "link", className: "group-data-secondary:text-white/80", text: text, ariaLabel: text, onClick: handleClick })] }));
642
+ }
643
+
644
+ const imageAlignmentMap = {
645
+ start: '@xl:self-start',
646
+ center: '@xl:self-center',
647
+ end: '@xl:self-end',
648
+ };
649
+ const BaseTile = JSX(({ className, version = 'primary', defaultPadding, padding, title = '', insetTitle = '', buttons, leftImage, rightImage, imageAlign, isImageAlwaysOnRight = false, isImageSecondary = false, backwardButton, children, }) => {
650
+ const router = useRouter();
651
+ const handleClick = useCallback((ev) => {
652
+ ev?.preventDefault();
653
+ router.back();
654
+ }, []);
655
+ return (jsxs("div", { className: getStyle(padding, defaultPadding, className), children: [backwardButton ? renderBackwardButton(version, handleClick) : null, title ? jsx("div", { className: "relative", children: title }) : null, jsxs("div", { className: style('grow relative flex flex-col @xl:flex-row gap-3xl w-full', leftImage ? 'self-start @xl:w-auto' : ''), children: [renderImageContainer(leftImage, { imageAlign, className: 'mx-auto' }), jsxs("div", { className: style('grid gap-3xl h-full', rightImage ? '@xl:grid-cols-2' : '', leftImage ? '' : 'grow'), children: [jsxs("div", { className: "grow space-y-lg min-w-fit", children: [insetTitle, children] }), renderImageContainer(rightImage, {
656
+ className: style('@xl:justify-self-end @xl:col-start-2', buttons ? rowSpanStyle(isImageAlwaysOnRight) : '', positionStyle(isImageAlwaysOnRight), imageSecondaryStyle(isImageSecondary)),
657
+ imageAlign,
658
+ }), renderButtons(buttons)] })] })] }));
659
+ });
660
+ const getStyle = (padding = '', defaultPadding = '', className = '') => style('relative flex flex-col gap-3xl overflow-hidden', padding || defaultPadding, className);
661
+ const rowSpanStyle = (isImageAlwaysOnRight) => isImageAlwaysOnRight ? 'row-span-2' : '@xl:row-span-2';
662
+ const positionStyle = (isImageAlwaysOnRight) => isImageAlwaysOnRight ? 'col-start-2 self-center' : '';
663
+ const renderButtons = (buttons) => buttons ? jsx("div", { className: "self-end", children: buttons }) : null;
664
+ const renderImageContainer = (image, { className, imageAlign }) => image ? (jsx("div", { className: style('shrink-1/2 justify-self-center', imageAlign && imageAlignmentMap[imageAlign], className), children: image })) : null;
665
+ const imageSecondaryStyle = (isImageSecondary) => isImageSecondary ? 'hidden @xl:block' : '';
666
+
667
+ const sum = (list = []) => list.reduce((a, b) => a + b, 0);
668
+
669
+ const avg = (items = []) => (items?.length ? sum(items) / items.length : 0);
670
+
671
+ const deviation = (items) => items?.length ? Math.sqrt(Math.abs(avg(items.map((_) => _ ** 2)) - avg(items) ** 2)) : 0;
672
+
673
+ const renderBenefitIcon = (icon, benefitsVersion = 'normal') => icon ? (jsx("div", { className: style('sm:w-12 sm:h-12 sm:min-w-12 w-11 h-11 min-w-11 box-border flex items-center justify-center rounded-icon', benefitsVersion === 'normal'
674
+ ? 'bg-secondary-light text-primary-main'
675
+ : 'bg-primary-main text-black group-data-secondary:bg-white/30 group-data-secondary:text-black'), children: jsx(Img, { className: "w-6 h-6", image: { ...icon, iconVersion: icon.iconVersion || benefitsVersion } }) })) : null;
676
+
677
+ const getHtmlText = (html) => html.replace(/<\/?[^>]+\/?>/g, '').trim();
678
+
679
+ const RichText = JSX((props) => {
680
+ const { __html = '', richVersion = '' } = props;
681
+ return getHtmlText(__html) ? (jsx("div", { className: style(richVersion, 'md-container'), dangerouslySetInnerHTML: { __html } })) : null;
682
+ });
683
+
684
+ const renderBenefitDescription = (description, i) => description ? (jsx(Paragraph, { font: "font-light", size: "text-m", color: "text-secondary-text group-data-secondary:text-white", children: description }, `description-${i}`)) : null;
685
+
686
+ const Text = JSX(({ children, ...styleProps }) => (jsx("span", { className: style('font-sans', Object.values(styleProps)), children: children })));
687
+
688
+ const renderBenefitLabel = (label, i) => label ? (jsx(Text, { color: "text-primary-text group-data-secondary:text-white", size: "text-h6", children: label }, `label-${i}`)) : null;
689
+
690
+ const renderBenefitText = (_, i) => _.type === 'rte' && '__html' in _ && _.__html ? (jsx(RichText, { ..._ }, `rte-${i}`)) : ([
691
+ 'label' in _ ? renderBenefitLabel(_.label, i) : null,
692
+ 'description' in _ ? (jsx("span", { className: _.descriptionClassName, children: renderBenefitDescription(_.description, i) }, String(i))) : null,
693
+ ]);
694
+
695
+ const BenefitItem = JSX(({ className, benefitsVersion, ..._ }) => (jsxs("div", { className: style('flex gap-m min-w-56 items-center', className), children: ['icon' in _ ? renderBenefitIcon(_.icon, benefitsVersion) : null, jsx("div", { children: renderBenefitText(_) })] })));
696
+
697
+ const MAX_BENEFITS_LEN_DEVIATION = 16;
698
+ const benefitLength = (_) => _.type === 'rte'
699
+ ? _?.__html?.length || 0
700
+ : Math.max(_?.label?.length || 0, _?.description?.length || 0);
701
+ const isDistortedBenefits = (benefits) => deviation(benefits.map(benefitLength)) > MAX_BENEFITS_LEN_DEVIATION;
702
+ const hasIcon = (_) => _ && 'icon' in _ && _.icon && (_.icon.icon || _.icon.src);
703
+ const isTextualBenefits = (benefits) => !benefits.some(hasIcon);
704
+ const DefaultBenefitsList = JSX(({ className, benefitsVersion = 'normal', benefits }) => benefits?.length ? (jsx("div", { className: style('flex gap-x-m gap-y-s', isDistortedBenefits(benefits) || isTextualBenefits(benefits) ? 'flex-col' : 'flex-wrap', className), children: benefits.map((_, i) => (jsx(BenefitItem, { benefitsVersion: benefitsVersion, ..._ }, String(i)))) })) : null);
705
+
706
+ const TabularBenefitsList = JSX(({ className, benefits }) => benefits?.length ? (jsx("div", { className: style('grid grid-cols-[max-content_1fr] auto-rows-auto items-baseline gap-x-m gap-y-xs', className), children: benefits.flatMap(renderBenefitText) })) : null);
707
+
708
+ const BenefitsList = JSX(({ isTabularBenefits, ...rest }) => isTabularBenefits ? jsx(TabularBenefitsList, { ...rest }) : jsx(DefaultBenefitsList, { ...rest }));
709
+
710
+ const isIcon = (icon) => Boolean(icon?.src || icon?.icon);
711
+
712
+ const renderButtonsSection = (buttons, { className, buttonClassName, isVertical } = {}) => buttons?.length && buttons.some((_) => _?.text || _?.icon?.icon) ? (jsx("div", { className: style('flex', isVertical
713
+ ? 'flex-col gap-xs justify-items-stretch'
714
+ : 'flex-wrap @xl:flex-nowrap gap-lg sm:gap-m', className), children: buttons.map(renderButton(buttonClassName)) })) : null;
715
+ const renderButton = (buttonClassName = '') => (button, index) => {
716
+ const { text, icon, iconRight, version, ...rest } = button || {};
717
+ const iconVersion = getIconVersion(icon, version);
718
+ const iconRightVersion = getIconVersion(iconRight, version);
719
+ return text || icon?.icon ? (jsx(Button, { className: style('basis-full @lg:basis-auto', buttonClassName), appendLeft: renderButtonIcon({ ...icon, iconVersion }), appendRight: renderButtonIcon({ ...iconRight, iconVersion: iconRightVersion }), version: version, text: text, ...rest }, index ? String(index) : '')) : null;
720
+ };
721
+ const DEFAULT_ICON_W = 24;
722
+ const getIconVersion = (icon, version = 'secondary') => {
723
+ const iconVersionDefault = version === 'secondary' ? 'color' : 'white';
724
+ return icon?.iconVersion ? icon?.iconVersion : iconVersionDefault;
725
+ };
726
+ const renderButtonIcon = (icon) => isIcon(icon) ? (jsx(Img, { image: icon, width: String(icon?.size?.width || DEFAULT_ICON_W), height: String(DEFAULT_ICON_W) })) : null;
727
+
728
+ const DOT_SIZE_MAP = {
729
+ L: 'w-1.5 h-1.5 mr-m',
730
+ M: 'w-1.5 h-1.5 mr-s',
731
+ S: 'w-1 h-1 mr-xs',
732
+ XS: 'w-1 h-1 mr-xs',
733
+ };
734
+ const ListItem = JSX(({ className, isDotted, children, size = 'M' }) => (jsxs("div", { className: style('font-sans flex', className), role: "listitem", children: [isDotted ? (jsx("div", { className: "shrink-0", children: jsx("div", { className: style('align-middle inline-block rounded-full bg-primary-text group-data-secondary:bg-white', DOT_SIZE_MAP[size]) }) })) : null, jsx("span", { children: children })] })));
735
+
736
+ const TEXT_SIZE_MAP = {
737
+ XS: 'text-m font-light',
738
+ S: 'text-l font-light',
739
+ M: 'text-h6',
740
+ L: 'text-h5',
741
+ };
742
+ const ITEM_INDENT_MAP = {
743
+ XS: 'ml-2xs',
744
+ S: 'ml-xs',
745
+ M: 'ml-s',
746
+ L: 'ml-m',
747
+ };
748
+ const List = JSX(({ className, hasIndent, isDotted = true, items = [], listItemSize = 'M' }) => items?.length ? (jsx("section", { className: style('flex flex-col gap-xs text-left text-primary-text group-data-secondary:text-white group-data-gray:text-secondary-text', TEXT_SIZE_MAP[listItemSize], hasIndent ? ITEM_INDENT_MAP[listItemSize] : '', className), role: "list", children: items.map((item, i) => (jsx(ListItem, { isDotted: isDotted, size: listItemSize, children: item }, String(i)))) })) : null);
749
+
750
+ const toLocalNumberFormat = (fractionDigits = 0) => (_ = 0) => new Intl.NumberFormat('ru-RU', {
751
+ minimumFractionDigits: 0,
752
+ maximumFractionDigits: fractionDigits,
753
+ }).format(Number(_) || 0);
754
+
755
+ const PriceList = JSX(({ priceList }) => priceList?.length ? (jsx("div", { className: "flex flex-wrap xl:flex-nowrap xl:bg-main-divider xl:rounded-md p-xs gap-xl", children: priceList.map(renderPriceListItem) })) : null);
756
+ const renderPriceListItem = ({ label, amount }) => (jsxs("div", { className: "basis-full flex flex-col-reverse sm:flex-row sm:justify-between sm:bg-main-divider sm:py-m sm:px-lg sm:rounded-md items-baseline whitespace-pre", children: [jsx(Text, { font: "font-light", size: "text-l", color: "text-secondary-text", children: label }), amount ? (jsxs("span", { className: "font-sans text-h6 sm:text-primary-main text-primary-text", children: [toLocalNumberFormat(2)(amount), " \u20BD"] })) : null] }));
757
+
758
+ const Tags = JSX(({ className, tags }) => tags?.length ? (jsx("div", { className: style('flex flex-wrap gap-xs', className), role: "list", children: tags.map(renderTag) })) : null);
759
+ const renderTag = (tag, key) => (jsx("div", { className: "p-xs border-solid border rounded-md border-gray", role: "listitem", children: jsx(Text, { size: "text-m", font: "font-light", children: tag }) }, String(key)));
760
+
761
+ const BaseProductTile = JSX(
762
+ // eslint-disable-next-line max-lines-per-function
763
+ ({ className, padding, defaultPadding, title, description, headlineVersion = 'L', align = 'text-left', benefitsVersion, isTabularBenefits, benefits, __html, isFullWidthTitle, items, isDotted = true, priceList = [], listItemSize, tags = [], buttons, image, imageOptions: { imageAlign = 'center', directionRight = true, isImageAlwaysOnRight, isImageSecondary = false, } = {}, backwardButton, children, ...rest }) => {
764
+ const img = image?.src ? jsx(Img, { image: image }) : null;
765
+ const headline = (jsx(Headline, { title: title, description: description, headlineVersion: headlineVersion, align: align, isEmbedded: true }));
766
+ const filteredBenefits = benefits?.filter((_) => _?.type === 'rte' || 'label' in _ || 'description' in _);
767
+ return (jsx(BaseTile, { className: className, padding: padding, defaultPadding: defaultPadding, ...(isFullWidthTitle ? { title: headline } : { insetTitle: headline }), ...leftOrRightImage(img, directionRight), isImageSecondary: isImageSecondary, imageAlign: imageAlign, isImageAlwaysOnRight: isImageAlwaysOnRight, buttons: renderButtonsSection(buttons), backwardButton: backwardButton, ...rest, children: jsxs("div", { className: "flex flex-col sm:gap-xl gap-4xl", children: [filteredBenefits?.length ? (jsx(BenefitsList, { benefitsVersion: benefitsVersion, isTabularBenefits: isTabularBenefits, benefits: filteredBenefits })) : null, __html ? jsx(RichText, { __html: __html }) : null, items?.length ? (jsx(List, { items: items, isDotted: isDotted, listItemSize: listItemSize })) : null, children, priceList?.length ? jsx(PriceList, { priceList: priceList }) : null, renderTags(tags)] }) }));
768
+ });
769
+ const leftOrRightImage = (img, directionRight) => directionRight ? { rightImage: img } : { leftImage: img };
770
+ const renderTags = (tags) => (tags?.length ? jsx(Tags, { tags: tags }) : null);
771
+
772
+ const getBorderStyle$1 = (showBorder) => showBorder
773
+ ? 'border border-solid border-gray group-data-secondary:border-white/50 group-data-gray:border-main-divider'
774
+ : '';
775
+
776
+ const ProductBlock = JSX(({ className, padding, showBorder, ...rest }) => (jsx(BlockWrapper, { className: style('overflow-hidden flex flex-col gap-3xl box-border', getBorderStyle$1(showBorder), className), padding: "p-0", ...rest, children: jsx(BaseProductTile, { defaultPadding: "p-6xl", padding: padding, className: "grow h-full", ...rest }) })));
777
+
778
+ const isFilled = (_) => _ !== null && _ !== undefined;
779
+
780
+ const defaultCache = new Map();
781
+ const applyCache = (fetcher, cache = defaultCache) => (key) => {
782
+ const cachedData = cache.get(key);
783
+ if (isFilled(cachedData)) {
784
+ return cachedData;
785
+ }
786
+ const data = fetcher(key);
787
+ if (isFilled(data)) {
788
+ cache.set(key, Promise.resolve(data));
789
+ }
790
+ else {
791
+ cache.delete(key);
792
+ }
793
+ return data;
794
+ };
795
+
796
+ const isSimpleKey = (args) => Boolean(args && Array.isArray(args) && args.length === 1 && typeof args[0] === 'string');
797
+ function useAsyncData(key, fetcher, { fallback, cache } = {}) {
798
+ const args = useMemo(() => keyToArgs(key), [key]);
799
+ const [simpleKey] = isSimpleKey(args) ? args : [];
800
+ const [data, setData] = useState(undefined);
801
+ const [error, setError] = useState(undefined);
802
+ useEffect(() => {
803
+ const isEmptyKey = !args.some(isFilled);
804
+ if (isEmptyKey) {
805
+ return;
806
+ }
807
+ let canceled = false;
808
+ const setResult = (newData, err) => {
809
+ if (!canceled) {
810
+ setData(newData);
811
+ setError(err);
812
+ }
813
+ };
814
+ (async () => {
815
+ try {
816
+ setResult(await (simpleKey ? applyCache(fetcher, cache)(simpleKey) : fetcher(...args)));
817
+ }
818
+ catch (err) {
819
+ setResult(undefined, err);
820
+ }
821
+ })();
822
+ return () => {
823
+ canceled = true;
824
+ };
825
+ }, [fetcher, cache, args]);
826
+ const fallbackData = fallback && simpleKey && fallback[simpleKey];
827
+ return {
828
+ data: !data && fallbackData ? fallbackData : data,
829
+ error,
830
+ mutate: () => Promise.resolve(undefined) // TODO Clean up cache
831
+ };
832
+ }
833
+ function keyToArgs(key) {
834
+ if (Array.isArray(key)) {
835
+ return key;
836
+ }
837
+ else if (key instanceof Function) {
838
+ return keyToArgs(key());
839
+ }
840
+ else {
841
+ return [key];
842
+ }
843
+ }
844
+
845
+ async function fetchJSON(url, options) {
846
+ try {
847
+ return url ? await fetchJSONUnsafe(url, options) : null;
848
+ }
849
+ catch (err) {
850
+ console.error(err);
851
+ }
852
+ return null;
853
+ }
854
+ async function fetchJSONUnsafe(url, options) {
855
+ const response = await fetch(url, {
856
+ ...options,
857
+ headers: {
858
+ ...options?.headers,
859
+ 'Content-Type': 'application/json',
860
+ },
861
+ });
862
+ return response.json();
863
+ }
864
+
865
+ const EMPTY_VALUE$5 = {};
866
+ const DEFAULT_FOLDER_NAME = 'wcms-resources';
867
+ function useSWRResource(filename, options = {}) {
868
+ const { fallback = EMPTY_VALUE$5, folderName = DEFAULT_FOLDER_NAME, setBasePath = false } = options;
869
+ const path = joinPath('/', setBasePath ? projectSettings.BASE_PATH : '', folderName, `${filename}.json`);
870
+ const { data } = useAsyncData(filename ? path : null, fetchJSONUnsafe, {
871
+ fallback,
872
+ });
873
+ return data || EMPTY_VALUE$5;
874
+ }
875
+
876
+ const useAdTile = (sourceBook = 'reklamnaya-plitka') => {
877
+ const data = useSWRResource(sourceBook);
878
+ const tileIndex = useMemo(() => randomNumInRange(0, data?.items?.length), [data]);
879
+ return data?.items?.[tileIndex];
880
+ };
881
+ const randomNumInRange = (min = 0, max = 0) => Math.floor(Math.random() * (max - min) + min);
882
+
883
+ const AdTile = JSX((props) => {
884
+ const content = useAdTile(props.options?.page?.adSourceBook);
885
+ return content ? (jsx(ClientOnly, { children: jsx(ProductBlock, { ...content, ...props }) })) : null;
886
+ });
887
+
888
+ function LeadServiceAPI() {
889
+ async function send(body, isIndividualType) {
890
+ const url = isIndividualType ? '/api/v1/lead' : '/api/v1/sendcorporatelead';
891
+ try {
892
+ const response = await fetch(url, {
893
+ method: 'POST',
894
+ headers: { 'Content-Type': 'application/json' },
895
+ mode: 'cors',
896
+ body: JSON.stringify(body),
897
+ });
898
+ if (!response?.ok) {
899
+ return null;
900
+ }
901
+ const data = await response.json();
902
+ return data;
903
+ }
904
+ catch (e) {
905
+ return null;
906
+ }
907
+ }
908
+ return {
909
+ send,
910
+ };
911
+ }
912
+
913
+ const identity = (_) => _;
914
+
915
+ const useForm = (initialState, onSubmit) => {
916
+ const [formState, setFormState] = useState(initialState);
917
+ const [isDirtyForm, setDirtyForm] = useState(false);
918
+ const [dirtyFieldsMap, setDirtyFieldsMap] = useState({});
919
+ const handlersMap = useRef({});
920
+ const field = useCallback((fieldName, options) => {
921
+ const { parse = identity, format = identity } = options || {};
922
+ if (!handlersMap.current) {
923
+ handlersMap.current = {};
924
+ }
925
+ handlersMap.current[fieldName] ||= (value) => {
926
+ setFormState((prev) => ({ ...prev, [fieldName]: parse(value) }));
927
+ setDirtyFieldsMap((prev) => ({ ...prev, [fieldName]: true }));
928
+ };
929
+ return {
930
+ value: format(formState[fieldName]),
931
+ isDirty: isDirtyForm || dirtyFieldsMap[fieldName],
932
+ onChange: handlersMap.current[fieldName],
933
+ };
934
+ }, [formState, isDirtyForm, dirtyFieldsMap]);
935
+ const update = useCallback((_) => {
936
+ setFormState(_);
937
+ setDirtyFieldsMap(_);
938
+ }, []);
939
+ const reset = useCallback(() => {
940
+ setFormState(initialState);
941
+ setDirtyForm(false);
942
+ setDirtyFieldsMap({});
943
+ }, [initialState]);
944
+ const handleSubmit = useCallback((e) => {
945
+ e.preventDefault();
946
+ setDirtyForm(true);
947
+ onSubmit && onSubmit(formState);
948
+ }, [onSubmit, formState]);
949
+ return [
950
+ formState,
951
+ {
952
+ isDirty: isDirtyForm || Object.values(dirtyFieldsMap).some(Boolean),
953
+ field,
954
+ update,
955
+ reset,
956
+ onSubmit: handleSubmit,
957
+ },
958
+ ];
959
+ };
960
+
961
+ const objectValidator = (validatorsMap) => (o) => (o &&
962
+ Object.entries(validatorsMap).flatMap(([key, validator]) => validator(o[key]))) ||
963
+ [];
704
964
 
705
- const Paragraph = JSX(({ children, ...styleProps }) => (jsx("p", { className: style('font-sans', Object.values(styleProps)), children: children })));
965
+ const isValidationSuccess = (info) => !info?.length;
966
+ const validator = (predicate) => (message) => (_) => predicate(_) ? [] : [message];
706
967
 
707
- const Text = JSX(({ children, ...styleProps }) => (jsx("span", { className: style('font-sans', Object.values(styleProps)), children: children })));
968
+ const REGIONS_URL$1 = '/api/v1/regions';
969
+ const EMPTY_VALUE$4 = [];
970
+ function useGetRegions() {
971
+ const { data } = useAsyncData(REGIONS_URL$1, fetchJSONUnsafe);
972
+ return data || EMPTY_VALUE$4;
973
+ }
708
974
 
709
975
  const Footnote = JSX(({ text, link }) => (jsxs(Paragraph, { size: "text-s", font: "font-light", color: "text-secondary-text", children: [jsx(Text, { children: text || 'Нажимая кнопку, вы подтверждаете согласие с ' }), link ? (jsx(Button, { href: link.href, ariaLabel: "\u0443\u0441\u043B\u043E\u0432\u0438\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043D\u043D\u044B\u0445", target: link.target, className: "text-primary-main", children: jsx(Text, { children: link.text }) })) : null] })));
710
976
 
@@ -796,31 +1062,6 @@
796
1062
  return [value, { setValue, setTrue, setFalse, toggle }];
797
1063
  }
798
1064
 
799
- const isOnlyDigits = (str) => str && !/\D/.test(str);
800
-
801
- const svgUseStyleMap = {
802
- normal: '',
803
- color: 'text-primary-main',
804
- black: 'text-black',
805
- white: 'text-black',
806
- };
807
- const Icon = JSX(({ className = '', imageClassName = '', name = '', alt = `Иконка ${name}`, title = alt, iconVersion = 'color', width, height, }) => {
808
- const router = useRouter();
809
- const href = adjustHref(router)(joinPath(projectSettings.CDN, '/icons', `${name}.svg`));
810
- if (iconVersion !== 'normal') {
811
- return (jsx(Background, { className: className, children: jsxs("svg", { className: style(getSvgSize(width), svgUseStyleMap[iconVersion], iconVersion === 'white' ? 'invert' : '', imageClassName), width: width, height: height, "aria-hidden": "true", children: [title ? jsx("title", { children: title }) : null, alt ? jsx("desc", { children: alt }) : null, jsx("use", { href: `${href}#icon`, xlinkHref: `${href}#icon` })] }) }));
812
- }
813
- return (jsx("img", { className: className, src: href, alt: alt, title: title, "aria-hidden": "true", width: width, height: height, style: getInlineStyle(className, height) }));
814
- });
815
- const getInlineStyle = (className, height) => {
816
- if (className?.includes('h-')) {
817
- return {};
818
- }
819
- return { height: isOnlyDigits(height) ? `${height}px` : height, width: 'auto' };
820
- };
821
- const getSvgSize = (width) => (width ? '' : 'w-full h-full');
822
- const Background = JSX(({ className, children }) => className ? jsx("div", { className: className, children: children }) : children);
823
-
824
1065
  const formatOption = (_) => _?.text || _?.key || '';
825
1066
 
826
1067
  function useEventListener(target, type, listener, options) {
@@ -909,11 +1150,11 @@
909
1150
  onClose: handleClose,
910
1151
  iconVersion,
911
1152
  });
912
- return (jsxs("div", { className: className, children: [renderLabel(label), jsxs("div", { className: style('relative', isOpen ? 'z-20' : 'z-10'), ref: inputRef, children: [jsxs("div", { className: style('h-14 text-l flex justify-between items-center text-primary-text cursor-pointer relative z-10', getBorderStyle$1(isBorder, valid)), onClick: isOpen ? handleClose : open, children: [jsx("p", { className: "p-m pr-3xl flex items-center overflow-hidden text-ellipsis whitespace-nowrap", children: formatOption(value) || placeholder }), renderIcon$1(isOpen, iconVersion)] }), isSearch && isOpen ? (jsx("div", { className: style('absolute top-0 w-full z-20'), children: jsx(Input, { type: "text", autoFocus: true, value: query, onChange: setQuery }) })) : null] })] }));
1153
+ return (jsxs("div", { className: className, children: [renderLabel(label), jsxs("div", { className: style('relative', isOpen ? 'z-20' : 'z-10'), ref: inputRef, children: [jsxs("div", { className: style('h-14 text-l flex justify-between items-center text-primary-text cursor-pointer relative z-10', getBorderStyle(isBorder, valid)), onClick: isOpen ? handleClose : open, children: [jsx("p", { className: "p-m pr-3xl flex items-center overflow-hidden text-ellipsis whitespace-nowrap", children: formatOption(value) || placeholder }), renderIcon$1(isOpen, iconVersion)] }), isSearch && isOpen ? (jsx("div", { className: style('absolute top-0 w-full z-20'), children: jsx(Input, { type: "text", autoFocus: true, value: query, onChange: setQuery }) })) : null] })] }));
913
1154
  });
914
1155
  const renderLabel = (label) => label ? (jsx("div", { className: "mb-xs", children: jsx(Text, { size: "text-m", color: "text-primary-text", font: "font-light", children: label }) })) : null;
915
1156
  const renderIcon$1 = (isOpen, iconVersion) => (jsx(Icon, { className: style('absolute right-3', isOpen ? '' : 'rotate-180'), iconVersion: iconVersion, name: "ArrowUpIcon", width: "16", height: "16" }));
916
- const getBorderStyle$1 = (isBorder, valid) => style(isBorder ? 'border rounded-md hover:border-primary-hover' : '', valid ? ' border-gray' : 'border-error');
1157
+ const getBorderStyle = (isBorder, valid) => style(isBorder ? 'border rounded-md hover:border-primary-hover' : '', valid ? ' border-gray' : 'border-error');
917
1158
 
918
1159
  const SelectControl = JSX(({ className = '', error, ...rest }) => (jsxs("div", { className: className, children: [jsx(Select, { ...rest, valid: !error }), jsx("div", { className: "h-2", children: error ? (jsx(Text, { size: "text-xs", font: "font-light", color: "text-error", children: error })) : null })] })));
919
1160
 
@@ -1005,14 +1246,14 @@
1005
1246
  });
1006
1247
 
1007
1248
  const BRANCHES_URL = '/api/v1/branches';
1008
- const EMPTY_VALUE$4 = [];
1249
+ const EMPTY_VALUE$3 = [];
1009
1250
  function useBranches(regionCode) {
1010
1251
  const { data } = useAsyncData(regionCode ? `${BRANCHES_URL}?regionCode=${regionCode}` : null, fetchSafeBoxes$1);
1011
- return data || EMPTY_VALUE$4;
1252
+ return data || EMPTY_VALUE$3;
1012
1253
  }
1013
1254
  const fetchSafeBoxes$1 = async (url) => {
1014
1255
  const result = await fetchJSON(url, { method: 'GET' });
1015
- return result || EMPTY_VALUE$4;
1256
+ return result || EMPTY_VALUE$3;
1016
1257
  };
1017
1258
 
1018
1259
  const MIN_CREDIT_AMOUNT = 1000;
@@ -1045,11 +1286,6 @@
1045
1286
 
1046
1287
  const clamp = (value, min, max) => Math.max(min, Math.min(value, max));
1047
1288
 
1048
- const toLocalNumberFormat = (fractionDigits = 0) => (_ = 0) => new Intl.NumberFormat('ru-RU', {
1049
- minimumFractionDigits: 0,
1050
- maximumFractionDigits: fractionDigits,
1051
- }).format(Number(_) || 0);
1052
-
1053
1289
  function parseDecimal(value) {
1054
1290
  const rawValue = (value || '').replace(/\D/g, '');
1055
1291
  const unsafeDecimal = parseInt(rawValue, 10);
@@ -1157,17 +1393,6 @@
1157
1393
  return (jsxs("form", { className: "container", onSubmit: formProps.onSubmit, children: [jsx(Heading, { headingType: "h6", title: "\u041E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u0437\u0430\u044F\u0432\u043A\u0443 \u0438 \u043C\u044B \u043E\u0442\u0432\u0435\u0442\u0438\u043C \u043D\u0430 \u043B\u044E\u0431\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u043F\u043E \u0434\u0435\u043F\u043E\u0437\u0438\u0442\u0430\u043C", className: "@xl:text-center mb-m" }), jsxs("div", { className: "max-w-[560px] m-auto space-y-s", children: [jsx(InputControl, { className: "shrink-0 w-full", label: "\u0418\u043C\u044F", ...withValidator(field('name'), nameValidator) }), jsx(PhoneInputControl, { className: "shrink-0 w-full", label: "\u0422\u0435\u043B\u0435\u0444\u043E\u043D", ...withValidator(field('phone'), phoneValidator) })] }), jsxs("div", { className: "flex justify-between flex-col-reverse @xl:items-center @xl:flex-row max-w-[560px] m-auto", children: [jsx("div", { className: "flex-1", children: jsx(Footnote, { link: link }) }), renderSubmitButton(button)] })] }));
1158
1394
  });
1159
1395
 
1160
- const EMPTY_VALUE$3 = {};
1161
- const DEFAULT_FOLDER_NAME = 'wcms-resources';
1162
- function useSWRResource(filename, options = {}) {
1163
- const { fallback = EMPTY_VALUE$3, folderName = DEFAULT_FOLDER_NAME, setBasePath = false } = options;
1164
- const path = joinPath('/', setBasePath ? projectSettings.BASE_PATH : '', folderName, `${filename}.json`);
1165
- const { data } = useAsyncData(filename ? path : null, fetchJSONUnsafe, {
1166
- fallback,
1167
- });
1168
- return data || EMPTY_VALUE$3;
1169
- }
1170
-
1171
1396
  const ApplicationFormGrantSupport = JSX((props) => {
1172
1397
  const { button, sourceBookDir } = props;
1173
1398
  const { regions } = useSWRResource(sourceBookDir || 'regions-grant-support');
@@ -1403,32 +1628,6 @@
1403
1628
  return (jsxs("form", { className: "container space-y-s", onSubmit: formProps.onSubmit, children: [renderIndividualsFields(field), jsxs("div", { className: "@xl:flex justify-between items-center", children: [jsxs("div", { className: "@xl:mb-0 mb-2 flex items-center gap-3", children: [jsx(Checkbox, { ...withValidator(field('consentDataProcessing'), defaultValidator) }), jsx(Footnote, { text: "\u0421\u043E\u0433\u043B\u0430\u0441\u0435\u043D \u0441 ", link: link })] }), renderSubmitButton(button)] })] }));
1404
1629
  });
1405
1630
 
1406
- const sourcesComparator = (a, b) => a?.media && b?.media ? a.media - b.media : 0;
1407
- const ImgAsPicture = JSX(({ className = '', image, imageClassName = '', pathPrefix }) => {
1408
- const router = useRouter();
1409
- return (jsxs("picture", { className: className, children: [image?.sources?.length
1410
- ? image.sources
1411
- .filter((_) => _?.src)
1412
- .sort(sourcesComparator)
1413
- .map(({ src, format, media }, index) => (jsx("source", { srcSet: adjustSrc(router, pathPrefix)(src), type: formatToMimeType(format), media: media ? `(max-width: ${media}px)` : '', width: image.size?.width, height: image.size?.height }, `${index}_${src}`)))
1414
- : null, image?.src
1415
- ? renderImg({ ...image, src: adjustSrc(router, pathPrefix)(image.src) }, imageClassName)
1416
- : null] }));
1417
- });
1418
- const renderImg = (image, imageClassName = '') => (jsx("img", { src: image.src, className: style('object-contain', imageClassName), alt: image.alt || image.title, title: image.title || '', style: {
1419
- width: image.size?.width ? `${image.size?.width}px` : '100%',
1420
- height: image.size?.height ? `${image.size?.height}px` : 'auto',
1421
- }, width: image.size?.width, height: image.size?.height }));
1422
- const adjustSrc = (router, pathPrefix) => (src) => src && !isURL(src) ? adjustHref(router)(joinPath(pathPrefix, src)) : src;
1423
- const formatToMimeType = (format) => format ? `image/${String(format)}` : undefined;
1424
-
1425
- const Img = JSX(({ className = '', image, imageClassName = '', pathPrefix, ...iconProps }) => {
1426
- if (!image?.src && !image?.icon) {
1427
- return null;
1428
- }
1429
- return image.icon ? (jsx(Icon, { className: className, imageClassName: imageClassName, iconVersion: image?.iconVersion, name: image.icon, ...iconProps })) : (jsx(ImgAsPicture, { className: className, imageClassName: imageClassName, image: image, pathPrefix: pathPrefix }));
1430
- });
1431
-
1432
1631
  const renderContacts = () => (jsxs("div", { className: "flex gap-xl", children: [jsxs("a", { className: "flex gap-s items-center text-primary-text no-underline", href: `tel:8 (800) 200-78-70`, "aria-label": "8 (800) 200-78-70", children: [jsx(Img, { image: { icon: 'PhoneIcon' }, width: "24", height: "24" }), jsx("span", { children: "8 (800) 200-78-70" })] }), jsxs("a", { className: "flex gap-s items-center text-primary-text no-underline", "aria-label": "ved@rshb.ru", href: `mailto:ved@rshb.ru`, children: [jsx(Img, { image: { icon: 'MailIcon' }, width: "24", height: "24" }), jsx("span", { children: "ved@rshb.ru" })] })] }));
1433
1632
 
1434
1633
  const Radio = JSX(({ name, text, value, checked, onChange, className }) => (jsx("div", { className: className, children: jsxs("label", { className: "font-sans flex gap-s items-center relative cursor-pointer", children: [jsx("input", { className: "appearance-none flex justify-center items-center shrink-0 w-5 h-5 border border-gray hover:border-primary-hover\n checked:border-2 checked:!border-primary-main focus:checked:border-primary-main focus:border-primary-text active:border-primary-text\n after:block after:w-2.5 after:h-2.5 after:rounded-full checked:after:bg-primary-main outline-none rounded-full cursor-pointer", type: "radio", value: value, name: name, checked: checked, onChange: (_) => onChange(_.target.value) }), text ? jsx(Text, { color: "text-primary-text", children: text }) : null] }) })));
@@ -1514,145 +1713,60 @@
1514
1713
  const responseOK = responseType === 'OK';
1515
1714
  const backgroundColor = responseOK ? 'bg-ok' : 'bg-fail';
1516
1715
  return (jsxs("div", { className: `flex items-center p-lg rounded-md space-x-m ${backgroundColor}`, children: [responseOK ? (jsx(Img, { image: { icon: 'ResponseOKIcon' }, width: "42", height: "42" })) : (jsx(Img, { image: { icon: 'ResponseFailIcon' }, width: "37", height: "34" })), jsxs("div", { children: [jsx(Heading, { headingType: "h6", title: responseOK ? 'Ваша заявка отправлена' : 'Не удалось отправить заявку', className: "mb-2xs" }), jsx(Text, { size: "text-l", font: "font-light", color: "text-secondary-text", children: responseOK ? 'Совсем скоро мы с вами свяжемся' : 'Пожалуйста, повторите позднее' })] })] }));
1517
- });
1518
-
1519
- const API = LeadServiceAPI();
1520
- const ApplicationForm = JSX((props) => {
1521
- const { className, formBlock, ...rest } = props;
1522
- const [responseType, setResponseType] = useState('');
1523
- const handleSubmit = useCallback(async (data, isIndividualType) => {
1524
- const status = (await API.send(data, isIndividualType)) ? 'OK' : 'Fail';
1525
- setResponseType(status);
1526
- return status;
1527
- }, []);
1528
- return (jsx(BlockWrapper, { className: className, defaultPadding: "p-6xl", ...rest, children: jsxs("div", { className: "container max-w-[978px] space-y-lg", children: [formBlock?.title ? (jsx(Heading, { headingType: "h3", title: formBlock.title, className: "@xl:text-center" })) : null, formBlock ? renderEmbeddedForm(formBlock, handleSubmit) : null, responseType ? jsx(ResponseNotification, { responseType: responseType }) : null] }) }));
1529
- });
1530
- const renderEmbeddedForm = (formBlock, handleSubmit) => {
1531
- const type = formBlock?.formType;
1532
- if (!type || !(type in EmbeddableForms)) {
1533
- return null;
1534
- }
1535
- const EmbeddedForm = EmbeddableForms[type];
1536
- return jsx(EmbeddedForm, { ...formBlock, onSubmit: handleSubmit });
1537
- };
1538
-
1539
- const AlignStyles = 'text-center';
1540
-
1541
- const iconBgStyles = {
1542
- '': 'bg-main-divider group-data-secondary:bg-white/30',
1543
- primary: 'bg-main-divider',
1544
- secondary: 'bg-secondary-light',
1545
- opacity: 'bg-white/30',
1546
- };
1547
- const RoundedIcon = JSX(({ className, defaultIconSize = 44, iconBgVersion = 'primary', size, icon, ...rest }) => {
1548
- const widthAndHeight = String(size?.width || defaultIconSize);
1549
- return icon ? (jsx("div", { style: {
1550
- width: `${widthAndHeight}px`,
1551
- height: `${widthAndHeight}px`,
1552
- }, className: style('rounded-icon object-fit flex justify-center items-center', iconBgStyles[iconBgVersion], className), children: jsx(Icon, { ...rest, width: "54%", height: "54%", name: icon }) })) : null;
1553
- });
1554
-
1555
- const DOT_SIZE_MAP = {
1556
- L: 'w-1.5 h-1.5 mr-m',
1557
- M: 'w-1.5 h-1.5 mr-s',
1558
- S: 'w-1 h-1 mr-xs',
1559
- XS: 'w-1 h-1 mr-xs',
1560
- };
1561
- const ListItem = JSX(({ className, isDotted, children, size = 'M' }) => (jsxs("div", { className: style('font-sans flex', className), role: "listitem", children: [isDotted ? (jsx("div", { className: "shrink-0", children: jsx("div", { className: style('align-middle inline-block rounded-full bg-primary-text group-data-secondary:bg-white', DOT_SIZE_MAP[size]) }) })) : null, jsx("span", { children: children })] })));
1562
-
1563
- const TEXT_SIZE_MAP = {
1564
- XS: 'text-m font-light',
1565
- S: 'text-l font-light',
1566
- M: 'text-h6',
1567
- L: 'text-h5',
1568
- };
1569
- const ITEM_INDENT_MAP = {
1570
- XS: 'ml-2xs',
1571
- S: 'ml-xs',
1572
- M: 'ml-s',
1573
- L: 'ml-m',
1574
- };
1575
- const List = JSX(({ className, hasIndent, isDotted = true, items = [], listItemSize = 'M' }) => items?.length ? (jsx("section", { className: style('flex flex-col gap-xs text-left text-primary-text group-data-secondary:text-white group-data-gray:text-secondary-text', TEXT_SIZE_MAP[listItemSize], hasIndent ? ITEM_INDENT_MAP[listItemSize] : '', className), role: "list", children: items.map((item, i) => (jsx(ListItem, { isDotted: isDotted, size: listItemSize, children: item }, String(i)))) })) : null);
1576
-
1577
- const defaultIconSize = 44;
1578
-
1579
- const BenefitsBlock = JSX(({ className = '', title, benefitList, ...rest }) => (jsxs(BlockWrapper, { className: className, defaultPadding: "p-6xl", ...rest, children: [title ? jsx(Heading, { headingType: "h3", as: "h2", className: AlignStyles, title: title }) : null, benefitList?.length ? (jsx("div", { className: "flex flex-col @md:flex-row flex-wrap w-full @md:justify-center mt-xl gap-5xl", role: "list", children: benefitList.map(renderBenefit) })) : null] })));
1580
- const renderBenefit = (benefit, i) => (jsxs("div", { className: "flex gap-m items-center @md:basis-1/2 @md:max-w-[500px]", role: "listitem", children: [benefit?.icon?.icon ? (jsx(RoundedIcon, { className: "shrink-0", defaultIconSize: defaultIconSize, iconBgVersion: benefit?.iconBgVersion || '', ...benefit?.icon })) : null, benefit?.icon?.src ? jsx(Img, { className: "shrink-0", image: benefit.icon }) : null, benefit?.label ? (jsxs("div", { className: "@sm:h-full", children: [jsx(Heading, { headingType: "h6", children: benefit.label }), renderDescription$1(benefit.description)] })) : null] }, String(i)));
1581
- const renderDescription$1 = (description) => {
1582
- const benefitType = description?.benefitType || null;
1583
- return description && benefitType ? (jsx("div", { className: "mt-xs text-l font-light text-secondary-text group-data-secondary:text-white/80", children: benefitType === 'list'
1584
- ? renderListBenefit(description)
1585
- : renderTextBenefit(description) })) : null;
1586
- };
1587
- const renderTextBenefit = (description) => description?.name ? (jsx(Text, { size: "text-l", color: "text-secondary-text group-data-secondary:text-white/80", font: "font-light", children: description.name })) : null;
1588
- const renderListBenefit = (description) => {
1589
- const listStyleType = description?.bullets ? 'list-disc pl-3xl' : '';
1590
- return description?.items && description.items.length > 0 ? (jsx("ul", { className: style(listStyleType, description.listItemSize ? TEXT_SIZE_MAP[description.listItemSize] : ''), children: description.items.map((_, i) => (jsx("li", { children: jsx(Text, { color: "text-secondary-text group-data-secondary:text-white/80", font: "font-light", children: _ }) }, `benefitListItem-${i}`))) })) : null;
1591
- };
1592
-
1593
- const isIcon = (icon) => Boolean(icon?.src || icon?.icon);
1594
-
1595
- const renderButtonsSection = (buttons, { className, buttonClassName, isVertical } = {}) => buttons?.length && buttons.some((_) => _?.text || _?.icon?.icon) ? (jsx("div", { className: style('flex', isVertical
1596
- ? 'flex-col gap-xs justify-items-stretch'
1597
- : 'flex-wrap @xl:flex-nowrap gap-lg sm:gap-m', className), children: buttons.map(renderButton(buttonClassName)) })) : null;
1598
- const renderButton = (buttonClassName = '') => (button, index) => {
1599
- const { text, icon, iconRight, version, ...rest } = button || {};
1600
- const iconVersion = getIconVersion(icon, version);
1601
- const iconRightVersion = getIconVersion(iconRight, version);
1602
- return text || icon?.icon ? (jsx(Button, { className: style('basis-full @lg:basis-auto', buttonClassName), appendLeft: renderButtonIcon({ ...icon, iconVersion }), appendRight: renderButtonIcon({ ...iconRight, iconVersion: iconRightVersion }), version: version, text: text, ...rest }, index ? String(index) : '')) : null;
1603
- };
1604
- const DEFAULT_ICON_W = 24;
1605
- const getIconVersion = (icon, version = 'secondary') => {
1606
- const iconVersionDefault = version === 'secondary' ? 'color' : 'white';
1607
- return icon?.iconVersion ? icon?.iconVersion : iconVersionDefault;
1608
- };
1609
- const renderButtonIcon = (icon) => isIcon(icon) ? (jsx(Img, { image: icon, width: String(icon?.size?.width || DEFAULT_ICON_W), height: String(DEFAULT_ICON_W) })) : null;
1610
-
1611
- const headlineVersionStyles = {
1612
- XXL: {
1613
- title: { headingType: 'h0', as: 'h1' },
1614
- descriptionSize: 'text-h5',
1615
- descriptionWeight: 'font-normal',
1616
- descriptionStyle: 'mt-xl',
1617
- },
1618
- XL: {
1619
- title: { headingType: 'h1', as: 'h1' },
1620
- descriptionSize: 'text-xl',
1621
- descriptionWeight: 'font-light',
1622
- descriptionStyle: 'mt-m',
1623
- },
1624
- L: {
1625
- title: { headingType: 'h2', as: 'h2' },
1626
- descriptionSize: 'text-xl',
1627
- descriptionWeight: 'font-light',
1628
- descriptionStyle: 'mt-m',
1629
- },
1630
- M: {
1631
- title: { headingType: 'h3', as: 'h2' },
1632
- descriptionSize: 'text-xl',
1633
- descriptionWeight: 'font-light',
1634
- descriptionStyle: 'mt-s',
1635
- },
1636
- S: {
1637
- title: { headingType: 'h4', as: 'h2' },
1638
- descriptionSize: 'text-xl',
1639
- descriptionWeight: 'font-light',
1640
- descriptionStyle: 'mt-xs',
1641
- },
1642
- XS: {
1643
- title: { headingType: 'h5', as: 'h2' },
1644
- descriptionSize: 'text-m',
1645
- descriptionWeight: 'font-light',
1646
- descriptionStyle: 'mt-xs',
1647
- },
1716
+ });
1717
+
1718
+ const API = LeadServiceAPI();
1719
+ const ApplicationForm = JSX((props) => {
1720
+ const { className, formBlock, ...rest } = props;
1721
+ const [responseType, setResponseType] = useState('');
1722
+ const handleSubmit = useCallback(async (data, isIndividualType) => {
1723
+ const status = (await API.send(data, isIndividualType)) ? 'OK' : 'Fail';
1724
+ setResponseType(status);
1725
+ return status;
1726
+ }, []);
1727
+ return (jsx(BlockWrapper, { className: className, defaultPadding: "p-6xl", ...rest, children: jsxs("div", { className: "container max-w-[978px] space-y-lg", children: [formBlock?.title ? (jsx(Heading, { headingType: "h3", title: formBlock.title, className: "@xl:text-center" })) : null, formBlock ? renderEmbeddedForm(formBlock, handleSubmit) : null, responseType ? jsx(ResponseNotification, { responseType: responseType }) : null] }) }));
1728
+ });
1729
+ const renderEmbeddedForm = (formBlock, handleSubmit) => {
1730
+ const type = formBlock?.formType;
1731
+ if (!type || !(type in EmbeddableForms)) {
1732
+ return null;
1733
+ }
1734
+ const EmbeddedForm = EmbeddableForms[type];
1735
+ return jsx(EmbeddedForm, { ...formBlock, onSubmit: handleSubmit });
1648
1736
  };
1649
1737
 
1650
- const Headline = JSX(({ className, version = '', headlineVersion = 'XL', title, description, align = 'text-center', as, isEmbedded = false, isTheme = false, ...rest }) => {
1651
- const versionStyle = headlineVersionStyles[headlineVersion];
1652
- const descriptionStyle = { marginTop: versionStyle.descriptionStyle };
1653
- return (jsxs(BlockWrapper, { className: style(isEmbedded ? '@container-normal' : '', className), defaultPadding: isEmbedded ? '' : 'p-6xl', version: version, isTheme: isTheme, ...rest, children: [title ? (jsx(Heading, { className: style('whitespace-pre-wrap', align), ...versionStyle?.title, as: as || versionStyle?.title.as, title: title })) : null, description ? (jsx(Paragraph, { size: versionStyle.descriptionSize, font: versionStyle.descriptionWeight, align: align, ...descriptionStyle, children: description })) : null] }));
1738
+ const AlignStyles = 'text-center';
1739
+
1740
+ const iconBgStyles = {
1741
+ '': 'bg-main-divider group-data-secondary:bg-white/30',
1742
+ primary: 'bg-main-divider',
1743
+ secondary: 'bg-secondary-light',
1744
+ opacity: 'bg-white/30',
1745
+ };
1746
+ const RoundedIcon = JSX(({ className, defaultIconSize = 44, iconBgVersion = 'primary', size, icon, ...rest }) => {
1747
+ const widthAndHeight = String(size?.width || defaultIconSize);
1748
+ return icon ? (jsx("div", { style: {
1749
+ width: `${widthAndHeight}px`,
1750
+ height: `${widthAndHeight}px`,
1751
+ }, className: style('rounded-icon object-fit flex justify-center items-center', iconBgStyles[iconBgVersion], className), children: jsx(Icon, { ...rest, width: "54%", height: "54%", name: icon }) })) : null;
1654
1752
  });
1655
1753
 
1754
+ const defaultIconSize = 44;
1755
+
1756
+ const BenefitsBlock = JSX(({ className = '', title, benefitList, ...rest }) => (jsxs(BlockWrapper, { className: className, defaultPadding: "p-6xl", ...rest, children: [title ? jsx(Heading, { headingType: "h3", as: "h2", className: AlignStyles, title: title }) : null, benefitList?.length ? (jsx("div", { className: "flex flex-col @md:flex-row flex-wrap w-full @md:justify-center mt-xl gap-5xl", role: "list", children: benefitList.map(renderBenefit) })) : null] })));
1757
+ const renderBenefit = (benefit, i) => (jsxs("div", { className: "flex gap-m items-center @md:basis-1/2 @md:max-w-[500px]", role: "listitem", children: [benefit?.icon?.icon ? (jsx(RoundedIcon, { className: "shrink-0", defaultIconSize: defaultIconSize, iconBgVersion: benefit?.iconBgVersion || '', ...benefit?.icon })) : null, benefit?.icon?.src ? jsx(Img, { className: "shrink-0", image: benefit.icon }) : null, benefit?.label ? (jsxs("div", { className: "@sm:h-full", children: [jsx(Heading, { headingType: "h6", children: benefit.label }), renderDescription$1(benefit.description)] })) : null] }, String(i)));
1758
+ const renderDescription$1 = (description) => {
1759
+ const benefitType = description?.benefitType || null;
1760
+ return description && benefitType ? (jsx("div", { className: "mt-xs text-l font-light text-secondary-text group-data-secondary:text-white/80", children: benefitType === 'list'
1761
+ ? renderListBenefit(description)
1762
+ : renderTextBenefit(description) })) : null;
1763
+ };
1764
+ const renderTextBenefit = (description) => description?.name ? (jsx(Text, { size: "text-l", color: "text-secondary-text group-data-secondary:text-white/80", font: "font-light", children: description.name })) : null;
1765
+ const renderListBenefit = (description) => {
1766
+ const listStyleType = description?.bullets ? 'list-disc pl-3xl' : '';
1767
+ return description?.items && description.items.length > 0 ? (jsx("ul", { className: style(listStyleType, description.listItemSize ? TEXT_SIZE_MAP[description.listItemSize] : ''), children: description.items.map((_, i) => (jsx("li", { children: jsx(Text, { color: "text-secondary-text group-data-secondary:text-white/80", font: "font-light", children: _ }) }, `benefitListItem-${i}`))) })) : null;
1768
+ };
1769
+
1656
1770
  const Bonus = JSX(({ className = '', title, description, bonusItems = [], align = AlignStyles, ...rest }) => (jsx(BlockWrapper, { className: className, defaultPadding: "p-6xl", ...rest, children: jsxs("div", { className: "container", children: [jsx(Headline, { className: "mb-xl", isEmbedded: true, title: title, description: description, headlineVersion: "M", align: align }), jsx("div", { className: "flex flex-wrap gap-3xl gap-x-m w-full", children: bonusItems.length > 0
1657
1771
  ? bonusItems.map((_, i) => (jsxs("div", { className: "w-full @xl:w-[48%] sm:space-y-xs flex flex-col grow p-xl sm:p-m border border-gray", children: [jsx("div", { className: "grow", children: jsx(Headline, { title: _?.title, description: _?.description, headlineVersion: "S", isEmbedded: true, align: "text-left" }) }), jsxs("div", { className: "flex justify-center sm:justify-between sm:items-end", children: [jsx("div", { className: "hidden sm:block", children: renderButtonsSection(_?.buttons) }), _.bonusItemContent?.bonusType
1658
1772
  ? renderBonusItemContent(_.bonusItemContent)
@@ -2783,10 +2897,6 @@
2783
2897
  : null;
2784
2898
  }
2785
2899
 
2786
- const getBorderStyle = (showBorder) => showBorder
2787
- ? 'border border-solid border-gray group-data-secondary:border-white/50 group-data-gray:border-main-divider'
2788
- : '';
2789
-
2790
2900
  const renderCardHighlight = ({ className, text = 'ХИТ' } = {}) => (jsxs("div", { className: style('w-14 h-14 bg-white flex flex-col items-center justify-center rounded-md shadow-main-black', className), children: [jsx(Icon, { iconVersion: "black", name: "HeartIcon", width: "24", height: "24" }), jsx(Paragraph, { size: "text-s", font: "font-normal", align: "text-center", color: "text-primary-text", children: text })] }));
2791
2901
 
2792
2902
  const cardBaseStyle = 'relative h-full';
@@ -2815,7 +2925,7 @@
2815
2925
  };
2816
2926
  const cardWrapperStyle = (_, { someCardsHighlighted }) => style(cardBaseStyle, someCardsHighlighted && (isCardHighlighted(_) ? 'pt-3xl' : 'pt-3xl sm:pt-16'));
2817
2927
  const cardStyle = (_, { someCardsHighlighted, showBorder, cardSize = 'normal', }) => style(cardBaseStyle, 'min-w-80', CARD_SIZE_MAP[cardSize], // TODO fix для RecommendationCard
2818
- someCardsHighlighted && (isCardHighlighted(_) ? 'pt-3xl sm:pt-16' : 'pt-3xl'), getBorderStyle(showBorder), showBorder && 'h-full');
2928
+ someCardsHighlighted && (isCardHighlighted(_) ? 'pt-3xl sm:pt-16' : 'pt-3xl'), getBorderStyle$1(showBorder), showBorder && 'h-full');
2819
2929
  const isCardHighlighted = (_) => _?.content && 'isHighlighting' in _.content && _.content.isHighlighting;
2820
2930
 
2821
2931
  const VISIBLE_ITEM_COUNT = 1;
@@ -2870,39 +2980,6 @@
2870
2980
  isVertical: true,
2871
2981
  })] })] }) })));
2872
2982
 
2873
- function renderBackwardButton(version, handleClick) {
2874
- const iconVersion = version === 'primary' ? 'white' : 'black';
2875
- const className = 'w-12 h-12 min-h-12 min-w-12 flex items-center justify-center';
2876
- const text = 'Вернуться назад';
2877
- return (jsxs("div", { className: "hidden sm:flex items-center gap-s", children: [jsx("div", { className: getRegularButtonClasses({ className, version, rounded: true }), onClick: handleClick, children: jsx(Img, { className: "w-4 h-4", image: {
2878
- icon: 'ArrowLeftIcon',
2879
- iconVersion: iconVersion,
2880
- } }) }), jsx(Button, { version: "link", className: "group-data-secondary:text-white/80", text: text, ariaLabel: text, onClick: handleClick })] }));
2881
- }
2882
-
2883
- const imageAlignmentMap = {
2884
- start: '@xl:self-start',
2885
- center: '@xl:self-center',
2886
- end: '@xl:self-end',
2887
- };
2888
- const BaseTile = JSX(({ className, version = 'primary', defaultPadding, padding, title = '', insetTitle = '', buttons, leftImage, rightImage, imageAlign, isImageAlwaysOnRight = false, isImageSecondary = false, backwardButton, children, }) => {
2889
- const router = useRouter();
2890
- const handleClick = useCallback((ev) => {
2891
- ev?.preventDefault();
2892
- router.back();
2893
- }, []);
2894
- return (jsxs("div", { className: getStyle(padding, defaultPadding, className), children: [backwardButton ? renderBackwardButton(version, handleClick) : null, title ? jsx("div", { className: "relative", children: title }) : null, jsxs("div", { className: style('grow relative flex flex-col @xl:flex-row gap-3xl w-full', leftImage ? 'self-start @xl:w-auto' : ''), children: [renderImageContainer(leftImage, { imageAlign, className: 'mx-auto' }), jsxs("div", { className: style('grid gap-3xl h-full', rightImage ? '@xl:grid-cols-2' : '', leftImage ? '' : 'grow'), children: [jsxs("div", { className: "grow space-y-lg min-w-fit", children: [insetTitle, children] }), renderImageContainer(rightImage, {
2895
- className: style('@xl:justify-self-end @xl:col-start-2', buttons ? rowSpanStyle(isImageAlwaysOnRight) : '', positionStyle(isImageAlwaysOnRight), imageSecondaryStyle(isImageSecondary)),
2896
- imageAlign,
2897
- }), renderButtons(buttons)] })] })] }));
2898
- });
2899
- const getStyle = (padding = '', defaultPadding = '', className = '') => style('relative flex flex-col gap-3xl overflow-hidden', padding || defaultPadding, className);
2900
- const rowSpanStyle = (isImageAlwaysOnRight) => isImageAlwaysOnRight ? 'row-span-2' : '@xl:row-span-2';
2901
- const positionStyle = (isImageAlwaysOnRight) => isImageAlwaysOnRight ? 'col-start-2 self-center' : '';
2902
- const renderButtons = (buttons) => buttons ? jsx("div", { className: "self-end", children: buttons }) : null;
2903
- const renderImageContainer = (image, { className, imageAlign }) => image ? (jsx("div", { className: style('shrink-1/2 justify-self-center', imageAlign && imageAlignmentMap[imageAlign], className), children: image })) : null;
2904
- const imageSecondaryStyle = (isImageSecondary) => isImageSecondary ? 'hidden @xl:block' : '';
2905
-
2906
2983
  const cardStyleMap = {
2907
2984
  black: 'bg-black',
2908
2985
  white: 'bg-white',
@@ -2936,64 +3013,6 @@
2936
3013
  .map((link, index) => (jsx(CarouselLinkButton, { ...link }, String(index)))) }, String(groupIndex)))) }));
2937
3014
  };
2938
3015
 
2939
- const sum = (list = []) => list.reduce((a, b) => a + b, 0);
2940
-
2941
- const avg = (items = []) => (items?.length ? sum(items) / items.length : 0);
2942
-
2943
- const deviation = (items) => items?.length ? Math.sqrt(Math.abs(avg(items.map((_) => _ ** 2)) - avg(items) ** 2)) : 0;
2944
-
2945
- const renderBenefitIcon = (icon, benefitsVersion = 'normal') => icon ? (jsx("div", { className: style('sm:w-12 sm:h-12 sm:min-w-12 w-11 h-11 min-w-11 box-border flex items-center justify-center rounded-icon', benefitsVersion === 'normal'
2946
- ? 'bg-secondary-light text-primary-main'
2947
- : 'bg-primary-main text-black group-data-secondary:bg-white/30 group-data-secondary:text-black'), children: jsx(Img, { className: "w-6 h-6", image: { ...icon, iconVersion: icon.iconVersion || benefitsVersion } }) })) : null;
2948
-
2949
- const getHtmlText = (html) => html.replace(/<\/?[^>]+\/?>/g, '').trim();
2950
-
2951
- const RichText = JSX((props) => {
2952
- const { __html = '', richVersion = '' } = props;
2953
- return getHtmlText(__html) ? (jsx("div", { className: style(richVersion, 'md-container'), dangerouslySetInnerHTML: { __html } })) : null;
2954
- });
2955
-
2956
- const renderBenefitDescription = (description, i) => description ? (jsx(Paragraph, { font: "font-light", size: "text-m", color: "text-secondary-text group-data-secondary:text-white", children: description }, `description-${i}`)) : null;
2957
-
2958
- const renderBenefitLabel = (label, i) => label ? (jsx(Text, { color: "text-primary-text group-data-secondary:text-white", size: "text-h6", children: label }, `label-${i}`)) : null;
2959
-
2960
- const renderBenefitText = (_, i) => _.type === 'rte' && '__html' in _ && _.__html ? (jsx(RichText, { ..._ }, `rte-${i}`)) : ([
2961
- 'label' in _ ? renderBenefitLabel(_.label, i) : null,
2962
- 'description' in _ ? (jsx("span", { className: _.descriptionClassName, children: renderBenefitDescription(_.description, i) }, String(i))) : null,
2963
- ]);
2964
-
2965
- const BenefitItem = JSX(({ className, benefitsVersion, ..._ }) => (jsxs("div", { className: style('flex gap-m min-w-56 items-center', className), children: ['icon' in _ ? renderBenefitIcon(_.icon, benefitsVersion) : null, jsx("div", { children: renderBenefitText(_) })] })));
2966
-
2967
- const MAX_BENEFITS_LEN_DEVIATION = 16;
2968
- const benefitLength = (_) => _.type === 'rte'
2969
- ? _?.__html?.length || 0
2970
- : Math.max(_?.label?.length || 0, _?.description?.length || 0);
2971
- const isDistortedBenefits = (benefits) => deviation(benefits.map(benefitLength)) > MAX_BENEFITS_LEN_DEVIATION;
2972
- const hasIcon = (_) => _ && 'icon' in _ && _.icon && (_.icon.icon || _.icon.src);
2973
- const isTextualBenefits = (benefits) => !benefits.some(hasIcon);
2974
- const DefaultBenefitsList = JSX(({ className, benefitsVersion = 'normal', benefits }) => benefits?.length ? (jsx("div", { className: style('flex gap-x-m gap-y-s', isDistortedBenefits(benefits) || isTextualBenefits(benefits) ? 'flex-col' : 'flex-wrap', className), children: benefits.map((_, i) => (jsx(BenefitItem, { benefitsVersion: benefitsVersion, ..._ }, String(i)))) })) : null);
2975
-
2976
- const TabularBenefitsList = JSX(({ className, benefits }) => benefits?.length ? (jsx("div", { className: style('grid grid-cols-[max-content_1fr] auto-rows-auto items-baseline gap-x-m gap-y-xs', className), children: benefits.flatMap(renderBenefitText) })) : null);
2977
-
2978
- const BenefitsList = JSX(({ isTabularBenefits, ...rest }) => isTabularBenefits ? jsx(TabularBenefitsList, { ...rest }) : jsx(DefaultBenefitsList, { ...rest }));
2979
-
2980
- const PriceList = JSX(({ priceList }) => priceList?.length ? (jsx("div", { className: "flex flex-wrap xl:flex-nowrap xl:bg-main-divider xl:rounded-md p-xs gap-xl", children: priceList.map(renderPriceListItem) })) : null);
2981
- const renderPriceListItem = ({ label, amount }) => (jsxs("div", { className: "basis-full flex flex-col-reverse sm:flex-row sm:justify-between sm:bg-main-divider sm:py-m sm:px-lg sm:rounded-md items-baseline whitespace-pre", children: [jsx(Text, { font: "font-light", size: "text-l", color: "text-secondary-text", children: label }), amount ? (jsxs("span", { className: "font-sans text-h6 sm:text-primary-main text-primary-text", children: [toLocalNumberFormat(2)(amount), " \u20BD"] })) : null] }));
2982
-
2983
- const Tags = JSX(({ className, tags }) => tags?.length ? (jsx("div", { className: style('flex flex-wrap gap-xs', className), role: "list", children: tags.map(renderTag) })) : null);
2984
- const renderTag = (tag, key) => (jsx("div", { className: "p-xs border-solid border rounded-md border-gray", role: "listitem", children: jsx(Text, { size: "text-m", font: "font-light", children: tag }) }, String(key)));
2985
-
2986
- const BaseProductTile = JSX(
2987
- // eslint-disable-next-line max-lines-per-function
2988
- ({ className, padding, defaultPadding, title, description, headlineVersion = 'L', align = 'text-left', benefitsVersion, isTabularBenefits, benefits, __html, isFullWidthTitle, items, isDotted = true, priceList = [], listItemSize, tags = [], buttons, image, imageOptions: { imageAlign = 'center', directionRight = true, isImageAlwaysOnRight, isImageSecondary = false, } = {}, backwardButton, children, ...rest }) => {
2989
- const img = image?.src ? jsx(Img, { image: image }) : null;
2990
- const headline = (jsx(Headline, { title: title, description: description, headlineVersion: headlineVersion, align: align, isEmbedded: true }));
2991
- const filteredBenefits = benefits?.filter((_) => _?.type === 'rte' || 'label' in _ || 'description' in _);
2992
- return (jsx(BaseTile, { className: className, padding: padding, defaultPadding: defaultPadding, ...(isFullWidthTitle ? { title: headline } : { insetTitle: headline }), ...leftOrRightImage(img, directionRight), isImageSecondary: isImageSecondary, imageAlign: imageAlign, isImageAlwaysOnRight: isImageAlwaysOnRight, buttons: renderButtonsSection(buttons), backwardButton: backwardButton, ...rest, children: jsxs("div", { className: "flex flex-col sm:gap-xl gap-4xl", children: [filteredBenefits?.length ? (jsx(BenefitsList, { benefitsVersion: benefitsVersion, isTabularBenefits: isTabularBenefits, benefits: filteredBenefits })) : null, __html ? jsx(RichText, { __html: __html }) : null, items?.length ? (jsx(List, { items: items, isDotted: isDotted, listItemSize: listItemSize })) : null, children, priceList?.length ? jsx(PriceList, { priceList: priceList }) : null, renderTags(tags)] }) }));
2993
- });
2994
- const leftOrRightImage = (img, directionRight) => directionRight ? { rightImage: img } : { leftImage: img };
2995
- const renderTags = (tags) => (tags?.length ? jsx(Tags, { tags: tags }) : null);
2996
-
2997
3016
  const LinkWrapper = JSX(({ className = '', href, target, isRemote = false, children }) => {
2998
3017
  const link = useLink({ isRemote });
2999
3018
  const linkProps = link({ href, target });
@@ -3197,6 +3216,8 @@
3197
3216
  const renderBlocks = (info) => (jsx("div", { className: "flex gap-5xl grow basis-0", children: info.map((column, index) => renderBlocksColumn({ column, index })) }));
3198
3217
  const renderBlocksColumn = ({ column, index }) => column ? (jsx("div", { className: "flex flex-col gap-xl grow basis-0", children: column.map(({ title = '', description, additionalDescription, button }, key) => (jsxs("div", { children: [jsx(Headline, { title: title, description: description, headlineVersion: "XS", align: "text-left", isEmbedded: true }), additionalDescription ? (jsx("div", { className: "mt-xs opacity-80", children: jsx(Paragraph, { size: "text-m", font: "font-light", children: additionalDescription }) })) : null, button?.href ? jsx(Button, { className: "mt-xl", ...button }) : null] }, String(key)))) }, `col-${String(index)}`)) : null;
3199
3218
 
3219
+ const isOdd = (n) => n % 2 !== 0;
3220
+
3200
3221
  const TextWithIcon = JSX(({ textNode, iconNode, tag, onClick, justifyContent = 'between', className, ...rest }) => {
3201
3222
  const Tag = tag;
3202
3223
  return (jsxs(Tag, { tag: tag, className: style('flex items-center w-full gap-1', justifyContent === 'between' ? 'justify-between' : 'justify-center', className), onClick: onClick, ...rest, children: [textNode ? jsx("div", { children: textNode }) : null, iconNode ? jsx("div", { children: iconNode }) : null] }));
@@ -3222,8 +3243,8 @@
3222
3243
  const [visibleBlocks, hiddenBlocks] = topItemsCount > 0
3223
3244
  ? [blocksToRender.slice(0, topItemsCount), blocksToRender.slice(topItemsCount)]
3224
3245
  : [blocksToRender, []];
3225
- return (jsxs("div", { children: [jsx("div", { className: style(blocksToRender.length ? 'hidden' : 'block'), children: notFound ? jsx(NotFound, { ...notFound }) : null }), jsxs("div", { className: style('space-y-2xs', blocksToRender.length ? '' : 'hidden'), children: [jsx("div", { className: style(resultsGridStyle), children: renderBlocksList(visibleBlocks, { ...rest.options, parent: block }) }), jsx(Foldable, { renderFoldableSection: ({ isUnfolded }) => {
3226
- return (jsx(FoldableSection, { className: style(resultsGridStyle), isUnfolded: isUnfolded, children: renderBlocksList(hiddenBlocks, { ...rest.options, parent: block }) }));
3246
+ return (jsxs("div", { children: [jsx("div", { className: style(blocksToRender.length ? 'hidden' : 'block'), children: notFound ? jsx(NotFound, { ...notFound }) : null }), jsxs("div", { className: style('space-y-2xs', blocksToRender.length ? '' : 'hidden'), children: [jsxs("div", { className: style(resultsGridStyle), children: [renderBlocksList(visibleBlocks, { ...rest.options, parent: block }), isOdd(visibleBlocks.length) ? jsx(AdTile, { className: "col-span-6" }) : null] }), jsx(Foldable, { renderFoldableSection: ({ isUnfolded }) => {
3247
+ return (jsxs(FoldableSection, { className: style(resultsGridStyle), isUnfolded: isUnfolded, children: [renderBlocksList(hiddenBlocks, { ...rest.options, parent: block }), isOdd(hiddenBlocks.length) ? jsx(AdTile, { className: "col-span-6" }) : null] }));
3227
3248
  }, renderFoldButton: ({ isUnfolded, onToggle }) => (jsx(DefaultFoldButton, { className: style(topItemsCount < 1 ? 'hidden' : ''), disabled: !hiddenBlocks?.length, label: label, icon: ICONS[Number(isUnfolded)], dataTheme: rest.options?.page?.colorPalette, onClick: onToggle })) })] })] }));
3228
3249
  });
3229
3250
 
@@ -3478,6 +3499,48 @@
3478
3499
  };
3479
3500
  const ErrorBlock = JSX(({ className = '', title, description, error, button, ...rest }) => (jsxs(BlockWrapper, { className: style('flex flex-col justify-center items-center', className), defaultPadding: style('p-6xl'), version: "transparent", ...rest, children: [jsx("div", { className: "flex justify-center", children: renderErrorContent(error) }), jsx(Headline, { title: title, description: description, headlineVersion: "XL", isEmbedded: true, className: "mb-2xl last:mb-0" }), button?.text ? jsx(Button, { version: button?.version, text: button?.text, ...button }) : null] })));
3480
3501
 
3502
+ const useLatestEvent = (eventBus, type, initialEvent) => {
3503
+ const [latestEvent, setLatestEvent] = useState(initialEvent || null);
3504
+ useEffect(() => eventBus.subscribe(type, (_) => setLatestEvent(_)), [eventBus, type]);
3505
+ const fireEvent = useCallback((_) => eventBus.fire(type, _), [eventBus, type]);
3506
+ return [latestEvent, fireEvent];
3507
+ };
3508
+
3509
+ const REGION_URL = '/api/v1/region';
3510
+ const LOCATION_STORAGE_KEY = 'location';
3511
+ function useLocation(defaultLocation = 'Москва') {
3512
+ const [currentLocation, fireCurrentLocation] = useLatestEvent(defaultEventBus, 'location', restoreLocation() ?? { name: defaultLocation });
3513
+ const selectCurrentLocation = useCallback((_) => {
3514
+ storeLocation(_);
3515
+ fireCurrentLocation(_);
3516
+ }, []);
3517
+ const { data } = useAsyncData(REGION_URL, fetchJSONUnsafe);
3518
+ useEffect(() => {
3519
+ if (data && !hasStoredLocation()) {
3520
+ fireCurrentLocation(data);
3521
+ }
3522
+ }, [data]);
3523
+ return [currentLocation ?? { name: defaultLocation }, selectCurrentLocation];
3524
+ }
3525
+ const hasStoredLocation = () => Boolean(globalThis.localStorage?.getItem(LOCATION_STORAGE_KEY));
3526
+ const restoreLocation = () => {
3527
+ try {
3528
+ const data = globalThis.localStorage?.getItem(LOCATION_STORAGE_KEY);
3529
+ return data && JSON.parse(data);
3530
+ }
3531
+ catch (ex) {
3532
+ return null;
3533
+ }
3534
+ };
3535
+ const storeLocation = (_) => {
3536
+ try {
3537
+ globalThis.localStorage?.setItem(LOCATION_STORAGE_KEY, JSON.stringify(_));
3538
+ }
3539
+ catch (ex) {
3540
+ // Do nothing
3541
+ }
3542
+ };
3543
+
3481
3544
  var Currency;
3482
3545
  (function (Currency) {
3483
3546
  Currency["RUB"] = "RUB";
@@ -3608,40 +3671,15 @@
3608
3671
  };
3609
3672
 
3610
3673
  const EXCHANGE_RATES_URL = '/api/v1/exchangerates';
3611
- const REGION_URL$1 = '/api/v1/region';
3612
- function useFetchExchangeRateData() {
3613
- const { data } = useAsyncData(EXCHANGE_RATES_URL, fetchData);
3674
+ function useFetchExchangeRateData(currentRegion) {
3675
+ const regionCode = currentRegion?.code || '000';
3676
+ const { data } = useAsyncData(EXCHANGE_RATES_URL + `?regionCode=${regionCode}`, fetchJSONUnsafe);
3614
3677
  return data || {};
3615
3678
  }
3616
- const fetchData = async (urlExchangeRates) => {
3617
- const region = await fetchRegion();
3618
- const regionCode = region?.code || '000';
3619
- const exchangeRates = await fetchExchangeRates(urlExchangeRates, regionCode);
3620
- return { region, exchangeRates };
3621
- };
3622
- const fetchRegion = async () => {
3623
- try {
3624
- return await fetchJSONUnsafe(REGION_URL$1, { method: 'GET' });
3625
- }
3626
- catch (error) {
3627
- console.log(error);
3628
- return {};
3629
- }
3630
- };
3631
- const fetchExchangeRates = async (url, regionCode) => {
3632
- try {
3633
- return await fetchJSONUnsafe(url + `?regionCode=${regionCode}`, {
3634
- method: 'GET',
3635
- });
3636
- }
3637
- catch (error) {
3638
- console.log(error);
3639
- return {};
3640
- }
3641
- };
3642
3679
 
3643
3680
  const ExchangeRateTile = JSX(({ className = '', title = 'Курсы обмена валют', button, ...rest }) => {
3644
- const { exchangeRates } = useFetchExchangeRateData();
3681
+ const [currentLocation] = useLocation();
3682
+ const exchangeRates = useFetchExchangeRateData(currentLocation);
3645
3683
  const currencyRates = getCurrencyRates(exchangeRates?.exchangeRate?.currencies);
3646
3684
  const currencyRatesBuy = currencyRates.filter((_) => _.buyExchangeRate);
3647
3685
  currencyRatesBuy.unshift({ currency: { currency: Currency.RUB } });
@@ -3996,48 +4034,6 @@
3996
4034
  ? 'text-primary-main'
3997
4035
  : style(flat ? 'text-primary-text' : 'text-secondary-text', 'hover:text-primary-main'), 'group-data-transparent:text-white group-data-transparent:hover:text-primary-hover');
3998
4036
 
3999
- const useLatestEvent = (eventBus, type, initialEvent) => {
4000
- const [latestEvent, setLatestEvent] = useState(initialEvent || null);
4001
- useEffect(() => eventBus.subscribe(type, (_) => setLatestEvent(_)), [eventBus, type]);
4002
- const fireEvent = useCallback((_) => eventBus.fire(type, _), [eventBus, type]);
4003
- return [latestEvent, fireEvent];
4004
- };
4005
-
4006
- const REGION_URL = '/api/v1/region';
4007
- const LOCATION_STORAGE_KEY = 'location';
4008
- function useLocation(defaultLocation = 'Москва') {
4009
- const [currentLocation, fireCurrentLocation] = useLatestEvent(defaultEventBus, 'location', restoreLocation() ?? { name: defaultLocation });
4010
- const selectCurrentLocation = useCallback((_) => {
4011
- storeLocation(_);
4012
- fireCurrentLocation(_);
4013
- }, []);
4014
- const { data } = useAsyncData(REGION_URL, fetchJSONUnsafe);
4015
- useEffect(() => {
4016
- if (data && !hasStoredLocation()) {
4017
- fireCurrentLocation(data);
4018
- }
4019
- }, [data]);
4020
- return [currentLocation ?? { name: defaultLocation }, selectCurrentLocation];
4021
- }
4022
- const hasStoredLocation = () => Boolean(globalThis.localStorage?.getItem(LOCATION_STORAGE_KEY));
4023
- const restoreLocation = () => {
4024
- try {
4025
- const data = globalThis.localStorage?.getItem(LOCATION_STORAGE_KEY);
4026
- return data && JSON.parse(data);
4027
- }
4028
- catch (ex) {
4029
- return null;
4030
- }
4031
- };
4032
- const storeLocation = (_) => {
4033
- try {
4034
- globalThis.localStorage?.setItem(LOCATION_STORAGE_KEY, JSON.stringify(_));
4035
- }
4036
- catch (ex) {
4037
- // Do nothing
4038
- }
4039
- };
4040
-
4041
4037
  const REGIONS_URL = '/api/v1/regions';
4042
4038
  function useRegions() {
4043
4039
  const { data } = useAsyncData(REGIONS_URL, fetchJSONUnsafe);
@@ -4267,7 +4263,7 @@
4267
4263
  const HorizontalLayout = JSX(({ className = '', gap = 'XS', isPadding = false, version = 'transparent', isTheme = false, isCardBorder, ...rest }) => (jsx(BlockWrapper, { className: style('relative', 'grid grid-cols-12', gapStyles[gap], className), defaultPadding: isPadding ? 'p-6xl' : '', version: version, isTheme: isTheme, ...rest, children: renderChildren({
4268
4264
  ...rest,
4269
4265
  extraProps: {
4270
- className: getBorderStyle(isCardBorder),
4266
+ className: getBorderStyle$1(isCardBorder),
4271
4267
  },
4272
4268
  }) })));
4273
4269
  HorizontalLayout.childrenTypes = {
@@ -4557,11 +4553,6 @@
4557
4553
  MortgageFiltration.childrenTypes = ['ProductTile'];
4558
4554
  MortgageFiltration.childSchema = (content) => content?.filtrationSchema || {};
4559
4555
 
4560
- const isSSR = () => Boolean(typeof globalThis.process === 'object' && globalThis.process && globalThis.process.version);
4561
-
4562
- const isClient = !isSSR();
4563
- const ClientOnly = JSX(({ children }) => (isClient ? children : null));
4564
-
4565
4556
  function renderClusterer(yandexMaps, map, points) {
4566
4557
  map.geoObjects.removeAll();
4567
4558
  const clusterIconContentLayout = yandexMaps.templateLayoutFactory.createClass('<div style="margin-top: -3px;">{{properties.geoObjects.length}}</div>');
@@ -4982,8 +4973,6 @@
4982
4973
  const renderShimmerItem = (width, index) => (jsx("div", { style: { width: `${width || 100}%` }, className: "h-4 mt-xs bg-secondary-light" }, String(index)));
4983
4974
  const goldenSequence = (first, size) => [first].concat(size > 0 ? goldenSequence(first / GOLDEN_RATIO, size - 1) : []);
4984
4975
 
4985
- const ProductBlock = JSX(({ className, padding, showBorder, ...rest }) => (jsx(BlockWrapper, { className: style('overflow-hidden flex flex-col gap-3xl box-border', getBorderStyle(showBorder), className), padding: "p-0", ...rest, children: jsx(BaseProductTile, { defaultPadding: "p-6xl", padding: padding, className: "grow h-full", ...rest }) })));
4986
-
4987
4976
  const ProductGallery = JSX(({ className = '', padding, slides = [], ...rest }) => {
4988
4977
  const [activeSlideIndex, setActiveSlideIndex] = useState(0);
4989
4978
  return (jsxs(BlockWrapper, { className: style('box-border overflow-hidden', className), defaultPadding: "py-6xl", padding: padding, ...rest, children: [jsx("div", { className: "flex duration-1000", style: { transform: `translateX(-${activeSlideIndex * 100}%)` }, role: "list", children: slides.map(({ productBlock }, i) => (jsx("div", { className: "box-border grow-0 shrink-0 basis-full", role: "listitem", children: jsx(BaseProductTile, { className: "pl-6xl h-full", headlineVersion: "M", isFullWidthTitle: false, ...productBlock, ...rest }) }, String(i)))) }), jsx("div", { className: "h-28 px-xs mt-m -mb-m flex gap-xs box-border", children: slides.map(renderNavButton({ activeSlideIndex, onClick: setActiveSlideIndex })) })] }));
@@ -5507,7 +5496,7 @@
5507
5496
  const VerticalLayout = JSX(({ className = '', gap = '', isPadding = false, isInnerPadding = true, version = 'transparent', isTheme = false, isInnerBorder = false, ...rest }) => (jsx(BlockWrapper, { className: style('relative flex flex-col', gapStyles[gap], className), defaultPadding: isPadding ? 'p-6xl' : '', version: version, isTheme: isTheme, ...rest, children: renderChildren({
5508
5497
  ...rest,
5509
5498
  extraProps: {
5510
- className: style('w-full', getBorderStyle(isInnerBorder)),
5499
+ className: style('w-full', getBorderStyle$1(isInnerBorder)),
5511
5500
  padding: isInnerPadding ? '' : 'p-0',
5512
5501
  },
5513
5502
  }) })));
@@ -5528,6 +5517,7 @@
5528
5517
  });
5529
5518
 
5530
5519
  const Blocks = {
5520
+ AdTile,
5531
5521
  ApplicationForm,
5532
5522
  BenefitsBlock,
5533
5523
  Bonus,
@@ -5545,8 +5535,8 @@
5545
5535
  CarouselTariffsCard,
5546
5536
  ComparisonTable,
5547
5537
  ContactsBlock,
5548
- Depository,
5549
5538
  DepositFiltration,
5539
+ Depository,
5550
5540
  ErrorBlock,
5551
5541
  ExchangeRateTile,
5552
5542
  Footer,
@@ -5570,8 +5560,8 @@
5570
5560
  RollupItem,
5571
5561
  SafeDepositRental,
5572
5562
  StepsBlock,
5573
- SwipeListControlBlock,
5574
5563
  StickyBottomMenu,
5564
+ SwipeListControlBlock,
5575
5565
  Tabs,
5576
5566
  TariffsTable,
5577
5567
  TextBlock,
@@ -5810,7 +5800,7 @@
5810
5800
  return (jsx("div", { className: "flex items-end absolute bottom-0 right-0 h-full pointer-events-none", children: jsx(LikeControl, { className: "rounded-tl-3xl sticky bottom-0 pointer-events-auto" }) }));
5811
5801
  }
5812
5802
 
5813
- const packageVersion = "0.14.57";
5803
+ const packageVersion = "0.14.59";
5814
5804
 
5815
5805
  exports.Blocks = Blocks;
5816
5806
  exports.ContentPage = ContentPage;