├── .eslintignore
├── .eslintrc.cjs
├── .gitignore
├── .husky
    └── pre-commit
├── .prettierignore
├── .prettierrc
├── README.md
├── app
    ├── favicon.ico
    ├── globals.css
    ├── layout.tsx
    └── page.tsx
├── components.json
├── components
    ├── dropdown
    │   ├── countries.tsx
    │   └── states.tsx
    └── ui
    │   ├── button.tsx
    │   ├── command.tsx
    │   ├── dialog.tsx
    │   ├── popover.tsx
    │   └── scroll-area.tsx
├── data
    ├── countries.json
    └── states.json
├── lib
    ├── store
    │   └── dropdown.ts
    ├── types.ts
    └── utils.ts
├── next.config.js
├── package.json
├── postcss.config.js
├── public
    ├── next.svg
    └── vercel.svg
├── tailwind.config.ts
├── tsconfig.json
├── widgets
    └── country-state.tsx
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
 1 | .next
 2 | next-env.d.ts
 3 | node_modules
 4 | yarn.lock
 5 | package-lock.json
 6 | public
 7 | .vscode
 8 | README.md
 9 | tailwind.config.js
10 | 
11 | ```
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
 1 | module.exports = {
 2 |     root: true,
 3 |     env: {
 4 |         browser: true,
 5 |         es2021: true,
 6 |     },
 7 |     extends: [
 8 |         "plugin:react/recommended",
 9 |         "standard-with-typescript",
10 |         "prettier",
11 |         "airbnb",
12 |         "airbnb-typescript",
13 |         "airbnb/hooks",
14 |         "plugin:@typescript-eslint/recommended",
15 |         "plugin:@typescript-eslint/recommended-requiring-type-checking",
16 |         "plugin:prettier/recommended",
17 |         "plugin:@next/next/recommended",
18 |         "eslint:recommended",
19 |     ],
20 |     globals: {
21 |         Atomics: "readonly",
22 |         SharedArrayBuffer: "readonly",
23 |     },
24 |     parser: "@typescript-eslint/parser",
25 |     overrides: [],
26 |     parserOptions: {
27 |         ecmaFeatures: {
28 |             jsx: true,
29 |         },
30 |         ecmaVersion: "latest",
31 |         sourceType: "module",
32 |         project: "./tsconfig.json",
33 |     },
34 |     plugins: ["react", "@typescript-eslint", "prettier"],
35 |     rules: {
36 |         quotes: "off",
37 |         "@typescript-eslint/quotes": [0],
38 |         "react/function-component-definition": [2, { namedComponents: "arrow-function" }],
39 |         "react/jsx-props-no-spreading": "off",
40 |         "@typescript-eslint/explicit-function-return-type": "off",
41 |         "@typescript-eslint/no-unsafe-member-access": "off",
42 |         "@typescript-eslint/no-unsafe-return": "off",
43 |         "@typescript-eslint/no-unsafe-call": "off",
44 |         "jsx-a11y/anchor-is-valid": "off",
45 |         "@typescript-eslint/no-unsafe-assignment": "off",
46 |         "@typescript-eslint/ban-ts-comment": "off",
47 |         "no-undef": "off",
48 |         "@next/next/no-img-element": "off",
49 |         "no-nested-ternary": "off",
50 |         // Debugging
51 |         "@typescript-eslint/no-explicit-any": "off",
52 |         "no-console": "off",
53 |         "import/extensions": "off",
54 |         "@typescript-eslint/promise-function-async": "off",
55 |         "@typescript-eslint/no-misused-promises": "off",
56 |         "@typescript-eslint/strict-boolean-expressions": "off",
57 |         "no-underscore-dangle": "off",
58 |         "@typescript-eslint/restrict-plus-operands": "off",
59 |         "no-plusplus": "off",
60 |         "react/button-has-type": "off",
61 |         "@typescript-eslint/no-floating-promises": "off",
62 |         "no-mixed-spaces-and-tabs": "off",
63 |         "import/prefer-default-export": "off",
64 |         "react/require-default-props": "off",
65 |         "@typescript-eslint/naming-convention": "off",
66 |         "import/no-extraneous-dependencies": "off",
67 |         "@typescript-eslint/no-unused-vars": ["error"],
68 |     },
69 |     settings: {
70 |         react: {
71 |             version: "18.2.0",
72 |         },
73 |         "import/resolver": {
74 |             node: {
75 |                 extensions: [".js", ".jsx", ".ts", ".tsx"],
76 |             },
77 |         },
78 |     },
79 | };
80 | 
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
 2 | 
 3 | # dependencies
 4 | /node_modules
 5 | /.pnp
 6 | .pnp.js
 7 | .yarn/install-state.gz
 8 | 
 9 | # testing
10 | /coverage
11 | 
12 | # next.js
13 | /.next/
14 | /out/
15 | 
16 | # production
17 | /build
18 | 
19 | # misc
20 | .DS_Store
21 | *.pem
22 | 
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 | 
28 | # local env files
29 | .env*.local
30 | 
31 | # vercel
32 | .vercel
33 | 
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 | 
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | . "$(dirname "$0")/_/husky.sh"
 3 | 
 4 | echo '🏗️👷 Styling, testing and building your project before committing'
 5 | 
 6 | # Check Prettier standards
 7 | yarn format ||
 8 | (
 9 |     echo '🤢🤮🤢🤮 Its FOKING RAW - Your styling looks disgusting. 🤢🤮🤢🤮
10 |             Prettier Check Failed. Run npm run format, add changes and try commit again.';
11 |     false;
12 | )
13 | 
14 | yarn check-format ||
15 | (
16 |     echo '🤢🤮🤢🤮 Its FOKING RAW - Your styling looks disgusting. 🤢🤮🤢🤮
17 |             Prettier Check Failed. Run npm run format, add changes and try commit again.';
18 |     false;
19 | )
20 | 
21 | # Check ESLint Standards
22 | yarn check-lint ||
23 | (
24 |         echo '😤🏀👋😤 Get that weak shit out of here! 😤🏀👋😤
25 |                 ESLint Check Failed. Make the required changes listed above, add changes and try to commit again.'
26 |         false;
27 | )
28 | 
29 | # If everything passes... Now we can commit
30 | echo '🤔🤔🤔🤔... Alright.... Code looks good to me... Trying to build now. 🤔🤔🤔🤔'
31 | 
32 | # Check tsconfig standards
33 | yarn check-types ||
34 | (
35 |     echo '🤡😂❌🤡 Failed Type check. 🤡😂❌🤡
36 |             Are you seriously trying to write that? Make the changes required above.'
37 |     false;
38 | )
39 | 
40 | yarn build ||
41 | (
42 |     echo '❌👷🔨❌ Better call Bob... Because your build failed ❌👷🔨❌
43 |             Next build failed: View the errors above to see why.
44 |     '
45 |     false;
46 | )
47 | 
48 | # If everything passes... Now we can commit
49 | echo '✅✅✅✅ You win this time... I am committing this now. ✅✅✅✅'
50 | 
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .next
2 | next-env.d.ts
3 | node_modules
4 | yarn.lock
5 | package-lock.json
6 | public
7 | .vscode
8 | README.md
9 | 
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
 1 | {
 2 |     "endOfLine": "lf",
 3 |     "htmlWhitespaceSensitivity": "css",
 4 |     "insertPragma": false,
 5 |     "jsxSingleQuote": false,
 6 |     "printWidth": 120,
 7 |     "proseWrap": "always",
 8 |     "quoteProps": "preserve",
 9 |     "requirePragma": false,
10 |     "semi": true,
11 |     "singleQuote": false,
12 |     "tabWidth": 4,
13 |     "trailingComma": "all",
14 |     "useTabs": false,
15 |     "arrowParens": "always",
16 |     "bracketSpacing": true,
17 |     "plugins": ["prettier-plugin-tailwindcss"]
18 | }
19 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with
 2 | [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
 3 | 
 4 | ## Getting Started
 5 | 
 6 | First, run the development server:
 7 | 
 8 | ```bash
 9 | npm run dev
10 | # or
11 | yarn dev
12 | # or
13 | pnpm dev
14 | # or
15 | bun dev
16 | ```
17 | 
18 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
19 | 
20 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
21 | 
22 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and
23 | load Inter, a custom Google Font.
24 | 
25 | ## Learn More
26 | 
27 | To learn more about Next.js, take a look at the following resources:
28 | 
29 | -   [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
30 | -   [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31 | 
32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions
33 | are welcome!
34 | 
35 | ## Deploy on Vercel
36 | 
37 | The easiest way to deploy your Next.js app is to use the
38 | [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme)
39 | from the creators of Next.js.
40 | 
41 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
42 | 
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jayprecode/country-state-dropdown/e9cbc6a2dbc485f9b6110a636b42322715310de8/app/favicon.ico
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 | 
--------------------------------------------------------------------------------
/app/layout.tsx:
--------------------------------------------------------------------------------
 1 | /* -------------------------------------------------------------------------- */
 2 | /*                             External Dependency                            */
 3 | /* -------------------------------------------------------------------------- */
 4 | 
 5 | import React from "react";
 6 | import type { Metadata } from "next";
 7 | import { Inter } from "next/font/google";
 8 | 
 9 | /* -------------------------------------------------------------------------- */
10 | /*                             Internal Dependency                            */
11 | /* -------------------------------------------------------------------------- */
12 | 
13 | import "./globals.css";
14 | 
15 | const inter = Inter({ subsets: ["latin"] });
16 | 
17 | export const metadata: Metadata = {
18 |     title: "Country Dropdown",
19 |     description: "A Country Dropdown",
20 | };
21 | 
22 | const RootLayout = ({ children }: { children: React.ReactNode }) => {
23 |     return (
24 |         
25 |             
{children}
26 |         
27 |     );
28 | };
29 | 
30 | export default RootLayout;
31 | 
--------------------------------------------------------------------------------
/app/page.tsx:
--------------------------------------------------------------------------------
 1 | /* -------------------------------------------------------------------------- */
 2 | /*                             External Dependency                            */
 3 | /* -------------------------------------------------------------------------- */
 4 | import React from "react";
 5 | 
 6 | /* -------------------------------------------------------------------------- */
 7 | /*                             Internal Dependency                            */
 8 | /* -------------------------------------------------------------------------- */
 9 | 
10 | import CountryState from "@/widgets/country-state";
11 | 
12 | const Home = () => {
13 |     return (
14 |         
15 |             
16 |         
17 |     );
18 | };
19 | 
20 | export default Home;
21 | 
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "$schema": "https://ui.shadcn.com/schema.json",
 3 |     "style": "default",
 4 |     "rsc": false,
 5 |     "tsx": true,
 6 |     "tailwind": {
 7 |         "config": "tailwind.config.js",
 8 |         "css": "app/globals.css",
 9 |         "baseColor": "slate",
10 |         "cssVariables": false
11 |     },
12 |     "aliases": {
13 |         "components": "@/components",
14 |         "utils": "@/lib/utils"
15 |     }
16 | }
17 | 
--------------------------------------------------------------------------------
/components/dropdown/countries.tsx:
--------------------------------------------------------------------------------
 1 | "use client";
 2 | 
 3 | /* -------------------------------------------------------------------------- */
 4 | /*                             External Dependency                            */
 5 | /* -------------------------------------------------------------------------- */
 6 | 
 7 | import React from "react";
 8 | import { Check, ChevronsUpDown } from "lucide-react";
 9 | 
10 | /* -------------------------------------------------------------------------- */
11 | /*                             Internal Dependency                            */
12 | /* -------------------------------------------------------------------------- */
13 | 
14 | import { Button } from "@/components/ui/button";
15 | import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
16 | import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command";
17 | import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
18 | 
19 | import { cn, lowerCase } from "@/lib/utils";
20 | import countries from "@/data/countries.json";
21 | 
22 | import { type CountryProps } from "@/lib/types";
23 | import { useDropdownStore } from "@/lib/store/dropdown";
24 | 
25 | interface CountryDropdownProps {
26 |     disabled?: boolean;
27 | }
28 | 
29 | const CountryDropdown = ({ disabled }: CountryDropdownProps) => {
30 |     const { countryValue, setCountryValue, openCountryDropdown, setOpenCountryDropdown } = useDropdownStore();
31 |     const C = countries as CountryProps[];
32 | 
33 |     return (
34 |         
35 |             
36 |                 
59 |             
60 |             
61 |                 
62 |                     
63 |                     No country found.
64 |                     
65 |                         
66 |                             {C.map((country) => (
67 |                                  {
71 |                                         setCountryValue(currentValue === lowerCase(country.name) ? currentValue : "");
72 |                                         setOpenCountryDropdown(false);
73 |                                     }}
74 |                                     className="flex cursor-pointer items-center justify-between text-xs hover:!bg-[#27272a] hover:!text-white"
75 |                                 >
76 |                                     
77 |                                         {country.emoji}
78 |                                         {country.name}
79 |                                     
80 |                                     
86 |                                 
87 |                             ))}
88 |                             
89 |                         
90 |                     
91 |                 
92 |             
93 |         
94 |     );
95 | };
96 | 
97 | export default CountryDropdown;
98 | 
--------------------------------------------------------------------------------
/components/dropdown/states.tsx:
--------------------------------------------------------------------------------
 1 | "use client";
 2 | 
 3 | /* -------------------------------------------------------------------------- */
 4 | /*                             External Dependency                            */
 5 | /* -------------------------------------------------------------------------- */
 6 | 
 7 | import React from "react";
 8 | import { Check, ChevronsUpDown } from "lucide-react";
 9 | 
10 | /* -------------------------------------------------------------------------- */
11 | /*                             Internal Dependency                            */
12 | /* -------------------------------------------------------------------------- */
13 | 
14 | import { Button } from "@/components/ui/button";
15 | import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
16 | import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from "@/components/ui/command";
17 | import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
18 | 
19 | import { cn, lowerCase, sentenceCase } from "@/lib/utils";
20 | import states from "@/data/states.json";
21 | import { useDropdownStore } from "@/lib/store/dropdown";
22 | 
23 | import { type StateProps } from "@/lib/types";
24 | 
25 | const StateDropdown = () => {
26 |     const { countryValue, stateValue, openStateDropdown, setOpenStateDropdown, setStateValue } = useDropdownStore();
27 | 
28 |     const SD = states as StateProps[];
29 |     const S = SD.filter((state) => state.country_name === sentenceCase(countryValue));
30 | 
31 |     return (
32 |         
33 |             
34 |                 
50 |             
51 |             
52 |                 
53 |                     
54 |                     No state found.
55 |                     
56 |                         
57 |                             {S.map((state) => (
58 |                                  {
62 |                                         setStateValue(currentValue === lowerCase(state.name) ? currentValue : "");
63 |                                         setOpenStateDropdown(false);
64 |                                     }}
65 |                                     className="flex cursor-pointer items-center justify-between text-xs hover:!bg-[#27272a] hover:!text-white"
66 |                                 >
67 |                                     
68 |                                         {state.name}
69 |                                     
70 |                                     
76 |                                 
77 |                             ))}
78 |                             
79 |                         
80 |                     
81 |                 
82 |             
83 |         
84 |     );
85 | };
86 | 
87 | export default StateDropdown;
88 | 
--------------------------------------------------------------------------------
/components/ui/button.tsx:
--------------------------------------------------------------------------------
 1 | import * as React from "react";
 2 | import { Slot } from "@radix-ui/react-slot";
 3 | import { cva, type VariantProps } from "class-variance-authority";
 4 | 
 5 | import { cn } from "@/lib/utils";
 6 | 
 7 | const buttonVariants = cva(
 8 |     "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",
 9 |     {
10 |         variants: {
11 |             variant: {
12 |                 default:
13 |                     "bg-slate-900 text-slate-50 hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90",
14 |                 destructive:
15 |                     "bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90",
16 |                 outline:
17 |                     "border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50",
18 |                 secondary:
19 |                     "bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",
20 |                 ghost: "hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50",
21 |                 link: "text-slate-900 underline-offset-4 hover:underline dark:text-slate-50",
22 |             },
23 |             size: {
24 |                 default: "h-10 px-4 py-2",
25 |                 sm: "h-9 rounded-md px-3",
26 |                 lg: "h-11 rounded-md px-8",
27 |                 icon: "h-10 w-10",
28 |             },
29 |         },
30 |         defaultVariants: {
31 |             variant: "default",
32 |             size: "default",
33 |         },
34 |     },
35 | );
36 | 
37 | export interface ButtonProps
38 |     extends React.ButtonHTMLAttributes,
39 |         VariantProps {
40 |     asChild?: boolean;
41 | }
42 | 
43 | const Button = React.forwardRef(
44 |     ({ className, variant, size, asChild = false, ...props }, ref) => {
45 |         const Comp = asChild ? Slot : "button";
46 |         return ;
47 |     },
48 | );
49 | Button.displayName = "Button";
50 | 
51 | export { Button, buttonVariants };
52 | 
--------------------------------------------------------------------------------
/components/ui/command.tsx:
--------------------------------------------------------------------------------
  1 | import * as React from "react";
  2 | import { type DialogProps } from "@radix-ui/react-dialog";
  3 | import { Command as CommandPrimitive } from "cmdk";
  4 | import { Search } from "lucide-react";
  5 | 
  6 | import { cn } from "@/lib/utils";
  7 | import { Dialog, DialogContent } from "@/components/ui/dialog";
  8 | 
  9 | const Command = React.forwardRef<
 10 |     React.ElementRef,
 11 |     React.ComponentPropsWithoutRef & { className?: string }
 12 | >(({ className, ...props }, ref) => (
 13 |     
 21 | ));
 22 | Command.displayName = CommandPrimitive.displayName;
 23 | 
 24 | interface CommandDialogProps extends DialogProps {}
 25 | 
 26 | const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
 27 |     return (
 28 |         
 35 |     );
 36 | };
 37 | 
 38 | const CommandInput = React.forwardRef<
 39 |     React.ElementRef,
 40 |     React.ComponentPropsWithoutRef & { className?: string }
 41 | >(({ className, ...props }, ref) => (
 42 |     // eslint-disable-next-line react/no-unknown-property
 43 |     
 44 |         
 45 |         
 53 |     
 54 | ));
 55 | 
 56 | CommandInput.displayName = CommandPrimitive.Input.displayName;
 57 | 
 58 | const CommandList = React.forwardRef<
 59 |     React.ElementRef,
 60 |     React.ComponentPropsWithoutRef & { className?: string }
 61 | >(({ className, ...props }, ref) => (
 62 |     
 67 | ));
 68 | 
 69 | CommandList.displayName = CommandPrimitive.List.displayName;
 70 | 
 71 | const CommandEmpty = React.forwardRef<
 72 |     React.ElementRef,
 73 |     React.ComponentPropsWithoutRef
 74 | >((props, ref) => );
 75 | 
 76 | CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
 77 | 
 78 | const CommandGroup = React.forwardRef<
 79 |     React.ElementRef,
 80 |     React.ComponentPropsWithoutRef & { className?: string }
 81 | >(({ className, ...props }, ref) => (
 82 |     
 90 | ));
 91 | 
 92 | CommandGroup.displayName = CommandPrimitive.Group.displayName;
 93 | 
 94 | const CommandSeparator = React.forwardRef<
 95 |     React.ElementRef,
 96 |     React.ComponentPropsWithoutRef & { className?: string }
 97 | >(({ className, ...props }, ref) => (
 98 |     
 99 | ));
100 | CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
101 | 
102 | const CommandItem = React.forwardRef<
103 |     React.ElementRef,
104 |     React.ComponentPropsWithoutRef & { className?: string }
105 | >(({ className, ...props }, ref) => (
106 |     
114 | ));
115 | 
116 | CommandItem.displayName = CommandPrimitive.Item.displayName;
117 | 
118 | const CommandShortcut = ({ className, ...props }: React.HTMLAttributes & { className?: string }) => {
119 |     return ;
120 | };
121 | CommandShortcut.displayName = "CommandShortcut";
122 | 
123 | export {
124 |     Command,
125 |     CommandDialog,
126 |     CommandInput,
127 |     CommandList,
128 |     CommandEmpty,
129 |     CommandGroup,
130 |     CommandItem,
131 |     CommandShortcut,
132 |     CommandSeparator,
133 | };
134 | 
--------------------------------------------------------------------------------
/components/ui/dialog.tsx:
--------------------------------------------------------------------------------
 1 | import * as React from "react";
 2 | import * as DialogPrimitive from "@radix-ui/react-dialog";
 3 | import { X } from "lucide-react";
 4 | 
 5 | import { cn } from "@/lib/utils";
 6 | 
 7 | const Dialog = DialogPrimitive.Root;
 8 | 
 9 | const DialogTrigger = DialogPrimitive.Trigger;
10 | 
11 | const DialogPortal = DialogPrimitive.Portal;
12 | 
13 | const DialogClose = DialogPrimitive.Close;
14 | 
15 | const DialogOverlay = React.forwardRef<
16 |     React.ElementRef,
17 |     React.ComponentPropsWithoutRef & { className?: string }
18 | >(({ className, ...props }, ref) => (
19 |     
27 | ));
28 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
29 | 
30 | const DialogContent = React.forwardRef<
31 |     React.ElementRef,
32 |     React.ComponentPropsWithoutRef & { className?: string }
33 | >(({ className, children, ...props }, ref) => (
34 |     
35 |         
36 |         
44 |             {children}
45 |             
46 |                 
47 |                 Close
48 |             
49 |         
50 |     
51 | ));
52 | DialogContent.displayName = DialogPrimitive.Content.displayName;
53 | 
54 | const DialogHeader = ({ className, ...props }: React.HTMLAttributes & { className?: string }) => (
55 |     
56 | );
57 | DialogHeader.displayName = "DialogHeader";
58 | 
59 | const DialogFooter = ({ className, ...props }: React.HTMLAttributes & { className?: string }) => (
60 |     
61 | );
62 | DialogFooter.displayName = "DialogFooter";
63 | 
64 | const DialogTitle = React.forwardRef<
65 |     React.ElementRef,
66 |     React.ComponentPropsWithoutRef & { className?: string }
67 | >(({ className, ...props }, ref) => (
68 |     
73 | ));
74 | DialogTitle.displayName = DialogPrimitive.Title.displayName;
75 | 
76 | const DialogDescription = React.forwardRef<
77 |     React.ElementRef,
78 |     React.ComponentPropsWithoutRef & { className?: string }
79 | >(({ className, ...props }, ref) => (
80 |     
81 | ));
82 | DialogDescription.displayName = DialogPrimitive.Description.displayName;
83 | 
84 | export {
85 |     Dialog,
86 |     DialogPortal,
87 |     DialogOverlay,
88 |     DialogClose,
89 |     DialogTrigger,
90 |     DialogContent,
91 |     DialogHeader,
92 |     DialogFooter,
93 |     DialogTitle,
94 |     DialogDescription,
95 | };
96 | 
--------------------------------------------------------------------------------
/components/ui/popover.tsx:
--------------------------------------------------------------------------------
 1 | import * as React from "react";
 2 | import * as PopoverPrimitive from "@radix-ui/react-popover";
 3 | 
 4 | import { cn } from "@/lib/utils";
 5 | 
 6 | const Popover = PopoverPrimitive.Root;
 7 | 
 8 | const PopoverTrigger = PopoverPrimitive.Trigger;
 9 | 
10 | const PopoverContent = React.forwardRef<
11 |     React.ElementRef,
12 |     React.ComponentPropsWithoutRef & {
13 |         className?: string;
14 |         align?: "start" | "center" | "end";
15 |         sideOffset?: number;
16 |     }
17 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
18 |     
19 |         
29 |     
30 | ));
31 | PopoverContent.displayName = PopoverPrimitive.Content.displayName;
32 | 
33 | export { Popover, PopoverTrigger, PopoverContent };
34 | 
--------------------------------------------------------------------------------
/components/ui/scroll-area.tsx:
--------------------------------------------------------------------------------
 1 | import * as React from "react";
 2 | import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
 3 | 
 4 | import { cn } from "@/lib/utils";
 5 | 
 6 | const ScrollBar = React.forwardRef<
 7 |     React.ElementRef,
 8 |     React.ComponentPropsWithoutRef & {
 9 |         className?: string;
10 |         orientation?: "vertical" | "horizontal";
11 |     }
12 | >(({ className, orientation = "vertical", ...props }, ref) => (
13 |     
24 |         
25 |     
26 | ));
27 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
28 | 
29 | const ScrollArea = React.forwardRef<
30 |     React.ElementRef,
31 |     React.ComponentPropsWithoutRef & { className?: string }
32 | >(({ className, children, ...props }, ref) => (
33 |     
34 |         
35 |             {children}
36 |         
37 |         
38 |         
39 |     
40 | ));
41 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
42 | 
43 | export { ScrollArea, ScrollBar };
44 | 
--------------------------------------------------------------------------------
/lib/store/dropdown.ts:
--------------------------------------------------------------------------------
 1 | import { create } from "zustand";
 2 | 
 3 | interface DropdownStateProps {
 4 |     countryValue: string;
 5 |     setCountryValue: (countries: string) => void;
 6 |     openCountryDropdown: boolean;
 7 |     setOpenCountryDropdown: (openCountry: boolean) => void;
 8 |     stateValue: string;
 9 |     setStateValue: (state: string) => void;
10 |     openStateDropdown: boolean;
11 |     setOpenStateDropdown: (openState: boolean) => void;
12 | }
13 | 
14 | export const useDropdownStore = create((set) => ({
15 |     countryValue: "",
16 |     setCountryValue: (country: string) => {
17 |         set({ countryValue: country });
18 |     },
19 |     openCountryDropdown: false,
20 |     setOpenCountryDropdown: (openCountry: boolean) => {
21 |         set({ openCountryDropdown: openCountry });
22 |     },
23 |     stateValue: "",
24 |     setStateValue: (state: string) => {
25 |         set({ stateValue: state });
26 |     },
27 |     openStateDropdown: false,
28 |     setOpenStateDropdown: (openState: boolean) => {
29 |         set({ openStateDropdown: openState });
30 |     },
31 | }));
32 | 
--------------------------------------------------------------------------------
/lib/types.ts:
--------------------------------------------------------------------------------
 1 | export interface CountryProps {
 2 |     id: number;
 3 |     name: string;
 4 |     iso3: string;
 5 |     iso2: string;
 6 |     numeric_code: string;
 7 |     phone_code: string;
 8 |     capital: string;
 9 |     currency: string;
10 |     currency_name: string;
11 |     currency_symbol: string;
12 |     tld: string;
13 |     native: string;
14 |     region: string;
15 |     region_id: string;
16 |     subregion: string;
17 |     subregion_id: string;
18 |     nationality: string;
19 |     timezones: Timezone[];
20 |     translations: Record;
21 |     latitude: string;
22 |     longitude: string;
23 |     emoji: string;
24 |     emojiU: string;
25 | }
26 | 
27 | interface Timezone {
28 |     zoneName: string;
29 |     gmtOffset: number;
30 |     gmtOffsetName: string;
31 |     abbreviation: string;
32 |     tzName: string;
33 | }
34 | 
35 | export interface StateProps {
36 |     id: number;
37 |     name: string;
38 |     country_id: number;
39 |     country_code: string;
40 |     country_name: string;
41 |     state_code: string;
42 |     type: string | null;
43 |     latitude: string;
44 |     longitude: string;
45 | }
46 | 
--------------------------------------------------------------------------------
/lib/utils.ts:
--------------------------------------------------------------------------------
 1 | import { type ClassValue, clsx } from "clsx";
 2 | import { twMerge } from "tailwind-merge";
 3 | 
 4 | export function cn(...inputs: ClassValue[]) {
 5 |     return twMerge(clsx(inputs));
 6 | }
 7 | 
 8 | // Function to capitalize the first letter
 9 | export const capitalizeFirstLetter = (string: string): string => {
10 |     return string.charAt(0).toUpperCase() + string.slice(1);
11 | };
12 | 
13 | // Function to lowercase the first letter
14 | export const lowercaseFirstLetter = (string: string): string => {
15 |     return string.charAt(0).toLowerCase() + string.slice(1);
16 | };
17 | 
18 | export const sentenceCase = (str: string): string => {
19 |     return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
20 | };
21 | 
22 | export const lowerCase = (str: string): string => {
23 |     return str.charAt(0).toLowerCase() + str.slice(1).toLowerCase();
24 | };
25 | 
26 | export const titleCase = (str: string): string => {
27 |     return str
28 |         .toLowerCase()
29 |         .split(" ")
30 |         .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
31 |         .join(" ");
32 | };
33 | 
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 | 
4 | module.exports = nextConfig;
5 | 
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "name": "country-dropdown",
 3 |     "version": "0.1.0",
 4 |     "private": true,
 5 |     "scripts": {
 6 |         "dev": "next dev",
 7 |         "start": "NODE_OPTIONS=\"--max-old-space-size=4096\" next start",
 8 |         "build": "next build",
 9 |         "compile": "next experimental-compile",
10 |         "generate": "next experimental-generate",
11 |         "build-export": "next build && next export",
12 |         "check-types": "tsc --pretty --noEmit",
13 |         "check-format": "prettier --check .",
14 |         "format": "next lint --fix && prettier '**/*.{js,jsx,json,md,yml,yaml,ts,tsx}' --write --ignore-path .gitignore",
15 |         "check-lint": "eslint . --ext jsx --ext js --ext ts --ext tsx",
16 |         "fix": "eslint --fix .",
17 |         "check-packages": "yarn clean && yarn compile && yarn test && yarn lint",
18 |         "test-all": "yarn check-format && yarn check-lint && yarn check-types && yarn build",
19 |         "prepare": "husky install"
20 |     },
21 |     "dependencies": {
22 |         "@radix-ui/react-dialog": "^1.0.5",
23 |         "@radix-ui/react-popover": "^1.0.7",
24 |         "@radix-ui/react-scroll-area": "^1.0.5",
25 |         "@radix-ui/react-slot": "^1.0.2",
26 |         "class-variance-authority": "^0.7.0",
27 |         "clsx": "^2.0.0",
28 |         "cmdk": "^0.2.0",
29 |         "lucide-react": "^0.298.0",
30 |         "next": "14.0.4",
31 |         "react": "^18",
32 |         "react-dom": "^18",
33 |         "tailwind-merge": "^2.1.0",
34 |         "tailwindcss-animate": "^1.0.7",
35 |         "zustand": "^4.4.7"
36 |     },
37 |     "devDependencies": {
38 |         "@types/node": "^20",
39 |         "@types/react": "^18",
40 |         "@types/react-dom": "^18",
41 |         "autoprefixer": "^10.0.1",
42 |         "eslint": "^8",
43 |         "eslint-config-next": "14.0.4",
44 |         "eslint-config-airbnb": "^19.0.4",
45 |         "eslint-config-airbnb-typescript": "^17.1.0",
46 |         "eslint-config-prettier": "^9.0.0",
47 |         "@next/eslint-plugin-next": "^14.0.0",
48 |         "eslint-config-standard-with-typescript": "^39.1.1",
49 |         "eslint-plugin-import": "^2.29.0",
50 |         "eslint-plugin-jsx-a11y": "^6.7.1",
51 |         "eslint-plugin-n": "^16.2.0",
52 |         "eslint-plugin-prettier": "^5.0.1",
53 |         "eslint-plugin-promise": "^6.1.1",
54 |         "eslint-plugin-react": "^7.33.2",
55 |         "eslint-plugin-react-hooks": "^4.6.0",
56 |         "@typescript-eslint/eslint-plugin": "^6.9.0",
57 |         "@typescript-eslint/parser": "^6.9.0",
58 |         "husky": "^8.0.0",
59 |         "lint-staged": "^15.0.2",
60 |         "prettier": "3.0.3",
61 |         "prettier-plugin-tailwindcss": "^0.5.6",
62 |         "postcss": "^8",
63 |         "tailwindcss": "^3.3.0",
64 |         "typescript": "^5"
65 |     }
66 | }
67 | 
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |     plugins: {
3 |         tailwindcss: {},
4 |         autoprefixer: {},
5 |     },
6 | };
7 | 
--------------------------------------------------------------------------------
/public/next.svg:
--------------------------------------------------------------------------------
1 | 
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 | 
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
 1 | import type { Config } from "tailwindcss";
 2 | 
 3 | const config: Config = {
 4 |     content: [
 5 |         "./pages/**/*.{js,ts,jsx,tsx,mdx}",
 6 |         "./components/**/*.{js,ts,jsx,tsx,mdx}",
 7 |         "./app/**/*.{js,ts,jsx,tsx,mdx}",
 8 |     ],
 9 |     theme: {
10 |         container: {
11 |             center: true,
12 |             padding: "2rem",
13 |             screens: {
14 |                 "2xl": "1400px",
15 |             },
16 |         },
17 |         extend: {
18 |             backgroundImage: {
19 |                 "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
20 |                 "gradient-conic": "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
21 |             },
22 |             keyframes: {
23 |                 "accordion-down": {
24 |                     from: { height: "0" },
25 |                     to: { height: "var(--radix-accordion-content-height)" },
26 |                 },
27 |                 "accordion-up": {
28 |                     from: { height: "var(--radix-accordion-content-height)" },
29 |                     to: { height: "0" },
30 |                 },
31 |             },
32 |             animation: {
33 |                 "accordion-down": "accordion-down 0.2s ease-out",
34 |                 "accordion-up": "accordion-up 0.2s ease-out",
35 |             },
36 |         },
37 |     },
38 |     plugins: [],
39 | };
40 | export default config;
41 | 
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "compilerOptions": {
 3 |         "lib": ["dom", "dom.iterable", "esnext"],
 4 |         "module": "esnext",
 5 |         "moduleResolution": "node",
 6 |         "removeComments": true,
 7 |         "preserveConstEnums": true,
 8 |         "strict": true,
 9 |         "alwaysStrict": true,
10 |         "strictNullChecks": true,
11 |         "noUncheckedIndexedAccess": true,
12 | 
13 |         "noImplicitAny": true,
14 |         "noImplicitReturns": true,
15 |         "noImplicitThis": true,
16 |         "noUnusedLocals": true,
17 |         "noUnusedParameters": true,
18 |         "allowUnreachableCode": false,
19 |         "noFallthroughCasesInSwitch": true,
20 | 
21 |         "target": "es2017",
22 |         "outDir": "out",
23 |         "declaration": true,
24 |         "sourceMap": true,
25 | 
26 |         "esModuleInterop": true,
27 |         "allowSyntheticDefaultImports": true,
28 |         "allowJs": true,
29 |         "checkJs": true,
30 |         "skipLibCheck": true,
31 |         "forceConsistentCasingInFileNames": true,
32 | 
33 |         "jsx": "preserve",
34 |         "noEmit": true,
35 |         "isolatedModules": true,
36 |         "incremental": true,
37 | 
38 |         "baseUrl": ".",
39 |         "allowUnusedLabels": false,
40 |         "pretty": true,
41 |         "resolveJsonModule": true,
42 |         "paths": {
43 |             "@/*": ["./*"]
44 |         },
45 |         "plugins": [
46 |             {
47 |                 "name": "next"
48 |             }
49 |         ]
50 |     },
51 |     "include": [
52 |         "next-env.d.ts",
53 |         "next.config.js",
54 |         "**/*.ts",
55 |         "**/*.tsx",
56 |         ".eslintrc.cjs",
57 |         ".next/types/**/*.ts",
58 |         "postcss.config.js",
59 |         "tailwind.config.ts",
60 |         "lint-staged.config.ts",
61 |         "app/(root)/quests/edit/layout"
62 |     ],
63 |     "exclude": ["node_modules", "dirty"]
64 | }
65 | 
--------------------------------------------------------------------------------
/widgets/country-state.tsx:
--------------------------------------------------------------------------------
 1 | /* -------------------------------------------------------------------------- */
 2 | /*                             External Dependency                            */
 3 | /* -------------------------------------------------------------------------- */
 4 | 
 5 | import React from "react";
 6 | 
 7 | /* -------------------------------------------------------------------------- */
 8 | /*                             Internal Dependency                            */
 9 | /* -------------------------------------------------------------------------- */
10 | 
11 | import CountryDropdown from "@/components/dropdown/countries";
12 | import StateDropdown from "@/components/dropdown/states";
13 | 
14 | const CountryState = () => {
15 |     return (
16 |         
17 |             
18 |             
19 |         
20 |     );
21 | };
22 | 
23 | export default CountryState;
24 | 
--------------------------------------------------------------------------------