@hhgtech/hhg-components
Version:
Hello Health Group common components
543 lines (496 loc) • 22.1 kB
JavaScript
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 };