UNPKG

@hhgtech/hhg-components

Version:
543 lines (496 loc) • 22.1 kB
import * as React from 'react'; import React__default, { useState, useMemo, useEffect, Fragment } from 'react'; import styled from '@emotion/styled'; import { M as MediaQueries, f as formatUrlWithPageParam } from './utils-538169b3.js'; import { theme } from './miscTheme.js'; import { _ as __rest } from './tslib.es6-00ab44b2.js'; import { L as Label, S as StyledDisplayIcon, a as StyledActionIcon, b as StyledErrorLabel } from './index-5e2dff13.js'; import { domainLocales } from './constantsDomainLocales.js'; import { u as useTranslations } from './index-09d9e570.js'; import { I as Input } from './index-bd44bcb2.js'; import '@mantine/core'; import '@mantine/dates'; import './index-8c40504a.js'; import './index-fe4471f4.js'; import './index-7adf994c.js'; import './index-3f09210d.js'; import './index-0b67696c.js'; import './index-2d25b0f0.js'; import './index-17c85f76.js'; import './index.styles-3adef5f6.js'; import './translationsContext-18f7b7e0.js'; import '@mantine/hooks'; import './index-04505e35.js'; import { C as Close } from './index-72e8c8cf.js'; /* eslint-disable prettier/prettier */ const Search2 = (props) => (React.createElement("svg", Object.assign({ width: "1em", height: "1em", viewBox: "0 0 24 25", fill: "none" }, props), React.createElement("path", { d: "M11 18.957C14.866 18.957 18 15.823 18 11.957C18 8.09104 14.866 4.95703 11 4.95703C7.13401 4.95703 4 8.09104 4 11.957C4 15.823 7.13401 18.957 11 18.957Z", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" }), React.createElement("path", { d: "M20 20.957L16 16.957", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" }))); const StyledCheckbox = styled.div ` display: flex; cursor: pointer; &[data-theme='marryBaby'] { input { width: 20px; height: 20px; border: 1.3px solid ${theme.mbColors.midGray}; border-radius: 9px; cursor: inherit; transition: border-color 0.4s, box-shadow 0.4s; &:hover, &:active { border-color: ${theme.mbColors.cobalt}; box-shadow: 0 0 2px 2px ${theme.mbColors.cobalt}; } &:focus-visible { border: 2px solid ${theme.mbColors.cobalt}; } &:checked { border: 0; background: ${theme.mbColors.cobalt} url("data:image/svg+xml,%3Csvg width='9' height='7' viewBox='0 0 9 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.5 4L3.45455 6L8 1' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A") no-repeat center center; } } label { max-width: 15rem; margin-left: 8px; width: calc(100% - 24px); cursor: inherit; font-weight: 600; font-size: 12px; line-height: 20px; letter-spacing: -0.2px; color: ${theme.mbColors.gray}; } } input { width: 20px; height: 20px; border: solid 1px ${theme.colors.gray500}; border-radius: 2px; cursor: inherit; transition: border-color 0.4s, box-shadow 0.4s; &:hover, &:active { border-color: ${theme.colors.primaryBase}; box-shadow: 0 0 2px 2px ${theme.colors.primary200}; } &:focus-visible { border: 2px solid ${theme.colors.primaryActive}; } &:checked { border: 0; background: ${theme.colors.primaryBase} url("data:image/svg+xml,%3Csvg width='12' height='9' viewBox='0 0 12 9' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 1L4.125 8L1 4.81819' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A") no-repeat center center; } } label { max-width: 15rem; margin-left: 8px; font-weight: ${theme.sizes.fwRegular}; width: calc(100% - 24px); cursor: inherit; ${MediaQueries.mbDown} { font-size: 14px; line-height: 24px; } ${MediaQueries.mbUp} { font-size: 16px; line-height: 22px; } } &[data-is-rectangle] > input { position: relative; width: unset; height: unset; padding: 5px 12px; border: 1px solid ${theme.colors.neutral100}; border-radius: 32px; &::after { color: ${theme.colors.gray800}; content: attr(data-label-text); font-size: 13px; } &:checked { border-color: ${theme.colors.primary50}; &::after { color: ${theme.colors.primaryBase}; } } &:checked { background: ${theme.colors.primary50}; } } &[data-disabled] { color: ${theme.colors.gray300}; cursor: not-allowed; input { border-color: ${theme.colors.gray300}; &:hover { border-color: ${theme.colors.gray300}; box-shadow: none; } } } `; /** * @deprecated Consider to use at '@hhgtech/hhg-components/mantine' */ const Checkbox = ({ label, name, checked, className, isDisabled, onChange, value, isRectangle, inputDataTestId, siteType, }) => { return (React__default.createElement(StyledCheckbox, { className: className, "data-disabled": isDisabled || undefined, "data-is-rectangle": isRectangle || undefined, "data-label-text": label, "data-theme": siteType }, React__default.createElement("input", { type: "checkbox", checked: checked, name: name, onChange: () => onChange(value, !checked), disabled: isDisabled, value: value, id: `${name}-${value}`, "data-label-text": label, "data-testid": inputDataTestId }), !isRectangle && React__default.createElement("label", { htmlFor: `${name}-${value}` }, label))); }; const StyledPagination = styled.div ` display: flex; align-items: center; justify-content: space-between; user-select: none; li { transition: all 0.3s ease; } [data-page-active] { background: ${theme.colors.primaryBase}; color: ${theme.colors.white}; > a { color: ${theme.colors.white}; } } `; const StyledPageBlock = styled.div ` display: flex; width: 32px; height: 32px; box-sizing: border-box; align-items: center; justify-content: center; border: 1px solid ${theme.colors.gray200}; margin: 0 2px; border-radius: 4px; color: ${theme.colors.gray800}; cursor: pointer; font-size: 14px; font-weight: ${theme.sizes.fwBold}; &[data-last-page] { border: none; background-color: ${theme.colors.gray100}; cursor: not-allowed; pointer-events: none; svg { path { stroke: ${theme.colors.gray300}; } } } `; const StyledPaginationBlock = styled.li ` display: flex; width: 32px; height: 32px; align-items: center; justify-content: center; margin: 0 2px; border-radius: 4px; color: ${theme.colors.gray800}; cursor: pointer; font-size: 14px; font-weight: ${theme.sizes.fwBold}; > a { color: ${theme.colors.gray800}; text-decoration: unset; display: block; width: 100%; height: 100%; line-height: 32px; text-align: center; } `; const RenderPagiWithDots = ({ pagesAmount, activePage, handlePageChange, handleClick, href, queryPageName = 'page', }) => { const pages = [...Array(pagesAmount)].map((__v, i) => i + 1); const [visiblePages, setVisiblePages] = useState(activePage <= 4 ? pages.slice(0, 5) : activePage >= pages.length - 3 ? pages.slice(pages.length - 5, pages.length) : pages.slice(activePage - 2, activePage + 1)); useEffect(() => { if (activePage <= 4) { setVisiblePages(pages.slice(0, 5)); } else if (activePage >= pages.length - 3) { setVisiblePages(pages.slice(pages.length - 5, pages.length)); } else { setVisiblePages(pages.slice(activePage - 2, activePage + 1)); } }, [activePage]); return (React__default.createElement(Fragment, null, activePage > 4 && (React__default.createElement(Fragment, null, React__default.createElement(StyledPaginationBlock, { onClick: () => handlePageChange(1) }, href ? (React__default.createElement("a", { href: href, onClick: handleClick }, 1)) : (1)), React__default.createElement(StyledPaginationBlock, null, "..."))), visiblePages.map((i) => (React__default.createElement(StyledPaginationBlock, { key: `${'pagination'}+${i}`, "data-page-active": i === activePage || undefined, onClick: () => handlePageChange(i) }, href ? (React__default.createElement("a", { href: formatUrlWithPageParam(href, i, queryPageName), onClick: handleClick }, i)) : (i)))), activePage < pages.length - 3 && (React__default.createElement(Fragment, null, React__default.createElement(StyledPaginationBlock, null, "..."), React__default.createElement(StyledPaginationBlock, { onClick: () => handlePageChange(pages.length) }, href ? (React__default.createElement("a", { href: formatUrlWithPageParam(href, pages.length, queryPageName), onClick: handleClick }, pages.length)) : (pages.length)))))); }; const Pagination = ({ className, pagesAmount, currentPage, onChange, onClick, style, href: _href, queryPageName = 'page', }) => { const pages = [...Array(pagesAmount)].map((__v, i) => i + 1); const [activePage, setActivePage] = useState(currentPage); const href = useMemo(() => { // Props `href` is updated from the version 1.8.4 and later. Please change the way to use this props properly // - To avoid crash app, transform href for the old way and remove the part &page= // /care/ho-chi-minh/hospital/da-khoa/&page= // -> /care/ho-chi-minh/hospital/da-khoa/ if (_href && _href.endsWith('&page=')) { return _href.replace('&page=', ''); } return _href; }, [_href]); const totalArray = pagesAmount - 1; const handlePageChange = (p) => { if (p <= pagesAmount && p > 0) { setActivePage(p); onChange(p); } }; const handleClick = (e) => { onClick && onClick(e); }; useEffect(() => { setActivePage(currentPage); }, [currentPage]); return (React__default.createElement(StyledPagination, { className: className, style: style }, React__default.createElement(StyledPageBlock, { className: "prev-page", onClick: () => handlePageChange(activePage - 1), "data-last-page": activePage === 1 || undefined }, href ? (React__default.createElement("a", { href: formatUrlWithPageParam(href, activePage, queryPageName), onClick: handleClick }, React__default.createElement("svg", { width: "7", height: "10", viewBox: "0 0 7 10", fill: "none" }, React__default.createElement("path", { d: "M5.5 9L1.5 5L5.5 1", stroke: "#2D87F3", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })))) : (React__default.createElement("svg", { width: "7", height: "10", viewBox: "0 0 7 10", fill: "none" }, React__default.createElement("path", { d: "M5.5 9L1.5 5L5.5 1", stroke: "#2D87F3", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })))), pages.length > 8 ? (React__default.createElement(RenderPagiWithDots, { pagesAmount: pagesAmount, activePage: activePage, handlePageChange: handlePageChange, handleClick: handleClick, href: href, queryPageName: queryPageName })) : (pages.map((i) => (React__default.createElement(StyledPaginationBlock, { key: `${'pagination'}+${i}`, "data-page-active": i === activePage || undefined, onClick: () => handlePageChange(i) }, href ? (React__default.createElement("a", { href: formatUrlWithPageParam(href, i, queryPageName), onClick: handleClick }, i)) : (i))))), React__default.createElement(StyledPageBlock, { className: "next-page", onClick: () => handlePageChange(activePage + 1), "data-last-page": activePage === totalArray + 1 || undefined }, href ? (React__default.createElement("a", { href: formatUrlWithPageParam(href, activePage, queryPageName), onClick: handleClick }, React__default.createElement("svg", { width: "7", height: "10", viewBox: "0 0 7 10", fill: "none" }, React__default.createElement("path", { d: "M1.5 9L5.5 5L1.5 1", stroke: "#2D87F3", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })))) : (React__default.createElement("svg", { width: "7", height: "10", viewBox: "0 0 7 10", fill: "none" }, React__default.createElement("path", { d: "M1.5 9L5.5 5L1.5 1", stroke: "#2D87F3", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })))))); }; const StyledInput$1 = styled.div ` position: relative; width: 100%; &[data-has-error] { input { border-color: ${theme.colors.red700}; } } input { width: 100%; padding: 12px 16px; border: solid 1px ${theme.colors.gray200}; border-radius: ${theme.borderRadius}; &:active, &:focus, .focused & { border-color: ${theme.colors.primaryBase}; box-shadow: 0px 0px 2px 2px ${theme.colors.primary200}; } &:disabled { background-color: ${theme.colors.gray100}; cursor: not-allowed; } } &[data-has-action-icon] { input { padding: 12px 48px 12px 16px; } } &[data-has-display-icon] { input { padding: 12px 16px 12px 48px; } } &[data-has-action-icon][data-has-display-icon] { input { padding: 12px 48px; } } &[data-size='lg'] { input { font-size: 16px; font-weight: ${theme.sizes.fwRegular}; ${MediaQueries.mbDown} { font-size: 22px; line-height: 1.2; } ${MediaQueries.mbUp} { font-size: 26px; line-height: 1.2; } } } &[data-size='md'] { input { font-weight: ${theme.sizes.fwRegular}; ${MediaQueries.mbDown} { font-size: 14px; line-height: 1.2; } ${MediaQueries.mbUp} { font-size: 16px; line-height: 1.2; } } } &[data-size='sm'] { input { font-weight: ${theme.sizes.fwRegular}; ${MediaQueries.mbDown} { font-size: 13px; line-height: 1.5; } ${MediaQueries.mbUp} { font-size: 13px; line-height: 1.5; } } } `; /** * @deprecated Consider to use at '@hhgtech/hhg-components/mantine' */ const PureInput = React__default.forwardRef((_a, ref) => { var { name, errorMessage, autoComplete = 'off', defaultValue, actionIcon: ActionIcon, displayIcon: DisplayIcon, isDeleteAction, onActionClick, label, placeholder, className, onChange, onKeyPress, isDisabled, CustomInput, size, style, autoFocus, type = 'text', isNumerousKeyboard = false, onFocus, enterKeyHint, nativeOnChange } = _a, other = __rest(_a, ["name", "errorMessage", "autoComplete", "defaultValue", "actionIcon", "displayIcon", "isDeleteAction", "onActionClick", "label", "placeholder", "className", "onChange", "onKeyPress", "isDisabled", "CustomInput", "size", "style", "autoFocus", "type", "isNumerousKeyboard", "onFocus", "enterKeyHint", "nativeOnChange"]); const [localValue, setLocalValue] = useState(defaultValue); const handleOnChange = (v) => { setLocalValue(v); onChange(v); }; const handleOnActionClick = () => { var _a; if (isDeleteAction) { setLocalValue(''); (_a = ref.current) === null || _a === void 0 ? void 0 : _a.focus(); } onActionClick && onActionClick(); }; return (React__default.createElement(StyledInput$1, { "data-size": size, className: className, "data-has-action-icon": !!ActionIcon || undefined, "data-has-display-icon": !!DisplayIcon || undefined, "data-has-error": (errorMessage && errorMessage.length > 0) || undefined, style: style }, label && (React__default.createElement(Label, { size: "label2", htmlFor: name, className: "inputLabel" }, label)), React__default.createElement("div", { style: { position: 'relative' } }, CustomInput ? (CustomInput) : (React__default.createElement("input", Object.assign({ id: name, name: name, placeholder: placeholder, onChange: nativeOnChange !== null && nativeOnChange !== void 0 ? nativeOnChange : ((e) => handleOnChange(e.target.value)), onKeyPress: onKeyPress, type: type, "aria-label": type, disabled: isDisabled, value: localValue, autoComplete: autoComplete, ref: ref, autoFocus: autoFocus, inputMode: isNumerousKeyboard || type === 'number' ? 'numeric' : type, pattern: isNumerousKeyboard ? '[0-9]*' : '.*', onFocus: onFocus, enterKeyHint: enterKeyHint }, other))), DisplayIcon && (React__default.createElement(StyledDisplayIcon, { className: "displayIcon" }, DisplayIcon)), ActionIcon && (React__default.createElement(StyledActionIcon, { className: "actionIcon", onClick: handleOnActionClick }, ActionIcon))), errorMessage && errorMessage.length > 0 && (React__default.createElement(StyledErrorLabel, { className: "errorLabel" }, errorMessage)))); }); PureInput.displayName = 'PureInput'; const DEFAULT_DEVICE_SIZES = [ 320, 420, 640, 750, 828, 1080, 1200, 1440, 1920, 2048, ]; const defaultLoader = ({ src, width, quality, locale }) => { try { const baseDomain = typeof window !== 'undefined' ? window.location.origin : domainLocales[locale] ? `https://${domainLocales[locale]}` : ''; if (!baseDomain) { return src; } const url = new URL(src, baseDomain); url.searchParams.set('w', String(width)); url.searchParams.set('q', String(quality !== null && quality !== void 0 ? quality : 75)); return url.toString(); } catch (error) { return src; } }; function getWidths(opts) { if (opts.sizes) return DEFAULT_DEVICE_SIZES; if (opts.width) { const w = Math.max(1, Math.round(opts.width)); return Array.from(new Set([w, Math.min(w * 2, 2048)])).sort((a, b) => a - b); } return DEFAULT_DEVICE_SIZES; } const ImageWrapV2 = (_a) => { var { alt, backupSrc, src, placeholderSrc, style, ref, unoptimized = false, quality, sizes, width } = _a, props = __rest(_a, ["alt", "backupSrc", "src", "placeholderSrc", "style", "ref", "unoptimized", "quality", "sizes", "width"]); const [hasError, setHasError] = useState(false); const { locale = 'vi-VN' } = useTranslations(); const widths = useMemo(() => (unoptimized ? [] : getWidths({ sizes, width })), [sizes, width, unoptimized]); const srcSet = useMemo(() => { if (unoptimized) return undefined; return widths .map((w) => `${defaultLoader({ src, width: w, quality, locale })} ${w}w`) .join(', '); }, [unoptimized, widths, src, quality]); const computedSrc = useMemo(() => { if (unoptimized) return src; // pick the largest width in the set for the base `src` const w = widths.length ? widths[widths.length - 1] : width !== null && width !== void 0 ? width : 1920; return defaultLoader({ src, width: w, quality, locale }); }, [unoptimized, widths, src, quality, width]); return (React__default.createElement(StyledImage, Object.assign({ loading: "lazy", alt: alt, srcSet: srcSet, onError: () => !hasError && setHasError(true), src: hasError ? backupSrc || computedSrc : computedSrc || backupSrc, style: Object.assign(Object.assign({}, (placeholderSrc ? { backgroundImage: `url(${placeholderSrc})`, } : {})), style), "data-has-placeholder": !!placeholderSrc, sizes: sizes, ref: ref }, props))); }; const StyledImage = styled.img ` &[data-has-placeholder='true'] { background-position: center; background-repeat: no-repeat; background-size: cover; } `; const StyledInput = styled(Input) ` box-shadow: 0px 0px 1px 0px #0000000a, 0px 2px 8px 0px #0000000a, 0px 10px 16px 0px #0000000a; border-radius: 0.75rem; overflow: hidden; input.mantine-Input-input { border: none; font-size: 0.8125rem; line-height: 1.25rem; } .close-icon-wrapper { display: none; background-color: ${theme.colors.gray400}; border-radius: 100%; cursor: pointer; width: 20px; height: 20px; padding: 2px; svg { pointer-events: none; } &[data-is-disabled='true'] { opacity: 0.2; cursor: not-allowed; pointer-events: none; } } input.mantine-Input-input:focus ~ .mantine-Input-rightSection .close-icon-wrapper, input.mantine-Input-input:not(:placeholder-shown) ~ .mantine-Input-rightSection .close-icon-wrapper { display: flex; } `; const StyledSearchIcon = styled(Search2) ` color: ${theme.colors.primaryBase}; width: 20px; height: 20px; `; const SearchInput = (props) => { const { loading, disabled, placeholder, value, onChange, icon = React__default.createElement(StyledSearchIcon, null), className, style, enableClear } = props, restProps = __rest(props, ["loading", "disabled", "placeholder", "value", "onChange", "icon", "className", "style", "enableClear"]); const handleChange = (e) => { onChange(e.currentTarget.value); }; const handleClear = () => { onChange(''); }; return (React__default.createElement(StyledInput, Object.assign({ disabled: loading || disabled, size: "lg", value: value, onChangeRaw: handleChange, type: "text", placeholder: placeholder, className: className, icon: icon, style: style, rightSection: enableClear ? (React__default.createElement("div", { className: "close-icon-wrapper", onClick: handleClear, "data-is-disabled": !value }, React__default.createElement(Close, { fill: "white", width: "100%", height: "100%" }))) : undefined }, restProps, { "data-event-label": value }))); }; export { Checkbox as C, ImageWrapV2 as I, Pagination as P, StyledSearchIcon as S, PureInput as a, SearchInput as b, Search2 as c };