[
  {
    "path": ".changeset/README.md",
    "content": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works\nwith multi-package repos, or single-package repos to help you version and publish your code. You can\nfind the full documentation for it [in our repository](https://github.com/changesets/changesets)\n\nWe have a quick list of common questions to get you started engaging with this project in\n[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)\n"
  },
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@3.1.1/schema.json\",\n  \"changelog\": false,\n  \"commit\": false,\n  \"fixed\": [[\"react-img-mapper\"]],\n  \"linked\": [],\n  \"access\": \"public\",\n  \"baseBranch\": \"master\",\n  \"updateInternalDependencies\": \"patch\",\n  \"ignore\": []\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Project files\n.gitattributes text eol=lf\n.gitignore text eol=lf\n.npmrc text eol=lf\n.nvmrc text eol=lf\n.prettierignore text eol=lf\n\n# Global text-based files\n*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,json,yaml,yml,sh,md,txt} text eol=lf\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "* @NishargShah"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1.bug.yml",
    "content": "name: Bug report 🐛\ndescription: Create a bug report\nassignees:\n  - NishargShah\nlabels:\n  - new\n  - bug\nbody:\n  - type: markdown\n    attributes:\n      value: Thanks for contributing by creating an issue! ❤️\n  - type: textarea\n    attributes:\n      label: Steps to reproduce\n      description: |\n        **⚠️ Issues that we can't reproduce can't be fixed.**\n\n        Please provide the steps to reproduce the behavior:\n      value: |\n        Steps:\n        1. Go to '...'\n        2. Click on '....'\n        3. Scroll down to '....'\n        4. See error\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Current behavior\n      description: Describe what happens instead of the expected behavior.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Expected behavior\n      description: Describe what should happen.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Context\n      description: What are you trying to accomplish? Providing context helps us come up with a solution that is more useful in the real world.\n  - type: textarea\n    attributes:\n      label: Error stack\n      description: Please provide the error stack of your error\n  - type: input\n    attributes:\n      label: Live example link\n      description: Please provide a link to a live example, you can use codesandbox/stackblitz for that\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Your environment\n      description: Please provide your desktop & smartphone environment if applicable\n      value: |\n        Desktop\n\n        - OS: [e.g. ubuntu]\n        - Browser: [e.g. chrome, safari]\n        - Version: [e.g. 22.04]\n\n        Smartphone\n\n        - Device: [e.g. samsung 24]\n        - OS: [e.g. Android 15]\n        - Browser: [e.g. chrome, safari]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2.feature.yml",
    "content": "name: Feature request 🚀\ndescription: Suggest an idea for this project\nassignees:\n  - NishargShah\nlabels:\n  - new\n  - enhancement\nbody:\n  - type: markdown\n    attributes:\n      value: Thanks for contributing by creating an issue! ❤️\n  - type: textarea\n    attributes:\n      label: Is your feature request related to a problem?\n      description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Describe the solution you'd like\n      description: A clear and concise description of what you want to happen.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Describe alternatives you've considered\n      description: A clear and concise description of any alternative solutions or features you've considered.\n  - type: textarea\n    attributes:\n      label: Context\n      description: Add any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!-- DO NOT IGNORE THE TEMPLATE!\n\nThank you for contributing!\n\nPlease fill out all fields below and make sure each item is true and [x] checked.\nOtherwise we may not be able to review your PR.\n\n-->\n\n## PR Checklist\n\n- [ ] Checked that there isn't already a PR that solves the problem the same way to avoid creating a\n      duplicate.\n- [ ] Provided a description in this PR that addresses **what** the PR is solving, or reference the\n      issue that it solves (e.g. `fixes #000`).\n\n### Description\n\n<!-- Please insert your description here and provide especially info about the \"what\" this PR is solving -->\n\n### Linked Issues\n\n<!-- Please insert linked issues -->\n\n### Additional context\n\n<!-- e.g. is there anything you'd like reviewers to focus on? -->\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 14\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 7\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - pinned\n  - security\n# Label to use when marking an issue as stale\nstaleLabel: wontfix\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n"
  },
  {
    "path": ".github/workflows/validate-pr.yml",
    "content": "name: Validate Pull Request\npermissions:\n  contents: read\n\non:\n  pull_request:\n    branches:\n      - master\n      - canary\n\njobs:\n  validate_pr:\n    name: Validating Pull Request\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Install PNPM\n        uses: pnpm/action-setup@v4\n        with:\n          run_install: false\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version-file: '.nvmrc'\n          cache: 'pnpm'\n\n      - name: Install dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Build Project\n        run: pnpm build\n\n      - name: Checking Linting\n        run: pnpm --silent script:lint --for=ci\n"
  },
  {
    "path": ".gitignore",
    "content": "# dependencies\nnode_modules\n.pnp\n.pnp.js\n\n# testing\ncoverage\n\n# production\nbuild\ndist\ncache\n\n# misc\n.DS_Store\n*.pem\n\n# debug\n*.log\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\nnext-env.d.ts\n\n# editor folders\n.idea\n.vscode\n\n# vite\n.vite\n\n# storybook\nstorybook-static\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "pnpm lint-staged\n"
  },
  {
    "path": ".husky/pre-push",
    "content": "pnpm --silent script:lint --for=check\n"
  },
  {
    "path": ".npmrc",
    "content": "script-shell=bash\nengine-strict=true\n"
  },
  {
    "path": ".nvmrc",
    "content": "24\n"
  },
  {
    "path": ".prettierignore",
    "content": "pnpm-lock.yaml\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## 2.1.0 (2025-10-00)\n\n### 🚨 Breaking Change\n\n- Introduce `vue-img-mapper` package.\n- **react-img-mapper:** ESM is by default.\n\n### 🚀 Features\n\n- **examples:** Added Vue Code support.\n\n## 2.0.3 (2025-10-23)\n\n### 🚀 Features\n\n- **docs:** Introduce official documentation of `img-mapper`.\n- **react-img-mapper:** Introduce playground for contributors.\n\n### 🩹 Fixes\n\n- Contribution guidelines added.\n- **examples:** Examples descriptions changed.\n\n## 2.0.2 (2025-10-19)\n\n### 🚀 Features\n\n- **react-img-mapper:** Added ESM support.\n\n### 🩹 Fixes\n\n- **react-img-mapper:** Required `ref` issue fixed.\n\n## 2.0.1 (2025-10-18)\n\n### 🚨 Breaking Change\n\n- Monorepo introduced.\n- Repository renamed from `react-img-mapper` to `img-mapper`.\n\n### 🚀 Features\n\n- **react-docs:** Upgrade storybook to latest and improve the code.\n\n### 🩹 Fixes\n\n- **react-img-mapper:** Fixed #96 issue.\n\n### ❤️ Thank You\n\n- @sheepysheepy\n\n## 2.0.0 (2025-01-26)\n\n### 🚨 Breaking Change\n\n- **react-img-mapper:** Wrote a library from scratch.\n- **react-img-mapper:** `map.name` prop changed to `name`.\n- **react-img-mapper:** `map.areas` prop changed to `areas`.\n- **react-img-mapper:** `containerRef` prop removed, you can directly use `ref` instead.\n- **react-img-mapper:** `stayHighlighted` prop changed to `isMulti: false`.\n- **react-img-mapper:** `stayMultiHighlighted` prop changed to `isMulti: true`.\n- **react-img-mapper:** `toggleHighlighted` prop changed to `toggle: true`.\n- **react-img-mapper:** `rerenderProps` prop removed.\n- **react-img-mapper:** `clearHighlightedArea` method removed.\n- **react-img-mapper:** Typescript types are changed.\n  - `MapAreas` changed to `MapArea`.\n  - `CustomArea` changed to `Area`.\n\n### 🚀 Features\n\n- **react-img-mapper:** React 19 upgrade added.\n- **react-img-mapper:** Converted non-controllable manner functionality to a controllable manner.\n- **react-img-mapper:** Typescript Reformatted.\n- **react-img-mapper:** New Utilities files added.\n- **react-img-mapper:** Removed `yarn` and added `pnpm`.\n\n### 🩹 Fixes\n\n- **react-img-mapper:** Fixed #66 issue.\n- **react-img-mapper:** Fixed #76 issue.\n- **react-img-mapper:** Fixed #83 issue.\n\n### ❤️ Thank You\n\n- Ethan Carlson @ethan-carlson\n- Melih Çoban @melihcoban\n- @sheepysheepy\n\n## 1.5.0 (2023-02-14)\n\n### 🚨 Breaking Change\n\n- **react-img-mapper:** Fully Compatible with Next.js.\n\n### 🚀 Features\n\n- **react-img-mapper:** Added different classnames for highlighted areas.\n  - The highlighted area will have `img-mapper-area-highlighted` classname in their area tag.\n- **react-img-mapper:** Upgrade to React V18 Peer Dep.\n\n### 🩹 Fixes\n\n- **react-img-mapper:** Removed the previously highlighted area when you click on the new highlighted area when stayHighlighted is applied (https://github.com/img-mapper/react-img-mapper/issues/53).\n- **react-img-mapper:** Area JSON preFillColor will not remove when the toggleHighlighted property is applied.\n- **react-img-mapper:** Fixed infinity coords issue (https://github.com/img-mapper/react-img-mapper/issues/42).\n- **react-img-mapper:** Fixed canvas height and width issue (https://github.com/img-mapper/react-img-mapper/issues/43).\n\n### ❤️ Thank You\n\n- Anders Weinstein @andersweinstein\n- Alba Mateos @albmat\n- GAURAV YADAV @DVGY\n\n## 1.4.0 (2022-03-06)\n\n### 🩹 Fixes\n\n- **react-img-mapper:** Resolved `onLoad` issue for Next.js.\n\n## 1.3.0\n\n### ⚠️ Deprecated\n\n## 1.2.0 (2021-07-12)\n\n### 🚀 Features\n\n- **react-img-mapper:** Compatible with CommonJS.\n\n## 1.1.0 (2021-03-29)\n\n### 🚀 Features\n\n- **react-img-mapper:** Added Disabled Property in Area.\n- **react-img-mapper:** Added Disabled and Active Properties In JSON example.\n\n## 1.0.0 (2021-03-21)\n\n### 🚨 Breaking Change\n\n- **react-img-mapper:** Built in TypeScript.\n\n## 0.5.0 (2021-02-13)\n\n### 🚨 Breaking Change\n\n- Shifted to new organization `img-mapper`.\n\n### 🚀 Features\n\n- **react-docs:** Added every property & method example with the code in documentation.\n- **react-img-mapper:** Removed Documentation from the package and shifted to another repo.\n\n## 0.4.0 (2021-01-23)\n\n### 🚀 Features\n\n- **react-docs:** Storybook documentation added.\n\n### 🩹 Fixes\n\n- **react-img-mapper:** Internal bugs fixed.\n\n## 0.3.0 (2021-01-22)\n\n### 🚀 Features\n\n- **react-img-mapper:** Added highlighted map after clicking on the image.\n- **react-img-mapper:** Added a responsive image mapper.\n- **react-img-mapper:** Added Image Reference in Width, Height, and onLoad function to access image properties.\n- **react-img-mapper:** Added rerenderProps prop.\n\n## 0.2.0 (2021-01-10)\n\n### 🚀 Features\n\n- **react-img-mapper:** Added Natural Dimensions options ( For Network Image ).\n- **react-img-mapper:** Added Babel & ESLint in the example folder, for better formatting and creating compiled files.\n\n## 0.1.0 (2021-01-10)\n\n### 🚀 Features\n\n- **react-img-mapper:** Decreased size of bundled.\n- **react-img-mapper:** Compatible for NPM.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our community a\nharassment-free experience for everyone, regardless of age, body size, visible or invisible\ndisability, ethnicity, sex characteristics, gender identity and expression, level of experience,\neducation, socio-economic status, nationality, personal appearance, race, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and\nhealthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our community include:\n\n- Demonstrating empathy and kindness toward other people\n- Being respectful of differing opinions, viewpoints, and experiences\n- Giving and gracefully accepting constructive feedback\n- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the\n  experience\n- Focusing on what is best not just for us as individuals, but for the overall community\n\nExamples of unacceptable behavior include:\n\n- The use of sexualized language or imagery, and sexual attention or advances of any kind\n- Trolling, insulting or derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or email address, without their\n  explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of acceptable behavior\nand will take appropriate and fair corrective action in response to any behavior that they deem\ninappropriate, threatening, offensive, or harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject comments, commits,\ncode, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and\nwill communicate reasons for moderation decisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when an individual is\nofficially representing the community in public spaces. Examples of representing our community\ninclude using an official e-mail address, posting via an official social media account, or acting as\nan appointed representative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community\nleaders responsible for enforcement at nishargshah3101@gmail.com. All complaints will be reviewed\nand investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the reporter of any\nincident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining the consequences for\nany action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or\nunwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing clarity around the\nnature of the violation and an explanation of why the behavior was inappropriate. A public apology\nmay be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of actions.\n\n**Consequence**: A warning with consequences for continued behavior. No interaction with the people\ninvolved, including unsolicited interaction with those enforcing the Code of Conduct, for a\nspecified period of time. This includes avoiding interactions in community spaces as well as\nexternal channels like social media. Violating these terms may lead to a temporary or permanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including sustained inappropriate\nbehavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public communication with the\ncommunity for a specified period of time. No public or private interaction with the people involved,\nincluding unsolicited interaction with those enforcing the Code of Conduct, is allowed during this\nperiod. Violating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community standards, including\nsustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement\nof classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nPlease refer [Contributing](https://img-mapper.nishargshah.dev/contribute/guide).\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2025 Nisharg Shah\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img src=\"https://img-mapper.nishargshah.dev/logo.png\" width=\"200\" style=\"border-radius: 40px;\">\n</p>\n\n<h1 align=\"center\">Img Mapper</h1>\n\n<p align=\"center\">\n  <a style=\"text-decoration:none\" href=\"https://img-mapper.nishargshah.dev\">Documentation</a> |\n  <a href=\"https://img-mapper-examples.nishargshah.dev\">Examples</a> |\n  <a href=\"https://img-mapper.nishargshah.dev/contribute/guide\">Contributing</a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/react-img-mapper\"><img src=\"https://img.shields.io/npm/v/react-img-mapper?style=flat&labelColor=ffffff&color=00acc1\" alt=\"npm version\"></a>\n  <a href=\"https://www.npmjs.com/package/react-img-mapper\"><img src=\"https://img.shields.io/npm/dm/react-img-mapper?style=flat&labelColor=ffffff&color=00acc1\" alt=\"npm downloads\"></a>\n  <a href=\"https://www.npmjs.com/package/react-img-mapper\"><img src=\"https://img.shields.io/npm/last-update/react-img-mapper?style=flat&labelColor=ffffff&color=00acc1\" alt=\"npm last updated\"></a>\n</p>\n\nLibraries for Creating Interactive and Highlighted Zones on Images.\n\n- **`react-img-mapper`**: A React component that lets you define, highlight, and interact with custom zones on images.\n- **`vue-img-mapper`**: A Vue component offering the same interactive image mapping and highlighting capabilities.\n\n## License\n\nThis project is licensed under the [MIT License](https://opensource.org/licenses/mit-license.php).\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nIf you discover a security vulnerability in this project, please report it responsibly:\n\n1. **Do not** create a public issue.\n2. Send an email to **nishargshah3101@gmail.com** with:\n   - The nature of the vulnerability.\n   - Steps to reproduce.\n   - Version(s) affected.\n   - Suggested fix or mitigation, if possible.\n3. We aim to respond within **72 hours**.\n\nAfter confirming the issue, we’ll prepare a fix and release a patched version. Once the patch is published, we will disclose the vulnerability publicly via GitHub.\n\n## Acknowledgments\n\nWe appreciate and welcome reports from the community. If you wish, we can credit you by name (or anonymously) in our release notes after publishing a fix.\n"
  },
  {
    "path": "apps/examples/.storybook/main.ts",
    "content": "import path from 'node:path';\n\nimport type { StorybookConfig } from '@storybook/react-vite';\n\nconst config = {\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['./react-code-addon/register.tsx', './vue-code-addon/register.tsx'],\n  framework: {\n    name: '@storybook/react-vite',\n    options: {},\n  },\n  staticDirs: ['../public'],\n  features: {\n    interactions: false,\n    actions: false,\n  },\n  viteFinal: (viteConfig) => {\n    const { root } = viteConfig;\n\n    if (!root) return viteConfig;\n\n    return {\n      ...viteConfig,\n      resolve: {\n        ...viteConfig.resolve,\n        alias: {\n          ...(Array.isArray(viteConfig.resolve?.alias)\n            ? null\n            : (viteConfig.resolve?.alias as Record<string, string>)),\n          '@': path.resolve(root, 'src'),\n        },\n      },\n    };\n  },\n} as StorybookConfig;\n\nexport default config;\n"
  },
  {
    "path": "apps/examples/.storybook/preview.tsx",
    "content": "import { Fragment } from 'react';\n\nimport { Analytics } from '@vercel/analytics/react';\n\nimport '@/styles/stories.css';\n\nimport type { Preview } from '@storybook/react-vite';\n\nconst preview = {\n  decorators: [\n    (Story) => (\n      <Fragment>\n        <Analytics />\n        <Story />\n      </Fragment>\n    ),\n  ],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/i,\n      },\n      disableSaveFromUI: true,\n    },\n    actions: {\n      argTypesRegex: '^on[A-Z].*',\n    },\n    options: {\n      storySort: {\n        order: [\n          'Examples',\n          ['Simple', 'Colors', 'Area', 'Responsive Map', 'Dynamic All Properties'],\n        ],\n      },\n    },\n  },\n} as Preview;\n\nexport default preview;\n"
  },
  {
    "path": "apps/examples/.storybook/react-code-addon/register.tsx",
    "content": "/* eslint-disable import-x/no-extraneous-dependencies */\n// DON'T REMOVE REACT FROM HERE\nimport React from 'react';\n\nimport SyntaxHighlighter from 'react-syntax-highlighter';\nimport { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs';\nimport { AddonPanel } from 'storybook/internal/components';\nimport { addons, types, useParameter } from 'storybook/manager-api';\n\nconst ReactContent = () => {\n  const reactCode = useParameter('reactCode', 'No Code Available');\n\n  return (\n    <SyntaxHighlighter showLineNumbers language=\"javascript\" style={atomOneDark}>\n      {reactCode}\n    </SyntaxHighlighter>\n  );\n};\n\naddons.register('my/react-code-addon', () => {\n  addons.add('react-code-addon/panel', {\n    title: 'React',\n    type: types.PANEL,\n    render: ({ active }) => (\n      <AddonPanel active={active ?? false}>\n        <ReactContent />\n      </AddonPanel>\n    ),\n  });\n});\n"
  },
  {
    "path": "apps/examples/.storybook/vue-code-addon/register.tsx",
    "content": "/* eslint-disable import-x/no-extraneous-dependencies */\n// DON'T REMOVE REACT FROM HERE\nimport React from 'react';\n\nimport SyntaxHighlighter from 'react-syntax-highlighter';\nimport { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs';\nimport { AddonPanel } from 'storybook/internal/components';\nimport { addons, types, useParameter } from 'storybook/manager-api';\n\nconst VueContent = () => {\n  const vueCode = useParameter('vueCode', 'No Code Available');\n\n  return (\n    <SyntaxHighlighter showLineNumbers language=\"javascript\" style={atomOneDark}>\n      {vueCode}\n    </SyntaxHighlighter>\n  );\n};\n\naddons.register('my/vue-code-addon', () => {\n  addons.add('vue-code-addon/panel', {\n    title: 'Vue',\n    type: types.PANEL,\n    render: ({ active }) => (\n      <AddonPanel active={active ?? false}>\n        <VueContent />\n      </AddonPanel>\n    ),\n  });\n});\n"
  },
  {
    "path": "apps/examples/package.json",
    "content": "{\n  \"name\": \"examples\",\n  \"version\": \"2.0.3\",\n  \"private\": true,\n  \"description\": \"Examples of react-img-mapper and vue-img-mapper\",\n  \"bugs\": {\n    \"url\": \"https://github.com/img-mapper/img-mapper/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/img-mapper/img-mapper.git\",\n    \"directory\": \"apps/examples\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Nisharg Shah <nishargshah3101@gmail.com>\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"prebuild\": \"pnpm build:react\",\n    \"build\": \"storybook build\",\n    \"build:react\": \"pnpm --filter react-img-mapper build\",\n    \"predev\": \"pnpm build:react\",\n    \"dev\": \"storybook dev -p 3002\",\n    \"typecheck\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@vercel/analytics\": \"catalog:\",\n    \"react\": \"catalog:\",\n    \"react-dom\": \"catalog:\",\n    \"react-img-mapper\": \"workspace:*\",\n    \"react-syntax-highlighter\": \"^15.6.6\"\n  },\n  \"devDependencies\": {\n    \"@storybook/react-vite\": \"^9.1.13\",\n    \"@types/react\": \"catalog:\",\n    \"@types/react-dom\": \"catalog:\",\n    \"@types/react-syntax-highlighter\": \"^15.5.13\",\n    \"storybook\": \"^9.1.13\",\n    \"typescript\": \"catalog:\"\n  }\n}\n"
  },
  {
    "path": "apps/examples/public/assets/areas.json",
    "content": "[\n  {\n    \"id\": \"469f9800-c45a-483f-b13e-bd24f3fb79f4\",\n    \"title\": \"Hardwood\",\n    \"shape\": \"poly\",\n    \"name\": \"1\",\n    \"fillColor\": \"#eab54d4d\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      520.0646766169153, 393.0348258706467, 85.23880597014923, 378.6069651741293, 637, 479,\n      13.099502487562177, 478.10945273631836, 11.606965174129343, 438.3084577114427\n    ],\n    \"polygon\": [\n      [520.0646766169153, 393.0348258706467],\n      [85.23880597014923, 378.6069651741293],\n      [637, 479],\n      [13.099502487562177, 478.10945273631836],\n      [11.606965174129343, 438.3084577114427]\n    ]\n  },\n  {\n    \"id\": \"1db62daa-22a4-4b02-b5c0-fffdcf77c66c\",\n    \"title\": \"Carpet\",\n    \"shape\": \"poly\",\n    \"name\": \"2\",\n    \"fillColor\": \"#eab54d4d\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      126.5323383084577, 345.273631840796, 465.3383084577114, 349.25373134328356, 520.0646766169153,\n      393.0348258706467, 85.23880597014923, 378.6069651741293\n    ],\n    \"polygon\": [\n      [126.5323383084577, 345.273631840796],\n      [465.3383084577114, 349.25373134328356],\n      [520.0646766169153, 393.0348258706467],\n      [85.23880597014923, 378.6069651741293]\n    ]\n  },\n  {\n    \"id\": \"667d73b1-4583-4080-ab6b-5759f25440bb\",\n    \"title\": \"Materials\",\n    \"shape\": \"poly\",\n    \"name\": \"3\",\n    \"fillColor\": \"#eab54d4d\",\n    \"strokeColor\": \"black\",\n    \"coords\": [],\n    \"polygon\": []\n  },\n  {\n    \"id\": \"a87203cb-3916-48ea-856f-2bacab8b7eda\",\n    \"title\": \"Floor\",\n    \"shape\": \"poly\",\n    \"name\": \"4\",\n    \"fillColor\": \"#eab54d4d\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      130.0149253731343, 341.2935323383084, 462.8507462686566, 347.7611940298507, 637, 479,\n      13.099502487562177, 478.10945273631836, 11.606965174129343, 438.3084577114427\n    ],\n    \"polygon\": [\n      [130.0149253731343, 341.2935323383084],\n      [462.8507462686566, 347.7611940298507],\n      [637, 479],\n      [13.099502487562177, 478.10945273631836],\n      [11.606965174129343, 438.3084577114427]\n    ]\n  },\n  {\n    \"id\": \"37ed1569-1e68-4816-9033-1a88c53b39df\",\n    \"title\": \"Electrical Fixture\",\n    \"shape\": \"poly\",\n    \"name\": \"5\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      521.0597014925372, 335.820895522388, 528.0248756218905, 338.30845771144277, 527.0298507462686,\n      354.228855721393, 518.0746268656716, 349.25373134328356\n    ],\n    \"polygon\": [\n      [521.0597014925372, 335.820895522388],\n      [528.0248756218905, 338.30845771144277],\n      [527.0298507462686, 354.228855721393],\n      [518.0746268656716, 349.25373134328356]\n    ]\n  },\n  {\n    \"id\": \"ce471cbe-4103-45cc-899c-2be6497dc79a\",\n    \"title\": \"Electrical Fixture\",\n    \"shape\": \"poly\",\n    \"name\": \"6\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      531.5074626865671, 342.2885572139303, 538.4726368159203, 342.78606965174123,\n      538.4726368159203, 357.7114427860696, 530.5124378109452, 355.72139303482584\n    ],\n    \"polygon\": [\n      [531.5074626865671, 342.2885572139303],\n      [538.4726368159203, 342.78606965174123],\n      [538.4726368159203, 357.7114427860696],\n      [530.5124378109452, 355.72139303482584]\n    ]\n  },\n  {\n    \"id\": \"5fde0edd-4e1c-4130-9ee5-4ec6dfd34f46\",\n    \"title\": \"Electrical Fixture\",\n    \"shape\": \"poly\",\n    \"name\": \"7\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      589.2189054726367, 136.31840796019898, 605.6368159203979, 133.83084577114425,\n      604.1442786069651, 153.73134328358208, 590.7114427860696, 153.23383084577114\n    ],\n    \"polygon\": [\n      [589.2189054726367, 136.31840796019898],\n      [605.6368159203979, 133.83084577114425],\n      [604.1442786069651, 153.73134328358208],\n      [590.7114427860696, 153.23383084577114]\n    ]\n  },\n  {\n    \"id\": \"976082e0-0653-4e5d-8094-cc351e482e72\",\n    \"title\": \"Electrical Fixture\",\n    \"shape\": \"poly\",\n    \"name\": \"8\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      606.6318407960198, 130.8457711442786, 619.5671641791045, 129.8507462686567, 621.0597014925372,\n      152.73631840796017, 606.1343283582089, 155.72139303482587\n    ],\n    \"polygon\": [\n      [606.6318407960198, 130.8457711442786],\n      [619.5671641791045, 129.8507462686567],\n      [621.0597014925372, 152.73631840796017],\n      [606.1343283582089, 155.72139303482587]\n    ]\n  },\n  {\n    \"id\": \"cc3c2799-ce62-4236-b4f6-6f4b50e7b666\",\n    \"title\": \"GWB\",\n    \"shape\": \"poly\",\n    \"name\": \"9\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      521.5621890547263, 103.98009950248755, 508.6268656716418, 381.09452736318406,\n      638.9701492537313, 28.358208955223876, 637.9751243781094, 477.6119402985074\n    ],\n    \"polygon\": [\n      [521.5621890547263, 103.98009950248755],\n      [508.6268656716418, 381.09452736318406],\n      [638.9701492537313, 28.358208955223876],\n      [637.9751243781094, 477.6119402985074]\n    ]\n  },\n  {\n    \"id\": \"6c682813-8162-42eb-b3a7-c7296a009b5a\",\n    \"title\": \"Brick\",\n    \"shape\": \"poly\",\n    \"name\": \"10\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      465.8358208955224, 137.81094527363183, 520.5621890547263, 103.98009950248755,\n      507.6268656716418, 381.09452736318406, 464.3432835820895, 350.7462686567164\n    ],\n    \"polygon\": [\n      [465.8358208955224, 137.81094527363183],\n      [520.5621890547263, 103.98009950248755],\n      [507.6268656716418, 381.09452736318406],\n      [464.3432835820895, 350.7462686567164]\n    ]\n  },\n  {\n    \"id\": \"1c9cabf2-4306-46cd-9423-63c7156cf4d4\",\n    \"title\": \"Materials\",\n    \"shape\": \"poly\",\n    \"name\": \"11\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [],\n    \"polygon\": []\n  },\n  {\n    \"id\": \"53c311f7-4e1c-4636-ac7e-b9cdec0d7ab7\",\n    \"title\": \"Right Wall\",\n    \"shape\": \"poly\",\n    \"name\": \"12\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      465.8358208955224, 138.8059701492537, 638.9701492537313, 28.358208955223876,\n      637.9751243781094, 477.6119402985074, 463.8457711442785, 349.25373134328356\n    ],\n    \"polygon\": [\n      [465.8358208955224, 138.8059701492537],\n      [638.9701492537313, 28.358208955223876],\n      [637.9751243781094, 477.6119402985074],\n      [463.8457711442785, 349.25373134328356]\n    ]\n  },\n  {\n    \"id\": \"21a3befd-c97b-476d-8e0c-7c98399988bf\",\n    \"title\": \"Window\",\n    \"shape\": \"poly\",\n    \"name\": \"13\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      211.10945273631836, 161.6915422885572, 387.7263681592039, 164.67661691542287,\n      383.7462686567164, 292.5373134328358, 207.62686567164178, 288.5572139303482\n    ],\n    \"polygon\": [\n      [211.10945273631836, 161.6915422885572],\n      [387.7263681592039, 164.67661691542287],\n      [383.7462686567164, 292.5373134328358],\n      [207.62686567164178, 288.5572139303482]\n    ]\n  },\n  {\n    \"id\": \"2f36ad1d-b934-4fb0-9486-7f429ef46a1b\",\n    \"title\": \"Front Wall\",\n    \"shape\": \"poly\",\n    \"name\": \"14\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      131.50746268656715, 131.34328358208953, 465.3383084577114, 138.30845771144277,\n      462.35323383084574, 347.7611940298507, 129.51741293532336, 341.79104477611935\n    ],\n    \"polygon\": [\n      [131.50746268656715, 131.34328358208953],\n      [465.3383084577114, 138.30845771144277],\n      [462.35323383084574, 347.7611940298507],\n      [129.51741293532336, 341.79104477611935]\n    ]\n  },\n  {\n    \"id\": \"f3653fb6-c1c5-4fe7-aec1-699d9da7bba1\",\n    \"title\": \"Microwave\",\n    \"shape\": \"poly\",\n    \"name\": \"15\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      120.06467661691539, 193.5323383084577, 145.93532338308455, 197.51243781094524,\n      146.4328358208955, 234.82587064676613, 118.07462686567163, 233.33333333333331\n    ],\n    \"polygon\": [\n      [120.06467661691539, 193.5323383084577],\n      [145.93532338308455, 197.51243781094524],\n      [146.4328358208955, 234.82587064676613],\n      [118.07462686567163, 233.33333333333331]\n    ]\n  },\n  {\n    \"id\": \"eca521ca-11c6-4312-830b-3492829649df\",\n    \"title\": \"Stove\",\n    \"shape\": \"poly\",\n    \"name\": \"16\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      85.73631840796017, 254.22885572139302, 85.73631840796017, 279.10447761194024,\n      139.46766169154228, 282.08955223880594, 162.85074626865668, 276.1194029850746,\n      118.07462686567163, 274.6268656716418, 117.57711442786066, 264.67661691542287,\n      115.08955223880594, 249.7512437810945\n    ],\n    \"polygon\": [\n      [85.73631840796017, 254.22885572139302],\n      [85.73631840796017, 279.10447761194024],\n      [139.46766169154228, 282.08955223880594],\n      [162.85074626865668, 276.1194029850746],\n      [118.07462686567163, 274.6268656716418],\n      [117.57711442786066, 264.67661691542287],\n      [115.08955223880594, 249.7512437810945]\n    ]\n  },\n  {\n    \"id\": \"e8da6027-7563-4a50-9b7b-9ffc1bb1b613\",\n    \"title\": \"Oven\",\n    \"shape\": \"poly\",\n    \"name\": \"17\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      145.4378109452736, 288.0597014925373, 164.34328358208953, 282.08955223880594,\n      166.33333333333331, 353.731343283582, 142.45273631840794, 371.6417910447761\n    ],\n    \"polygon\": [\n      [145.4378109452736, 288.0597014925373],\n      [164.34328358208953, 282.08955223880594],\n      [166.33333333333331, 353.731343283582],\n      [142.45273631840794, 371.6417910447761]\n    ]\n  },\n  {\n    \"id\": \"5248f935-10c8-4b16-8cff-21b66d2cb56f\",\n    \"title\": \"Countertop\",\n    \"shape\": \"poly\",\n    \"name\": \"18\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      70.31343283582089, 287.56218905472633, 82.25373134328356, 281.09452736318406,\n      140.46268656716416, 283.0845771144278, 77.77611940298505, 303.4825870646766\n    ],\n    \"polygon\": [\n      [70.31343283582089, 287.56218905472633],\n      [82.25373134328356, 281.09452736318406],\n      [140.46268656716416, 283.0845771144278],\n      [77.77611940298505, 303.4825870646766]\n    ]\n  },\n  {\n    \"id\": \"5b40c828-ecb3-4633-b181-78e2832823b1\",\n    \"title\": \"Double Cabinet\",\n    \"shape\": \"poly\",\n    \"name\": \"19\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      108.62189054726366, 298.5074626865671, 139.46766169154228, 289.5522388059701,\n      138.47263681592037, 364.1791044776119, 106.13432835820893, 390.54726368159197\n    ],\n    \"polygon\": [\n      [108.62189054726366, 298.5074626865671],\n      [139.46766169154228, 289.5522388059701],\n      [138.47263681592037, 364.1791044776119],\n      [106.13432835820893, 390.54726368159197]\n    ]\n  },\n  {\n    \"id\": \"7810e113-49d2-4284-9e49-318af8378663\",\n    \"title\": \"Dishwasher\",\n    \"shape\": \"poly\",\n    \"name\": \"20\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      81.25870646766168, 308.45771144278604, 108.12437810945272, 300.4975124378109,\n      106.13432835820893, 393.53233830845767, 80.26368159203977, 410.4477611940298\n    ],\n    \"polygon\": [\n      [81.25870646766168, 308.45771144278604],\n      [108.12437810945272, 300.4975124378109],\n      [106.13432835820893, 393.53233830845767],\n      [80.26368159203977, 410.4477611940298]\n    ]\n  },\n  {\n    \"id\": \"5998531a-25b3-4288-adbe-53c4470a369b\",\n    \"title\": \"Refrigerator\",\n    \"shape\": \"poly\",\n    \"name\": \"21\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      18.572139303482572, 169.65174129353233, 82.25373134328356, 182.5870646766169,\n      80.76119402985074, 424.8756218905472, 14.09452736318407, 475.6218905472636\n    ],\n    \"polygon\": [\n      [18.572139303482572, 169.65174129353233],\n      [82.25373134328356, 182.5870646766169],\n      [80.76119402985074, 424.8756218905472],\n      [14.09452736318407, 475.6218905472636]\n    ]\n  },\n  {\n    \"id\": \"9db9f57d-c15e-4d3a-abb7-faa7e69657c8\",\n    \"title\": \"Single Cabinet\",\n    \"shape\": \"poly\",\n    \"name\": \"22\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      140.46268656716416, 142.28855721393032, 149.91542288557213, 148.75621890547262,\n      147.4278606965174, 234.3283582089552, 138.9701492537313, 232.3383084577114\n    ],\n    \"polygon\": [\n      [140.46268656716416, 142.28855721393032],\n      [149.91542288557213, 148.75621890547262],\n      [147.4278606965174, 234.3283582089552],\n      [138.9701492537313, 232.3383084577114]\n    ]\n  },\n  {\n    \"id\": \"d2c06088-49ce-404b-ab78-d865a336248d\",\n    \"title\": \"Double Cabinet\",\n    \"shape\": \"poly\",\n    \"name\": \"23\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      111.10945273631839, 128.35820895522386, 139.46766169154228, 142.7860696517413,\n      139.96517412935322, 196.01990049751242, 112.10447761194027, 191.04477611940297\n    ],\n    \"polygon\": [\n      [111.10945273631839, 128.35820895522386],\n      [139.46766169154228, 142.7860696517413],\n      [139.96517412935322, 196.01990049751242],\n      [112.10447761194027, 191.04477611940297]\n    ]\n  },\n  {\n    \"id\": \"07feade7-e370-4384-bb96-c21f9eedb238\",\n    \"title\": \"Double Cabinet\",\n    \"shape\": \"poly\",\n    \"name\": \"24\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      72.80099502487562, 108.45771144278606, 111.60696517412933, 127.36318407960198,\n      112.60199004975124, 233.83084577114425, 74.79104477611938, 234.82587064676613\n    ],\n    \"polygon\": [\n      [72.80099502487562, 108.45771144278606],\n      [111.60696517412933, 127.36318407960198],\n      [112.60199004975124, 233.83084577114425],\n      [74.79104477611938, 234.82587064676613]\n    ]\n  },\n  {\n    \"id\": \"db82b663-6c46-4a21-9ba6-fa6aa5bf84dc\",\n    \"title\": \"Double Cabinet\",\n    \"shape\": \"poly\",\n    \"name\": \"25\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      19.567164179104466, 56.21890547263681, 71.80597014925371, 87.56218905472636,\n      71.80597014925371, 173.63184079601987, 18.572139303482572, 159.20398009950247\n    ],\n    \"polygon\": [\n      [19.567164179104466, 56.21890547263681],\n      [71.80597014925371, 87.56218905472636],\n      [71.80597014925371, 173.63184079601987],\n      [18.572139303482572, 159.20398009950247]\n    ]\n  },\n  {\n    \"id\": \"9258a68c-dc5d-4b08-bee1-720d8e8e3509\",\n    \"title\": \"Left Wall\",\n    \"shape\": \"poly\",\n    \"name\": \"26\",\n    \"fillColor\": \"#00ff194c\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      20.064676616915406, 57.71144278606965, 131.50746268656715, 131.34328358208953,\n      130.0149253731343, 341.79104477611935, 12.104477611940283, 436.8159203980099\n    ],\n    \"polygon\": [\n      [20.064676616915406, 57.71144278606965],\n      [131.50746268656715, 131.34328358208953],\n      [130.0149253731343, 341.79104477611935],\n      [12.104477611940283, 436.8159203980099]\n    ]\n  },\n  {\n    \"id\": \"e30e9e21-0a03-4514-9473-887f23991361\",\n    \"title\": \"Vent\",\n    \"shape\": \"poly\",\n    \"name\": \"27\",\n    \"fillColor\": \"#ff000026\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      249.91542288557213, 0, 299.66666666666663, 0.49751243781094523, 298.67164179104475,\n      13.930348258706466, 250.910447761194, 13.930348258706466\n    ],\n    \"polygon\": [\n      [249.91542288557213, 0],\n      [299.66666666666663, 0.49751243781094523],\n      [298.67164179104475, 13.930348258706466],\n      [250.910447761194, 13.930348258706466]\n    ]\n  },\n  {\n    \"id\": \"f5a8d660-61df-4783-a631-8ea6758ee50d\",\n    \"title\": \"Vent\",\n    \"shape\": \"poly\",\n    \"name\": \"28\",\n    \"fillColor\": \"#ff000026\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      285.2388059701492, 117.41293532338307, 309.1194029850746, 116.91542288557213,\n      309.1194029850746, 128.8557213930348, 286.731343283582, 128.35820895522386\n    ],\n    \"polygon\": [\n      [285.2388059701492, 117.41293532338307],\n      [309.1194029850746, 116.91542288557213],\n      [309.1194029850746, 128.8557213930348],\n      [286.731343283582, 128.35820895522386]\n    ]\n  },\n  {\n    \"id\": \"6721b73c-a4f7-486c-8d72-5d7e817db59a\",\n    \"title\": \"Light\",\n    \"shape\": \"poly\",\n    \"name\": \"29\",\n    \"fillColor\": \"#ff000026\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      266.83084577114425, 93.5323383084577, 277.2786069651741, 93.03482587064676, 277.2786069651741,\n      99.50248756218905, 267.3283582089552, 99.00497512437809\n    ],\n    \"polygon\": [\n      [266.83084577114425, 93.5323383084577],\n      [277.2786069651741, 93.03482587064676],\n      [277.2786069651741, 99.50248756218905],\n      [267.3283582089552, 99.00497512437809]\n    ]\n  },\n  {\n    \"id\": \"6fe8c503-66f8-47be-bad8-5a39d170e538\",\n    \"title\": \"Recessed Light\",\n    \"shape\": \"poly\",\n    \"name\": \"30\",\n    \"fillColor\": \"#ff000026\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      206.1343283582089, 103.48258706467661, 227.0298507462686, 105.47263681592038,\n      222.5522388059701, 113.93034825870646, 207.12935323383084, 112.93532338308457\n    ],\n    \"polygon\": [\n      [206.1343283582089, 103.48258706467661],\n      [227.0298507462686, 105.47263681592038],\n      [222.5522388059701, 113.93034825870646],\n      [207.12935323383084, 112.93532338308457]\n    ]\n  },\n  {\n    \"id\": \"b5ef36ad-484b-4605-a2ba-72b9f1e7114f\",\n    \"title\": \"Recessed Light\",\n    \"shape\": \"poly\",\n    \"name\": \"31\",\n    \"fillColor\": \"#ff000026\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      164.84079601990047, 55.721393034825866, 187.72636815920396, 54.72636815920397,\n      185.73631840796017, 66.16915422885572, 167.82587064676613, 66.66666666666666\n    ],\n    \"polygon\": [\n      [164.84079601990047, 55.721393034825866],\n      [187.72636815920396, 54.72636815920397],\n      [185.73631840796017, 66.16915422885572],\n      [167.82587064676613, 66.66666666666666]\n    ]\n  },\n  {\n    \"id\": \"75449960-7fde-4907-a463-7bb5b146d70c\",\n    \"title\": \"Ceiling\",\n    \"shape\": \"poly\",\n    \"name\": \"32\",\n    \"fillColor\": \"#ff000026\",\n    \"strokeColor\": \"black\",\n    \"coords\": [\n      19.567164179104466, 52.73631840796019, 19.567164179104466, 1.990049751243781,\n      637.9751243781094, 1.4925373134328357, 638.9701492537313, 28.358208955223876,\n      464.8407960199004, 138.8059701492537, 131.50746268656715, 130.34825870646765\n    ],\n    \"polygon\": [\n      [19.567164179104466, 52.73631840796019],\n      [19.567164179104466, 1.990049751243781],\n      [637.9751243781094, 1.4925373134328357],\n      [638.9701492537313, 28.358208955223876],\n      [464.8407960199004, 138.8059701492537],\n      [131.50746268656715, 130.34825870646765]\n    ]\n  }\n]\n"
  },
  {
    "path": "apps/examples/src/code/areas.ts",
    "content": "import mapper from '@/functions/mapper';\nimport mapperWithState from '@/functions/mapperWithState';\n\nexport const showHighlightedAreaCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      active={props.active} // dynamic active\n   />\n  )`);\n\nexport const inArrayShowHighlightedAreaCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n    />\n  )`);\n\nexport const disabledAreaCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      disabled={props.disabled} // dynamic disabled\n   />\n  )`);\n\nexport const inArrayDisabledAreaCode = inArrayShowHighlightedAreaCode;\n\nexport const staySelectedHighlightedAreaCode = mapperWithState(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      onChange={(_, newAreas) => setAreas(newAreas)}\n      isMulti={false}\n   />\n  )`);\n\nexport const stayMultipleSelectedHighlightedAreaCode = mapperWithState(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      onChange={(_, newAreas) => setAreas(newAreas)}\n      isMulti\n   />\n  )`);\n\nexport const toggleStayHighlightedAreaCode = mapperWithState(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      onChange={(_, newAreas) => setAreas(newAreas)}\n      isMulti={props.isMulti} // dynamic isMulti\n      toggle={props.toggle} // dynamic toggle\n   />\n  )`);\n\nexport { default as clearSelectedHighlightedAreaCode } from '@/templates/clearButtonTemplate';\n\nexport { default as zoomInZoomOutAreaCode } from '@/templates/zoomTemplate';\n"
  },
  {
    "path": "apps/examples/src/code/colors.ts",
    "content": "import mapper from '@/functions/mapper';\n\nexport const fillColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n    />\n  )`);\n\nexport const inArrayFillColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n    />\n  )`);\n\nexport const dynamicFillColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      fillColor={props.fillColor} // dynamic fill color\n   />\n  )`);\n\nexport const dynamicMixArrayFillColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      fillColor={props.fillColor} // dynamic fill color\n   />\n  )`);\n\nexport const strokeColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      lineWidth={2}\n   />\n  )`);\n\nexport const inArrayStrokeColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      lineWidth={2}\n   />\n  )`);\n\nexport const dynamicStrokeColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      strokeColor={props.strokeColor} // dynamic stroke color\n      lineWidth={props.lineWidth} // dynamic stroke line width\n   />\n  )`);\n\nexport const dynamicMixArrayStrokeColorCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      strokeColor={props.strokeColor} // dynamic stroke color\n      lineWidth={props.lineWidth} // dynamic stroke line width\n   />\n  )`);\n"
  },
  {
    "path": "apps/examples/src/code/dynamic.ts",
    "content": "import mapper from '@/functions/mapper';\n\nconst dynamicAllPropertiesCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      isMulti={props.isMulti}\n      toggle={props.toggle}\n      active={props.active}\n      disabled={props.disabled}\n      fillColor={props.fillColor}\n      strokeColor={props.strokeColor}\n      lineWidth={props.lineWidth}\n      imgWidth={props.imgWidth}\n      width={props.width}\n      height={props.height}\n      natural={props.natural}\n      responsive={props.responsive}\n      parentWidth={props.parentWidth}\n   />\n  )`);\n\nexport default dynamicAllPropertiesCode;\n"
  },
  {
    "path": "apps/examples/src/code/map.ts",
    "content": "import mapper from '@/functions/mapper';\n\nexport const nonResponsiveDimensionsCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      width={props.width} // dynamic width\n      height={props.height} // dynamic height\n      imageWidth={props.imageWidth} // dynamic imageWidth\n      natural={props.natural} // dynamic natural\n   />\n  )`);\n\nexport const responsiveDimensionsCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      responsive\n      parentWidth={props.parentWidth} // dynamic parentWidth\n   />\n  )`);\n\nexport const allDimensionsCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n      width={props.width} // dynamic width\n      height={props.height} // dynamic height\n      imgWidth={props.imgWidth} // dynamic imgWidth\n      natural={props.natural} // dynamic natural\n      responsive={props.responsive} // dynamic responsive\n      parentWidth={props.parentWidth} // dynamic parentWidth\n   />\n  )`);\n"
  },
  {
    "path": "apps/examples/src/code/simple.ts",
    "content": "import mapper from '@/functions/mapper';\n\nconst simpleCode = mapper(`(\n    <ImageMapper \n      src={url} \n      name={name}\n      areas={areas}\n    />\n  )`);\n\nexport default simpleCode;\n"
  },
  {
    "path": "apps/examples/src/components/DynamicMapper.tsx",
    "content": "import { Fragment, useEffect, useState } from 'react';\n\nimport ImageMapper from 'react-img-mapper';\n\nimport TopComponent from '@/components/TopComponent';\nimport CONSTANTS from '@/constants';\nimport { useAreas } from '@/hooks/useAreas';\n\nimport type { ImageMapperProps } from 'react-img-mapper';\n\nimport type { Component } from '@/types';\n\nconst { url, name } = CONSTANTS;\n\ntype DynamicMapperProps = Omit<ImageMapperProps, 'src' | 'name' | 'areas' | 'onChange'>;\n\nconst DynamicMapper: Component<DynamicMapperProps> = (props) => {\n  const { areas: initialAreas } = useAreas();\n\n  const [areas, setAreas] = useState(initialAreas);\n\n  useEffect(() => {\n    if (areas.length === 0) {\n      setAreas(\n        initialAreas.map((cur) => {\n          const temp = { ...cur };\n\n          if (['Front Wall', 'Window'].includes(cur.title)) {\n            delete temp.fillColor;\n            delete temp.strokeColor;\n            return temp;\n          }\n\n          return temp;\n        }),\n      );\n    }\n  }, [areas.length, initialAreas]);\n\n  if (areas.length === 0) return null;\n\n  return (\n    <Fragment>\n      {TopComponent(\n        'Dynamic All Properties Example',\n        <p>\n          In this example, all the <span className=\"tag\">functionalities</span> developed so far\n          have been merged into a single demo.\n          <br />\n          <br />\n          <span className=\"block\">Feel free to explore and have fun experimenting!</span>\n        </p>,\n      )}\n      <ImageMapper\n        {...props}\n        areas={areas}\n        name={name}\n        onChange={(_, newAreas) => setAreas(newAreas)}\n        src={url}\n      />\n    </Fragment>\n  );\n};\n\nexport default DynamicMapper;\n"
  },
  {
    "path": "apps/examples/src/components/Mapper.tsx",
    "content": "import { Fragment, useCallback, useEffect, useState } from 'react';\n\nimport ImageMapper from 'react-img-mapper';\n\nimport CONSTANTS from '@/constants';\nimport { useAreas } from '@/hooks/useAreas';\n\nimport type { ReactNode } from 'react';\nimport type { ImageMapperProps } from 'react-img-mapper';\n\nimport type { Component } from '@/types';\n\ninterface TopComponentProps {\n  resetAreas: () => void;\n}\n\ninterface BottomComponentProps {\n  resetAreas: () => void;\n}\n\ntype MapperProps = Omit<ImageMapperProps, 'src' | 'name' | 'areas' | 'onChange'> & {\n  customJSON?: 0 | 1 | 2;\n  customType?: 'fill' | 'stroke' | 'active' | 'disabled';\n  isOnChangeNeeded?: boolean;\n  TopComponent?: (props: TopComponentProps) => ReactNode;\n  BottomComponent?: (props: BottomComponentProps) => ReactNode;\n};\n\nconst { url, name } = CONSTANTS;\n\nconst Mapper: Component<MapperProps> = (props) => {\n  const { customJSON, customType, isOnChangeNeeded, TopComponent, BottomComponent, ...restProps } =\n    props;\n\n  const { areas: initialAreas } = useAreas();\n\n  const [areas, setAreas] = useState(initialAreas);\n\n  const getJSON = useCallback(() => {\n    if (customJSON === 0) {\n      return initialAreas.map((item) => {\n        const temp = { ...item } as typeof item;\n\n        if (customType === 'fill') {\n          delete temp.fillColor;\n        }\n\n        if (customType === 'stroke') {\n          delete temp.fillColor;\n          delete temp.strokeColor;\n        }\n\n        return temp;\n      });\n    }\n\n    if (customJSON === 1) {\n      return initialAreas.map((item) => {\n        const temp = { ...item } as typeof item;\n\n        if (['Front Wall', 'Window'].includes(item.title)) {\n          if (customType === 'fill') {\n            delete temp.fillColor;\n          }\n\n          if (customType === 'stroke') {\n            delete temp.strokeColor;\n          }\n\n          return temp;\n        }\n\n        return temp;\n      });\n    }\n\n    if (customJSON === 2) {\n      return initialAreas.map((item) => {\n        const temp = { ...item } as typeof item;\n\n        if (['Refrigerator', 'Window'].includes(item.title)) {\n          if (customType === 'active') {\n            temp.active = false;\n          }\n\n          if (customType === 'disabled') {\n            temp.disabled = true;\n          }\n\n          return temp;\n        }\n\n        return temp;\n      });\n    }\n\n    return initialAreas;\n  }, [initialAreas, customJSON, customType]);\n\n  const resetAreas = () => setAreas(getJSON());\n\n  useEffect(() => {\n    if (areas.length === 0) setAreas(getJSON());\n  }, [areas.length, getJSON]);\n\n  if (areas.length === 0) return null;\n\n  return (\n    <Fragment>\n      {TopComponent ? <TopComponent resetAreas={resetAreas} /> : null}\n      <ImageMapper\n        {...restProps}\n        areas={areas}\n        name={name}\n        onChange={(_, newAreas) => (isOnChangeNeeded ? setAreas(newAreas) : null)}\n        src={url}\n      />\n      {BottomComponent ? <BottomComponent resetAreas={resetAreas} /> : null}\n    </Fragment>\n  );\n};\n\nexport default Mapper;\n"
  },
  {
    "path": "apps/examples/src/components/TopComponent.tsx",
    "content": "import type { JSX, ReactNode } from 'react';\n\ntype TopComponentElement = (title: string, content: ReactNode) => JSX.Element;\n\nconst TopComponent: TopComponentElement = (title, content) => (\n  <div className=\"top_container\">\n    <h1 className=\"title\">{title}</h1>\n    <div className=\"top_content\">{content}</div>\n  </div>\n);\n\nexport default TopComponent;\n"
  },
  {
    "path": "apps/examples/src/components/ZoomInZoomOutAreaComp.tsx",
    "content": "import { useState } from 'react';\n\nimport Mapper from '@/components/Mapper';\nimport TopComponent from '@/components/TopComponent';\n\nimport type { ImageMapperProps } from 'react-img-mapper';\n\nimport type { Component } from '@/types';\n\ntype ZoomInZoomOutAreaCompProps = Pick<ImageMapperProps, 'parentWidth'>;\n\nconst ZoomInZoomOutAreaComp: Component<ZoomInZoomOutAreaCompProps> = (props) => {\n  const minWidth = 400;\n  const { parentWidth = 100 } = props;\n\n  const [zoom, setZoom] = useState(640);\n\n  const handleZoom = (type: 'in' | 'out') => {\n    setZoom((prev) => {\n      if (prev <= minWidth && type === 'out') return prev;\n      return type === 'in' ? prev + parentWidth : prev - parentWidth;\n    });\n  };\n\n  return (\n    <Mapper\n      responsive\n      parentWidth={zoom}\n      TopComponent={() =>\n        TopComponent(\n          'Zoom In & Zoom Out Area Example',\n          <p>\n            In this example, zoom is controlled via the <span className=\"tag\">parentWidth</span>,\n            which you can adjust using the Storybook <span className=\"tag\">Controls</span> tab.\n            Click the buttons below to see the <span className=\"tag\">live</span> zoom effect in the\n            image mapper:\n            <br />\n            <br />\n            <button onClick={() => handleZoom('in')} style={{ marginRight: 8 }} type=\"button\">\n              Zoom In\n            </button>\n            <button onClick={() => handleZoom('out')} type=\"button\">\n              Zoom Out\n            </button>\n          </p>,\n        )\n      }\n    />\n  );\n};\n\nexport default ZoomInZoomOutAreaComp;\n"
  },
  {
    "path": "apps/examples/src/constants/index.ts",
    "content": "const CONSTANTS = {\n  url: 'https://img-mapper-examples.nishargshah.dev/assets/example.jpg',\n  name: 'my-map',\n  areasUrl: 'https://img-mapper-examples.nishargshah.dev/assets/areas.json',\n};\n\nexport default CONSTANTS;\n"
  },
  {
    "path": "apps/examples/src/functions/mapper.ts",
    "content": "import variablesTemplate from '@/templates/variablesTemplate';\n\ntype Mapper = (code: string) => string;\n\nconst mapper: Mapper = (code) =>\n  `import React from 'react';\nimport ImageMapper from 'react-img-mapper';\n\nconst Mapper = props => {\n  ${variablesTemplate}\n  \n  return ${code}\n}\n\nexport default Mapper;`;\n\nexport default mapper;\n"
  },
  {
    "path": "apps/examples/src/functions/mapperWithState.ts",
    "content": "import CONSTANTS from '@/constants';\n\nconst { url, name, areasUrl } = CONSTANTS;\n\ntype MapperWithState = (code: string) => string;\n\nconst mapperWithState: MapperWithState = (code) =>\n  `import React from 'react';\nimport ImageMapper from 'react-img-mapper';\n\nconst Mapper = props => {\n  const url = '${url}';\n  const name = '${name}';\n  \n  // Get JSON from below URL as an example and put it into the useState hook\n  // URL: ${areasUrl}\n  const [areas, setAreas] = useState([]);\n  \n  return ${code}\n}\n\nexport default Mapper;`;\n\nexport default mapperWithState;\n"
  },
  {
    "path": "apps/examples/src/hooks/useAreas.ts",
    "content": "import { useEffect, useState } from 'react';\n\nimport CONSTANTS from '@/constants';\n\nimport type { MapArea } from 'react-img-mapper';\n\ninterface AreasHookOutput {\n  areas: MapArea[];\n}\n\ntype AreasHook = () => AreasHookOutput;\n\nconst { areasUrl } = CONSTANTS;\n\nexport const useAreas: AreasHook = () => {\n  const [areas, setAreas] = useState<AreasHookOutput['areas']>([]);\n\n  useEffect(() => {\n    (async () => {\n      const res = await fetch(areasUrl);\n      const json = await res.json();\n\n      setAreas(json);\n    })();\n  }, []);\n\n  return { areas };\n};\n"
  },
  {
    "path": "apps/examples/src/stories/Area.stories.tsx",
    "content": "import {\n  clearSelectedHighlightedAreaCode,\n  disabledAreaCode,\n  inArrayDisabledAreaCode,\n  inArrayShowHighlightedAreaCode,\n  showHighlightedAreaCode,\n  stayMultipleSelectedHighlightedAreaCode,\n  staySelectedHighlightedAreaCode,\n  toggleStayHighlightedAreaCode,\n  zoomInZoomOutAreaCode,\n} from '@/code/areas';\nimport Mapper from '@/components/Mapper';\nimport TopComponent from '@/components/TopComponent';\nimport ZoomInZoomOutAreaComp from '@/components/ZoomInZoomOutAreaComp';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nconst meta = {\n  title: 'Examples/Area',\n  component: Mapper,\n  tags: ['autodocs'],\n} as Meta<typeof Mapper>;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const ShowHighlightedArea: Story = {\n  render: (args) => {\n    const { active } = args;\n\n    return (\n      <Mapper\n        active={active}\n        TopComponent={() =>\n          TopComponent(\n            'Show Highlighted Area Example',\n            <p>\n              In this example, you can use the Storybook <span className=\"tag\">Controls</span> tab\n              to dynamically choose whether to <span className=\"tag\">show or hide</span> the\n              highlighted areas using the\n              <span className=\"tag\">active</span> toggle button, based on your preference.\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: showHighlightedAreaCode,\n  },\n  args: {\n    active: true,\n  },\n  argTypes: {\n    active: {\n      control: 'boolean',\n    },\n  },\n};\n\nexport const InArrayShowHighlightedArea: Story = {\n  render: () => (\n    <Mapper\n      customJSON={2}\n      customType=\"active\"\n      TopComponent={() =>\n        TopComponent(\n          'Show Highlighted Area from Area JSON Example',\n          <p>\n            This example demonstrates how to selectively <span className=\"tag\">show or hide</span>\n            <span className=\"tag\">active</span> areas of an image. Here, the{' '}\n            <span className=\"tag\">window</span>\n            and <span className=\"tag\">refrigerator</span> <span className=\"tag\">areas</span> are\n            excluded from visibility.\n            <br />\n            <br />\n            <span className=\"block note\">\n              <strong>Note:</strong> By default, the <span className=\"tag\">active</span> property is\n              set to\n              <span className=\"tag\">true</span> for the remaining areas.\n            </span>\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: inArrayShowHighlightedAreaCode,\n  },\n};\n\nexport const DisabledArea: Story = {\n  render: (args) => {\n    const { disabled } = args;\n\n    return (\n      <Mapper\n        disabled={disabled}\n        TopComponent={() =>\n          TopComponent(\n            'Disabled Area Example',\n            <p>\n              In this example, you can use the Storybook <span className=\"tag\">Controls</span> tab\n              to dynamically\n              <span className=\"tag\">enable or disable</span> event listeners and highlighted areas\n              using the\n              <span className=\"tag\">disabled</span> toggle button, according to your preference.\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: disabledAreaCode,\n  },\n  args: {\n    disabled: true,\n  },\n  argTypes: {\n    disabled: {\n      control: 'boolean',\n    },\n  },\n};\n\nexport const InArrayDisabledArea: Story = {\n  render: () => (\n    <Mapper\n      customJSON={2}\n      customType=\"disabled\"\n      TopComponent={() =>\n        TopComponent(\n          'Disabled Area from Area JSON Example',\n          <p>\n            This example demonstrates how to selectively{' '}\n            <span className=\"tag\">enable or disable</span>\n            specific areas of an image. Here, the <span className=\"tag\">window</span> and\n            <span className=\"tag\">refrigerator</span> <span className=\"tag\">areas</span> are\n            excluded from interaction.\n            <br />\n            <br />\n            <span className=\"block note\">\n              <strong>Note:</strong> By default, the <span className=\"tag\">disabled</span> property\n              is set to\n              <span className=\"tag\">false</span> for the remaining areas.\n            </span>\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: inArrayDisabledAreaCode,\n  },\n};\n\nexport const StaySelectedHighlightedArea: Story = {\n  render: () => (\n    <Mapper\n      isOnChangeNeeded\n      isMulti={false}\n      TopComponent={() =>\n        TopComponent(\n          'Stay Selected Highlighted Area Example',\n          <p>\n            In this example, you can <span className=\"tag\">freeze</span> specific{' '}\n            <span className=\"tag\">areas</span>\n            to keep them <span className=\"tag\">highlighted</span> by clicking, while still being\n            able to highlight the <span className=\"tag\">remaining</span> areas on hover.\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: staySelectedHighlightedAreaCode,\n  },\n};\n\nexport const StayMultipleSelectedHighlightedArea: Story = {\n  render: () => (\n    <Mapper\n      isMulti\n      isOnChangeNeeded\n      TopComponent={() =>\n        TopComponent(\n          'Stay Multiple Selected Highlighted Area Example',\n          <p>\n            This example is similar to the{' '}\n            <span className=\"tag\">Stay Selected Highlighted Area</span> section, with the added\n            feature of allowing you to freeze <span className=\"tag\">multiple</span> highlighted\n            areas simultaneously.\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: stayMultipleSelectedHighlightedAreaCode,\n  },\n};\n\nexport const ClearSelectedHighlightedArea: Story = {\n  render: () => (\n    <Mapper\n      isMulti\n      isOnChangeNeeded\n      TopComponent={({ resetAreas }) =>\n        TopComponent(\n          'Clear Selected Highlighted Area Example',\n          <p>\n            You can clear the <span className=\"tag\">single or multiple</span> selected highlighted\n            areas by resetting the state to its initial value. Click the button below to see the\n            changes\n            <span className=\"tag\">live</span> in the image mapper:\n            <br />\n            <br />\n            <button onClick={resetAreas} type=\"button\">\n              Clear\n            </button>\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: clearSelectedHighlightedAreaCode,\n  },\n};\n\nexport const ToggleStayHighlightedArea: Story = {\n  render: (args) => {\n    const { isMulti, toggle } = args;\n\n    return (\n      <Mapper\n        isOnChangeNeeded\n        isMulti={isMulti}\n        toggle={toggle}\n        TopComponent={() =>\n          TopComponent(\n            'Toggle Stay Highlighted Area Example',\n            <p>\n              This example introduces the <span className=\"tag\">toggle</span> property, which allows\n              you to\n              <span className=\"tag\">toggle</span> previously frozen highlighted areas on and off.\n              <br />\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: toggleStayHighlightedAreaCode,\n  },\n  args: {\n    isMulti: true,\n    toggle: true,\n  },\n  argTypes: {\n    isMulti: {\n      control: 'boolean',\n    },\n    toggle: {\n      control: 'boolean',\n    },\n  },\n};\n\nexport const ZoomInZoomOutArea: Story = {\n  render: ({ parentWidth }) => <ZoomInZoomOutAreaComp parentWidth={parentWidth} />,\n  parameters: {\n    reactCode: zoomInZoomOutAreaCode,\n  },\n  args: {\n    parentWidth: 100,\n  },\n  argTypes: {\n    parentWidth: {\n      control: 'number',\n    },\n  },\n};\n\nexport default meta;\n"
  },
  {
    "path": "apps/examples/src/stories/Colors.stories.tsx",
    "content": "import {\n  dynamicFillColorCode,\n  dynamicMixArrayFillColorCode,\n  dynamicMixArrayStrokeColorCode,\n  dynamicStrokeColorCode,\n  fillColorCode,\n  inArrayFillColorCode,\n  inArrayStrokeColorCode,\n  strokeColorCode,\n} from '@/code/colors';\nimport Mapper from '@/components/Mapper';\nimport TopComponent from '@/components/TopComponent';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nconst meta = {\n  title: 'Examples/Colors',\n  component: Mapper,\n  tags: ['autodocs'],\n} as Meta<typeof Mapper>;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const FillColor: Story = {\n  render: () => (\n    <Mapper\n      customJSON={0}\n      customType=\"fill\"\n      TopComponent={() =>\n        TopComponent(\n          'Fill Color Example',\n          <p>\n            In this example, the <span className=\"tag\">fillColor</span> property is not defined in\n            the\n            <span className=\"tag\">areas</span> JSON. As a result, the mapper uses its default\n            <span className=\"tag\">fillColor</span> behavior.\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: fillColorCode,\n  },\n};\n\nexport const InArrayFillColor: Story = {\n  render: () => (\n    <Mapper\n      customType=\"fill\"\n      TopComponent={() =>\n        TopComponent(\n          'Fill Color from Area JSON Example',\n          <p>\n            In this example, the <span className=\"tag\">fillColor</span> property is defined in the\n            <span className=\"tag\">areas</span> JSON. Therefore, the mapper applies the\n            <span className=\"tag\">fillColor</span> values from the JSON, resulting in different\n            <span className=\"tag\">fillColor</span> for each <span className=\"tag\">area</span>.\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: inArrayFillColorCode,\n  },\n};\n\nexport const DynamicFillColor: Story = {\n  render: (args) => {\n    const { fillColor } = args;\n\n    return (\n      <Mapper\n        customJSON={0}\n        customType=\"fill\"\n        fillColor={fillColor}\n        TopComponent={() =>\n          TopComponent(\n            'Dynamic Fill Color Example',\n            <p>\n              In this example, you can use the Storybook <span className=\"tag\">Controls</span> tab\n              to dynamically modify the <span className=\"tag\">fillColor</span> property according to\n              your preference.\n              <br />\n              <br />\n              <span className=\"block note\">\n                <strong>Note:</strong> For better visual results, try reducing the opacity of the\n                <span className=\"tag\">fillColor</span>.\n              </span>\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: dynamicFillColorCode,\n  },\n  args: {\n    fillColor: 'rgba(255, 255, 255, 0.5)',\n  },\n  argTypes: {\n    fillColor: {\n      control: 'color',\n    },\n  },\n};\n\nexport const DynamicMixArrayFillColor: Story = {\n  render: (args) => {\n    const { fillColor } = args;\n\n    return (\n      <Mapper\n        customJSON={1}\n        customType=\"fill\"\n        fillColor={fillColor}\n        TopComponent={() =>\n          TopComponent(\n            'Dynamic Mix Array Fill Color Example',\n            <p>\n              In this example, we demonstrate how to <span className=\"tag\">exclude</span> a specific\n              area of an image from the <span className=\"tag\">whole</span> mapping. Here, the{' '}\n              <span className=\"tag\">wall area</span>\n              is excluded, any changes made to the <span className=\"tag\">fillColor</span> property\n              from the\n              <span className=\"tag\">Controls</span> tab will only apply to the{' '}\n              <span className=\"tag\">wall area</span>.\n              <br />\n              <br />\n              <span className=\"block note\">\n                <strong>Note:</strong> The <span className=\"tag\">fillColor</span> property for the\n                remaining areas is already defined in the JSON data.\n              </span>\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: dynamicMixArrayFillColorCode,\n  },\n  args: {\n    fillColor: 'rgba(255, 255, 255, 0.5)',\n  },\n  argTypes: {\n    fillColor: {\n      control: 'color',\n    },\n  },\n};\n\nexport const StrokeColor: Story = {\n  render: () => (\n    <Mapper\n      customJSON={0}\n      customType=\"stroke\"\n      lineWidth={2}\n      TopComponent={() =>\n        TopComponent(\n          'Stroke Color Example',\n          <p>\n            In this example, the <span className=\"tag\">strokeColor</span> property is not defined in\n            the\n            <span className=\"tag\">areas</span> JSON. Therefore, the mapper applies its default\n            <span className=\"tag\">strokeColor</span> behavior.\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: strokeColorCode,\n  },\n};\n\nexport const InArrayStrokeColor: Story = {\n  render: () => (\n    <Mapper\n      customType=\"stroke\"\n      lineWidth={2}\n      TopComponent={() =>\n        TopComponent(\n          'Stroke Color from Area JSON Example',\n          <p>\n            In this example, the <span className=\"tag\">strokeColor</span> property is defined in the\n            <span className=\"tag\">areas</span> JSON. Hence, the mapper applies the\n            <span className=\"tag\">strokeColor</span> values directly from the JSON.\n          </p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: inArrayStrokeColorCode,\n  },\n};\n\nexport const DynamicStrokeColor: Story = {\n  render: (args) => {\n    const { strokeColor, lineWidth } = args;\n\n    return (\n      <Mapper\n        customJSON={0}\n        customType=\"stroke\"\n        lineWidth={lineWidth}\n        strokeColor={strokeColor}\n        TopComponent={() =>\n          TopComponent(\n            'Dynamic Stroke Color Example',\n            <p>\n              In this example, you can use the Storybook <span className=\"tag\">Controls</span> tab\n              to dynamically adjust the <span className=\"tag\">strokeColor</span> and{' '}\n              <span className=\"tag\">lineWidth</span> properties according to your preference.\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: dynamicStrokeColorCode,\n  },\n  args: {\n    strokeColor: 'rgba(0, 0, 0, 0.5)',\n    lineWidth: 1,\n  },\n  argTypes: {\n    strokeColor: {\n      control: 'color',\n    },\n    lineWidth: {\n      control: 'number',\n    },\n  },\n};\n\nexport const DynamicMixArrayStrokeColor: Story = {\n  render: (args) => {\n    const { strokeColor, lineWidth } = args;\n\n    return (\n      <Mapper\n        customJSON={1}\n        customType=\"stroke\"\n        lineWidth={lineWidth}\n        strokeColor={strokeColor}\n        TopComponent={() =>\n          TopComponent(\n            'Dynamic Mix Array Stroke Color Example',\n            <p>\n              This example demonstrates how to <span className=\"tag\">exclude</span> a specific area\n              of an image from the <span className=\"tag\">whole</span> mapping. Here, the{' '}\n              <span className=\"tag\">wall area</span>\n              is excluded, so any changes to the <span className=\"tag\">strokeColor</span> property\n              from the\n              <span className=\"tag\">Controls</span> tab will only apply to the{' '}\n              <span className=\"tag\">wall area</span>. Changes to the{' '}\n              <span className=\"tag\">lineWidth</span> property, however, will be applied to all\n              areas.\n              <br />\n              <br />\n              <span className=\"block note\">\n                <strong>Note:</strong> The <span className=\"tag\">strokeColor</span> for the\n                remaining areas is already defined in the JSON data.\n              </span>\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: dynamicMixArrayStrokeColorCode,\n  },\n  args: {\n    strokeColor: 'rgba(0, 0, 0, 0.5)',\n    lineWidth: 1,\n  },\n  argTypes: {\n    strokeColor: {\n      control: 'color',\n    },\n    lineWidth: {\n      control: 'number',\n    },\n  },\n};\n\nexport default meta;\n"
  },
  {
    "path": "apps/examples/src/stories/Dynamic.stories.tsx",
    "content": "import dynamicAllPropertiesCode from '@/code/dynamic';\nimport DynamicMapper from '@/components/DynamicMapper';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nconst meta = {\n  title: 'Examples/Dynamic All Properties',\n  component: DynamicMapper,\n  tags: ['autodocs'],\n} as Meta<typeof DynamicMapper>;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const DynamicAllProperties: Story = {\n  render: (args) => <DynamicMapper {...args} />,\n  parameters: {\n    reactCode: dynamicAllPropertiesCode,\n  },\n  args: {\n    isMulti: true,\n    toggle: false,\n    active: true,\n    disabled: false,\n    fillColor: 'rgba(255, 255, 255, 0.5)',\n    strokeColor: 'rgba(0, 0, 0, 0.5)',\n    lineWidth: 1,\n    imgWidth: 0,\n    width: 0,\n    height: 0,\n    natural: false,\n    responsive: false,\n    parentWidth: 0,\n  },\n  argTypes: {\n    isMulti: {\n      control: 'boolean',\n    },\n    toggle: {\n      control: 'boolean',\n    },\n    active: {\n      control: 'boolean',\n    },\n    disabled: {\n      control: 'boolean',\n    },\n    fillColor: {\n      control: 'color',\n    },\n    strokeColor: {\n      control: 'color',\n    },\n    lineWidth: {\n      control: 'number',\n    },\n    imgWidth: {\n      control: 'number',\n    },\n    width: {\n      control: 'number',\n    },\n    height: {\n      control: 'number',\n    },\n    natural: {\n      control: 'boolean',\n    },\n    responsive: {\n      control: 'boolean',\n    },\n    parentWidth: {\n      control: 'number',\n    },\n  },\n};\n\nexport default meta;\n"
  },
  {
    "path": "apps/examples/src/stories/Map.stories.tsx",
    "content": "import {\n  allDimensionsCode,\n  nonResponsiveDimensionsCode,\n  responsiveDimensionsCode,\n} from '@/code/map';\nimport Mapper from '@/components/Mapper';\nimport TopComponent from '@/components/TopComponent';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nconst meta = {\n  title: 'Examples/Responsive Map',\n  component: Mapper,\n  tags: ['autodocs'],\n} as Meta<typeof Mapper>;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const NonResponsiveDimensions: Story = {\n  render: (args) => {\n    const { width, height, imgWidth, natural } = args;\n\n    return (\n      <Mapper\n        height={height}\n        imgWidth={imgWidth}\n        natural={natural}\n        width={width}\n        TopComponent={() =>\n          TopComponent(\n            'Non Responsive Dimensions Example',\n            <p>\n              In this example, the <span className=\"tag\">width</span>,{' '}\n              <span className=\"tag\">height</span>,<span className=\"tag\">imgWidth</span>, and{' '}\n              <span className=\"tag\">natural</span> properties are available in the Storybook{' '}\n              <span className=\"tag\">Controls</span> tab. You can adjust them to see the{' '}\n              <span className=\"tag\">live</span> results in the image mapper.\n              <br />\n              <br />\n              Experimenting with different values in these fields highlights that making the image\n              mapper fully <span className=\"tag\">responsive</span> can be challenging.\n              <br />\n              <br />\n              <span className=\"block note\">\n                Note: Full descriptions and explanations of all properties are available in the\n                GitHub repository.\n              </span>\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: nonResponsiveDimensionsCode,\n  },\n  args: {\n    width: 640,\n    height: 480,\n    imgWidth: 0,\n    natural: false,\n  },\n  argTypes: {\n    width: {\n      control: 'number',\n    },\n    height: {\n      control: 'number',\n    },\n    imgWidth: {\n      control: 'number',\n    },\n    natural: {\n      control: 'boolean',\n    },\n  },\n};\n\nexport const ResponsiveDimensions: Story = {\n  render: (args) => {\n    const { parentWidth } = args;\n\n    return (\n      <Mapper\n        responsive\n        parentWidth={parentWidth}\n        TopComponent={() =>\n          TopComponent(\n            'Responsive Dimensions Example',\n            <p>\n              In this example, the <span className=\"tag\">responsive</span> and{' '}\n              <span className=\"tag\">parentWidth</span>\n              properties are available in the Storybook <span className=\"tag\">Controls</span> tab.\n              You can adjust them to see the <span className=\"tag\">live</span> results in the image\n              mapper.\n              <br />\n              <br />\n              By experimenting with different values for <span className=\"tag\">parentWidth</span>,\n              you&apos;ll notice that the mapper becomes responsive. Try copying the code and see\n              the results, kudos!\n              <br />\n              <br />\n              <span className=\"block note\">\n                Note: Full descriptions and explanations of all properties are available in the\n                GitHub repository.\n              </span>\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: responsiveDimensionsCode,\n  },\n  args: {\n    parentWidth: 640,\n  },\n  argTypes: {\n    parentWidth: {\n      control: 'number',\n    },\n  },\n};\n\nexport const AllDimensions: Story = {\n  render: (args) => {\n    const { width, height, imgWidth, natural, responsive, parentWidth } = args;\n\n    return (\n      <Mapper\n        height={height}\n        imgWidth={imgWidth}\n        natural={natural}\n        parentWidth={parentWidth}\n        responsive={responsive}\n        width={width}\n        TopComponent={() =>\n          TopComponent(\n            'All Dimensions Example',\n            <p>\n              In this example, the <span className=\"tag\">width</span>,{' '}\n              <span className=\"tag\">height</span>,<span className=\"tag\">imgWidth</span>,{' '}\n              <span className=\"tag\">natural</span>,<span className=\"tag\">responsive</span>, and{' '}\n              <span className=\"tag\">parentWidth</span> fields are available in the Storybook{' '}\n              <span className=\"tag\">Controls</span> tab. You can modify them to see the{' '}\n              <span className=\"tag\">live</span> results in the image mapper.\n              <br />\n              <br />\n              This example combines all responsive and non-responsive properties, have fun\n              experimenting!\n              <br />\n              <br />\n              <span className=\"block note\">\n                Note: Full descriptions and explanations of all properties are available in the\n                GitHub repository.\n              </span>\n            </p>,\n          )\n        }\n      />\n    );\n  },\n  parameters: {\n    reactCode: allDimensionsCode,\n  },\n  args: {\n    width: 640,\n    height: 480,\n    imgWidth: 0,\n    natural: false,\n    responsive: false,\n    parentWidth: 640,\n  },\n  argTypes: {\n    width: {\n      control: 'number',\n    },\n    height: {\n      control: 'number',\n    },\n    imgWidth: {\n      control: 'number',\n    },\n    natural: {\n      control: 'boolean',\n    },\n    responsive: {\n      control: 'boolean',\n    },\n    parentWidth: {\n      control: 'number',\n    },\n  },\n};\n\nexport default meta;\n"
  },
  {
    "path": "apps/examples/src/stories/Simple.stories.tsx",
    "content": "import simpleCode from '@/code/simple';\nimport Mapper from '@/components/Mapper';\nimport TopComponent from '@/components/TopComponent';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nconst meta = {\n  title: 'Examples/Simple',\n  component: Mapper,\n  tags: ['autodocs'],\n} as Meta<typeof Mapper>;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Simple: Story = {\n  render: () => (\n    <Mapper\n      TopComponent={() =>\n        TopComponent(\n          'Simple Example',\n          <p>Basic example showcasing the default setup and essential required properties.</p>,\n        )\n      }\n    />\n  ),\n  parameters: {\n    reactCode: simpleCode,\n  },\n};\n\nexport default meta;\n"
  },
  {
    "path": "apps/examples/src/styles/stories.css",
    "content": ":root {\n  --tag: #1b1f230d;\n  --block: #efefef;\n  --block-border: #cecece;\n  --tag-block: #f6f8fa;\n}\n\nbody {\n  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;\n}\n\np {\n  margin: 0;\n}\n\n.tag {\n  padding: 0.2em 0.4em;\n  margin: 0;\n  font-size: 85%;\n  background-color: var(--tag);\n  border-radius: 6px;\n}\n\n.block {\n  background: var(--block);\n  border-left: var(--block-border) solid 10px;\n  border-radius: 3px;\n  padding: 12px 16px;\n}\n\n.tag-block {\n  padding: 16px;\n  line-height: 1.75;\n  background-color: var(--tag-block);\n  border-radius: 6px;\n}\n\n.big-font {\n  font-size: 1.35rem;\n  margin-top: 1rem;\n}\n\n.top_container {\n  margin-bottom: 2rem;\n}\n\n.top_container .top_content {\n  line-height: 1.5;\n}\n"
  },
  {
    "path": "apps/examples/src/templates/clearButtonTemplate.ts",
    "content": "import CONSTANTS from '@/constants';\n\nconst { url, name, areasUrl } = CONSTANTS;\n\nconst clearButtonTemplate = `import React, { Fragment } from 'react';\nimport ImageMapper from 'react-img-mapper';\n\nconst Mapper = () => {\n  const url = '${url}';\n  const name = '${name}';\n  \n  // Get JSON from below URL as an example and put it into the useState hook\n  // URL: ${areasUrl}\n  const initialAreas = [];\n  const [areas, setAreas] = useState(initialAreas);\n  \n  return (\n    <Fragment>\n      <ImageMapper\n        src={url} \n        name={name}\n        areas={areas}\n        onChange={(_, newAreas) => setAreas(newAreas)}\n        isMulti\n       />\n       <button onClick={() => setAreas(initialAreas)}>Clear</button>\n    </Fragment>\n  )\n}\n\nexport default Mapper;`;\n\nexport default clearButtonTemplate;\n"
  },
  {
    "path": "apps/examples/src/templates/variablesTemplate.ts",
    "content": "import CONSTANTS from '@/constants';\n\nconst { url, name, areasUrl } = CONSTANTS;\n\nconst variablesTemplate = `const url = '${url}';\n  const name = '${name}';\n  // Get JSON from below URL as an example and put it here\n  const areas = '${areasUrl}';`;\n\nexport default variablesTemplate;\n"
  },
  {
    "path": "apps/examples/src/templates/zoomTemplate.ts",
    "content": "import variablesTemplate from '@/templates/variablesTemplate';\n\nconst zoomTemplate = `import React, { Fragment, useState } from 'react';\nimport ImageMapper from 'react-img-mapper';\n\nconst Mapper = props => {\n  const minWidth = 400;\n  const [zoom, setZoom] = useState(640);\n\n  ${variablesTemplate}\n\n  const handleZoom = type => {\n    setZoom(prev => {\n      if (prev <= minWidth && type === 'out') return prev;\n      return type === 'in' ? prev + props.parentWidth : prev - props.parentWidth;\n    });\n  };\n  \n  return (\n    <Fragment>\n      <ImageMapper\n        src={url} \n        name={name}\n        areas={areas}\n        responsive\n        parentWidth={zoom}\n       />\n       <button style={{ marginRight: 8 }} onClick={() => handleZoom('in')}>Zoom In</button>\n       <button onClick={() => handleZoom('out')}>Zoom Out</button>\n    </Fragment>\n  )\n}\n\nexport default Mapper;`;\n\nexport default zoomTemplate;\n"
  },
  {
    "path": "apps/examples/src/types/globals.d.ts",
    "content": "import 'react-img-mapper';\n\ndeclare module 'react-img-mapper' {\n  interface OverrideMapArea {\n    title: string;\n  }\n}\n"
  },
  {
    "path": "apps/examples/src/types/index.ts",
    "content": "import type { FC, ReactNode } from 'react';\n\nexport interface Children {\n  children: ReactNode;\n}\n\nexport type Component<E = unknown> = FC<E>;\n\nexport type Layout<E = unknown> = Component<Children & E>;\n"
  },
  {
    "path": "apps/examples/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"jsx\": \"react-jsx\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \"**/*.mjs\",\n    \"**/*.mts\",\n    \"**/*.d.ts\",\n    \".storybook/**/*.ts\",\n    \".storybook/**/*.tsx\"\n  ],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "apps/examples/vercel.json",
    "content": "{\n  \"$schema\": \"https://openapi.vercel.sh/vercel.json\",\n  \"buildCommand\": \"pnpm build\",\n  \"cleanUrls\": true,\n  \"devCommand\": \"pnpm dev\",\n  \"framework\": \"storybook\",\n  \"installCommand\": \"pnpm install\",\n  \"outputDirectory\": \"storybook-static\"\n}\n"
  },
  {
    "path": "docs/.vitepress/config.mts",
    "content": "import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineConfig } from 'vitepress';\nimport { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons';\n\nimport type { Plugin } from 'vitepress';\n\nconst projectRoot = fileURLToPath(new URL('../..', import.meta.url));\nconst { version } = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));\n\nconst githubUrl = 'https://github.com/img-mapper/img-mapper';\nconst npmUrl = 'https://www.npmjs.com/package/react-img-mapper';\nconst siteUrl = 'https://img-mapper.nishargshah.dev';\nconst exampleUrl = 'https://img-mapper-examples.nishargshah.dev';\n\nconst title = 'Img Mapper';\nconst description =\n  'A React/Vue Component for Creating Interactive and Highlighted Zones on Images';\n\nexport default defineConfig({\n  title,\n  description,\n  cleanUrls: true,\n  lastUpdated: true,\n  rewrites: {},\n  markdown: {\n    config(md) {\n      md.use(groupIconMdPlugin);\n    },\n  },\n  vite: {\n    plugins: [groupIconVitePlugin() as Plugin],\n  },\n  sitemap: {\n    hostname: siteUrl,\n  },\n  themeConfig: {\n    logo: '/logo.png',\n    nav: [\n      {\n        text: 'Guide',\n        link: '/',\n      },\n      {\n        text: 'Examples',\n        link: exampleUrl,\n      },\n      {\n        text: `v${version}`,\n        items: [\n          {\n            text: 'Release Notes',\n            link: `${githubUrl}/releases`,\n          },\n          {\n            text: 'Changelog',\n            link: `${githubUrl}/blob/master/CHANGELOG.md`,\n          },\n          {\n            text: 'Contributing',\n            link: '/contribute/guide',\n          },\n        ],\n      },\n    ],\n    sidebar: [\n      {\n        text: 'Introduction',\n        items: [\n          {\n            text: 'Getting Started',\n            link: '/guide/getting-started',\n          },\n          {\n            text: 'Examples',\n            link: '/guide/examples',\n          },\n        ],\n      },\n      {\n        text: 'React',\n        collapsed: false,\n        items: [\n          {\n            text: 'Installation',\n            link: '/react/installation',\n          },\n          {\n            text: 'Properties',\n            link: '/react/properties',\n          },\n        ],\n      },\n      {\n        text: 'Vue',\n        collapsed: false,\n        items: [\n          {\n            text: 'Installation',\n            link: '/vue/installation',\n          },\n          {\n            text: 'Properties',\n            link: '/vue/properties',\n          },\n        ],\n      },\n      {\n        text: 'Contribute',\n        items: [\n          {\n            text: 'Contributing',\n            link: '/contribute/guide',\n          },\n        ],\n      },\n    ],\n    socialLinks: [\n      {\n        icon: 'github',\n        link: githubUrl,\n      },\n      {\n        icon: 'npm',\n        link: npmUrl,\n      },\n    ],\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: 'Copyright © 2025-PRESENT <br/> Made with ❤️ by Nisharg Shah',\n    },\n    editLink: {\n      pattern: `${githubUrl}/edit/master/docs/:path`,\n      text: 'Edit this page on GitHub',\n    },\n    lastUpdated: {\n      text: 'Last Updated on',\n      formatOptions: {\n        dateStyle: 'medium',\n        timeStyle: 'short',\n        hour12: true,\n      },\n    },\n    search: {\n      provider: 'local',\n      options: {\n        detailedView: true,\n      },\n    },\n  },\n  head: [\n    ['link', { rel: 'icon', href: '/logo.png', type: 'image/png' }],\n    ['meta', { name: 'theme-color', content: '#ffffff' }],\n    ['meta', { name: 'author', content: `${title} Team` }],\n    [\n      'meta',\n      { name: 'viewport', content: 'width=device-width, initial-scale=1.0, viewport-fit=cover' },\n    ],\n    [\n      'meta',\n      {\n        name: 'description',\n        content: description,\n      },\n    ],\n    [\n      'meta',\n      {\n        name: 'keywords',\n        content:\n          'img-mapper, image-mapper, react-img-mapper, react-image-mapper, vue-img-mapper, vue-image-mapper, img mapper, image mapper, react img mapper, react image mapper, vue img mapper, vue image mapper',\n      },\n    ],\n    // OG\n    ['meta', { property: 'og:title', content: title }],\n    [\n      'meta',\n      {\n        property: 'og:description',\n        content: description,\n      },\n    ],\n    [\n      'meta',\n      {\n        property: 'og:image',\n        content: `${siteUrl}/og-logo.png`,\n      },\n    ],\n    ['meta', { property: 'og:type', content: 'website' }],\n    ['meta', { property: 'og:url', content: siteUrl }],\n    ['meta', { property: 'og:site_name', content: title }],\n    // TWITTER\n    ['meta', { name: 'twitter:title', content: title }],\n    [\n      'meta',\n      {\n        name: 'twitter:description',\n        content: description,\n      },\n    ],\n    [\n      'meta',\n      {\n        name: 'twitter:image',\n        content: `${siteUrl}/og-logo.png`,\n      },\n    ],\n    ['meta', { name: 'twitter:card', content: 'summary_large_image' }],\n    ['meta', { name: 'twitter:creator', content: '@iamnisharg' }],\n  ],\n});\n"
  },
  {
    "path": "docs/.vitepress/theme/index.ts",
    "content": "import { inject } from '@vercel/analytics';\n// eslint-disable-next-line import-x/no-unresolved\nimport 'virtual:group-icons.css';\nimport Theme from 'vitepress/theme';\n\nimport './style.css';\n\nexport default {\n  extends: Theme,\n  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n  enhanceApp() {\n    if (globalThis.window !== undefined) {\n      inject();\n    }\n  },\n};\n"
  },
  {
    "path": "docs/.vitepress/theme/style.css",
    "content": "/**\n * Theme\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-c-brand-1: #00acc1;\n}\n\n.VPImage.image-src {\n  margin-top: 2rem;\n}\n\n/**\n * Component: Home\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(90deg, var(--vp-c-brand-1), #a67cff);\n  --vp-home-hero-image-background-image: linear-gradient(160deg, #00bdd680, #8c24a880);\n  --vp-home-hero-image-filter: blur(40px);\n}\n\n.dark {\n  --vp-home-hero-image-background-image: linear-gradient(160deg, var(--vp-c-brand-1), #8e24aa);\n}\n\n@media (min-width: 640px) {\n  :root {\n    --vp-home-hero-image-filter: blur(56px);\n  }\n}\n\n@media (min-width: 960px) {\n  :root {\n    --vp-home-hero-image-filter: blur(72px);\n  }\n}\n\n/**\n * Component: Button\n * -------------------------------------------------------------------------- */\n:root {\n  --vp-button-brand-bg: var(--vp-c-brand-1);\n  --vp-button-brand-hover-bg: #0097a7;\n  --vp-button-brand-active-bg: #00838f;\n}\n\n.dark {\n  --vp-button-brand-bg: var(--vp-c-brand-1);\n  --vp-button-brand-hover-bg: #26c6da;\n  --vp-button-brand-active-bg: #4dd0e1;\n}\n"
  },
  {
    "path": "docs/contribute/guide.md",
    "content": "# Contributing {#contributing}\n\nThank you for considering contributing to `img-mapper`. We welcome all contributions, whether it’s fixing a bug, improving documentation, or suggesting new rules.\n\n## How to Contribute {#how-to-contribute}\n\n### 1. Fork & Clone the Repository {#for-clone-repository}\n\n::: code-group\n\n```sh [SSH]\n$ git clone git@github.com:img-mapper/img-mapper.git\n$ cd img-mapper\n```\n\n```sh [HTTPS]\n$ git clone https://github.com/img-mapper/img-mapper.git\n$ cd img-mapper\n```\n\n:::\n\n### 2. Install Dependencies {#install-dependencies}\n\nCheck the `.nvmrc` file for the required Node.js version. For `pnpm` version, see the `packageManager` field in the root `package.json`.\n\nThis project is a **monorepo** managed with **pnpm**. Install dependencies with:\n\n```sh\n$ pnpm install\n```\n\n### 3. Project Structure {#project-structure}\n\nThe repo is organized as a monorepo with two main packages:\n\n- `packages/react-img-mapper` → React img mapper package\n- `packages/vue-img-mapper` → Vue img mapper package\n- `apps/examples` → Img mapper examples\n- `docs/` → Documentation site (built with VitePress)\n\n### 4. Making Changes {#making-changes}\n\n- Always create a new branch:\n\n  ```sh\n  $ git checkout -b fix/your-change\n  ```\n\n- For docs → check formatting and verify links.\n\n### 5. Linting & Formatting {#linting-formatting}\n\nRun checks and fixes before committing:\n\n::: code-group\n\n```sh [Check]\n$ pnpm lint\n$ pnpm format:check\n```\n\n```sh [Fix]\n$ pnpm lint:fix\n$ pnpm format:fix\n```\n\n:::\n\n### 6. Commit Guidelines {#commit-guidelines}\n\nWe follow **Conventional Commits** for a clean commit history. Examples:\n\n- `feat: implement ESM functionality`\n- `fix: resolve path alias issue`\n- `docs: update installation steps`\n\n### 7. Running Scripts {#running-scripts}\n\nBefore pushing, ensure all scripts pass:\n\n```sh\n$ pnpm script:lint\n```\n\n### 8. Submitting a PR {#submitting-pr}\n\n- Push your branch and open a Pull Request against `canary`.\n- Clearly describe the problem, your solution, and reference any related issues/discussions.\n- Maintainers will review, suggest improvements if needed, and merge once approved.\n\n## Code of Conduct {#code-of-conduct}\n\nThis project follows a [**Code of Conduct**](https://github.com/img-mapper/img-mapper/blob/master/CODE_OF_CONDUCT.md). Please be respectful, collaborative, and inclusive.\n\n## Suggestions & Issues {#suggestions-issues}\n\n- Found a bug? → [Open an Issue](https://github.com/img-mapper/img-mapper/issues/new/choose)\n- Want a new feature or rule? → Use the same link to create an issue, or start a discussion before opening a PR.\n"
  },
  {
    "path": "docs/guide/examples.md",
    "content": "# Examples {#examples}\n\nExplore live demos of Img Mapper at: [**img-mapper-examples.nishargshah.dev**](https://img-mapper-examples.nishargshah.dev)\n\n::: tip\n\nUse the site to quickly explore examples and see how interactive areas, events, and responsive scaling work in real time.\n\n:::\n\nThe examples site demonstrates **real-world use cases** of Img Mapper in both **React** and **Vue**. Each demo illustrates how to:\n\n- Define interactive image regions using JSON-based coordinate maps\n- Implement hover, click, and other interactions\n- Implement Multi-selection and toggle support for complex workflows\n- Customize styles with fill colors, strokes, and opacities\n- Ensure responsive behavior as images and maps scale across devices\n\nWhether you're building product hotspots, floor plans, or data visualizations, these examples provide practical insights into integrating Img Mapper into your projects.\n\nEach demo is **playable and editable**, giving you hands-on understanding of how to integrate Img Mapper into your own projects.\n"
  },
  {
    "path": "docs/guide/getting-started.md",
    "content": "# Getting Started {#getting-started}\n\n**Img Mapper** is an open-source library that enables developers to create **interactive, clickable, and highlightable regions on images**.\n\nIt simplifies building visual interfaces like seat maps, product previews, floor plans, or educational diagrams, anywhere you want users to interact directly with parts of an image.\n\nThe library provides a **declarative API** to define areas using coordinate data, manage hover and click events, and style highlighted zones.\nIt is available for both **React** and **Vue**, ensuring a consistent experience across frameworks.\n\n## React Img Mapper {#react-img-mapper}\n\n**React Img Mapper** is the React implementation of Img Mapper.\nIt allows you to define and manage image map regions in React components with full event support.\n\n### Key Features {#react-key-features}\n\n- Define clickable or hoverable zones with JSON coordinates\n- Handle events like `onClick`, `onMouseEnter`, and `onMouseLeave`\n- Customize colors, opacity, and borders for each area\n- Supports responsive resizing while preserving mapping accuracy\n\n## Vue Img Mapper {#vue-img-mapper}\n\n**Vue Img Mapper** brings the same functionality to the Vue ecosystem with a native component syntax.\n\n### Key Features {#vue-key-features}\n\n- Simple and reactive props for managing maps and areas\n- Emits events such as `click`, `mouseenter`, and `mouseleave`\n- Full compatibility with Vue 3 composition API\n- Lightweight and flexible and perfect for interactive UIs\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\n# https://vitepress.dev/reference/default-theme-home-page\nlayout: home\n\nhero:\n  name: 'Img Mapper'\n  tagline: A React/Vue Component for Creating Interactive and Highlighted Zones on Images\n  image:\n    src: /logo.png\n    alt: Image\n  actions:\n    - theme: brand\n      text: Get Started\n      link: /guide/getting-started\n    - theme: alt\n      text: React\n      link: /react/installation\n    - theme: alt\n      text: Vue\n      link: /vue/installation\n\nfeatures:\n  - icon: 🚀\n    title: Next.js & SSR Ready\n    details: Works perfectly with Next.js and other SSR frameworks.\n  - icon: 📱\n    title: Fully Responsive\n    details: Automatically adapts to any screen size or container.\n  - icon: 📦\n    title: TypeScript Support\n    details: Out-of-the-box TypeScript support for all your code.\n  - icon: 🪶\n    title: Lightweight & Fast\n    details: Minimal bundle size for top-notch performance.\n  - icon: ⚙️\n    title: Composable API\n    details: Designed for flexibility and easy integration in React apps.\n  - icon: 📘\n    title: Extensive Docs & Examples\n    details: Learn quickly with guided usage and live demos.\n---\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"img-mapper-docs\",\n  \"version\": \"2.0.3\",\n  \"private\": true,\n  \"description\": \"Documentation of img-mapper\",\n  \"homepage\": \"https://img-mapper.nishargshah.dev\",\n  \"bugs\": {\n    \"url\": \"https://github.com/img-mapper/img-mapper/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/img-mapper/img-mapper.git\",\n    \"directory\": \"docs\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Nisharg Shah <nishargshah3101@gmail.com>\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"vitepress build\",\n    \"dev\": \"vitepress dev\",\n    \"preview\": \"vitepress preview\",\n    \"typecheck\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@vercel/analytics\": \"catalog:\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"catalog:\",\n    \"vitepress\": \"^1.6.4\",\n    \"vitepress-plugin-group-icons\": \"^1.6.4\"\n  }\n}\n"
  },
  {
    "path": "docs/react/installation.md",
    "content": "# Installation {#installation}\n\nInstall **react-img-mapper** using your preferred package manager:\n\n::: code-group\n\n```sh [npm]\n$ npm install react-img-mapper\n```\n\n```sh [yarn]\n$ yarn add react-img-mapper\n```\n\n```sh [pnpm]\n$ pnpm install react-img-mapper\n```\n\n:::\n\n## Usage Example\n\nIntegrate `react-img-mapper` into your React app:\n\n```javascript\nimport React from 'react';\nimport ImageMapper from 'react-img-mapper';\n\nconst Mapper = () => {\n  const url = 'https://img-mapper-examples.nishargshah.dev/assets/example.jpg';\n  const name = 'my-map';\n  // Get JSON from below URL as an example and put it here\n  const areas = 'https://img-mapper-examples.nishargshah.dev/assets/areas.json';\n\n  return <ImageMapper src={url} name={name} areas={areas} />;\n};\n\nexport default Mapper;\n```\n"
  },
  {
    "path": "docs/react/properties.md",
    "content": "# Properties {#properties}\n\nTogether, below sections let you fully control the component, customize its behavior and appearance, handle user interactions, configure individual areas, and access internal function references via React refs.\n\n## Component Properties {#component-properties}\n\nConfigure the main behavior, appearance, and responsiveness of the component.\n\n| Prop             | Type                       | Description                                                | Default                    |\n| ---------------- | -------------------------- | ---------------------------------------------------------- | -------------------------- |\n| `src`            | string                     | Image URL to display                                       | **required**               |\n| `name`           | string                     | Unique map name associated with the image                  | **required**               |\n| `areas`          | array                      | Array of area objects (see **Area Properties**)            | **required**               |\n| `areaKeyName`    | string                     | Key used to uniquely identify areas                        | `id`                       |\n| `isMulti`        | bool                       | Allows multiple areas to be selected                       | `true`                     |\n| `toggle`         | bool                       | Enables toggling selection on click                        | `false`                    |\n| `active`         | bool                       | Enables area listeners and highlighting                    | `true`                     |\n| `disabled`       | bool                       | Disables highlighting and interactions                     | `false`                    |\n| `fillColor`      | string                     | Highlight fill color                                       | `rgba(255, 255, 255, 0.5)` |\n| `strokeColor`    | string                     | Highlight border color                                     | `rgba(0, 0, 0, 0.5)`       |\n| `lineWidth`      | number                     | Border thickness of highlighted zones                      | `1`                        |\n| `imgWidth`       | number                     | Original width of the image                                | `0`                        |\n| `width`          | number \\| (func => number) | Image width (can be use as a function for dynamic sizing)  | `0`                        |\n| `height`         | number \\| (func => number) | Image height (can be use as a function for dynamic sizing) | `0`                        |\n| `natural`        | bool                       | Use the image's original dimensions                        | `false`                    |\n| `responsive`     | bool                       | Enable responsive scaling (requires `parentWidth`)         | `false`                    |\n| `parentWidth`    | number                     | Max width of parent container                              | `0`                        |\n| `containerProps` | object                     | Props for the wrapping `<div>`                             | `null`                     |\n| `imgProps`       | object                     | Props for the `<img>` element                              | `null`                     |\n| `canvasProps`    | object                     | Props for the `<canvas>` element                           | `null`                     |\n| `mapProps`       | object                     | Props for the `<map>` element                              | `null`                     |\n| `areaProps`      | object \\| array            | Props for `<area>` elements                                | `null`                     |\n\n## Callbacks {#callbacks}\n\nHandle user interactions, such as clicks, hovers, and touch events on the mapped areas or image.\n\n| Callback           | Trigger                           | Signature                       |\n| ------------------ | --------------------------------- | ------------------------------- |\n| `onChange`         | Click on an area                  | `(selectedArea, areas) => void` |\n| `onImageClick`     | Click outside mapped areas        | `(event) => void`               |\n| `onImageMouseMove` | Mouse move over the image         | `(event) => void`               |\n| `onClick`          | Click on a mapped area            | `(area, index, event) => void`  |\n| `onMouseDown`      | Mouse down on area                | `(area, index, event) => void`  |\n| `onMouseUp`        | Mouse up on area                  | `(area, index, event) => void`  |\n| `onTouchStart`     | Touch start on area               | `(area, index, event) => void`  |\n| `onTouchEnd`       | Touch end on area                 | `(area, index, event) => void`  |\n| `onMouseMove`      | Mouse move over area              | `(area, index, event) => void`  |\n| `onMouseEnter`     | Hover over area                   | `(area, index, event) => void`  |\n| `onMouseLeave`     | Leave area                        | `(area, index, event) => void`  |\n| `onLoad`           | Image loaded & canvas initialized | `(event, dimensions) => void`   |\n\n## Methods {#methods}\n\nRetrieve internal function references through React refs for advanced control.\n\n| Method    | Description                                                |\n| --------- | ---------------------------------------------------------- |\n| `getRefs` | Returns refs for the container, canvas, and image elements |\n\n---\n\n## Area Properties {#area-properties}\n\nDefine individual area shapes, coordinates, styling, and interaction behavior within the image map.\n\n| Property       | Type     | Description                                                                                                                                                                                                                                      | Default                    |\n| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------- |\n| `id`           | string   | Unique identifier; defaults to index if not provided. This can be customized using the `areaKeyName` property.                                                                                                                                   | based on `areaKeyName`     |\n| `shape`        | string   | Shape: `rect`, `circle`, `poly`                                                                                                                                                                                                                  | **required**               |\n| `coords`       | string[] | Coordinates for the area: <ul><li>**rect**: `top-left-X, top-left-Y, bottom-right-X, bottom-right-Y`</li><li>**circle**: `center-X, center-Y, radius`</li><li>**poly**: List of points defining the polygon as `point-X, point-Y, ...`</li></ul> | **required**               |\n| `active`       | bool     | Enables area listeners and highlighting                                                                                                                                                                                                          | `true`                     |\n| `disabled`     | bool     | Disables highlighting and interactions                                                                                                                                                                                                           | `false`                    |\n| `href`         | string   | Target link for area clicks, ignored if `onClick` exists                                                                                                                                                                                         | `undefined`                |\n| `fillColor`    | string   | Highlight fill color                                                                                                                                                                                                                             | `rgba(255, 255, 255, 0.5)` |\n| `strokeColor`  | string   | Highlight border color                                                                                                                                                                                                                           | `rgba(0, 0, 0, 0.5)`       |\n| `lineWidth`    | number   | Border thickness of highlighted zones                                                                                                                                                                                                            | `1`                        |\n| `preFillColor` | string   | Pre-filled highlight color                                                                                                                                                                                                                       | `undefined`                |\n\nAdditional properties available when triggered via an event:\n\n| Property       | Type     | Description                                |\n| -------------- | -------- | ------------------------------------------ |\n| `scaledCoords` | number[] | Coordinates adjusted to current image size |\n| `center`       | number[] | Centroid coordinates `[X, Y]` of the area  |\n"
  },
  {
    "path": "docs/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    }\n  },\n  \"include\": [\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \"**/*.mjs\",\n    \"**/*.mts\",\n    \".vitepress/**/*.ts\",\n    \".vitepress/**/*.mts\"\n  ],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "docs/vercel.json",
    "content": "{\n  \"$schema\": \"https://openapi.vercel.sh/vercel.json\",\n  \"buildCommand\": \"pnpm build\",\n  \"cleanUrls\": true,\n  \"devCommand\": \"pnpm dev\",\n  \"framework\": \"vitepress\",\n  \"installCommand\": \"pnpm install\",\n  \"outputDirectory\": \".vitepress/dist\"\n}\n"
  },
  {
    "path": "docs/vue/installation.md",
    "content": "# Installation {#installation}\n\n::: warning\n\n`vue-img-mapper` is currently in beta. Features and APIs are still evolving and improvements are coming soon.\n\n:::\n\nInstall **vue-img-mapper** using your preferred package manager:\n\n::: code-group\n\n```sh [npm]\n$ npm install vue-img-mapper\n```\n\n```sh [yarn]\n$ yarn add vue-img-mapper\n```\n\n```sh [pnpm]\n$ pnpm install vue-img-mapper\n```\n\n:::\n\n## Usage Example\n\nIntegrate `vue-img-mapper` into your Vue app:\n\n```javascript\n<template>\n  <ImageMapper :src=\"src\" :map=\"map\" />\n</template>\n\n<script>\nimport ImageMapper from 'vue-img-mapper';\n\nexport default {\n  name: 'Mapper',\n  components: { ImageMapper },\n  computed: {\n    src: () => 'https://img-mapper-examples.nishargshah.dev/assets/example.jpg',\n    map() {\n      return {\n        name: 'my-map',\n        // Get JSON from below URL as an example and put it here\n        areas: 'https://img-mapper-examples.nishargshah.dev/assets/areas.json',\n      };\n    },\n  },\n};\n</script>\n```\n"
  },
  {
    "path": "docs/vue/properties.md",
    "content": "# Properties {#properties}\n\n::: warning\n\n`vue-img-mapper` is currently in beta. Features and APIs are still evolving and improvements are coming soon.\n\n:::\n\nTogether, below sections let you fully control the component, customize its behavior and appearance, handle user interactions, configure individual areas, and access internal function references via Vue refs.\n\n## Component Properties {#component-properties}\n\nConfigure the main behavior, appearance, and responsiveness of the component.\n\n| Prop             | Type                       | Description                                                | Default                    |\n| ---------------- | -------------------------- | ---------------------------------------------------------- | -------------------------- |\n| `src`            | string                     | Image URL to display                                       | **required**               |\n| `name`           | string                     | Unique map name associated with the image                  | **required**               |\n| `areas`          | array                      | Array of area objects (see **Area Properties**)            | **required**               |\n| `areaKeyName`    | string                     | Key used to uniquely identify areas                        | `id`                       |\n| `isMulti`        | bool                       | Allows multiple areas to be selected                       | `true`                     |\n| `toggle`         | bool                       | Enables toggling selection on click                        | `false`                    |\n| `active`         | bool                       | Enables area listeners and highlighting                    | `true`                     |\n| `disabled`       | bool                       | Disables highlighting and interactions                     | `false`                    |\n| `fillColor`      | string                     | Highlight fill color                                       | `rgba(255, 255, 255, 0.5)` |\n| `strokeColor`    | string                     | Highlight border color                                     | `rgba(0, 0, 0, 0.5)`       |\n| `lineWidth`      | number                     | Border thickness of highlighted zones                      | `1`                        |\n| `imgWidth`       | number                     | Original width of the image                                | `0`                        |\n| `width`          | number \\| (func => number) | Image width (can be use as a function for dynamic sizing)  | `0`                        |\n| `height`         | number \\| (func => number) | Image height (can be use as a function for dynamic sizing) | `0`                        |\n| `natural`        | bool                       | Use the image's original dimensions                        | `false`                    |\n| `responsive`     | bool                       | Enable responsive scaling (requires `parentWidth`)         | `false`                    |\n| `parentWidth`    | number                     | Max width of parent container                              | `0`                        |\n| `containerProps` | object                     | Props for the wrapping `<div>`                             | `null`                     |\n| `imgProps`       | object                     | Props for the `<img>` element                              | `null`                     |\n| `canvasProps`    | object                     | Props for the `<canvas>` element                           | `null`                     |\n| `mapProps`       | object                     | Props for the `<map>` element                              | `null`                     |\n| `areaProps`      | object \\| array            | Props for `<area>` elements                                | `null`                     |\n\n## Callbacks {#callbacks}\n\nHandle user interactions, such as clicks, hovers, and touch events on the mapped areas or image.\n\n| Callback          | Trigger                           | Signature                       |\n| ----------------- | --------------------------------- | ------------------------------- |\n| `@change`         | Click on an area                  | `(selectedArea, areas) => void` |\n| `@imageClick`     | Click outside mapped areas        | `(event) => void`               |\n| `@imageMouseMove` | Mouse move over the image         | `(event) => void`               |\n| `@click`          | Click on a mapped area            | `(area, index, event) => void`  |\n| `@mousedown`      | Mouse down on area                | `(area, index, event) => void`  |\n| `@mouseup`        | Mouse up on area                  | `(area, index, event) => void`  |\n| `@touchstart`     | Touch start on area               | `(area, index, event) => void`  |\n| `@touchend`       | Touch end on area                 | `(area, index, event) => void`  |\n| `@mousemove`      | Mouse move over area              | `(area, index, event) => void`  |\n| `@mouseenter`     | Hover over area                   | `(area, index, event) => void`  |\n| `@mouseleave`     | Leave area                        | `(area, index, event) => void`  |\n| `@load`           | Image loaded & canvas initialized | `(event, dimensions) => void`   |\n\n## Methods {#methods}\n\nRetrieve internal function references through Vue refs for advanced control.\n\n| Method    | Description                                                |\n| --------- | ---------------------------------------------------------- |\n| `getRefs` | Returns refs for the container, canvas, and image elements |\n\n---\n\n## Area Properties {#area-properties}\n\nDefine individual area shapes, coordinates, styling, and interaction behavior within the image map.\n\n| Property       | Type     | Description                                                                                                                                                                                                                                      | Default                    |\n| -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------- |\n| `id`           | string   | Unique identifier; defaults to index if not provided. This can be customized using the `areaKeyName` property.                                                                                                                                   | based on `areaKeyName`     |\n| `shape`        | string   | Shape: `rect`, `circle`, `poly`                                                                                                                                                                                                                  | **required**               |\n| `coords`       | string[] | Coordinates for the area: <ul><li>**rect**: `top-left-X, top-left-Y, bottom-right-X, bottom-right-Y`</li><li>**circle**: `center-X, center-Y, radius`</li><li>**poly**: List of points defining the polygon as `point-X, point-Y, ...`</li></ul> | **required**               |\n| `active`       | bool     | Enables area listeners and highlighting                                                                                                                                                                                                          | `true`                     |\n| `disabled`     | bool     | Disables highlighting and interactions                                                                                                                                                                                                           | `false`                    |\n| `href`         | string   | Target link for area clicks, ignored if `onClick` exists                                                                                                                                                                                         | `undefined`                |\n| `fillColor`    | string   | Highlight fill color                                                                                                                                                                                                                             | `rgba(255, 255, 255, 0.5)` |\n| `strokeColor`  | string   | Highlight border color                                                                                                                                                                                                                           | `rgba(0, 0, 0, 0.5)`       |\n| `lineWidth`    | number   | Border thickness of highlighted zones                                                                                                                                                                                                            | `1`                        |\n| `preFillColor` | string   | Pre-filled highlight color                                                                                                                                                                                                                       | `undefined`                |\n\nAdditional properties available when triggered via an event:\n\n| Property       | Type     | Description                                |\n| -------------- | -------- | ------------------------------------------ |\n| `scaledCoords` | number[] | Coordinates adjusted to current image size |\n| `center`       | number[] | Centroid coordinates `[X, Y]` of the area  |\n"
  },
  {
    "path": "eslint.config.mjs",
    "content": "import customGeneralESLintConfig from './lint/general.eslint.mjs';\nimport customImportESLintConfig from './lint/import.eslint.mjs';\nimport customJSESLintConfig from './lint/javascript.eslint.mjs';\nimport customPrettierESLintConfig from './lint/prettier.eslint.mjs';\nimport customReactESLintConfig from './lint/react.eslint.mjs';\nimport customTSESLintConfig from './lint/typescript.eslint.mjs';\nimport { gitIgnoreFile } from './lint/utils.eslint.mjs';\n\nexport default [\n  gitIgnoreFile,\n  ...customJSESLintConfig,\n  ...customReactESLintConfig,\n  ...customTSESLintConfig,\n  ...customImportESLintConfig,\n  ...customGeneralESLintConfig,\n  ...customPrettierESLintConfig,\n];\n"
  },
  {
    "path": "lint/general.eslint.mjs",
    "content": "const customGeneralESLintConfig = [\n  {\n    name: 'x/general/rules',\n    rules: {\n      'no-console': 'off',\n      'no-void': 'off',\n      'consistent-return': 'off',\n      'no-array-constructor': 'off',\n      'no-underscore-dangle': [\n        'error',\n        {\n          allow: ['_id'],\n        },\n      ],\n      'no-restricted-syntax': [\n        'error',\n        'ForStatement',\n        'ContinueStatement',\n        'DoWhileStatement',\n        'WhileStatement',\n        'WithStatement',\n        // React\n        {\n          selector: 'MemberExpression[object.name=\"React\"]',\n          message: 'Use of React.method is not allowed.',\n        },\n        // React - TypeScript\n        {\n          selector: 'TSTypeReference[typeName.left.name=\"React\"]',\n          message: 'Use of React.type is not allowed.',\n        },\n      ],\n    },\n  },\n  {\n    name: 'x/general/ts-only',\n    files: ['**/*.{ts,cts,mts,tsx}'],\n    ignores: ['docs/**/*.{ts,cts,mts,tsx}'],\n    rules: {\n      'no-restricted-imports': [\n        'error',\n        {\n          patterns: [\n            {\n              group: ['./*', '../*'],\n              message: \"Please use the absolute path '@/*' instead.\",\n            },\n          ],\n        },\n      ],\n    },\n  },\n];\n\nexport default customGeneralESLintConfig;\n"
  },
  {
    "path": "lint/import.eslint.mjs",
    "content": "import { rules } from 'eslint-config-airbnb-extended';\nimport unusedImportsPlugin from 'eslint-plugin-unused-imports';\n\nconst customImportESLintConfig = [\n  // Strict Import Rules\n  rules.base.importsStrict,\n  // Unused Import Config\n  {\n    name: 'unused-imports/config',\n    plugins: {\n      'unused-imports': unusedImportsPlugin,\n    },\n    rules: {\n      'unused-imports/no-unused-imports': 'error',\n    },\n  },\n  // Disable Default Export for Hooks\n  {\n    name: 'x/import-x/disable-default-export',\n    files: ['**/use*.ts'],\n    rules: {\n      'import-x/prefer-default-export': 'off',\n    },\n  },\n  // Disable Dependencies Import Issue for Templates ESLint Files\n  {\n    name: 'x/import-x/disable-extraneous-deps',\n    files: ['docs/**/*.{ts,cts,mts,tsx}'],\n    rules: {\n      'import-x/no-extraneous-dependencies': 'off',\n    },\n  },\n  // Disable Extensions in Module Files\n  {\n    name: 'x/import-x/disable-extensions-in-module-files',\n    files: ['**/*.mjs'],\n    rules: {\n      'import-x/extensions': 'off',\n    },\n  },\n];\n\nexport default customImportESLintConfig;\n"
  },
  {
    "path": "lint/javascript.eslint.mjs",
    "content": "import js from '@eslint/js';\nimport { configs, plugins } from 'eslint-config-airbnb-extended';\nimport promisePlugin from 'eslint-plugin-promise';\nimport unicornPlugin from 'eslint-plugin-unicorn';\n\nconst customJSESLintConfig = [\n  // ESLint Recommended Rules\n  {\n    name: 'js/config',\n    ...js.configs.recommended,\n  },\n  // Stylistic Plugin\n  plugins.stylistic,\n  // Import X Plugin\n  plugins.importX,\n  // Airbnb Base Recommended Config\n  ...configs.base.recommended,\n  // Promise Config\n  promisePlugin.configs['flat/recommended'],\n  // Unicorn Config\n  unicornPlugin.configs.recommended,\n  // Unicorn Config Rules\n  {\n    name: 'x/unicorn/rules',\n    rules: {\n      'unicorn/filename-case': [\n        'error',\n        {\n          cases: {\n            kebabCase: true,\n            camelCase: true,\n            pascalCase: true,\n          },\n          multipleFileExtensions: false,\n        },\n      ],\n      'unicorn/prevent-abbreviations': 'off',\n      'unicorn/no-null': 'off',\n      'unicorn/no-array-reduce': 'off',\n      'unicorn/consistent-function-scoping': 'off',\n    },\n  },\n];\n\nexport default customJSESLintConfig;\n"
  },
  {
    "path": "lint/prettier.eslint.mjs",
    "content": "import { rules as prettierConfigRules } from 'eslint-config-prettier';\nimport prettierPlugin from 'eslint-plugin-prettier';\n\nconst customPrettierESLintConfig = [\n  // Prettier Plugin\n  {\n    name: 'prettier/plugin/config',\n    plugins: {\n      prettier: prettierPlugin,\n    },\n  },\n  // Prettier Config\n  {\n    name: 'prettier/config',\n    rules: {\n      ...prettierConfigRules,\n      'prettier/prettier': 'error',\n    },\n  },\n];\n\nexport default customPrettierESLintConfig;\n"
  },
  {
    "path": "lint/react.eslint.mjs",
    "content": "import { configs, plugins, rules } from 'eslint-config-airbnb-extended';\n\nconst customReactESLintConfig = [\n  // React Plugin\n  plugins.react,\n  // React Hooks Plugin\n  plugins.reactHooks,\n  // React JSX A11y Plugin\n  plugins.reactA11y,\n  // Airbnb Next Recommended Config\n  ...configs.react.recommended,\n  // Airbnb React Strict Rules\n  rules.react.strict,\n  // JSX A11y Config Rules\n  {\n    name: 'x/jsx-a11y/rules',\n    rules: {\n      'jsx-a11y/label-has-associated-control': 'off',\n    },\n  },\n  // Disable JSX Runtime rule\n  {\n    name: 'x/react/disable-jsx-runtime',\n    rules: {\n      'react/jsx-uses-react': 'off',\n      'react/react-in-jsx-scope': 'off',\n    },\n  },\n];\n\nexport default customReactESLintConfig;\n"
  },
  {
    "path": "lint/typescript.eslint.mjs",
    "content": "import { configs, plugins, rules } from 'eslint-config-airbnb-extended';\n\nconst customTSESLintConfig = [\n  // TypeScript ESLint Plugin\n  plugins.typescriptEslint,\n  // Airbnb Base TypeScript Config\n  ...configs.base.typescript,\n  // Airbnb Next TypeScript Config\n  ...configs.react.typescript,\n  // Airbnb TypeScript ESLint Strict Rules\n  rules.typescript.typescriptEslintStrict,\n  // Disable Return Type for Features Hook\n  {\n    name: 'x/typescript-eslint/features-hook-only',\n    files: ['src/features/**/use*.ts'],\n    rules: {\n      '@typescript-eslint/explicit-module-boundary-types': 'off',\n    },\n  },\n];\n\nexport default customTSESLintConfig;\n"
  },
  {
    "path": "lint/utils.eslint.mjs",
    "content": "import path from 'node:path';\n\nimport { includeIgnoreFile } from '@eslint/compat';\n\nexport const gitignorePath = path.resolve('.', '.gitignore');\n\nexport const gitIgnoreFile = includeIgnoreFile(gitignorePath);\n"
  },
  {
    "path": "lint-staged.config.mjs",
    "content": "/**\n * @type {import('lint-staged').Configuration}\n */\nexport default {\n  '*.{js,mjs,jsx,ts,mts,tsx}': 'pnpm lint',\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"img-mapper-project\",\n  \"version\": \"2.0.3\",\n  \"description\": \"Creates Interactive and Highlighted Zones on Images\",\n  \"bugs\": {\n    \"url\": \"https://github.com/img-mapper/img-mapper/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/img-mapper/img-mapper.git\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Nisharg Shah <nishargshah3101@gmail.com>\",\n  \"scripts\": {\n    \"build\": \"pnpm -r build\",\n    \"build:react\": \"pnpm --filter react-img-mapper build\",\n    \"clean:all\": \"pnpm clean:node_modules && pnpm clean:generated-folders\",\n    \"clean:dist\": \"pnpx rimraf dist && pnpm -r exec pnpx rimraf dist\",\n    \"clean:generated-folders\": \"pnpm clean:dist\",\n    \"clean:node_modules\": \"pnpx rimraf node_modules && pnpm -r exec pnpx rimraf node_modules\",\n    \"clean:workspace\": \"pnpm clean:node_modules && pnpx rimraf pnpm-lock.yaml\",\n    \"dev:docs\": \"pnpm --filter img-mapper-docs dev\",\n    \"dev:examples\": \"pnpm --filter examples dev\",\n    \"format:check\": \"prettier . --check\",\n    \"format:fix\": \"prettier . --write\",\n    \"fresh:init\": \"pnpm clean:workspace && pnpm clean:generated-folders && pnpm install\",\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"pnpm --silent lint --fix\",\n    \"pkg:prepare\": \"pnpm changeset && pnpm changeset version\",\n    \"pkg:publish\": \"pnpm build:react && pnpm changeset publish\",\n    \"play:react\": \"pnpm --filter react-img-mapper play\",\n    \"play:vue\": \"pnpm --filter vue-img-mapper play\",\n    \"prepare\": \"husky || true\",\n    \"script:lint\": \"bash -e ./scripts/lint.sh\",\n    \"typecheck\": \"pnpm -r typecheck\"\n  },\n  \"devDependencies\": {\n    \"@changesets/cli\": \"^2.29.7\",\n    \"@eslint/compat\": \"^1.4.0\",\n    \"@eslint/js\": \"^9.38.0\",\n    \"@stylistic/eslint-plugin\": \"^3.1.0\",\n    \"@types/node\": \"^24.9.1\",\n    \"eslint\": \"^9.38.0\",\n    \"eslint-config-airbnb-extended\": \"^2.3.2\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"eslint-import-resolver-typescript\": \"^4.4.4\",\n    \"eslint-plugin-import-x\": \"^4.16.1\",\n    \"eslint-plugin-jsx-a11y\": \"^6.10.2\",\n    \"eslint-plugin-prettier\": \"^5.5.4\",\n    \"eslint-plugin-promise\": \"^7.2.1\",\n    \"eslint-plugin-react\": \"^7.37.5\",\n    \"eslint-plugin-react-hooks\": \"^7.0.0\",\n    \"eslint-plugin-unicorn\": \"^61.0.2\",\n    \"eslint-plugin-unused-imports\": \"^4.3.0\",\n    \"husky\": \"^9.1.7\",\n    \"lint-staged\": \"^16.2.6\",\n    \"prettier\": \"^3.6.2\",\n    \"prettier-plugin-packagejson\": \"^2.5.19\",\n    \"typescript\": \"catalog:\",\n    \"typescript-eslint\": \"^8.46.2\"\n  },\n  \"packageManager\": \"pnpm@10.19.0\",\n  \"engines\": {\n    \"node\": \">=16.0.0\",\n    \"npm\": \"please-use-pnpm\",\n    \"pnpm\": \">=10.18.0\",\n    \"yarn\": \"please-use-pnpm\"\n  }\n}\n"
  },
  {
    "path": "packages/react-img-mapper/.npmignore",
    "content": "# Ignore everything\n/*\n\n# Not ignored folders\n!dist\n\n# Inside dist\n*.tsbuildinfo\n"
  },
  {
    "path": "packages/react-img-mapper/README.md",
    "content": "# `react-img-mapper`\n\n[![NPM Version](https://img.shields.io/npm/v/react-img-mapper?style=flat&labelColor=ffffff&color=00acc1)](https://www.npmjs.com/package/react-img-mapper)\n[![NPM Downloads](https://img.shields.io/npm/dw/react-img-mapper?style=flat&labelColor=ffffff&color=00acc1)](https://www.npmjs.com/package/react-img-mapper)\n[![NPM Last Update](https://img.shields.io/npm/last-update/react-img-mapper?style=flat&labelColor=ffffff&color=00acc1)](https://www.npmjs.com/package/react-img-mapper)\n\nA React Component for Creating Interactive and Highlighted Zones on Images\n\n> Check out the package docs here: https://img-mapper.nishargshah.dev/react/installation\n"
  },
  {
    "path": "packages/react-img-mapper/package.json",
    "content": "{\n  \"name\": \"react-img-mapper\",\n  \"version\": \"2.0.3\",\n  \"description\": \"A React Component for Creating Interactive and Highlighted Zones on Images\",\n  \"keywords\": [\n    \"react-img-mapper\",\n    \"react-image-mapper\",\n    \"img-mapper\",\n    \"image-mapper\",\n    \"img mapper\",\n    \"image mapper\",\n    \"react img mapper\",\n    \"react image mapper\",\n    \"react img mapper docs\",\n    \"react image mapper docs\"\n  ],\n  \"homepage\": \"https://img-mapper.nishargshah.dev\",\n  \"bugs\": {\n    \"url\": \"https://github.com/img-mapper/img-mapper/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/img-mapper/img-mapper.git\",\n    \"directory\": \"packages/react-img-mapper\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Nisharg Shah <nishargshah3101@gmail.com>\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.cjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"main\": \"./dist/index.cjs\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.cts\",\n  \"scripts\": {\n    \"build\": \"tsdown\",\n    \"dev\": \"tsdown --watch\",\n    \"play\": \"vite --port 3000\",\n    \"typecheck\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"react-fast-compare\": \"^3.2.2\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"catalog:\",\n    \"@types/react-dom\": \"catalog:\",\n    \"@vitejs/plugin-react\": \"^5.0.4\",\n    \"react\": \"catalog:\",\n    \"tsdown\": \"catalog:\",\n    \"typescript\": \"catalog:\",\n    \"vite\": \"catalog:\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n  },\n  \"engines\": {\n    \"node\": \">=16.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/react-img-mapper/playground/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/vite.svg\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Playground</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/main.tsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/react-img-mapper/playground/src/ReactPlayground.tsx",
    "content": "import React, { useEffect, useRef, useState } from 'react';\n\nimport ImageMapper from '@/ImageMapper';\nimport { useAreas } from '@playground/hooks/useAreas';\n\nimport type { FC } from 'react';\n\nimport type { MapArea, RefProperties } from '@/@types';\n\nconst name = 'my-map';\nconst url = 'https://img-mapper-examples.nishargshah.dev/assets/example.jpg';\n\nconst ReactPlayground: FC = () => {\n  const { areas: initialAreas } = useAreas();\n\n  const [areas, setAreas] = useState<MapArea[]>(initialAreas);\n  const [parentWidth, setParentWidth] = useState<number>(640);\n  const [responsive, setResponsive] = useState(false);\n  const ref = useRef<RefProperties>(null);\n\n  useEffect(() => {\n    if (ref.current) {\n      console.log(ref.current.getRefs());\n    }\n  }, []);\n\n  const handleClick = () => {\n    const area = areas.map((cur: MapArea, i: number) => {\n      if (i % 4 === 0) {\n        const temp = { ...cur };\n        temp.preFillColor = 'red';\n        return temp;\n      }\n\n      return cur;\n    });\n    setAreas(area);\n  };\n\n  useEffect(() => {\n    if (areas.length === 0) setAreas(initialAreas);\n  }, [initialAreas, areas.length]);\n\n  if (areas.length === 0) return null;\n\n  return (\n    <React.Fragment>\n      <ImageMapper\n        ref={ref}\n        areas={areas}\n        name={name}\n        onLoad={(...arg) => console.log('onLoad =>>>>>>>>>>>>', arg)}\n        parentWidth={responsive ? parentWidth : 0}\n        responsive={responsive}\n        src={url}\n        onChange={(selectedArea, allAreas) => {\n          console.log(selectedArea, allAreas);\n          setAreas(allAreas);\n        }}\n      />\n      <input\n        max={1000}\n        min={100}\n        onChange={(e) => setParentWidth(e.target.valueAsNumber)}\n        step={40}\n        type=\"range\"\n        value={parentWidth}\n      />\n      <button onClick={handleClick} type=\"button\">\n        Highlight\n      </button>\n      <button onClick={() => setAreas(initialAreas)} type=\"button\">\n        Clear\n      </button>\n      <button onClick={() => setResponsive((prev) => !prev)} type=\"button\">\n        {responsive ? 'Enabled: Responsive' : 'Enable: Responsive'}\n      </button>\n      <button onClick={() => console.log(ref.current?.getRefs())} type=\"button\">\n        Get Ref\n      </button>\n    </React.Fragment>\n  );\n};\n\nexport default ReactPlayground;\n"
  },
  {
    "path": "packages/react-img-mapper/playground/src/hooks/useAreas.ts",
    "content": "import { useEffect, useState } from 'react';\n\nimport type { MapArea } from 'react-img-mapper';\n\ninterface AreasHookOutput {\n  areas: MapArea[];\n}\n\ntype AreasHook = () => AreasHookOutput;\n\nconst areasUrl = 'https://img-mapper-examples.nishargshah.dev/assets/areas.json';\n\nexport const useAreas: AreasHook = () => {\n  const [areas, setAreas] = useState<AreasHookOutput['areas']>([]);\n\n  useEffect(() => {\n    (async () => {\n      const res = await fetch(areasUrl);\n      const json = await res.json();\n\n      setAreas(json);\n    })();\n  }, []);\n\n  return { areas };\n};\n"
  },
  {
    "path": "packages/react-img-mapper/playground/src/main.tsx",
    "content": "import { createRoot } from 'react-dom/client';\n\nimport ReactPlayground from '@playground/ReactPlayground';\n\ncreateRoot(document.querySelector('#root') as Element).render(<ReactPlayground />);\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/area.d.ts",
    "content": "import type { Area, ImageMapperProps, MapArea } from '@/@types';\nimport type { GetPropDimensionParams } from '@/@types/dimensions';\n\ntype ScaleCoordsParams = GetPropDimensionParams &\n  Pick<Required<ImageMapperProps>, 'responsive' | 'parentWidth' | 'imgWidth'>;\n\nexport type ScaleCoords = (\n  coords: MapArea['coords'],\n  scaleCoordsParams: ScaleCoordsParams,\n) => number[];\n\nexport type ComputeCenter = (\n  shape: MapArea['shape'],\n  scaleCoordsParams: ReturnType<ScaleCoords>,\n) => Area['center'];\n\ntype GetExtendedAreaParams = Pick<\n  Required<ImageMapperProps>,\n  'fillColor' | 'lineWidth' | 'strokeColor'\n>;\n\nexport type GetExtendedArea = (\n  area: MapArea,\n  scaleCoordsParams: ScaleCoordsParams,\n  params: GetExtendedAreaParams,\n) => Area;\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/constants.d.ts",
    "content": "import type { ImageMapperProps } from '@/@types';\n\ntype RequiredProps = 'src' | 'name' | 'areas';\n\nexport type ImageMapperDefaultProps = Omit<ImageMapperProps, RequiredProps>;\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/dimensions.d.ts",
    "content": "import type { RefObject } from 'react';\n\nimport type { Dimension, ImageMapperProps, Refs, WidthHeight } from '@/@types';\n\ntype ImgRef = RefObject<Refs['imgRef']>;\n\nexport type GetDimension = (dimension: Dimension, img: ImgRef) => number;\n\nexport interface GetPropDimensionParams {\n  width: Dimension;\n  height: Dimension;\n  img: ImgRef;\n}\n\nexport type GetPropDimension = (params: GetPropDimensionParams) => WidthHeight;\n\ntype GetDimensionValuesParams = GetPropDimensionParams &\n  Pick<Required<ImageMapperProps>, 'responsive' | 'parentWidth' | 'natural'>;\n\nexport type GetDimensionValues = (\n  type: 'width' | 'height',\n  params: GetDimensionValuesParams,\n) => number;\n\ntype GetDimensionsParams = Omit<GetDimensionValuesParams, 'type'>;\n\nexport type GetDimensions = (params: GetDimensionsParams) => WidthHeight;\n\nexport interface PrevStateRef {\n  parentWidth: number;\n  width: number;\n  height: number;\n}\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/draw.d.ts",
    "content": "import type { RefObject } from 'react';\n\nimport type { Area } from '@/@types';\n\nexport type CTX<E = CanvasRenderingContext2D> = RefObject<CanvasRenderingContext2D | E>;\n\ntype DrawArea = 'scaledCoords' | 'fillColor' | 'lineWidth' | 'strokeColor';\n\nexport type DrawChosenShape = (area: Pick<Area, DrawArea>, ctx: CTX) => boolean;\n\nexport type DrawShape = (area: Pick<Area, 'shape' | DrawArea>, ctx: CTX<null>) => boolean;\n\nexport type GetShape = (shape: Area['shape']) => DrawChosenShape | false;\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/events.d.ts",
    "content": "import type { AreaEvent, ImageEvent, ImageMapperProps, MapArea } from '@/@types';\n\nexport interface EventListenerParam {\n  area: MapArea;\n  index: number;\n}\n\nexport type EventListenerProps<T extends keyof ImageMapperProps> = Pick<ImageMapperProps, T> & {\n  cb?: (area: MapArea) => void;\n};\n\nexport type EventListener<T extends keyof ImageMapperProps, E = AreaEvent> = (\n  params: EventListenerParam,\n  props: EventListenerProps<T>,\n) => (event: E) => void;\n\nexport type ImageEventListener<T extends keyof ImageMapperProps> = (\n  props: EventListenerProps<T>,\n) => (event: ImageEvent) => void;\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/index.d.ts",
    "content": "import type { HTMLProps, MouseEvent, Ref, TouchEvent as ReactTouchEvent } from 'react';\n\nimport type { ConditionalKeys, NoUndefinedField } from '@/@types/lib';\n\nexport interface Refs {\n  containerRef: HTMLDivElement | null;\n  imgRef: HTMLImageElement | null;\n  canvasRef: HTMLCanvasElement | null;\n}\n\nexport interface RefProperties {\n  getRefs: () => Refs;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface OverrideMapArea {}\n\nexport interface MapArea extends OverrideMapArea {\n  id: string;\n  shape: string;\n  coords: number[];\n  active?: boolean;\n  disabled?: boolean;\n  href?: string;\n  fillColor?: string;\n  strokeColor?: string;\n  lineWidth?: number;\n  preFillColor?: string;\n}\n\ntype RequiredMapArea = 'active' | 'fillColor' | 'lineWidth' | 'strokeColor';\ntype RequiredArea<T extends MapArea = MapArea, R extends keyof T = RequiredMapArea> = Omit<T, R> &\n  Pick<NoUndefinedField<T>, R>;\n\nexport interface Area extends RequiredArea {\n  scaledCoords: number[];\n  center: [number, number];\n}\n\nexport interface WidthHeight {\n  width: number;\n  height: number;\n}\n\nexport type Dimension = number | ((event: HTMLImageElement) => number);\n\nexport type ContainerProps = Omit<HTMLProps<HTMLDivElement>, 'ref' | 'id'> | null;\nexport type ImgProps = Omit<\n  HTMLProps<HTMLImageElement>,\n  'ref' | 'src' | 'useMap' | 'onClick' | 'onMouseMove'\n> | null;\nexport type CanvasProps = Omit<HTMLProps<HTMLCanvasElement>, 'ref'> | null;\nexport type MapProps = Omit<HTMLProps<HTMLMapElement>, 'name'> | null;\nexport type AreaProps = Omit<\n  HTMLProps<HTMLAreaElement>,\n  | 'key'\n  | 'coords'\n  | 'onMouseEnter'\n  | 'onMouseLeave'\n  | 'onMouseMove'\n  | 'onMouseDown'\n  | 'onMouseUp'\n  | 'onTouchStart'\n  | 'onTouchEnd'\n  | 'onClick'\n> | null;\n\nexport type TouchEvent = ReactTouchEvent<HTMLAreaElement>;\nexport type AreaEvent = MouseEvent<HTMLAreaElement>;\nexport type ImageEvent = MouseEvent<HTMLImageElement>;\n\nexport type ChangeEventHandler = ((selectedArea: MapArea, areas: MapArea[]) => void) | null;\nexport type ImageEventHandler = ((event: ImageEvent) => void) | null;\nexport type EventHandler<T = AreaEvent> = ((area: MapArea, index: number, e: T) => void) | null;\nexport type LoadEventHandler = ((event: HTMLImageElement, dimensions: WidthHeight) => void) | null;\n\nexport interface ImageMapperProps {\n  src: string;\n  name: string;\n  areas: MapArea[];\n  areaKeyName?: ConditionalKeys<MapArea, string>;\n  isMulti?: boolean;\n  toggle?: boolean;\n  active?: boolean;\n  disabled?: boolean;\n  fillColor?: string;\n  strokeColor?: string;\n  lineWidth?: number;\n  imgWidth?: number;\n  width?: Dimension;\n  height?: Dimension;\n  natural?: boolean;\n  responsive?: boolean;\n  parentWidth?: number;\n  containerProps?: ContainerProps;\n  imgProps?: ImgProps;\n  canvasProps?: CanvasProps;\n  mapProps?: MapProps;\n  areaProps?: AreaProps | AreaProps[];\n\n  onChange?: ChangeEventHandler;\n  onImageClick?: ImageEventHandler;\n  onImageMouseMove?: ImageEventHandler;\n  onClick?: EventHandler;\n  onMouseDown?: EventHandler;\n  onMouseUp?: EventHandler;\n  onTouchStart?: EventHandler<TouchEvent>;\n  onTouchEnd?: EventHandler<TouchEvent>;\n  onMouseMove?: EventHandler;\n  onMouseEnter?: EventHandler;\n  onMouseLeave?: EventHandler;\n  onLoad?: LoadEventHandler;\n}\n\nexport interface ImageMapperPropsWithRef extends ImageMapperProps {\n  ref?: Ref<RefProperties>;\n}\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/lib.d.ts",
    "content": "export type NoUndefinedField<T> = { [P in keyof T]-?: NoUndefinedField<NonNullable<T[P]>> };\n\nexport type ConditionalKeys<Base, Condition> = NonNullable<\n  {\n    [Key in keyof Base]: Base[Key] extends Condition ? Key : never;\n  }[keyof Base]\n>;\n"
  },
  {
    "path": "packages/react-img-mapper/src/@types/styles.d.ts",
    "content": "import type { CSSProperties } from 'react';\n\nexport interface StylesProps {\n  container: CSSProperties;\n  canvas: CSSProperties;\n  img: (responsive: boolean) => CSSProperties;\n  map: (onClick: boolean) => CSSProperties | undefined;\n}\n"
  },
  {
    "path": "packages/react-img-mapper/src/ImageMapper.tsx",
    "content": "import React, {\n  memo,\n  useCallback,\n  useEffect,\n  useImperativeHandle,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\n\nimport isEqual from 'react-fast-compare';\n\nimport { getExtendedArea } from '@/helpers/area';\nimport { generateProps, rerenderPropsList } from '@/helpers/constants';\nimport { getDimension, getDimensions, getPropDimension } from '@/helpers/dimensions';\nimport drawShape from '@/helpers/draw';\nimport {\n  click,\n  imageClick,\n  imageMouseMove,\n  mouseDown,\n  mouseEnter,\n  mouseLeave,\n  mouseMove,\n  mouseUp,\n  touchEnd,\n  touchStart,\n} from '@/helpers/events';\nimport styles from '@/helpers/styles';\n\nimport type { FC, ReactNode } from 'react';\n\nimport type { ImageMapperPropsWithRef, MapArea, Refs } from '@/@types';\nimport type { PrevStateRef } from '@/@types/dimensions';\nimport type { CTX } from '@/@types/draw';\n\nconst ImageMapper: FC<ImageMapperPropsWithRef> = ({ ref, ...props }) => {\n  const generatedProps = generateProps(props);\n  const {\n    src,\n    name,\n    areas,\n    areaKeyName,\n    isMulti,\n    toggle,\n    active,\n    disabled,\n    fillColor,\n    strokeColor,\n    lineWidth,\n    imgWidth,\n    width,\n    height,\n    natural,\n    responsive,\n    parentWidth,\n    containerProps,\n    imgProps,\n    canvasProps,\n    mapProps,\n    areaProps,\n\n    onChange,\n    onImageClick,\n    onImageMouseMove,\n    onClick,\n    onMouseDown,\n    onMouseUp,\n    onTouchStart,\n    onTouchEnd,\n    onMouseMove,\n    onMouseEnter,\n    onMouseLeave,\n    onLoad,\n  } = generatedProps;\n\n  const [isRendered, setIsRendered] = useState<boolean>(false);\n  const areasRef = useRef<MapArea[]>(areas);\n  const containerRef = useRef<Refs['containerRef']>(null);\n  const img = useRef<Refs['imgRef']>(null);\n  const canvas = useRef<Refs['canvasRef']>(null);\n  const ctx = useRef<CTX<null>['current']>(null);\n  const interval = useRef<number>(0);\n  const prevState = useRef<PrevStateRef>({\n    parentWidth,\n    ...getPropDimension({ width, height, img }),\n  });\n\n  const dimensionParams = useMemo(\n    () => ({ width, height, responsive, parentWidth, natural }),\n    [width, height, responsive, parentWidth, natural],\n  );\n\n  const scaleCoordsParams = useMemo(\n    () => ({ width, height, responsive, parentWidth, imgWidth }),\n    [width, height, responsive, parentWidth, imgWidth],\n  );\n\n  const areaParams = useMemo(\n    () => ({ fillColor, lineWidth, strokeColor }),\n    [fillColor, lineWidth, strokeColor],\n  );\n\n  const init = useCallback(() => {\n    if (img.current?.complete && canvas.current && containerRef.current) {\n      ctx.current = canvas.current.getContext('2d');\n\n      setIsRendered(true);\n    }\n  }, []);\n\n  useEffect(() => {\n    if (isRendered) {\n      clearInterval(interval.current);\n    } else {\n      // eslint-disable-next-line unicorn/prefer-global-this\n      interval.current = window.setInterval(init, 500);\n    }\n  }, [init, isRendered]);\n\n  const renderPrefilledAreas = useCallback(() => {\n    // eslint-disable-next-line unicorn/no-array-for-each\n    areas.forEach((area) => {\n      const extendedArea = getExtendedArea(area, { img, ...scaleCoordsParams }, areaParams);\n\n      if (!extendedArea.preFillColor) return false;\n\n      return drawShape({ ...extendedArea, fillColor: extendedArea.preFillColor }, ctx);\n    });\n  }, [areaParams, areas, scaleCoordsParams]);\n\n  const clearCanvas = useCallback(() => {\n    if (!(ctx.current && canvas.current)) return;\n\n    ctx.current.clearRect(0, 0, canvas.current.width, canvas.current.height);\n  }, []);\n\n  const resetCanvasAndPrefillArea = useCallback(() => {\n    clearCanvas();\n    renderPrefilledAreas();\n  }, [clearCanvas, renderPrefilledAreas]);\n\n  const highlightArea = (area: MapArea): boolean => {\n    const extendedArea = getExtendedArea(area, { img, ...scaleCoordsParams }, areaParams);\n\n    if (!extendedArea.active) return false;\n\n    return drawShape(extendedArea, ctx);\n  };\n\n  const onHighlightArea = (area: MapArea): void => {\n    const chosenAreasRef = areasRef.current;\n\n    const chosenArea = isMulti\n      ? area\n      : chosenAreasRef.find((c) => c[areaKeyName] === area[areaKeyName]);\n\n    if (!chosenArea) return;\n\n    const extendedArea = getExtendedArea(chosenArea, { img, ...scaleCoordsParams }, areaParams);\n    if (!(active && extendedArea.active)) return;\n\n    const chosenAreas = isMulti ? areas : chosenAreasRef;\n    const newArea = { ...chosenArea };\n\n    const isCurrentAreaSelected = (() => {\n      if (toggle) {\n        if (isMulti && newArea.preFillColor) return true;\n        return !isMulti && !!area.preFillColor;\n      }\n\n      return false;\n    })();\n\n    if (isCurrentAreaSelected) {\n      const isPreFillColorFromJSON = chosenAreas.find((c) => c[areaKeyName] === area[areaKeyName]);\n      if (isPreFillColorFromJSON?.preFillColor) delete newArea.preFillColor;\n    } else {\n      newArea.preFillColor = extendedArea.fillColor;\n    }\n\n    const updatedAreas = chosenAreas.map((cur) =>\n      cur[areaKeyName] === area[areaKeyName] ? newArea : cur,\n    );\n\n    if (onChange) onChange(newArea, updatedAreas);\n  };\n\n  const initCanvas = useCallback(\n    (isFirstTime = true, triggerOnLoad = false) => {\n      const { width: imageWidth, height: imageHeight } = getDimensions({ img, ...dimensionParams });\n\n      if (!(img.current && canvas.current && containerRef.current && ctx.current)) return;\n\n      containerRef.current.style.width = `${imageWidth}px`;\n      containerRef.current.style.height = `${imageHeight}px`;\n\n      if (isFirstTime) {\n        initCanvas(false, true);\n      } else {\n        img.current.width = imageWidth;\n        img.current.height = imageHeight;\n\n        canvas.current.width = imageWidth;\n        canvas.current.height = imageHeight;\n\n        renderPrefilledAreas();\n      }\n\n      if (onLoad && triggerOnLoad) {\n        onLoad(img.current, { width: imageWidth, height: imageHeight });\n      }\n    },\n    [dimensionParams, onLoad, renderPrefilledAreas],\n  );\n\n  const getRefs = useCallback(\n    () => ({ containerRef: containerRef.current, imgRef: img.current, canvasRef: canvas.current }),\n    [],\n  );\n\n  useEffect(() => {\n    if (isRendered) initCanvas();\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [isRendered]);\n\n  useEffect(() => {\n    resetCanvasAndPrefillArea();\n  }, [areas, resetCanvasAndPrefillArea]);\n\n  useEffect(() => {\n    if (responsive && parentWidth && prevState.current.parentWidth !== parentWidth) {\n      initCanvas();\n      prevState.current.parentWidth = parentWidth;\n    }\n\n    if (width && prevState.current.width !== width) {\n      initCanvas();\n      prevState.current.width = getDimension(width, img);\n    }\n\n    if (height && prevState.current.height !== height) {\n      initCanvas();\n      prevState.current.height = getDimension(height, img);\n    }\n  }, [height, initCanvas, parentWidth, responsive, width]);\n\n  useImperativeHandle(ref, () => ({ getRefs }), [getRefs]);\n\n  const handleMouseEnter = (area: MapArea): void => {\n    if (active) highlightArea(area);\n  };\n\n  const handleMouseLeave = (): void => {\n    if (active) resetCanvasAndPrefillArea();\n  };\n\n  const handleClick = (area: MapArea): void => {\n    onHighlightArea(area);\n  };\n\n  const renderAreas = (): ReactNode =>\n    areas.map((area, index) => {\n      const { areaKeyName: areaKeyNameProp } = props;\n\n      const { scaledCoords } = getExtendedArea(area, { img, ...scaleCoordsParams }, areaParams);\n\n      if (area.disabled) return null;\n\n      const { preFillColor, shape, href } = area;\n      const currentAreaProps = (() => {\n        if (Array.isArray(areaProps)) {\n          if (areaKeyNameProp) {\n            return areaProps.find((cur) => cur && cur[areaKeyNameProp] === area[areaKeyNameProp]);\n          }\n\n          return areaProps[index];\n        }\n\n        return areaProps;\n      })();\n\n      return (\n        <area\n          alt=\"map\"\n          {...currentAreaProps}\n          key={area[areaKeyName] ?? index.toString()}\n          coords={scaledCoords.join(',')}\n          href={href ?? currentAreaProps?.href}\n          onClick={click({ area, index }, { onClick, cb: handleClick })}\n          onMouseDown={mouseDown({ area, index }, { onMouseDown })}\n          onMouseEnter={mouseEnter({ area, index }, { onMouseEnter, cb: handleMouseEnter })}\n          onMouseLeave={mouseLeave({ area, index }, { onMouseLeave, cb: handleMouseLeave })}\n          onMouseMove={mouseMove({ area, index }, { onMouseMove })}\n          onMouseUp={mouseUp({ area, index }, { onMouseUp })}\n          onTouchEnd={touchEnd({ area, index }, { onTouchEnd })}\n          onTouchStart={touchStart({ area, index }, { onTouchStart })}\n          shape={shape ?? currentAreaProps?.shape}\n          className={[\n            'img-mapper-area',\n            ...(preFillColor ? ['img-mapper-area-highlighted'] : []),\n            ...(currentAreaProps?.className ? [currentAreaProps.className] : []),\n          ].join(' ')}\n        />\n      );\n    });\n\n  return (\n    <div\n      {...containerProps}\n      ref={containerRef}\n      id=\"img-mapper\"\n      style={{ ...containerProps?.style, ...styles.container }}\n    >\n      <img\n        alt=\"map\"\n        role=\"presentation\"\n        {...imgProps}\n        ref={img}\n        onClick={imageClick({ onImageClick })}\n        onMouseMove={imageMouseMove({ onImageMouseMove })}\n        src={src}\n        useMap={`#${name}`}\n        className={['img-mapper-img', ...(imgProps?.className ? [imgProps.className] : [])].join(\n          ' ',\n        )}\n        style={{\n          ...imgProps?.style,\n          ...styles.img(responsive),\n          ...(isRendered ? null : { display: 'none' }),\n        }}\n      />\n      <canvas\n        {...canvasProps}\n        ref={canvas}\n        style={{ ...canvasProps?.style, ...styles.canvas }}\n        className={[\n          'img-mapper-canvas',\n          ...(canvasProps?.className ? [canvasProps.className] : []),\n        ].join(' ')}\n      />\n      <map\n        {...mapProps}\n        name={name}\n        style={{ ...mapProps?.style, ...styles.map(!!onClick) }}\n        className={['img-mapper-map', ...(mapProps?.className ? [mapProps.className] : [])].join(\n          ' ',\n        )}\n      >\n        {isRendered && !disabled ? renderAreas() : null}\n      </map>\n    </div>\n  );\n};\n\nexport default memo(ImageMapper, (prevProps, nextProps) => {\n  const propChanged = rerenderPropsList.some((prop) => prevProps[prop] !== nextProps[prop]);\n\n  return isEqual(prevProps.areas, nextProps.areas) && !propChanged;\n});\n"
  },
  {
    "path": "packages/react-img-mapper/src/helpers/area.ts",
    "content": "import { getPropDimension } from '@/helpers/dimensions';\n\nimport type { ComputeCenter, GetExtendedArea, ScaleCoords } from '@/@types/area';\n\nexport const scaleCoords: ScaleCoords = (\n  coords,\n  { width, height, img, responsive, parentWidth, imgWidth },\n) =>\n  coords.map((coord) => {\n    if (responsive && parentWidth && img.current) {\n      return coord / (img.current.naturalWidth / parentWidth);\n    }\n\n    const { width: imageWidth } = getPropDimension({ width, height, img });\n    const scale = imageWidth && imgWidth > 0 ? imageWidth / imgWidth : 1;\n    return coord * scale;\n  });\n\nexport const computeCenter: ComputeCenter = (shape, scaledCoords) => {\n  switch (shape) {\n    case 'circle': {\n      return [scaledCoords[0], scaledCoords[1]];\n    }\n\n    default: {\n      const n = scaledCoords.length / 2;\n      const { y: scaleY, x: scaleX } = scaledCoords.reduce(\n        ({ y, x }, val, idx) => (idx % 2 ? { y: y + val / n, x } : { y, x: x + val / n }),\n        { y: 0, x: 0 },\n      );\n\n      return [scaleX, scaleY];\n    }\n  }\n};\n\nexport const getExtendedArea: GetExtendedArea = (\n  area,\n  scaleCoordsParams,\n  { fillColor, lineWidth, strokeColor },\n) => {\n  const scaledCoords = scaleCoords(area.coords, scaleCoordsParams);\n  const center = computeCenter(area.shape, scaledCoords);\n\n  return {\n    ...area,\n    scaledCoords,\n    center,\n    active: area.active ?? true,\n    fillColor: area.fillColor ?? fillColor,\n    lineWidth: area.lineWidth ?? lineWidth,\n    strokeColor: area.strokeColor ?? strokeColor,\n  };\n};\n"
  },
  {
    "path": "packages/react-img-mapper/src/helpers/constants.ts",
    "content": "import type { ImageMapperProps } from '@/@types';\nimport type { ImageMapperDefaultProps } from '@/@types/constants';\n\nexport const rerenderPropsList = [\n  'src',\n  'name',\n  'areaKeyName',\n  'isMulti',\n  'toggle',\n  'active',\n  'disabled',\n  'fillColor',\n  'strokeColor',\n  'lineWidth',\n  'imgWidth',\n  'width',\n  'height',\n  'natural',\n  'responsive',\n  'parentWidth',\n] as const;\n\nconst imageMapperDefaultProps: ImageMapperDefaultProps = {\n  areaKeyName: 'id',\n  isMulti: true,\n  toggle: false,\n  active: true,\n  disabled: false,\n  fillColor: 'rgba(255, 255, 255, 0.5)',\n  strokeColor: 'rgba(0, 0, 0, 0.5)',\n  lineWidth: 1,\n  imgWidth: 0,\n  width: 0,\n  height: 0,\n  natural: false,\n  responsive: false,\n  parentWidth: 0,\n  containerProps: null,\n  imgProps: null,\n  canvasProps: null,\n  mapProps: null,\n  areaProps: null,\n\n  onChange: null,\n  onImageClick: null,\n  onImageMouseMove: null,\n  onClick: null,\n  onMouseDown: null,\n  onMouseUp: null,\n  onTouchStart: null,\n  onTouchEnd: null,\n  onMouseMove: null,\n  onMouseEnter: null,\n  onMouseLeave: null,\n  onLoad: null,\n};\n\nexport const generateProps = <T extends ImageMapperProps>(props: T): Required<T> =>\n  Object.entries(imageMapperDefaultProps).reduce(\n    (acc, val) => {\n      const [key, value] = val as unknown as [keyof T, typeof val];\n\n      // @ts-expect-error acc key error\n      acc[key] = props[key] ?? value;\n      return acc;\n    },\n    { src: props.src, name: props.name, areas: props.areas },\n  ) as Required<T>;\n"
  },
  {
    "path": "packages/react-img-mapper/src/helpers/dimensions.ts",
    "content": "import type {\n  GetDimension,\n  GetDimensions,\n  GetDimensionValues,\n  GetPropDimension,\n} from '@/@types/dimensions';\n\nexport const getDimension: GetDimension = (dimension, img) => {\n  if (!img.current) return 0;\n\n  return typeof dimension === 'function' ? dimension(img.current) : dimension;\n};\n\nexport const getPropDimension: GetPropDimension = ({ width, height, img }) => ({\n  width: getDimension(width, img),\n  height: getDimension(height, img),\n});\n\nconst getDimensionValues: GetDimensionValues = (\n  type,\n  { width, height, img, responsive, parentWidth, natural },\n) => {\n  const { width: imageWidth, height: imageHeight } = getPropDimension({ width, height, img });\n\n  if (img.current) {\n    const { naturalWidth, naturalHeight, clientWidth, clientHeight } = img.current;\n\n    if (type === 'width') {\n      if (responsive) return parentWidth;\n      if (natural) return naturalWidth;\n      if (imageWidth) return imageWidth;\n      return clientWidth;\n    }\n\n    if (type === 'height') {\n      if (responsive) return clientHeight;\n      if (natural) return naturalHeight;\n      if (imageHeight) return imageHeight;\n      return clientHeight;\n    }\n  }\n\n  return 0;\n};\n\nexport const getDimensions: GetDimensions = (props) => ({\n  width: getDimensionValues('width', props),\n  height: getDimensionValues('height', props),\n});\n"
  },
  {
    "path": "packages/react-img-mapper/src/helpers/draw.ts",
    "content": "import type { DrawChosenShape, DrawShape, GetShape } from '@/@types/draw';\n\nconst drawRect: DrawChosenShape = (area, ctx) => {\n  const { scaledCoords, fillColor, lineWidth, strokeColor } = area;\n  const [left, top, right, bottom] = scaledCoords;\n\n  ctx.current.fillStyle = fillColor;\n  ctx.current.lineWidth = lineWidth;\n  ctx.current.strokeStyle = strokeColor;\n  ctx.current.strokeRect(left, top, right - left, bottom - top);\n  ctx.current.fillRect(left, top, right - left, bottom - top);\n  return true;\n};\n\nconst drawCircle: DrawChosenShape = (area, ctx) => {\n  const { scaledCoords, fillColor, lineWidth, strokeColor } = area;\n  const [left, top, right] = scaledCoords;\n\n  ctx.current.fillStyle = fillColor;\n  ctx.current.beginPath();\n  ctx.current.lineWidth = lineWidth;\n  ctx.current.strokeStyle = strokeColor;\n  ctx.current.arc(left, top, right, 0, 2 * Math.PI);\n  ctx.current.closePath();\n  ctx.current.stroke();\n  ctx.current.fill();\n  return true;\n};\n\nconst drawPoly: DrawChosenShape = (area, ctx) => {\n  const { scaledCoords, fillColor, lineWidth, strokeColor } = area;\n  const groupCoords = scaledCoords.reduce<[number, number][]>((acc, val, index, array) => {\n    if (index % 2) return acc;\n    return [...acc, array.slice(index, index + 2)] as [number, number][];\n  }, []);\n\n  // const first = groupCoords.unshift();\n  ctx.current.fillStyle = fillColor;\n  ctx.current.beginPath();\n  ctx.current.lineWidth = lineWidth;\n  ctx.current.strokeStyle = strokeColor;\n\n  // ctx.current.moveTo(first[0], first[1]);\n  for (const [first, second] of groupCoords) ctx.current.lineTo(first, second);\n  ctx.current.closePath();\n  ctx.current.stroke();\n  ctx.current.fill();\n  return true;\n};\n\nconst getShape: GetShape = (shape) => {\n  if (shape === 'rect') return drawRect;\n  if (shape === 'circle') return drawCircle;\n  if (shape === 'poly') return drawPoly;\n  return false;\n};\n\nconst drawShape: DrawShape = (area, ctx) => {\n  const { shape, ...restArea } = area;\n  const shapeFn = getShape(shape);\n\n  if (shapeFn && ctx.current instanceof CanvasRenderingContext2D) {\n    const currentCtx = { current: ctx.current };\n    return shapeFn(restArea, currentCtx);\n  }\n\n  return false;\n};\n\nexport default drawShape;\n"
  },
  {
    "path": "packages/react-img-mapper/src/helpers/events.ts",
    "content": "import type { TouchEvent } from '@/@types';\nimport type { EventListener, ImageEventListener } from '@/@types/events';\n\nexport const imageMouseMove: ImageEventListener<'onImageMouseMove'> = (props) => (event) => {\n  const { onImageMouseMove } = props;\n\n  if (onImageMouseMove) onImageMouseMove(event);\n};\n\nexport const imageClick: ImageEventListener<'onImageClick'> = (props) => (event) => {\n  const { onImageClick } = props;\n\n  if (onImageClick) {\n    event.preventDefault();\n    onImageClick(event);\n  }\n};\n\nexport const mouseEnter: EventListener<'onMouseEnter'> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onMouseEnter, cb } = props;\n\n    if (cb) cb(area);\n\n    if (onMouseEnter) onMouseEnter(area, index, event);\n  };\n\nexport const mouseLeave: EventListener<'onMouseLeave'> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onMouseLeave, cb } = props;\n\n    if (cb) cb(area);\n\n    if (onMouseLeave) onMouseLeave(area, index, event);\n  };\n\nexport const click: EventListener<'onClick'> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onClick, cb } = props;\n\n    if (cb) cb(area);\n\n    if (onClick) {\n      event.preventDefault();\n      onClick(area, index, event);\n    }\n  };\n\nexport const mouseMove: EventListener<'onMouseMove'> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onMouseMove } = props;\n\n    if (onMouseMove) onMouseMove(area, index, event);\n  };\n\nexport const mouseDown: EventListener<'onMouseDown'> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onMouseDown } = props;\n\n    if (onMouseDown) onMouseDown(area, index, event);\n  };\n\nexport const mouseUp: EventListener<'onMouseUp'> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onMouseUp } = props;\n\n    if (onMouseUp) onMouseUp(area, index, event);\n  };\n\nexport const touchStart: EventListener<'onTouchStart', TouchEvent> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onTouchStart } = props;\n\n    if (onTouchStart) onTouchStart(area, index, event);\n  };\n\nexport const touchEnd: EventListener<'onTouchEnd', TouchEvent> =\n  ({ area, index }, props) =>\n  (event) => {\n    const { onTouchEnd } = props;\n\n    if (onTouchEnd) onTouchEnd(area, index, event);\n  };\n"
  },
  {
    "path": "packages/react-img-mapper/src/helpers/styles.ts",
    "content": "import type { CSSProperties } from 'react';\n\nimport type { StylesProps } from '@/@types/styles';\n\nconst absPos: CSSProperties = {\n  position: 'absolute',\n  top: 0,\n  left: 0,\n};\n\nconst imgNonResponsive: CSSProperties = {\n  ...absPos,\n  zIndex: 1,\n  userSelect: 'none',\n};\n\nconst imgResponsive: CSSProperties = {\n  ...imgNonResponsive,\n  width: '100%',\n  height: 'auto',\n};\n\nconst styles: StylesProps = {\n  container: {\n    position: 'relative',\n  },\n  canvas: {\n    ...absPos,\n    pointerEvents: 'none',\n    zIndex: 2,\n  },\n  img: (responsive) => (responsive ? imgResponsive : imgNonResponsive),\n  map: (onClick) => (onClick ? { cursor: 'pointer' } : undefined),\n};\n\nexport default styles;\n"
  },
  {
    "path": "packages/react-img-mapper/src/index.ts",
    "content": "export type * from '@/@types';\n\n// eslint-disable-next-line no-restricted-exports\nexport { default } from '@/ImageMapper';\n"
  },
  {
    "path": "packages/react-img-mapper/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"jsx\": \"react-jsx\",\n    \"skipLibCheck\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"@playground/*\": [\"./playground/src/*\"]\n    }\n  },\n  \"include\": [\"**/*.ts\", \"**/*.tsx\", \"**/*.mjs\", \"**/*.mts\", \"**/*.d.ts\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "packages/react-img-mapper/tsdown.config.mts",
    "content": "// eslint-disable-next-line import-x/no-extraneous-dependencies\nimport { defineConfig } from 'tsdown';\n\nexport default defineConfig((options) => {\n  const { watch } = options;\n\n  return {\n    dts: true,\n    format: ['cjs', 'esm'],\n    outDir: 'dist',\n    platform: 'browser',\n    treeshake: !watch,\n    minify: !watch,\n    exports: !watch,\n  };\n});\n"
  },
  {
    "path": "packages/react-img-mapper/vite.config.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport react from '@vitejs/plugin-react';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n  root: './playground',\n  plugins: [react()],\n  resolve: {\n    alias: {\n      '@': fileURLToPath(new URL('src', import.meta.url)),\n      '@playground': fileURLToPath(new URL('playground/src', import.meta.url)),\n    },\n  },\n});\n"
  },
  {
    "path": "packages/vue-img-mapper/.npmignore",
    "content": "# Ignore everything\n/*\n\n# Not ignored folders\n!dist\n\n# Inside dist\n*.tsbuildinfo\n"
  },
  {
    "path": "packages/vue-img-mapper/README.md",
    "content": "# `vue-img-mapper`\n\n[![NPM Version](https://img.shields.io/npm/v/vue-img-mapper?style=flat&labelColor=ffffff&color=00acc1)](https://www.npmjs.com/package/vue-img-mapper)\n[![NPM Downloads](https://img.shields.io/npm/dw/vue-img-mapper?style=flat&labelColor=ffffff&color=00acc1)](https://www.npmjs.com/package/vue-img-mapper)\n[![NPM Last Update](https://img.shields.io/npm/last-update/vue-img-mapper?style=flat&labelColor=ffffff&color=00acc1)](https://www.npmjs.com/package/vue-img-mapper)\n\nA Vue Component for Creating Interactive and Highlighted Zones on Images\n\n> Check out the package docs here: https://img-mapper.nishargshah.dev/vue/installation\n"
  },
  {
    "path": "packages/vue-img-mapper/package.json",
    "content": "{\n  \"name\": \"vue-img-mapper\",\n  \"version\": \"2.0.3\",\n  \"description\": \"A Vue Component for Creating Interactive and Highlighted Zones on Images\",\n  \"keywords\": [\n    \"vue-img-mapper\",\n    \"vue-image-mapper\",\n    \"img-mapper\",\n    \"image-mapper\",\n    \"img mapper\",\n    \"image mapper\",\n    \"vue img mapper\",\n    \"vue image mapper\",\n    \"vue img mapper docs\",\n    \"vue image mapper docs\"\n  ],\n  \"homepage\": \"https://img-mapper.nishargshah.dev\",\n  \"bugs\": {\n    \"url\": \"https://github.com/img-mapper/img-mapper/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/img-mapper/img-mapper.git\",\n    \"directory\": \"packages/vue-img-mapper\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Nisharg Shah <nishargshah3101@gmail.com>\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.cjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"main\": \"./dist/index.cjs\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.cts\",\n  \"scripts\": {\n    \"build\": \"tsdown\",\n    \"dev\": \"tsdown --watch\",\n    \"play\": \"vite --port 3001\",\n    \"typecheck\": \"vue-tsc --noEmit\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-vue\": \"^6.0.1\",\n    \"tsdown\": \"catalog:\",\n    \"typescript\": \"catalog:\",\n    \"vite\": \"catalog:\",\n    \"vue\": \"^3.5.22\",\n    \"vue-tsc\": \"^3.1.1\"\n  },\n  \"peerDependencies\": {\n    \"vue\": \"^2.0.0 || ^3.0.0\"\n  },\n  \"engines\": {\n    \"node\": \">=16.0.0\"\n  }\n}\n"
  },
  {
    "path": "packages/vue-img-mapper/playground/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Playground</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/index.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/vue-img-mapper/playground/src/App.vue",
    "content": "<script setup lang=\"ts\">\nimport ImageMapper from '@/ImageMapper.vue';\n</script>\n\n<template>\n  <p>Hello</p>\n  <ImageMapper />\n</template>\n"
  },
  {
    "path": "packages/vue-img-mapper/playground/src/index.ts",
    "content": "import { createApp } from 'vue';\n\nimport App from '@playground/App.vue';\n\ncreateApp(App).mount('#app');\n"
  },
  {
    "path": "packages/vue-img-mapper/src/ImageMapper.vue",
    "content": "<script setup lang=\"ts\">\nimport { hello } from '@/helpers/area';\nimport { ref } from 'vue';\n\nconst { type } = defineProps<{\n  type?: 'primary';\n}>();\n\nconst counter = ref(0);\n\nconst handleClick = () => {\n  counter.value += 1;\n};\n</script>\n\n<template>\n  <p>Hello World {{ counter }}</p>\n  <p>{{ type }}</p>\n  <button @click=\"handleClick\">Click</button>\n  <button @click=\"hello\">Hello</button>\n</template>\n"
  },
  {
    "path": "packages/vue-img-mapper/src/helpers/area.ts",
    "content": "// eslint-disable-next-line import-x/prefer-default-export\nexport const hello = (): void => {\n  console.log('hello');\n};\n"
  },
  {
    "path": "packages/vue-img-mapper/src/index.ts",
    "content": "// eslint-disable-next-line no-restricted-exports\nexport { default } from '@/ImageMapper.vue';\n"
  },
  {
    "path": "packages/vue-img-mapper/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"],\n      \"@playground/*\": [\"./playground/src/*\"]\n    }\n  },\n  \"include\": [\"**/*.ts\", \"**/*.mjs\", \"**/*.mts\", \"**/*.vue\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "packages/vue-img-mapper/tsdown.config.mts",
    "content": "// eslint-disable-next-line import-x/no-extraneous-dependencies\nimport { defineConfig } from 'tsdown';\n\nexport default defineConfig((options) => {\n  const { watch } = options;\n\n  return {\n    fromVite: true,\n    dts: {\n      vue: true,\n    },\n    format: ['cjs', 'esm'],\n    outDir: 'dist',\n    platform: 'browser',\n    treeshake: !watch,\n    minify: !watch,\n    exports: !watch,\n  };\n});\n"
  },
  {
    "path": "packages/vue-img-mapper/vite.config.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport vue from '@vitejs/plugin-vue';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n  root: './playground',\n  plugins: [vue()],\n  resolve: {\n    alias: {\n      '@': fileURLToPath(new URL('src', import.meta.url)),\n      '@playground': fileURLToPath(new URL('playground/src', import.meta.url)),\n    },\n  },\n});\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - docs\n  - apps/*\n  - packages/*\n\ncatalog:\n  '@types/react': ^19.2.2\n  '@types/react-dom': ^19.2.2\n  '@vercel/analytics': ^1.5.0\n  react: ^19.2.0\n  react-dom: ^19.2.0\n  tsdown: ^0.15.9\n  typescript: ^5.9.3\n  vite: ^7.1.11\n\nonlyBuiltDependencies:\n  - '@swc/core'\n  - esbuild\n  - unrs-resolver\n"
  },
  {
    "path": "prettier.config.mjs",
    "content": "/**\n * @see https://prettier.io/docs/configuration\n * @type {import(\"prettier\").Config}\n */\nexport default {\n  printWidth: 100,\n  singleQuote: true,\n  plugins: ['prettier-plugin-packagejson'],\n};\n"
  },
  {
    "path": "scripts/lint.sh",
    "content": "#!/bin/bash\n\nmode=\"fix\"\n\nfilters=()\n\nfor arg in \"$@\"; do\n  case $arg in\n  --for=*)\n    mode=\"${arg#--for=}\"\n    ;;\n  --filter=*)\n    filterArg=\"${arg#--filter=}\"\n    IFS=',' read -ra userFilters <<<\"$filterArg\"\n    for monorepo in \"${userFilters[@]}\"; do\n      filters+=(--filter \"$monorepo\")\n    done\n    ;;\n  esac\ndone\n\necho \"Started (mode: $mode)\"\n\nif [[ \"$mode\" == \"ci\" ]]; then\n  pnpm \"${filters[@]}\" --silent format:check --log-level silent >/dev/null 2>&1\n  echo \"Prettier Verified\"\n\n  pnpm \"${filters[@]}\" --silent lint >/dev/null 2>&1\n  echo \"ESLint Verified\"\n\n  pnpm \"${filters[@]}\" --silent typecheck >/dev/null 2>&1\n  echo \"TypeScript Verified\"\n\nelif [[ \"$mode\" == \"check\" ]]; then\n  pnpm \"${filters[@]}\" --silent format:check --log-level silent\n  echo \"Prettier Checked\"\n\n  pnpm \"${filters[@]}\" --silent lint\n  echo \"ESLint Checked\"\n\n  pnpm \"${filters[@]}\" --silent typecheck\n  echo \"TypeScript Checked\"\n\nelse\n  pnpm \"${filters[@]}\" --silent format:fix --log-level silent\n  echo \"Prettier Completed\"\n\n  pnpm \"${filters[@]}\" --silent lint:fix\n  echo \"ESLint Completed\"\n\n  pnpm \"${filters[@]}\" --silent typecheck\n  echo \"TypeScript Completed\"\nfi\n\necho \"Done\"\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"preserve\",\n    \"moduleResolution\": \"bundler\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"strict\": true,\n    \"noImplicitReturns\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"esModuleInterop\": true,\n    \"resolveJsonModule\": true,\n    \"useUnknownInCatchVariables\": true,\n    \"isolatedModules\": true,\n    \"declaration\": true\n  },\n  \"files\": [],\n  \"references\": [\n    {\n      \"path\": \"apps/examples\"\n    },\n    {\n      \"path\": \"docs\"\n    },\n    {\n      \"path\": \"packages/react-img-mapper\"\n    },\n    {\n      \"path\": \"packages/vue-img-mapper\"\n    }\n  ]\n}\n"
  }
]