@redneckz/wildless-cms-uni-blocks 0.14.271 → 0.14.272

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.
@@ -1824,28 +1824,130 @@
1824
1824
  : _ === (dataValue?.key ?? dataValue);
1825
1825
  }));
1826
1826
 
1827
- const AlignStyles = 'text-left';
1827
+ const joinList = (sep) => (list) => list.reduce((acc, el, i) => (acc.length ? acc.concat({ ...sep, key: `sep-${i}` }, el) : [el]), []);
1828
1828
 
1829
- const iconBgStyles = {
1830
- '': 'bg-main-divider group-data-secondary:bg-white/30',
1831
- primary: 'bg-main-divider',
1832
- secondary: 'bg-secondary-light',
1833
- opacity: 'bg-white/30',
1834
- };
1835
- const RoundedIcon = JSX(({ className, defaultIconSize = 44, iconBgVersion = 'primary', size, icon, ...rest }) => {
1836
- const widthAndHeight = String(size?.width || defaultIconSize);
1837
- return icon ? (jsx("div", { style: {
1838
- width: `${widthAndHeight}px`,
1839
- height: `${widthAndHeight}px`,
1840
- }, 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;
1829
+ const SlideCheckboxGroup = JSX(({ value, onChange, items = [], multiple }) => {
1830
+ const handleChange = (newValue) => {
1831
+ if (!onChange) {
1832
+ return;
1833
+ }
1834
+ const hasAlready = value?.includes(newValue);
1835
+ if (multiple) {
1836
+ onChange(hasAlready ? (value || []).filter((v) => v !== newValue) : [...(value || []), newValue]);
1837
+ }
1838
+ else {
1839
+ onChange(hasAlready ? [] : [newValue]);
1840
+ }
1841
+ };
1842
+ return items.map((item) => (jsx(SlideCheckbox, { text: item?.title, value: [value].flatMap((_) => _).includes(item.value), onChange: () => handleChange(item.value), type: multiple ? 'checkbox' : 'radio' }, item.value)));
1841
1843
  });
1842
1844
 
1843
- const defaultIconSize = 56;
1845
+ const FiltrationForm = JSX(({ children, filtrationSchema, resetButton, field, reset }) => (jsxs("form", { className: "flex flex-col @4xl:flex-row justify-between bg-white p-4xl gap-s @4xl:gap-0", children: [jsxs("div", { className: "flex flex-col @4xl:flex-row gap-xl", children: [children, joinList(jsx("div", { className: "h-full w-px bg-gray" }))(
1846
+ // TS can't correctly refine array's type after filter
1847
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1848
+ Object.entries(filtrationSchema).map(renderFormItem(field)).filter(Boolean))] }), resetButton ? (jsx("div", { children: jsx(Button, { type: "reset", className: "w-full @4xl:w-56 @4xl:ml-s", onClick: reset, children: resetButton?.text }) })) : null] })));
1849
+ const renderFormItem = (field) => ([key, item]) => {
1850
+ const type = item?.type;
1851
+ switch (type) {
1852
+ case 'array':
1853
+ return renderArrayFormItem(key, field)(item);
1854
+ default:
1855
+ return null;
1856
+ }
1857
+ };
1858
+ const renderArrayFormItem = (key, field) => (item) => item?.ui !== 'dropdown' ? renderCheckboxes(key, field)(item) : null;
1859
+ const renderCheckboxes = (key, field) => (item) => {
1860
+ const options = item?.items?.enum?.map((e, i) => ({ value: e, title: item?.items?.enumNames?.[i] || '' })) ||
1861
+ [];
1862
+ return (jsxs("div", { className: "flex-1", children: [item?.title ? (jsx("div", { className: "mb-m", children: jsx(Text, { size: "text-m", font: "font-medium", color: "text-primary-text", children: item.title }) })) : null, jsx(SlideCheckboxGroup, { items: options, multiple: !item?.single, ...field(key) })] }, key));
1863
+ };
1844
1864
 
1845
- 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] })));
1846
- const renderBenefit = ({ label, description, items, icon, iconBgVersion, isDotted = false }, i) => (jsxs("div", { className: "flex gap-m items-center @md:basis-1/2 @md:max-w-[500px]", role: "listitem", children: [icon?.icon ? (jsx(RoundedIcon, { className: "shrink-0", defaultIconSize: defaultIconSize, iconBgVersion: iconBgVersion || '', ...icon })) : null, icon?.src ? jsx(Img, { className: "shrink-0", image: icon }) : null, label ? (jsxs("div", { className: "@sm:h-full space-y-xs", children: [jsx(Heading, { headingType: "h6", children: label }), jsx(Text, { size: "text-l", color: "text-secondary-text group-data-secondary:text-white/80", font: "font-light", children: description }), jsx(List, { dotClassName: "bg-secondary-text", listItemSize: "S", items: items, isDotted: isDotted })] })) : null] }, String(i)));
1865
+ function zip(firstCol, ...restCols) {
1866
+ return firstCol.map((firstEl, rowIndex) => [firstEl, ...restCols.map((col) => col[rowIndex])]);
1867
+ }
1847
1868
 
1848
- const isShowDots = true;
1869
+ const isEmpty = (v) => v === null ||
1870
+ v === undefined ||
1871
+ v === '' ||
1872
+ (Array.isArray(v) && v.length === 0) ||
1873
+ (typeof v === 'object' && Object.keys(v).length === 0);
1874
+
1875
+ const isSingularFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) || isEmpty(target[key]) || pattern[key] === target[key];
1876
+ const isMultipleFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) ||
1877
+ isEmpty(target[key]) ||
1878
+ pattern[key]?.every((_) => target[key]?.includes(_));
1879
+ const isNumberFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) ||
1880
+ isEmpty(target[key]) ||
1881
+ naturalNumber(pattern[key]) <= naturalNumber(target[key]);
1882
+ const isMultipleNumberFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) || isEmpty(target[key]) || target[key]?.includes(pattern[key]);
1883
+ const isValueInRange = (key, pattern) => (target) => isEmpty(pattern[key]) ||
1884
+ isEmpty(target[key]) ||
1885
+ (naturalNumber(pattern[key]?.min) >= naturalNumber(target[key]?.min) &&
1886
+ naturalNumber(pattern[key]?.min) <= naturalNumber(target[key]?.max));
1887
+ const targetMatchPattern = (pattern, target) => Object.entries(pattern)
1888
+ .map(([key, subPattern]) => {
1889
+ if (typeof subPattern === 'number') {
1890
+ return Array.isArray(target[key])
1891
+ ? isMultipleNumberFieldMatch(key, pattern)
1892
+ : isNumberFieldMatch(key, pattern);
1893
+ }
1894
+ if (typeof subPattern === 'object' && 'min' in subPattern && 'max' in subPattern) {
1895
+ return isValueInRange(key, pattern);
1896
+ }
1897
+ return Array.isArray(subPattern)
1898
+ ? isMultipleFieldMatch(key, pattern)
1899
+ : isSingularFieldMatch(key, pattern);
1900
+ })
1901
+ .every((predicate) => predicate(target));
1902
+ const naturalNumber = (n) => Number(n || 0);
1903
+
1904
+ const filterBlocks = (blocksWithProps, filtrationState) => (normalize = identity) => blocksWithProps
1905
+ ?.filter(([, content]) => targetMatchPattern(filtrationState, normalize(content) || {}))
1906
+ .map(([block]) => block);
1907
+
1908
+ const useFiltrationForm = (initialFormState, { block, page, normalize = identity, }) => {
1909
+ const blocks = block?.blocks || [];
1910
+ const [filtrationState, { field, reset, update: replaceFiltrationState }] = useForm(initialFormState);
1911
+ const blocksWithProps = useMemo(() => zip(blocks, blocks.map((b) => resolveBlockProps(b.content, page?.fallback))), [blocks, page?.fallback]);
1912
+ const blocksToRender = filtrationState === initialFormState
1913
+ ? blocks
1914
+ : filterBlocks(blocksWithProps, filtrationState)(normalize);
1915
+ return [
1916
+ filtrationState,
1917
+ { blocksToRender, blocksWithProps },
1918
+ { field, reset, update: replaceFiltrationState },
1919
+ ];
1920
+ };
1921
+
1922
+ const AlignStyles = 'text-left';
1923
+
1924
+ const NotFound = JSX(({ title, description }) => (jsxs("div", { className: "bg-white p-6xl py-20 flex gap-s flex-col @xl:items-center", children: [jsx(Img, { image: { icon: 'MagnifierIcon', iconVersion: 'normal' }, width: "120", height: "120" }), jsx(Headline, { title: title, description: description, headlineVersion: "S", isEmbedded: true, align: AlignStyles })] })));
1925
+
1926
+ const getBorderStyle = (showBorder = false) => showBorder
1927
+ ? 'border border-solid border-gray group-data-secondary:border-white/50 group-data-gray:border-main-divider'
1928
+ : '';
1929
+
1930
+ const useCarouselControls = (props, initialIndex = 0) => {
1931
+ const { itemCount, visibleItemCount } = props;
1932
+ const [activeIndex, setActiveIndex] = useState(initialIndex);
1933
+ const inc = useCallback(() => setActiveIndex((_) => Math.min(_ + 1, itemCount - 1)), [itemCount]);
1934
+ const dec = useCallback(() => setActiveIndex((_) => Math.max(_ - 1, 0)), [itemCount]);
1935
+ const canInc = visibleItemCount
1936
+ ? itemCount > visibleItemCount && activeIndex < itemCount - visibleItemCount
1937
+ : activeIndex < itemCount - 1;
1938
+ const canDec = activeIndex > 0;
1939
+ const isScrollAvailable = canDec || canInc;
1940
+ return [
1941
+ activeIndex,
1942
+ {
1943
+ inc,
1944
+ dec,
1945
+ canInc,
1946
+ canDec,
1947
+ isScrollAvailable,
1948
+ },
1949
+ ];
1950
+ };
1849
1951
 
1850
1952
  const mapChildren = (mapper) => (children) => {
1851
1953
  if (children === null || children === undefined) {
@@ -2037,6 +2139,163 @@
2037
2139
  ];
2038
2140
  };
2039
2141
 
2142
+ /** @deprecated */
2143
+ const ArrowButton = JSX(({ className, disabled, ...rest }) => (jsx(LinkButton, { rounded: true, className: style('group/btn w-12 h-12 min-h-12 max-h-12 flex items-center justify-center shadow-main-black', disabled
2144
+ ? 'bg-secondary-light text-secondary-text'
2145
+ : 'bg-white text-primary-text hover:text-primary-main', className || ''), disabled: disabled, ...rest, children: jsx(Img, { className: "w-4 h-4 min-w-4 min-h-4 rounded-full box-border", image: { icon: 'ArrowLeftIcon', iconVersion: 'black' }, imageClassName: "group-hover/btn:text-primary-main", width: "16", height: "16" }) })));
2146
+ /** @deprecated */
2147
+ const ScrollLeftButton = JSX((props) => (jsx(ArrowButton, { ...props, ariaLabel: "\u041F\u0440\u043E\u043B\u0438\u0441\u0442\u0430\u0442\u044C \u0432\u043B\u0435\u0432\u043E", "data-block-control": "scroll-left" })));
2148
+ /** @deprecated */
2149
+ const ScrollRightButton = JSX((props) => (jsx(ArrowButton, { ...props, className: `${props.className || ''} rotate-180`, ariaLabel: "\u041F\u0440\u043E\u043B\u0438\u0441\u0442\u0430\u0442\u044C \u0432\u043F\u0440\u0430\u0432\u043E", "data-block-control": "scroll-right" })));
2150
+
2151
+ const scrollButtonStyle$1 = 'absolute top-[calc(50%-24px)] z-40';
2152
+ const blurBaseStyle = 'absolute top-0 bottom-0 z-40 hidden @lg:block w-20 pointer-events-none';
2153
+ const CarouselScrollButtons = JSX(({ scroll, activeIndex, itemCount, arrowsPadded, hasEdgeBlocks, onScrollLeft, onScrollRight, }) => {
2154
+ const { canScrollLeft, canScrollRight, scrollLeft, scrollRight } = scroll;
2155
+ const canMoveLeft = hasEdgeBlocks ? activeIndex > 0 : canScrollLeft;
2156
+ const canMoveRight = hasEdgeBlocks ? activeIndex < itemCount - 1 : canScrollRight;
2157
+ const handleScrollLeft = useCallback(() => {
2158
+ if (!hasEdgeBlocks) {
2159
+ scrollLeft();
2160
+ }
2161
+ else {
2162
+ canScrollLeft && activeIndex !== itemCount - 1 && scrollLeft();
2163
+ onScrollLeft();
2164
+ }
2165
+ }, [scrollLeft, onScrollLeft, hasEdgeBlocks, canScrollLeft, activeIndex, itemCount]);
2166
+ const handleScrollRight = useCallback(() => {
2167
+ if (!hasEdgeBlocks) {
2168
+ scrollRight();
2169
+ }
2170
+ else {
2171
+ canScrollRight && activeIndex !== 0 && scrollRight();
2172
+ onScrollRight();
2173
+ }
2174
+ }, [scrollRight, onScrollRight, hasEdgeBlocks, canScrollLeft, activeIndex, itemCount]);
2175
+ return (jsxs("div", { className: "m:hidden block", children: [renderBlur(scroll), canMoveLeft ? (jsx(ScrollLeftButton, { className: style(scrollButtonStyle$1, arrowsPadded ? 'left-1 m:left-8' : 'left-0'), onClick: handleScrollLeft })) : null, canMoveRight ? (jsx(ScrollRightButton, { className: style(scrollButtonStyle$1, arrowsPadded ? 'right-1 m:right-8' : 'right-0'), onClick: handleScrollRight })) : null] }));
2176
+ });
2177
+ const renderBlur = (scroll) => (jsxs("div", { children: [scroll.canScrollLeft ? (jsx("div", { className: style(blurBaseStyle, 'left-0 bg-opacity-from-white group-data-secondary:bg-none') })) : null, scroll.canScrollRight ? (jsx("div", { className: style(blurBaseStyle, 'right-0 bg-opacity-to-white group-data-secondary:bg-none') })) : null] }));
2178
+
2179
+ const ITEMS_GAP = 16;
2180
+
2181
+ 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 })] }));
2182
+
2183
+ const cardBaseStyle = 'relative h-full';
2184
+ const CARD_SIZE_MAP = {
2185
+ small: 'sm:min-w-64',
2186
+ normal: 'sm:min-w-96',
2187
+ big: 'sm:min-w-[515px]',
2188
+ };
2189
+ const renderCarouselCards = ({ noCardBorder, activeIndex, cardSize = 'normal', ...rest }) => {
2190
+ const { blocks: childBlocks } = rest.block || {};
2191
+ const someCardsHighlighted = childBlocks?.some(isCardHighlighted);
2192
+ return renderChildren({
2193
+ ...rest,
2194
+ renderProps: (block, options, blockIndex) => (jsxs("div", { className: cardWrapperStyle(block, { someCardsHighlighted }), children: [renderBlock$1(block, options, {
2195
+ className: cardStyle(block, {
2196
+ someCardsHighlighted,
2197
+ showBorder: !noCardBorder,
2198
+ cardSize,
2199
+ }),
2200
+ blockIndex,
2201
+ isActive: blockIndex === activeIndex,
2202
+ }), isCardHighlighted(block)
2203
+ ? renderCardHighlight({ className: 'absolute top-0 -right-4 z-40' })
2204
+ : null] }, String(blockIndex))),
2205
+ });
2206
+ };
2207
+ const cardWrapperStyle = (_, { someCardsHighlighted }) => style(cardBaseStyle, someCardsHighlighted && (isCardHighlighted(_) ? 'pt-3xl' : 'pt-3xl sm:pt-16'));
2208
+ const cardStyle = (_, { someCardsHighlighted, showBorder, cardSize = 'normal', }) => style(cardBaseStyle, 'min-w-80', CARD_SIZE_MAP[cardSize], // TODO fix для RecommendationCard
2209
+ someCardsHighlighted && (isCardHighlighted(_) ? 'pt-3xl sm:pt-16' : 'pt-3xl'), getBorderStyle(showBorder), showBorder && 'h-full');
2210
+ const isCardHighlighted = (_) => _?.content && 'isHighlighting' in _.content && _.content.isHighlighting;
2211
+
2212
+ const VISIBLE_ITEM_COUNT = 0;
2213
+
2214
+ const Carousel = UniBlock(({ className, itemCount, visibleItemCount = VISIBLE_ITEM_COUNT, noCardBorder, isAlignCenter, arrowsPadded = true, isGap = true, isEmbedded = false, cardSize = 'normal', ...rest }) => {
2215
+ const { blocks: childBlocks = [] } = rest.block || {};
2216
+ const count = itemCount || childBlocks?.length;
2217
+ const [activeIndex, { inc: increaseActiveIndex, dec: decreaseActiveIndex }] = useCarouselControls({
2218
+ itemCount: count,
2219
+ visibleItemCount,
2220
+ }, Math.floor(visibleItemCount / 2));
2221
+ const [containerRef, scroll] = useSwipeListScroll({ itemCount: count });
2222
+ const [dotsActiveIndex] = scroll.visibleIndicesRange;
2223
+ // TODO Remove
2224
+ const isBankHistoryCarousel = childBlocks && childBlocks[0]?.type === 'CarouselBankHistoryCard';
2225
+ return (jsxs(BlockWrapper, { className: style(isEmbedded ? '@container-normal' : '', className), defaultPadding: "p-6xl", ...rest, children: [jsxs("div", { className: style(isAlignCenter ? 'flex justify-center' : '', 'relative max-w-full'), children: [jsx(SwipeListContainer, { containerRef: containerRef, visibleItemCount: visibleItemCount, snapAlign: "snap-start", gap: isGap ? ITEMS_GAP : undefined, onVisibleIndicesChange: scroll.handleVisibleIndicesChange, children: renderCarouselCards({ noCardBorder, activeIndex, cardSize, ...rest }) }), jsx(CarouselScrollButtons, { scroll: scroll, arrowsPadded: arrowsPadded, onScrollLeft: decreaseActiveIndex, onScrollRight: increaseActiveIndex, hasEdgeBlocks: isBankHistoryCarousel, activeIndex: activeIndex, itemCount: count })] }), jsx(SwipeListControlDots, { className: "@5xl:hidden", containerRef: containerRef, activeIndex: dotsActiveIndex, dotCount: count, listType: "horizontal-list" })] }));
2226
+ }, {
2227
+ childrenTypes: [
2228
+ 'CarouselCard',
2229
+ 'CarouselBankHistoryCard',
2230
+ 'CarouselCatalogCard',
2231
+ 'CarouselRecommendationCard',
2232
+ 'CarouselTariffsCard',
2233
+ 'RichTextBlock',
2234
+ 'ProductBlock',
2235
+ ],
2236
+ childSchema: () => ({
2237
+ isHighlighting: {
2238
+ title: 'Выделить карточку',
2239
+ type: 'boolean',
2240
+ },
2241
+ }),
2242
+ });
2243
+
2244
+ const EMPTY_SCHEMA = {};
2245
+ const initialFiltrationState$2 = {};
2246
+ const BankAccountFiltration = UniBlock(({ className, filtrationSchema = EMPTY_SCHEMA, resetButton, notFound, ...rest }) => {
2247
+ const [, { blocksToRender }, { field, reset }] = useFiltrationForm(initialFiltrationState$2, {
2248
+ block: rest.block,
2249
+ page: rest.options?.page,
2250
+ });
2251
+ const selectArrProps = Object.entries(filtrationSchema)
2252
+ // Only StringArray
2253
+ .filter(([, schema]) => schema.type === 'array' && schema.ui === 'dropdown')
2254
+ .map(([name, schema]) => ({
2255
+ className: 'w-64',
2256
+ label: schema.title,
2257
+ options: stringArrayToOptions(schema),
2258
+ ...field(name, {
2259
+ parse: ({ key }) => [key],
2260
+ format: ([value] = []) => stringArrayToOptions(schema).find((_) => _.key === value) || { key: '' },
2261
+ }),
2262
+ }));
2263
+ const Selects = selectArrProps.map((props, i) => jsx(Select, { ...props }, String(i)));
2264
+ return (jsxs(BlockWrapper, { className: style(className), defaultPadding: "p-0", version: "transparent", ...rest, children: [jsx(FiltrationForm, { filtrationSchema: filtrationSchema, field: field, reset: reset, children: jsxs("div", { children: [Selects, jsx("div", { children: jsx(Button, { type: "reset", className: "mt-lg w-64", onClick: reset, version: resetButton?.version, children: resetButton?.text }) })] }) }), jsx("div", { className: style(blocksToRender?.length ? 'hidden' : 'block'), children: notFound ? jsx(NotFound, { ...notFound }) : null }), jsx(Carousel, { padding: "p-0", isEmbedded: true, itemCount: blocksToRender?.length, visibleItemCount: 0, isAlignCenter: true, isGap: false, children: renderBlocksList(blocksToRender, {
2265
+ ...rest.options,
2266
+ parent: rest.block,
2267
+ renderProps: (block, options, i) => (jsx("div", { className: style('relative min-w-80', getBorderStyle(true)), children: renderBlock$1(block, options) }, String(i))),
2268
+ }) })] }));
2269
+ }, {
2270
+ childrenTypes: ['CarouselTariffsCard'],
2271
+ childSchema: (content) => content?.filtrationSchema || {},
2272
+ });
2273
+ const stringArrayToOptions = (stringEnum) => zip(stringEnum.items?.enum || [], stringEnum.items?.enumNames || []).map(([key, text]) => ({
2274
+ key,
2275
+ text,
2276
+ }));
2277
+
2278
+ const iconBgStyles = {
2279
+ '': 'bg-main-divider group-data-secondary:bg-white/30',
2280
+ primary: 'bg-main-divider',
2281
+ secondary: 'bg-secondary-light',
2282
+ opacity: 'bg-white/30',
2283
+ };
2284
+ const RoundedIcon = JSX(({ className, defaultIconSize = 44, iconBgVersion = 'primary', size, icon, ...rest }) => {
2285
+ const widthAndHeight = String(size?.width || defaultIconSize);
2286
+ return icon ? (jsx("div", { style: {
2287
+ width: `${widthAndHeight}px`,
2288
+ height: `${widthAndHeight}px`,
2289
+ }, 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;
2290
+ });
2291
+
2292
+ const defaultIconSize = 56;
2293
+
2294
+ 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] })));
2295
+ const renderBenefit = ({ label, description, items, icon, iconBgVersion, isDotted = false }, i) => (jsxs("div", { className: "flex gap-m items-center @md:basis-1/2 @md:max-w-[500px]", role: "listitem", children: [icon?.icon ? (jsx(RoundedIcon, { className: "shrink-0", defaultIconSize: defaultIconSize, iconBgVersion: iconBgVersion || '', ...icon })) : null, icon?.src ? jsx(Img, { className: "shrink-0", image: icon }) : null, label ? (jsxs("div", { className: "@sm:h-full space-y-xs", children: [jsx(Heading, { headingType: "h6", children: label }), jsx(Text, { size: "text-l", color: "text-secondary-text group-data-secondary:text-white/80", font: "font-light", children: description }), jsx(List, { dotClassName: "bg-secondary-text", listItemSize: "S", items: items, isDotted: isDotted })] })) : null] }, String(i)));
2296
+
2297
+ const isShowDots = true;
2298
+
2040
2299
  const DEFAULT_GAP = 14;
2041
2300
  /*
2042
2301
  Horizontal padding used on a container above SwipeListControl.
@@ -2888,134 +3147,6 @@
2888
3147
  return (jsxs(BlockWrapper, { className: style('flex flex-col items-center', className), defaultPadding: "p-6xl", ...rest, children: [title ? (jsx(Heading, { className: "pb-lg xl:pb-4xl self-start xl:self-center", headingType: "h3", title: title })) : null, jsxs("form", { className: "w-full xl:max-w-[468px]", method: "POST", action: FORM_URL_MAP[formType], children: [jsx(CurrencyInput, { valid: !isDisabled, placeholder: placeholder, label: label, max: MAX_AMOUNT, min: MIN_AMOUNT, ...field('amount', { parse: Number, format: String }) }), jsx("input", { type: "hidden", name: "amount", value: amount }), button?.text ? (jsx(Button, { className: "w-full mt-lg", type: "submit", disabled: isDisabled, children: button.text })) : null] })] }));
2889
3148
  });
2890
3149
 
2891
- const useCarouselControls = (props, initialIndex = 0) => {
2892
- const { itemCount, visibleItemCount } = props;
2893
- const [activeIndex, setActiveIndex] = useState(initialIndex);
2894
- const inc = useCallback(() => setActiveIndex((_) => Math.min(_ + 1, itemCount - 1)), [itemCount]);
2895
- const dec = useCallback(() => setActiveIndex((_) => Math.max(_ - 1, 0)), [itemCount]);
2896
- const canInc = visibleItemCount
2897
- ? itemCount > visibleItemCount && activeIndex < itemCount - visibleItemCount
2898
- : activeIndex < itemCount - 1;
2899
- const canDec = activeIndex > 0;
2900
- const isScrollAvailable = canDec || canInc;
2901
- return [
2902
- activeIndex,
2903
- {
2904
- inc,
2905
- dec,
2906
- canInc,
2907
- canDec,
2908
- isScrollAvailable,
2909
- },
2910
- ];
2911
- };
2912
-
2913
- /** @deprecated */
2914
- const ArrowButton = JSX(({ className, disabled, ...rest }) => (jsx(LinkButton, { rounded: true, className: style('group/btn w-12 h-12 min-h-12 max-h-12 flex items-center justify-center shadow-main-black', disabled
2915
- ? 'bg-secondary-light text-secondary-text'
2916
- : 'bg-white text-primary-text hover:text-primary-main', className || ''), disabled: disabled, ...rest, children: jsx(Img, { className: "w-4 h-4 min-w-4 min-h-4 rounded-full box-border", image: { icon: 'ArrowLeftIcon', iconVersion: 'black' }, imageClassName: "group-hover/btn:text-primary-main", width: "16", height: "16" }) })));
2917
- /** @deprecated */
2918
- const ScrollLeftButton = JSX((props) => (jsx(ArrowButton, { ...props, ariaLabel: "\u041F\u0440\u043E\u043B\u0438\u0441\u0442\u0430\u0442\u044C \u0432\u043B\u0435\u0432\u043E", "data-block-control": "scroll-left" })));
2919
- /** @deprecated */
2920
- const ScrollRightButton = JSX((props) => (jsx(ArrowButton, { ...props, className: `${props.className || ''} rotate-180`, ariaLabel: "\u041F\u0440\u043E\u043B\u0438\u0441\u0442\u0430\u0442\u044C \u0432\u043F\u0440\u0430\u0432\u043E", "data-block-control": "scroll-right" })));
2921
-
2922
- const scrollButtonStyle$1 = 'absolute top-[calc(50%-24px)] z-40';
2923
- const blurBaseStyle = 'absolute top-0 bottom-0 z-40 hidden @lg:block w-20 pointer-events-none';
2924
- const CarouselScrollButtons = JSX(({ scroll, activeIndex, itemCount, arrowsPadded, hasEdgeBlocks, onScrollLeft, onScrollRight, }) => {
2925
- const { canScrollLeft, canScrollRight, scrollLeft, scrollRight } = scroll;
2926
- const canMoveLeft = hasEdgeBlocks ? activeIndex > 0 : canScrollLeft;
2927
- const canMoveRight = hasEdgeBlocks ? activeIndex < itemCount - 1 : canScrollRight;
2928
- const handleScrollLeft = useCallback(() => {
2929
- if (!hasEdgeBlocks) {
2930
- scrollLeft();
2931
- }
2932
- else {
2933
- canScrollLeft && activeIndex !== itemCount - 1 && scrollLeft();
2934
- onScrollLeft();
2935
- }
2936
- }, [scrollLeft, onScrollLeft, hasEdgeBlocks, canScrollLeft, activeIndex, itemCount]);
2937
- const handleScrollRight = useCallback(() => {
2938
- if (!hasEdgeBlocks) {
2939
- scrollRight();
2940
- }
2941
- else {
2942
- canScrollRight && activeIndex !== 0 && scrollRight();
2943
- onScrollRight();
2944
- }
2945
- }, [scrollRight, onScrollRight, hasEdgeBlocks, canScrollLeft, activeIndex, itemCount]);
2946
- return (jsxs("div", { className: "m:hidden block", children: [renderBlur(scroll), canMoveLeft ? (jsx(ScrollLeftButton, { className: style(scrollButtonStyle$1, arrowsPadded ? 'left-1 m:left-8' : 'left-0'), onClick: handleScrollLeft })) : null, canMoveRight ? (jsx(ScrollRightButton, { className: style(scrollButtonStyle$1, arrowsPadded ? 'right-1 m:right-8' : 'right-0'), onClick: handleScrollRight })) : null] }));
2947
- });
2948
- const renderBlur = (scroll) => (jsxs("div", { children: [scroll.canScrollLeft ? (jsx("div", { className: style(blurBaseStyle, 'left-0 bg-opacity-from-white group-data-secondary:bg-none') })) : null, scroll.canScrollRight ? (jsx("div", { className: style(blurBaseStyle, 'right-0 bg-opacity-to-white group-data-secondary:bg-none') })) : null] }));
2949
-
2950
- const ITEMS_GAP = 16;
2951
-
2952
- const getBorderStyle = (showBorder = false) => showBorder
2953
- ? 'border border-solid border-gray group-data-secondary:border-white/50 group-data-gray:border-main-divider'
2954
- : '';
2955
-
2956
- 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 })] }));
2957
-
2958
- const cardBaseStyle = 'relative h-full';
2959
- const CARD_SIZE_MAP = {
2960
- small: 'sm:min-w-64',
2961
- normal: 'sm:min-w-96',
2962
- big: 'sm:min-w-[515px]',
2963
- };
2964
- const renderCarouselCards = ({ noCardBorder, activeIndex, cardSize = 'normal', ...rest }) => {
2965
- const { blocks: childBlocks } = rest.block || {};
2966
- const someCardsHighlighted = childBlocks?.some(isCardHighlighted);
2967
- return renderChildren({
2968
- ...rest,
2969
- renderProps: (block, options, blockIndex) => (jsxs("div", { className: cardWrapperStyle(block, { someCardsHighlighted }), children: [renderBlock$1(block, options, {
2970
- className: cardStyle(block, {
2971
- someCardsHighlighted,
2972
- showBorder: !noCardBorder,
2973
- cardSize,
2974
- }),
2975
- blockIndex,
2976
- isActive: blockIndex === activeIndex,
2977
- }), isCardHighlighted(block)
2978
- ? renderCardHighlight({ className: 'absolute top-0 -right-4 z-40' })
2979
- : null] }, String(blockIndex))),
2980
- });
2981
- };
2982
- const cardWrapperStyle = (_, { someCardsHighlighted }) => style(cardBaseStyle, someCardsHighlighted && (isCardHighlighted(_) ? 'pt-3xl' : 'pt-3xl sm:pt-16'));
2983
- const cardStyle = (_, { someCardsHighlighted, showBorder, cardSize = 'normal', }) => style(cardBaseStyle, 'min-w-80', CARD_SIZE_MAP[cardSize], // TODO fix для RecommendationCard
2984
- someCardsHighlighted && (isCardHighlighted(_) ? 'pt-3xl sm:pt-16' : 'pt-3xl'), getBorderStyle(showBorder), showBorder && 'h-full');
2985
- const isCardHighlighted = (_) => _?.content && 'isHighlighting' in _.content && _.content.isHighlighting;
2986
-
2987
- const VISIBLE_ITEM_COUNT = 0;
2988
-
2989
- const Carousel = UniBlock(({ className, itemCount, visibleItemCount = VISIBLE_ITEM_COUNT, noCardBorder, isAlignCenter, arrowsPadded = true, isGap = true, isEmbedded = false, cardSize = 'normal', ...rest }) => {
2990
- const { blocks: childBlocks = [] } = rest.block || {};
2991
- const count = itemCount || childBlocks?.length;
2992
- const [activeIndex, { inc: increaseActiveIndex, dec: decreaseActiveIndex }] = useCarouselControls({
2993
- itemCount: count,
2994
- visibleItemCount,
2995
- }, Math.floor(visibleItemCount / 2));
2996
- const [containerRef, scroll] = useSwipeListScroll({ itemCount: count });
2997
- const [dotsActiveIndex] = scroll.visibleIndicesRange;
2998
- // TODO Remove
2999
- const isBankHistoryCarousel = childBlocks && childBlocks[0]?.type === 'CarouselBankHistoryCard';
3000
- return (jsxs(BlockWrapper, { className: style(isEmbedded ? '@container-normal' : '', className), defaultPadding: "p-6xl", ...rest, children: [jsxs("div", { className: style(isAlignCenter ? 'flex justify-center' : '', 'relative max-w-full'), children: [jsx(SwipeListContainer, { containerRef: containerRef, visibleItemCount: visibleItemCount, snapAlign: "snap-start", gap: isGap ? ITEMS_GAP : undefined, onVisibleIndicesChange: scroll.handleVisibleIndicesChange, children: renderCarouselCards({ noCardBorder, activeIndex, cardSize, ...rest }) }), jsx(CarouselScrollButtons, { scroll: scroll, arrowsPadded: arrowsPadded, onScrollLeft: decreaseActiveIndex, onScrollRight: increaseActiveIndex, hasEdgeBlocks: isBankHistoryCarousel, activeIndex: activeIndex, itemCount: count })] }), jsx(SwipeListControlDots, { className: "@5xl:hidden", containerRef: containerRef, activeIndex: dotsActiveIndex, dotCount: count, listType: "horizontal-list" })] }));
3001
- }, {
3002
- childrenTypes: [
3003
- 'CarouselCard',
3004
- 'CarouselBankHistoryCard',
3005
- 'CarouselCatalogCard',
3006
- 'CarouselRecommendationCard',
3007
- 'CarouselTariffsCard',
3008
- 'RichTextBlock',
3009
- 'ProductBlock',
3010
- ],
3011
- childSchema: () => ({
3012
- isHighlighting: {
3013
- title: 'Выделить карточку',
3014
- type: 'boolean',
3015
- },
3016
- }),
3017
- });
3018
-
3019
3150
  const CarouselBankHistoryCard = JSX(({ title, description, className }) => (jsx(BlockWrapper, { className: className, defaultPadding: "p-6xl", children: jsx(Headline, { headlineVersion: "XS", title: title, description: description, align: "text-left", className: "text-primary-text", isEmbedded: true }) })));
3020
3151
 
3021
3152
  const titleSize = 'XS';
@@ -3218,8 +3349,6 @@
3218
3349
  return (jsx(DefaultFoldButton, { icon: icons[Number(isUnfolded)], label: labels[Number(isUnfolded)], onClick: onToggle }));
3219
3350
  };
3220
3351
 
3221
- const NotFound = JSX(({ title, description }) => (jsxs("div", { className: "bg-white p-6xl py-20 flex gap-s flex-col @xl:items-center", children: [jsx(Img, { image: { icon: 'MagnifierIcon', iconVersion: 'normal' }, width: "120", height: "120" }), jsx(Headline, { title: title, description: description, headlineVersion: "S", isEmbedded: true, align: AlignStyles })] })));
3222
-
3223
3352
  const ICONS$1 = ['ArrowDownIcon', 'ArrowUpIcon'];
3224
3353
  const resultsGridStyle = 'space-y-px lg:space-y-0 lg:grid lg:grid-cols-12 gap-2xs border-box';
3225
3354
  const BaseFiltrationInner = JSX(({ label = '', blocksToRender = [], topItemsCount = 0, block, notFound, ...rest }) => {
@@ -3231,101 +3360,6 @@
3231
3360
  }, renderFoldButton: ({ isUnfolded, onToggle }) => (jsx(DefaultFoldButton, { className: style(topItemsCount < 1 ? 'hidden' : ''), disabled: !hiddenBlocks?.length, label: label, icon: ICONS$1[Number(isUnfolded)], dataTheme: rest.options?.page?.colorPalette, onClick: onToggle })) })] })] }));
3232
3361
  });
3233
3362
 
3234
- const joinList = (sep) => (list) => list.reduce((acc, el, i) => (acc.length ? acc.concat({ ...sep, key: `sep-${i}` }, el) : [el]), []);
3235
-
3236
- const SlideCheckboxGroup = JSX(({ value, onChange, items = [], multiple }) => {
3237
- const handleChange = (newValue) => {
3238
- if (!onChange) {
3239
- return;
3240
- }
3241
- const hasAlready = value?.includes(newValue);
3242
- if (multiple) {
3243
- onChange(hasAlready ? (value || []).filter((v) => v !== newValue) : [...(value || []), newValue]);
3244
- }
3245
- else {
3246
- onChange(hasAlready ? [] : [newValue]);
3247
- }
3248
- };
3249
- return items.map((item) => (jsx(SlideCheckbox, { text: item?.title, value: [value].flatMap((_) => _).includes(item.value), onChange: () => handleChange(item.value), type: multiple ? 'checkbox' : 'radio' }, item.value)));
3250
- });
3251
-
3252
- const FiltrationForm = JSX(({ children, filtrationSchema, resetButton, field, reset }) => (jsxs("form", { className: "flex flex-col @4xl:flex-row justify-between bg-white p-4xl gap-s @4xl:gap-0", children: [jsxs("div", { className: "flex flex-col @4xl:flex-row gap-xl", children: [children, joinList(jsx("div", { className: "h-full w-px bg-gray" }))(
3253
- // TS can't correctly refine array's type after filter
3254
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
3255
- Object.entries(filtrationSchema).map(renderFormItem(field)).filter(Boolean))] }), resetButton ? (jsx("div", { children: jsx(Button, { type: "reset", className: "w-full @4xl:w-56 @4xl:ml-s", onClick: reset, children: resetButton?.text }) })) : null] })));
3256
- const renderFormItem = (field) => ([key, item]) => {
3257
- const type = item?.type;
3258
- switch (type) {
3259
- case 'array':
3260
- return renderArrayFormItem(key, field)(item);
3261
- default:
3262
- return null;
3263
- }
3264
- };
3265
- const renderArrayFormItem = (key, field) => (item) => item?.ui !== 'dropdown' ? renderCheckboxes(key, field)(item) : null;
3266
- const renderCheckboxes = (key, field) => (item) => {
3267
- const options = item?.items?.enum?.map((e, i) => ({ value: e, title: item?.items?.enumNames?.[i] || '' })) ||
3268
- [];
3269
- return (jsxs("div", { className: "flex-1", children: [item?.title ? (jsx("div", { className: "mb-m", children: jsx(Text, { size: "text-m", font: "font-medium", color: "text-primary-text", children: item.title }) })) : null, jsx(SlideCheckboxGroup, { items: options, multiple: !item?.single, ...field(key) })] }, key));
3270
- };
3271
-
3272
- function zip(firstCol, ...restCols) {
3273
- return firstCol.map((firstEl, rowIndex) => [firstEl, ...restCols.map((col) => col[rowIndex])]);
3274
- }
3275
-
3276
- const isEmpty = (v) => v === null ||
3277
- v === undefined ||
3278
- v === '' ||
3279
- (Array.isArray(v) && v.length === 0) ||
3280
- (typeof v === 'object' && Object.keys(v).length === 0);
3281
-
3282
- const isSingularFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) || isEmpty(target[key]) || pattern[key] === target[key];
3283
- const isMultipleFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) ||
3284
- isEmpty(target[key]) ||
3285
- pattern[key]?.every((_) => target[key]?.includes(_));
3286
- const isNumberFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) ||
3287
- isEmpty(target[key]) ||
3288
- naturalNumber(pattern[key]) <= naturalNumber(target[key]);
3289
- const isMultipleNumberFieldMatch = (key, pattern) => (target) => isEmpty(pattern[key]) || isEmpty(target[key]) || target[key]?.includes(pattern[key]);
3290
- const isValueInRange = (key, pattern) => (target) => isEmpty(pattern[key]) ||
3291
- isEmpty(target[key]) ||
3292
- (naturalNumber(pattern[key]?.min) >= naturalNumber(target[key]?.min) &&
3293
- naturalNumber(pattern[key]?.min) <= naturalNumber(target[key]?.max));
3294
- const targetMatchPattern = (pattern, target) => Object.entries(pattern)
3295
- .map(([key, subPattern]) => {
3296
- if (typeof subPattern === 'number') {
3297
- return Array.isArray(target[key])
3298
- ? isMultipleNumberFieldMatch(key, pattern)
3299
- : isNumberFieldMatch(key, pattern);
3300
- }
3301
- if (typeof subPattern === 'object' && 'min' in subPattern && 'max' in subPattern) {
3302
- return isValueInRange(key, pattern);
3303
- }
3304
- return Array.isArray(subPattern)
3305
- ? isMultipleFieldMatch(key, pattern)
3306
- : isSingularFieldMatch(key, pattern);
3307
- })
3308
- .every((predicate) => predicate(target));
3309
- const naturalNumber = (n) => Number(n || 0);
3310
-
3311
- const filterBlocks = (blocksWithProps, filtrationState) => (normalize = identity) => blocksWithProps
3312
- ?.filter(([, content]) => targetMatchPattern(filtrationState, normalize(content) || {}))
3313
- .map(([block]) => block);
3314
-
3315
- const useFiltrationForm = (initialFormState, { block, page, normalize = identity, }) => {
3316
- const blocks = block?.blocks || [];
3317
- const [filtrationState, { field, reset, update: replaceFiltrationState }] = useForm(initialFormState);
3318
- const blocksWithProps = useMemo(() => zip(blocks, blocks.map((b) => resolveBlockProps(b.content, page?.fallback))), [blocks, page?.fallback]);
3319
- const blocksToRender = filtrationState === initialFormState
3320
- ? blocks
3321
- : filterBlocks(blocksWithProps, filtrationState)(normalize);
3322
- return [
3323
- filtrationState,
3324
- { blocksToRender, blocksWithProps },
3325
- { field, reset, update: replaceFiltrationState },
3326
- ];
3327
- };
3328
-
3329
3363
  const isRateRow = (rateRow) => {
3330
3364
  return typeof rateRow?.minMonths === 'number' && typeof rateRow?.maxMonths === 'number';
3331
3365
  };
@@ -5380,6 +5414,7 @@
5380
5414
  const Blocks = {
5381
5415
  AdTile,
5382
5416
  ApplicationFormCustom,
5417
+ BankAccountFiltration,
5383
5418
  BenefitsBlock,
5384
5419
  BonusBenefitsBlock,
5385
5420
  ButtonsBlock,
@@ -5607,7 +5642,7 @@
5607
5642
  slots: () => [HEADER_SLOT, FOOTER_SLOT, STICKY_FOOTER_SLOT],
5608
5643
  });
5609
5644
 
5610
- const packageVersion = "0.14.270";
5645
+ const packageVersion = "0.14.271";
5611
5646
 
5612
5647
  exports.Blocks = Blocks;
5613
5648
  exports.ContentPage = ContentPage;