Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix selection trigger #13

Merged
merged 18 commits into from
May 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/playground.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: playground

on:
push:
branches: [ master ]

jobs:
deploy:
environment:
name: Playground
url: https://playground.typesnippet.org/mui-phone-input
runs-on: ubuntu-latest
steps:
- name: Run deployment script on server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.KEY_ED25519 }}
port: ${{ secrets.PORT }}
script: bash ~/mui-phone-input/examples/deploy.sh
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# MUI Phone Input <img src="https://github.com/typesnippet.png" align="right" height="64" />

[![npm](https://img.shields.io/npm/v/mui-phone-input)](https://www.npmjs.com/package/mui-phone-input)
[![Playground](https://img.shields.io/badge/playground-blue.svg?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNzEzNTE0OTc5MTUzIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE2MjciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0iTTc2OCA1MDYuMDI2NjY3djExLjk0NjY2NmEzMi40MjY2NjcgMzIuNDI2NjY3IDAgMCAxLTE1Ljc4NjY2NyAyNy43MzMzMzRMMzcwLjM0NjY2NyA3NjhjLTIzLjA0IDEzLjY1MzMzMy0zNC45ODY2NjcgMTMuNjUzMzMzLTQ1LjIyNjY2NyA3LjY4bC0xMC42NjY2NjctNS45NzMzMzNhMzIuNDI2NjY3IDMyLjQyNjY2NyAwIDAgMS0xNS43ODY2NjYtMjYuODhWMjgxLjE3MzMzM2EzMi40MjY2NjcgMzIuNDI2NjY3IDAgMCAxIDE1Ljc4NjY2Ni0yNy43MzMzMzNsMTAuNjY2NjY3LTUuOTczMzMzYzEwLjI0LTUuOTczMzMzIDIyLjE4NjY2Ny01Ljk3MzMzMyA1Mi4wNTMzMzMgMTEuNTJsMzc1LjA0IDIxOS4zMDY2NjZhMzIuNDI2NjY3IDMyLjQyNjY2NyAwIDAgMSAxNS43ODY2NjcgMjcuNzMzMzM0eiIgcC1pZD0iMTYyOCIgZGF0YS1zcG0tYW5jaG9yLWlkPSJhMzEzeC5zZWFyY2hfaW5kZXguMC5pMS40NzE5M2E4MVdiYjYyWiIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiI+PC9wYXRoPjwvc3ZnPg==)](https://playground.typesnippet.org/mui-phone-input/)
[![distro](https://img.shields.io/badge/distro-core%20|%20material%20|%20base%20|%20joy-blue)](https://mui.com/)
[![types](https://img.shields.io/npm/types/mui-phone-input)](https://www.npmjs.com/package/mui-phone-input)
[![License](https://img.shields.io/npm/l/mui-phone-input)](https://github.com/typesnippet/mui-phone-input/blob/master/LICENSE)
[![Tests](https://github.com/typesnippet/mui-phone-input/actions/workflows/tests.yml/badge.svg)](https://github.com/typesnippet/mui-phone-input/actions/workflows/tests.yml)

Advanced phone input component for Material UI that leverages the [react-phone-hooks](https://www.npmjs.com/package/react-phone-hooks) supporting all countries. The package is compatible with [@material-ui/core](https://v4.mui.com/), [@mui/material](https://mui.com/), [@mui/base](https://mui.com/base-ui/getting-started/) and [@mui/joy](https://mui.com/joy-ui/getting-started/) distributions. It provides built-in support for area codes and strict validation.
<p>Advanced phone input component for Material UI that leverages the <a href="https://www.npmjs.com/package/react-phone-hooks">react-phone-hooks</a> supporting all countries. The package is compatible with <a href="https://v4.mui.com/">@material-ui/core</a>, <a href="https://mui.com/">@mui/material</a>, <a href="https://mui.com/base-ui/getting-started/">@mui/base</a> and <a href="https://mui.com/joy-ui/getting-started/">@mui/joy</a> distributions. It provides built-in support for area codes and strict validation.</p>

<p align="center">
<a href="https://playground.typesnippet.org/mui-phone-input">
<img src="https://github.com/typesnippet/mui-phone-input/assets/44609997/71a747c1-6682-488c-aa7f-01b47a228f8a" alt="MUI Phone Input"/>
</a>
</p>

## Value

Expand Down Expand Up @@ -76,6 +83,7 @@ Apart from the phone-specific properties described below, all [Input](https://mu
| value | An object containing a parsed phone number or the raw number. | [object](#value) / string |
| country | Country code to be selected by default. By default, it will show the flag of the user's country. | string |
| enableSearch | Enables search in the country selection dropdown menu. Default value is `false`. | boolean |
| searchVariant | Accepts an Input variant, and values depend on the chosen Material distribution. | TextFieldVariants |
| searchNotFound | The value is shown if `enableSearch` is `true` and the query does not match any country. Default value is `No country found`. | string |
| searchPlaceholder | The value is shown if `enableSearch` is `true`. Default value is `Search country`. | string |
| disableDropdown | Disables the manual country selection through the dropdown menu. | boolean |
Expand Down
2 changes: 1 addition & 1 deletion examples/base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@mui/material": "^5.15.1",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"mui-phone-input": "0.1.0-alpha",
"mui-phone-input": "^0.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1",
Expand Down
2 changes: 1 addition & 1 deletion examples/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"@material-ui/core": "^4.12.4",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"mui-phone-input": "0.1.0-alpha",
"mui-phone-input": "^0.1.0",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"react-scripts": "^5.0.1",
Expand Down
16 changes: 16 additions & 0 deletions examples/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash
cd ~/mui-phone-input/
git restore .
git pull

nvm use 18
npm i -g yarn

cd ~/mui-phone-input/examples/material
yarn && yarn build

sudo rm -r /var/www/playground/mui-phone-input/*
sudo mkdir /var/www/playground/mui-phone-input/material
sudo cp -r ~/mui-phone-input/examples/material/build/* /var/www/playground/mui-phone-input/material

sudo service nginx restart
2 changes: 1 addition & 1 deletion examples/joy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"@mui/joy": "^5.0.0-beta.15",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"mui-phone-input": "0.1.0-alpha",
"mui-phone-input": "^0.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1",
Expand Down
5 changes: 4 additions & 1 deletion examples/material/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.17",
"@mui/material": "^5.14.18",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"mui-phone-input": "0.1.0-alpha",
"copy-to-clipboard": "^3.3.3",
"mui-phone-input": "^0.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.4",
"react-scripts": "^5.0.1",
"typescript": "^4.9.5"
},
Expand Down
12 changes: 11 additions & 1 deletion examples/material/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<style>
a {
color: #1677FF !important;
}

*:not(pre) {
font-size: 14px;
font-family: -apple-system, Arial, "Noto Sans", sans-serif !important;
}
</style>
<title>Material UI</title>
</head>
<body>
<div id="root" style="height: 100%;"></div>
<div id="root"></div>
</body>
</html>
235 changes: 222 additions & 13 deletions examples/material/src/Demo.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,239 @@
import {useCallback, useMemo, useState} from "react";
import {Button, Container, CssBaseline} from "@mui/material";
import {createTheme, ThemeProvider} from "@mui/material/styles";

import copy from "copy-to-clipboard";
import {useForm} from "react-hook-form";
import PhoneInput from "mui-phone-input";
import CheckIcon from "@mui/icons-material/Check";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import {createTheme, ThemeProvider} from "@mui/material/styles";
import {checkValidity, parsePhoneNumber} from "react-phone-hooks";
import {
Alert,
Button,
Container,
CssBaseline,
Divider,
FormControlLabel,
IconButton,
Switch,
Typography
} from "@mui/material";

const Demo = () => {
const [mode, setMode] = useState("dark");
const {register, handleSubmit} = useForm();
const [value, setValue] = useState<any>(null);
const [mode, setMode] = useState<string>("light");
const [show, setShow] = useState<boolean>(true);
const [strict, setStrict] = useState<boolean>(false);
const [search, setSearch] = useState<boolean>(false);
const [copied, setCopied] = useState<boolean>(false);
const [preview, setPreview] = useState<boolean>(false);
const [dropdown, setDropdown] = useState<boolean>(true);
const [disabled, setDisabled] = useState<boolean>(false);

const phoneProps = register("phone", {
validate: (value: any) => checkValidity(parsePhoneNumber(value)),
value,
})

const onChange = useCallback((value: any) => {
setPreview(false);
setValue(value);
}, [])

const error = useMemo(() => value?.valid && !value.valid(strict), [value, strict]);

const theme = useMemo(() => createTheme({palette: {mode: mode as any}}), [mode]);

const handleThemeChange = useCallback(() => setMode(mode === "dark" ? "light" : "dark"), [mode]);
const changeTheme = useCallback(() => setMode(mode === "dark" ? "light" : "dark"), [mode]);

const code = useMemo(() => {
let code = "<PhoneInput\n";
if (disabled) code += " disabled\n";
if (search && dropdown) code += " enableSearch\n";
if (!dropdown) code += " disableDropdown\n";
if (code === "<PhoneInput\n") code = "<PhoneInput />";
else code += "/>";
return code;
}, [disabled, search, dropdown])

return (
<ThemeProvider theme={theme}>
<CssBaseline/>
<Container>
<div style={{display: "flex", alignItems: "flex-end", gap: 20}}>
<PhoneInput enableSearch variant="standard"/>
<PhoneInput enableSearch variant="outlined"/>
<Container style={{display: "flex", justifyContent: "center"}}>
<div style={{
minWidth: 425,
maxWidth: 425,
height: "100%",
display: "flex",
margin: "0 20px",
padding: "10px 0",
minHeight: "100vh",
flexDirection: "column",
}}>
<Typography variant="h2" style={{fontWeight: "bold", fontSize: 30, marginBottom: "0.5em"}}>
MUI Phone Input Playground
</Typography>
<Typography style={{fontSize: 14, marginBottom: "1em"}}>
This is a playground for the MUI Phone Input component. You can change the settings and see how
the component behaves. Also, see the code for the component and the value it returns.
</Typography>
<Divider textAlign="left" style={{margin: "16px 0"}}>Settings</Divider>
<div style={{gap: 24, display: "flex", alignItems: "center"}}>
<FormControlLabel
control={<Switch
color="primary"
onChange={changeTheme}
/>}
labelPlacement="start"
style={{margin: 0}}
label="Theme"
/>
<FormControlLabel
control={<Switch
color="primary"
onChange={() => setStrict(!strict)}
/>}
labelPlacement="start"
style={{margin: 0}}
label="Validation"
defaultChecked
/>
<FormControlLabel
control={<Switch
color="primary"
onChange={() => setDisabled(!disabled)}
/>}
labelPlacement="start"
style={{margin: 0}}
label="Disabled"
/>
</div>
<div style={{gap: 24, display: "flex", alignItems: "center"}}>
<FormControlLabel
control={<Switch
color="primary"
disabled={!dropdown}
onChange={() => setSearch(!search)}
/>}
labelPlacement="start"
style={{margin: 0}}
label="Search"
/>
<FormControlLabel
control={<Switch
defaultChecked
color="primary"
onChange={() => setDropdown(!dropdown)}
/>}
labelPlacement="start"
style={{margin: 0}}
label="Dropdown"
/>
</div>
<Divider textAlign="left" style={{margin: "16px 0"}}>Code</Divider>
<div style={{position: "relative"}}>
<IconButton
onClick={() => {
copy(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}}
style={{position: "absolute", background: "transparent", top: 5, right: 5}}
>
{copied ? <CheckIcon color="success" fontSize="small"/> :
<ContentCopyIcon fontSize="small"/>}
</IconButton>
<pre style={{
background: mode === "dark" ? "#1f1f1f" : "#efefef",
color: mode === "dark" ? "#efefef" : "#1f1f1f",
padding: 10, marginTop: 0,
}}>
{code}
</pre>
</div>
<Divider textAlign="left" style={{margin: "16px 0"}}>Component</Divider>
<form onSubmit={handleSubmit(() => null)}
style={{display: "flex", flexDirection: "column", gap: 24}}>
{show && (
<PhoneInput
{...phoneProps}
error={error}
disabled={disabled}
onChange={onChange}
enableSearch={search}
style={{width: "100%"}}
disableDropdown={!dropdown}
/>
)}
{(preview && value && !error) && (
<pre style={{
background: mode === "dark" ? "#1f1f1f" : "#efefef",
color: mode === "dark" ? "#efefef" : "#1f1f1f",
padding: 10, margin: 0,
}}>
{JSON.stringify(value, null, 2)}
</pre>
)}
<div style={{display: "flex", gap: 24, justifyContent: "flex-start"}}>
<Button
type="submit"
variant="contained"
onClick={() => setPreview(true)}
>Preview Value</Button>
<Button
variant="outlined"
onClick={() => {
setValue(null);
setShow(false);
setTimeout(() => setShow(true), 10);
}}
>Reset Value</Button>
</div>
</form>
<Alert icon={false} color="info" style={{marginTop: 24}}>
If your application uses one of <b>@material-ui/core</b>, <b>@mui/base</b> or <b>@mui/joy</b>
&nbsp;distributions of <b>Material UI</b>, you should checkout the&nbsp;
<a target="_blank" rel="noreferrer" style={{textDecoration: "none"}}
href="//github.com/typesnippet/mui-phone-input/tree/master/examples">examples</a> to test the
components out.
</Alert>
<div style={{marginTop: "auto"}}>
<Divider style={{margin: "10px 0"}}/>
<div style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}>
<div>
&copy; Made with ❤️ by&nbsp;
<a href="//github.com/typesnippet" target="_blank"
style={{textDecoration: "none"}} rel="noreferrer author">
TypeSnippet
</a>
</div>
<div style={{display: "flex", gap: 10}}>
<a target="_blank" rel="noreferrer"
href="//github.com/typesnippet/mui-phone-input/blob/master/LICENSE">
<img src="//img.shields.io/npm/l/mui-phone-input" alt="MIT License"/>
</a>
<a href="//www.npmjs.com/package/mui-phone-input" target="_blank" rel="noreferrer">
<img src="//img.shields.io/npm/v/mui-phone-input" alt="NPM Package"/>
</a>
</div>
</div>
<Typography style={{margin: "5px 0 0 0"}}>
Find the&nbsp;
<a href="//github.com/typesnippet/mui-phone-input/tree/master/examples/material"
target="_blank" rel="noreferrer" style={{textDecoration: "none"}}>
source code
</a>
&nbsp;of this playground server on our GitHub repo.
</Typography>
</div>
</div>
<Button onClick={handleThemeChange}>
Change Theme
</Button>
</Container>
</ThemeProvider>
);
)
}

export default Demo;
Loading
Loading