Skip to content

Commit

Permalink
added className overrides, and disabled support
Browse files Browse the repository at this point in the history
  • Loading branch information
replaysMike committed Feb 9, 2024
1 parent 7c26a48 commit d73f0f5
Show file tree
Hide file tree
Showing 12 changed files with 16,603 additions and 888 deletions.
17,241 changes: 16,393 additions & 848 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
{
"name": "react-country-state-dropdown",
"version": "1.0.1",
"version": "1.0.6",
"description": "A country, state, city, and language dropdown for React",
"main": "dist/index.js",
"module": "dist/esm/index.js",
"scripts": {
"build": "babel src -d dist",
"build": "rollup -c",
"start": "rollup -c -w",
"prepublishOnly": "npm run build"
},
"repository": {
Expand Down Expand Up @@ -49,10 +51,18 @@
"@babel/cli": "^7.23.9",
"@babel/plugin-syntax-jsx": "^7.23.3",
"@babel/preset-env": "^7.23.9",
"@babel/preset-react": "^7.23.3"
"@babel/preset-react": "^7.23.3",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-url": "^8.0.2",
"rollup": "^2.79.1",
"rollup-plugin-postcss": "^4.0.2"
},
"dependencies": {
"libphonenumber-js": "^1.10.55",
"react-scripts": "^5.0.1",
"underscore": "^1.13.6"
}
}
31 changes: 31 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import terser from '@rollup/plugin-terser';
import url from '@rollup/plugin-url';
import postcss from 'rollup-plugin-postcss';
import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import pkg from './package.json' with { type: "json" };

export default {
input: 'src/index.js',
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true,
},
{
file: pkg.module,
format: 'esm',
sourcemap: true
}
],
plugins: [
terser(),
url(),
postcss(),
babel({
exclude: 'node_modules/**'
}),
],
};
30 changes: 25 additions & 5 deletions src/CityDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ const CityDropdown = ({
allowFreeFormText,
/** true to disable the control */
disabled,
/** add classes to the rcsd-dropdown */
className = '',
/** add classes to the rcsd-input */
inputContainerClassName = '',
/** add classes to the input element */
inputClassName = '',
/** add classes to the menu */
menuClassName = '',
/** add classes to the items container */
itemsClassName = '',
/** add classes to the item */
itemClassName = '',
/** add classes to the prioritized items container */
prioritizedClassName = '',
...rest
}) => {

Expand Down Expand Up @@ -164,16 +178,22 @@ const CityDropdown = ({
emptyLabel={emptyLabel}
allowFreeFormText={allowFreeFormText}
searchable={searchable}
disabled={disabled}
inputContainerClassName={inputContainerClassName}
inputClassName={inputClassName}
menuClassName={menuClassName}
itemsClassName={itemsClassName}
itemClassName={itemClassName}
{...rest}
onRenderEmpty={() => selectedCountry ? (selectedState ? emptyLabel : noStateLabel) : noCountryLabel }
onRenderMenu={(itemRenderer, selected, isFiltered, striped, handleItemSelect) => {
return <div className='menu'>
<div className={`items${striped ? ' striped' : ''}`}>
{!isFiltered && prioritizedCities && prioritizedCities.length > 0 && <div className='prioritized'>
return <div className={`menu ${menuClassName}`}>
<div className={`items${striped ? ' striped' : ''} ${itemsClassName}`}>
{!isFiltered && prioritizedCities && prioritizedCities.length > 0 && <div className={`prioritized ${prioritizedClassName}`}>
{prioritizedCities.map((option, key) => (
<div
key={key}
className={`item${option === selected ? ' selected' : ''}`}
className={`item${option === selected ? ' selected' : ''} ${itemClassName}`}
data-id={option.id}
data-countryid={selectedCountry.id}
data-country={selectedCountry.iso2}
Expand All @@ -192,7 +212,7 @@ const CityDropdown = ({
onRenderItem={(key, option, selected, isFiltered, handleItemSelect) => {
const output = (<div
key={key}
className={`item${option === selected ? ' selected' : ''}`}
className={`item${option === selected ? ' selected' : ''} ${itemClassName}`}
role="option"
aria-checked={selected ? 'true' : 'false'}
aria-selected={selected ? 'true' : 'false'}
Expand Down
34 changes: 27 additions & 7 deletions src/CountryDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Dropdown from "./Dropdown";
import { data_countries } from "./data/countries";
import { getCountry } from "./Utils";
import _ from 'underscore';
import "./flags.css";

/**
* Country dropdown component
Expand Down Expand Up @@ -39,6 +38,20 @@ const CountryDropdown = ({
allowFreeFormText,
/** true to disable the control */
disabled,
/** add classes to the rcsd-dropdown */
className,
/** add classes to the rcsd-input */
inputContainerClassName = '',
/** add classes to the input element */
inputClassName = '',
/** add classes to the menu */
menuClassName = '',
/** add classes to the items container */
itemsClassName = '',
/** add classes to the item */
itemClassName = '',
/** add classes to the prioritized items container */
prioritizedClassName = '',
...rest
}) => {

Expand Down Expand Up @@ -101,10 +114,17 @@ const CountryDropdown = ({
emptyLabel={emptyLabel}
allowFreeFormText={allowFreeFormText}
searchable={searchable}
className={className}
disabled={disabled}
inputContainerClassName={inputContainerClassName}
inputClassName={inputClassName}
menuClassName={menuClassName}
itemsClassName={itemsClassName}
itemClassName={itemClassName}
{...rest}
onRenderInput={(option, ref, value, placeHolder, onChangeHandler) => {
return (<div className='wrapped-input'>{showFlags && option && <i className={`${option.iso2.toLowerCase()} flag`} />}<input
className={`dropdown`}
className={`dropdown ${inputClassName}`}
aria-autocomplete="list"
autoComplete="new-password"
onChange={onChangeHandler}
Expand All @@ -115,13 +135,13 @@ const CountryDropdown = ({
/></div>)
}}
onRenderMenu={(itemRenderer, selected, isFiltered, striped, handleItemSelect) => {
return <div className='menu'>
<div className={`items${striped ? ' striped' : ''}`}>
{!isFiltered && prioritizedCountries && prioritizedCountries.length > 0 && <div className='prioritized'>
return <div className={`menu ${menuClassName}`}>
<div className={`items${striped ? ' striped' : ''} ${itemsClassName}`}>
{!isFiltered && prioritizedCountries && prioritizedCountries.length > 0 && <div className={`prioritized ${prioritizedClassName}`}>
{prioritizedCountries.map((option, key) => (
<div
key={key}
className={`item${option === selected ? ' selected' : ''}`}
className={`item${option === selected ? ' selected' : ''} ${itemClassName}`}
data-id={option.id}
data-iso2={option.iso2}
data-iso3={option.iso3}
Expand All @@ -140,7 +160,7 @@ const CountryDropdown = ({
onRenderItem={(key, option, selected, isFiltered, handleItemSelect) => {
const output = (<div
key={key}
className={`item${option === selected ? ' selected' : ''}`}
className={`item${option === selected ? ' selected' : ''} ${itemClassName}`}
role="option"
aria-checked={selected ? 'true' : 'false'}
aria-selected={selected ? 'true' : 'false'}
Expand Down
31 changes: 25 additions & 6 deletions src/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ const Dropdown = ({
allowFreeFormText,
/** true to disable the control */
disabled,
/** add classes to the rcsd-dropdown */
className = '',
/** add classes to the rcsd-input */
inputContainerClassName = '',
/** add classes to the input element */
inputClassName = '',
/** add classes to the menu */
menuClassName = '',
/** add classes to the items container */
itemsClassName = '',
/** add classes to the item */
itemClassName = '',
...rest
}) => {

Expand All @@ -49,6 +61,8 @@ const Dropdown = ({
const inputRef = useRef(null);

const globalClickHandler = useCallback((e) => {
if (disabled) return;

if (isFiltered) {
if (!allowFreeFormText) {
// reset filtering
Expand All @@ -65,7 +79,7 @@ const Dropdown = ({
if (inputRef.current && !inputRef.current.contains(e.target)) {
setMenuIsOpen(false);
}
}, [isFiltered, allowFreeFormText, internalValue]);
}, [isFiltered, allowFreeFormText, internalValue, disabled]);

useEffect(() => {
window.addEventListener("click", globalClickHandler);
Expand All @@ -88,6 +102,8 @@ const Dropdown = ({
}, [value, internalOptions]);

const handleInputClick = () => {
if (disabled) return;

setMenuIsOpen(!menuIsOpen);
};

Expand All @@ -103,6 +119,7 @@ const Dropdown = ({
else {
setInternalOptionsFiltered(internalOptions);
setIsFiltered(false);

if (onChange) onChange(e, '');
}
}
Expand All @@ -118,23 +135,25 @@ const Dropdown = ({
};

const handleClear = (e) => {
if (disabled) return;
setInternalSelectedItem(null);
setInternalValue('');
setInternalOptionsFiltered(internalOptions);
setIsFiltered(false);

if (onChange) onChange(e, null);
};

const renderMenuInternal = () => {
if (onRenderMenu) return onRenderMenu(renderItemInternal, internalSelectedItem, isFiltered, striped, handleItemSelect);
return (<div className='menu'><div className={`items${striped ? ' striped' : ''}`}>{renderItemInternal()}</div></div>);
return (<div className={`menu ${menuClassName}`}><div className={`items${striped ? ' striped' : ''} ${itemsClassName}`}>{renderItemInternal()}</div></div>);
};

const renderItemInternal = () => {
if (internalOptionsFiltered && internalOptionsFiltered.length > 0) {
return internalOptionsFiltered.map((option, key) => (onRenderItem && onRenderItem(key, option, internalSelectedItem, isFiltered, handleItemSelect)
|| (<div
className={`item${option === internalSelectedItem ? ' selected' : ''}`}
className={`item${option === internalSelectedItem ? ' selected' : ''} ${itemClassName}`}
role="option"
aria-checked={internalSelectedItem}
aria-selected={internalSelectedItem}
Expand All @@ -148,7 +167,7 @@ const Dropdown = ({
const renderInputInternal = () => {
if (onRenderInput) return onRenderInput(internalSelectedItem, searchRef, internalValue, placeHolder, handleTextInputChange);
return <input
className={`dropdown`}
className={`dropdown ${inputClassName}`}
aria-autocomplete="list"
autoComplete="new-password"
onChange={handleTextInputChange}
Expand All @@ -160,8 +179,8 @@ const Dropdown = ({
};

return (
<div className='rcsd rcsd-dropdown'>
<div className='rcsd-input' ref={inputRef} onClick={handleInputClick} {...rest}>
<div className={`rcsd rcsd-dropdown${disabled ? ' disabled' : ''} ${className}`} {...rest}>
<div className={`rcsd-input ${inputContainerClassName}`} ref={inputRef} onClick={handleInputClick}>
{renderInputInternal()}
{clearable && internalSelectedItem && <i aria-hidden="true" className="clear" onClick={handleClear} />}
<i aria-hidden="true" className="icon" />
Expand Down
30 changes: 25 additions & 5 deletions src/LanguageDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ const LanguageDropdown = ({
allowFreeFormText,
/** true to disable the control */
disabled,
/** add classes to the rcsd-dropdown */
className = '',
/** add classes to the rcsd-input */
inputContainerClassName = '',
/** add classes to the input element */
inputClassName = '',
/** add classes to the menu */
menuClassName = '',
/** add classes to the items container */
itemsClassName = '',
/** add classes to the item */
itemClassName = '',
/** add classes to the prioritized items container */
prioritizedClassName = '',
...rest
}) => {

Expand Down Expand Up @@ -94,15 +108,21 @@ const LanguageDropdown = ({
emptyLabel={emptyLabel}
allowFreeFormText={allowFreeFormText}
searchable={searchable}
disabled={disabled}
inputContainerClassName={inputContainerClassName}
inputClassName={inputClassName}
menuClassName={menuClassName}
itemsClassName={itemsClassName}
itemClassName={itemClassName}
{...rest}
onRenderMenu={(itemRenderer, selected, isFiltered, striped, handleItemSelect) => {
return <div className='menu'>
<div className={`items${striped ? ' striped' : ''}`}>
{!isFiltered && prioritizedLanguages && prioritizedLanguages.length > 0 && <div className='prioritized'>
return <div className={`menu ${menuClassName}`}>
<div className={`items${striped ? ' striped' : ''} ${itemsClassName}`}>
{!isFiltered && prioritizedLanguages && prioritizedLanguages.length > 0 && <div className={`prioritized ${prioritizedClassName}`}>
{prioritizedLanguages.map((option, key) => (
<div
key={key}
className={`item${option === selected ? ' selected' : ''}`}
className={`item${option === selected ? ' selected' : ''} ${itemClassName}`}
data-id={option.id}
data-code={option.code}
onClick={(e) => handleItemSelect(e, option)}
Expand All @@ -116,7 +136,7 @@ const LanguageDropdown = ({
onRenderItem={(key, option, selected, isFiltered, handleItemSelect) => {
const output = (<div
key={key}
className={`item${option === selected ? ' selected' : ''}`}
className={`item${option === selected ? ' selected' : ''} ${itemClassName}`}
role="option"
aria-checked={selected ? 'true' : 'false'}
aria-selected={selected ? 'true' : 'false'}
Expand Down
Loading

0 comments on commit d73f0f5

Please sign in to comment.