[
  {
    "path": ".browserslistrc",
    "content": "# Browsers that we support\n\nlast 2 Chrome versions\nlast 2 Firefox versions\nlast 2 Safari versions\nlast 2 Edge versions\nEdge 18\n"
  },
  {
    "path": ".eslintignore",
    "content": "/coverage/\n/cypress/dummy/js/prism.js\n/dist/\n/docs/\n/dummy/\n/landing/\n/site/\n/test/cypress/dummy/\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  parserOptions: {\n    ecmaVersion: 'latest',\n    sourceType: 'module'\n  },\n  extends: ['eslint:recommended', 'plugin:svelte/recommended'],\n  env: {\n    browser: true\n  },\n  rules: {\n    'no-console': 'off',\n    'prefer-const': 'off'\n  },\n  overrides: [\n    // svelte files\n    {\n      files: ['**/*.svelte'],\n      processor: 'svelte/svelte'\n    },\n    // Typescript files\n    {\n      parser: '@typescript-eslint/parser',\n      files: ['**/*.ts'],\n      plugins: ['@typescript-eslint'],\n      extends: ['plugin:@typescript-eslint/recommended'],\n      rules: {\n        '@typescript-eslint/no-unused-vars': [\n          'error',\n          { argsIgnorePattern: '^_' }\n        ],\n        'prefer-rest-params': 'off'\n      }\n    },\n    // node files\n    {\n      files: [\n        '.eslintrc.js',\n        '.prettierrc.js',\n        'babel.config.js',\n        'svelte.config.js',\n        'tailwind.config.js'\n      ],\n      parserOptions: {\n        sourceType: 'module',\n        ecmaVersion: 2020\n      },\n      env: {\n        node: true\n      }\n    }\n  ]\n};\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "@chuckcarpenter\n@RobbieTheWagner\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: npm\n  directory: \"/\"\n  schedule:\n    interval: daily\n    time: \"10:00\"\n  open-pull-requests-limit: 10\n  labels:\n  - dependencies\n  versioning-strategy: increase\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 30\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"
  },
  {
    "path": ".github/workflows/plan-release.yml",
    "content": "name: Plan Release\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n      - master\n  pull_request_target: # This workflow has permissions on the repo, do NOT run code from PRs in this workflow. See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/\n    types:\n      - labeled\n      - unlabeled\n\nconcurrency:\n  group: plan-release # only the latest one of these should ever be running\n  cancel-in-progress: true\n\njobs:\n  should-run-release-plan-prepare:\n    name: Should we run release-plan prepare?\n    runs-on: ubuntu-latest\n    outputs:\n      should-prepare: ${{ steps.should-prepare.outputs.should-prepare }}\n    steps:\n      - uses: release-plan/actions/should-prepare-release@v1\n        with:\n          ref: 'main'\n        id: should-prepare\n\n  create-prepare-release-pr:\n    name: Create Prepare Release PR\n    runs-on: ubuntu-latest\n    timeout-minutes: 5\n    needs: should-run-release-plan-prepare\n    permissions:\n      contents: write\n      issues: read\n      pull-requests: write\n    if: needs.should-run-release-plan-prepare.outputs.should-prepare == 'true'\n    steps:\n      - uses: release-plan/actions/prepare@v1\n        name: Run release-plan prepare\n        with:\n          ref: 'main'\n        env:\n          GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}\n        id: explanation\n\n      - uses: peter-evans/create-pull-request@v8\n        name: Create Prepare Release PR\n        with:\n          commit-message: \"Prepare Release ${{ steps.explanation.outputs.new-version}} using 'release-plan'\"\n          labels: \"internal\"\n          sign-commits: true\n          branch: release-preview\n          title: Prepare Release ${{ steps.explanation.outputs.new-version }}\n          body: |\n            This PR is a preview of the release that [release-plan](https://github.com/embroider-build/release-plan) has prepared. To release you should just merge this PR 👍\n\n            -----------------------------------------\n\n            ${{ steps.explanation.outputs.text }}\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "# For every push to the primary branch with .release-plan.json modified,\n# runs release-plan.\n\nname: Publish Stable\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n      - master\n    paths:\n      - '.release-plan.json'\n\nconcurrency:\n  group: publish-${{ github.head_ref || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  publish:\n    name: \"NPM Publish\"\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      id-token: write\n      attestations: write\n\n    steps:\n      - uses: actions/checkout@v6\n      - uses: pnpm/action-setup@v4\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 22\n          registry-url: 'https://registry.npmjs.org'\n          cache: pnpm\n      - run: npm install -g npm@latest # ensure that the globally installed npm is new enough to support OIDC\n      - run: pnpm install --frozen-lockfile\n      - name: Publish to NPM\n        run: NPM_CONFIG_PROVENANCE=true pnpm release-plan publish\n        env:\n          GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - main\n    paths-ignore:\n      - 'app/**'\n  pull_request:\n    paths-ignore:\n      - 'app/**'\n\njobs:\n  lint:\n    name: Linting\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n\n      - name: Setup pnpm\n        uses: wyvox/action-setup-pnpm@v3\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Run linting\n        run: pnpm lint\n\n  typecheck:\n    name: Type Check\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n\n      - name: Setup pnpm\n        uses: wyvox/action-setup-pnpm@v3\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Check types\n        run: pnpm types:check\n\n  test:\n    name: Tests\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n\n      - name: Setup pnpm\n        uses: wyvox/action-setup-pnpm@v3\n\n      - name: Install Dependencies\n        run: pnpm install\n\n      - name: Install Cypress Binary\n        run: pnpm cypress:install\n\n      - name: Run Jest/Vitest and Cypress Tests\n        uses: cypress-io/github-action@v6\n        with:\n          command: pnpm test:ci\n          install: false\n      - name: Upload Coverage to Qlty\n        uses: qltysh/qlty-action/coverage@v2\n        with:\n          token: ${{ secrets.QLTY_COVERAGE_TOKEN }}\n          files: shepherd.js/test/coverage/lcov.info\n          add-prefix: shepherd.js/\n"
  },
  {
    "path": ".gitignore",
    "content": "# Editors\n/.idea/\n/.vscode/\n\n.eslintcache\n.nyc_output/\ncoverage/\ndist/\nnode_modules/\n\n/.log/\n\n/cypress/\n/docs/\n/site/\n/test/unit/dist\n*.DS_Store\n/.sass-cache\n/npm-debug.log*\n/stats.html\n/yarn-error.log\n\n# app specific \n.DS_Store\n.env\n.env.local\nfly-*.toml\n/app/.redwood/*\n!.redwood/README.md\ndev.db*\ndist\ndist-babel\nnode_modules\nyarn-error.log\nweb/public/mockServiceWorker.js\nweb/types/graphql.d.ts\napi/types/graphql.d.ts\napi/src/lib/generateGraphiQLHeader.*\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\nsendgrid.env\n\npostgres\n"
  },
  {
    "path": ".nojekyll",
    "content": ""
  },
  {
    "path": ".prettierrc.js",
    "content": "'use strict';\n\nmodule.exports = {\n  arrowParens: 'always',\n  proseWrap: 'always',\n  trailingComma: 'none',\n  singleQuote: true,\n  plugins: ['prettier-plugin-astro'],\n  overrides: [\n    {\n      files: '*.astro',\n      options: {\n        parser: 'astro'\n      }\n    },\n    { files: '*.svelte', options: { parser: 'svelte' } }\n  ]\n};\n"
  },
  {
    "path": ".release-plan.json",
    "content": "{\n  \"solution\": {\n    \"react-shepherd\": {\n      \"impact\": \"patch\",\n      \"oldVersion\": \"7.0.3\",\n      \"newVersion\": \"7.0.4\",\n      \"tagName\": \"latest\",\n      \"constraints\": [\n        {\n          \"impact\": \"patch\",\n          \"reason\": \"Has dependency `workspace:*` on shepherd.js\"\n        }\n      ],\n      \"pkgJSONPath\": \"./packages/react/package.json\"\n    },\n    \"shepherd.js\": {\n      \"impact\": \"patch\",\n      \"oldVersion\": \"15.2.1\",\n      \"newVersion\": \"15.2.2\",\n      \"tagName\": \"latest\",\n      \"constraints\": [\n        {\n          \"impact\": \"patch\",\n          \"reason\": \"Appears in changelog section :bug: Bug Fix\"\n        }\n      ],\n      \"pkgJSONPath\": \"./shepherd.js/package.json\"\n    }\n  },\n  \"description\": \"## Release (2026-03-11)\\n\\n* react-shepherd 7.0.4 (patch)\\n* shepherd.js 15.2.2 (patch)\\n\\n#### :bug: Bug Fix\\n* `shepherd.js`\\n  * [#3376](https://github.com/shipshapecode/shepherd/pull/3376) Fix missing cancel event when navigating back past a hidden first step ([@Copilot](https://github.com/apps/copilot-swe-agent))\\n\\n#### Committers: 1\\n- Copilot [Bot] ([@copilot-swe-agent](https://github.com/apps/copilot-swe-agent))\\n\"\n}\n"
  },
  {
    "path": ".tool-versions",
    "content": "nodejs 22.22.0\npnpm 10.28.2\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## Release (2026-03-11)\n\n* react-shepherd 7.0.4 (patch)\n* shepherd.js 15.2.2 (patch)\n\n#### :bug: Bug Fix\n* `shepherd.js`\n  * [#3376](https://github.com/shipshapecode/shepherd/pull/3376) Fix missing cancel event when navigating back past a hidden first step ([@Copilot](https://github.com/apps/copilot-swe-agent))\n\n#### Committers: 1\n- Copilot [Bot] ([@copilot-swe-agent](https://github.com/apps/copilot-swe-agent))\n\n## Release (2026-02-23)\n\n* react-shepherd 7.0.3 (patch)\n* shepherd.js 15.2.1 (patch)\n\n#### :bug: Bug Fix\n* `shepherd.js`\n  * [#3373](https://github.com/shipshapecode/shepherd/pull/3373) Use files to reduce what is published to npm ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2026-02-19)\n\n* react-shepherd 7.0.2 (patch)\n* shepherd.js 15.2.0 (minor)\n\n#### :rocket: Enhancement\n* `shepherd.js`\n  * [#3370](https://github.com/shipshapecode/shepherd/pull/3370) Add support for HTML attributes on buttons and cancelIcon ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2026-02-18)\n\n* react-shepherd 7.0.1 (patch)\n* shepherd.js 15.1.0 (minor)\n\n#### :rocket: Enhancement\n* `shepherd.js`\n  * [#3362](https://github.com/shipshapecode/shepherd/pull/3362) Remove string continuations ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#3361](https://github.com/shipshapecode/shepherd/pull/3361) Switch to polar astro package ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2026-02-08)\n\n* react-shepherd 7.0.0 (major)\n* shepherd.js 15.0.0 (major)\n\n#### :boom: Breaking Change\n* `shepherd.js`\n  * [#3352](https://github.com/shipshapecode/shepherd/pull/3352) Remove svelte and use vanilla TS ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n  * [#3342](https://github.com/shipshapecode/shepherd/pull/3342) Drop support for node 18, move tests ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* `react-shepherd`, `shepherd.js`\n  * [#3144](https://github.com/shipshapecode/shepherd/pull/3144) Update to Svelte 5 ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :rocket: Enhancement\n* `react-shepherd`\n  * [#3339](https://github.com/shipshapecode/shepherd/pull/3339) Support React 18+ in peerDeps ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :bug: Bug Fix\n* `shepherd.js`\n  * [#3351](https://github.com/shipshapecode/shepherd/pull/3351) Restore attachTo tabindex when tour is hidden ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :memo: Documentation\n* `react-shepherd`, `shepherd.js`\n  * [#3341](https://github.com/shipshapecode/shepherd/pull/3341) More license updates ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* Other\n  * [#3340](https://github.com/shipshapecode/shepherd/pull/3340) Update LICENSE.md ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* `shepherd.js`\n  * [#3323](https://github.com/shipshapecode/shepherd/pull/3323) Redirect to root when starting demo ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* `react-shepherd`\n  * [#3315](https://github.com/shipshapecode/shepherd/pull/3315) Update README example path ([@Poylar](https://github.com/Poylar))\n\n#### :house: Internal\n* Other\n  * [#3343](https://github.com/shipshapecode/shepherd/pull/3343) Update landing to tailwind 4 ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* `react-shepherd`, `shepherd.js`\n  * [#3324](https://github.com/shipshapecode/shepherd/pull/3324) pnpm update ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n  * [#3302](https://github.com/shipshapecode/shepherd/pull/3302) Remove scarf, bump vitest ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 2\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n- [@Poylar](https://github.com/Poylar)\n\n## Release (2025-07-23)\n\n* react-shepherd 6.1.9 (patch)\n* shepherd.js 14.5.1 (patch)\n\n#### :bug: Bug Fix\n* `shepherd.js`\n  * [#3230](https://github.com/shipshapecode/shepherd/pull/3230) Add attachTo elements to the keyboard focus flow ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* `shepherd.js`\n  * [#3229](https://github.com/shipshapecode/shepherd/pull/3229) Add dummy app back for development ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2025-02-20)\n\nreact-shepherd 6.1.8 (patch)\nshepherd.js 14.5.0 (minor)\n\n#### :rocket: Enhancement\n* `shepherd-docs`, `shepherd.js`, `cypress-tests`, `unit-tests`\n  * [#3051](https://github.com/shipshapecode/shepherd/pull/3051) Allow arrow padding to be configured for a step. ([@JakeThurman](https://github.com/JakeThurman))\n\n#### :house: Internal\n* `shepherd-docs`, `landing`, `shepherd.js`, `cypress-tests`, `unit-tests`\n  * [#3111](https://github.com/shipshapecode/shepherd/pull/3111) Update to Astro 5.x ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 2\n- Jake Thurman ([@JakeThurman](https://github.com/JakeThurman))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2025-01-13)\n\nreact-shepherd 6.1.7 (patch)\nshepherd.js 14.4.0 (minor)\n\n#### :rocket: Enhancement\n* `shepherd.js`\n  * [#3068](https://github.com/shipshapecode/shepherd/pull/3068) 💄 Add reset for dialog element ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :bug: Bug Fix\n* `shepherd.js`, `cypress-tests`\n  * [#3083](https://github.com/shipshapecode/shepherd/pull/3083) ♿ Remove tabindex to reduce tabs for modal trap ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* `landing`\n  * [#3089](https://github.com/shipshapecode/shepherd/pull/3089) ⬆ Update Polar SDK and use new API ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* Other\n  * [#3066](https://github.com/shipshapecode/shepherd/pull/3066) Prepare Release ([@github-actions[bot]](https://github.com/apps/github-actions))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- [@github-actions[bot]](https://github.com/apps/github-actions)\n\n\n\n\n\n\n## Release (2024-11-19)\n\nreact-shepherd 6.1.6 (patch)\nshepherd.js 14.3.0 (minor)\n\n#### :rocket: Enhancement\n* `shepherd-docs`, `shepherd.js`, `unit-tests`\n  * [#3009](https://github.com/shipshapecode/shepherd/pull/3009) Add 'auto' as placement option ([@patrikholcak](https://github.com/patrikholcak))\n\n#### :house: Internal\n* `react-shepherd`, `shepherd.js`\n  * [#3035](https://github.com/shipshapecode/shepherd/pull/3035) Prepare Release ([@github-actions[bot]](https://github.com/apps/github-actions))\n\n#### Committers: 2\n- Patrik Holčák ([@patrikholcak](https://github.com/patrikholcak))\n- [@github-actions[bot]](https://github.com/apps/github-actions)\n\n## Release (2024-11-19)\n\nreact-shepherd 6.1.5 (patch)\nshepherd.js 14.2.0 (minor)\n\n#### :rocket: Enhancement\n* `shepherd-docs`, `shepherd.js`, `unit-tests`\n  * [#3009](https://github.com/shipshapecode/shepherd/pull/3009) Add 'auto' as placement option ([@patrikholcak](https://github.com/patrikholcak))\n\n#### Committers: 1\n- Patrik Holčák ([@patrikholcak](https://github.com/patrikholcak))\n\n## Release (2024-10-21)\n\nreact-shepherd 6.1.4 (patch)\nshepherd.js 14.1.0 (minor)\n\n#### :rocket: Enhancement\n* `shepherd-docs`, `landing`, `shepherd.js`, `unit-tests`\n  * [#2995](https://github.com/shipshapecode/shepherd/pull/2995) Implement multiple element highlighting feature ([@YuunsGit](https://github.com/YuunsGit))\n\n#### :bug: Bug Fix\n* `shepherd.js`\n  * [#3011](https://github.com/shipshapecode/shepherd/pull/3011) Fix options type for `options.floatingUIOptions` ([@patrikholcak](https://github.com/patrikholcak))\n\n#### :memo: Documentation\n* `landing`\n  * [#3025](https://github.com/shipshapecode/shepherd/pull/3025) Fix loading on button, add link to root page on logo ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* `landing`\n  * [#3025](https://github.com/shipshapecode/shepherd/pull/3025) Fix loading on button, add link to root page on logo ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n  * [#3015](https://github.com/shipshapecode/shepherd/pull/3015) State Fix for Pricing ([@Naman-B-Parlecha](https://github.com/Naman-B-Parlecha))\n  * [#3013](https://github.com/shipshapecode/shepherd/pull/3013) 🐛 Change check for DOMContentLoaded to astro:page-load ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 5\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Naman-Parlecha ([@Naman-B-Parlecha](https://github.com/Naman-B-Parlecha))\n- Patrik Holčák ([@patrikholcak](https://github.com/patrikholcak))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Yunus Emre ([@YuunsGit](https://github.com/YuunsGit))\n\n## Release (2024-10-10)\n\nreact-shepherd 6.1.3 (patch)\nshepherd.js 14.0.1 (patch)\n\n#### :bug: Bug Fix\n* `shepherd.js`, `unit-tests`\n  * [#3005](https://github.com/shipshapecode/shepherd/pull/3005) 🐛 Fix issue where passed in custom middleware is overridden ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* [#3003](https://github.com/shipshapecode/shepherd/pull/3003) Prepare Release ([@github-actions[bot]](https://github.com/apps/github-actions))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- [@github-actions[bot]](https://github.com/apps/github-actions)\n\n\n\n\n\n\n## Release (2024-10-08)\n\nreact-shepherd 6.1.2 (patch)\nshepherd.js 14.0.0 (major)\n\n#### :boom: Breaking Change\n* `shepherd.js`\n  * [#2976](https://github.com/shipshapecode/shepherd/pull/2976) Update license to AGPL-3.0 ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* Other\n  * [#2969](https://github.com/shipshapecode/shepherd/pull/2969) 📄 Update license for commercial use cases ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :rocket: Enhancement\n* `landing`, `shepherd.js`, `cypress-tests`\n  * [#2982](https://github.com/shipshapecode/shepherd/pull/2982) ✨ Update shepherd element to use html dialog ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :bug: Bug Fix\n* `landing`, `react-shepherd`\n  * [#2988](https://github.com/shipshapecode/shepherd/pull/2988) 🐛 Landing: Fix checkout issue with correct PAT ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd.js`\n  * [#2979](https://github.com/shipshapecode/shepherd/pull/2979) Fix handler type for Evented.off() ([@joeldomke](https://github.com/joeldomke))\n* `shepherd-docs`, `landing`, `shepherd.js`\n  * [#2980](https://github.com/shipshapecode/shepherd/pull/2980) 🐛 Fix event timing issue and add button for demo start ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* `landing`\n  * [#2974](https://github.com/shipshapecode/shepherd/pull/2974) Update some various styles ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n  * [#2972](https://github.com/shipshapecode/shepherd/pull/2972) ✨ Add updated pricing page and commerical benefits ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `landing`, `react-shepherd`, `shepherd.js`\n  * [#2973](https://github.com/shipshapecode/shepherd/pull/2973) 📝 Update documentation for correct url ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd-docs`\n  * [#2967](https://github.com/shipshapecode/shepherd/pull/2967) 📝 Add docs for analytics and react usage ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* Other\n  * [#2960](https://github.com/shipshapecode/shepherd/pull/2960) 📝 Remove docker info on README ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* Other\n  * [#2981](https://github.com/shipshapecode/shepherd/pull/2981) 🔥 Pro: Remove deprecated pro package ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `landing`\n  * [#2975](https://github.com/shipshapecode/shepherd/pull/2975) 🐛 Landing: Remove import string from frontmatter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2968](https://github.com/shipshapecode/shepherd/pull/2968) Landing: 🔥 Remove and upgrade dependencies ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `landing`, `react-shepherd`, `shepherd.js`\n  * [#2973](https://github.com/shipshapecode/shepherd/pull/2973) 📝 Update documentation for correct url ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd-docs`\n  * [#2967](https://github.com/shipshapecode/shepherd/pull/2967) 📝 Add docs for analytics and react usage ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2966](https://github.com/shipshapecode/shepherd/pull/2966) ⬆ Update Astro to v14.15 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 3\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Joel Domke ([@joeldomke](https://github.com/joeldomke))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2024-08-05)\n\n@shepherdpro/pro-js 1.3.1 (patch)\nreact-shepherd 6.1.1 (patch)\nshepherd.js 13.0.3 (patch)\n\n#### :house: Internal\n* `shepherd-docs`, `landing`\n  * [#2944](https://github.com/shipshapecode/shepherd/pull/2944) 🐛 Fix pnpm version in Dockerfiles ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `landing`, `shepherd.js`, `cypress-tests`, `unit-tests`\n  * [#2938](https://github.com/shipshapecode/shepherd/pull/2938) ✨ Landing: Add storyblok CMS ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-07-25)\n\n@shepherdpro/pro-js 1.3.0 (minor)\nreact-shepherd 6.1.0 (minor)\n\n#### :rocket: Enhancement\n* `@shepherdpro/pro-js`, `react-shepherd`\n  * [#2929](https://github.com/shipshapecode/shepherd/pull/2929) ➖ React: Remove extra pro specific setup ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* `shepherd-docs`\n  * [#2928](https://github.com/shipshapecode/shepherd/pull/2928) 📝 Docs updates for pro beta setup/usage ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* `shepherd-docs`\n  * [#2928](https://github.com/shipshapecode/shepherd/pull/2928) 📝 Docs updates for pro beta setup/usage ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* Other\n  * [#2925](https://github.com/shipshapecode/shepherd/pull/2925) Prepare Release ([@github-actions[bot]](https://github.com/apps/github-actions))\n  * [#2924](https://github.com/shipshapecode/shepherd/pull/2924) Update publish.yml to have node-registry-url ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### Committers: 3\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- [@NullVoxPopuli](https://github.com/NullVoxPopuli)\n- [@github-actions[bot]](https://github.com/apps/github-actions)\n\n## Release (2024-07-24)\n\n\n\n#### :house: Internal\n* [#2924](https://github.com/shipshapecode/shepherd/pull/2924) Update publish.yml to have node-registry-url ([@NullVoxPopuli](https://github.com/NullVoxPopuli))\n\n#### Committers: 1\n- [@NullVoxPopuli](https://github.com/NullVoxPopuli)\n\n## Release (2024-07-24)\n\n@shepherdpro/pro-js 1.2.2 (patch)\nreact-shepherd 6.0.8 (patch)\nshepherd.js 13.0.2 (patch)\n\n#### :house: Internal\n* `@shepherdpro/pro-js`, `react-shepherd`, `shepherd.js`\n  * [#2922](https://github.com/shipshapecode/shepherd/pull/2922) 👷 Add publish config and scarf paackage ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-07-22)\n\n@shepherdpro/pro-js 1.2.1 (patch)\nreact-shepherd 6.0.7 (patch)\n\n#### :bug: Bug Fix\n* `@shepherdpro/pro-js`, `react-shepherd`\n  * [#2920](https://github.com/shipshapecode/shepherd/pull/2920) 👷 Fix package for correct release plan build ordering ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-07-18)\n\n@shepherdpro/pro-js 1.2.0 (minor)\nreact-shepherd 6.0.6 (patch)\n\n#### :rocket: Enhancement\n* `@shepherdpro/pro-js`\n  * [#2911](https://github.com/shipshapecode/shepherd/pull/2911) ✨ Pro: Add functions to pro for taking config from API ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* `shepherd-docs`, `landing`\n  * [#2912](https://github.com/shipshapecode/shepherd/pull/2912) ⬆ Update of Astro to v4.12 and related deps upgrades ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `react-shepherd`\n  * [#2882](https://github.com/shipshapecode/shepherd/pull/2882) ➖ Remove release-it package and configs ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-06-28)\n\n@shepherdpro/pro-js 1.1.0 (minor)\nreact-shepherd 6.0.5 (patch)\nshepherd.js 13.0.1 (patch)\n\n#### :rocket: Enhancement\n* `@shepherdpro/pro-js`\n  * [#2895](https://github.com/shipshapecode/shepherd/pull/2895) ✨ Add reading for isAutoStart value sent from app ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :bug: Bug Fix\n* `shepherd.js`\n  * [#2900](https://github.com/shipshapecode/shepherd/pull/2900) 🐛 Add small padding to arrow if edge alignment is used ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* [#2898](https://github.com/shipshapecode/shepherd/pull/2898) 👷 Fix changelog error on merges ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-06-22)\n\n@shepherdpro/pro-js 1.0.4 (patch)\nreact-shepherd 6.0.4 (patch)\n\n#### :bug: Bug Fix\n* `@shepherdpro/pro-js`\n  * [#2887](https://github.com/shipshapecode/shepherd/pull/2887) 🐛 Fix issue with object merge to push events to pro app ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-06-21)\n\n@shepherdpro/pro-js 1.0.3 (patch)\nreact-shepherd 6.0.3 (patch)\n\n#### :bug: Bug Fix\n* `@shepherdpro/pro-js`, `react-shepherd`\n  * [#2885](https://github.com/shipshapecode/shepherd/pull/2885) 🐛 Fix missing tour active check ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-06-21)\n\n@shepherdpro/pro-js 1.0.2 (patch)\nreact-shepherd 6.0.2 (patch)\n\n#### :bug: Bug Fix\n* `@shepherdpro/pro-js`\n  * [#2883](https://github.com/shipshapecode/shepherd/pull/2883) 🐛 Fix bug where events fail to fire due to naming ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* `shepherd-docs`, `landing`\n  * [#2880](https://github.com/shipshapecode/shepherd/pull/2880) 📝 Add updated documentation for pro package and updated CDN links ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* [#2881](https://github.com/shipshapecode/shepherd/pull/2881) Prepare Release ([@github-actions[bot]](https://github.com/apps/github-actions))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- [@github-actions[bot]](https://github.com/apps/github-actions)\n\n## Release (2024-06-21)\n\n\n\n#### :memo: Documentation\n* `shepherd-docs`, `landing`\n  * [#2880](https://github.com/shipshapecode/shepherd/pull/2880) 📝 Add updated documentation for pro package and updated CDN links ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-06-20)\n\n@shepherdpro/pro-js 1.0.1 (patch)\nreact-shepherd 6.0.1 (patch)\n\n#### :bug: Bug Fix\n* `@shepherdpro/pro-js`\n  * [#2878](https://github.com/shipshapecode/shepherd/pull/2878) 👷 Add prepack script to pro-js ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-06-19)\n\n@shepherdpro/pro-js 1.0.0 (major)\nreact-shepherd 6.0.0 (major)\nshepherd.js 13.0.0 (major)\n\n#### :boom: Breaking Change\n* `shepherd-docs`, `@shepherdpro/pro-js`, `react-shepherd`, `shepherd.js`, `cypress-tests`, `unit-tests`\n  * [#2870](https://github.com/shipshapecode/shepherd/pull/2870) ✨ Add new package specific to Pro features ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :bug: Bug Fix\n* `shepherd-docs`, `react-shepherd`, `shepherd.js`\n  * [#2871](https://github.com/shipshapecode/shepherd/pull/2871) Simplify dist to only include one TS file ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* `landing`\n  * [#2877](https://github.com/shipshapecode/shepherd/pull/2877) 👷 Add correct token to publish all packages ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2838](https://github.com/shipshapecode/shepherd/pull/2838) tweak: prevents header links overflow in small screens ([@ArnavK-09](https://github.com/ArnavK-09))\n\n#### Committers: 3\n- Arnav K ([@ArnavK-09](https://github.com/ArnavK-09))\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2024-06-07)\n\nreact-shepherd 5.0.6 (patch)\nshepherd.js 12.0.6 (patch)\n\n#### :bug: Bug Fix\n* `shepherd.js`, `cypress-tests`\n  * [#2853](https://github.com/shipshapecode/shepherd/pull/2853) fix: reconfigure CSS bundling ([@Kenneth-Sills](https://github.com/Kenneth-Sills))\n\n#### :house: Internal\n* `shepherd.js`\n  * [#2848](https://github.com/shipshapecode/shepherd/pull/2848) Bump @floating-ui/dom from 1.6.3 to 1.6.5 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2851](https://github.com/shipshapecode/shepherd/pull/2851) Bump rollup-plugin-license from 3.3.1 to 3.4.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `shepherd.js`, `cypress-tests`, `unit-tests`\n  * [#2849](https://github.com/shipshapecode/shepherd/pull/2849) Bump @babel/core from 7.24.5 to 7.24.6 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* Other\n  * [#2850](https://github.com/shipshapecode/shepherd/pull/2850) Bump release-it from 17.2.1 to 17.3.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2846](https://github.com/shipshapecode/shepherd/pull/2846) App: 🔥 Remove app as it is not part of a workspace ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2844](https://github.com/shipshapecode/shepherd/pull/2844) App: ⬆ Upgrade Shepherd lib in the app to v5 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd-docs`\n  * [#2852](https://github.com/shipshapecode/shepherd/pull/2852) Bump @astrojs/starlight from 0.22.4 to 0.23.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2799](https://github.com/shipshapecode/shepherd/pull/2799) Bump @flydotio/dockerfile from 0.5.6 to 0.5.7 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `unit-tests`\n  * [#2816](https://github.com/shipshapecode/shepherd/pull/2816) Bump core-js from 3.37.0 to 3.37.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Kenneth Sills ([@Kenneth-Sills](https://github.com/Kenneth-Sills))\n\n## Release (2024-05-29)\n\nreact-shepherd 5.0.5 (patch)\nshepherd.js 12.0.5 (patch)\n\n#### :bug: Bug Fix\n* `shepherd-docs`, `shepherd.js`, `cypress-tests`\n  * [#2839](https://github.com/shipshapecode/shepherd/pull/2839) Export CSS and just create one file ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* `shepherd-docs`, `landing`\n  * [#2840](https://github.com/shipshapecode/shepherd/pull/2840) Bump @astrojs/check from 0.5.10 to 0.7.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `shepherd.js`\n  * [#2818](https://github.com/shipshapecode/shepherd/pull/2818) Bump eslint-plugin-svelte from 2.38.0 to 2.39.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2835](https://github.com/shipshapecode/shepherd/pull/2835) Landing: ➕ Update node version for deployment action ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `cypress-tests`\n  * [#2841](https://github.com/shipshapecode/shepherd/pull/2841) Bump chai from 4.4.1 to 5.1.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* Other\n  * [#2836](https://github.com/shipshapecode/shepherd/pull/2836) App: ⬆ Upgrade RW version to v7.6 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2024-05-24)\n\nshepherd-docs 0.0.6 (patch)\nreact-shepherd 5.0.4 (patch)\nshepherd.js 12.0.4 (patch)\n\n#### :bug: Bug Fix\n* `shepherd-docs`, `landing`, `shepherd.js`, `cypress-tests`\n  * [#2820](https://github.com/shipshapecode/shepherd/pull/2820) Fix TS issues, more correctly ship CJS and ESM ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* `unit-tests`\n  * [#2814](https://github.com/shipshapecode/shepherd/pull/2814) Bump eslint-plugin-jest from 28.4.0 to 28.5.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `react-shepherd`\n  * [#2819](https://github.com/shipshapecode/shepherd/pull/2819) Bump happy-dom from 14.7.1 to 14.11.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2024-05-24)\n\nshepherd-docs 0.0.5 (patch)\nreact-shepherd 5.0.3 (patch)\nshepherd.js 12.0.3 (patch)\n\n#### :bug: Bug Fix\n* `react-shepherd`\n  * [#2828](https://github.com/shipshapecode/shepherd/pull/2828) React: 🐛 Fix init to be optional ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2809](https://github.com/shipshapecode/shepherd/pull/2809) React: 👷 Update tsc target to match lowest compatibility ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `landing`\n  * [#2821](https://github.com/shipshapecode/shepherd/pull/2821) Landing: 🐛 Fix config for canonicalURL ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* [#2824](https://github.com/shipshapecode/shepherd/pull/2824) Update README.md for incorrect URL ([@pranshugupta54](https://github.com/pranshugupta54))\n\n#### :house: Internal\n* `landing`\n  * [#2827](https://github.com/shipshapecode/shepherd/pull/2827) Landing: 🐛 Update action to build js lib before docker copys it ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2826](https://github.com/shipshapecode/shepherd/pull/2826) Landing: 🐛 Update Dockerfile to build JS lib before copy ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2804](https://github.com/shipshapecode/shepherd/pull/2804) Bump @tailwindcss/typography from 0.5.12 to 0.5.13 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `shepherd-docs`, `landing`, `react-shepherd`, `shepherd.js`\n  * [#2825](https://github.com/shipshapecode/shepherd/pull/2825) Landing: 🚚 Move blog to index page and update URLs ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* Other\n  * [#2822](https://github.com/shipshapecode/shepherd/pull/2822) App: 🐛 Fix IP address check for webhook ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2811](https://github.com/shipshapecode/shepherd/pull/2811) App: ✨ Remove FF for pricing and edit signup flow ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2810](https://github.com/shipshapecode/shepherd/pull/2810) App: 🗃️  Add created at for users and subscription defaults ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `landing`, `shepherd.js`\n  * [#2812](https://github.com/shipshapecode/shepherd/pull/2812) Landing: 👷 Add fly.io deployment ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd-docs`\n  * [#2808](https://github.com/shipshapecode/shepherd/pull/2808) Bump @astrojs/starlight from 0.21.5 to 0.22.4 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `react-shepherd`\n  * [#2798](https://github.com/shipshapecode/shepherd/pull/2798) Bump @testing-library/react from 15.0.6 to 15.0.7 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2797](https://github.com/shipshapecode/shepherd/pull/2797) Bump @types/react from 18.3.1 to 18.3.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `shepherd-docs`, `landing`\n  * [#2806](https://github.com/shipshapecode/shepherd/pull/2806) Bump astro from 4.6.3 to 4.8.4 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Pranshu Gupta ([@pranshugupta54](https://github.com/pranshugupta54))\n\n## Release (2024-05-14)\n\nshepherd-docs 0.0.4 (patch)\nreact-shepherd 5.0.2 (patch)\nshepherd.js 12.0.2 (patch)\n\n#### :bug: Bug Fix\n* `landing`, `shepherd.js`\n  * [#2805](https://github.com/shipshapecode/shepherd/pull/2805) 🐛 Fixes import issues reported in 2785 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd.js`\n  * [#2794](https://github.com/shipshapecode/shepherd/pull/2794) 🐛  Add missing required type attribute for button ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2793](https://github.com/shipshapecode/shepherd/pull/2793) 🐛  Add fix for modal reshow from 2436 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* Other\n  * [#2784](https://github.com/shipshapecode/shepherd/pull/2784) Bump release-it from 17.2.0 to 17.2.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2790](https://github.com/shipshapecode/shepherd/pull/2790) App: ✨ Add webhook for subscription management ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2788](https://github.com/shipshapecode/shepherd/pull/2788) App: 🗃️  Add migration to give all users a subscription ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd.js`\n  * [#2782](https://github.com/shipshapecode/shepherd/pull/2782) Bump rollup from 4.14.3 to 4.17.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `react-shepherd`\n  * [#2778](https://github.com/shipshapecode/shepherd/pull/2778) Bump vite from 5.2.10 to 5.2.11 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## Release (2024-05-10)\n\nshepherd-docs 0.0.3 (patch)\nreact-shepherd 5.0.1 (patch)\nshepherd.js 12.0.1 (patch)\n\n#### :bug: Bug Fix\n* `react-shepherd`, `shepherd.js`\n  * [#2789](https://github.com/shipshapecode/shepherd/pull/2789) Add prepack scripts ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* `react-shepherd`\n  * [#2781](https://github.com/shipshapecode/shepherd/pull/2781) Bump vite-plugin-dts from 3.9.0 to 3.9.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `shepherd.js`, `cypress-tests`, `unit-tests`\n  * [#2783](https://github.com/shipshapecode/shepherd/pull/2783) Bump @babel/core from 7.24.4 to 7.24.5 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* Other\n  * [#2786](https://github.com/shipshapecode/shepherd/pull/2786) App: 🚑️ Fix to disable post for checkout url ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## Release (2024-05-06)\n\nshepherd-docs 0.0.2 (patch)\nreact-shepherd 5.0.0 (major)\nshepherd.js 12.0.0 (patch)\n\n#### :boom: Breaking Change\n* `react-shepherd`\n  * [#2707](https://github.com/shipshapecode/shepherd/pull/2707) React: ✨ Adding improved provider for v5 release ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* `shepherd-docs`\n  * [#2768](https://github.com/shipshapecode/shepherd/pull/2768) Docs: 📝 Add page for pro analytics ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd-docs`, `shepherd.js`\n  * [#2717](https://github.com/shipshapecode/shepherd/pull/2717) Docs: 📝 Move docs generator to Starlight and typedoc ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd.js`\n  * [#2735](https://github.com/shipshapecode/shepherd/pull/2735) 🚚 Move copy of main README to lib ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* `react-shepherd`\n  * [#2755](https://github.com/shipshapecode/shepherd/pull/2755) Bump vite-plugin-dts from 3.8.3 to 3.9.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2772](https://github.com/shipshapecode/shepherd/pull/2772) Bump @testing-library/react from 15.0.4 to 15.0.6 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2774](https://github.com/shipshapecode/shepherd/pull/2774) Bump @vitest/ui from 1.5.0 to 1.6.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2759](https://github.com/shipshapecode/shepherd/pull/2759) Bump @types/react from 18.2.79 to 18.3.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2753](https://github.com/shipshapecode/shepherd/pull/2753) Bump @testing-library/react from 14.2.2 to 15.0.4 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2754](https://github.com/shipshapecode/shepherd/pull/2754) Bump vitest from 1.4.0 to 1.5.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2742](https://github.com/shipshapecode/shepherd/pull/2742) Bump vite from 5.2.8 to 5.2.10 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2750](https://github.com/shipshapecode/shepherd/pull/2750) Bump @vitest/ui from 1.4.0 to 1.5.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2718](https://github.com/shipshapecode/shepherd/pull/2718) Bump vite-plugin-dts from 3.7.3 to 3.8.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2704](https://github.com/shipshapecode/shepherd/pull/2704) Bump happy-dom from 14.3.9 to 14.7.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2726](https://github.com/shipshapecode/shepherd/pull/2726) Bump @types/react from 18.2.70 to 18.2.79 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* Other\n  * [#2776](https://github.com/shipshapecode/shepherd/pull/2776) App: ✨ Add initial Chargebee integration, under feature flag ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2751](https://github.com/shipshapecode/shepherd/pull/2751) App: ⬆ Upgrade redwood to 7.4.3 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2741](https://github.com/shipshapecode/shepherd/pull/2741) App: 💄 Fix benefits layout on mobile ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2740](https://github.com/shipshapecode/shepherd/pull/2740) App: 💄 Add mobile menu and styling for landing page ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2739](https://github.com/shipshapecode/shepherd/pull/2739) App: 🐛 Update footer links to not use component link ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2738](https://github.com/shipshapecode/shepherd/pull/2738) App: 📝 Update analytics text on landing page ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2737](https://github.com/shipshapecode/shepherd/pull/2737) App: 💄 Update main landing page ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2732](https://github.com/shipshapecode/shepherd/pull/2732) Update README.md ([@malthauser](https://github.com/malthauser))\n  * [#2733](https://github.com/shipshapecode/shepherd/pull/2733) App: 🐛 Add href to reset email link ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2730](https://github.com/shipshapecode/shepherd/pull/2730) App: ✨ Add email for forgot password flow ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2731](https://github.com/shipshapecode/shepherd/pull/2731) App: 🐛 Fix position of second step to allow click on smaller screens ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2728](https://github.com/shipshapecode/shepherd/pull/2728) App: ✨ Add user properties to tour setup ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2714](https://github.com/shipshapecode/shepherd/pull/2714) Bump jose from 4.15.4 to 4.15.5 in /app ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2727](https://github.com/shipshapecode/shepherd/pull/2727) App: 🐛 Update before show of tour to wait for element to render ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2724](https://github.com/shipshapecode/shepherd/pull/2724) App: 🐛 Fix some TS errors from emails fix and prerender landing page ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2723](https://github.com/shipshapecode/shepherd/pull/2723) App: ⬆ Update Redwood to v7.4.1 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2716](https://github.com/shipshapecode/shepherd/pull/2716) App: ✨ Add description field to demo request form ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2713](https://github.com/shipshapecode/shepherd/pull/2713) App: ⬆ Update Redwood to v7.3.2 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2706](https://github.com/shipshapecode/shepherd/pull/2706) 🚚 Move platform application files to main repo ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd-docs`, `landing`\n  * [#2775](https://github.com/shipshapecode/shepherd/pull/2775) Docs: ➕ Add posthog for analytics to both docs and landing ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd-docs`\n  * [#2763](https://github.com/shipshapecode/shepherd/pull/2763) Bump sharp from 0.32.6 to 0.33.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `shepherd.js`\n  * [#2764](https://github.com/shipshapecode/shepherd/pull/2764) Bump cssnano from 6.1.2 to 7.0.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2722](https://github.com/shipshapecode/shepherd/pull/2722) Bump rollup from 4.13.2 to 4.14.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* `unit-tests`\n  * [#2770](https://github.com/shipshapecode/shepherd/pull/2770) Bump eslint-plugin-jest from 28.2.0 to 28.4.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2703](https://github.com/shipshapecode/shepherd/pull/2703) Bump eslint-plugin-jest from 27.9.0 to 28.2.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2725](https://github.com/shipshapecode/shepherd/pull/2725) App: ✨ Add intro tour to admin portal ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `shepherd.js`, `unit-tests`\n  * [#2765](https://github.com/shipshapecode/shepherd/pull/2765) Revert CI changes ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* `landing`\n  * [#2736](https://github.com/shipshapecode/shepherd/pull/2736) Blog: 🐛 Add sharp for pnpm based md image processing ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2734](https://github.com/shipshapecode/shepherd/pull/2734) Blog: 📝 Add alpha launch blog post ([@chuckcarpenter](https://github.com/chuckcarpenter))\n  * [#2687](https://github.com/shipshapecode/shepherd/pull/2687) Bump @astrojs/check from 0.5.9 to 0.5.10 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2698](https://github.com/shipshapecode/shepherd/pull/2698) Bump @astrojs/sitemap from 3.1.1 to 3.1.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2719](https://github.com/shipshapecode/shepherd/pull/2719) Bump astro from 4.5.12 to 4.6.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2715](https://github.com/shipshapecode/shepherd/pull/2715) Landing: 💬 Add codepen as OSS user ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* `landing`, `react-shepherd`, `shepherd.js`, `cypress-tests`, `unit-tests`\n  * [#2721](https://github.com/shipshapecode/shepherd/pull/2721) Bump typescript from 5.4.2 to 5.4.5 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 3\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Matt Althauser ([@malthauser](https://github.com/malthauser))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## v12.0.0-alpha.13 (2024-04-05)\n\n#### :rocket: Enhancement\n* [#2684](https://github.com/shipshapecode/shepherd/pull/2684) Use IndexedDB to store tour data ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* `react`\n  * [#2690](https://github.com/shipshapecode/shepherd/pull/2690) Bump vite from 5.1.7 to 5.2.8 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2675](https://github.com/shipshapecode/shepherd/pull/2675) Bump happy-dom from 12.10.3 to 14.3.9 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2685](https://github.com/shipshapecode/shepherd/pull/2685) Bump vite from 5.1.4 to 5.1.7 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* Other\n  * [#2694](https://github.com/shipshapecode/shepherd/pull/2694) Bump cypress from 13.7.1 to 13.7.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2692](https://github.com/shipshapecode/shepherd/pull/2692) Bump @babel/core from 7.24.3 to 7.24.4 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2693](https://github.com/shipshapecode/shepherd/pull/2693) Bump @astrojs/mdx from 2.2.2 to 2.2.4 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2688](https://github.com/shipshapecode/shepherd/pull/2688) Bump @typescript-eslint/eslint-plugin from 7.4.0 to 7.5.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2686](https://github.com/shipshapecode/shepherd/pull/2686) Add tests for `Shepherd.isTourEnabled` ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n  * [#2678](https://github.com/shipshapecode/shepherd/pull/2678) Bump astro from 4.5.9 to 4.5.12 ([@dependabot[bot]](https://github.com/apps/dependabot))\n  * [#2676](https://github.com/shipshapecode/shepherd/pull/2676) Bump @tailwindcss/typography from 0.5.10 to 0.5.12 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.12 (2024-04-02)\n\n#### :boom: Breaking Change\n* [#2683](https://github.com/shipshapecode/shepherd/pull/2683) Update to Svelte 4, run ESM in tests ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#2679](https://github.com/shipshapecode/shepherd/pull/2679) Bump @astrojs/mdx from 2.2.1 to 2.2.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2681](https://github.com/shipshapecode/shepherd/pull/2681) Bump @babel/preset-typescript from 7.23.3 to 7.24.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2680](https://github.com/shipshapecode/shepherd/pull/2680) Bump rollup from 4.13.0 to 4.13.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2677](https://github.com/shipshapecode/shepherd/pull/2677) Bump tailwindcss from 3.4.1 to 3.4.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.11 (2024-04-01)\n\n#### :bug: Bug Fix\n* [#2682](https://github.com/shipshapecode/shepherd/pull/2682) Simplify rollup config ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.10 (2024-04-01)\n\n#### :house: Internal\n* [#2670](https://github.com/shipshapecode/shepherd/pull/2670) Remove NoOp type usage ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.9 (2024-04-01)\n\n#### :rocket: Enhancement\n* [#2669](https://github.com/shipshapecode/shepherd/pull/2669) Ship both cjs and esm ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :memo: Documentation\n* [#2668](https://github.com/shipshapecode/shepherd/pull/2668) ✨ Add dynamic button with stars count from github ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.8 (2024-03-29)\n\n#### :rocket: Enhancement\n* `react`\n  * [#2649](https://github.com/shipshapecode/shepherd/pull/2649) ✨ Add initial React package from SDK ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* Other\n  * [#2667](https://github.com/shipshapecode/shepherd/pull/2667) Move `properties` under the `data` object ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :bug: Bug Fix\n* [#2665](https://github.com/shipshapecode/shepherd/pull/2665) Add async/await for ShepherdPro init ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.7 (2024-03-28)\n\n#### :rocket: Enhancement\n* [#2664](https://github.com/shipshapecode/shepherd/pull/2664) Add extra properties bucket to send to Shepherd Pro ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2648](https://github.com/shipshapecode/shepherd/pull/2648) ✨ Add pro init and explicit ID ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :bug: Bug Fix\n* [#2659](https://github.com/shipshapecode/shepherd/pull/2659) 🐛 Update user ID ref to be direct from localstorage ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* [#2662](https://github.com/shipshapecode/shepherd/pull/2662) Document release process ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#2663](https://github.com/shipshapecode/shepherd/pull/2663) Update linting and prettier ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2656](https://github.com/shipshapecode/shepherd/pull/2656) Bump postcss from 8.4.37 to 8.4.38 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2653](https://github.com/shipshapecode/shepherd/pull/2653) Bump @babel/core from 7.24.0 to 7.24.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2661](https://github.com/shipshapecode/shepherd/pull/2661) Bump cssnano from 6.1.0 to 6.1.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2658](https://github.com/shipshapecode/shepherd/pull/2658) Bump release-plan from 0.8.0 to 0.9.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2650](https://github.com/shipshapecode/shepherd/pull/2650) Bump autoprefixer from 10.4.17 to 10.4.19 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2652](https://github.com/shipshapecode/shepherd/pull/2652) Bump cypress from 13.7.0 to 13.7.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2657](https://github.com/shipshapecode/shepherd/pull/2657) Bump @babel/preset-env from 7.24.0 to 7.24.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2654](https://github.com/shipshapecode/shepherd/pull/2654) Bump astro from 4.5.6 to 4.5.9 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2655](https://github.com/shipshapecode/shepherd/pull/2655) Bump @astrojs/mdx from 2.2.0 to 2.2.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2627](https://github.com/shipshapecode/shepherd/pull/2627) Bump cssnano from 6.0.5 to 6.1.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2629](https://github.com/shipshapecode/shepherd/pull/2629) Bump @astrojs/mdx from 2.1.1 to 2.2.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2634](https://github.com/shipshapecode/shepherd/pull/2634) Bump rollup-plugin-svelte from 7.1.6 to 7.2.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.6 (2024-03-20)\n\n#### :memo: Documentation\n* [#2647](https://github.com/shipshapecode/shepherd/pull/2647) Remove webcomponents polyfill ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#2635](https://github.com/shipshapecode/shepherd/pull/2635) Bump rollup from 4.12.0 to 4.13.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.5 (2024-03-20)\n\n#### :memo: Documentation\n* [#2646](https://github.com/shipshapecode/shepherd/pull/2646) Fix docs build ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#2637](https://github.com/shipshapecode/shepherd/pull/2637) Bump @astrojs/check from 0.3.4 to 0.5.9 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2644](https://github.com/shipshapecode/shepherd/pull/2644) Bump postcss from 8.4.35 to 8.4.37 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2636](https://github.com/shipshapecode/shepherd/pull/2636) Bump cypress from 13.6.6 to 13.7.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.4 (2024-03-19)\n\n#### :bug: Bug Fix\n* [#2640](https://github.com/shipshapecode/shepherd/pull/2640) 🐛 Fix issue with full steps being circular dependency ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* [#2613](https://github.com/shipshapecode/shepherd/pull/2613) Add TS support for JSDoc ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#2642](https://github.com/shipshapecode/shepherd/pull/2642) Bump astro from 4.4.15 to 4.5.6 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.3 (2024-03-12)\n\n#### :rocket: Enhancement\n* [#2631](https://github.com/shipshapecode/shepherd/pull/2631) Add EventOptions interface, tweak data format ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2632](https://github.com/shipshapecode/shepherd/pull/2632) Move Step and Tour assignment ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#2630](https://github.com/shipshapecode/shepherd/pull/2630) Bump rollup-plugin-license from 3.2.0 to 3.3.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2628](https://github.com/shipshapecode/shepherd/pull/2628) Bump typescript from 5.3.3 to 5.4.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2625](https://github.com/shipshapecode/shepherd/pull/2625) Bump astro from 4.4.8 to 4.4.15 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-alpha.2 (2024-03-08)\n\n#### :boom: Breaking Change\n* [#2626](https://github.com/shipshapecode/shepherd/pull/2626) Convert to ESM ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## v12.0.0-1 (2024-03-08)\n\n## v12.0.0-0 (2024-03-08)\n\n#### :boom: Breaking Change\n* [#2610](https://github.com/shipshapecode/shepherd/pull/2610) Move files from src/js to src, convert to TS ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2572](https://github.com/shipshapecode/shepherd/pull/2572) Drop support for node < 18 ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n#### :rocket: Enhancement\n* [#2620](https://github.com/shipshapecode/shepherd/pull/2620) ✨ Add Pro events sharing ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2562](https://github.com/shipshapecode/shepherd/pull/2562) Related to #2399, also stop keydown default behavior when navigation is enabled ([@karendolan](https://github.com/karendolan))\n\n#### :bug: Bug Fix\n* [#2551](https://github.com/shipshapecode/shepherd/pull/2551) fix: handle target elements within an iframe ([@rafiazman](https://github.com/rafiazman))\n\n#### :memo: Documentation\n* [#2604](https://github.com/shipshapecode/shepherd/pull/2604) 🎨 Add note in docs about importing styles ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2603](https://github.com/shipshapecode/shepherd/pull/2603) 📝 Add blog entry for Feb 2023 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2582](https://github.com/shipshapecode/shepherd/pull/2582) 📝 Add blog post on Redwood.js ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2563](https://github.com/shipshapecode/shepherd/pull/2563) 🎨 Add blog layout and styling, plus first post! ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2557](https://github.com/shipshapecode/shepherd/pull/2557) 🔥 Remove extra options ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2556](https://github.com/shipshapecode/shepherd/pull/2556) ✨ Add new pricing page with options and contact link ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2549](https://github.com/shipshapecode/shepherd/pull/2549) 🚀 Add Astro and convert landing site to use framework  ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2508](https://github.com/shipshapecode/shepherd/pull/2508) Added complete method on usage doc ([@abhayvershwal](https://github.com/abhayvershwal))\n\n#### :house: Internal\n* [#2624](https://github.com/shipshapecode/shepherd/pull/2624) Split library and tests into their own workspaces ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2621](https://github.com/shipshapecode/shepherd/pull/2621) Add release-plan ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2615](https://github.com/shipshapecode/shepherd/pull/2615) Adjust exports and rollup config ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2616](https://github.com/shipshapecode/shepherd/pull/2616) Update rollup packages ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2608](https://github.com/shipshapecode/shepherd/pull/2608) Fix cypress tests ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2601](https://github.com/shipshapecode/shepherd/pull/2601) 👷‍ Add typescript with minimal setup ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2605](https://github.com/shipshapecode/shepherd/pull/2605) 📝 Remove `polyfill.io` ([@SukkaW](https://github.com/SukkaW))\n* [#2607](https://github.com/shipshapecode/shepherd/pull/2607) Switch from yarn to pnpm, initial monorepo setup ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2598](https://github.com/shipshapecode/shepherd/pull/2598) 👷‍ Add remaining yarn 4 files ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2594](https://github.com/shipshapecode/shepherd/pull/2594) ⬆  Upgrade to Yarn v4 ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2574](https://github.com/shipshapecode/shepherd/pull/2574) Bump deps, yarn upgrade ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2573](https://github.com/shipshapecode/shepherd/pull/2573) Update some actions versions ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2570](https://github.com/shipshapecode/shepherd/pull/2570) Update to release-it 16 ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n* [#2558](https://github.com/shipshapecode/shepherd/pull/2558) 📈 Add analytics and remove carbon ads ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#2545](https://github.com/shipshapecode/shepherd/pull/2545) Bump prettier from 3.1.0 to 3.1.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2544](https://github.com/shipshapecode/shepherd/pull/2544) Bump cypress from 13.6.0 to 13.6.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2543](https://github.com/shipshapecode/shepherd/pull/2543) Bump rollup-plugin-visualizer from 5.10.0 to 5.11.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2542](https://github.com/shipshapecode/shepherd/pull/2542) Bump @babel/preset-env from 7.23.3 to 7.23.5 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2541](https://github.com/shipshapecode/shepherd/pull/2541) Bump tailwindcss from 3.3.5 to 3.3.6 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2540](https://github.com/shipshapecode/shepherd/pull/2540) Bump @babel/core from 7.23.3 to 7.23.5 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2537](https://github.com/shipshapecode/shepherd/pull/2537) Bump postcss from 8.4.31 to 8.4.32 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2536](https://github.com/shipshapecode/shepherd/pull/2536) Bump eslint from 8.54.0 to 8.55.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2535](https://github.com/shipshapecode/shepherd/pull/2535) Bump rollup-plugin-visualizer from 5.9.3 to 5.10.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2534](https://github.com/shipshapecode/shepherd/pull/2534) Bump eslint-config-prettier from 9.0.0 to 9.1.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2532](https://github.com/shipshapecode/shepherd/pull/2532) Bump @adobe/css-tools from 4.3.1 to 4.3.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2531](https://github.com/shipshapecode/shepherd/pull/2531) Bump rollup-plugin-visualizer from 5.9.2 to 5.9.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2530](https://github.com/shipshapecode/shepherd/pull/2530) Bump svelte-preprocess from 5.1.0 to 5.1.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2529](https://github.com/shipshapecode/shepherd/pull/2529) Bump cypress from 13.5.1 to 13.6.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2528](https://github.com/shipshapecode/shepherd/pull/2528) Bump eslint from 8.53.0 to 8.54.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2527](https://github.com/shipshapecode/shepherd/pull/2527) Bump cypress from 13.5.0 to 13.5.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2526](https://github.com/shipshapecode/shepherd/pull/2526) Bump start-server-and-test from 2.0.2 to 2.0.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2525](https://github.com/shipshapecode/shepherd/pull/2525) Bump svelte-preprocess from 5.0.4 to 5.1.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2524](https://github.com/shipshapecode/shepherd/pull/2524) Bump @babel/core from 7.23.2 to 7.23.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2523](https://github.com/shipshapecode/shepherd/pull/2523) Bump prettier from 3.0.3 to 3.1.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2522](https://github.com/shipshapecode/shepherd/pull/2522) Bump cypress from 13.4.0 to 13.5.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2521](https://github.com/shipshapecode/shepherd/pull/2521) Bump @babel/preset-env from 7.23.2 to 7.23.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2518](https://github.com/shipshapecode/shepherd/pull/2518) Bump start-server-and-test from 2.0.1 to 2.0.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2519](https://github.com/shipshapecode/shepherd/pull/2519) Bump eslint from 8.52.0 to 8.53.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2517](https://github.com/shipshapecode/shepherd/pull/2517) Bump cypress from 13.3.3 to 13.4.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2515](https://github.com/shipshapecode/shepherd/pull/2515) Bump tailwindcss from 3.3.3 to 3.3.5 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2514](https://github.com/shipshapecode/shepherd/pull/2514) Bump eslint-plugin-jest from 27.4.3 to 27.6.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2513](https://github.com/shipshapecode/shepherd/pull/2513) Bump cypress from 13.3.2 to 13.3.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2510](https://github.com/shipshapecode/shepherd/pull/2510) Bump eslint-plugin-jest from 27.4.2 to 27.4.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2511](https://github.com/shipshapecode/shepherd/pull/2511) Bump cypress from 13.3.1 to 13.3.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2509](https://github.com/shipshapecode/shepherd/pull/2509) Bump eslint from 8.51.0 to 8.52.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2506](https://github.com/shipshapecode/shepherd/pull/2506) Bump @babel/preset-env from 7.22.20 to 7.23.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2504](https://github.com/shipshapecode/shepherd/pull/2504) Bump rollup-plugin-license from 3.1.0 to 3.2.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2502](https://github.com/shipshapecode/shepherd/pull/2502) Bump cypress from 13.3.0 to 13.3.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2503](https://github.com/shipshapecode/shepherd/pull/2503) Bump eslint-plugin-prettier from 5.0.0 to 5.0.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2501](https://github.com/shipshapecode/shepherd/pull/2501) Bump @babel/core from 7.23.0 to 7.23.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2497](https://github.com/shipshapecode/shepherd/pull/2497) Bump eslint from 8.50.0 to 8.51.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2494](https://github.com/shipshapecode/shepherd/pull/2494) Bump rimraf from 5.0.1 to 5.0.5 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2493](https://github.com/shipshapecode/shepherd/pull/2493) Bump glob from 10.3.7 to 10.3.10 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2492](https://github.com/shipshapecode/shepherd/pull/2492) Bump cypress from 13.1.0 to 13.3.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2491](https://github.com/shipshapecode/shepherd/pull/2491) Bump eslint from 8.49.0 to 8.50.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2489](https://github.com/shipshapecode/shepherd/pull/2489) Bump eslint-plugin-jest from 27.2.3 to 27.4.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2490](https://github.com/shipshapecode/shepherd/pull/2490) Bump postcss from 8.4.30 to 8.4.31 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2488](https://github.com/shipshapecode/shepherd/pull/2488) Bump chai from 4.3.8 to 4.3.10 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2486](https://github.com/shipshapecode/shepherd/pull/2486) Bump get-func-name from 2.0.0 to 2.0.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2480](https://github.com/shipshapecode/shepherd/pull/2480) Bump glob from 10.3.4 to 10.3.7 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2484](https://github.com/shipshapecode/shepherd/pull/2484) Bump @babel/core from 7.22.20 to 7.23.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2479](https://github.com/shipshapecode/shepherd/pull/2479) Bump start-server-and-test from 2.0.0 to 2.0.1 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2483](https://github.com/shipshapecode/shepherd/pull/2483) Bump autoprefixer from 10.4.15 to 10.4.16 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2482](https://github.com/shipshapecode/shepherd/pull/2482) Bump postcss from 8.4.29 to 8.4.30 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2481](https://github.com/shipshapecode/shepherd/pull/2481) Bump babel-jest from 29.6.4 to 29.7.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2476](https://github.com/shipshapecode/shepherd/pull/2476) Bump jest-environment-jsdom from 29.6.4 to 29.7.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2477](https://github.com/shipshapecode/shepherd/pull/2477) Bump @babel/core from 7.22.17 to 7.22.20 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2475](https://github.com/shipshapecode/shepherd/pull/2475) Bump jest from 29.6.4 to 29.7.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2473](https://github.com/shipshapecode/shepherd/pull/2473) Bump @floating-ui/dom from 1.5.2 to 1.5.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2474](https://github.com/shipshapecode/shepherd/pull/2474) Bump @babel/preset-env from 7.22.15 to 7.22.20 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2467](https://github.com/shipshapecode/shepherd/pull/2467) Bump @floating-ui/dom from 1.5.1 to 1.5.2 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2464](https://github.com/shipshapecode/shepherd/pull/2464) Bump @babel/core from 7.22.11 to 7.22.17 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2468](https://github.com/shipshapecode/shepherd/pull/2468) Bump @babel/preset-env from 7.22.14 to 7.22.15 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2465](https://github.com/shipshapecode/shepherd/pull/2465) Bump prettier from 3.0.2 to 3.0.3 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2466](https://github.com/shipshapecode/shepherd/pull/2466) Bump eslint from 8.48.0 to 8.49.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2462](https://github.com/shipshapecode/shepherd/pull/2462) Bump del from 7.0.0 to 7.1.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2463](https://github.com/shipshapecode/shepherd/pull/2463) Bump postcss from 8.4.28 to 8.4.29 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2461](https://github.com/shipshapecode/shepherd/pull/2461) Bump cypress from 12.17.4 to 13.1.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2460](https://github.com/shipshapecode/shepherd/pull/2460) Bump glob from 10.3.3 to 10.3.4 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2459](https://github.com/shipshapecode/shepherd/pull/2459) Bump @babel/preset-env from 7.22.10 to 7.22.14 ([@dependabot[bot]](https://github.com/apps/dependabot))\n* [#2458](https://github.com/shipshapecode/shepherd/pull/2458) Bump rollup-plugin-license from 3.0.1 to 3.1.0 ([@dependabot[bot]](https://github.com/apps/dependabot))\n\n#### Committers: 6\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Karen Dolan ([@karendolan](https://github.com/karendolan))\n- Rafi ([@rafiazman](https://github.com/rafiazman))\n- Robbie Wagner ([@RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Sukka ([@SukkaW](https://github.com/SukkaW))\n- [@abhayvershwal](https://github.com/abhayvershwal)\n\n## v11.2.0 (2023-09-02)\n\n#### :rocket: Enhancement\n* [#2399](https://github.com/shipshapecode/shepherd/pull/2399) Prevent ESC, KEY_RIGHT, KEY_LEFT propagation when keyboardNav is enabled ([@karendolan](https://github.com/karendolan))\n\n#### Committers: 1\n- Karen Dolan ([@karendolan](https://github.com/karendolan))\n\n## v11.1.1 (2023-04-03)\n\n## v11.1.0 (2023-04-03)\n\n#### :rocket: Enhancement\n* [#2168](https://github.com/shipshapecode/shepherd/pull/2168) add funtion support for confirmCancel ([@taozhiyu](https://github.com/taozhiyu))\n\n#### :bug: Bug Fix\n* [#2204](https://github.com/shipshapecode/shepherd/pull/2204) Bugfix: prevent to show spurious warnings in dev panel console ([@SamyCookie](https://github.com/SamyCookie))\n\n#### :memo: Documentation\n* [#2251](https://github.com/shipshapecode/shepherd/pull/2251) Use a valid event on code example ([@didaquis](https://github.com/didaquis))\n* [#2224](https://github.com/shipshapecode/shepherd/pull/2224) Remove mention to Popper on docs ([@didaquis](https://github.com/didaquis))\n* [#2205](https://github.com/shipshapecode/shepherd/pull/2205) Fix the typo in docs ([@de-don](https://github.com/de-don))\n* [#2174](https://github.com/shipshapecode/shepherd/pull/2174) Adding an example use case of shepherd to Read Me ([@JayP718](https://github.com/JayP718))\n\n#### Committers: 5\n- Denis ([@de-don](https://github.com/de-don))\n- Dídac García ([@didaquis](https://github.com/didaquis))\n- [@JayP718](https://github.com/JayP718)\n- [@SamyCookie](https://github.com/SamyCookie)\n- 涛之雨 ([@taozhiyu](https://github.com/taozhiyu))\n\n## v11.0.1 (2022-12-12)\n\n#### :bug: Bug Fix\n* [#2183](https://github.com/shipshapecode/shepherd/pull/2183) Fix centering steps with no attachTo.on ([@rwwagner90](https://github.com/RobbieTheWagner))\n* [#2182](https://github.com/shipshapecode/shepherd/pull/2182) Fix arrow offset, add back flipping behavior ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n## v11.0.0 (2022-11-21)\n\n#### :boom: Breaking Change\n* [#2037](https://github.com/shipshapecode/shepherd/pull/2037) Replace popperJS with Floating UI ([@theodoreb](https://github.com/theodoreb))\n\n#### :rocket: Enhancement\n* [#2137](https://github.com/shipshapecode/shepherd/pull/2137) Exporting StepOptionsButton type to be able to add tour steps buttons dynamically with type checking ([@xhafan](https://github.com/xhafan))\n* [#2116](https://github.com/shipshapecode/shepherd/pull/2116) feat: add ability to specify corner radii ([@simoneb](https://github.com/simoneb))\n\n#### :bug: Bug Fix\n* [#2068](https://github.com/shipshapecode/shepherd/pull/2068) Do nothing when running server side ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :memo: Documentation\n* [#2129](https://github.com/shipshapecode/shepherd/pull/2129) Replace references to popperjs ([@theodoreb](https://github.com/theodoreb))\n* [#2022](https://github.com/shipshapecode/shepherd/pull/2022) remove all mentions of data-shepherd-active-tour ([@EmNicholson93](https://github.com/EmNicholson93))\n\n#### :house: Internal\n* [#2157](https://github.com/shipshapecode/shepherd/pull/2157) Remove firefox tests ([@rwwagner90](https://github.com/RobbieTheWagner))\n* [#2047](https://github.com/shipshapecode/shepherd/pull/2047) chore: make yarn lint:js pass ([@theodoreb](https://github.com/theodoreb))\n* [#2046](https://github.com/shipshapecode/shepherd/pull/2046) Fix calls to setTimeout in tests ([@theodoreb](https://github.com/theodoreb))\n\n#### Committers: 6\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Eli Nicholson ([@EmNicholson93](https://github.com/EmNicholson93))\n- Martin Havlišta ([@xhafan](https://github.com/xhafan))\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n- Simone Busoli ([@simoneb](https://github.com/simoneb))\n- Théodore Biadala ([@theodoreb](https://github.com/theodoreb))\n\n## v10.0.1 (2022-08-01)\n\n#### :bug: Bug Fix\n* [#1997](https://github.com/shipshapecode/shepherd/pull/1997) Fix for smooth scrolling ([@hrypkema-amplify](https://github.com/hrypkema-amplify))\n\n#### Committers: 1\n- Henrik Rypkema ([@hrypkema-amplify](https://github.com/hrypkema-amplify))\n\n## v10.0.0 (2022-06-07)\n\n#### :boom: Breaking Change\n* [#1930](https://github.com/shipshapecode/shepherd/pull/1930) Implement lazy evaluation of attachTo.element ([@monshan](https://github.com/monshan))\n\n#### :bug: Bug Fix\n* [#1942](https://github.com/shipshapecode/shepherd/pull/1942) Fix chrome opacity bug ([@monshan](https://github.com/monshan))\n\n#### Committers: 1\n- Marika Shanahan ([@monshan](https://github.com/monshan))\n\n## v9.1.1 (2022-05-26)\n\n#### :bug: Bug Fix\n* [#1931](https://github.com/shipshapecode/shepherd/pull/1931) fixed showOn incorrectly skipping an index ([@liam-jones-lucout](https://github.com/liam-jones-lucout))\n\n#### :house: Internal\n* [#1920](https://github.com/shipshapecode/shepherd/pull/1920) Cleanup jest comments, update yarn.lock ([@monshan](https://github.com/monshan))\n* [#1919](https://github.com/shipshapecode/shepherd/pull/1919) Write jest-environment-jsdom into package.json file ([@monshan](https://github.com/monshan))\n\n#### Committers: 2\n- Marika Shanahan ([@monshan](https://github.com/monshan))\n- [@liam-jones-lucout](https://github.com/liam-jones-lucout)\n\n## v9.1.0 (2022-04-09)\n\n#### :rocket: Enhancement\n* [#1815](https://github.com/shipshapecode/shepherd/pull/1815) Add dynamic text and label properties for buttons ([@radibit](https://github.com/radibit))\n\n#### Committers: 1\n- Radimir Bitsov ([@radibit](https://github.com/radibit))\n\n## v9.0.0 (2022-01-11)\n\n#### :boom: Breaking Change\n* [#1682](https://github.com/shipshapecode/shepherd/pull/1682) Drop node 10 support ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### :rocket: Enhancement\n* [#1758](https://github.com/shipshapecode/shepherd/pull/1758) Fix type signature for `Evented.off()` ([@ulken](https://github.com/ulken))\n\n#### :bug: Bug Fix\n* [#1544](https://github.com/shipshapecode/shepherd/pull/1544) 🐛 Add check to remove class if canClickTarget is true ([@chuckcarpenter](https://github.com/chuckcarpenter))\n* [#1479](https://github.com/shipshapecode/shepherd/pull/1479) Fix issue #1353 : Complete the tour when skipStep is the lastStep ([@thomasguittonneau](https://github.com/thomasguittonneau))\n\n#### :memo: Documentation\n* [#1513](https://github.com/shipshapecode/shepherd/pull/1513) Add `useModalOverlay` to example ([@rodrigoaraujolima92trulogic](https://github.com/rodrigoaraujolima92trulogic))\n* [#1651](https://github.com/shipshapecode/shepherd/pull/1651) Adds Drupal to the list of Projects Using Shepherd ([@thejimbirch](https://github.com/thejimbirch))\n* [#1632](https://github.com/shipshapecode/shepherd/pull/1632) I faced a problem while was trying to install shepherdjs ([@loldalolwerollnroll](https://github.com/loldalolwerollnroll))\n* [#1623](https://github.com/shipshapecode/shepherd/pull/1623) Add another progress indicator cookbook example ([@aripddev](https://github.com/aripddev))\n\n#### :house: Internal\n* [#1520](https://github.com/shipshapecode/shepherd/pull/1520) Update config for tailwind 2 ([@rwwagner90](https://github.com/RobbieTheWagner))\n* [#1462](https://github.com/shipshapecode/shepherd/pull/1462) Add automerge back to dependabot ([@rwwagner90](https://github.com/RobbieTheWagner))\n* [#1447](https://github.com/shipshapecode/shepherd/pull/1447) Add catalog-info.yaml config file ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 8\n- Aleksey Baranov ([@loldalolwerollnroll](https://github.com/loldalolwerollnroll))\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Jim Birch ([@thejimbirch](https://github.com/thejimbirch))\n- Oskar Löfgren ([@ulken](https://github.com/ulken))\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n- Rodrigo Lima ([@rodrigoaraujolima92trulogic](https://github.com/rodrigoaraujolima92trulogic))\n- [@thomasguittonneau](https://github.com/thomasguittonneau)\n- aripddev ([@aripddev](https://github.com/aripddev))\n\n## v8.3.1 (2021-05-07)\n\n#### :bug: Bug Fix\n* [#1449](https://github.com/shipshapecode/shepherd/pull/1449) 🐛 Add preventOverflow option for tether to false ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 2\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- [@dependabot-preview[bot]](https://github.com/apps/dependabot-preview)\n\n## v8.3.0 (2021-04-06)\n\n#### :house: Internal\n* [#1402](https://github.com/shipshapecode/shepherd/pull/1402) Update rollup-plugin-postcss ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### Committers: 2\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n- [@dependabot-preview[bot]](https://github.com/apps/dependabot-preview)\n\n## v8.2.3 (2021-03-25)\n\n#### :house: Internal\n* [#1379](https://github.com/shipshapecode/shepherd/pull/1379) Update npmignore, add assets to release ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### Committers: 1\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n## v8.2.1 (2021-03-24)\n\n#### :house: Internal\n* [#1354](https://github.com/shipshapecode/shepherd/pull/1354) 👷 Add github token to action ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 1\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## v8.2.0 (2021-03-03)\n\n#### :rocket: Enhancement\n* [#1189](https://github.com/shipshapecode/shepherd/pull/1189) Remove `shepherd-target-click-disabled` class on step hide ([@zefj](https://github.com/zefj))\n\n#### :bug: Bug Fix\n* [#1332](https://github.com/shipshapecode/shepherd/pull/1332) properly handle centered modal ([@xiwcx](https://github.com/xiwcx))\n\n#### :memo: Documentation\n* [#1214](https://github.com/shipshapecode/shepherd/pull/1214) Add license scan report and status ([@fossabot](https://github.com/fossabot))\n* [#1199](https://github.com/shipshapecode/shepherd/pull/1199) Add snapsure to Websites and Apps list in README.md ([@kkoppenhaver](https://github.com/kkoppenhaver))\n\n#### :house: Internal\n* [#1351](https://github.com/shipshapecode/shepherd/pull/1351) Bump cypress, fix cancel test ([@rwwagner90](https://github.com/RobbieTheWagner))\n* [#1316](https://github.com/shipshapecode/shepherd/pull/1316) Remove browsersync, add rollup-serve ([@xiwcx](https://github.com/xiwcx))\n* [#1262](https://github.com/shipshapecode/shepherd/pull/1262) 👷 Move CI/CD to actions ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 7\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Filip Rec ([@zefj](https://github.com/zefj))\n- Keanan Koppenhaver ([@kkoppenhaver](https://github.com/kkoppenhaver))\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n- [@dependabot-preview[bot]](https://github.com/apps/dependabot-preview)\n- fossabot ([@fossabot](https://github.com/fossabot))\n- i. welch canavan ([@xiwcx](https://github.com/xiwcx))\n\n## v8.1.0 (2020-10-05)\n\n#### :rocket: Enhancement\n* [#1176](https://github.com/shipshapecode/shepherd/pull/1176) Add `stepsContainer` option, allowing users to specify rendering target for step elements ([@zefj](https://github.com/zefj))\n* [#1074](https://github.com/shipshapecode/shepherd/pull/1074) Add missing types for Step.options and Tour.steps ([@anakorn](https://github.com/anakorn))\n\n#### :bug: Bug Fix\n* [#1132](https://github.com/shipshapecode/shepherd/pull/1132) Added default fallback for target when step is hidden/destroyed ([@IWMTom](https://github.com/IWMTom))\n* [#1119](https://github.com/shipshapecode/shepherd/pull/1119) shift + tab handled ([@faizanu94](https://github.com/faizanu94))\n\n#### :memo: Documentation\n* [#1133](https://github.com/shipshapecode/shepherd/pull/1133) docs: Fix simple typo, unminifed -> unminified ([@timgates42](https://github.com/timgates42))\n* [#1098](https://github.com/shipshapecode/shepherd/pull/1098) Update demo image ([@shepmaster](https://github.com/shepmaster))\n* [#1086](https://github.com/shipshapecode/shepherd/pull/1086) Add multiple events example to docs ([@ricobonfim](https://github.com/ricobonfim))\n\n#### :house: Internal\n* [#1044](https://github.com/shipshapecode/shepherd/pull/1044) add Step.id to typings, fix tour.getById() typing ([@cyremur](https://github.com/cyremur))\n\n#### Committers: 9\n- Alex Nakorn ([@anakorn](https://github.com/anakorn))\n- Filip Rec ([@zefj](https://github.com/zefj))\n- Jake Goulding ([@shepmaster](https://github.com/shepmaster))\n- Muhammad Faizan Uddin ([@faizanu94](https://github.com/faizanu94))\n- Ricardo Bonfim ([@ricobonfim](https://github.com/ricobonfim))\n- Tim Gates ([@timgates42](https://github.com/timgates42))\n- Tom Wilson ([@IWMTom](https://github.com/IWMTom))\n- [@cyremur](https://github.com/cyremur)\n- [@dependabot-preview[bot]](https://github.com/apps/dependabot-preview)\n\n## v8.0.2 (2020-07-10)\n\n#### :rocket: Enhancement\n* [#1026](https://github.com/shipshapecode/shepherd/pull/1026) Add Edge 18 to browserslist ([@te1](https://github.com/te1))\n* [#996](https://github.com/shipshapecode/shepherd/pull/996) Step Element Target Action ([@WORMSS](https://github.com/WORMSS))\n* [#995](https://github.com/shipshapecode/shepherd/pull/995) Added the correct this context to StepOption 'when' functions ([@WORMSS](https://github.com/WORMSS))\n\n#### :bug: Bug Fix\n* [#1039](https://github.com/shipshapecode/shepherd/pull/1039) Use isElement fot svg scrollIntoView support ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### :house: Internal\n* [#1040](https://github.com/shipshapecode/shepherd/pull/1040) Add secondary property on StepOptionsButton ([@linsolas](https://github.com/linsolas))\n* [#1006](https://github.com/shipshapecode/shepherd/pull/1006) Switch to svelte-jester, test with node 12 ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### Committers: 5\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n- Romain Linsolas ([@linsolas](https://github.com/linsolas))\n- WORMSS ([@WORMSS](https://github.com/WORMSS))\n- [@dependabot-preview[bot]](https://github.com/apps/dependabot-preview)\n- te ([@te1](https://github.com/te1))\n\n## v8.0.1 (2020-05-30)\n\n## v8.0.0 (2020-05-25)\n\n#### :boom: Breaking Change\n* [#982](https://github.com/shipshapecode/shepherd/pull/982) Officially drop IE 11 and remove from browserslist ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### :bug: Bug Fix\n* [#979](https://github.com/shipshapecode/shepherd/pull/979) Require attachTo.on to show arrow ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### :memo: Documentation\n* [#967](https://github.com/shipshapecode/shepherd/pull/967) 📝 Add cookbook item for multi item highlighting ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### :house: Internal\n* [#981](https://github.com/shipshapecode/shepherd/pull/981) Remove eslint from rollup, tweak tailwind ([@rwwagner90](https://github.com/RobbieTheWagner))\n\n#### Committers: 3\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Robert Wagner ([@rwwagner90](https://github.com/RobbieTheWagner))\n- [@dependabot-preview[bot]](https://github.com/apps/dependabot-preview)\n\n# Changelog\n\n## [v7.0.2](https://github.com/shipshapecode/shepherd/tree/v7.0.2) (2020-02-25)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v7.0.1...v7.0.2)\n\n**Fixed bugs:**\n\n- Fix bug when modifiers was not defined [\\#811](https://github.com/shipshapecode/shepherd/pull/811) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- Installing v7.0.0 fails  [\\#810](https://github.com/shipshapecode/shepherd/issues/810)\n\n## [v7.0.1](https://github.com/shipshapecode/shepherd/tree/v7.0.1) (2020-02-24)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v7.0.0...v7.0.1)\n\n## [v7.0.0](https://github.com/shipshapecode/shepherd/tree/v7.0.0) (2020-02-24)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v6.0.2...v7.0.0)\n\n**Breaking changes:**\n\n- \\[WIP\\] Popper v2 [\\#752](https://github.com/shipshapecode/shepherd/pull/752) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Implemented enhancements:**\n\n- Refactor back to Popper [\\#744](https://github.com/shipshapecode/shepherd/issues/744)\n\n**Fixed bugs:**\n\n- Smooth scrolling not working? [\\#788](https://github.com/shipshapecode/shepherd/issues/788)\n- Overlay does not resize [\\#751](https://github.com/shipshapecode/shepherd/issues/751)\n- 🐛 Fix initial scroll to top before scrolling to target [\\#801](https://github.com/shipshapecode/shepherd/pull/801) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n**Closed issues:**\n\n- .shepherd-arrow does not \"flip\" when scroll/resize causes a tour stop to switch sides [\\#787](https://github.com/shipshapecode/shepherd/issues/787)\n- Arrow position is incorrect for ion-fab element \\#ionic [\\#745](https://github.com/shipshapecode/shepherd/issues/745)\n- shepherd in webview  does not show buttons [\\#721](https://github.com/shipshapecode/shepherd/issues/721)\n\n**Merged pull requests:**\n\n- 🔥 Remove demo directory and use landing site as default [\\#802](https://github.com/shipshapecode/shepherd/pull/802) ([chuckcarpenter](https://github.com/chuckcarpenter))\n- 🐛 Fix step positioning for viewport [\\#797](https://github.com/shipshapecode/shepherd/pull/797) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n## [v6.0.2](https://github.com/shipshapecode/shepherd/tree/v6.0.2) (2019-11-08)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v6.0.1...v6.0.2)\n\n## [v6.0.1](https://github.com/shipshapecode/shepherd/tree/v6.0.1) (2019-11-06)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v6.0.0...v6.0.1)\n\n## [v5.0.0](https://github.com/shipshapecode/shepherd/tree/v5.0.0) (2019-08-25)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.6.0...v5.0.0)\n\n**Breaking changes:**\n\n- Remove style vendor prefixing [\\#519](https://github.com/shipshapecode/shepherd/pull/519) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- showCancelLink -\\> cancelIcon [\\#518](https://github.com/shipshapecode/shepherd/pull/518) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove link styles [\\#509](https://github.com/shipshapecode/shepherd/pull/509) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove Shepherd.Evented [\\#506](https://github.com/shipshapecode/shepherd/pull/506) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Implemented enhancements:**\n\n- Vue wrapper [\\#333](https://github.com/shipshapecode/shepherd/issues/333)\n- Add includeStyles option [\\#526](https://github.com/shipshapecode/shepherd/pull/526) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Tie modal z-index to shepherdElementZIndex [\\#523](https://github.com/shipshapecode/shepherd/pull/523) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add disableScroll to types [\\#522](https://github.com/shipshapecode/shepherd/pull/522) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Types don't support activeTour or Evented properties. [\\#504](https://github.com/shipshapecode/shepherd/issues/504)\n- Remove object-assign-deep, refactor setting popper options [\\#516](https://github.com/shipshapecode/shepherd/pull/516) ([genadis](https://github.com/genadis))\n- Use requestAnimationFrame to position modal opening [\\#514](https://github.com/shipshapecode/shepherd/pull/514) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add overlayOpacity to styleVariables options [\\#512](https://github.com/shipshapecode/shepherd/pull/512) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add keyboardNav and exitOnEsc options [\\#508](https://github.com/shipshapecode/shepherd/pull/508) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Move activeTour to namespace [\\#507](https://github.com/shipshapecode/shepherd/pull/507) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- advanceOn click doesn't work on nested elements [\\#511](https://github.com/shipshapecode/shepherd/issues/511)\n- Use currentTarget for advanceOn [\\#513](https://github.com/shipshapecode/shepherd/pull/513) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- Z-Index Issues [\\#521](https://github.com/shipshapecode/shepherd/issues/521)\n- ionic element - bubbles not pointing to right place due to clientHeight = 0 \\(etc.\\) [\\#426](https://github.com/shipshapecode/shepherd/issues/426)\n- Disable built in component styles [\\#497](https://github.com/shipshapecode/shepherd/issues/497)\n- Feature Request: I18n cancel link [\\#499](https://github.com/shipshapecode/shepherd/issues/499)\n\n**Merged pull requests:**\n\n- Update rimraf to the latest version 🚀 [\\#515](https://github.com/shipshapecode/shepherd/pull/515) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update rollup-plugin-license to the latest version 🚀 [\\#505](https://github.com/shipshapecode/shepherd/pull/505) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- adding alt and role to img element [\\#503](https://github.com/shipshapecode/shepherd/pull/503) ([MelSumner](https://github.com/MelSumner))\n- fixing a11y issue by adding lang attribute to html element [\\#501](https://github.com/shipshapecode/shepherd/pull/501) ([MelSumner](https://github.com/MelSumner))\n\n## [v4.6.0](https://github.com/shipshapecode/shepherd/tree/v4.6.0) (2019-08-09)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.5.0...v4.6.0)\n\n**Implemented enhancements:**\n\n- Wrong type definition for scrollTo [\\#490](https://github.com/shipshapecode/shepherd/issues/490)\n- Fade in modal overlay [\\#496](https://github.com/shipshapecode/shepherd/pull/496) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Fix for the wrong type definition of StepOptions.scrollTo [\\#494](https://github.com/shipshapecode/shepherd/pull/494) ([moxival](https://github.com/moxival))\n\n## [v4.5.0](https://github.com/shipshapecode/shepherd/tree/v4.5.0) (2019-08-09)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.4.1...v4.5.0)\n\n**Fixed bugs:**\n\n- Passing 'HTMLElement' to tour.addStep{ text: ... } doesn't work anymore [\\#492](https://github.com/shipshapecode/shepherd/issues/492)\n- Support passing elements for text [\\#493](https://github.com/shipshapecode/shepherd/pull/493) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v4.4.1](https://github.com/shipshapecode/shepherd/tree/v4.4.1) (2019-08-07)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.4.0...v4.4.1)\n\n**Fixed bugs:**\n\n- ShepherdClass missing after adding modifiers of popper [\\#486](https://github.com/shipshapecode/shepherd/issues/486)\n- Use objectAssignDeep to deeply merge tippyOptions [\\#488](https://github.com/shipshapecode/shepherd/pull/488) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v4.4.0](https://github.com/shipshapecode/shepherd/tree/v4.4.0) (2019-08-05)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.3.4...v4.4.0)\n\n**Implemented enhancements:**\n\n- Add addSteps method and allow passing steps to tour constructor [\\#485](https://github.com/shipshapecode/shepherd/pull/485) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- Shepherd.Tour constructor definition of steps errors with showOn being undefined [\\#114](https://github.com/shipshapecode/shepherd/issues/114)\n\n## [v4.3.4](https://github.com/shipshapecode/shepherd/tree/v4.3.4) (2019-08-04)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.3.3...v4.3.4)\n\n**Implemented enhancements:**\n\n- styleVariables missing in 'TourOptions' declaration and beforeShowStep not implemented [\\#483](https://github.com/shipshapecode/shepherd/issues/483)\n- Fix some types and docs [\\#484](https://github.com/shipshapecode/shepherd/pull/484) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v4.3.3](https://github.com/shipshapecode/shepherd/tree/v4.3.3) (2019-08-02)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.3.2...v4.3.3)\n\n**Implemented enhancements:**\n\n- Fix some TypeScript issues [\\#482](https://github.com/shipshapecode/shepherd/pull/482) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v4.3.2](https://github.com/shipshapecode/shepherd/tree/v4.3.2) (2019-08-02)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.3.1...v4.3.2)\n\n**Implemented enhancements:**\n\n- Add confirmCancel and confirmCancelMessage to types [\\#480](https://github.com/shipshapecode/shepherd/pull/480) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v4.3.1](https://github.com/shipshapecode/shepherd/tree/v4.3.1) (2019-08-02)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.3.0...v4.3.1)\n\n**Implemented enhancements:**\n\n- Closing the tour should move the focus back to the element that opened it [\\#473](https://github.com/shipshapecode/shepherd/issues/473)\n- Return focus after closing the tour [\\#479](https://github.com/shipshapecode/shepherd/pull/479) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Merged pull requests:**\n\n- Update rollup-plugin-license to the latest version 🚀 [\\#478](https://github.com/shipshapecode/shepherd/pull/478) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v4.3.0](https://github.com/shipshapecode/shepherd/tree/v4.3.0) (2019-08-01)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.2.0...v4.3.0)\n\n**Implemented enhancements:**\n\n- Add option to specify container element for the modal [\\#474](https://github.com/shipshapecode/shepherd/pull/474) ([genadis](https://github.com/genadis))\n\n**Fixed bugs:**\n\n- Fix cancel link color for when the header has dark background [\\#477](https://github.com/shipshapecode/shepherd/pull/477) ([genadis](https://github.com/genadis))\n- Fix content border radius [\\#476](https://github.com/shipshapecode/shepherd/pull/476) ([genadis](https://github.com/genadis))\n- Fix applying tippyOptions [\\#475](https://github.com/shipshapecode/shepherd/pull/475) ([genadis](https://github.com/genadis))\n\n## [v4.2.0](https://github.com/shipshapecode/shepherd/tree/v4.2.0) (2019-07-31)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.1.0...v4.2.0)\n\n**Implemented enhancements:**\n\n- Accessibility support [\\#198](https://github.com/shipshapecode/shepherd/issues/198)\n- Remove shepherdElementWidth option [\\#471](https://github.com/shipshapecode/shepherd/pull/471) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v4.1.0](https://github.com/shipshapecode/shepherd/tree/v4.1.0) (2019-07-30)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v4.0.0...v4.1.0)\n\n**Implemented enhancements:**\n\n- Make cancel link more accessible [\\#469](https://github.com/shipshapecode/shepherd/pull/469) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- switched to default export in TS typing [\\#468](https://github.com/shipshapecode/shepherd/pull/468) ([grycmat](https://github.com/grycmat))\n\n## [v4.0.0](https://github.com/shipshapecode/shepherd/tree/v4.0.0) (2019-07-29)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v3.1.0...v4.0.0)\n\n**Breaking changes:**\n\n- Switch modals from ids to classes and prefix them [\\#466](https://github.com/shipshapecode/shepherd/pull/466) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Simplify addStep API [\\#464](https://github.com/shipshapecode/shepherd/pull/464) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove predefined themes [\\#462](https://github.com/shipshapecode/shepherd/pull/462) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Switch to CSSinJS [\\#450](https://github.com/shipshapecode/shepherd/pull/450) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Use autoBind, pass context rather than manually binding [\\#440](https://github.com/shipshapecode/shepherd/pull/440) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove array support for `step.options.text` [\\#429](https://github.com/shipshapecode/shepherd/pull/429) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- .shepherd-popper -\\> .shepherd, move .shepherd-has-title [\\#422](https://github.com/shipshapecode/shepherd/pull/422) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Tippy v5 [\\#420](https://github.com/shipshapecode/shepherd/pull/420) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove remaining lodash, IE 11+ [\\#419](https://github.com/shipshapecode/shepherd/pull/419) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove the string option for `advanceOn` in favor of object [\\#418](https://github.com/shipshapecode/shepherd/pull/418) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove string option for `attachTo` in favor of object [\\#417](https://github.com/shipshapecode/shepherd/pull/417) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- ommiting 'on' doesn't work [\\#460](https://github.com/shipshapecode/shepherd/issues/460)\n- Modal mask opening shows back up on scroll [\\#444](https://github.com/shipshapecode/shepherd/issues/444)\n- IE11 support is broken [\\#437](https://github.com/shipshapecode/shepherd/issues/437)\n- Incorrect path to typings files in package.json [\\#435](https://github.com/shipshapecode/shepherd/issues/435)\n- Start fixing IE11 support [\\#438](https://github.com/shipshapecode/shepherd/pull/438) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- fix for incorrect types path in package.json [\\#434](https://github.com/shipshapecode/shepherd/pull/434) ([cmcnicholas](https://github.com/cmcnicholas))\n- Arrow navigation skips steps if you do back then next [\\#423](https://github.com/shipshapecode/shepherd/issues/423)\n- Only add keydown listeners once [\\#424](https://github.com/shipshapecode/shepherd/pull/424) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- useModalOverlay does not play well with multiple instances on the page [\\#370](https://github.com/shipshapecode/shepherd/issues/370)\n\n**Implemented enhancements:**\n\n- Make build smaller, while still supporting IE11 [\\#467](https://github.com/shipshapecode/shepherd/pull/467) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Convert to Preact components [\\#458](https://github.com/shipshapecode/shepherd/pull/458) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add first class support for secondary button [\\#457](https://github.com/shipshapecode/shepherd/pull/457) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Prefixes fixes [\\#453](https://github.com/shipshapecode/shepherd/pull/453) ([genadis](https://github.com/genadis))\n- Add prefix to data attributes [\\#452](https://github.com/shipshapecode/shepherd/pull/452) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Import ES5 bodyScrollLock, use babel-transform-runtime [\\#447](https://github.com/shipshapecode/shepherd/pull/447) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove drop util [\\#436](https://github.com/shipshapecode/shepherd/pull/436) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Cleanup public/private API [\\#430](https://github.com/shipshapecode/shepherd/pull/430) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- An in-range update of eslint-plugin-jest is breaking the build 🚨 [\\#443](https://github.com/shipshapecode/shepherd/issues/443)\n- Modal classes are not prefixed [\\#456](https://github.com/shipshapecode/shepherd/issues/456)\n- fix removing 'shepherd-modal-target' [\\#455](https://github.com/shipshapecode/shepherd/issues/455)\n- Document canClickTarget [\\#461](https://github.com/shipshapecode/shepherd/issues/461)\n\n**Merged pull requests:**\n\n- Document canClickTarget [\\#465](https://github.com/shipshapecode/shepherd/pull/465) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add index to 'show' and 'cancel' events [\\#454](https://github.com/shipshapecode/shepherd/pull/454) ([genadis](https://github.com/genadis))\n- Remove Eager [\\#451](https://github.com/shipshapecode/shepherd/pull/451) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add StackShare badge [\\#446](https://github.com/shipshapecode/shepherd/pull/446) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Transpile auto-bind [\\#441](https://github.com/shipshapecode/shepherd/pull/441) ([RobbieTheWagner](https://github.com/RobbieTheWagner)\n- Update del to the latest version 🚀 [\\#425](https://github.com/shipshapecode/shepherd/pull/425) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.1.0](https://github.com/shipshapecode/shepherd/tree/v3.1.0) (2019-06-25)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v3.0.0...v3.1.0)\n\n**Fixed bugs:**\n\n- Fix jumpy disableScroll [\\#416](https://github.com/shipshapecode/shepherd/pull/416) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Reuse existing modal overlay [\\#414](https://github.com/shipshapecode/shepherd/pull/414) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Merged pull requests:**\n\n- Update rollup-plugin-eslint to the latest version 🚀 [\\#415](https://github.com/shipshapecode/shepherd/pull/415) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.0.0](https://github.com/shipshapecode/shepherd/tree/v3.0.0) (2019-06-23)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.10.0...v3.0.0)\n\n**Breaking changes:**\n\n- Remove ul, li button wrapper [\\#409](https://github.com/shipshapecode/shepherd/pull/409) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Implemented enhancements:**\n\n- Support to keyboard navigation [\\#406](https://github.com/shipshapecode/shepherd/issues/406)\n- Feature request --- Add Typescript Typings [\\#359](https://github.com/shipshapecode/shepherd/issues/359)\n- Add `disableScroll` option [\\#413](https://github.com/shipshapecode/shepherd/pull/413) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add aria-describedby and aria-labeledby [\\#411](https://github.com/shipshapecode/shepherd/pull/411) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Arrow nav [\\#410](https://github.com/shipshapecode/shepherd/pull/410) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add focus trap, to disallow tabbing outside the modal [\\#408](https://github.com/shipshapecode/shepherd/pull/408) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Support close with ESC, focus tooltip on `show` [\\#407](https://github.com/shipshapecode/shepherd/pull/407) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Merged pull requests:**\n\n- Update eslint to the latest version 🚀 [\\#412](https://github.com/shipshapecode/shepherd/pull/412) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Greenkeeper/rollup plugin visualizer 2.1.1 [\\#404](https://github.com/shipshapecode/shepherd/pull/404) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.10.0](https://github.com/shipshapecode/shepherd/tree/v2.10.0) (2019-06-13)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.9.1...v2.10.0)\n\n**Implemented enhancements:**\n\n- Add scrollIntoView options and polyfill [\\#402](https://github.com/shipshapecode/shepherd/pull/402) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add TypeScript definitions [\\#360](https://github.com/shipshapecode/shepherd/pull/360) ([superheri](https://github.com/superheri))\n\n**Fixed bugs:**\n\n- \"TypeError: Property 'handleEvent' is not callable.\" in Firefox [\\#393](https://github.com/shipshapecode/shepherd/issues/393)\n- Remove addStepEventListeners call [\\#396](https://github.com/shipshapecode/shepherd/pull/396) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- \\[Proposal\\] center elements for scrollTo [\\#398](https://github.com/shipshapecode/shepherd/issues/398)\n- An in-range update of rollup is breaking the build 🚨 [\\#392](https://github.com/shipshapecode/shepherd/issues/392)\n\n**Merged pull requests:**\n\n- build support for windows \\(rm does not exist\\) [\\#403](https://github.com/shipshapecode/shepherd/pull/403) ([hheexx](https://github.com/hheexx))\n- Update stylelint-config-ship-shape to the latest version 🚀 [\\#399](https://github.com/shipshapecode/shepherd/pull/399) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.9.1](https://github.com/shipshapecode/shepherd/tree/v2.9.1) (2019-06-09)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.9.0...v2.9.1)\n\n**Implemented enhancements:**\n\n- Tippy 4.3.4, bump deps, fix lint [\\#395](https://github.com/shipshapecode/shepherd/pull/395) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Fix modal padding test failures, add tests, docs [\\#390](https://github.com/shipshapecode/shepherd/pull/390) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- An in-range update of autoprefixer is breaking the build 🚨 [\\#388](https://github.com/shipshapecode/shepherd/issues/388)\n- An in-range update of tippy.js is breaking the build 🚨 [\\#387](https://github.com/shipshapecode/shepherd/issues/387)\n- An in-range update of rollup-plugin-analyzer is breaking the build 🚨 [\\#386](https://github.com/shipshapecode/shepherd/issues/386)\n- An in-range update of rollup-plugin-node-resolve is breaking the build 🚨 [\\#385](https://github.com/shipshapecode/shepherd/issues/385)\n- An in-range update of rollup is breaking the build 🚨 [\\#384](https://github.com/shipshapecode/shepherd/issues/384)\n- Add space around attachedElement [\\#379](https://github.com/shipshapecode/shepherd/issues/379)\n\n**Merged pull requests:**\n\n- Optional padding on modalOverlayOpening [\\#383](https://github.com/shipshapecode/shepherd/pull/383) ([skmbr](https://github.com/skmbr))\n\n## [v2.9.0](https://github.com/shipshapecode/shepherd/tree/v2.9.0) (2019-05-26)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.8.0...v2.9.0)\n\n**Implemented enhancements:**\n\n- Add back IE support [\\#380](https://github.com/shipshapecode/shepherd/pull/380) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- Show event of tour does not pass the hash of `step` and `previous` [\\#371](https://github.com/shipshapecode/shepherd/issues/371)\n- Ensure arguments are passed down to trigger [\\#381](https://github.com/shipshapecode/shepherd/pull/381) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- Is it possible to change fill color of the modal ? [\\#374](https://github.com/shipshapecode/shepherd/issues/374)\n- There will be blue edges after clicking [\\#369](https://github.com/shipshapecode/shepherd/issues/369)\n- \\[Suggestion\\] Add transition effects when the mask moving [\\#304](https://github.com/shipshapecode/shepherd/issues/304)\n\n**Merged pull requests:**\n\n- Update rollup-plugin-eslint to the latest version 🚀 [\\#378](https://github.com/shipshapecode/shepherd/pull/378) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update rollup-plugin-terser to the latest version 🚀 [\\#376](https://github.com/shipshapecode/shepherd/pull/376) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update rollup-plugin-node-resolve to the latest version 🚀 [\\#373](https://github.com/shipshapecode/shepherd/pull/373) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.8.0](https://github.com/shipshapecode/shepherd/tree/v2.8.0) (2019-05-03)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.7.0...v2.8.0)\n\n**Implemented enhancements:**\n\n- Convert several lodash functions to internal utils [\\#368](https://github.com/shipshapecode/shepherd/pull/368) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Use internal debounce function [\\#367](https://github.com/shipshapecode/shepherd/pull/367) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Greenkeeper/stylelint 10.0.1 [\\#362](https://github.com/shipshapecode/shepherd/pull/362) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- Shepherd popper-tippy CSS styles mixing up with non-shepherd tippy styles on the page [\\#363](https://github.com/shipshapecode/shepherd/issues/363)\n\n**Closed issues:**\n\n- An in-range update of rollup is breaking the build 🚨 [\\#350](https://github.com/shipshapecode/shepherd/issues/350)\n\n**Merged pull requests:**\n\n- Added 'shepherd-popper' css class [\\#366](https://github.com/shipshapecode/shepherd/pull/366) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add ESDoc, bump some deps [\\#365](https://github.com/shipshapecode/shepherd/pull/365) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.7.0](https://github.com/shipshapecode/shepherd/tree/v2.7.0) (2019-04-22)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.6.0...v2.7.0)\n\n**Fixed bugs:**\n\n- After tour is canceled/completed and started again, overlay is not present anymore [\\#347](https://github.com/shipshapecode/shepherd/issues/347)\n- Add createModalOverlay function [\\#358](https://github.com/shipshapecode/shepherd/pull/358) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Merged pull requests:**\n\n- \\[BugFix\\] Issue \\#347 [\\#357](https://github.com/shipshapecode/shepherd/pull/357) ([jayjfletcher](https://github.com/jayjfletcher))\n\n## [v2.6.0](https://github.com/shipshapecode/shepherd/tree/v2.6.0) (2019-04-15)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.5.0...v2.6.0)\n\n**Implemented enhancements:**\n\n- React wrapper [\\#331](https://github.com/shipshapecode/shepherd/issues/331)\n\n**Fixed bugs:**\n\n- Minified File Size [\\#354](https://github.com/shipshapecode/shepherd/issues/354)\n- Fix inflated build size, bump some deps [\\#355](https://github.com/shipshapecode/shepherd/pull/355) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.5.0](https://github.com/shipshapecode/shepherd/tree/v2.5.0) (2019-03-20)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.4.0...v2.5.0)\n\n**Breaking changes:**\n\n- Drop IE support, bump some deps [\\#344](https://github.com/shipshapecode/shepherd/pull/344) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- Shepherd Doesn't Work Good On Mobile [\\#339](https://github.com/shipshapecode/shepherd/issues/339)\n- Fix demo app arrows to be title color [\\#314](https://github.com/shipshapecode/shepherd/issues/314)\n\n**Merged pull requests:**\n\n- Add flipping tippy by default, scrollTo for demo [\\#345](https://github.com/shipshapecode/shepherd/pull/345) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Update del to the latest version 🚀 [\\#340](https://github.com/shipshapecode/shepherd/pull/340) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.4.0](https://github.com/shipshapecode/shepherd/tree/v2.4.0) (2019-02-27)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.3.3...v2.4.0)\n\n**Implemented enhancements:**\n\n- Angular wrapper [\\#332](https://github.com/shipshapecode/shepherd/issues/332)\n- Add tabindex=\"0\" to shepherd-button [\\#337](https://github.com/shipshapecode/shepherd/pull/337) ([knoobie](https://github.com/knoobie))\n\n**Fixed bugs:**\n\n- Links in modal mode [\\#328](https://github.com/shipshapecode/shepherd/issues/328)\n- svg mask for the opening in browsers do not support getBoundingClientRect\\(\\).x|y [\\#330](https://github.com/shipshapecode/shepherd/pull/330) ([yaxinr](https://github.com/yaxinr))\n\n**Merged pull requests:**\n\n- Tippy 4 [\\#336](https://github.com/shipshapecode/shepherd/pull/336) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Fix inability to click things in shepherd-element [\\#334](https://github.com/shipshapecode/shepherd/pull/334) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Update rollup-plugin-css-only to the latest version 🚀 [\\#327](https://github.com/shipshapecode/shepherd/pull/327) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.3.3](https://github.com/shipshapecode/shepherd/tree/v2.3.3) (2019-01-23)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.3.2...v2.3.3)\n\n**Fixed bugs:**\n\n- Adds missing 'hide' to binded methods list in Tour [\\#326](https://github.com/shipshapecode/shepherd/pull/326) ([seppsepp](https://github.com/seppsepp))\n\n**Merged pull requests:**\n\n- Update rollup-plugin-babel-minify to the latest version 🚀 [\\#325](https://github.com/shipshapecode/shepherd/pull/325) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.3.2](https://github.com/shipshapecode/shepherd/tree/v2.3.2) (2019-01-16)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.3.1...v2.3.2)\n\n**Fixed bugs:**\n\n- Object.assign not transpiled [\\#323](https://github.com/shipshapecode/shepherd/issues/323)\n- Toggling developer tools breaks modal mask [\\#320](https://github.com/shipshapecode/shepherd/issues/320)\n- Scrolling to an element causes modal overlay to appear in wrong place [\\#319](https://github.com/shipshapecode/shepherd/issues/319)\n\n**Merged pull requests:**\n\n- Use @babel/plugin-transform-object-assign [\\#324](https://github.com/shipshapecode/shepherd/pull/324) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Apply scroll listener to all scroll events [\\#322](https://github.com/shipshapecode/shepherd/pull/322) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Use vh and vw to ensure modal is always full screen [\\#321](https://github.com/shipshapecode/shepherd/pull/321) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.3.1](https://github.com/shipshapecode/shepherd/tree/v2.3.1) (2019-01-15)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.3.0...v2.3.1)\n\n**Fixed bugs:**\n\n- fix: move touchmove event listener cleanup out of if statement [\\#317](https://github.com/shipshapecode/shepherd/pull/317) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n**Merged pull requests:**\n\n- Update rollup-plugin-license to the latest version 🚀 [\\#318](https://github.com/shipshapecode/shepherd/pull/318) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.3.0](https://github.com/shipshapecode/shepherd/tree/v2.3.0) (2019-01-14)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.2.0...v2.3.0)\n\n**Implemented enhancements:**\n\n- Inject tippy CSS to head [\\#315](https://github.com/shipshapecode/shepherd/pull/315) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.2.0](https://github.com/shipshapecode/shepherd/tree/v2.2.0) (2019-01-14)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.1.1...v2.2.0)\n\n**Implemented enhancements:**\n\n- setAttributeNS -\\> setAttribute, add modal utils tests [\\#312](https://github.com/shipshapecode/shepherd/pull/312) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Use rollup instead of webpack [\\#309](https://github.com/shipshapecode/shepherd/pull/309) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.1.1](https://github.com/shipshapecode/shepherd/tree/v2.1.1) (2019-01-11)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.1.0...v2.1.1)\n\n**Fixed bugs:**\n\n- Use correct cleanupStepEventListeners [\\#311](https://github.com/shipshapecode/shepherd/pull/311) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.1.0](https://github.com/shipshapecode/shepherd/tree/v2.1.0) (2019-01-06)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.2...v2.1.0)\n\n**Fixed bugs:**\n\n- fix: turn off passive events for touchmove on Safari \\> 10 [\\#307](https://github.com/shipshapecode/shepherd/pull/307) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n**Merged pull requests:**\n\n- Move modal to its own class [\\#308](https://github.com/shipshapecode/shepherd/pull/308) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.0.2](https://github.com/shipshapecode/shepherd/tree/v2.0.2) (2019-01-04)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.1...v2.0.2)\n\n**Fixed bugs:**\n\n- fix: remove class when modal hidden so elements are clickable [\\#305](https://github.com/shipshapecode/shepherd/pull/305) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n## [v2.0.1](https://github.com/shipshapecode/shepherd/tree/v2.0.1) (2018-12-31)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0...v2.0.1)\n\n## [v2.0.0](https://github.com/shipshapecode/shepherd/tree/v2.0.0) (2018-12-31)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.35...v2.0.0)\n\n**Implemented enhancements:**\n\n- Add data attribute to the body for the currently active tour name and current step [\\#284](https://github.com/shipshapecode/shepherd/issues/284)\n- Use data attributes for element selection in demo/tests [\\#273](https://github.com/shipshapecode/shepherd/issues/273)\n\n**Closed issues:**\n\n- An in-range update of autoprefixer is breaking the build 🚨 [\\#298](https://github.com/shipshapecode/shepherd/issues/298)\n- An in-range update of webpack is breaking the build 🚨 [\\#297](https://github.com/shipshapecode/shepherd/issues/297)\n\n**Merged pull requests:**\n\n- Integrate modal functionality that was originally in Ember Shepherd [\\#301](https://github.com/shipshapecode/shepherd/pull/301) ([BrianSipple](https://github.com/BrianSipple))\n- Use data attributes for test selectors [\\#299](https://github.com/shipshapecode/shepherd/pull/299) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Remove redundant `id` attribute on step tooltip containers. [\\#295](https://github.com/shipshapecode/shepherd/pull/295) ([BrianSipple](https://github.com/BrianSipple))\n- Link to Shepherd's Tippy defaults in docs [\\#294](https://github.com/shipshapecode/shepherd/pull/294) ([BrianSipple](https://github.com/BrianSipple))\n\n## [v2.0.0-beta.35](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.35) (2018-11-09)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.34...v2.0.0-beta.35)\n\n**Implemented enhancements:**\n\n- Document Tour.removeStep [\\#278](https://github.com/shipshapecode/shepherd/issues/278)\n- Update documentation to clarify arrow usage. [\\#287](https://github.com/shipshapecode/shepherd/pull/287) ([BrianSipple](https://github.com/BrianSipple))\n\n**Fixed bugs:**\n\n- fix tooltip centering [\\#288](https://github.com/shipshapecode/shepherd/pull/288) ([BrianSipple](https://github.com/BrianSipple))\n\n**Closed issues:**\n\n- An in-range update of start-server-and-test is breaking the build 🚨 [\\#283](https://github.com/shipshapecode/shepherd/issues/283)\n\n**Merged pull requests:**\n\n- Bump deps [\\#291](https://github.com/shipshapecode/shepherd/pull/291) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add testing for `Tour.isActive`. [\\#290](https://github.com/shipshapecode/shepherd/pull/290) ([BrianSipple](https://github.com/BrianSipple))\n- Added documentation for tour.removeStep \\(fixes \\#278\\) [\\#289](https://github.com/shipshapecode/shepherd/pull/289) ([joeinnes](https://github.com/joeinnes))\n- Improve CodeClimate and test coverage. [\\#286](https://github.com/shipshapecode/shepherd/pull/286) ([BrianSipple](https://github.com/BrianSipple))\n- Remove unnecessary management of `this.el.hidden` [\\#285](https://github.com/shipshapecode/shepherd/pull/285) ([BrianSipple](https://github.com/BrianSipple))\n\n## [v2.0.0-beta.34](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.34) (2018-10-23)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.33...v2.0.0-beta.34)\n\n**Implemented enhancements:**\n\n- Change `data-id` to `data-shepherd-step-id` on Step content elements. [\\#282](https://github.com/shipshapecode/shepherd/pull/282) ([BrianSipple](https://github.com/BrianSipple))\n\n**Closed issues:**\n\n- An in-range update of webpack is breaking the build 🚨 [\\#280](https://github.com/shipshapecode/shepherd/issues/280)\n\n## [v2.0.0-beta.33](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.33) (2018-10-19)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.32...v2.0.0-beta.33)\n\n**Implemented enhancements:**\n\n- Add minified js + css to release package [\\#258](https://github.com/shipshapecode/shepherd/issues/258)\n- Bump a bunch of deps [\\#281](https://github.com/shipshapecode/shepherd/pull/281) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- Exit animations don't play before step tooltip disappears. [\\#277](https://github.com/shipshapecode/shepherd/issues/277)\n- Allow exit animations to play before step tooltip disappears. [\\#279](https://github.com/shipshapecode/shepherd/pull/279) ([BrianSipple](https://github.com/BrianSipple))\n- Remove default arrow setting on centered tippy [\\#275](https://github.com/shipshapecode/shepherd/pull/275) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n**Merged pull requests:**\n\n- Fix bug of classes not being added to targets on returned-to steps. [\\#276](https://github.com/shipshapecode/shepherd/pull/276) ([BrianSipple](https://github.com/BrianSipple))\n\n## [v2.0.0-beta.32](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.32) (2018-10-13)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.31...v2.0.0-beta.32)\n\n## [v2.0.0-beta.31](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.31) (2018-10-13)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.30...v2.0.0-beta.31)\n\n## [v2.0.0-beta.30](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.30) (2018-10-13)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.29...v2.0.0-beta.30)\n\n**Implemented enhancements:**\n\n- Hide buttons if none are passed to `Step.options.buttons` [\\#243](https://github.com/shipshapecode/shepherd/issues/243)\n- Constrain input for `Step.options.buttons` to an array of buttons. [\\#271](https://github.com/shipshapecode/shepherd/pull/271) ([BrianSipple](https://github.com/BrianSipple))\n\n**Merged pull requests:**\n\n- fix docs typo [\\#272](https://github.com/shipshapecode/shepherd/pull/272) ([BrianSipple](https://github.com/BrianSipple))\n\n## [v2.0.0-beta.29](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.29) (2018-10-11)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.28...v2.0.0-beta.29)\n\n**Implemented enhancements:**\n\n- Bundle minified Tippy code with distribution [\\#263](https://github.com/shipshapecode/shepherd/issues/263)\n- Implement `Tour.hide` [\\#265](https://github.com/shipshapecode/shepherd/pull/265) ([BrianSipple](https://github.com/BrianSipple))\n\n**Fixed bugs:**\n\n- Remove or restore hide method on Tour instance [\\#249](https://github.com/shipshapecode/shepherd/issues/249)\n\n**Closed issues:**\n\n- An in-range update of tippy.js is breaking the build 🚨 [\\#266](https://github.com/shipshapecode/shepherd/issues/266)\n\n**Merged pull requests:**\n\n- Bundle tippy with the main Shepherd distribution file. [\\#270](https://github.com/shipshapecode/shepherd/pull/270) ([BrianSipple](https://github.com/BrianSipple))\n- remove spm from package.json [\\#269](https://github.com/shipshapecode/shepherd/pull/269) ([BrianSipple](https://github.com/BrianSipple))\n- remove some popper arrow styles and target tippy-arrow [\\#268](https://github.com/shipshapecode/shepherd/pull/268) ([chuckcarpenter](https://github.com/chuckcarpenter))\n- Update screenshot of intro step in README [\\#264](https://github.com/shipshapecode/shepherd/pull/264) ([BrianSipple](https://github.com/BrianSipple))\n\n## [v2.0.0-beta.28](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.28) (2018-10-08)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.27...v2.0.0-beta.28)\n\n**Implemented enhancements:**\n\n- Not all of popper.js placement values are supported [\\#259](https://github.com/shipshapecode/shepherd/issues/259)\n- Integrate Tippy for step modal creation [\\#255](https://github.com/shipshapecode/shepherd/issues/255)\n- Tippy.js Integration [\\#261](https://github.com/shipshapecode/shepherd/pull/261) ([BrianSipple](https://github.com/BrianSipple))\n\n**Merged pull requests:**\n\n- use uniqueId for step ID prop over idAttribute [\\#262](https://github.com/shipshapecode/shepherd/pull/262) ([chuckcarpenter](https://github.com/chuckcarpenter))\n- Support placement values and modifiers according to popper.js API \\(\\#259\\) [\\#260](https://github.com/shipshapecode/shepherd/pull/260) ([tedbeer](https://github.com/tedbeer))\n- Change localhost port for cypress tests and document how its used [\\#257](https://github.com/shipshapecode/shepherd/pull/257) ([BrianSipple](https://github.com/BrianSipple))\n- replace hubspot favicons with shipshape favicons [\\#256](https://github.com/shipshapecode/shepherd/pull/256) ([BrianSipple](https://github.com/BrianSipple))\n- documentation update: add beforeShowPromise example [\\#253](https://github.com/shipshapecode/shepherd/pull/253) ([jaffadog](https://github.com/jaffadog))\n- Update uglifyjs-webpack-plugin to the latest version 🚀 [\\#247](https://github.com/shipshapecode/shepherd/pull/247) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update theming documentation. [\\#242](https://github.com/shipshapecode/shepherd/pull/242) ([BrianSipple](https://github.com/BrianSipple))\n\n## [v2.0.0-beta.27](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.27) (2018-09-13)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.26...v2.0.0-beta.27)\n\n**Breaking changes:**\n\n- Rename `Tour.options.defaults` to `Tour.options.defaultStepOptions`. [\\#244](https://github.com/shipshapecode/shepherd/pull/244) ([BrianSipple](https://github.com/BrianSipple))\n\n**Implemented enhancements:**\n\n- Change `tour.options.defaults` to `tour.options.stepOptions` [\\#240](https://github.com/shipshapecode/shepherd/issues/240)\n\n**Merged pull requests:**\n\n- Greenkeeper/babel plugin add module exports 1.0.0 [\\#246](https://github.com/shipshapecode/shepherd/pull/246) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.0.0-beta.26](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.26) (2018-09-07)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.25...v2.0.0-beta.26)\n\n**Fixed bugs:**\n\n- Build syntax errors and element.prepend function not supported \\(Internet Explorer\\) [\\#238](https://github.com/shipshapecode/shepherd/issues/238)\n- Syntax errors and ParentNode.prepend not supported in IE [\\#239](https://github.com/shipshapecode/shepherd/pull/239) ([alexdaube](https://github.com/alexdaube))\n\n## [v2.0.0-beta.25](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.25) (2018-09-06)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.24...v2.0.0-beta.25)\n\n## [v2.0.0-beta.24](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.24) (2018-09-05)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.23...v2.0.0-beta.24)\n\n**Implemented enhancements:**\n\n- Way to get user to confirm quitting a tutorial [\\#133](https://github.com/shipshapecode/shepherd/issues/133)\n- Add step options to ESDoc [\\#234](https://github.com/shipshapecode/shepherd/pull/234) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Add Confirm cancel [\\#232](https://github.com/shipshapecode/shepherd/pull/232) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- improved theming [\\#204](https://github.com/shipshapecode/shepherd/pull/204) ([bm2u](https://github.com/bm2u))\n\n**Fixed bugs:**\n\n- advanceOn doesn't complete tour [\\#93](https://github.com/shipshapecode/shepherd/issues/93)\n- advanceOn blur? [\\#89](https://github.com/shipshapecode/shepherd/issues/89)\n\n**Closed issues:**\n\n- Action required: Greenkeeper could not be activated 🚨 [\\#227](https://github.com/shipshapecode/shepherd/issues/227)\n\n**Merged pull requests:**\n\n- add `.vscode` directory to `.gitignore` [\\#237](https://github.com/shipshapecode/shepherd/pull/237) ([BrianSipple](https://github.com/BrianSipple))\n- Update extract-loader to the latest version 🚀 [\\#236](https://github.com/shipshapecode/shepherd/pull/236) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- \\[Issue/89\\]- add onCapture setting to bubble events such as blur for tour elements… [\\#233](https://github.com/shipshapecode/shepherd/pull/233) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n## [v2.0.0-beta.23](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.23) (2018-08-29)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.22...v2.0.0-beta.23)\n\n**Implemented enhancements:**\n\n- Update to Babel 7, use lodash-es [\\#231](https://github.com/shipshapecode/shepherd/pull/231) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Merged pull requests:**\n\n- add more tests for increased coverage [\\#230](https://github.com/shipshapecode/shepherd/pull/230) ([chuckcarpenter](https://github.com/chuckcarpenter))\n- Update dependencies to enable Greenkeeper 🌴 [\\#229](https://github.com/shipshapecode/shepherd/pull/229) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.0.0-beta.22](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.22) (2018-08-29)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.21...v2.0.0-beta.22)\n\n**Implemented enhancements:**\n\n- Implement ESDoc [\\#226](https://github.com/shipshapecode/shepherd/pull/226) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- Fix cancel on any step with a title [\\#228](https://github.com/shipshapecode/shepherd/pull/228) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n## [v2.0.0-beta.21](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.21) (2018-08-27)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.20...v2.0.0-beta.21)\n\n**Merged pull requests:**\n\n- Merge coverage from cypress and unit tests [\\#225](https://github.com/shipshapecode/shepherd/pull/225) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Renaming of scss source dir [\\#219](https://github.com/shipshapecode/shepherd/pull/219) ([bm2u](https://github.com/bm2u))\n\n## [v2.0.0-beta.20](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.20) (2018-08-26)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.19...v2.0.0-beta.20)\n\n**Implemented enhancements:**\n\n- Increase test coverage, refactor, and cleanup [\\#224](https://github.com/shipshapecode/shepherd/pull/224) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.0.0-beta.19](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.19) (2018-08-25)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.18...v2.0.0-beta.19)\n\n## [v2.0.0-beta.18](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.18) (2018-08-25)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.17...v2.0.0-beta.18)\n\n**Implemented enhancements:**\n\n- Add some tour tests [\\#216](https://github.com/shipshapecode/shepherd/pull/216) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Testing for Evented module [\\#215](https://github.com/shipshapecode/shepherd/pull/215) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n**Fixed bugs:**\n\n- ES2015 imports not working [\\#210](https://github.com/shipshapecode/shepherd/issues/210)\n- Fix issue with cancel button [\\#220](https://github.com/shipshapecode/shepherd/pull/220) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n**Merged pull requests:**\n\n- Move bind methods to their own file [\\#222](https://github.com/shipshapecode/shepherd/pull/222) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Start some refactoring [\\#221](https://github.com/shipshapecode/shepherd/pull/221) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Step.js coverage increase [\\#218](https://github.com/shipshapecode/shepherd/pull/218) ([chuckcarpenter](https://github.com/chuckcarpenter))\n- Reduce Evented complexity [\\#217](https://github.com/shipshapecode/shepherd/pull/217) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- Start refactoring for Code Climate [\\#214](https://github.com/shipshapecode/shepherd/pull/214) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.0.0-beta.17](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.17) (2018-08-15)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.16...v2.0.0-beta.17)\n\n**Merged pull requests:**\n\n- Feature/webpack [\\#212](https://github.com/shipshapecode/shepherd/pull/212) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n## [v2.0.0-beta.16](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.16) (2018-08-14)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.15...v2.0.0-beta.16)\n\n**Implemented enhancements:**\n\n- \\[feature/builder\\] - replace Gulp with module loader and npm [\\#203](https://github.com/shipshapecode/shepherd/pull/203) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n**Fixed bugs:**\n\n- Uncaught TypeError: \\_shepherd2.default.Tour is not a constructor [\\#202](https://github.com/shipshapecode/shepherd/issues/202)\n\n**Merged pull requests:**\n\n- Start on cypress [\\#209](https://github.com/shipshapecode/shepherd/pull/209) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n- increase test coverage [\\#206](https://github.com/shipshapecode/shepherd/pull/206) ([chuckcarpenter](https://github.com/chuckcarpenter))\n\n## [v2.0.0-beta.15](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.15) (2018-08-06)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.14...v2.0.0-beta.15)\n\n**Fixed bugs:**\n\n- Error: Cannot find module 'popper' from '\\node\\_modules\\shepherd.js\\dist\\js' [\\#201](https://github.com/shipshapecode/shepherd/issues/201)\n\n## [v2.0.0-beta.14](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.14) (2018-08-02)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.13...v2.0.0-beta.14)\n\n**Fixed bugs:**\n\n- Error thrown if element not visible anymore [\\#197](https://github.com/shipshapecode/shepherd/issues/197)\n\n**Merged pull requests:**\n\n- Basic testing framework [\\#199](https://github.com/shipshapecode/shepherd/pull/199) ([chuckcarpenter](https://github.com/chuckcarpenter))\n- Update documentation link in demo tour [\\#195](https://github.com/shipshapecode/shepherd/pull/195) ([mikelkew](https://github.com/mikelkew))\n\n## [v2.0.0-beta.13](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.13) (2018-07-16)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.12...v2.0.0-beta.13)\n\n**Implemented enhancements:**\n\n- Refactor css in shepherd-theme-arrows theme [\\#52](https://github.com/shipshapecode/shepherd/issues/52)\n- Automatically use theme if styles are included [\\#1](https://github.com/shipshapecode/shepherd/issues/1)\n\n## [v2.0.0-beta.12](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.12) (2018-07-12)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.11...v2.0.0-beta.12)\n\n## [v2.0.0-beta.11](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.11) (2018-07-12)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.10...v2.0.0-beta.11)\n\n**Implemented enhancements:**\n\n- Attach shepherd-step to \"custom\" element / supporting dialog elements. [\\#157](https://github.com/shipshapecode/shepherd/issues/157)\n- Add renderLocation option [\\#192](https://github.com/shipshapecode/shepherd/pull/192) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- Tours fail to load on Chrome 65  [\\#180](https://github.com/shipshapecode/shepherd/issues/180)\n- Step divs remain after tour has ended [\\#66](https://github.com/shipshapecode/shepherd/issues/66)\n\n**Closed issues:**\n\n- Step class cleanup [\\#36](https://github.com/shipshapecode/shepherd/issues/36)\n\n## [v2.0.0-beta.10](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.10) (2018-07-11)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.9...v2.0.0-beta.10)\n\n## [v2.0.0-beta.9](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.9) (2018-07-11)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.8...v2.0.0-beta.9)\n\n**Implemented enhancements:**\n\n- CSS should not be required to use this library [\\#166](https://github.com/shipshapecode/shepherd/issues/166)\n\n**Fixed bugs:**\n\n- Arrows don't appear on some boxes randomly \\(video\\) [\\#156](https://github.com/shipshapecode/shepherd/issues/156)\n\n**Closed issues:**\n\n- Undocumented `scrollToHandler` option [\\#107](https://github.com/shipshapecode/shepherd/issues/107)\n\n## [v2.0.0-beta.8](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.8) (2018-07-09)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.7...v2.0.0-beta.8)\n\n## [v2.0.0-beta.7](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.7) (2018-07-07)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.6...v2.0.0-beta.7)\n\n**Fixed bugs:**\n\n- Use frame safe way for isArray\\(\\) & isObject\\(\\) [\\#153](https://github.com/shipshapecode/shepherd/issues/153)\n- remove shepherd-target class on tour.next\\(\\)/tour.back\\(\\) [\\#109](https://github.com/shipshapecode/shepherd/issues/109)\n\n**Closed issues:**\n\n- Rethethering issue when target element is re-rendered. [\\#112](https://github.com/shipshapecode/shepherd/issues/112)\n\n## [v2.0.0-beta.6](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.6) (2018-07-07)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.5...v2.0.0-beta.6)\n\n**Implemented enhancements:**\n\n- Close button as HTML entity [\\#148](https://github.com/shipshapecode/shepherd/pull/148) ([bm2u](https://github.com/bm2u))\n\n**Fixed bugs:**\n\n- Hide events being triggered twice when there is another step [\\#167](https://github.com/shipshapecode/shepherd/issues/167)\n- Removing duplicate call to hide step [\\#168](https://github.com/shipshapecode/shepherd/pull/168) ([pedroceles](https://github.com/pedroceles))\n\n**Closed issues:**\n\n- The install doc is not working [\\#179](https://github.com/shipshapecode/shepherd/issues/179)\n- addStep not return step instance [\\#165](https://github.com/shipshapecode/shepherd/issues/165)\n- cancelling the tour when clicking outside the element [\\#141](https://github.com/shipshapecode/shepherd/issues/141)\n- showCancelLink yields weird characters [\\#117](https://github.com/shipshapecode/shepherd/issues/117)\n\n**Merged pull requests:**\n\n- Added a demo tour at Simple Planner [\\#155](https://github.com/shipshapecode/shepherd/pull/155) ([newscloud](https://github.com/newscloud))\n\n## [v2.0.0-beta.5](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.5) (2018-07-03)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.4...v2.0.0-beta.5)\n\n## [v2.0.0-beta.4](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.4) (2018-07-03)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.3...v2.0.0-beta.4)\n\n## [v2.0.0-beta.3](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.3) (2018-07-03)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.2...v2.0.0-beta.3)\n\n**Closed issues:**\n\n- How can i use it with ionic 2 typescript? [\\#174](https://github.com/shipshapecode/shepherd/issues/174)\n\n## [v2.0.0-beta.2](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.2) (2018-07-02)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v2.0.0-beta.1...v2.0.0-beta.2)\n\n## [v2.0.0-beta.1](https://github.com/shipshapecode/shepherd/tree/v2.0.0-beta.1) (2018-07-02)\n\n[Full Changelog](https://github.com/shipshapecode/shepherd/compare/v1.8.1...v2.0.0-beta.1)\n\n**Implemented enhancements:**\n\n- Convert to popper [\\#189](https://github.com/shipshapecode/shepherd/pull/189) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Fixed bugs:**\n\n- Attempting to fix uncaught exception caused by non-existing element f… [\\#190](https://github.com/shipshapecode/shepherd/pull/190) ([RobbieTheWagner](https://github.com/RobbieTheWagner))\n\n**Closed issues:**\n\n- href of the \"View docs\" button on demo site --\\> 404 [\\#187](https://github.com/shipshapecode/shepherd/issues/187)\n- Demo site is down [\\#185](https://github.com/shipshapecode/shepherd/issues/185)\n- Maintainer/transfer [\\#183](https://github.com/shipshapecode/shepherd/issues/183)\n- cannot get node\\_modules/tether-shepherd/dist/js/shepherd.min.js  [\\#173](https://github.com/shipshapecode/shepherd/issues/173)\n- ES6 import from NPM failed. [\\#171](https://github.com/shipshapecode/shepherd/issues/171)\n- Display Shepherd only during first visit [\\#164](https://github.com/shipshapecode/shepherd/issues/164)\n- Tether EOL implications [\\#163](https://github.com/shipshapecode/shepherd/issues/163)\n- Get the AttachTo object [\\#150](https://github.com/shipshapecode/shepherd/issues/150)\n- Arrow problem [\\#145](https://github.com/shipshapecode/shepherd/issues/145)\n- `attachment: together` does not work as expected if attachment width greater than target width [\\#142](https://github.com/shipshapecode/shepherd/issues/142)\n- shepherd-step not placed in proper position [\\#130](https://github.com/shipshapecode/shepherd/issues/130)\n- attachTo is not working when passing a string [\\#122](https://github.com/shipshapecode/shepherd/issues/122)\n- Triggering click of an page element on tour step \"show\" [\\#119](https://github.com/shipshapecode/shepherd/issues/119)\n- Inherit animation styles from Drop [\\#84](https://github.com/shipshapecode/shepherd/issues/84)\n- Shepherd might need jQuery... [\\#79](https://github.com/shipshapecode/shepherd/issues/79)\n- Not accessibility friendly [\\#26](https://github.com/shipshapecode/shepherd/issues/26)\n\n**Merged pull requests:**\n\n- RM Hubs Copyright [\\#188](https://github.com/shipshapecode/shepherd/pull/188) ([FranDias](https://github.com/FranDias))\n- Link correct demo site [\\#186](https://github.com/shipshapecode/shepherd/pull/186) ([drucci](https://github.com/drucci))\n- Add Repo to package.json [\\#149](https://github.com/shipshapecode/shepherd/pull/149) ([bm2u](https://github.com/bm2u))\n\n## v1.7.0\n- Fixes bug where `buttons: false` resulted in the default Next button instead of showing the desired result of no buttons.\n\n## v1.6.0 & v1.6.2\n- Patches issue where Tether anchor reference was being cached instead of reset when step is shown.\n\n## v1.5.2\n- Adds functionality to pass an object `{element: el, on: tetherPositionString}` to tour step `attachTo` parameter.\n\n## v1.5.1\n- Exposes `scrollTo` option in Eager\n\n## v1.5.0\n- Positioning string parse improvements with regex\n- Installation support for dynamically rendered pages in Eager\n- Live updates for eager / creation of `tour.removeStep`\n\n## v1.2.2\n- Moves `Tether.js` out of `bower_components` and into `dist` for supoort in Eager\n\n## v1.2.1\n- Exposes tour object on eager install\n\n## v1.2.0\n- Adds `showOn` for conditionally showing tour steps\n\n## v1.1.4\n- Eager - Install helper now checks for the presence of first attach node before starting\n\n## v1.1.2 & v1.1.3\n- Fix stacking event listeners\n\n## v1.1.1\n- Pointer event none for arrows\n\n## v1.1.0\n- Update `Tether` to version 1\n- Bump all dependencies\n\n## v1.0.0\n- Add proper UMD to `Shepherd`\n- Convert from `Coffeescript` to `ES6 (Babel)`\n- Fix `*.json` files to include `main`\n- Remove bundled versions\n- Restructure directory layout\n- Update `gulp` builds\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guide\n\nYou will need:\n\n- [pnpm](https://pnpm.io/)\n\n## Getting started\n\n1. Fork the project\n2. Clone your forked project by running `git clone git@github.com:{\nYOUR_USERNAME }/shepherd.git`\n3. Run `pnpm i` to install node modules\n4. Test that you can build the source by running `pnpm build` and ensure the `dist` directory appears.\n\n## Writing code!\n\nWe use `rollup` to facilitate things like transpilation, minification, etc. so\nyou can focus on writing relevant code. If there is a fix or feature you would like\nto contribute, we ask that you take the following steps:\n\n1. Most of the _editable_ code lives in the `src` directory while built code\n   will end up in the `dist` directory upon running `pnpm build`.\n\n2. The demo app is served out of the `landing` directory. Running `pnpm start` will open it in your browser and initiate a live-reloading session as you make changes.\n\n## Opening Pull Requests\n\n1. Please Provide a thoughtful commit message and push your changes to your fork using\n   `git push origin main` (assuming your forked project is using `origin` for\n   the remote name and you are on the `main` branch).\n\n2. Open a Pull Request on GitHub with a description of your changes.\n\n## Testing\n\nAll PRs that change code functionality are required to have accompanying tests.\n\n### Acceptance Tests\n\nAcceptance tests are run using [`cypress`](https://github.com/cypress-io/cypress). A number of different testing configurations can be found in [`package.json`](/package.json), but you can simply run `pnpm test:cy:watch` to build your latest changes and begin running the tests inside a Chrome browser instance.\n\n⚠️ The acceptance tests are set up to run on `localhost` port `9002`. If you'd like to change this port, make sure to change the `baseUrl` option inside of [`cypress.json`](/cypress.json), and change any references to port `9002` in [`package.json`](/package.json) accordingly.\n"
  },
  {
    "path": "LICENSE.md",
    "content": "# Shepherd.js License\n\nShepherd.js is dual-licensed under **AGPL-3.0** (for open source and non-commercial use) and a **Commercial License** (for commercial use).\n\n---\n 🆓 Free Use - AGPL-3.0 License\nYou may use Shepherd.js **FREE OF CHARGE** under the AGPL-3.0 license if you are:\n ✅ Open Source Projects\n- Your project is open source and licensed under an AGPL-compatible license (GPL, AGPL, etc.)\n- Your complete source code is publicly available\n ✅ Personal & Non-Commercial Use\n- Personal projects, portfolios, and hobby websites\n- Educational purposes (students, teachers, coursework)\n- Academic research projects\n ✅ Evaluation & Testing\n- Evaluating Shepherd.js for up to 30 days\n- Development, testing, and staging environments during evaluation\n- Proof-of-concept and demo projects\n**Important:** If you use Shepherd.js under AGPL-3.0, you must:\n- Make your complete source code available if you distribute or provide your software over a network\n- License your code under AGPL-3.0 or a compatible license\n- Comply with all AGPL-3.0 terms (see full license text below)\n---\n 💳 Commercial License Required\nYou **must purchase a commercial license** at [shepherdjs.dev/pricing](https://shepherdjs.dev/pricing) if:\n ❌ Commercial Products & Services\n- You're building a commercial product, application, SaaS, or website that generates revenue\n- Your company generates revenue (even if the specific project using Shepherd.js does not)\n- You're using Shepherd.js in any customer-facing commercial application\n ❌ Closed-Source Use\n- You cannot or don't want to open-source your code under AGPL-3.0\n- You want to keep your source code proprietary\n- You want to avoid AGPL's source code disclosure requirements\n ❌ White-Label, Resale, or OEM Use\n- You're embedding Shepherd.js in a product you sell or distribute\n- You're offering Shepherd.js as part of a commercial service or hosting\n- You're using Shepherd.js in a product sold to other businesses\n ❌ Internal Business Tools\n- You're using Shepherd.js for internal tools, dashboards, or admin panels in a revenue-generating company\n- Even if the tool is not customer-facing, commercial licenses are required for for-profit companies\n**Why Commercial License?**\n- ✅ No AGPL obligations - keep your code proprietary\n- ✅ Legal protection and indemnification\n- ✅ Priority support and updates\n- ✅ Lifetime license with no recurring fees\n[**Purchase Commercial License →**](https://shepherdjs.dev/pricing)\n---\n ❓ Still Not Sure?\nIf you're unsure whether you need a commercial license:\n- **Contact us:** [ahoy@shipshape.io](mailto:ahoy@shipshape.io)\n- **View pricing:** [shepherdjs.dev/pricing](https://shepherdjs.dev/pricing)\n**When in doubt:** If your organization generates revenue, you likely need a commercial license.\n---\n\n### GNU AFFERO GENERAL PUBLIC LICENSE\n\nVersion 3, 19 November 2007\n\nCopyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n\nEveryone is permitted to copy and distribute verbatim copies of this license\ndocument, but changing it is not allowed.\n\n### Preamble\n\nThe GNU Affero General Public License is a free, copyleft license for software\nand other kinds of works, specifically designed to ensure cooperation with the\ncommunity in the case of network server software.\n\nThe licenses for most software and other practical works are designed to take\naway your freedom to share and change the works. By contrast, our General Public\nLicenses are intended to guarantee your freedom to share and change all versions\nof a program--to make sure it remains free software for all its users.\n\nWhen we speak of free software, we are referring to freedom, not price. Our\nGeneral Public Licenses are designed to make sure that you have the freedom to\ndistribute copies of free software (and charge for them if you wish), that you\nreceive source code or can get it if you want it, that you can change the\nsoftware or use pieces of it in new free programs, and that you know you can do\nthese things.\n\nDevelopers that use our General Public Licenses protect your rights with two\nsteps: (1) assert copyright on the software, and (2) offer you this License\nwhich gives you legal permission to copy, distribute and/or modify the software.\n\nA secondary benefit of defending all users' freedom is that improvements made in\nalternate versions of the program, if they receive widespread use, become\navailable for other developers to incorporate. Many developers of free software\nare heartened and encouraged by the resulting cooperation. However, in the case\nof software used on network servers, this result may fail to come about. The GNU\nGeneral Public License permits making a modified version and letting the public\naccess it on a server without ever releasing its source code to the public.\n\nThe GNU Affero General Public License is designed specifically to ensure that,\nin such cases, the modified source code becomes available to the community. It\nrequires the operator of a network server to provide the source code of the\nmodified version running there to the users of that server. Therefore, public\nuse of a modified version, on a publicly accessible server, gives the public\naccess to the source code of the modified version.\n\nAn older license, called the Affero General Public License and published by\nAffero, was designed to accomplish similar goals. This is a different license,\nnot a version of the Affero GPL, but Affero has released a new version of the\nAffero GPL which permits relicensing under this license.\n\nThe precise terms and conditions for copying, distribution and modification\nfollow.\n\n### TERMS AND CONDITIONS\n\n#### 0. Definitions.\n\n\"This License\" refers to version 3 of the GNU Affero General Public License.\n\n\"Copyright\" also means copyright-like laws that apply to other kinds of works,\nsuch as semiconductor masks.\n\n\"The Program\" refers to any copyrightable work licensed under this License. Each\nlicensee is addressed as \"you\". \"Licensees\" and \"recipients\" may be individuals\nor organizations.\n\nTo \"modify\" a work means to copy from or adapt all or part of the work in a\nfashion requiring copyright permission, other than the making of an exact copy.\nThe resulting work is called a \"modified version\" of the earlier work or a work\n\"based on\" the earlier work.\n\nA \"covered work\" means either the unmodified Program or a work based on the\nProgram.\n\nTo \"propagate\" a work means to do anything with it that, without permission,\nwould make you directly or secondarily liable for infringement under applicable\ncopyright law, except executing it on a computer or modifying a private copy.\nPropagation includes copying, distribution (with or without modification),\nmaking available to the public, and in some countries other activities as well.\n\nTo \"convey\" a work means any kind of propagation that enables other parties to\nmake or receive copies. Mere interaction with a user through a computer network,\nwith no transfer of a copy, is not conveying.\n\nAn interactive user interface displays \"Appropriate Legal Notices\" to the extent\nthat it includes a convenient and prominently visible feature that (1) displays\nan appropriate copyright notice, and (2) tells the user that there is no\nwarranty for the work (except to the extent that warranties are provided), that\nlicensees may convey the work under this License, and how to view a copy of this\nLicense. If the interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n#### 1. Source Code.\n\nThe \"source code\" for a work means the preferred form of the work for making\nmodifications to it. \"Object code\" means any non-source form of a work.\n\nA \"Standard Interface\" means an interface that either is an official standard\ndefined by a recognized standards body, or, in the case of interfaces specified\nfor a particular programming language, one that is widely used among developers\nworking in that language.\n\nThe \"System Libraries\" of an executable work include anything, other than the\nwork as a whole, that (a) is included in the normal form of packaging a Major\nComponent, but which is not part of that Major Component, and (b) serves only to\nenable use of the work with that Major Component, or to implement a Standard\nInterface for which an implementation is available to the public in source code\nform. A \"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system (if any) on\nwhich the executable work runs, or a compiler used to produce the work, or an\nobject code interpreter used to run it.\n\nThe \"Corresponding Source\" for a work in object code form means all the source\ncode needed to generate, install, and (for an executable work) run the object\ncode and to modify the work, including scripts to control those activities.\nHowever, it does not include the work's System Libraries, or general-purpose\ntools or generally available free programs which are used unmodified in\nperforming those activities but which are not part of the work. For example,\nCorresponding Source includes interface definition files associated with source\nfiles for the work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require, such as by\nintimate data communication or control flow between those subprograms and other\nparts of the work.\n\nThe Corresponding Source need not include anything that users can regenerate\nautomatically from other parts of the Corresponding Source.\n\nThe Corresponding Source for a work in source code form is that same work.\n\n#### 2. Basic Permissions.\n\nAll rights granted under this License are granted for the term of copyright on\nthe Program, and are irrevocable provided the stated conditions are met. This\nLicense explicitly affirms your unlimited permission to run the unmodified\nProgram. The output from running a covered work is covered by this License only\nif the output, given its content, constitutes a covered work. This License\nacknowledges your rights of fair use or other equivalent, as provided by\ncopyright law.\n\nYou may make, run and propagate covered works that you do not convey, without\nconditions so long as your license otherwise remains in force. You may convey\ncovered works to others for the sole purpose of having them make modifications\nexclusively for you, or provide you with facilities for running those works,\nprovided that you comply with the terms of this License in conveying all\nmaterial for which you do not control copyright. Those thus making or running\nthe covered works for you must do so exclusively on your behalf, under your\ndirection and control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\nConveying under any other circumstances is permitted solely under the conditions\nstated below. Sublicensing is not allowed; section 10 makes it unnecessary.\n\n#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\nNo covered work shall be deemed part of an effective technological measure under\nany applicable law fulfilling obligations under article 11 of the WIPO copyright\ntreaty adopted on 20 December 1996, or similar laws prohibiting or restricting\ncircumvention of such measures.\n\nWhen you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention is\neffected by exercising rights under this License with respect to the covered\nwork, and you disclaim any intention to limit operation or modification of the\nwork as a means of enforcing, against the work's users, your or third parties'\nlegal rights to forbid circumvention of technological measures.\n\n#### 4. Conveying Verbatim Copies.\n\nYou may convey verbatim copies of the Program's source code as you receive it,\nin any medium, provided that you conspicuously and appropriately publish on each\ncopy an appropriate copyright notice; keep intact all notices stating that this\nLicense and any non-permissive terms added in accord with section 7 apply to the\ncode; keep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\nYou may charge any price or no price for each copy that you convey, and you may\noffer support or warranty protection for a fee.\n\n#### 5. Conveying Modified Source Versions.\n\nYou may convey a work based on the Program, or the modifications to produce it\nfrom the Program, in the form of source code under the terms of section 4,\nprovided that you also meet all of these conditions:\n\n- a) The work must carry prominent notices stating that you modified it, and\n  giving a relevant date.\n- b) The work must carry prominent notices stating that it is released under\n  this License and any conditions added under section 7. This requirement\n  modifies the requirement in section 4 to \"keep intact all notices\".\n- c) You must license the entire work, as a whole, under this License to anyone\n  who comes into possession of a copy. This License will therefore apply, along\n  with any applicable section 7 additional terms, to the whole of the work, and\n  all its parts, regardless of how they are packaged. This License gives no\n  permission to license the work in any other way, but it does not invalidate\n  such permission if you have separately received it.\n- d) If the work has interactive user interfaces, each must display Appropriate\n  Legal Notices; however, if the Program has interactive interfaces that do not\n  display Appropriate Legal Notices, your work need not make them do so.\n\nA compilation of a covered work with other separate and independent works, which\nare not by their nature extensions of the covered work, and which are not\ncombined with it such as to form a larger program, in or on a volume of a\nstorage or distribution medium, is called an \"aggregate\" if the compilation and\nits resulting copyright are not used to limit the access or legal rights of the\ncompilation's users beyond what the individual works permit. Inclusion of a\ncovered work in an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n#### 6. Conveying Non-Source Forms.\n\nYou may convey a covered work in object code form under the terms of sections 4\nand 5, provided that you also convey the machine-readable Corresponding Source\nunder the terms of this License, in one of these ways:\n\n- a) Convey the object code in, or embodied in, a physical product (including a\n  physical distribution medium), accompanied by the Corresponding Source fixed\n  on a durable physical medium customarily used for software interchange.\n- b) Convey the object code in, or embodied in, a physical product (including a\n  physical distribution medium), accompanied by a written offer, valid for at\n  least three years and valid for as long as you offer spare parts or customer\n  support for that product model, to give anyone who possesses the object code\n  either (1) a copy of the Corresponding Source for all the software in the\n  product that is covered by this License, on a durable physical medium\n  customarily used for software interchange, for a price no more than your\n  reasonable cost of physically performing this conveying of source, or (2)\n  access to copy the Corresponding Source from a network server at no charge.\n- c) Convey individual copies of the object code with a copy of the written\n  offer to provide the Corresponding Source. This alternative is allowed only\n  occasionally and noncommercially, and only if you received the object code\n  with such an offer, in accord with subsection 6b.\n- d) Convey the object code by offering access from a designated place (gratis\n  or for a charge), and offer equivalent access to the Corresponding Source in\n  the same way through the same place at no further charge. You need not require\n  recipients to copy the Corresponding Source along with the object code. If the\n  place to copy the object code is a network server, the Corresponding Source\n  may be on a different server (operated by you or a third party) that supports\n  equivalent copying facilities, provided you maintain clear directions next to\n  the object code saying where to find the Corresponding Source. Regardless of\n  what server hosts the Corresponding Source, you remain obligated to ensure\n  that it is available for as long as needed to satisfy these requirements.\n- e) Convey the object code using peer-to-peer transmission, provided you inform\n  other peers where the object code and Corresponding Source of the work are\n  being offered to the general public at no charge under subsection 6d.\n\nA separable portion of the object code, whose source code is excluded from the\nCorresponding Source as a System Library, need not be included in conveying the\nobject code work.\n\nA \"User Product\" is either (1) a \"consumer product\", which means any tangible\npersonal property which is normally used for personal, family, or household\npurposes, or (2) anything designed or sold for incorporation into a dwelling. In\ndetermining whether a product is a consumer product, doubtful cases shall be\nresolved in favor of coverage. For a particular product received by a particular\nuser, \"normally used\" refers to a typical or common use of that class of\nproduct, regardless of the status of the particular user or of the way in which\nthe particular user actually uses, or expects or is expected to use, the\nproduct. A product is a consumer product regardless of whether the product has\nsubstantial commercial, industrial or non-consumer uses, unless such uses\nrepresent the only significant mode of use of the product.\n\n\"Installation Information\" for a User Product means any methods, procedures,\nauthorization keys, or other information required to install and execute\nmodified versions of a covered work in that User Product from a modified version\nof its Corresponding Source. The information must suffice to ensure that the\ncontinued functioning of the modified object code is in no case prevented or\ninterfered with solely because modification has been made.\n\nIf you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as part of a\ntransaction in which the right of possession and use of the User Product is\ntransferred to the recipient in perpetuity or for a fixed term (regardless of\nhow the transaction is characterized), the Corresponding Source conveyed under\nthis section must be accompanied by the Installation Information. But this\nrequirement does not apply if neither you nor any third party retains the\nability to install modified object code on the User Product (for example, the\nwork has been installed in ROM).\n\nThe requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates for a\nwork that has been modified or installed by the recipient, or for the User\nProduct in which it has been modified or installed. Access to a network may be\ndenied when the modification itself materially and adversely affects the\noperation of the network or violates the rules and protocols for communication\nacross the network.\n\nCorresponding Source conveyed, and Installation Information provided, in accord\nwith this section must be in a format that is publicly documented (and with an\nimplementation available to the public in source code form), and must require no\nspecial password or key for unpacking, reading or copying.\n\n#### 7. Additional Terms.\n\n\"Additional permissions\" are terms that supplement the terms of this License by\nmaking exceptions from one or more of its conditions. Additional permissions\nthat are applicable to the entire Program shall be treated as though they were\nincluded in this License, to the extent that they are valid under applicable\nlaw. If additional permissions apply only to part of the Program, that part may\nbe used separately under those permissions, but the entire Program remains\ngoverned by this License without regard to the additional permissions.\n\nWhen you convey a copy of a covered work, you may at your option remove any\nadditional permissions from that copy, or from any part of it. (Additional\npermissions may be written to require their own removal in certain cases when\nyou modify the work.) You may place additional permissions on material, added by\nyou to a covered work, for which you have or can give appropriate copyright\npermission.\n\nNotwithstanding any other provision of this License, for material you add to a\ncovered work, you may (if authorized by the copyright holders of that material)\nsupplement the terms of this License with terms:\n\n- a) Disclaiming warranty or limiting liability differently from the terms of\n  sections 15 and 16 of this License; or\n- b) Requiring preservation of specified reasonable legal notices or author\n  attributions in that material or in the Appropriate Legal Notices displayed by\n  works containing it; or\n- c) Prohibiting misrepresentation of the origin of that material, or requiring\n  that modified versions of such material be marked in reasonable ways as\n  different from the original version; or\n- d) Limiting the use for publicity purposes of names of licensors or authors of\n  the material; or\n- e) Declining to grant rights under trademark law for use of some trade names,\n  trademarks, or service marks; or\n- f) Requiring indemnification of licensors and authors of that material by\n  anyone who conveys the material (or modified versions of it) with contractual\n  assumptions of liability to the recipient, for any liability that these\n  contractual assumptions directly impose on those licensors and authors.\n\nAll other non-permissive additional terms are considered \"further restrictions\"\nwithin the meaning of section 10. If the Program as you received it, or any part\nof it, contains a notice stating that it is governed by this License along with\na term that is a further restriction, you may remove that term. If a license\ndocument contains a further restriction but permits relicensing or conveying\nunder this License, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does not survive\nsuch relicensing or conveying.\n\nIf you add terms to a covered work in accord with this section, you must place,\nin the relevant source files, a statement of the additional terms that apply to\nthose files, or a notice indicating where to find the applicable terms.\n\nAdditional terms, permissive or non-permissive, may be stated in the form of a\nseparately written license, or stated as exceptions; the above requirements\napply either way.\n\n#### 8. Termination.\n\nYou may not propagate or modify a covered work except as expressly provided\nunder this License. Any attempt otherwise to propagate or modify it is void, and\nwill automatically terminate your rights under this License (including any\npatent licenses granted under the third paragraph of section 11).\n\nHowever, if you cease all violation of this License, then your license from a\nparticular copyright holder is reinstated (a) provisionally, unless and until\nthe copyright holder explicitly and finally terminates your license, and (b)\npermanently, if the copyright holder fails to notify you of the violation by\nsome reasonable means prior to 60 days after the cessation.\n\nMoreover, your license from a particular copyright holder is reinstated\npermanently if the copyright holder notifies you of the violation by some\nreasonable means, this is the first time you have received notice of violation\nof this License (for any work) from that copyright holder, and you cure the\nviolation prior to 30 days after your receipt of the notice.\n\nTermination of your rights under this section does not terminate the licenses of\nparties who have received copies or rights from you under this License. If your\nrights have been terminated and not permanently reinstated, you do not qualify\nto receive new licenses for the same material under section 10.\n\n#### 9. Acceptance Not Required for Having Copies.\n\nYou are not required to accept this License in order to receive or run a copy of\nthe Program. Ancillary propagation of a covered work occurring solely as a\nconsequence of using peer-to-peer transmission to receive a copy likewise does\nnot require acceptance. However, nothing other than this License grants you\npermission to propagate or modify any covered work. These actions infringe\ncopyright if you do not accept this License. Therefore, by modifying or\npropagating a covered work, you indicate your acceptance of this License to do\nso.\n\n#### 10. Automatic Licensing of Downstream Recipients.\n\nEach time you convey a covered work, the recipient automatically receives a\nlicense from the original licensors, to run, modify and propagate that work,\nsubject to this License. You are not responsible for enforcing compliance by\nthird parties with this License.\n\nAn \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations. If propagation of a covered work results\nfrom an entity transaction, each party to that transaction who receives a copy\nof the work also receives whatever licenses to the work the party's predecessor\nin interest had or could give under the previous paragraph, plus a right to\npossession of the Corresponding Source of the work from the predecessor in\ninterest, if the predecessor has it or can get it with reasonable efforts.\n\nYou may not impose any further restrictions on the exercise of the rights\ngranted or affirmed under this License. For example, you may not impose a\nlicense fee, royalty, or other charge for exercise of rights granted under this\nLicense, and you may not initiate litigation (including a cross-claim or\ncounterclaim in a lawsuit) alleging that any patent claim is infringed by\nmaking, using, selling, offering for sale, or importing the Program or any\nportion of it.\n\n#### 11. Patents.\n\nA \"contributor\" is a copyright holder who authorizes use under this License of\nthe Program or a work on which the Program is based. The work thus licensed is\ncalled the contributor's \"contributor version\".\n\nA contributor's \"essential patent claims\" are all patent claims owned or\ncontrolled by the contributor, whether already acquired or hereafter acquired,\nthat would be infringed by some manner, permitted by this License, of making,\nusing, or selling its contributor version, but do not include claims that would\nbe infringed only as a consequence of further modification of the contributor\nversion. For purposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of this License.\n\nEach contributor grants you a non-exclusive, worldwide, royalty-free patent\nlicense under the contributor's essential patent claims, to make, use, sell,\noffer for sale, import and otherwise run, modify and propagate the contents of\nits contributor version.\n\nIn the following three paragraphs, a \"patent license\" is any express agreement\nor commitment, however denominated, not to enforce a patent (such as an express\npermission to practice a patent or covenant not to sue for patent infringement).\nTo \"grant\" such a patent license to a party means to make such an agreement or\ncommitment not to enforce a patent against the party.\n\nIf you convey a covered work, knowingly relying on a patent license, and the\nCorresponding Source of the work is not available for anyone to copy, free of\ncharge and under the terms of this License, through a publicly available network\nserver or other readily accessible means, then you must either (1) cause the\nCorresponding Source to be so available, or (2) arrange to deprive yourself of\nthe benefit of the patent license for this particular work, or (3) arrange, in a\nmanner consistent with the requirements of this License, to extend the patent\nlicense to downstream recipients. \"Knowingly relying\" means you have actual\nknowledge that, but for the patent license, your conveying the covered work in a\ncountry, or your recipient's use of the covered work in a country, would\ninfringe one or more identifiable patents in that country that you have reason\nto believe are valid.\n\nIf, pursuant to or in connection with a single transaction or arrangement, you\nconvey, or propagate by procuring conveyance of, a covered work, and grant a\npatent license to some of the parties receiving the covered work authorizing\nthem to use, propagate, modify or convey a specific copy of the covered work,\nthen the patent license you grant is automatically extended to all recipients of\nthe covered work and works based on it.\n\nA patent license is \"discriminatory\" if it does not include within the scope of\nits coverage, prohibits the exercise of, or is conditioned on the non-exercise\nof one or more of the rights that are specifically granted under this License.\nYou may not convey a covered work if you are a party to an arrangement with a\nthird party that is in the business of distributing software, under which you\nmake payment to the third party based on the extent of your activity of\nconveying the work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory patent\nlicense (a) in connection with copies of the covered work conveyed by you (or\ncopies made from those copies), or (b) primarily for and in connection with\nspecific products or compilations that contain the covered work, unless you\nentered into that arrangement, or that patent license was granted, prior to 28\nMarch 2007.\n\nNothing in this License shall be construed as excluding or limiting any implied\nlicense or other defenses to infringement that may otherwise be available to you\nunder applicable patent law.\n\n#### 12. No Surrender of Others' Freedom.\n\nIf conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not excuse\nyou from the conditions of this License. If you cannot convey a covered work so\nas to satisfy simultaneously your obligations under this License and any other\npertinent obligations, then as a consequence you may not convey it at all. For\nexample, if you agree to terms that obligate you to collect a royalty for\nfurther conveying from those to whom you convey the Program, the only way you\ncould satisfy both those terms and this License would be to refrain entirely\nfrom conveying the Program.\n\n#### 13. Remote Network Interaction; Use with the GNU General Public License.\n\nNotwithstanding any other provision of this License, if you modify the Program,\nyour modified version must prominently offer all users interacting with it\nremotely through a computer network (if your version supports such interaction)\nan opportunity to receive the Corresponding Source of your version by providing\naccess to the Corresponding Source from a network server at no charge, through\nsome standard or customary means of facilitating copying of software. This\nCorresponding Source shall include the Corresponding Source for any work covered\nby version 3 of the GNU General Public License that is incorporated pursuant to\nthe following paragraph.\n\nNotwithstanding any other provision of this License, you have permission to link\nor combine any covered work with a work licensed under version 3 of the GNU\nGeneral Public License into a single combined work, and to convey the resulting\nwork. The terms of this License will continue to apply to the part which is the\ncovered work, but the work with which it is combined will remain governed by\nversion 3 of the GNU General Public License.\n\n#### 14. Revised Versions of this License.\n\nThe Free Software Foundation may publish revised and/or new versions of the GNU\nAffero General Public License from time to time. Such new versions will be\nsimilar in spirit to the present version, but may differ in detail to address\nnew problems or concerns.\n\nEach version is given a distinguishing version number. If the Program specifies\nthat a certain numbered version of the GNU Affero General Public License \"or any\nlater version\" applies to it, you have the option of following the terms and\nconditions either of that numbered version or of any later version published by\nthe Free Software Foundation. If the Program does not specify a version number\nof the GNU Affero General Public License, you may choose any version ever\npublished by the Free Software Foundation.\n\nIf the Program specifies that a proxy can decide which future versions of the\nGNU Affero General Public License can be used, that proxy's public statement of\nacceptance of a version permanently authorizes you to choose that version for\nthe Program.\n\nLater license versions may give you additional or different permissions.\nHowever, no additional obligations are imposed on any author or copyright holder\nas a result of your choosing to follow a later version.\n\n#### 15. Disclaimer of Warranty.\n\nTHERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER\nPARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER\nEXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE\nQUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE\nDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n#### 16. Limitation of Liability.\n\nIN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY\nCOPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS\nPERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,\nINCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE\nTHE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED\nINACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE\nPROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY\nHAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n#### 17. Interpretation of Sections 15 and 16.\n\nIf the disclaimer of warranty and limitation of liability provided above cannot\nbe given local legal effect according to their terms, reviewing courts shall\napply local law that most closely approximates an absolute waiver of all civil\nliability in connection with the Program, unless a warranty or assumption of\nliability accompanies a copy of the Program in return for a fee.\n\nEND OF TERMS AND CONDITIONS\n\n### How to Apply These Terms to Your New Programs\n\nIf you develop a new program, and you want it to be of the greatest possible use\nto the public, the best way to achieve this is to make it free software which\neveryone can redistribute and change under these terms.\n\nTo do so, attach the following notices to the program. It is safest to attach\nthem to the start of each source file to most effectively state the exclusion of\nwarranty; and each file should have at least the \"copyright\" line and a pointer\nto where the full notice is found.\n\n        Better introductions for websites and features with a step-by-step guide for your projects.\n        Copyright (C) 2012-2021 Afshin Mehrabani\n\n        This program is free software: you can redistribute it and/or modify\n        it under the terms of the GNU Affero General Public License as\n        published by the Free Software Foundation, either version 3 of the\n        License, or (at your option) any later version.\n\n        This program is distributed in the hope that it will be useful,\n        but WITHOUT ANY WARRANTY; without even the implied warranty of\n        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n        GNU Affero General Public License for more details.\n\n        You should have received a copy of the GNU Affero General Public License\n        along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf your software can interact with users remotely through a computer network,\nyou should also make sure that it provides a way for users to get its source.\nFor example, if your program is a web application, its interface could display a\n\"Source\" link that leads users to an archive of the code. There are many ways\nyou could offer source, and different solutions will be better for different\nprograms; see section 13 for the specific requirements.\n\nYou should also get your employer (if you work as a programmer) or school, if\nany, to sign a \"copyright disclaimer\" for the program, if necessary. For more\ninformation on this, and how to apply and follow the GNU AGPL, see\n<https://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img \n    alt=\"Shepherd.js Logo\"\n    src=\"https://i.imgur.com/cowwtSX.png\"/>\n</p>\n  \n\n[![npm version](https://badge.fury.io/js/shepherd.js.svg)](http://badge.fury.io/js/shepherd.js)\n![Download count all time](https://img.shields.io/npm/dt/shepherd.js.svg)\n![npm](https://img.shields.io/npm/dm/shepherd.js.svg)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fshipshapecode%2Fshepherd.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%shipshapecode%2Fshepherd?ref=badge_shield)\n![npm bundle size](https://img.shields.io/bundlephobia/minzip/shepherd.js.svg)\n[![Test](https://github.com/shipshapecode/shepherd/actions/workflows/test.yml/badge.svg)](https://github.com/shipshapecode/shepherd/actions/workflows/test.yml)\n[![Maintainability](https://qlty.sh/gh/shipshapecode/projects/shepherd/maintainability.svg)](https://qlty.sh/gh/shipshapecode/projects/shepherd)\n[![Code Coverage](https://qlty.sh/gh/shipshapecode/projects/shepherd/coverage.svg)](https://qlty.sh/gh/shipshapecode/projects/shepherd)\n[![StackShare](https://img.shields.io/badge/Follow%20on-StackShare-blue.svg?logo=stackshare&style=flat)](https://stackshare.io/shepherd-js)  \n\n[Shepherd](https://shepherdjs.dev/) is an open source, fully featured, digital adoption platform (DAP) and user on-boarding service.\n\nSupported Browsers\n----------------------------------------------------------\n\n| [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\" alt=\"IE / Edge\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\" alt=\"Firefox\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\" alt=\"Chrome\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src=\"https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\" alt=\"Safari\" width=\"24px\" height=\"24px\" />](http://godban.github.io/browsers-support-badges/)</br>Safari |\n| --------- | --------- | --------- | --------- |\n| Edge| last 2 versions| last 2 versions| last 2 versions\n\n# Shepherd\n\nShepherd makes it simple to create custom user on-boarding tours, trainings and announcements to drive user adoption. \n\nShepherd enables you to guide users through a custom tour or journey within your app or website. Highly customizable with minimal styles, Shepherd allows for powerful customization while being easy to use. Various frameworks supported including React, Ember, Angular, Vue.js, ES Modules, or plain JavaScript. \n\n# Demo\nSee Shepherd Live on our website by clicking on the image:\n<a href=\"https://shepherdjs.dev\">\n  <img \n    src=\"https://shepherdjs.dev/img/demo.png\" \n    alt=\"Guide your users through a tour of your app\" \n    style=\"height: auto; max-width: 800px; width: 100%;\"/>\n</a>\n\n# Using Shepherd\n\n### Shepherd Open Source Library\n\nThe Shepherd Standalone Library has been open source since the very beginning. Check out our tutorials here:\n\n#### [React Shepherd Wrapper](packages/react)\n#### [Angular Shepherd Wrapper](https://github.com/shipshapecode/angular-shepherd)\n#### [Vue Shepherd Wrapper](https://github.com/shipshapecode/vue-shepherd)\n#### [Ember Shepherd Wrapper](https://github.com/RobbieTheWagner/ember-shepherd)\n\n\n# White Glove Services\n\nIf you have an idea or project in mind and would like to engage our team to build a custom tour, training or on-boarding experience, [get in touch](mailto:ahoy@shipshape.io)! \n\n\n## Resources\n\n- [Website](https://shepherdjs.dev/)\n- [Documentation](https://docs.shepherdjs.dev/)\n- [Demo](https://shepherdjs.dev/)\n- [Discord](https://discord.gg/EGcDW5NSud)\n\n\n## Contributing\n\nWe encourage contributions of all kinds. If you would like to contribute in some way, please review our [guidelines for contributing](CONTRIBUTING.md).\nOur release process is mostly automated. For more details, see [RELEASE.md](RELEASE.md).\n\n\n## Projects Already Using Shepherd\n\n### Rails gems\n\n### [abraham](https://github.com/actmd/abraham)\n\nRails engine that generates and tracks Shepherd tours within an application\n\n### Websites and Apps\n\n### [SimplePlanner](https://simpleplanner.io)\n\n[SimplePlanner](https://simpleplanner.io) uses Shepherd to help new users get familiar with its collaborative scheduling approach. \nYou do need to sign up via OAuth or email to see the scheduling tour. \nCheck out the [Envato Tuts+ Startup Series on its codebase](https://code.tutsplus.com/series/building-your-startup-with-php--cms-742) which describes how Simple Planner was built.\n\n### [LogSeq](https://logseq.com/) \n\n[LogSeq](https://logseq.com/) uses Shepherd to guide users through initial setup steps.\n\n### [Snapsure](https://snapsure.app)\n\n[Snapsure](https://snapsure.app) uses Shepherd to help photographers learn how to set up alerts for their desired picture-perfect weather conditions.\n\n### [Drupal](https://www.drupal.org/docs/8/core/modules/tour/overview)\n\nThe [Drupal](https://www.drupal.org/docs/8/core/modules/tour/overview) CMS uses Shepherd to offer tours of it's core modules, and allows developers to add Tours to their custom and contributed modules.\n\n### [Budibase Shepherd Tour Plugin](https://github.com/JayP718/tour_shepherd_bb_plugin)\n\n[Budibase](https://budibase.com/) is an open source application which allows you develop low code applications rapidly and efficiently.This [Budibase](https://budibase.com/) Shepherd tour plugin allows you to create interative walkthroughs for your application.\n\n\n### Your Project Here\n\nIf you have a cool open-source library built on Shepherd, PR this doc.\n\n\n## License\n\nShepherd.js is dual-licensed under AGPL-3.0 and a Commercial License.\n\n- **Free for open source and non-commercial use** under AGPL-3.0\n- **Commercial license required** for commercial products and revenue-generating companies\n\nSee [LICENSE.md](LICENSE.md) for complete details or visit [shepherdjs.dev/pricing](https://shepherdjs.dev/pricing) to purchase a commercial license.\n\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fshipshapecode%2Fshepherd.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fshipshapecode%2Fshepherd?ref=badge_large)\n"
  },
  {
    "path": "RELEASE.md",
    "content": "# Release Process\n\nReleases in this repo are mostly automated using [release-plan](https://github.com/embroider-build/release-plan/). Once you label all your PRs correctly (see below) you will have an automatically generated PR that updates your CHANGELOG.md file and a `.release-plan.json` that is used to prepare the release once the PR is merged.\n\n## Preparation\n\nSince the majority of the actual release process is automated, the remaining tasks before releasing are:\n\n- correctly labeling **all** pull requests that have been merged since the last release\n- updating pull request titles so they make sense to our users\n\nSome great information on why this is important can be found at [keepachangelog.com](https://keepachangelog.com/en/1.1.0/), but the overall\nguiding principle here is that changelogs are for humans, not machines.\n\nWhen reviewing merged PR's the labels to be used are:\n\n- breaking - Used when the PR is considered a breaking change.\n- enhancement - Used when the PR adds a new feature or enhancement.\n- bug - Used when the PR fixes a bug included in a previous release.\n- documentation - Used when the PR adds or updates documentation.\n- internal - Internal changes or things that don't fit in any other category.\n\n**Note:** `release-plan` requires that **all** PRs are labeled. If a PR doesn't fit in a category it's fine to label it as `internal`\n\n## Release\n\nOnce the prep work is completed, the actual release is straight forward: you just need to merge the open [Plan Release](https://github.com/shipshapecode/shepherd/pulls?q=is%3Apr+is%3Aopen+%22Prepare+Release%22+in%3Atitle) PR\n"
  },
  {
    "path": "docs-src/.dockerignore",
    "content": "# build output\ndist/\n# generated types\n.astro/\n\n# dependencies\nnode_modules/\n\n# logs\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n\n# environment variables\n.env\n.env.production\n\n# macOS-specific files\n.DS_Store\n"
  },
  {
    "path": "docs-src/.gitignore",
    "content": "# build output\ndist/\n# generated types\n.astro/\n\n# dependencies\nnode_modules/\n\n# generated api docs\nsrc/content/docs/api/*\n\n# logs\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n\n# environment variables\n.env\n.env.production\n\n# macOS-specific files\n.DS_Store\n"
  },
  {
    "path": "docs-src/.vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\"astro-build.astro-vscode\"],\n  \"unwantedRecommendations\": []\n}\n"
  },
  {
    "path": "docs-src/.vscode/launch.json",
    "content": "{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"command\": \"./node_modules/.bin/astro dev\",\n      \"name\": \"Development server\",\n      \"request\": \"launch\",\n      \"type\": \"node-terminal\"\n    }\n  ]\n}\n"
  },
  {
    "path": "docs-src/Dockerfile",
    "content": "# syntax = docker/dockerfile:1\n\n# Adjust NODE_VERSION as desired\nARG NODE_VERSION=20.10.0\nFROM node:${NODE_VERSION}-slim as base\n\nLABEL fly_launch_runtime=\"Astro\"\n\n# Astro app lives here\nWORKDIR /app\n\n# Set production environment\nENV NODE_ENV=\"production\"\n\n# Install pnpm\nARG PNPM_VERSION=9.2.0\nRUN npm install -g pnpm@$PNPM_VERSION\n\n\n# Throw-away build stage to reduce size of final image\nFROM base as build\n\n# Install packages needed to build node modules\nRUN apt-get update -qq && \\\n    apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3\n\n# Install node modules\nCOPY --link package.json pnpm-lock.yaml pnpm-workspace.yaml ./\n\n# Copy library code\nCOPY --link ./shepherd.js ./shepherd.js\n\n# Copy application code\nCOPY --link ./docs-src ./docs-src\nRUN pnpm install --frozen-lockfile --prod=false\n\n# Build application\nRUN pnpm -F shepherd-docs run build\n\n# Remove development dependencies\nRUN pnpm prune --prod\n\n\n# Final stage for app image\nFROM nginx\n\n# Copy built application\nCOPY --from=build /app/docs-src/dist /usr/share/nginx/html\n\n# Start the server by default, this can be overwritten at runtime\nEXPOSE 80\nCMD [ \"/usr/sbin/nginx\", \"-g\", \"daemon off;\" ]\n"
  },
  {
    "path": "docs-src/README.md",
    "content": "# Starlight Starter Kit: Basics\n\n[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)\n\n```\nnpm create astro@latest -- --template starlight\n```\n\n[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)\n[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)\n[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwithastro%2Fstarlight%2Ftree%2Fmain%2Fexamples%2Fbasics&project-name=my-starlight-docs&repository-name=my-starlight-docs)\n\n> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!\n\n## 🚀 Project Structure\n\nInside of your Astro + Starlight project, you'll see the following folders and files:\n\n```\n.\n├── public/\n├── src/\n│   ├── assets/\n│   ├── content/\n│   │   ├── docs/\n│   │   └── config.ts\n│   └── env.d.ts\n├── astro.config.mjs\n├── package.json\n└── tsconfig.json\n```\n\nStarlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.\n\nImages can be added to `src/assets/` and embedded in Markdown with a relative link.\n\nStatic assets, like favicons, can be placed in the `public/` directory.\n\n## 🧞 Commands\n\nAll commands are run from the root of the project, from a terminal:\n\n| Command                   | Action                                           |\n| :------------------------ | :----------------------------------------------- |\n| `npm install`             | Installs dependencies                            |\n| `npm run dev`             | Starts local dev server at `localhost:4321`      |\n| `npm run build`           | Build your production site to `./dist/`          |\n| `npm run preview`         | Preview your build locally, before deploying     |\n| `npm run astro ...`       | Run CLI commands like `astro add`, `astro check` |\n| `npm run astro -- --help` | Get help using the Astro CLI                     |\n\n## 👀 Want to learn more?\n\nCheck out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).\n"
  },
  {
    "path": "docs-src/astro.config.mjs",
    "content": "import { defineConfig } from 'astro/config';\nimport starlight from '@astrojs/starlight';\n\nimport starlightTypeDoc, { typeDocSidebarGroup } from 'starlight-typedoc';\n\n// https://astro.build/config\nexport default defineConfig({\n  integrations: [\n    starlight({\n      title: 'Documentation',\n      description:\n        'Shepherd is a way for guiding users through your app to that moment of \"aha!\".',\n      logo: {\n        src: './src/assets/Shepherd-Lamb.svg'\n      },\n      favicon: '/favicon.ico',\n      social: [\n        {\n          icon: 'github',\n          label: 'GitHub',\n          href: 'https://github.com/shipshapecode/shepherd'\n        },\n        {\n          icon: 'discord',\n          label: 'Discord',\n          href: 'https://discord.gg/EGcDW5NSud'\n        }\n      ],\n      components: {\n        // Override the default `Head` component.\n        Head: './src/components/HeadWithPosthog.astro'\n      },\n      plugins: [\n        starlightTypeDoc({\n          entryPoints: ['./node_modules/shepherd.js/src/*.ts'],\n          tsconfig: './node_modules/shepherd.js/tsconfig.json',\n          typeDoc: {\n            entryPointStrategy: 'expand',\n            includeVersion: true\n          }\n        })\n      ],\n      sidebar: [\n        {\n          label: 'Guides',\n          items: [\n            {\n              label: 'Install',\n              link: '/guides/install/'\n            },\n            {\n              label: 'Styling',\n              link: '/guides/styling/'\n            },\n            {\n              label: 'Usage',\n              link: '/guides/usage/'\n            },\n            {\n              label: 'License & Pricing',\n              link: '/guides/license/'\n            }\n          ]\n        },\n        {\n          label: 'Recipes',\n          items: [\n            {\n              label: 'Cookbook',\n              link: '/recipes/cookbook/'\n            },\n            {\n              label: 'Analytics',\n              link: '/guides/analytics/'\n            },\n            {\n              label: 'React',\n              link: '/recipes/react/'\n            }\n          ]\n        },\n        // {\n        //   label: 'Reference',\n        //   autogenerate: {\n        //     directory: 'reference'\n        //   }\n        // },\n        typeDocSidebarGroup\n      ]\n    })\n  ]\n});\n"
  },
  {
    "path": "docs-src/fly.toml",
    "content": "# fly.toml app configuration file generated for shepherd-docs on 2024-04-23T14:17:39-07:00\n#\n# See https://fly.io/docs/reference/configuration/ for information about how to use this file.\n#\n\napp = 'shepherd-docs'\nprimary_region = 'dfw'\n\n[build]\n\n[http_service]\n  internal_port = 80\n  force_https = true\n  auto_stop_machines = true\n  auto_start_machines = true\n  min_machines_running = 0\n  processes = ['app']\n\n[[vm]]\n  memory = '1gb'\n  cpu_kind = 'shared'\n  cpus = 1\n"
  },
  {
    "path": "docs-src/package.json",
    "content": "{\n  \"name\": \"shepherd-docs\",\n  \"type\": \"module\",\n  \"version\": \"0.0.6\",\n  \"private\": \"true\",\n  \"scripts\": {\n    \"dev\": \"astro dev\",\n    \"start\": \"astro dev\",\n    \"build\": \"astro check && astro build\",\n    \"preview\": \"astro preview\",\n    \"astro\": \"astro\"\n  },\n  \"dependencies\": {\n    \"@astrojs/starlight\": \"^0.37.6\",\n    \"astro\": \"^5.18.0\",\n    \"shepherd.js\": \"workspace:*\",\n    \"starlight-typedoc\": \"^0.21.5\"\n  },\n  \"devDependencies\": {\n    \"@astrojs/check\": \"^0.9.8\",\n    \"@flydotio/dockerfile\": \"^0.7.10\",\n    \"sharp\": \"^0.34.5\",\n    \"typedoc\": \"^0.28.17\",\n    \"typedoc-plugin-markdown\": \"^4.10.0\",\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "docs-src/src/components/HeadWithPosthog.astro",
    "content": "---\nimport type { Props } from '@astrojs/starlight/props';\nimport Default from '@astrojs/starlight/components/Head.astro';\nimport PostHog from './Posthog.astro';\n---\n\n<Default {...Astro.props}><slot /></Default>\n<PostHog />\n"
  },
  {
    "path": "docs-src/src/components/Posthog.astro",
    "content": "<script is:inline>\n  !(function (t, e) {\n    var o, n, p, r;\n    e.__SV ||\n      ((window.posthog = e),\n      (e._i = []),\n      (e.init = function (i, s, a) {\n        function g(t, e) {\n          var o = e.split('.');\n          2 == o.length && ((t = t[o[0]]), (e = o[1])),\n            (t[e] = function () {\n              t.push([e].concat(Array.prototype.slice.call(arguments, 0)));\n            });\n        }\n        ((p = t.createElement('script')).type = 'text/javascript'),\n          (p.async = !0),\n          (p.src = s.api_host + '/static/array.js'),\n          (r = t.getElementsByTagName('script')[0]).parentNode.insertBefore(\n            p,\n            r\n          );\n        var u = e;\n        for (\n          void 0 !== a ? (u = e[a] = []) : (a = 'posthog'),\n            u.people = u.people || [],\n            u.toString = function (t) {\n              var e = 'posthog';\n              return (\n                'posthog' !== a && (e += '.' + a), t || (e += ' (stub)'), e\n              );\n            },\n            u.people.toString = function () {\n              return u.toString(1) + '.people (stub)';\n            },\n            o =\n              'capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys onSessionId'.split(\n                ' '\n              ),\n            n = 0;\n          n < o.length;\n          n++\n        )\n          g(u, o[n]);\n        e._i.push([i, s, a]);\n      }),\n      (e.__SV = 1));\n  })(document, window.posthog || []);\n  posthog.init('phc_sl7TroBwU2fA7dJVU70ZV5u0575fQNWYv1GK5enODkX', {\n    api_host: 'https://us.i.posthog.com'\n  });\n</script>\n"
  },
  {
    "path": "docs-src/src/content/config.ts",
    "content": "import { defineCollection } from 'astro:content';\nimport { docsSchema } from '@astrojs/starlight/schema';\n\nexport const collections = {\n\tdocs: defineCollection({ schema: docsSchema() }),\n};\n"
  },
  {
    "path": "docs-src/src/content/docs/api/README.md",
    "content": "---\neditUrl: false\nnext: false\nprev: false\ntitle: \"shepherd.js\"\n---\n\n## Modules\n\n- [evented](/api/evented/readme/)\n- [shepherd](/api/shepherd/readme/)\n- [step](/api/step/readme/)\n- [tour](/api/tour/readme/)\n"
  },
  {
    "path": "docs-src/src/content/docs/guides/analytics.mdx",
    "content": "---\ntitle: Analytics\n---\n\nWith Shepherd, you can track the progress of your users through your app journey. e.g., This can be useful for understanding how users are interacting with your site, and where they might be getting stuck. \n\n## Tracking\nEvents occur at each step of the journey, and can be tracked using the `on` method of a `Tour` instance. The most obvious way to track is with the following events: `active`, `cancel`, `complete`, `show`.\n\n### Active\nThis event triggers when the tour itself becomes active. This means that the tour is ready and not necessarily that the first step is shown.\n\n### Cancel\nAt any point, if the user cancels the tour, this event will trigger.\n\n### Complete\nWhen the user completes the tour, this event will trigger. This means that the user has gone through all the steps in the tour.\n\n### Show\nThis event triggers when a step is shown to the user.\n\n\n## Exposing the Analytics\nIn order to start tracking, just tell Shepherd what you want to do when one of the events is fired.\n\n```javascript\nconst shepherd = new Shepherd.Tour();\nconst trackedEvents = ['active', 'cancel', 'complete', 'show'];\n\nshepherd.on('start', (eventOptions) => { ... });\nshepherd.start(); //the above will fire and run the function\n```"
  },
  {
    "path": "docs-src/src/content/docs/guides/install.mdx",
    "content": "---\ntitle: Installation\n---\n\nimport { Tabs, TabItem } from '@astrojs/starlight/components';\n\n:::note[License Information]\nShepherd.js is **free for open source and non-commercial use** under AGPL-3.0. Commercial projects require a commercial license. [Learn more about licensing →](/guides/license/)\n:::\n\n## Install Directly\n\n<Tabs>\n  <TabItem label=\"npm\">\n  ```bash \n  npm install shepherd.js --save \n  ```\n  </TabItem>\n  <TabItem label=\"yarn\">\n  ```bash \n  yarn add shepherd.js \n  ```\n  </TabItem>\n  <TabItem label=\"pnpm\">\n  ```bash \n  pnpm add shepherd.js \n  ```\n  </TabItem>\n  <TabItem label=\"bun\">\n  ```bash \n  bun add shepherd.js \n  ```\n  </TabItem>\n</Tabs>\n\n### styles\n\nDon't forget to add your styles\n\n```javascript\nimport 'shepherd.js/dist/css/shepherd.css';\n```\n\n### GitHub Releases\n\nWhenever we release a new version, the contents of the `dist` are uploaded\nto the release in GitHub. You can find those assets [here](https://github.com/shipshapecode/shepherd/releases).\n\n### jsDelivr CDN\n\nYou can use jsDelivr to pull down any release from npm. For example, you could include v10.0.1 with styles in your app\nwith:\n\n```html\n<script\n  type=\"module\"\n  src=\"https://cdn.jsdelivr.net/npm/shepherd.js@17.0.0/dist/js/shepherd.mjs\"\n></script>\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/shepherd.js@17.0.0/dist/css/shepherd.css\"\n/>\n```\n\n## JS Framework Wrappers\n\nWe strive to make it easy to use Shepherd in all the major frameworks, and have written wrappers to facilitate this.\n\n- [angular-shepherd](https://github.com/shipshapecode/angular-shepherd)\n- [ember-shepherd](https://github.com/shipshapecode/ember-shepherd)\n- [react-shepherd](https://github.com/shipshapecode/shepherd/tree/main/packages/react)\n- [vue-shepherd](https://github.com/shipshapecode/vue-shepherd)\n"
  },
  {
    "path": "docs-src/src/content/docs/guides/license.mdx",
    "content": "---\ntitle: License & Pricing\ndescription: Understanding Shepherd.js licensing and when you need a commercial license\n---\n\nShepherd.js uses a **dual-licensing model** to support both open source and commercial use.\n\n## Free Use - AGPL-3.0\n\nShepherd.js is **free for open source and non-commercial use** under the AGPL-3.0 license.\n\n### Who Can Use Shepherd.js for Free?\n\n✅ **Open Source Projects**\n- Your project is open source under an AGPL-compatible license\n- Your complete source code is publicly available\n\n✅ **Personal & Non-Commercial Use**\n- Personal projects, portfolios, and hobby websites\n- Educational purposes (students, teachers, coursework)\n- Academic research projects\n\n✅ **Evaluation & Testing**\n- Evaluating Shepherd.js for up to 30 days\n- Development, testing, and staging environments during evaluation\n- Proof-of-concept and demo projects\n\n### AGPL-3.0 Requirements\n\nWhen using Shepherd.js under AGPL-3.0, you must:\n- Make your complete source code available if you distribute or provide your software over a network\n- License your code under AGPL-3.0 or a compatible license\n- Comply with all AGPL-3.0 terms\n\n[Read the full AGPL-3.0 license text](https://github.com/shipshapecode/shepherd/blob/main/LICENSE.md)\n\n---\n\n## Commercial License\n\nYou **must purchase a commercial license** if:\n\n❌ **Commercial Products & Services**\n- You're building a commercial product, application, SaaS, or website that generates revenue\n- Your company generates revenue (even if the specific project using Shepherd.js does not)\n- You're using Shepherd.js in any customer-facing commercial application\n\n❌ **Closed-Source Use**\n- You cannot or don't want to open-source your code under AGPL-3.0\n- You want to keep your source code proprietary\n- You want to avoid AGPL's source code disclosure requirements\n\n❌ **White-Label, Resale, or OEM Use**\n- You're embedding Shepherd.js in a product you sell or distribute\n- You're offering Shepherd.js as part of a commercial service or hosting\n- You're using Shepherd.js in a product sold to other businesses\n\n❌ **Internal Business Tools**\n- You're using Shepherd.js for internal tools, dashboards, or admin panels in a revenue-generating company\n- Even if the tool is not customer-facing, commercial licenses are required for for-profit companies\n\n### Benefits of Commercial License\n\n- ✅ **No AGPL obligations** - Keep your code proprietary\n- ✅ **Legal protection and indemnification**\n- ✅ **Priority support and updates**\n- ✅ **Lifetime license with no recurring fees**\n\n[**View Pricing & Purchase →**](https://shepherdjs.dev/pricing)\n\n---\n\n## Still Not Sure?\n\nIf you're unsure whether you need a commercial license:\n\n**When in doubt:** If your organization generates revenue, you likely need a commercial license.\n\n**Contact us:** [ahoy@shipshape.io](mailto:ahoy@shipshape.io)\n\n---\n\n## Framework Wrappers\n\n### React Shepherd\n\nThe `react-shepherd` wrapper is licensed under MIT, but it depends on `shepherd.js` which is AGPL-3.0. \n\nIf you need a commercial license for Shepherd.js, you also need one when using the React wrapper.\n\n### Other Wrappers\n\n- [Angular Shepherd](https://github.com/shipshapecode/angular-shepherd)\n- [Vue Shepherd](https://github.com/shipshapecode/vue-shepherd)\n- [Ember Shepherd](https://github.com/RobbieTheWagner/ember-shepherd)\n\nAll wrappers depend on the core Shepherd.js library and inherit its licensing requirements.\n"
  },
  {
    "path": "docs-src/src/content/docs/guides/styling.md",
    "content": "---\ntitle: Styling\n---\n\n### Default Styles\n\nShepherd ships with some default styles, but we try to keep it minimal, so you do not have a ton to override.\nYou can also opt out of styles entirely, by not including the `shepherd.css` file.\n\n### Custom Classes\n\nIf you'd like to change styles within your own CSS, you can pass custom class names to the tour instance &mdash;\nor, as part of the options for each step &mdash; and use them as hooks for your own styling rules.\n\n```javascript\nlet tour = new Shepherd.Tour({\n  defaultStepOptions: {\n    classes: 'shepherd-theme-custom'\n  }\n});\n```\n\n### Adding a prefix to the default `shepherd-*` classes\n\nIf you have a situation where you are running two Shepherd instances on a page, and they need to be styled\ndifferently, you may want to prefix the class names. This is now possible with the `classPrefix` option.\n\n```js\nconst tour = new Shepherd.Tour({\n  classPrefix: 'my-tour-'\n});\n```\n"
  },
  {
    "path": "docs-src/src/content/docs/guides/usage.md",
    "content": "---\ntitle: Usage\n---\n\n### Rollup/Webpack Based Builds\n\nThe latest versions of Rollup and Webpack support ES6 imports. Shepherd ships as\nan ES module which should allow you to import using standard ES import syntax.\n\ni.e.\n\n```js\nimport Shepherd from 'shepherd.js';\n```\n\nFirst create a new `Tour` instance for your tour:\n\n```javascript\nconst tour = new Shepherd.Tour({\n  useModalOverlay: true,\n  defaultStepOptions: {\n    classes: 'shadow-md bg-purple-dark',\n    scrollTo: true\n  }\n});\n```\n\nThe `defaultStepOptions` option allows you to specify any options which should\nbe applied to all this tour's steps by default.\n\nNext, add your steps:\n\n```javascript\ntour.addStep({\n  id: 'example-step',\n  text: 'This step is attached to the bottom of the <code>.example-css-selector</code> element.',\n  attachTo: {\n    element: '.example-css-selector',\n    on: 'bottom'\n  },\n  classes: 'example-step-extra-class',\n  buttons: [\n    {\n      text: 'Next',\n      action: tour.next\n    }\n  ]\n});\n```\n\nFinally, to start the tour, just call `start` on your `Tour` instance:\n\n```javascript\ntour.start();\n```\n\nIf you need to remove a step from your tour, call `removeStep` on your `Tour`\ninstance. If the step currently being displayed is the one you're removing, and\nthere are steps left in the tour, then the first one will be shown, otherwise,\nthe tour will be cancelled.\n\n```javascript\ntour.removeStep('example-step');\n```\n\n### API\n\n#### Global Shepherd Object\n\nShepherd exposes a single object onto the window, `Shepherd`.\n\nThat global object fires several events to let you link up actions with events\noccurring in _any_ tour:\n\n##### Methods\n\n- `Shepherd.on(eventName, handler, [context])`: Bind an event\n- `Shepherd.off(eventName, [handler])`: Unbind an event\n- `Shepherd.once(eventName, handler, [context])`: Bind just the next instance of\n  an event\n\n##### Events\n\nThe global Shepherd fires the following events whenever a `Tour` instance fires\nthem. It adds to the object passed to the event handlers a `tour` key pointing\nto the instance which fired the event:\n\n- `complete`\n- `cancel`\n- `hide`\n- `show`\n- `start`\n- `active`\n- `inactive`\n\nFor multiple events, you can use something like:\n\n```javascript\n['complete', 'cancel'].forEach((event) =>\n  shepherd.on(event, () => {\n    // some code here\n  })\n);\n```\n\n##### Current Tour\n\nThe global `Shepherd` includes a property which is always set to the currently\nactive tour, or null if there is no active tour:\n\n- `Shepherd.activeTour`\n\n#### Tour Instances\n\n##### Creation\n\nYou create a `Tour` object for each tour you'd like to create.\n\nTour's constructor accepts a hash of options:\n\n```javascript\nconst myTour = new Shepherd.Tour(options);\n```\n\n##### Tour Options\n\n- `classPrefix`: The prefix to add to the `shepherd-enabled` and\n  `shepherd-target` class names as well as the `data-shepherd-step-id`.\n- `confirmCancel`:\n  - If true, will issue a `window.confirm` before cancelling\n  - If it is a function(support Async Function), it will be called and wait for\n    the return value, and will only be cancelled if the value returned is true\n- `confirmCancelMessage`: The message to display in the confirm dialog\n- `defaultStepOptions`: Default options for Steps created through `addStep`\n- `exitOnEsc`: Exiting the tour with the escape key will be enabled unless this\n  is explicitly set to `false`.\n- `keyboardNavigation`: Navigating the tour via left and right arrow keys will\n  be enabled unless this is explicitly set to `false`.\n- `stepsContainer` An optional container element for the steps. If not set, the\n  steps will be appended to `document.body`.\n- `modalContainer` An optional container element for the modal. If not set, the\n  modal will be appended to `document.body`.\n- `steps`: An array of step options objects or Step instances to initialize the\n  tour with.\n- `tourName`: An optional \"name\" for the tour. This will be appended to the the\n  tour's dynamically generated `id` property.\n- `useModalOverlay`: Whether or not steps should be placed above a darkened\n  modal overlay. If true, the overlay will create an opening around the target\n  element so that it can remain interactive.\n\n##### Tour Methods\n\n- `addStep(options)`: Creates a new Step object with options, and returns the\n  `Step` instance it created. If the options hash doesn't include an `id`, one\n  will be generated. You can also pass an existing `Step` instance rather than\n  `options`, but note that Shepherd does not support a Step being attached to\n  multiple Tours.\n- `addSteps([Steps])`: Add multiple steps to the tour\n- `getById(id)`: Return a step with a specific id\n- `isActive()`: Check if the tour is active\n- `next()`: Advance to the next step, in the order they were added\n- `back()`: Show the previous step, in the order they were added\n- `cancel()`: Trigger cancel on the current step, hiding it without advancing\n- `complete()`: Calls \\_done() triggering the `complete` event\n- `hide()`: Hide the current step\n- `show([id])`: Show the step specified by id (if it's a string), or index (if\n  it's a number) provided. Defaults to the first step.\n- `start()`: Show the first step and begin the tour\n- `getCurrentStep()`: Returns the currently shown step\n- `removeStep(id)`: Removes the step from the tour\n- `on(eventName, handler, [context])`: Bind an event\n- `off(eventName, [handler])`: Unbind an event\n- `once(eventName, handler, [context])`: Bind just the next instance of an event\n\n##### Tour Events\n\n- `complete`: Triggered when the last step is advanced\n- `cancel`\n- `hide`\n- `show`: Triggered with a hash of the `step` and the `previous` step\n- `start`\n\nSteps are instances of the Step object. They are generally created by the\n`Tour::addStep` method, which returns the `Step` instance it created.\n\n#### Steps\n\n##### Step Options\n\n- `text`: The text in the body of the step. It can be one of three types:\n  - HTML string\n  - `HTMLElement` object\n  - `Function` to be executed when the step is built. It must return one the two\n    options above.\n- `title`: The step's title. It becomes an `h3` at the top of the step.\n- `attachTo`: The element the step should be attached to on the page. An object\n  with properties `element` and `on`.\n  - `element`: An element selector string, a DOM element, or a function\n    (returning a selector, a DOM element, `null` or `undefined`).\n  - `on`: The optional direction to place the Floating UI tooltip relative to\n    the element.\n    - Possible string values: 'auto', 'auto-start', 'auto-end', 'top',\n      'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'right',\n      'right-start', 'right-end', 'left', 'left-start', 'left-end'\n\n```js\nconst new Step(tour, {\n  attachTo: { element: '.some .selector-path', on: 'left' },\n  ...moreOptions\n});\n```\n\nIf you don’t specify an `attachTo` the element will appear in the middle of the\nscreen. The same will happen if your `attachTo.element` callback returns `null`,\n`undefined`, or a selector that does not exist in the DOM.\n\nIf you omit the `on` portion of `attachTo`, the element will still be\nhighlighted, but the tooltip will appear in the middle of the screen, without an\narrow pointing to the target.\n\nIf the element to highlight does not yet exist while instantiating tour steps,\nyou may use lazy evaluation by supplying a function to `attachTo.element`. The\nfunction will be called in the `before-show` phase.\n\n- `beforeShowPromise`: A function that returns a promise. When the promise\n  resolves, the rest of the `show` code for the step will execute. For example:\n  ```javascript\n  beforeShowPromise: function() {\n    return new Promise(function(resolve) {\n      $('#my-bootstrap-modal').on('shown.bs.modal', function () {\n        resolve();\n      });\n    });\n  },\n  ```\n- `canClickTarget` A boolean, that when set to false, will set\n  `pointer-events: none` on the target\n- `cancelIcon` Options for the cancel icon\n  - `attrs` Additional HTML attributes to apply to the cancel icon button\n    element. This is useful for adding data attributes for testing or analytics.\n    Note: These attributes cannot override critical properties like `type`,\n    `onclick`, `class`, or `aria-label`.\n\n  ```javascript\n  cancelIcon: {\n    enabled: true,\n    label: 'Close Tour',\n    attrs: {\n      'data-test': 'close-tour-button',\n      'data-analytics-id': 'tour-close'\n    }\n  }\n  ```\n\n  - `enabled` Should a cancel \"✕\" be shown in the header of the step?\n  - `label` The label to add for `aria-label`\n\n- `classes`: A string of extra classes to add to the step's content element.\n- `buttons`: An array of buttons to add to the step. These will be rendered in a\n  footer below the main body text. Each button in the array is an object of the\n  format:\n  - `attrs`: Additional HTML attributes to apply to the button element. Useful\n    for adding data attributes for testing or analytics.\n  - `label`: The label to add for `aria-label`. It can also be a function that\n    returns a string (useful with i18n solutions).\n  - `disabled`: A boolean that controls the `disabled` attribute. It can also be\n    a function that returns a boolean.\n  - `classes`: Extra classes to apply to the `<a>`\n  - `secondary`: A boolean, that when true, adds a `shepherd-button-secondary`\n    class to the button\n  - `text`: The HTML text of the button. It can also be a function that returns\n    a string (useful with i18n solutions).\n  - `action`: A function executed when the button is clicked on. It is\n    automatically bound to the `tour` the step is associated with, so things\n    like `this.next` will work inside the action. You can use action to skip\n    steps or navigate to specific steps, with something like:\n  ```javascript\n    action() {\n      return this.show('some_step_name');\n    }\n  ```\n- `extraHighlights`: An array of extra element selectors to highlight when the\n  overlay is shown The tooltip won’t be fixed to these elements, but they will\n  be highlighted just like the attachTo element.\n- `advanceOn`: An action on the page which should advance shepherd to the next\n  step. It should be an object with a string `selector` and an `event` name. For\n  example: `{selector: '.some-element', event: 'click'}`. It doesn't have to be\n  an event inside the tour, it can be any event fired on any element on the\n  page. You can also always manually advance the Tour by calling\n  `myTour.next()`.\n- `highlightClass`: An extra class to apply to the `attachTo` element when it is\n  highlighted (that is, when its step is active). You can then target that\n  selector in your CSS.\n- `id`: The string to use as the `id` for the step. If an id is not passed one\n  will be generated.\n- `modalOverlayOpeningPadding`: An amount of padding to add around the modal\n  overlay opening\n- `modalOverlayOpeningRadius`: An amount of border radius to add around the\n  modal overlay opening. It can be either a number or an object with properties\n  `{ topLeft, bottomLeft, bottomRight, topRight }`\n- `floatingUIOptions`: Extra options to pass to\n  [Floating UI](https://floating-ui.com/docs/getting-started)\n- `showOn`: A function that, when it returns true, will show the step. If it\n  returns false, the step will be skipped.\n- `scrollTo`: Should the element be scrolled to when this step is shown? If\n  true, uses the default `scrollIntoView`, if an object, passes that object as\n  the params to `scrollIntoView` i.e. `{behavior: 'smooth', block: 'center'}`\n- `scrollToHandler`: A function that lets you override the default `scrollTo`\n  behavior and define a custom action to do the scrolling, and possibly other\n  logic.\n- `when`: You can define show, hide, etc events inside when. For example:\n\n```javascript\nwhen: {\n  show: function() {\n    window.scrollTo(0, 0);\n  }\n}\n```\n\n##### Step Methods\n\n- `show()`: Show this step\n- `hide()`: Hide this step\n- `cancel()`: Hide this step and trigger the `cancel` event\n- `complete()`: Hide this step and trigger the `complete` event\n- `scrollTo()`: Scroll to this step's element\n- `isOpen()`: Returns true if the step is currently shown\n- `destroy()`: Remove the element\n- `on(eventName, handler, [context])`: Bind an event\n- `off(eventName, [handler])`: Unbind an event\n- `once(eventName, handler, [context])`: Bind just the next instance of an event\n\n##### Step Events\n\n- `before-show`\n- `show`\n- `before-hide`\n- `hide`\n- `complete`\n- `cancel`\n- `destroy`\n\nPlease note that `complete` and `cancel` are only ever triggered if you call the\nassociated methods in your code.\n\n### Advancing on Actions\n\nYou can use the `advanceOn` option, or the Next button, to advance steps. If you\nwould like however to have a step advance on a complex user action, you can do\nthe following:\n\n```javascript\nconst myStep = myTour.addStep(options);\n\nyourApp.on('some-event', () => {\n  if (myStep.isOpen()) {\n    Shepherd.activeTour.next();\n  }\n});\n```\n\n### 🔼 Displaying Arrows\n\nBy default, Shepherd will generate and position an \"arrow\" element that points\nto the target of a step. This is done by setting the `arrow` option to `true` on\neach ``Step.options` &mdash; but you can disable the arrow manually by setting\nit to false:\n\n```js\nmyTour.addStep({\n  id: 'Step 1',\n  arrow: false\n});\n```\n\nYou can also provide an options object, to configure the arrow's\n[padding](https://floating-ui.com/docs/arrow#padding). The padding is the\nclosest the arrow will get to the edge of the step.\n\n```js\nmyTour.addStep({\n  id: 'Step 1',\n  arrow: { padding: 10 }\n});\n```\n\nFurthermore, while Shepherd provides some basic arrow styling, you can style it\nas you wish by targeting the `.shepherd-arrow` element.\n"
  },
  {
    "path": "docs-src/src/content/docs/recipes/cookbook.md",
    "content": "---\ntitle: Cookbook\n---\n\n### Disable Scroll\n\nPreviously, disabling scrolling was built into Shepherd, but it was buggy\nand bulky, so we opted to remove [body-scroll-lock](https://github.com/willmcpo/body-scroll-lock)\nas a dependency, in favor of users installing it directly in their apps. To disable scrolling,\nyou can install `body-scroll-lock` and run `bodyScrollLock.disableBodyScroll();` before\nstarting the tour, then `bodyScrollLock.clearAllBodyScrollLocks();` after stopping the tour.\n\n### Highlighting multiple elements\n\nHighlighting multiple elements is supported by Shepherd out of the box. You can pass an array of selectors to the `extraHighlights` option in the step configuration. This will highlight all the elements in the array as well as the target element defined in the `attachTo` option.\n\n```javascript\nconst tour = new Shepherd.Tour({\n  steps: [\n    {\n      text: 'This is a step with multiple highlights',\n      attachTo: {\n        element: '.target-element',\n        on: 'bottom'\n      },\n      extraHighlights: ['.example-selector', '.example-selector-2']\n    }\n  ]\n});\n```\n\nIf an element to be highlighted is contained by another element that is also being highlighted, the contained element will not be highlighted. This is to prevent the contained element from being obscured by the containing element.\n\n### Offsets\n\nBy default, FloatingUI instances are placed directly next to their target. However, if you need to apply some margin\nbetween them or if you need to fine tune the position according to some custom logic, you can use an offset middleware.\n\nFor example:\n\n```js\nimport { offset } from '@floating-ui/dom';\n\nconst tour = new Shepherd.Tour({\n  steps: [\n    {\n      ...\n      floatingUIOptions: {\n        middleware: [offset({ mainAxis: 0, crossAxis: 12 })]\n      }\n      ...\n    }\n  ]\n});\n```\n\n### Progress Indicator\n\nUsing the already exposed API, you could add a progress indicator of your choosing\nfor each step to let your users know how far into a tour they may be.\n\nThe example below uses the [Step](https://docs.shepherdjs.dev/api/step/classes/step/) `options`\nobject and adds to `when` on the `show` event. Within that, we create an element\nto render in the header with text of what step out of all potential steps is now\nbeing show.\n\n```javascript\nwhen: {\n  show() {\n    const currentStep = Shepherd.activeTour?.getCurrentStep();\n    const currentStepElement = currentStep?.getElement();\n    const header = currentStepElement?.querySelector('.shepherd-header');\n    const progress = document.createElement('span');\n    progress.style['margin-right'] = '315px';\n    progress.innerText = `${Shepherd.activeTour?.steps.indexOf(currentStep) + 1}/${Shepherd.activeTour?.steps.length}`;\n    header?.insertBefore(progress, currentStepElement.querySelector('.shepherd-cancel-icon'));\n  }\n}\n```\n\nAnother example, for anyone who wants to add progress indicators to the footer. Add the `shepherd-progress` className and some extra styles.\n\n```javascript\nwhen: {\n  show() {\n    const currentStep = Shepherd.activeTour?.getCurrentStep();\n    const currentStepElement = currentStep?.getElement();\n    const footer = currentStepElement?.querySelector('.shepherd-footer');\n    const progress = document.createElement('span');\n    progress.className = 'shepherd-progress';\n    progress.innerText = `${Shepherd.activeTour?.steps.indexOf(currentStep) + 1} of ${Shepherd.activeTour?.steps.length}`;\n    footer?.insertBefore(progress, currentStepElement.querySelector('.shepherd-button:last-child'));\n  }\n}\n```\n\n```scss\n.shepherd-footer {\n  align-items: center;\n  border-bottom-left-radius: 5px;\n  border-bottom-right-radius: 5px;\n  display: flex;\n  justify-content: space-between;\n  padding: 0 0.75rem 0.75rem;\n\n  .shepherd-button:last-child {\n    margin-right: 0;\n  }\n\n  .shepherd-progress {\n    font-size: 0.8rem;\n  }\n}\n```\n"
  },
  {
    "path": "docs-src/src/content/docs/recipes/react.md",
    "content": "---\ntitle: React Usage\n---\n\n## Use in React\nWe've published a React package for years that really just exports the default Shepherd class and gives you some syntactical sugar for setting up Shepherd in a React app. This adds another layer from the root API and provides opinionated patterns. It's mainly a wrapper around the Shepherd library that exposes the tour object and methods to the context object that can be passed into props for dynamic interactivity. We think there's more than one way to create solutions and instead just prefer to provide a couple of examples on how you can do this. \n\n### Custom hooks pattern\nYou can just create a hook that will let you setup and share a Tour instance and swap them out as needed.\n\n```javascript\nexport const useShepherdTour = ({ tourOptions, steps }) => {\n  const tourObject = useMemo(() => {\n    const tourInstance = new Shepherd.Tour(tourOptions);\n\n    tourInstance.addSteps(steps);\n\n    return tourInstance;\n  }, [tourOptions, steps]);\n\n  return tourObject;\n};\n```\n\n### Context/Provider pattern\n\n```javascript\n// App imports above, this is either in a root App.js/ts file or somewhere in your app\nconst ShepherdTourContext = React.createContext();\nconst ShepherdTourContextConsumer = ShepherdTourContext.Consumer;\nconst shepherdTourInstance = new Shepherd.Tour();\n\nreturn (\n  <ShepherdTourContext.Provider value={shepherdTourInstance}>\n    { ... }\n  </ShepherdTourContext.Provider>\n);\n\n// elsewhere in your app within a component\nconst tour = useContext(ShepherdTourContext);\n\nreturn (\n  <div>\n    <HomePage>\n      <button className=\"button dark\" onClick={tour.start}>\n        Start Tour\n      </button>\n    </HomePage>\n  </div>\n);\n```"
  },
  {
    "path": "docs-src/src/env.d.ts",
    "content": "/// <reference path=\"../.astro/types.d.ts\" />\n/// <reference types=\"astro/client\" />\n"
  },
  {
    "path": "docs-src/src/pages/index.astro",
    "content": "<meta http-equiv=\"refresh\" content=\"0;url=/guides/install/\" />\n"
  },
  {
    "path": "docs-src/tsconfig.json",
    "content": "{\n  \"extends\": \"astro/tsconfigs/strict\"\n}"
  },
  {
    "path": "landing/.gitignore",
    "content": "# build output\ndist/\n# generated types\n.astro/\n\n# dependencies\nnode_modules/\n\n# logs\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# environment variables\n.env\n.env.production\n\n# macOS-specific files\n.DS_Store\n\n# shepherd copied dependencies\npublic/shepherd.js\n"
  },
  {
    "path": "landing/.vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\"astro-build.astro-vscode\", \"unifiedjs.vscode-mdx\"],\n  \"unwantedRecommendations\": []\n}\n"
  },
  {
    "path": "landing/.vscode/launch.json",
    "content": "{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"command\": \"./node_modules/.bin/astro dev\",\n      \"name\": \"Development server\",\n      \"request\": \"launch\",\n      \"type\": \"node-terminal\"\n    }\n  ]\n}\n"
  },
  {
    "path": "landing/README.md",
    "content": "# Astro Starter Kit: Blog\n\n```sh\nnpm create astro@latest -- --template blog\n```\n\n[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/blog)\n[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/blog)\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/blog/devcontainer.json)\n\n> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!\n\n![blog](https://github.com/withastro/astro/assets/2244813/ff10799f-a816-4703-b967-c78997e8323d)\n\nFeatures:\n\n- ✅ Minimal styling (make it your own!)\n- ✅ 100/100 Lighthouse performance\n- ✅ SEO-friendly with canonical URLs and OpenGraph data\n- ✅ Sitemap support\n- ✅ RSS Feed support\n- ✅ Markdown & MDX support\n\n## 🚀 Project Structure\n\nInside of your Astro project, you'll see the following folders and files:\n\n```text\n├── public/\n├── src/\n│   ├── components/\n│   ├── content/\n│   ├── layouts/\n│   └── pages/\n├── astro.config.mjs\n├── README.md\n├── package.json\n└── tsconfig.json\n```\n\nAstro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.\n\nThere's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.\n\nThe `src/content/` directory contains \"collections\" of related Markdown and MDX documents. Use `getCollection()` to retrieve posts from `src/content/blog/`, and type-check your frontmatter using an optional schema. See [Astro's Content Collections docs](https://docs.astro.build/en/guides/content-collections/) to learn more.\n\nAny static assets, like images, can be placed in the `public/` directory.\n\n## 🧞 Commands\n\nAll commands are run from the root of the project, from a terminal:\n\n| Command                   | Action                                           |\n| :------------------------ | :----------------------------------------------- |\n| `npm install`             | Installs dependencies                            |\n| `npm run dev`             | Starts local dev server at `localhost:4321`      |\n| `npm run build`           | Build your production site to `./dist/`          |\n| `npm run preview`         | Preview your build locally, before deploying     |\n| `npm run astro ...`       | Run CLI commands like `astro add`, `astro check` |\n| `npm run astro -- --help` | Get help using the Astro CLI                     |\n\n## 👀 Want to learn more?\n\nCheck out [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).\n\n## Credit\n\nThis theme is based off of the lovely [Bear Blog](https://github.com/HermanMartinus/bearblog/).\n"
  },
  {
    "path": "landing/astro.config.mjs",
    "content": "import { defineConfig } from 'astro/config';\nimport mdx from '@astrojs/mdx';\nimport sitemap from '@astrojs/sitemap';\nimport tailwindcss from '@tailwindcss/vite';\n\nimport vercel from '@astrojs/vercel';\n\n// https://astro.build/config\nexport default defineConfig({\n  site: 'https://shepherdjs.dev',\n\n  integrations: [mdx(), sitemap()],\n\n  output: 'static',\n  adapter: vercel(),\n  vite: {\n    plugins: [tailwindcss()]\n  }\n});\n"
  },
  {
    "path": "landing/package.json",
    "content": "{\n  \"name\": \"landing\",\n  \"private\": \"true\",\n  \"type\": \"module\",\n  \"version\": \"0.0.1\",\n  \"scripts\": {\n    \"dev\": \"astro dev\",\n    \"start\": \"astro dev\",\n    \"build\": \"astro check && astro build\",\n    \"preview\": \"astro preview\",\n    \"astro\": \"astro\"\n  },\n  \"dependencies\": {\n    \"@astrojs/mdx\": \"^4.3.13\",\n    \"@astrojs/vercel\": \"^9.0.4\",\n    \"@polar-sh/astro\": \"^0.7.3\",\n    \"astro\": \"^5.18.0\",\n    \"shepherd.js\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@astrojs/check\": \"^0.9.8\",\n    \"@astrojs/rss\": \"^4.0.15\",\n    \"@astrojs/sitemap\": \"^3.7.0\",\n    \"@tailwindcss/typography\": \"^0.5.19\",\n    \"@tailwindcss/vite\": \"^4.2.1\",\n    \"sharp\": \"^0.34.5\",\n    \"tailwindcss\": \"^4.2.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.3.1\"\n  }\n}\n"
  },
  {
    "path": "landing/public/CNAME",
    "content": "shepherdjs.dev"
  },
  {
    "path": "landing/public/favicons/site.webmanifest",
    "content": "{\"name\":\"\",\"short_name\":\"\",\"icons\":[{\"src\":\"/favicons/android-chrome-192x192.png\",\"sizes\":\"192x192\",\"type\":\"image/png\"},{\"src\":\"/favicons/android-chrome-512x512.png\",\"sizes\":\"512x512\",\"type\":\"image/png\"}],\"theme_color\":\"#ffffff\",\"background_color\":\"#ffffff\",\"display\":\"standalone\"}"
  },
  {
    "path": "landing/src/components/ArticleCard.astro",
    "content": "---\nconst { article } = Astro.props;\n---\n\n<article class=\"column feature bg-gray-100 rounded-sm\">\n  <img\n    class=\"object-cover object-center w-full lg:h-48 md:h-36 rounded-sm\"\n    src={`${article.image.filename}/m/360x240`}\n    alt={article.image.alt}\n  />\n  <div class=\"p-4\">\n    <h1 class=\"text-2xl font-semibold lg:text-3xl\">\n      {article.title}\n    </h1>\n    <p class=\"leading-relaxed text-gray-700 line-clamp-2 my-4\">\n      {article.teaser}\n    </p>\n    <a\n      href={`/blog/${article.slug}`}\n      class=\"font-semibold text-blue-600 hover:underline\"\n      title=\"read more\"\n    >\n      Read More »\n    </a>\n  </div>\n</article>\n"
  },
  {
    "path": "landing/src/components/BaseHead.astro",
    "content": "---\nimport { ViewTransitions } from 'astro:transitions';\nimport PostHog from './Posthog.astro';\n\n// Import the global.css file here so that it is included on\n// all pages through the use of the <BaseHead /> component.\nimport '../styles/fonts.css';\nimport '../styles/prism.css';\nimport '../styles/shepherd.css';\nimport '../styles/styles.css';\n\ninterface Props {\n  title: string;\n  description: string;\n  image?: string;\n}\n\nconst canonicalURL = new URL(Astro.url.pathname, Astro.url.origin);\n\nconst { title, description } = Astro.props;\n---\n\n<!-- Global Metadata -->\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<link rel=\"manifest\" href=\"/favicons/site.webmanifest\" />\n<meta name=\"generator\" content={Astro.generator} />\n\n<!--favicons-->\n\n<link\n  rel=\"apple-touch-icon\"\n  sizes=\"180x180\"\n  href=\"/favicons/apple-touch-icon.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"32x32\"\n  href=\"/favicons/favicon-32x32.png\"\n/>\n<link\n  rel=\"icon\"\n  type=\"image/png\"\n  sizes=\"16x16\"\n  href=\"/favicons/favicon-16x16.png\"\n/>\n\n<!-- Font preloads -->\n<link\n  rel=\"preload\"\n  href=\"/fonts/GTPressura-Bold.woff\"\n  as=\"font\"\n  type=\"font/woff\"\n  crossorigin\n/>\n<link\n  rel=\"preload\"\n  href=\"/fonts/GTPressura-Bold.woff2\"\n  as=\"font\"\n  type=\"font/woff\"\n  crossorigin\n/>\n<link\n  rel=\"preload\"\n  href=\"/fonts/FoundersGrotesk-Regular.woff2\"\n  as=\"font\"\n  type=\"font/woff\"\n  crossorigin\n/>\n<link\n  rel=\"preload\"\n  href=\"/fonts/FoundersGrotesk-Regular.woff\"\n  as=\"font\"\n  type=\"font/woff\"\n  crossorigin\n/>\n\n<!-- Canonical URL -->\n<link rel=\"canonical\" href={canonicalURL} />\n\n<!-- Primary Meta Tags -->\n<title>{title}</title>\n<meta name=\"title\" content={title} />\n<meta name=\"description\" content={description} />\n\n<PostHog />\n\n<!-- Open Graph Facebook -->\n<!-- <meta property=\"og:type\" content=\"website\" />\n<meta property=\"og:url\" content={Astro.url} />\n<meta property=\"og:title\" content={title} />\n<meta property=\"og:description\" content={description} />\n<meta property=\"og:image\" content={new URL(image, Astro.url)} /> -->\n\n<!-- Twitter -->\n<!-- <meta property=\"twitter:card\" content=\"summary_large_image\" />\n<meta property=\"twitter:url\" content={Astro.url} />\n<meta property=\"twitter:title\" content={title} />\n<meta property=\"twitter:description\" content={description} />\n<meta property=\"twitter:image\" content={new URL(image, Astro.url)} /> -->\n\n<ViewTransitions />\n"
  },
  {
    "path": "landing/src/components/Footer.astro",
    "content": "---\nimport { Image } from 'astro:assets';\n\nimport GitHubLogo from '../images/github.svg?raw';\nimport LinkedInLogo from '../images/linkedin.svg?raw';\nimport TwitterLogo from '../images/twitter.svg?raw';\nimport ShepherdWink from '../images/shepherd-head-wink.svg';\n---\n\n<footer class=\"flex justify-center mt-auto w-full\">\n  <Image\n    class=\"footer-logo absolute w-48\"\n    src={ShepherdWink}\n    alt=\"An adorable, retro looking sheep that is winking and smiling.\"\n    role=\"presentation\"\n  />\n\n  <div\n    class=\"bg-grey border-4 border-navy flex flex-wrap items-center justify-center md:justify-between max-w-8xl p-8 pt-20 w-full md:pt-8\"\n  >\n    <div\n      class=\"flex items-center justify-center w-full md:justify-between md:w-auto\"\n    >\n      <img\n        class=\"inline mr-2 w-8\"\n        src=\"/img/ship-shape-logo.svg\"\n        alt=\"Ship Shape Logo\"\n      />\n\n      <span class=\"font-heading text-xl uppercase\">\n        Library by\n        <a class=\"underline hover:text-navy-light\" href=\"https://shipshape.io\">\n          Ship Shape\n        </a>\n      </span>\n    </div>\n\n    <div class=\"flex items-center\">\n      <a\n        class=\"footer-icon mr-4 w-6\"\n        href=\"https://github.com/shipshapecode/shepherd\"\n      >\n        <Fragment set:html={GitHubLogo} />\n      </a>\n\n      <a class=\"footer-icon mr-4 w-6\" href=\"https://twitter.com/whiskeywebfm\">\n        <Fragment set:html={TwitterLogo} />\n      </a>\n\n      <a\n        class=\"footer-icon mr-4 w-6\"\n        href=\"https://www.linkedin.com/company/ship-shape/\"\n      >\n        <Fragment set:html={LinkedInLogo} />\n      </a>\n    </div>\n  </div>\n</footer>\n"
  },
  {
    "path": "landing/src/components/FormattedDate.astro",
    "content": "---\ninterface Props {\n\tdate: Date;\n}\n\nconst { date } = Astro.props;\n---\n\n<time datetime={date.toISOString()}>\n\t{\n\t\tdate.toLocaleDateString('en-us', {\n\t\t\tyear: 'numeric',\n\t\t\tmonth: 'short',\n\t\t\tday: 'numeric',\n\t\t})\n\t}\n</time>\n"
  },
  {
    "path": "landing/src/components/GithubButton.astro",
    "content": "---\nimport { getFormattedStars } from '../lib/github';\n\nconst starCount = await getFormattedStars();\n---\n\n<a\n  class=\"button star bg-white border-2 border-navy p-6 text-navy whitespace-nowrap w-full\"\n  href=\"https://github.com/shipshapecode/shepherd\"\n>\n  {starCount} ★ on Github\n</a>\n"
  },
  {
    "path": "landing/src/components/Header.astro",
    "content": "---\nimport { SITE_TITLE } from '../consts';\nimport ShepherdHead from '../images/shepherd-head.svg?raw';\nimport ShepherdHeader from '../images/shepherd-header.svg';\n\nconst { isHome } = Astro.props;\n---\n\n<header class=\"flex justify-center mt-4 w-full\">\n  <div class=\"absolute ml-2 top-0\">\n    <a href=\"/\">\n      <Fragment class=\"shepherd-logo absolute ml-2\" set:html={ShepherdHead} />\n    </a>\n  </div>\n\n  <div\n    class=\"bg-grey-light flex flex-col font-heading justify-center items-center w-full\"\n  >\n    <nav\n      class=\"flex flex-wrap justify-center p-4 mt-40 max-w-8xl text-xl w-full lg:justify-between lg:mt-0\"\n    >\n      <div class=\"flex lg:p-12\">\n        <a\n          class=\"pr-6 uppercase hover:text-navy-light lg:pr-10\"\n          href=\"https://github.com/shipshapecode/shepherd\"\n        >\n          GitHub\n        </a>\n        <a\n          class=\"pr-6 uppercase lg:pr-10 hover:text-navy-light\"\n          href=\"https://docs.shepherdjs.dev\"\n        >\n          Docs\n        </a>\n        <button\n          class=\"pr-6 uppercase cursor-pointer hover:text-navy-light lg:pr-0\"\n          id=\"showTour\"\n          type=\"button\"\n        >\n          Demo\n        </button>\n      </div>\n\n      <div class=\"flex lg:p-12\">\n        <a\n          class=\"pr-6 uppercase hover:text-navy-light lg:pr-10\"\n          href=\"/pricing\"\n        >\n          Pricing\n        </a>\n        <a\n          class=\"pr-6 uppercase hover:text-navy-light lg:pr-10\"\n          href=\"https://discord.gg/EGcDW5NSud\"\n        >\n          Discord\n        </a>\n        <!-- <a class='pr-6 uppercase hover:text-navy-light lg:pr-10' href='/blog'>\n          Blog\n        </a> -->\n        <a\n          class=\"uppercase hover:text-navy-light\"\n          href=\"mailto:ahoy@shipshape.io\"\n        >\n          Contact\n        </a>\n      </div>\n    </nav>\n\n    <img\n      class=\"hero-welcome p-4 w-full lg:mt-4 lg:p-0 lg:w-auto\"\n      src={ShepherdHeader.src}\n      alt={SITE_TITLE}\n    />\n\n    <h2 class=\"font-body p-2 text-xl\">\n      Guide your users through a tour of your app\n    </h2>\n\n    {\n      isHome && (\n        <div class=\"flex flex-wrap max-w-6xl p-4 w-full lg:flex-nowrap\">\n          <div class=\"feature m-4 relative w-full lg:w-1/3\">\n            <div class=\"border-4 border-navy w-full\">\n              <img\n                class=\"absolute a11y-icon z-20\"\n                src=\"/img/accessibility.svg\"\n                alt=\"\"\n                role=\"presentation\"\n              />\n\n              <div class=\"bg-grey-light border-b-4 border-navy h-40 relative w-full z-10\" />\n\n              <div class=\"bg-white h-72 p-6 relative z-10\">\n                <h3 class=\"p-2 text-2xl text-center uppercase w-full\">\n                  Accessibility\n                </h3>\n\n                <p class=\"font-body p-2 text-xl\">\n                  Shepherd has full keyboard navigation support, focus trapping,\n                  and a11y compliance via aria attributes.\n                </p>\n              </div>\n\n              <div class=\"absolute bg-navy h-full -ml-3 mt-3 top-0 w-full z-0\" />\n            </div>\n          </div>\n\n          <div class=\"customizable m-4 relative w-full lg:w-1/3\">\n            <div class=\"border-4 border-navy w-full\">\n              <img\n                class=\"absolute customizable-icon z-20\"\n                src=\"/img/customizable.svg\"\n                alt=\"\"\n                role=\"presentation\"\n              />\n\n              <div class=\"bg-grey-light border-b-4 border-navy h-40 relative w-full z-10\" />\n\n              <div class=\"bg-white h-72 p-6 relative z-10\">\n                <h3 class=\"p-2 text-2xl text-center uppercase w-full\">\n                  Highly Customizable\n                </h3>\n\n                <p class=\"font-body p-2 text-xl\">\n                  Shepherd's styles are kept minimal, allowing you to easily\n                  customize the look and feel, but still give you enough to drop\n                  in and be ready to go quickly.\n                </p>\n              </div>\n\n              <div class=\"absolute bg-navy h-full -ml-3 mt-3 top-0 w-full z-0\" />\n            </div>\n          </div>\n\n          <div class=\"feature m-4 relative w-full lg:w-1/3\">\n            <div class=\"border-4 border-navy w-full\">\n              <img\n                class=\"absolute framework-icon z-20\"\n                src=\"/img/framework.svg\"\n                alt=\"\"\n                role=\"presentation\"\n              />\n\n              <div class=\"bg-grey-light border-b-4 border-navy h-40 relative w-full z-10\" />\n\n              <div class=\"bg-white h-72 p-6 relative z-10\">\n                <h3 class=\"p-2 text-2xl text-center uppercase w-full\">\n                  Framework Ready\n                </h3>\n\n                <p class=\"font-body p-2 text-xl\">\n                  Shepherd is ready to drop into your application using React,\n                  Ember, Angular, Vue.js, ES Modules, or plain Javascript!\n                </p>\n              </div>\n\n              <div class=\"absolute bg-navy h-full -ml-3 mt-3 top-0 w-full z-0\" />\n            </div>\n          </div>\n        </div>\n      )\n    }\n  </div>\n</header>\n\n<script>\n  // Handle demo button click - redirect to home if not already there\n  function setupDemoButton() {\n    const showTourBtn = document.querySelector('#showTour');\n\n    if (!showTourBtn) return;\n\n    // Clean up previous listener if it exists\n    if ((window as any).__demoButtonAbortController) {\n      (window as any).__demoButtonAbortController.abort();\n    }\n\n    // Create new AbortController for this listener\n    const controller = new AbortController();\n    (window as any).__demoButtonAbortController = controller;\n\n    showTourBtn.addEventListener(\n      'click',\n      () => {\n        // Check if we're on the home page\n        if (window.location.pathname !== '/') {\n          // Store flag to start tour after navigation\n          sessionStorage.setItem('startTourOnLoad', 'true');\n          window.location.href = '/';\n        } else {\n          // We're already on home page, dispatch event to start tour\n          window.dispatchEvent(new CustomEvent('startTour'));\n        }\n      },\n      { signal: controller.signal }\n    );\n  }\n\n  // Run on Astro page transitions (fires on both initial load and transitions)\n  document.addEventListener('astro:page-load', setupDemoButton);\n</script>\n"
  },
  {
    "path": "landing/src/components/HeaderLink.astro",
    "content": "---\nimport type { HTMLAttributes } from 'astro/types';\n\ntype Props = HTMLAttributes<'a'>;\n\nconst { href, class: className, ...props } = Astro.props;\n\nconst { pathname } = Astro.url;\nconst isActive = href === pathname || href === pathname.replace(/\\/$/, '');\n---\n\n<a href={href} class:list={[className, { active: isActive }]} {...props}>\n\t<slot />\n</a>\n<style>\n\ta {\n\t\tdisplay: inline-block;\n\t\ttext-decoration: none;\n\t}\n\ta.active {\n\t\tfont-weight: bolder;\n\t\ttext-decoration: underline;\n\t}\n</style>\n"
  },
  {
    "path": "landing/src/components/Icon.astro",
    "content": "---\nexport interface Props {\n  icon: string;\n}\n\nconst { icon } = Astro.props as Props;\nconst { default: innerHTML } = await import(`/src/svg/${icon}.svg?raw`);\n---\n\n<Fragment set:html={innerHTML} />\n"
  },
  {
    "path": "landing/src/components/Posthog.astro",
    "content": "<script is:inline>\n  !(function (t, e) {\n    var o, n, p, r;\n    e.__SV ||\n      ((window.posthog = e),\n      (e._i = []),\n      (e.init = function (i, s, a) {\n        function g(t, e) {\n          var o = e.split('.');\n          2 == o.length && ((t = t[o[0]]), (e = o[1])),\n            (t[e] = function () {\n              t.push([e].concat(Array.prototype.slice.call(arguments, 0)));\n            });\n        }\n        ((p = t.createElement('script')).type = 'text/javascript'),\n          (p.async = !0),\n          (p.src = s.api_host + '/static/array.js'),\n          (r = t.getElementsByTagName('script')[0]).parentNode.insertBefore(\n            p,\n            r\n          );\n        var u = e;\n        for (\n          void 0 !== a ? (u = e[a] = []) : (a = 'posthog'),\n            u.people = u.people || [],\n            u.toString = function (t) {\n              var e = 'posthog';\n              return (\n                'posthog' !== a && (e += '.' + a), t || (e += ' (stub)'), e\n              );\n            },\n            u.people.toString = function () {\n              return u.toString(1) + '.people (stub)';\n            },\n            o =\n              'capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys onSessionId'.split(\n                ' '\n              ),\n            n = 0;\n          n < o.length;\n          n++\n        )\n          g(u, o[n]);\n        e._i.push([i, s, a]);\n      }),\n      (e.__SV = 1));\n  })(document, window.posthog || []);\n  posthog.init('phc_sl7TroBwU2fA7dJVU70ZV5u0575fQNWYv1GK5enODkX', {\n    api_host: 'https://us.i.posthog.com'\n  });\n</script>\n"
  },
  {
    "path": "landing/src/consts.ts",
    "content": "// Place any global data in this file.\n// You can import this data from anywhere in your site by using the `import` keyword.\n\nexport const SITE_TITLE = 'Shepherd — Guide your users through a tour of your app.';\nexport const SITE_DESCRIPTION = 'Guide your users through a tour of your app.';\n"
  },
  {
    "path": "landing/src/content/blog/alpha-launch-pro.md",
    "content": "---\ntitle: 'Introducing Shepherd Pro: Adding User Journey Analytics'\nauthorId: chuckcarpenter\npubDate: '2024-04-18'\nslug: alpha-launch-pro\ndescription: 'Let us talk about some cool new technologies, but how sometimes well know frameworks are still good.'\n---\n\nHey there, it’s me Chuck Carpenter. Today I want to talk about Shepherd.js, the open source library and to announce Shepherd Pro, a way to take things further to create user journeys that are informed and effective. The TL;DR is:\n\n- An alpha launch of the Pro platform and adding analytics capabilities to the library\n- Chuck is building the Pro product, with continued support and help from Robbie and the OS community for the library\n- Sign up today at https://shepherdpro.com\n- Everything remains open source, MIT licensed, and we are looking for feedback on the product to help us drive things forward\n\n![Github Star History](../../images/blog/star-history.png)\n\nAs many of you know, I’ve been a maintainer of the Shepherd library for about 7 years or so. What originally started as an Ember.js add-on of an existing tour library, has been rewritten a number of times and morphed into one of the most popular user journey libraries (thanks to our 90+ contributors) with almost 12k stars! We now believe our users are looking for more while supporting the ethos of open source (we are committed to keeping the library OSS).\n\nWe’ve worked to make software that is stable, accessible, and very composable in order to allow developers to create some clever ways to help their users find functionality and value for their time (companies and projects such as Drupal, Google, and recently our friends at Codepen.io). Much of that work has also allowed us to learn a lot about maintaining/publishing dependencies and work through a few interesting patterns such as attaching an element to another, highlighting it, and programmatically reacting to user events.\n\nToday, we’re excited to announce the alpha release of Shepherd Pro, a robust new addition to our trusted Shepherd library. Shepherd has gained and maintained popularity for its openness and expandability, and now we’re dialing it up by integrating powerful analytics capabilities. While there exists paid software where you can create onboarding tours for your application, they seem to be very focused on WYSIWYG creation and customization. Our users are very technical and are able to control all these things quite comfortably in code. Why not empower them to and give them a professional product that allows them to bring in feedback and data? These new features will transform how you understand and improve user interactions throughout their journeys.\n\nWith Shepherd Pro, you’ll have deep insights into how users interact with your guided journeys. Our new analytics tools allow you to track user engagement step-by-step, pinpointing exactly where users might disengage or need extra help. This data isn’t just informative—it’s crucial for enhancing the effectiveness of each journey and identifying areas for improvement.\n\n![Downloads over the last year](../../images/blog/npm-trends.png)\n\nWhile other tools exist in the market to address some of these areas, we feel that a completely open source approach that allows end product users to not only provide valuable insights but also actively contribute is critical in our path to deliver the most impactful solutions. Additionally, there are features that aren't available in other products such as:\n\nOn premise/self hosted solutions\nAccessibility focus\nCatering to highly technical and high performing engineering teams\n\nThe ultimate goal? To make your tours not only more engaging but also easier to navigate, boosting product adoption and user satisfaction. We aim to get users to the \"aha!\" moment of your application more smoothly and quickly, because a well-informed user is a happy user. Integrations extend beyond just our own tools as well. Now, Shepherd Pro easily connects with top analytics platforms like Posthog, with more integrations on the horizon. This seamless connection ensures that you can manage and analyze your user journey data effortlessly within a familiar environment.\n\nWe’re thrilled to see how Shepherd Pro will empower you to craft even more engaging and effective user journeys and we’re launching all of this to alpha users under our open source project that is MIT licensed. As we progress toward the next stages of release, we plan to add targeting options, allow you to sync your cohorts from our integrations, and eventually add ways to more easily define the configurations of a journey. Join us at [https://shepherdpro.com](https://shepherdpro.com) to sign up or feel free to reach out to me directly, [hello@shepherdpro.com](mailto:hello@shepherdpro.com).\n"
  },
  {
    "path": "landing/src/content/blog/secret-handshakes-hidden-passages.md",
    "content": "---\ntitle: 'Secret Handshakes and Hidden Passages: Using Redwood Functions'\nauthorId: chuckcarpenter\npubDate: '2024-02-27'\nslug: secret-handshakes-hidden-passages\ndescription: 'When you need something outside of the design of your API, actions in functions can be exposed.'\nheroImage: 'cyoa-mystery.png'\nheroImageCaption: 'Which way to the promise land?'\n---\n\nRedwood.js has served as a great choice in terms of a fully featured web application stack, covering lots of my needs such as authentication and mailing capabilities right out of the box. \n\nFor your main application, using and managing the API for your admin users is very straightforward and uses known conventions. Let's say you have perhaps another use case though? One that creates data via an action or even takes in events from another site? Enter Redwood functions.\n\n## Understanding Redwood Functions\n\nRedwood functions are the backbone of your serverless architecture, enabling you to execute server-side logic without the overhead of managing special access points in the GraphQL that have their own custom directives and you avoid enforcing GraphQL style queries where it might be unfamiliar. These functions can range from processing data, handling requests, to interacting with databases. However, without proper protection, they're like open doors to your data treasury.\n\n## Implementing API Key Authentication\n\nTo secure these precious endpoints, we turn to API keys—a unique string that a client must send to access the function. Think of it as a special pass-code that unlocks your application's capabilities. Implementing API key authentication in Redwood functions ensures that only requests with the correct key can invoke your business logic.\n\nHere’s how you might implement such a check:\n\n```typescript\nexport const handler = async (event: APIGatewayEvent, _context: Context) => {\n  const apiKey = event.headers['x-api-key'];\n  if (!apiKey) {\n    return {\n      statusCode: 401,\n      body: JSON.stringify({\n        error: \"Invalid API Key\",\n      }),\n    };\n  }\n\n  // Do your business here, good people\n  return {\n    statusCode: 200,\n    body: JSON.stringify({\n      message: \"Access granted: Welcome to the secret club!\",\n    }),\n  }\n}\n```\n\nYou might notice the event arguments on the handler function look familiar if you've worked in serverless environments before. As noted in the Redwood.js documentation:\n\n> Originally, Redwood apps were intended to be deployed as serverless functions to AWS Lambda. Whenever a Redwood app is deployed to a \"serverful\" environment such as Fly or Render, a Fastify server is started and your Redwood app's functions in api/src/functions are automatically registered onto the server. \n\nMeaning, they have a similar signature to Lambdas even when in a containerized application. Huzzah!\n\nIn the above example, the function first checks if the incoming request contains an 'api-key' header that matches a predefined key stored in the environment variables. If not, it responds with a 403 Forbidden status, effectively barring the door against unauthorized access.\n\n## Why API Keys?\n\nAPI keys are simple yet effective in controlling access to your functions. They help you track and control how the API is being used, preventing unauthorized use and safeguarding your application from unwanted guests.\n\n## The Tale Ends Here\nIncorporating API key authentication into your Redwood functions is like equipping your digital fortress with a sophisticated locking mechanism. It ensures that your functions, whether they're updating user data, processing payments, or querying databases, remain secure and accessible only to those with the correct key.\n\nAs you continue to develop and deploy, remember that the security of your functions is integral to the integrity of your application. Secure your Redwood functions with API keys (or any other way you wish), and rest easy knowing that your back-end operations are guarded against the wild west of the web.\n"
  },
  {
    "path": "landing/src/content/blog/shepherd-the-product.md",
    "content": "---\ntitle: 'Innovating in the Open: Building a Product with Shepherd'\nauthorId: chuckcarpenter\npubDate: '2024-01-05'\nslug: shepherd-the-product\ndescription: ''\nheroImage: 'shepherd-HQ.jpg'\nheroImageCaption: 'Shepherd Pro HQ, the kid&apos;s playhouse'\n---\n\nWeb development isn’t just about slinging code – it’s about creating experiences that don’t make users want to pull their hair out. Enter Shepherd.js, our guiding light in this adventure, and our choice for steering users through journeys in our apps without getting them lost and helping to drive value every time they interact. What makes this development story unique is our approach: building in public with open source.\n\n## Why Shepherd.js?\n\nIt’s like having a GPS for your app - but without the annoying “recalculating” voice. Shepherd.js is lightweight, flexible, and doesn’t hog the spotlight, ensuring our app remains the star of the show. With this library our product isn’t just functional; it becomes more accessible and user-friendly.\n\n## Building in Public\n\nWe’re embracing the “building in public” approach. It’s like cooking with the kitchen door open – everyone sees the mess, but they also see the masterpiece in the making. This transparency invites valuable feedback and keeps us honest (and a little bit on edge).\n\n## Open Source: A Collaborative Effort\n\nOpen source is at the core of our development strategy. By making our code available to the community, we’re not just sharing our work; we’re inviting collaboration. This collective wisdom not only enhances our product but also enriches the wider open-source ecosystem. Let’s be honest, we don’t always have the best or right answers for what our customers will need and we’re happy to let them help drive us in the right direction.\n\n## Shepherd Pro: The Journey Leading Superstar\n\nWe've worked to create and iterate over this library over a number of years, and now we are taking the next step to unlock the potential capabilities of advanced user journeys with Pro. Shepherd Pro is like Shepherd.js on a caffeine boost. This enhanced offering is designed to unlock a plethora of capabilities and craft more full-featured user journeys.\n\n* **Customizable Tour Templates**: Like fashion templates, but for software. Dress your app in the best style that feels seemless to what your visitors are used to seeing.\n* **Analytics Integration**: Understanding user engagement is crucial. Shepherd Pro integrates analytics to provide insights into the effectiveness of the journeys, helping us make data-driven decisions.\n* **Multi-Language Support**: Parlez-vous tour? ¡Claro que sí!\n* **User Behavior Tracking**: By tracking how users interact with the tours, we gain invaluable insights. This helps us continuously optimize the user experience, making it more intuitive and effective.\n* **Integration Capabilities**: Plays well with others. No sandbox squabbles here.\n* **Feedback Mechanisms**: Because we actually want to know what you think.\n* **Advanced Branching Logic**: It's like choose-your-own-adventure, but for user journeys.\n\n## Flexible Hosting Options: Your Place or Ours\n\nWith Shepherd Pro, we’re not just handing you the keys to a sleek car; we’re giving you the choice of where to park it. Whether you’re more comfortable with us hosting, or hosting the application on your own premises or in your cloud account, Shepherd Pro adapts to your environment. Whether you’re guiding users through a complex application or a simple interface, the choice of hosting is yours. Host Shepherd Pro on your premises or in your cloud account to seamlessly integrate these journeys into your environment. It’s like choosing the perfect setting for a story – whether it’s in your own home or a cloud in the sky, we ensure the user journey remains uninterrupted and secure. This flexibility ensures that your data sovereignty and security preferences are always top priority.\n\n## Conclusion\nJoin us on this quirky, code-filled journey. Whether you're a developer, a tech aficionado, or just someone who appreciates a great user experience, your insights and involvement are what make this a thrilling adventure."
  },
  {
    "path": "landing/src/content/blog/tale-of-frameworks.md",
    "content": "---\ntitle: 'A Tale of Frameworks: Our Quirky Quest from Next.js to Redwood.js'\nauthorId: chuckcarpenter\npubDate: '2024-01-19'\nslug: tale-of-frameworks\ndescription: 'Let us talk about some cool new technologies, but how sometimes well know frameworks are still good.'\nheroImage: 'dan-meyers-T5w1xkN1c-Q-unsplash.jpg'\nheroImageCaption: 'Photo by Dan Meyers on Unsplash'\n---\n\n## And so it begins\n\nIn the realm of web development, choosing the right framework can feel like finding a needle in a digital haystack. Our latest project, an application for managing user journeys and getting analytics for them, started with a dive into [Next.js](https://nextjs.org/) version 14 (\"blessed\" with React Server Components), paired with a separate API using [ElysiaJS](https://elysiajs.com/). However, as the project continued and the complexity grew, so did our needs.\n\n## Why We Started with Next.js and ElysiaJS\nNext.js, with its robust features and scalability, seemed like a natural choice. We've used it quite successfully plenty in the past and felt like an old friend to help us in our own project now, rather than enterprise client projects. React can be the wild west in some ways when it comes to compiling together all the dependencies to make it a full app framework suite, Next.js makes many of those choices for you and provides nice defaults. \n\nCoupled with ElysiaJS for our API needs (which to be fair is quite bleeding edge and built on the newly released [Bun](https://bun.sh/) runtime), we embarked on this journey with high hopes. Next.js offered us a modern framework with great performance, while ElysiaJS promised a flexible and fast API layer. Bun is just fast, no question.\n\n## The Twist in the Tale: Shifting to RedwoodJS\nHowever, as we navigated through development, we encountered a few hitches. The separate management of front-end and API layers started to feel like juggling apples and oranges – doable, but unnecessarily complex. Bleeding edge tech isn't always the most documented and while open source folks are quite helpful, it's time consuming to ask questions in multiple projects and/or Discord servers. Enter RedwoodJS.\n\nRedwoodJS offered us an integrated solution, blending the front-end and API seamlessly. It was like finding a tool that could juggle for us. The allure of its full-stack capabilities, coupled with a simpler, more cohesive development experience, was too good to pass up.\n\n## Building the App with RedwoodJS\nWith RedwoodJS, our development process became smoother, akin to a well-oiled machine. Its opinionated structure provided a clear path forward, reducing the overhead of decision-making. The integrated GraphQL API meant that our data management became more streamlined and all the work happened in one monorepo.\n\n## Conclusion\nIn the end, our journey led us to RedwoodJS, a framework that aligned perfectly with our vision for the journey management application. It reminded us that in the world of web development, flexibility and adaptability are just as important as the features a framework offers. There's something to be said for relying on web technologies that have worked well for years on end. Join us as we continue to explore and share our experiences in this ever-evolving landscape."
  },
  {
    "path": "landing/src/content/config.ts",
    "content": "import { defineCollection, z } from 'astro:content';\n\nconst blog = defineCollection({\n  // Type-check frontmatter using a schema\n  schema: z.object({\n    title: z.string(),\n    authorId: z.string(),\n    description: z.string(),\n    // Transform string to Date object\n    pubDate: z.coerce.date(),\n    updatedDate: z.coerce.date().optional(),\n    heroImage: z.string().optional(),\n    heroImageCaption: z.string().optional()\n  })\n});\n\nexport const collections = { blog };\n"
  },
  {
    "path": "landing/src/env.d.ts",
    "content": "/// <reference path=\"../.astro/types.d.ts\" />\n/// <reference types=\"astro/client\" />\n"
  },
  {
    "path": "landing/src/layouts/Base.astro",
    "content": "---\nimport BaseHead from '@components/BaseHead.astro';\nimport { SITE_TITLE, SITE_DESCRIPTION } from '../consts';\n\nconst { overrideTitle = SITE_TITLE, overrideDescription = SITE_DESCRIPTION } =\n  Astro.props;\n---\n\n<html lang=\"en\">\n  <head>\n    <BaseHead title={overrideTitle} description={overrideDescription} /></head\n  >\n  <body class=\"bg-white flex flex-col font-body p-4 min-h-screen text-navy\">\n    <slot />\n  </body>\n</html>\n"
  },
  {
    "path": "landing/src/layouts/BlogPost.astro",
    "content": "---\nimport type { CollectionEntry } from 'astro:content';\nimport Base from '@layouts/Base.astro';\nimport Header from '@components/Header.astro';\nimport Footer from '@components/Footer.astro';\nimport { SITE_TITLE } from '../consts';\n\ntype Props = CollectionEntry<'blog'>['data'];\n\nconst { title, description } = Astro.props;\n---\n\n<Base overrideDescription={description} overrideTitle={title}>\n  <Header title={SITE_TITLE} />\n\n  <main>\n    <article class=\"max-w-(--breakpoint-md) mb-20 mx-auto\">\n      <slot />\n    </article>\n    <Footer />\n  </main>\n</Base>\n"
  },
  {
    "path": "landing/src/layouts/MainPage.astro",
    "content": "---\nimport Base from './Base.astro';\nimport Header from '../components/Header.astro';\nimport Footer from '../components/Footer.astro';\nimport GithubButton from '../components/GithubButton.astro';\nimport { SITE_TITLE } from '../consts';\n\nconst { isHome } = Astro.props;\n---\n\n<Base>\n  <Header title={SITE_TITLE} isHome={isHome} />\n  <main>\n    <slot name='hero-heading' />\n\n    <div class='flex justify-center mb-20 w-full'>\n      <div class='max-w-3xl text-center w-full'>\n        <slot name='content' />\n        <div class='hero-followup font-heading mb-12 mt-12 lg:mb-24 lg:mt-24'>\n          <div class='bg-navy inline-block mb-4 w-56 lg:mr-4'>\n            <GithubButton />\n          </div>\n\n          <div class='bg-navy inline-block mb-4 w-56'>\n            <a\n              class='button bg-white border-2 border-navy p-6 text-navy whitespace-nowrap w-full'\n              href='https://docs.shepherdjs.dev'\n            >\n              View Docs\n            </a>\n          </div>\n        </div>\n\n        <div class='mb-12 mt-8'>\n          <h3 class='font-heading text-2xl uppercase'>\n            Brands that use Shepherd\n          </h3>\n\n          <div class='flex flex-wrap justify-center w-full'>\n            <div\n              class='flex items-center justify-center m-4 h-32 relative w-32 md:h-48 md:w-48 lg:h-56 lg:w-56'\n            >\n              <div\n                class='bg-white border-4 border-navy flex items-center justify-center h-full p-6 w-full z-10 md:p-12'\n              >\n                <img\n                  class='h-auto w-full'\n                  src='/users/ally.svg'\n                  alt=''\n                  role='presentation'\n                />\n              </div>\n\n              <div class='absolute bg-navy h-full -ml-3 mt-3 top-0 w-full z-0'>\n              </div>\n            </div>\n\n            <div\n              class='flex items-center justify-center m-4 h-32 relative w-32 md:h-48 md:w-48 lg:h-56 lg:w-56'\n            >\n              <div\n                class='bg-white border-4 border-navy flex items-center justify-center h-full p-4 w-full z-10 md:p-8'\n              >\n                <a href='https://codepen.io/pen/?welcome=true' target='_blank'>\n                  <img\n                    class='h-auto w-full'\n                    src='/users/codepen.svg'\n                    alt=''\n                    role='presentation'\n                  />\n                </a>\n              </div>\n\n              <div class='absolute bg-navy h-full -ml-3 mt-3 top-0 w-full z-0'>\n              </div>\n            </div>\n\n            <div\n              class='flex items-center justify-center m-4 h-32 relative w-32 md:h-48 md:w-48 lg:h-56 lg:w-56'\n            >\n              <div\n                class='bg-white border-4 border-navy flex items-center justify-center h-full p-4 w-full z-10 md:p-8'\n              >\n                <img\n                  class='h-auto w-full'\n                  src='/users/google.svg'\n                  alt=''\n                  role='presentation'\n                />\n                <!-- <img\n                  class=\"h-auto w-full\"\n                  src=\"/users/bonsai.png\"\n                  alt=\"\"\n                  role=\"presentation\"\n                /> -->\n              </div>\n\n              <div class='absolute bg-navy h-full -ml-3 mt-3 top-0 w-full z-0'>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  </main>\n  <Footer />\n</Base>\n"
  },
  {
    "path": "landing/src/lib/github.ts",
    "content": "const formatter = Intl.NumberFormat('en-US', {\n  notation: 'compact'\n});\n\nconst defaultStarCount = 11800;\nlet starCount: number | undefined = undefined;\n\nexport async function countStars(\n  repo = 'shipshapecode/shepherd'\n): Promise<number> {\n  if (starCount) {\n    return starCount;\n  }\n\n  try {\n    const repoData = await fetch(`https://api.github.com/repos/${repo}`);\n    const json = await repoData.json();\n\n    starCount = json.stargazers_count * 1 || defaultStarCount;\n  } catch (e) {\n    console.log('Failed to fetch stars', e);\n    starCount = defaultStarCount;\n  }\n\n  return starCount;\n}\n\nexport async function getFormattedStars(\n  repo = 'shipshapecode/shepherd'\n): Promise<string> {\n  const stars = import.meta.env.DEV ? defaultStarCount : await countStars(repo);\n\n  return formatter.format(stars);\n}\n"
  },
  {
    "path": "landing/src/pages/api/checkout.ts",
    "content": "import { Checkout } from '@polar-sh/astro';\n\nexport const prerender = false;\n\nexport const GET = Checkout({\n  accessToken: import.meta.env.POLAR_ACCESS_TOKEN ?? '',\n  successUrl: 'https://docs.shepherdjs.dev'\n});\n"
  },
  {
    "path": "landing/src/pages/blog/[...slug].astro",
    "content": "---\nimport { type CollectionEntry, getCollection } from 'astro:content';\nimport { Image } from 'astro:assets';\nimport BlogPost from '@layouts/BlogPost.astro';\n\nexport async function getStaticPaths() {\n  const posts = await getCollection('blog');\n  return posts.map((post) => ({\n    params: { slug: post.slug },\n    props: post\n  }));\n}\ntype Props = CollectionEntry<'blog'>;\n\nconst post = Astro.props;\nconst { Content } = await post.render();\n---\n\n<BlogPost {...post.data}>\n  <div class=\"section flex flex-wrap justify-center\">\n    <div class=\"max-w-4xl w-full\">\n      <h1\n        class=\"font-heading m-auto max-w-3xl my-8 text-5xl\"\n        itemprop=\"headline\"\n      >\n        {post.data.title}\n      </h1>\n\n      <!-- <AuthorRow\n        categories={post.data.categories}\n        date={post.data.date}\n        id={author.id}\n        image={author.image}\n        name={author.name}\n      /> -->\n\n      {\n        post.data.heroImage && (\n          <figure>\n            <Image\n              alt=\"Shepherd Pro HQ, the kid's playhouse\"\n              class=\"my-6 rounded-md\"\n              itemprop=\"image\"\n              format=\"webp\"\n              height={672}\n              loading=\"lazy\"\n              src={`/img/blog/${post.data.heroImage}`}\n              width={896}\n            />\n            <figcaption class=\"italic mb-12 text-gray-700\">\n              {post.data.heroImageCaption}\n            </figcaption>\n          </figure>\n        )\n      }\n\n      <div\n        class=\"prose max-w-none m-auto\n\t\t\t\tprose-headings:font-heading prose-headings:text-navy\n\t\t\t\tprose-p:font-body\n\t\t\t\tprose-p:text-gray-600\n\t\t\t\tmd:prose-lg lg:prose-xl\"\n      >\n        <Content />\n      </div>\n    </div>\n  </div>\n</BlogPost>\n"
  },
  {
    "path": "landing/src/pages/blog/index.astro",
    "content": "---\nimport { getCollection } from 'astro:content';\n\nimport Base from '@layouts/Base.astro';\nimport Header from '@components/Header.astro';\nimport Footer from '@components/Footer.astro';\nimport { SITE_TITLE } from '../../consts';\nimport FormattedDate from '@components/FormattedDate.astro';\n\nconst posts = (await getCollection('blog')).sort(\n  (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()\n);\n---\n\n<Base>\n  <Header title={SITE_TITLE} />\n  <main class=\"flex justify-center w-full\">\n    <section class=\"max-w-4xl my-10 text-2xl w-full\">\n      <ul class=\"list-square\">\n        {\n          posts.map((post) => (\n            <li class=\"grid grid-cols-[1fr] md:grid-cols-[1fr_auto] mb-3 md:gap-2 items-start\">\n              <div class=\"before:float-left before:leading-7 before:text-red-300 before:text-sm before:mr-2 before:content-['>>']\">\n                <a\n                  href={`/blog/${post.slug}`}\n                  class=\"unset hover:text-navy-light\"\n                >\n                  <h4 class=\"font-bold font-title\">{post.data.title}</h4>\n                </a>\n              </div>\n              <div class=\"text-text-muted text-md italic\">\n                <time datetime={post.data.pubDate.toISOString()}>\n                  <FormattedDate date={post.data.pubDate} />\n                </time>\n              </div>\n            </li>\n          ))\n        }\n      </ul>\n    </section>\n  </main>\n  <Footer />\n</Base>\n"
  },
  {
    "path": "landing/src/pages/index.astro",
    "content": "---\nimport { Code } from 'astro:components';\nimport MainPage from '@layouts/MainPage.astro';\n---\n\n<MainPage isHome={true}>\n  <div\n    class=\"font-heading mt-8 text-6xl text-center uppercase w-full\"\n    slot=\"hero-heading\"\n  >\n    <img\n      class=\"inline p-4 w-full lg:mt-4 lg:p-0 lg:w-auto\"\n      src=\"/img/demo.svg\"\n      alt=\"Demo\"\n    />\n  </div>\n\n  <div slot=\"content\">\n    <div class=\"hero-including mt-8\" id=\"hero-including\">\n      <h3 class=\"demo-heading font-heading text-2xl uppercase\">\n        01. How to Include\n      </h3>\n      <div class=\"hero-example-code text-left\">\n        <Code\n          code={`\n\t<link rel=\"stylesheet\" href=\"shepherd.js/dist/css/shepherd.css\"/>\n\t<script type=\"module\" src=\"shepherd.js/dist/js/shepherd.mjs\"></script>\n  \n`}\n          lang=\"js\"\n          theme=\"nord\"\n          wrap\n        />\n      </div>\n    </div>\n\n    <div class=\"hero-example mt-8\">\n      <h3 class=\"demo-heading font-heading text-2xl uppercase\">02. Example</h3>\n\n      <div class=\"hero-example-code text-left\">\n        <Code\n          code={`\n\tconst tour = new Shepherd.Tour({\n\t\tdefaultStepOptions: {\n\t\t\tcancelIcon: {\n\t\t\t\tenabled: true\n\t\t\t},\n\t\t\tclasses: 'class-1 class-2',\n\t\t\tscrollTo: { behavior: 'smooth', block: 'center' }\n\t\t}\n\t});\n\n\ttour.addStep({\n\t\ttitle: 'Creating a Shepherd Tour',\n\t\ttext: 'Creating a Shepherd tour is easy. too! Just create a \"Tour\" instance, and add as many steps as you want.',\n\t\tattachTo: {\n\t\t\telement: '.hero-example',\n\t\t\ton: 'bottom'\n\t\t},\n\t\tbuttons: [\n\t\t\t{\n\t\t\t\taction() {\n\t\t\t\t\treturn this.back();\n\t\t\t\t},\n\t\t\t\tclasses: 'shepherd-button-secondary',\n\t\t\t\ttext: 'Back'\n\t\t\t},\n\t\t\t{\n\t\t\t\taction() {\n\t\t\t\t\treturn this.next();\n\t\t\t\t},\n\t\t\t\ttext: 'Next'\n\t\t\t}\n\t\t],\n\t\tid: 'creating'\n\t});\n\n\ttour.start();\n\t\t\t\t\t`}\n          lang=\"js\"\n          theme=\"nord\"\n          wrap\n        />\n      </div>\n    </div>\n  </div>\n</MainPage>\n\n<script>\n  import Shepherd from 'shepherd.js';\n\n  (function () {\n    async function init() {\n      // wait for shepherd to be ready\n      setTimeout(function () {\n        const shepherd = setupShepherd();\n        \n        // Check if we should auto-start the tour (after redirect from another page)\n        const shouldStartTour = sessionStorage.getItem('startTourOnLoad');\n        if (shouldStartTour) {\n          sessionStorage.removeItem('startTourOnLoad');\n          shepherd.start();\n        }\n        \n        // Clean up previous listener if it exists\n        if ((window as any).__startTourAbortController) {\n          (window as any).__startTourAbortController.abort();\n        }\n        \n        // Create new AbortController for this listener\n        const controller = new AbortController();\n        (window as any).__startTourAbortController = controller;\n        \n        // Listen for custom event from Demo button when already on home page\n        window.addEventListener('startTour', () => shepherd.start(), { signal: controller.signal });\n      }, 400);\n    }\n\n    function setupShepherd() {\n      const element = document.createElement('p');\n      element.innerText =\n        'Including Shepherd is easy! Just include shepherd.js. The styles are bundled with the JS.';\n\n      const shepherd = new Shepherd.Tour({\n        id: 'ts4udfrnm7o95ny7e9qbjo3t',\n        defaultStepOptions: {\n          cancelIcon: {\n            enabled: true\n          },\n          classes: 'class-1 class-2',\n          scrollTo: {\n            behavior: 'smooth',\n            block: 'center'\n          }\n        },\n        // This should add the first tour step\n        steps: [\n          {\n            text: '\\n         <p>\\n           Shepherd is a JavaScript library for guiding users through your app.\\n           It uses <a href=\"https://floating-ui.com/\" data-test-popper-link>Floating UI</a>,\\n           another open source library, to render dialogs for each tour \"step\".\\n         </p>\\n        \\n         <p>\\n           Among many things, Floating UI makes sure your steps never end up off screen or cropped by an overflow.\\n           (Try resizing your browser to see what we mean.)\\n         </p>\\n',\n            attachTo: {\n              element: '.hero-welcome',\n              on: 'bottom'\n            },\n            buttons: [\n              {\n                action() {\n                  return this.cancel();\n                },\n                secondary: true,\n                text: 'Exit'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                text: 'Next'\n              }\n            ],\n            id: 'welcome'\n          },\n          {\n            title: 'Features',\n            text: 'Shepherd has many built-in features to guide users through your app. You can easily customize the look and feel of your tour by adding your own styles. Also, you can highlight multiple elements at once to draw attention to key areas of your application.',\n            attachTo: {\n              element: '.customizable',\n              on: 'bottom'\n            },\n            extraHighlights: ['.feature'],\n            buttons: [\n              {\n                action() {\n                  return this.back();\n                },\n                secondary: true,\n                text: 'Back'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                text: 'Next'\n              }\n            ],\n            id: 'features'\n          },\n          {\n            title: 'Including',\n            text: element,\n            attachTo: {\n              element: '.hero-including',\n              on: 'bottom'\n            },\n            buttons: [\n              {\n                action() {\n                  return this.back();\n                },\n                secondary: true,\n                text: 'Back'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                text: 'Next'\n              }\n            ],\n            id: 'including'\n          },\n          {\n            title: 'Creating a Shepherd Tour',\n            text:\n              'Creating a Shepherd tour is easy. too! ' +\n              'Just create a `Tour` instance, and add as many steps as you want.',\n            attachTo: {\n              element: '.hero-example',\n              on: 'right'\n            },\n            buttons: [\n              {\n                action() {\n                  return this.back();\n                },\n                secondary: true,\n                text: 'Back'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                text: 'Next'\n              }\n            ],\n            id: 'creating'\n          },\n          {\n            title: 'Attaching to Elements',\n            text: 'Your tour steps can target and attach to elements in DOM (like this step).',\n            attachTo: {\n              element: '.hero-example',\n              on: 'left'\n            },\n            buttons: [\n              {\n                action() {\n                  return this.back();\n                },\n                secondary: true,\n                text: 'Back'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                text: 'Next'\n              }\n            ],\n            id: 'attaching'\n          }\n        ],\n        useModalOverlay: true\n      });\n\n      // This should add steps after the ones added with `addSteps`\n      shepherd.addStep({\n        title: 'Centered Shepherd Element',\n        text: 'But attachment is totally optional!\\n       Without a target, a tour step will create an element that\\'s centered within the view.       Check out the <a href=\"https://docs.shepherdjs.dev/\">documentation</a> to learn more.',\n        buttons: [\n          {\n            action() {\n              return this.back();\n            },\n            secondary: true,\n            text: 'Back'\n          },\n          {\n            action() {\n              return this.next();\n            },\n            text: 'Next'\n          }\n        ],\n        id: 'centered-example'\n      });\n\n      shepherd.addStep({\n        title: 'Learn more',\n        text: 'Star Shepherd on Github so you remember it for your next project',\n        attachTo: {\n          element: '.hero-followup',\n          on: 'top'\n        },\n        buttons: [\n          {\n            action() {\n              return this.back();\n            },\n            secondary: true,\n            text: 'Back'\n          },\n          {\n            action() {\n              return this.next();\n            },\n            text: 'Done'\n          }\n        ],\n        id: 'followup',\n        modalOverlayOpeningPadding: 10\n      });\n      return shepherd;\n    }\n\n    function ready() {\n      // Only listen for astro:page-load which fires on both initial load and transitions\n      document.addEventListener('astro:page-load', init);\n    }\n\n    ready();\n  }).call(void 0);\n</script>\n"
  },
  {
    "path": "landing/src/pages/pricing.astro",
    "content": "---\nimport BaseHead from '@components/BaseHead.astro';\nimport Header from '@components/Header.astro';\nimport Footer from '@components/Footer.astro';\nimport { SITE_TITLE, SITE_DESCRIPTION } from '../consts';\n---\n\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />\n  </head>\n  <body class=\"bg-white font-body text-navy\">\n    <Header title={SITE_TITLE} />\n    <main>\n      <div class=\"bg-white flex justify-center py-12 sm:py-20\">\n        <div class=\"max-w-6xl px-6 lg:px-8\">\n          <h2\n            class=\"mt-2 text-4xl font-bold font-heading tracking-tight text-gray-900 uppercase sm:text-5xl\"\n          >\n            Choose the right next step for you\n          </h2>\n\n          <p class=\"font-body mt-6 text-xl text-left leading-8 text-gray-600\">\n            Shepherd remains open-source software, and this commitment is\n            unwavering. Our library serves as a foundation for countless solo\n            developers and esteemed organizations, empowering them to create\n            their applications. With a thriving community of users, the ongoing\n            enhancement and upkeep of the library, documentation, and community\n            engagement demand significant resources. Your support is essential\n            for us to continue this mission. So, if you want to use Shepherd.js\n            in your commercial app, website or plugin, you would need to obtain\n            a commercial license.\n          </p>\n\n          <div class=\"my-20 flow-root\">\n            <div\n              class=\"isolate -mt-16 grid grid-cols-1 gap-y-16 divide-y divide-gray-100 sm:mx-auto lg:-mx-8 lg:mt-0 lg:grid-cols-3 lg:divide-x lg:divide-y-0 xl:-mx-4\"\n            >\n              <div class=\"pt-16 lg:px-8 lg:pt-0 xl:px-14\">\n                <h3 class=\"font-heading text-xl uppercase w-full\">\n                  Business Plan\n                </h3>\n                <p class=\"mt-6 flex items-baseline gap-x-1\">\n                  <span class=\"text-5xl font-bold tracking-tight text-gray-900\"\n                    >$50</span\n                  >\n                  <span class=\"text-sm font-semibold leading-6 text-gray-600\"\n                    >/lifetime</span\n                  >\n                </p>\n                <div class=\"bg-navy font-heading inline-block mb-4 w-56\">\n                  <button\n                    class=\"button bg-white border-2 border-navy p-6 text-navy whitespace-nowrap w-full\"\n                    aria-describedby=\"purchase business license\"\n                    data-pricing-id=\"5dea1175-6e19-4613-bf7a-a0ae4354ccf9\"\n                    type=\"button\"\n                  >\n                    Purchase\n                  </button>\n                </div>\n                <p class=\"mt-10 text-m font-semibold leading-6 text-gray-900\">\n                  Everything necessary to get started.\n                </p>\n                <ul\n                  role=\"list\"\n                  class=\"mt-6 space-y-3 text-l leading-6 text-gray-600\"\n                >\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Up to 5 projects\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    1 month commercial support\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Regular product updates\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Lifetime license\n                  </li>\n                </ul>\n              </div>\n              <div class=\"pt-16 lg:px-8 lg:pt-0 xl:px-14\">\n                <h3 class=\"font-heading text-xl uppercase w-full\">\n                  Enterprise Plan\n                </h3>\n                <p class=\"mt-6 flex items-baseline gap-x-1\">\n                  <span class=\"text-5xl font-bold tracking-tight text-gray-900\"\n                    >$300</span\n                  >\n                  <span class=\"text-sm font-semibold leading-6 text-gray-600\"\n                    >/lifetime</span\n                  >\n                </p>\n                <div class=\"bg-navy font-heading inline-block mb-4 w-56\">\n                  <button\n                    class=\"button bg-white border-2 border-navy p-6 text-navy whitespace-nowrap w-full\"\n                    aria-describedby=\"purchase enterprise license\"\n                    data-pricing-id=\"713b19cd-7fbf-41fb-9bf7-b5c25c318406\"\n                    type=\"button\"\n                  >\n                    Purchase\n                  </button>\n                </div>\n                <p class=\"mt-10 text-m font-semibold leading-6 text-gray-900\">\n                  Partner to use on all your products.\n                </p>\n                <ul\n                  role=\"list\"\n                  class=\"mt-6 space-y-3 text-l leading-6 text-gray-600\"\n                >\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Unlimited projects\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    6 months support\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Prioritized Github Issues\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Lifetime license\n                  </li>\n                </ul>\n              </div>\n\n              <div class=\"pt-16 lg:px-8 lg:pt-0 xl:px-14\">\n                <h3 class=\"font-heading text-xl uppercase w-full\">\n                  Shepherd Consulting\n                </h3>\n                <p class=\"mt-6 mb-4 flex items-baseline gap-x-1\">\n                  <span class=\"text-4xl font-bold tracking-tight text-gray-900\"\n                    >Request a Quote</span\n                  >\n                </p>\n\n                <div class=\"bg-navy font-heading inline-block mb-4 w-56\">\n                  <a\n                    class=\"button bg-white border-2 text-center border-navy p-6 text-navy whitespace-nowrap w-full\"\n                    href=\"mailto:ahoy@shipshape.io\"\n                    aria-describedby=\"tier-growth\"\n                  >\n                    Contact Us\n                  </a>\n                </div>\n                <p class=\"mt-10 text-m font-semibold leading-6 text-gray-900\">\n                  Let us help you get the most out of Shepherd\n                </p>\n                <ul\n                  role=\"list\"\n                  class=\"mt-6 space-y-3 text-m leading-6 text-gray-600\"\n                >\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    White-Glove Services\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    On-Boarding & Training\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Advanced analytics\n                  </li>\n                  <li class=\"flex gap-x-3\">\n                    <svg\n                      class=\"h-5 w-5 flex-none text-indigo-600\"\n                      viewBox=\"0 0 20 20\"\n                      fill=\"currentColor\"\n                      aria-hidden=\"true\"\n                    >\n                      <path\n                        fill-rule=\"evenodd\"\n                        d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z\"\n                        clip-rule=\"evenodd\"></path>\n                    </svg>\n                    Support via Professional Services\n                  </li>\n                </ul>\n              </div>\n            </div>\n          </div>\n\n          <div class=\"mb-8 mt-4 relative lg:mt-20\">\n            <div class=\"\">\n              <div\n                class=\"bg-grey-light px-6 py-8 sm:p-10 lg:flex lg:items-center\"\n              >\n                <div class=\"flex-1\">\n                  <div>\n                    <h3\n                      class=\"inline-flex px-4 py-1 pt-2 text-sm font-semibold tracking-wide uppercase bg-white text-gray-800\"\n                    >\n                      Free plan\n                    </h3>\n                  </div><div class=\"mt-4 text-lg text-gray-600\">\n                    Shepherd.js is free for open-source, personal and\n                    non-commercial sites. If your project is non-commercial, you\n                    can use Shepherd.js for free.\n                  </div>\n                </div>\n                <div class=\"mt-6 lg:mt-2 lg:ml-10 lg:shrink-0\">\n                  <div class=\"bg-navy font-heading inline-block mb-4 w-56\">\n                    <a\n                      class=\"button bg-white border-2 text-center border-navy p-4 text-navy whitespace-nowrap w-full\"\n                      href=\"https://github.com/shipshapecode/shepherd\"\n                      aria-describedby=\"link to github\"\n                    >\n                      Enjoy Free Software!\n                    </a>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </main>\n    <Footer />\n  </body>\n</html>\n\n<script>\n  document.addEventListener('astro:page-load', () => {\n    const buttons = document.querySelectorAll('[data-pricing-id]');\n\n    // Store original button texts\n    const buttonStates = new Map();\n    buttons.forEach((button) => {\n      if (button instanceof HTMLButtonElement) {\n        buttonStates.set(button, button.innerHTML);\n      }\n    });\n\n    // Reset button states when user navigates back\n    const resetButtons = () => {\n      buttons.forEach((button) => {\n        if (button instanceof HTMLButtonElement) {\n          const originalText = buttonStates.get(button);\n          if (originalText) {\n            button.disabled = false;\n            button.innerHTML = originalText;\n          }\n        }\n      });\n    };\n\n    // Listen for page visibility changes (when user comes back from checkout)\n    document.addEventListener('visibilitychange', () => {\n      if (document.visibilityState === 'visible') {\n        resetButtons();\n      }\n    });\n\n    // Also reset on page show event (handles browser back button)\n    window.addEventListener('pageshow', (event) => {\n      // Reset buttons if coming back via browser navigation\n      resetButtons();\n    });\n\n    buttons.forEach((button) => {\n      button.addEventListener('click', async (event) => {\n        if (!(event.target instanceof HTMLButtonElement)) {\n          return;\n        }\n        const btn = event.target;\n        const originalText = buttonStates.get(btn);\n        btn.disabled = true;\n        btn.innerHTML = `\n        <span class=\"inline-flex items-center\">\n          <span class=\"mr-2\">Loading</span>\n          <span class=\"flex space-x-1\">\n            <span class=\"w-2 h-2 bg-navy-light rounded-full animate-ellipsis1\"></span>\n            <span class=\"w-2 h-2 bg-navy-light rounded-full animate-ellipsis2\"></span>\n            <span class=\"w-2 h-2 bg-navy-light rounded-full animate-ellipsis3\"></span>\n          </span>\n        </span>\n      `;\n\n        const productId = event.target?.dataset.pricingId;\n\n        if (!productId) {\n          console.warn('No product ID found for this button');\n          btn.disabled = false;\n          btn.innerHTML = originalText || '';\n          return;\n        }\n\n        // Use full-page navigation to follow server-side redirect to external Polar checkout\n        window.location.href = `/api/checkout?products=${productId}`;\n      });\n    });\n  });\n</script>\n"
  },
  {
    "path": "landing/src/pages/rss.xml.js",
    "content": "import rss from '@astrojs/rss';\nimport { getCollection } from 'astro:content';\nimport { SITE_TITLE, SITE_DESCRIPTION } from '../consts';\n\nexport async function GET(context) {\n\tconst posts = await getCollection('blog');\n\treturn rss({\n\t\ttitle: SITE_TITLE,\n\t\tdescription: SITE_DESCRIPTION,\n\t\tsite: context.site,\n\t\titems: posts.map((post) => ({\n\t\t\t...post.data,\n\t\t\tlink: `/blog/${post.slug}/`,\n\t\t})),\n\t});\n}\n"
  },
  {
    "path": "landing/src/styles/fonts.css",
    "content": "@font-face {\n  font-family: 'GT Pressura';\n  src: url('/fonts/GTPressura-Bold.woff2') format('woff2'),\n  url('/fonts/GTPressura-Bold.woff') format('woff');\n  font-weight: bold;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'Founders Grotesk';\n  src: url('/fonts/FoundersGrotesk-Regular.woff2') format('woff2'),\n  url('/fonts/FoundersGrotesk-Regular.woff') format('woff');\n  font-weight: normal;\n  font-style: normal;\n}\n"
  },
  {
    "path": "landing/src/styles/prism.css",
    "content": "/*\n\nName:       Base16 Ocean Dark\nAuthor:     Chris Kempson (http://chriskempson.com)\n\nPrism template by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/prism/)\nOriginal Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\ncode[class*=\"language-\"],\npre[class*=\"language-\"] {\n  font-family: Consolas, Menlo, Monaco, \"Andale Mono WT\", \"Andale Mono\", \"Lucida Console\", \"Lucida Sans Typewriter\", \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\", \"Liberation Mono\", \"Nimbus Mono L\", \"Courier New\", Courier, monospace;\n  font-size: 14px;\n  line-height: 1.375;\n  direction: ltr;\n  text-align: left;\n  white-space: pre;\n  word-spacing: normal;\n  word-break: normal;\n  -moz-tab-size: 4;\n  -o-tab-size: 4;\n  tab-size: 4;\n  -webkit-hyphens: none;\n  -ms-hyphens: none;\n  hyphens: none;\n  background: #2b303b;\n  color: #c0c5ce;\n}\n\npre[class*=\"language-\"]::-moz-selection, pre[class*=\"language-\"] ::-moz-selection,\ncode[class*=\"language-\"]::-moz-selection, code[class*=\"language-\"] ::-moz-selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\npre[class*=\"language-\"]::selection, pre[class*=\"language-\"] ::selection,\ncode[class*=\"language-\"]::selection, code[class*=\"language-\"] ::selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\n/* Code blocks */\npre[class*=\"language-\"] {\n  padding: 2rem;\n  margin: .5em 0;\n  overflow: auto;\n}\n\n/* Inline code */\n:not(pre) > code[class*=\"language-\"] {\n  padding: .1em;\n  border-radius: .3em;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n  color: #65737e;\n}\n\n.token.punctuation {\n  color: #c0c5ce;\n}\n\n.token.namespace {\n  opacity: .7;\n}\n\n.token.operator,\n.token.boolean,\n.token.number {\n  color: #d08770;\n}\n\n.token.property {\n  color: #ebcb8b;\n}\n\n.token.tag {\n  color: #8fa1b3;\n}\n\n.token.string {\n  color: #96b5b4;\n}\n\n.token.selector {\n  color: #b48ead;\n}\n\n.token.attr-name {\n  color: #d08770;\n}\n\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n  color: #96b5b4;\n}\n\n.token.attr-value,\n.token.keyword,\n.token.control,\n.token.directive,\n.token.unit {\n  color: #a3be8c;\n}\n\n.token.statement,\n.token.regex,\n.token.atrule {\n  color: #96b5b4;\n}\n\n.token.placeholder,\n.token.variable {\n  color: #8fa1b3;\n}\n\n.token.deleted {\n  text-decoration: line-through;\n}\n\n.token.inserted {\n  border-bottom: 1px dotted #eff1f5;\n  text-decoration: none;\n}\n\n.token.italic {\n  font-style: italic;\n}\n\n.token.important,\n.token.bold {\n  font-weight: bold;\n}\n\n.token.important {\n  color: #bf616a;\n}\n\n.token.entity {\n  cursor: help;\n}\n\npre > code.highlight {\n  outline: 0.4em solid #bf616a;\n  outline-offset: .4em;\n}\n\n.line-numbers .line-numbers-rows {\n  border-right-color: #343d46 !important;\n}\n\n.line-numbers-rows > span:before {\n  color: #4f5b66 !important;\n}\n\n.line-highlight {\n  background: rgba(239, 241, 245, 0.2) !important;\n  background: -webkit-linear-gradient(left, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n  background: linear-gradient(to right, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n}\n"
  },
  {
    "path": "landing/src/styles/shepherd.css",
    "content": ".shepherd-button{background:#3288e6;border:0;border-radius:3px;color:hsla(0,0%,100%,.75);cursor:pointer;margin-right:.5rem;padding:.5rem 1.5rem;transition:all .5s ease}.shepherd-button:not(:disabled):hover{background:#196fcc;color:hsla(0,0%,100%,.75)}.shepherd-button.shepherd-button-secondary{background:#f1f2f3;color:rgba(0,0,0,.75)}.shepherd-button.shepherd-button-secondary:not(:disabled):hover{background:#d6d9db;color:rgba(0,0,0,.75)}.shepherd-button:disabled{cursor:not-allowed}\n.shepherd-footer{border-bottom-left-radius:5px;border-bottom-right-radius:5px;display:flex;justify-content:flex-end;padding:0 .75rem .75rem}.shepherd-footer .shepherd-button:last-child{margin-right:0}\n.shepherd-cancel-icon{background:transparent;border:none;color:hsla(0,0%,50%,.75);cursor:pointer;font-size:2em;font-weight:400;margin:0;padding:0;transition:color .5s ease}.shepherd-cancel-icon:hover{color:rgba(0,0,0,.75)}.shepherd-has-title .shepherd-content .shepherd-cancel-icon{color:hsla(0,0%,50%,.75)}.shepherd-has-title .shepherd-content .shepherd-cancel-icon:hover{color:rgba(0,0,0,.75)}\n.shepherd-title{color:rgba(0,0,0,.75);display:flex;flex:1 0 auto;font-size:1rem;font-weight:400;margin:0;padding:0}\n.shepherd-header{align-items:center;border-top-left-radius:5px;border-top-right-radius:5px;display:flex;justify-content:flex-end;line-height:2em;padding:.75rem .75rem 0}.shepherd-has-title .shepherd-content .shepherd-header{background:#e6e6e6;padding:1em}\n.shepherd-text{color:rgba(0,0,0,.75);font-size:1rem;line-height:1.3em;padding:.75em}.shepherd-text p{margin-top:0}.shepherd-text p:last-child{margin-bottom:0}\n.shepherd-content{border-radius:5px;outline:none;padding:0}\n.shepherd-element{background:#fff;border-radius:5px;box-shadow:0 1px 4px rgba(0,0,0,.2);margin: 0;max-width:400px;opacity:0;outline:none;transition:opacity .3s,visibility .3s;visibility:hidden;width:100%;z-index:9999}.shepherd-enabled.shepherd-element{opacity:1;visibility:visible}.shepherd-element[data-popper-reference-hidden]:not(.shepherd-centered){opacity:0;pointer-events:none;visibility:hidden}.shepherd-element,.shepherd-element *,.shepherd-element :after,.shepherd-element :before{box-sizing:border-box}.shepherd-arrow,.shepherd-arrow:before{height:16px;position:absolute;width:16px;z-index:-1}.shepherd-arrow:before{background:#fff;content:\"\";transform:rotate(45deg)}.shepherd-element[data-popper-placement^=top]>.shepherd-arrow{bottom:-8px}.shepherd-element[data-popper-placement^=bottom]>.shepherd-arrow{top:-8px}.shepherd-element[data-popper-placement^=left]>.shepherd-arrow{right:-8px}.shepherd-element[data-popper-placement^=right]>.shepherd-arrow{left:-8px}.shepherd-element.shepherd-centered>.shepherd-arrow{opacity:0}.shepherd-element.shepherd-has-title[data-popper-placement^=bottom]>.shepherd-arrow:before{background-color:#e6e6e6}.shepherd-target-click-disabled.shepherd-enabled.shepherd-target,.shepherd-target-click-disabled.shepherd-enabled.shepherd-target *{pointer-events:none}\n.shepherd-modal-overlay-container{height:0;left:0;opacity:0;overflow:hidden;pointer-events:none;position:fixed;top:0;transition:all .3s ease-out,height 0ms .3s,opacity .3s 0ms;width:100vw;z-index:9997}.shepherd-modal-overlay-container.shepherd-modal-is-visible{height:100vh;opacity:.5;transform:translateZ(0);transition:all .3s ease-out,height 0s 0s,opacity .3s 0s}.shepherd-modal-overlay-container.shepherd-modal-is-visible path{pointer-events:all}"
  },
  {
    "path": "landing/src/styles/styles.css",
    "content": "@import 'tailwindcss';\n\n@plugin '@tailwindcss/typography';\n\n@theme {\n  --shadow-*: initial;\n  --shadow-default:\n    0 10px 30px 0 rgba(0, 0, 0, 1), 0 10px 20px 0 rgba(0, 0, 0, 1);\n\n  --color-*: initial;\n  --color-transparent: transparent;\n  --color-black: #000000;\n  --color-navy: #16202d;\n  --color-navy-light: #959fac;\n  --color-grey: #f3f5f5;\n  --color-grey-light: #eff2f3;\n  --color-white: #ffffff;\n\n  --color-pink-200: #ffa6f6;\n  --color-pink-300: #fa8cef;\n  --color-pink-400: #fa7fee;\n\n  --font-*: initial;\n  --font-body: Founders Grotesk, sans-serif;\n  --font-heading: GT Pressura, sans-serif;\n\n  --text-*: initial;\n  --text-xs: 0.75rem;\n  --text-sm: 0.875rem;\n  --text-base: 1rem;\n  --text-lg: 1.125rem;\n  --text-xl: 1.25rem;\n  --text-2xl: 1.5rem;\n  --text-3xl: 1.875rem;\n  --text-4xl: 2.25rem;\n  --text-5xl: 3rem;\n  --text-6xl: 4rem;\n\n  --container-*: initial;\n  --container-xxs: 13rem;\n  --container-xs: 20rem;\n  --container-sm: 24rem;\n  --container-md: 28rem;\n  --container-lg: 32rem;\n  --container-xl: 36rem;\n  --container-2xl: 42rem;\n  --container-3xl: 48rem;\n  --container-4xl: 56rem;\n  --container-5xl: 64rem;\n  --container-6xl: 72rem;\n  --container-7xl: 80rem;\n  --container-8xl: 90rem;\n  --container-9xl: 100rem;\n  --container-full: 100%;\n\n  --spacing-*: initial;\n  --spacing-0: 0;\n  --spacing-1: 0.25rem;\n  --spacing-2: 0.5rem;\n  --spacing-3: 0.75rem;\n  --spacing-4: 1rem;\n  --spacing-5: 1.25rem;\n  --spacing-6: 1.5rem;\n  --spacing-8: 2rem;\n  --spacing-10: 2.5rem;\n  --spacing-12: 3rem;\n  --spacing-16: 4rem;\n  --spacing-20: 5rem;\n  --spacing-24: 6rem;\n  --spacing-32: 8rem;\n  --spacing-40: 10rem;\n  --spacing-48: 12rem;\n  --spacing-56: 14rem;\n  --spacing-64: 16rem;\n  --spacing-72: 18rem;\n  --spacing-80: 20rem;\n  --spacing-140: 36rem;\n  --spacing-px: 1px;\n\n  --animate-ellipsis1: ellipsis 1s infinite;\n  --animate-ellipsis2: ellipsis 1s infinite 0.333s;\n  --animate-ellipsis3: ellipsis 1s infinite 0.666s;\n\n  @keyframes ellipsis {\n    0% {\n      transform: scale(0);\n    }\n    50% {\n      transform: scale(1);\n    }\n    100% {\n      transform: scale(0);\n    }\n  }\n}\n\n/*\n  The default border color has changed to `currentcolor` in Tailwind CSS v4,\n  so we've added these compatibility styles to make sure everything still\n  looks the same as it did with Tailwind CSS v3.\n\n  If we ever want to remove these styles, we need to add an explicit border\n  color utility to any element that depends on these defaults.\n*/\n@layer base {\n  *,\n  ::after,\n  ::before,\n  ::backdrop,\n  ::file-selector-button {\n    border-color: var(--color-gray-200, currentcolor);\n  }\n}\n\nhtml,\nbody {\n  font-family: 'Pier Sans', 'proxima-nova', 'Helvetica Neue', sans-serif;\n}\n\nbody {\n  height: 100%;\n  margin: 0;\n}\n\na,\nbutton {\n  transition: 0.25s ease-in-out;\n}\n\n.a11y-icon {\n  left: 50%;\n  transform: translateX(-50%) translateY(10%);\n}\n\n.customizable-icon {\n  left: 50%;\n  transform: translateX(-50%) translateY(25%);\n}\n\n.framework-icon {\n  left: 50%;\n  transform: translateX(-50%) translateY(35%);\n}\n\n.button {\n  cursor: pointer;\n  display: inline-block;\n  text-decoration: none;\n  text-transform: uppercase;\n  transition: 0.25s ease-in-out;\n}\n\n.button:hover {\n  background: #f3f5f5;\n  transform: translateX(10px) translateY(-10px);\n}\n\n.shepherd-logo {\n  height: auto;\n  width: 217px;\n}\n\n.shepherd-logo .lines,\n.shepherd-logo .open-eye,\n.shepherd-logo .wink {\n  transition:\n    visibility 0s,\n    opacity 0.25s ease-in-out;\n}\n\n.shepherd-logo .open-eye {\n  opacity: 1;\n  visibility: visible;\n}\n\n.shepherd-logo .lines,\n.shepherd-logo .wink {\n  opacity: 0;\n  visibility: hidden;\n}\n\n.shepherd-logo:hover .lines,\n.shepherd-logo:hover .wink {\n  opacity: 1;\n  visibility: visible;\n}\n\n.shepherd-logo:hover .open-eye {\n  opacity: 0;\n  visibility: hidden;\n}\n\n.footer-icon path {\n  fill: #16202d;\n  transition: 0.25s ease-in-out;\n}\n\n.footer-icon:hover path {\n  fill: #959fac;\n}\n\n.footer-logo {\n  left: 50%;\n  transform: translateX(-50%) translateY(-50%);\n}\n\n.hero-outer .hero-followup {\n  padding-top: 20px;\n}\n\npre {\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  line-height: 1.4em;\n}\n\n.shepherd-button {\n  background: #ffffff;\n  border-top: solid 4px #16202d;\n  border-radius: 0;\n  color: #16202d;\n  display: flex;\n  flex-grow: 1;\n  font-family: 'GT Pressura', sans-serif;\n  font-size: 1rem;\n  justify-content: center;\n  margin: 0;\n  padding: 1rem;\n  text-align: center;\n  text-transform: uppercase;\n}\n\n.shepherd-button:hover {\n  background: #16202d;\n  color: #ffffff;\n}\n\n.shepherd-button.shepherd-button-secondary {\n  background: #cad5d5;\n}\n\n.shepherd-button.shepherd-button-secondary:hover {\n  color: #cad5d5;\n  background: #16202d;\n}\n\n.shepherd-cancel-icon {\n  font-family: 'GT Pressura', sans-serif;\n}\n\n.shepherd-element {\n  border: solid 4px #16202d;\n}\n\n.shepherd-element,\n.shepherd-header,\n.shepherd-footer {\n  border-radius: 0;\n}\n\n.shepherd-element .shepherd-arrow {\n  border-width: 0;\n  height: auto;\n  width: auto;\n}\n\n.shepherd-arrow::before {\n  display: none;\n}\n\n.shepherd-element .shepherd-arrow:after {\n  content: url('../img/arrow.svg');\n  display: inline-block;\n}\n\n.shepherd-element[data-popper-placement^='top'] .shepherd-arrow,\n.shepherd-element.shepherd-pinned-top .shepherd-arrow {\n  bottom: -35px;\n}\n\n.shepherd-element[data-popper-placement^='top'] .shepherd-arrow:after,\n.shepherd-element.shepherd-pinned-top .shepherd-arrow:after {\n  transform: rotate(270deg);\n}\n\n.shepherd-element[data-popper-placement^='bottom'] .shepherd-arrow {\n  top: -35px;\n}\n\n.shepherd-element[data-popper-placement^='bottom'] .shepherd-arrow:after {\n  transform: rotate(90deg);\n}\n\n.shepherd-element[data-popper-placement^='left'] .shepherd-arrow,\n.shepherd-element.shepherd-pinned-left .shepherd-arrow {\n  right: -35px;\n}\n\n.shepherd-element[data-popper-placement^='left'] .shepherd-arrow:after,\n.shepherd-element.shepherd-pinned-left .shepherd-arrow:after {\n  transform: rotate(180deg);\n}\n\n.shepherd-element[data-popper-placement^='right'] .shepherd-arrow,\n.shepherd-element.shepherd-pinned-right .shepherd-arrow {\n  left: -35px;\n}\n\n.shepherd-footer {\n  padding: 0;\n}\n\n.shepherd-footer button:not(:last-of-type) {\n  border-right: solid 4px #16202d;\n}\n\n.shepherd-has-title .shepherd-content .shepherd-cancel-icon {\n  margin-top: -7px;\n}\n\n.shepherd-has-title .shepherd-content .shepherd-header {\n  background: transparent;\n  font-family: 'GT Pressura', sans-serif;\n  padding-bottom: 0;\n  padding-left: 2rem;\n}\n\n.shepherd-has-title .shepherd-content .shepherd-header .shepherd-title {\n  font-size: 1.2rem;\n  text-transform: uppercase;\n}\n\n.shepherd-text {\n  font-size: 1.2rem;\n  padding: 2rem;\n}\n\n.shepherd-text a,\n.shepherd-text a:visited,\n.shepherd-text a:active {\n  border-bottom: 1px dotted;\n  border-bottom-color: rgba(0, 0, 0, 0.75);\n  color: rgba(0, 0, 0, 0.75);\n  text-decoration: none;\n}\n\n.shepherd-text a:hover,\n.shepherd-text a:visited:hover,\n.shepherd-text a:active:hover {\n  border-bottom-style: solid;\n}\n"
  },
  {
    "path": "landing/tsconfig.json",
    "content": "{\n  \"extends\": \"astro/tsconfigs/strict\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@components/*\": [\"src/components/*\"],\n      \"@layouts/*\": [\"src/layouts/*\"]\n    },\n    \"strictNullChecks\": true,\n    \"verbatimModuleSyntax\": true\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"shepherd-monorepo\",\n  \"private\": \"true\",\n  \"description\": \"The monorepo for Shepherd\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/shipshapecode/shepherd.git\"\n  },\n  \"license\": \"AGPL-3.0\",\n  \"scripts\": {\n    \"build\": \"pnpm -F shepherd.js build && pnpm -F '!shepherd.js' -F !landing -F !shepherd-docs build\",\n    \"cypress:install\": \"pnpm -F shepherd.js cypress:install\",\n    \"dev\": \"pnpm watch\",\n    \"lint\": \"pnpm -F '*' lint\",\n    \"lint:fix\": \"pnpm -F '*' lint:fix\",\n    \"lint:js\": \"pnpm -F '*' lint:js\",\n    \"lint:prettier\": \"pnpm -F '*' lint:prettier\",\n    \"lint:prettier:fix\": \"pnpm -F '*' lint:prettier:fix\",\n    \"prepare\": \"pnpm -F shepherd.js build\",\n    \"start\": \"pnpm watch\",\n    \"test:ci\": \"pnpm build && pnpm -F shepherd.js test:ci\",\n    \"test:cy:ci\": \"pnpm -F shepherd.js test:cy:ci\",\n    \"test:cy:watch\": \"pnpm -F shepherd.js test:cy:watch\",\n    \"test:unit:ci\": \"pnpm -F shepherd.js test:unit:ci\",\n    \"test:unit:watch\": \"pnpm -F shepherd.js test:unit:watch\",\n    \"types:check\": \"pnpm -F shepherd.js types:check\",\n    \"view-coverage\": \"pnpm -F shepherd.js view-coverage\",\n    \"watch\": \"pnpm -F shepherd.js watch\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@eslint/js\": \"^9.39.4\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.56.1\",\n    \"@typescript-eslint/parser\": \"^8.56.1\",\n    \"autoprefixer\": \"^10.4.27\",\n    \"concurrently\": \"^9.2.1\",\n    \"del\": \"^7.1.0\",\n    \"eslint\": \"^9.39.3\",\n    \"postcss\": \"^8.5.8\",\n    \"prettier\": \"3.8.1\",\n    \"prettier-plugin-astro\": \"^0.14.1\",\n    \"release-plan\": \"^0.17.4\",\n    \"replace\": \"^1.2.2\",\n    \"shepherd.js\": \"workspace:*\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"packageManager\": \"pnpm@10.28.2\",\n  \"engines\": {\n    \"node\": \">= 20\"\n  },\n  \"authors\": [\n    \"Robbie Wagner <rwwagner90@gmail.com>\",\n    \"Chuck Carpenter <chuck@shipshape.io>\"\n  ]\n}\n"
  },
  {
    "path": "packages/react/.gitignore",
    "content": "# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore\n\n# Logs\n\nlogs\n_.log\nnpm-debug.log_\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Caches \n\n.cache\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\n\nreport.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json\n\n# Runtime data\n\npids\n_.pid\n_.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\n\nlib-cov\n\n# Coverage directory used by tools like istanbul\n\ncoverage\n*.lcov\n\n# nyc test coverage\n\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n\n.grunt\n\n# Bower dependency directory (https://bower.io/)\n\nbower_components\n\n# node-waf configuration\n\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\n\nbuild/Release\n\n# Dependency directories\n\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\n\nweb_modules/\n\n# TypeScript cache\n\n*.tsbuildinfo\n\n# Optional npm cache directory\n\n.npm\n\n# Optional eslint cache\n\n.eslintcache\n\n# Optional stylelint cache\n\n.stylelintcache\n\n# Microbundle cache\n\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n\n.node_repl_history\n\n# Output of 'npm pack'\n\n*.tgz\n\n# Yarn Integrity file\n\n.yarn-integrity\n\n# dotenv environment variable files\n\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n\n.parcel-cache\n\n# Next.js build output\n\n.next\nout\n\n# Nuxt.js build / generate output\n\n.nuxt\ndist\n\n# Gatsby files\n\n# Comment in the public line in if your project uses Gatsby and not Next.js\n\n# https://nextjs.org/blog/next-9-1#public-directory-support\n\n# public\n\n# vuepress build output\n\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n\n.temp\n\n# Docusaurus cache and generated files\n\n.docusaurus\n\n# Serverless directories\n\n.serverless/\n\n# FuseBox cache\n\n.fusebox/\n\n# DynamoDB Local files\n\n.dynamodb/\n\n# TernJS port file\n\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n\n.vscode-test\n\n# yarn v2\n\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n# IntelliJ based IDEs\n.idea\n\n# Finder (MacOS) folder config\n.DS_Store\n\n# Auto-generated from root during build\nLICENSE.md\n"
  },
  {
    "path": "packages/react/CHANGELOG.md",
    "content": "## v4.3.0 (2024-01-21)\n\n## v4.0.1 (2022-07-06)\n\n#### :bug: Bug Fix\n\n- `lib`\n  - [#637](https://github.com/shipshapecode/react-shepherd/pull/637) Add children field for React 18 ([@andersaamodt](https://github.com/andersaamodt))\n\n#### Committers: 2\n\n- Anders ([@andersaamodt](https://github.com/andersaamodt))\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n## v3.3.1 (2020-11-13)\n\n#### :rocket: Enhancement\n\n- [#439](https://github.com/shipshapecode/react-shepherd/pull/439) ✨ Shepmaster expose more types ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- [#391](https://github.com/shipshapecode/react-shepherd/pull/391) Manage secondary property on Step button ([@linsolas](https://github.com/linsolas))\n\n#### :bug: Bug Fix\n\n- [#528](https://github.com/shipshapecode/react-shepherd/pull/528) 🐛 Remove check for current action assignment ([@chuckcarpenter](https://github.com/chuckcarpenter))\n\n#### Committers: 4\n\n- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))\n- Hakeem Almidan ([@Hakeemmidan](https://github.com/Hakeemmidan))\n- Romain Linsolas ([@linsolas](https://github.com/linsolas))\n- [@cyremur](https://github.com/cyremur)\n\n## v2.0.0 (2019-08-29)\n\n#### :bug: Bug Fix\n\n- [#36](https://github.com/shipshapecode/react-shepherd/pull/36) Make custom button actions work, if specified ([@jmfirth](https://github.com/jmfirth))\n- [#38](https://github.com/shipshapecode/react-shepherd/pull/38) Fix adding steps ([@jmfirth](https://github.com/jmfirth))\n\n#### Committers: 1\n\n- Justin Firth ([@jmfirth](https://github.com/jmfirth))\n"
  },
  {
    "path": "packages/react/README.md",
    "content": "# react-shepherd\n\n[![NPM](https://img.shields.io/npm/v/react-shepherd.svg)](https://www.npmjs.com/package/react-shepherd)\n\nThis is a React wrapper for the\n[Shepherd](https://github.com/shipshapecode/shepherd) tour library. It's mainly\na wrapper around the Shepherd library that exposes the tour object and methods\nto the context object that can be passed into props for dynamic interactivity.\n\n## Install\n\nUse this simple NPM command or whatever package manager is your favorite.\n\n```bash\nnpm install --save react-shepherd\n```\n\n## Usage\n\n### Via Provider/Context\n\n```tsx\nimport { Component, useContext } from 'react';\nimport { ShepherdJourneyProvider, useShepherd } from 'react-shepherd';\nimport newSteps from './steps';\n\nconst tourOptions = {\n  defaultStepOptions: {\n    cancelIcon: {\n      enabled: true\n    }\n  },\n  useModalOverlay: true\n};\n\nfunction Button() {\n  const Shepherd = useShepherd();\n  const tour = new Shepherd.Tour({\n    ...tourOptions,\n    steps: newSteps\n  });\n\n  return (\n    <button className=\"button dark\" onClick={tour.start}>\n      Start Tour\n    </button>\n  );\n}\n\nexport default function App() {\n  return (\n    <div>\n      <ShepherdJourneyProvider>\n        <Button />\n      </ShepherdJourneyProvider>\n    </div>\n  );\n}\n```\n\n## Configuration\n\nThe following configuration options for a tour can be set on the `useShepherd`\nhook to control the way that Shepherd is used. This is simply a POJO passed to\nShepherd to use the options noted in the Shepherd Tour\n[options](https://docs.shepherdjs.dev/api/tour/classes/tour/).\n\n## License\n\n`react-shepherd` is licensed under **AGPL-3.0** (for open source and\nnon-commercial use) with a **Commercial License** available for commercial use.\n\n- **Free** for open source and non-commercial projects under AGPL-3.0\n- **Commercial license required** for commercial products and revenue-generating\n  companies\n\n📄 [Read License Details](../../LICENSE.md)  \n💳 [Purchase Commercial License](https://shepherdjs.dev/pricing)\n"
  },
  {
    "path": "packages/react/package.json",
    "content": "{\n  \"name\": \"react-shepherd\",\n  \"version\": \"7.0.4\",\n  \"private\": false,\n  \"license\": \"AGPL-3.0\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/shipshapecode/shepherd.git\"\n  },\n  \"main\": \"./dist/index.umd.cjs\",\n  \"module\": \"./dist/index.js\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\",\n      \"require\": \"./dist/index.umd.cjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"type\": \"module\",\n  \"files\": [\n    \"dist\",\n    \"src\",\n    \"LICENSE.md\"\n  ],\n  \"scripts\": {\n    \"build\": \"vite build\",\n    \"prepack\": \"cp ../../LICENSE.md ./LICENSE.md && pnpm build\",\n    \"test:ci\": \"vitest --run\",\n    \"test:dev\": \"vitest\"\n  },\n  \"dependencies\": {\n    \"shepherd.js\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/react\": \"^16.3.2\",\n    \"@types/react\": \"^19.2.14\",\n    \"@vitejs/plugin-react\": \"^5.1.4\",\n    \"@vitest/ui\": \"^4.0.18\",\n    \"happy-dom\": \"^20.6.1\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.3.1\",\n    \"vite-plugin-dts\": \"^4.5.4\",\n    \"vitest\": \"^4.0.18\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^18.0.0 || ^19.0.0\",\n    \"typescript\": \"^5.0.0\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npmjs.org\",\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/react/src/index.tsx",
    "content": "import { createContext, FC, useContext, type ReactNode } from 'react';\nimport Shepherd from 'shepherd.js';\n\ninterface ShepherdContextType {\n  Shepherd: typeof Shepherd;\n}\n\nconst ShepherdJourneyContext = createContext<ShepherdContextType | undefined>(\n  undefined\n);\nconst ShepherdJourneyContextConsumer = ShepherdJourneyContext.Consumer;\n\nexport const useShepherd = () => {\n  const context = useContext(ShepherdJourneyContext);\n  if (!context) {\n    throw new Error(\n      'useShepherd must be used within a ShepherdJourneyProvider'\n    );\n  }\n\n  const { Shepherd: ShepherdInsance } = context;\n\n  return ShepherdInsance;\n};\n\nexport const ShepherdJourneyProvider = ({\n  children\n}: {\n  children?: ReactNode;\n}) => {\n  return (\n    <ShepherdJourneyContext.Provider value={{ Shepherd }}>\n      {children}\n    </ShepherdJourneyContext.Provider>\n  );\n};\n\n// For backwards compatibility, we're also exporting consumer and context\nexport {\n  ShepherdJourneyContextConsumer as JourneyMethods,\n  ShepherdJourneyContext\n};\n"
  },
  {
    "path": "packages/react/test/index.test.tsx",
    "content": "import React from 'react';\nimport { describe, expect, it } from 'vitest';\nimport { render, fireEvent } from '@testing-library/react';\nimport { ShepherdJourneyProvider, useShepherd } from '../src/index.tsx';\n\nconst steps = [\n  {\n    id: 'welcome',\n    text: [\n      `\n      Shepherd is a JavaScript library for guiding users through your app.\n      It uses <a href=\"https://atomiks.github.io/tippyjs//\">Tippy.js</a>,\n      another open source library, to render dialogs for each tour \"step\".\n    `,\n      `\n      Among many things, Tippy makes sure your steps never end up off screen or cropped by an overflow.\n      Try resizing your browser to see what we mean.\n    `\n    ],\n    classes: 'shepherd shepherd-welcome',\n    buttons: [\n      {\n        type: 'cancel',\n        classes: 'shepherd-button-secondary',\n        text: 'Exit'\n      },\n      {\n        type: 'next',\n        text: 'Next'\n      }\n    ]\n  }\n];\nconst tourOptions = {\n  defaultStepOptions: {\n    cancelIcon: {\n      enabled: true\n    }\n  },\n  useModalOverlay: true\n};\n\ndescribe('<ShepherdTour />', () => {\n  it('exists', () => {\n    expect(ShepherdJourneyProvider).toBeTruthy();\n  });\n\n  it('renders the component, creates the Tour, and it can be started', async () => {\n    const Button = () => {\n      const shepherd = useShepherd();\n      const tour = new shepherd.Tour(tourOptions);\n      tour.addSteps(steps);\n\n      return (\n        <button className=\"button dark\" type=\"button\" onClick={tour.start}>\n          Start Tour\n        </button>\n      );\n    };\n    const TestApp = () => (\n      <ShepherdJourneyProvider>\n        <Button />\n      </ShepherdJourneyProvider>\n    );\n\n    const container = render(<TestApp />);\n    await fireEvent.click(container.getByText(/Start Tour/));\n\n    const cancelBtn = await container.findByText('Exit');\n    const nextBtn = await container.findByText('Next');\n\n    expect(cancelBtn).toBeTruthy();\n    expect(nextBtn).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "packages/react/test/setup.ts",
    "content": "import '@testing-library/jest-dom';\n"
  },
  {
    "path": "packages/react/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"esnext\"],\n    \"target\": \"es2021\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"moduleDetection\": \"force\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"composite\": true,\n    \"strict\": true,\n    \"downlevelIteration\": true,\n    \"skipLibCheck\": true,\n    \"jsx\": \"react-jsx\",\n    \"allowSyntheticDefaultImports\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"allowJs\": true,\n    \"baseUrl\": \".\"\n  },\n  \"exclude\": [\"node_modules\", \"test\", \"vite.config.ts\", \"vitest.config.ts\"],\n  \"include\": [\"**/*.ts\", \"**/*.tsx\"],\n}\n"
  },
  {
    "path": "packages/react/vite.config.ts",
    "content": "import { resolve } from 'path';\nimport { defineConfig } from 'vite';\nimport dts from 'vite-plugin-dts';\n\n// https://vitejs.dev/guide/build.html#library-mode\nexport default defineConfig({\n  build: {\n    lib: {\n      entry: resolve(__dirname, 'src/index.tsx'),\n      name: 'ReactShepherd',\n      fileName: 'index'\n    },\n    rollupOptions: {\n      external: ['react', 'react-dom'],\n      output: {\n        globals: {\n          react: 'React'\n        }\n      }\n    }\n  },\n  plugins: [dts({ rollupTypes: true })]\n});\n"
  },
  {
    "path": "packages/react/vitest.config.ts",
    "content": "/// <reference types=\"vitest\" />\n/// <reference types=\"vite/client\" />\n\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n  test: {\n    setupFiles: './test/setup.ts',\n    globals: true,\n    environment: 'happy-dom'\n  }\n});\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - shepherd.js\n  - landing\n  - packages/*\n  - docs-src\n\nonlyBuiltDependencies:\n  - cypress\n  - esbuild\n  - sharp\n  - svelte-preprocess\n"
  },
  {
    "path": "shepherd.js/.attw.json",
    "content": "{\n  \"ignoreRules\": [\"no-resolution\"]\n}\n"
  },
  {
    "path": "shepherd.js/.eslintignore",
    "content": "/dev/\ndist/\ndummy/\ntmp/\n"
  },
  {
    "path": "shepherd.js/.eslintrc.cjs",
    "content": "module.exports = {\n  root: true,\n  parserOptions: {\n    ecmaVersion: 'latest',\n    sourceType: 'module'\n  },\n  extends: ['eslint:recommended', 'plugin:svelte/recommended'],\n  env: {\n    browser: true,\n    es2020: true,\n  },\n  rules: {\n    'no-console': 'off',\n    'prefer-const': 'off'\n  },\n  overrides: [\n    // svelte files\n    {\n      files: ['**/*.svelte'],\n      processor: 'svelte/svelte',\n      rules: {\n        'svelte/no-at-html-tags': 'off',\n        'svelte/valid-compile': 'off'\n      }\n    },\n    // Typescript files\n    {\n      parser: '@typescript-eslint/parser',\n      files: ['**/*.ts'],\n      plugins: ['@typescript-eslint'],\n      extends: ['plugin:@typescript-eslint/recommended'],\n      rules: {\n        '@typescript-eslint/no-unused-vars': [\n          'error',\n          { argsIgnorePattern: '^_' }\n        ],\n        'prefer-rest-params': 'off'\n      }\n    },\n    // Vitest setup file (uses Node globals)\n    {\n      files: ['test/unit/setupTests.js'],\n      env: {\n        node: true,\n        es2020: true\n      }\n    },\n    // node files\n    {\n      files: [\n        '.eslintrc.js',\n        '.prettierrc.js',\n        'babel.config.js',\n        'rollup.config.mjs',\n        'svelte.config.js'\n      ],\n      parserOptions: {\n        sourceType: 'module',\n        ecmaVersion: 2020\n      },\n      env: {\n        browser: false,\n        node: true\n      }\n    }\n  ]\n};\n"
  },
  {
    "path": "shepherd.js/.gitignore",
    "content": "# Editors\n/.idea/\n/.vscode/\n\n/.log/\n/.nyc_output/\n/coverage/\n/cypress/\n/test/coverage/\n/node_modules/\n/tmp/\n/.DS_Store\n/.sass-cache\n/npm-debug.log*\n/stats.html\n/yarn-error.log\n\n# Build artifacts and cache files\n.eslintcache\nerrors.json\n\n# Auto-generated from root during build\nREADME.md\nLICENSE.md\n"
  },
  {
    "path": "shepherd.js/.prettierignore",
    "content": "/dev/\ndist/\ndummy/\ntmp/\n"
  },
  {
    "path": "shepherd.js/babel.config.cjs",
    "content": "module.exports = function (api) {\n  api.cache(true);\n\n  return {\n    presets: ['@babel/preset-typescript'],\n    plugins: [\n      ['@babel/plugin-transform-typescript', { allowDeclareFields: true }]\n    ],\n    env: {\n      development: {\n        presets: [\n          [\n            '@babel/preset-env',\n            {\n              loose: true\n            }\n          ]\n        ]\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "shepherd.js/dev/assets/favicons/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo src=\"/mstile-150x150.png\"/>\n            <TileColor>#00aba9</TileColor>\n        </tile>\n    </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "shepherd.js/dev/assets/favicons/manifest.json",
    "content": "{\n  \"name\": \"Ship Shape\",\n  \"short_name\": \"Ship Shape\",\n  \"icons\": [\n    {\n      \"src\": \"\\/favicons\\/android-chrome-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image\\/png\"\n    },\n    {\n      \"src\": \"\\/favicons\\/android-chrome-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image\\/png\"\n    }\n  ],\n  \"theme_color\": \"#ffffff\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "shepherd.js/dev/css/fonts.css",
    "content": "@font-face {\n  font-family: 'GT Pressura';\n  src: url('../../landing/public/assets/fonts/GTPressura-Bold.woff2') format('woff2'),\n  url('../../landing/public/assets/fonts/GTPressura-Bold.woff') format('woff');\n  font-weight: bold;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'Founders Grotesk';\n  src: url('../../landing/public/assets/fonts/FoundersGrotesk-Regular.woff2') format('woff2'),\n  url('../../landing/public/assets/fonts/FoundersGrotesk-Regular.woff') format('woff');\n  font-weight: normal;\n  font-style: normal;\n}\n"
  },
  {
    "path": "shepherd.js/dev/css/prism.css",
    "content": "/*\n\nName:       Base16 Ocean Dark\nAuthor:     Chris Kempson (http://chriskempson.com)\n\nPrism template by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/prism/)\nOriginal Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\ncode[class*=\"language-\"],\npre[class*=\"language-\"] {\n  font-family: Consolas, Menlo, Monaco, \"Andale Mono WT\", \"Andale Mono\", \"Lucida Console\", \"Lucida Sans Typewriter\", \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\", \"Liberation Mono\", \"Nimbus Mono L\", \"Courier New\", Courier, monospace;\n  font-size: 14px;\n  line-height: 1.375;\n  direction: ltr;\n  text-align: left;\n  white-space: pre;\n  word-spacing: normal;\n  word-break: normal;\n  -moz-tab-size: 4;\n  -o-tab-size: 4;\n  tab-size: 4;\n  -webkit-hyphens: none;\n  -ms-hyphens: none;\n  hyphens: none;\n  background: #2b303b;\n  color: #c0c5ce;\n}\n\npre[class*=\"language-\"]::-moz-selection, pre[class*=\"language-\"] ::-moz-selection,\ncode[class*=\"language-\"]::-moz-selection, code[class*=\"language-\"] ::-moz-selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\npre[class*=\"language-\"]::selection, pre[class*=\"language-\"] ::selection,\ncode[class*=\"language-\"]::selection, code[class*=\"language-\"] ::selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\n/* Code blocks */\npre[class*=\"language-\"] {\n  padding: 2rem;\n  margin: .5em 0;\n  overflow: auto;\n}\n\n/* Inline code */\n:not(pre) > code[class*=\"language-\"] {\n  padding: .1em;\n  border-radius: .3em;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n  color: #65737e;\n}\n\n.token.punctuation {\n  color: #c0c5ce;\n}\n\n.token.namespace {\n  opacity: .7;\n}\n\n.token.operator,\n.token.boolean,\n.token.number {\n  color: #d08770;\n}\n\n.token.property {\n  color: #ebcb8b;\n}\n\n.token.tag {\n  color: #8fa1b3;\n}\n\n.token.string {\n  color: #96b5b4;\n}\n\n.token.selector {\n  color: #b48ead;\n}\n\n.token.attr-name {\n  color: #d08770;\n}\n\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n  color: #96b5b4;\n}\n\n.token.attr-value,\n.token.keyword,\n.token.control,\n.token.directive,\n.token.unit {\n  color: #a3be8c;\n}\n\n.token.statement,\n.token.regex,\n.token.atrule {\n  color: #96b5b4;\n}\n\n.token.placeholder,\n.token.variable {\n  color: #8fa1b3;\n}\n\n.token.deleted {\n  text-decoration: line-through;\n}\n\n.token.inserted {\n  border-bottom: 1px dotted #eff1f5;\n  text-decoration: none;\n}\n\n.token.italic {\n  font-style: italic;\n}\n\n.token.important,\n.token.bold {\n  font-weight: bold;\n}\n\n.token.important {\n  color: #bf616a;\n}\n\n.token.entity {\n  cursor: help;\n}\n\npre > code.highlight {\n  outline: 0.4em solid #bf616a;\n  outline-offset: .4em;\n}\n\n.line-numbers .line-numbers-rows {\n  border-right-color: #343d46 !important;\n}\n\n.line-numbers-rows > span:before {\n  color: #4f5b66 !important;\n}\n\n.line-highlight {\n  background: rgba(239, 241, 245, 0.2) !important;\n  background: -webkit-linear-gradient(left, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n  background: linear-gradient(to right, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n}\n"
  },
  {
    "path": "shepherd.js/dev/css/welcome.css",
    "content": "html, body {\n  font-family: \"Pier Sans\", \"proxima-nova\", \"Helvetica Neue\", sans-serif;\n}\n\nbody {\n  background-color: rgba(236, 243, 246, 50);\n  color: #5F6976;\n  height: 100%;\n  margin: 0;\n}\n\n.button {\n  border: 2px solid #5F6976;\n  color: #5F6976;\n  cursor: pointer;\n  display: inline-block;\n  font-size: 0.8em;\n  font-weight: 500;\n  letter-spacing: 3px;\n  line-height: 1.3em;\n  padding: 1em 1.25em;\n  text-decoration: none;\n  text-transform: uppercase;\n  width: 140px;\n}\n\n.button:hover {\n  background-color: #5F6976;\n  color: #ffffff;\n}\n\n@media (max-width: 568px) {\n  .button {\n    display: block;\n    margin: 1em auto 0;\n  }\n}\n\n.hero-outer {\n  -webkit-box-sizing: border-box;\n  box-sizing: border-box;\n  display: table;\n  height: 100%;\n  padding: 20px 0;\n  width: 100%;\n}\n\n.hero-inner {\n  max-width: 700px;\n  width: 90%;\n}\n\n@media (max-width: 600px) {\n  .hero-inner {\n    width: 340px;\n  }\n}\n\n@media (max-width: 360px) {\n  .hero-inner {\n    width: 200px;\n  }\n}\n\n.hero-outer .hero-inner {\n  margin: 0 auto 1em;\n  text-align: center;\n}\n\n.demo-heading {\n  color: #00213B;\n}\n\nh1.demo-heading {\n  font-size: 3rem;\n  font-weight: bold;\n  padding-top: 10px;\n}\n\nh3.demo-heading {\n  font-size: 1.3em;\n  padding-top: 13px;\n}\n\nh2.demo-heading,\nh3.demo-heading {\n  font-weight: normal;\n}\n\n.hero-outer .hero-followup {\n  padding-top: 20px;\n}\n\npre {\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  line-height: 1.4em;\n}\n\n.shepherd-button {\n  background: #00213b;\n  font-size: 0.7rem;\n  text-transform: uppercase;\n}\n\n.shepherd-button:hover {\n  background: #ececec;\n  color: #00213b;\n}\n\n.shepherd-text a,\n.shepherd-text a:visited,\n.shepherd-text a:active {\n  border-bottom: 1px dotted;\n  border-bottom-color: rgba(0, 0, 0, 0.75);\n  color: rgba(0, 0, 0, 0.75);\n  text-decoration: none;\n}\n\n.shepherd-text a:hover,\n.shepherd-text a:visited:hover,\n.shepherd-text a:active:hover {\n  border-bottom-style: solid;\n}"
  },
  {
    "path": "shepherd.js/dev/index.html",
    "content": "<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <title>Shepherd — Guide your users through a tour of your app.</title>\n    <meta\n      name=\"description\"\n      content=\"Guide your users through a tour of your app.\"\n    />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width, initial-scale=1, user-scalable=no\"\n    />\n\n    <!--favicons-->\n\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"assets/favicons/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"32x32\"\n      href=\"assets/favicons/favicon-32x32.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"16x16\"\n      href=\"assets/favicons/favicon-16x16.png\"\n    />\n    <link rel=\"manifest\" href=\"assets/favicons/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"assets/favicons/safari-pinned-tab.svg\"\n      color=\"#426170\"\n    />\n    <link rel=\"shortcut icon\" href=\"assets/favicons/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"assets/favicons/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Welcome docs styles -->\n    <link rel=\"stylesheet\" href=\"/css/shepherd.css\" />\n    <link rel=\"stylesheet\" href=\"./css/fonts.css\" />\n    <link rel=\"stylesheet\" href=\"./css/prism.css\" />\n    <link rel=\"stylesheet\" href=\"./css/welcome.css\" />\n  </head>\n\n  <body>\n    <div class=\"hero-outer\" data-test-hero-outer>\n      <div class=\"hero-inner\">\n        <div class=\"hero-welcome\" data-test-hero-welcome>\n          <h1>Shepherd</h1>\n\n          <h2>Guide your users through a tour of your app.</h2>\n        </div>\n\n        <div class=\"hero-including\" data-test-hero-including>\n          <h3>Including</h3>\n\n          <script\n            type=\"text/plain\"\n            class=\"language-markup\"\n            id=\"hero-including-code\"\n          >\n            <script type=\"module\" src=\"shepherd.min.js\">&lt;/script>\n          </script>\n        </div>\n\n        <div class=\"hero-example\">\n          <h3>Example</h3>\n\n          <pre id=\"hero-example-code\">\n          <code class=\"language-javascript\">\n            const tour = new Shepherd.Tour({\n              defaultStepOptions: {\n                classes: 'shadow-md bg-purple-dark',\n                scrollTo: true\n              }\n            });\n\n            tour.addStep({\n              title: 'Example Shepherd',\n              text: 'Creating a Shepherd is easy too! Just create ...',\n              attachTo: {\n                element: '.hero-example',\n                on: 'bottom'\n              },\n              advanceOn: {\n                selector: '.docs-link',\n                event: 'click'\n              },\n              id: 'example'\n            });\n\n            tour.start();\n          </code>\n        </pre>\n        </div>\n\n        <div class=\"hero-followup\">\n          <p>\n            <a\n              class=\"button star\"\n              href=\"https://github.com/shipshapecode/shepherd\"\n              >★ on Github</a\n            >\n            &nbsp;&nbsp;\n            <a class=\"button\" href=\"https://shepherdjs.dev/docs/\">View Docs</a>\n          </p>\n        </div>\n        <div>\n          <img src=\"sheep.svg\" />\n        </div>\n      </div>\n    </div>\n\n    <!-- Shepherd -->\n    <script type=\"module\">\n      import Shepherd from '/js/shepherd.mjs';\n      const tour = new Shepherd.Tour({\n        defaultStepOptions: {\n          cancelIcon: { enabled: true }\n        },\n        useModalOverlay: true,\n        steps: [\n          {\n            text: `\n         <p>\n           Shepherd is a JavaScript library for guiding users through your app.\n           It uses <a href=\"https://floating-ui.com/\" data-test-popper-link>Floating UI</a>,\n           another open source library, to render dialogs for each tour \"step\".\n         </p>\n        \n         <p>\n           Among many things, Floating UI makes sure your steps never end up off screen or cropped by an overflow.\n           (Try resizing your browser to see what we mean.)\n         </p>`,\n            attachTo: {\n              element: '.hero-welcome',\n              on: 'bottom'\n            },\n            classes:\n              'shepherd-step-element shepherd-transparent-text first-step',\n            buttons: [\n              {\n                action() {\n                  return this.cancel();\n                },\n                classes: 'shepherd-button-secondary',\n                text: 'Exit'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                classes: 'shepherd-button-example-primary',\n                text: 'Next'\n              }\n            ],\n            id: 'welcome'\n          },\n          {\n            title: 'Including',\n            text: 'Including Shepherd is easy! Just include shepherd.js. The styles are bundled with the JS.',\n            attachTo: {\n              element: '.hero-including',\n              on: 'bottom'\n            },\n            buttons: [\n              {\n                action() {\n                  return this.back();\n                },\n                classes: 'shepherd-button-secondary',\n                text: 'Back'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                classes: 'shepherd-button-example-primary',\n                text: 'Next'\n              }\n            ],\n            id: 'including',\n            classes: 'shepherd-step-element second-step'\n          },\n          {\n            title: 'Example Shepherd',\n            text: 'Creating a Shepherd is easy too! Just create Shepherd and add as many steps as you want. Check out the <a href=\"https://shepherdjs.dev/docs/\">documentation</a> to learn more.',\n            attachTo: {\n              element: '.hero-example',\n              on: 'bottom'\n            },\n            buttons: [\n              {\n                action() {\n                  return this.back();\n                },\n                classes: 'shepherd-button-secondary',\n                text: 'Back'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                classes: 'shepherd-button-example-primary',\n                text: 'Next'\n              }\n            ],\n            id: 'example',\n            classes: 'shepherd-step-element third-step'\n          },\n          {\n            title: 'Learn more',\n            text: 'Star Shepherd on Github so you remember it for your next project',\n            attachTo: {\n              element: '.hero-followup',\n              on: 'left'\n            },\n            buttons: [\n              {\n                action() {\n                  return this.back();\n                },\n                classes: 'shepherd-button-secondary',\n                text: 'Back'\n              },\n              {\n                action() {\n                  return this.next();\n                },\n                classes: 'shepherd-button-example-primary',\n                text: 'Done'\n              }\n            ],\n            id: 'followup',\n            classes: 'shepherd-step-element fourth-step'\n          }\n        ]\n      });\n\n      tour.start();\n    </script>\n\n    <!-- Welcome page -->\n    <script src=\"js/prism.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "shepherd.js/dev/js/prism.js",
    "content": "/* PrismJS 1.15.0\nhttps://prismjs.com/download.html#themes=prism&languages=markup+clike+javascript&plugins=unescaped-markup+normalize-whitespace */\nvar _self=\"undefined\"!=typeof window?window:\"undefined\"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\\blang(?:uage)?-([\\w-]+)\\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):\"Array\"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/\\u00a0/g,\" \")},type:function(e){return Object.prototype.toString.call(e).match(/\\[object (\\w+)\\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,\"__id\",{value:++t}),e.__id},clone:function(e,t){var r=n.util.type(e);switch(t=t||{},r){case\"Object\":if(t[n.util.objId(e)])return t[n.util.objId(e)];var a={};t[n.util.objId(e)]=a;for(var l in e)e.hasOwnProperty(l)&&(a[l]=n.util.clone(e[l],t));return a;case\"Array\":if(t[n.util.objId(e)])return t[n.util.objId(e)];var a=[];return t[n.util.objId(e)]=a,e.forEach(function(e,r){a[r]=n.util.clone(e,t)}),a}return e}},languages:{extend:function(e,t){var r=n.util.clone(n.languages[e]);for(var a in t)r[a]=t[a];return r},insertBefore:function(e,t,r,a){a=a||n.languages;var l=a[e];if(2==arguments.length){r=arguments[1];for(var i in r)r.hasOwnProperty(i)&&(l[i]=r[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in r)r.hasOwnProperty(i)&&(o[i]=r[i]);o[s]=l[s]}return n.languages.DFS(n.languages,function(t,n){n===a[e]&&t!=e&&(this[t]=o)}),a[e]=o},DFS:function(e,t,r,a){a=a||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],r||l),\"Object\"!==n.util.type(e[l])||a[n.util.objId(e[l])]?\"Array\"!==n.util.type(e[l])||a[n.util.objId(e[l])]||(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,a)):(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,a)))}},plugins:{},highlightAll:function(e,t){n.highlightAllUnder(document,e,t)},highlightAllUnder:function(e,t,r){var a={callback:r,selector:'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'};n.hooks.run(\"before-highlightall\",a);for(var l,i=a.elements||e.querySelectorAll(a.selector),o=0;l=i[o++];)n.highlightElement(l,t===!0,a.callback)},highlightElement:function(t,r,a){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,\"\"])[1].toLowerCase(),i=n.languages[l]),t.className=t.className.replace(e,\"\").replace(/\\s+/g,\" \")+\" language-\"+l,t.parentNode&&(o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,\"\").replace(/\\s+/g,\" \")+\" language-\"+l));var s=t.textContent,u={element:t,language:l,grammar:i,code:s};if(n.hooks.run(\"before-sanity-check\",u),!u.code||!u.grammar)return u.code&&(n.hooks.run(\"before-highlight\",u),u.element.textContent=u.code,n.hooks.run(\"after-highlight\",u)),n.hooks.run(\"complete\",u),void 0;if(n.hooks.run(\"before-highlight\",u),r&&_self.Worker){var g=new Worker(n.filename);g.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run(\"before-insert\",u),u.element.innerHTML=u.highlightedCode,a&&a.call(u.element),n.hooks.run(\"after-highlight\",u),n.hooks.run(\"complete\",u)},g.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run(\"before-insert\",u),u.element.innerHTML=u.highlightedCode,a&&a.call(t),n.hooks.run(\"after-highlight\",u),n.hooks.run(\"complete\",u)},highlight:function(e,t,a){var l={code:e,grammar:t,language:a};return n.hooks.run(\"before-tokenize\",l),l.tokens=n.tokenize(l.code,l.grammar),n.hooks.run(\"after-tokenize\",l),r.stringify(n.util.encode(l.tokens),l.language)},matchGrammar:function(e,t,r,a,l,i,o){var s=n.Token;for(var u in r)if(r.hasOwnProperty(u)&&r[u]){if(u==o)return;var g=r[u];g=\"Array\"===n.util.type(g)?g:[g];for(var c=0;c<g.length;++c){var h=g[c],f=h.inside,d=!!h.lookbehind,m=!!h.greedy,p=0,y=h.alias;if(m&&!h.pattern.global){var v=h.pattern.toString().match(/[imuy]*$/)[0];h.pattern=RegExp(h.pattern.source,v+\"g\")}h=h.pattern||h;for(var b=a,k=l;b<t.length;k+=t[b].length,++b){var w=t[b];if(t.length>e.length)return;if(!(w instanceof s)){if(m&&b!=t.length-1){h.lastIndex=k;var _=h.exec(e);if(!_)break;for(var j=_.index+(d?_[1].length:0),P=_.index+_[0].length,A=b,x=k,O=t.length;O>A&&(P>x||!t[A].type&&!t[A-1].greedy);++A)x+=t[A].length,j>=x&&(++b,k=x);if(t[b]instanceof s)continue;I=A-b,w=e.slice(k,x),_.index-=k}else{h.lastIndex=0;var _=h.exec(w),I=1}if(_){d&&(p=_[1]?_[1].length:0);var j=_.index+p,_=_[0].slice(p),P=j+_.length,N=w.slice(0,j),S=w.slice(P),C=[b,I];N&&(++b,k+=N.length,C.push(N));var E=new s(u,f?n.tokenize(_,f):_,y,_,m);if(C.push(E),S&&C.push(S),Array.prototype.splice.apply(t,C),1!=I&&n.matchGrammar(e,t,r,b,k,!0,u),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||\"\").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if(\"string\"==typeof e)return e;if(\"Array\"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join(\"\");var l={type:e.type,content:r.stringify(e.content,t,a),tag:\"span\",classes:[\"token\",e.type],attributes:{},language:t,parent:a};if(e.alias){var i=\"Array\"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run(\"wrap\",l);var o=Object.keys(l.attributes).map(function(e){return e+'=\"'+(l.attributes[e]||\"\").replace(/\"/g,\"&quot;\")+'\"'}).join(\" \");return\"<\"+l.tag+' class=\"'+l.classes.join(\" \")+'\"'+(o?\" \"+o:\"\")+\">\"+l.content+\"</\"+l.tag+\">\"},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener(\"message\",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName(\"script\")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute(\"data-manual\")||(\"loading\"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener(\"DOMContentLoaded\",n.highlightAll))),_self.Prism}();\"undefined\"!=typeof module&&module.exports&&(module.exports=Prism),\"undefined\"!=typeof global&&(global.Prism=Prism);\nPrism.languages.markup={comment:/<!--[\\s\\S]*?-->/,prolog:/<\\?[\\s\\S]+?\\?>/,doctype:/<!DOCTYPE[\\s\\S]+?>/i,cdata:/<!\\[CDATA\\[[\\s\\S]*?]]>/i,tag:{pattern:/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s+[^\\s>\\/=]+(?:=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+))?)*\\s*\\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\\/?[^\\s>\\/]+/i,inside:{punctuation:/^<\\/?/,namespace:/^[^\\s>\\/:]+:/}},\"attr-value\":{pattern:/=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\\\])[\"']/,lookbehind:!0}]}},punctuation:/\\/?>/,\"attr-name\":{pattern:/[^\\s>\\/]+/,inside:{namespace:/^[^\\s>\\/:]+:/}}}},entity:/&#?[\\da-z]{1,8};/i},Prism.languages.markup.tag.inside[\"attr-value\"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add(\"wrap\",function(a){\"entity\"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,\"&\"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;\nPrism.languages.clike={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":{pattern:/((?:\\b(?:class|interface|extends|implements|trait|instanceof|new)\\s+)|(?:catch\\s+\\())[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\\b/,\"boolean\":/\\b(?:true|false)\\b/,\"function\":/[a-z0-9_]+(?=\\()/i,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/--?|\\+\\+?|!=?=?|<=?|>=?|==?=?|&&?|\\|\\|?|\\?|\\*|\\/|~|\\^|%/,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.javascript=Prism.languages.extend(\"clike\",{keyword:/\\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\\b/,number:/\\b(?:0[xX][\\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:[Ee][+-]?\\d+)?/,\"function\":/[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*\\()/i,operator:/-[-=]?|\\+[+=]?|!=?=?|<<?=?|>>?>?=?|=(?:==?|>)?|&[&=]?|\\|[|=]?|\\*\\*?=?|\\/=?|~|\\^=?|%=?|\\?|\\.{3}/}),Prism.languages.insertBefore(\"javascript\",\"keyword\",{regex:{pattern:/((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s])\\s*)\\/(\\[[^\\]\\r\\n]+]|\\\\.|[^\\/\\\\\\[\\r\\n])+\\/[gimyu]{0,5}(?=\\s*($|[\\r\\n,.;})\\]]))/,lookbehind:!0,greedy:!0},\"function-variable\":{pattern:/[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*=\\s*(?:function\\b|(?:\\([^()]*\\)|[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*)\\s*=>))/i,alias:\"function\"},constant:/\\b[A-Z][A-Z\\d_]*\\b/}),Prism.languages.insertBefore(\"javascript\",\"string\",{\"template-string\":{pattern:/`(?:\\\\[\\s\\S]|\\${[^}]+}|[^\\\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\\${[^}]+}/,inside:{\"interpolation-punctuation\":{pattern:/^\\${|}$/,alias:\"punctuation\"},rest:null}},string:/[\\s\\S]+/}}}),Prism.languages.javascript[\"template-string\"].inside.interpolation.inside.rest=Prism.languages.javascript,Prism.languages.markup&&Prism.languages.insertBefore(\"markup\",\"tag\",{script:{pattern:/(<script[\\s\\S]*?>)[\\s\\S]*?(?=<\\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:\"language-javascript\",greedy:!0}}),Prism.languages.js=Prism.languages.javascript;\n!function(){\"undefined\"!=typeof self&&self.Prism&&self.document&&Prism.languages.markup&&(Prism.plugins.UnescapedMarkup=!0,Prism.hooks.add(\"before-highlightall\",function(e){e.selector+=\", [class*='lang-'] script[type='text/plain'], [class*='language-'] script[type='text/plain'], script[type='text/plain'][class*='lang-'], script[type='text/plain'][class*='language-']\"}),Prism.hooks.add(\"before-sanity-check\",function(e){if((e.element.matches||e.element.msMatchesSelector).call(e.element,\"script[type='text/plain']\")){var t=document.createElement(\"code\"),n=document.createElement(\"pre\");return n.className=t.className=e.element.className,e.element.dataset&&Object.keys(e.element.dataset).forEach(function(t){Object.prototype.hasOwnProperty.call(e.element.dataset,t)&&(n.dataset[t]=e.element.dataset[t])}),e.code=e.code.replace(/&lt;\\/script(>|&gt;)/gi,\"</script>\"),t.textContent=e.code,n.appendChild(t),e.element.parentNode.replaceChild(n,e.element),e.element=t,void 0}var n=e.element.parentNode;!e.code&&n&&\"pre\"==n.nodeName.toLowerCase()&&e.element.childNodes.length&&\"#comment\"==e.element.childNodes[0].nodeName&&(e.element.textContent=e.code=e.element.childNodes[0].textContent)}))}();\n!function(){function e(e){this.defaults=r({},e)}function n(e){return e.replace(/-(\\w)/g,function(e,n){return n.toUpperCase()})}function t(e){for(var n=0,t=0;t<e.length;++t)e.charCodeAt(t)==\"\t\".charCodeAt(0)&&(n+=3);return e.length+n}var r=Object.assign||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);return e};e.prototype={setDefaults:function(e){this.defaults=r(this.defaults,e)},normalize:function(e,t){t=r(this.defaults,t);for(var i in t){var o=n(i);\"normalize\"!==i&&\"setDefaults\"!==o&&t[i]&&this[o]&&(e=this[o].call(this,e,t[i]))}return e},leftTrim:function(e){return e.replace(/^\\s+/,\"\")},rightTrim:function(e){return e.replace(/\\s+$/,\"\")},tabsToSpaces:function(e,n){return n=0|n||4,e.replace(/\\t/g,new Array(++n).join(\" \"))},spacesToTabs:function(e,n){return n=0|n||4,e.replace(new RegExp(\" {\"+n+\"}\",\"g\"),\"\t\")},removeTrailing:function(e){return e.replace(/\\s*?$/gm,\"\")},removeInitialLineFeed:function(e){return e.replace(/^(?:\\r?\\n|\\r)/,\"\")},removeIndent:function(e){var n=e.match(/^[^\\S\\n\\r]*(?=\\S)/gm);return n&&n[0].length?(n.sort(function(e,n){return e.length-n.length}),n[0].length?e.replace(new RegExp(\"^\"+n[0],\"gm\"),\"\"):e):e},indent:function(e,n){return e.replace(/^[^\\S\\n\\r]*(?=\\S)/gm,new Array(++n).join(\"\t\")+\"$&\")},breakLines:function(e,n){n=n===!0?80:0|n||80;for(var r=e.split(\"\\n\"),i=0;i<r.length;++i)if(!(t(r[i])<=n)){for(var o=r[i].split(/(\\s+)/g),a=0,s=0;s<o.length;++s){var l=t(o[s]);a+=l,a>n&&(o[s]=\"\\n\"+o[s],a=l)}r[i]=o.join(\"\")}return r.join(\"\\n\")}},\"undefined\"!=typeof module&&module.exports&&(module.exports=e),\"undefined\"!=typeof Prism&&(Prism.plugins.NormalizeWhitespace=new e({\"remove-trailing\":!0,\"remove-indent\":!0,\"left-trim\":!0,\"right-trim\":!0}),Prism.hooks.add(\"before-sanity-check\",function(e){var n=Prism.plugins.NormalizeWhitespace;if(!e.settings||e.settings[\"whitespace-normalization\"]!==!1){if((!e.element||!e.element.parentNode)&&e.code)return e.code=n.normalize(e.code,e.settings),void 0;var t=e.element.parentNode,r=/\\bno-whitespace-normalization\\b/;if(e.code&&t&&\"pre\"===t.nodeName.toLowerCase()&&!r.test(t.className)&&!r.test(e.element.className)){for(var i=t.childNodes,o=\"\",a=\"\",s=!1,l=0;l<i.length;++l){var c=i[l];c==e.element?s=!0:\"#text\"===c.nodeName&&(s?a+=c.nodeValue:o+=c.nodeValue,t.removeChild(c),--l)}if(e.element.children.length&&Prism.plugins.KeepMarkup){var u=o+e.element.innerHTML+a;e.element.innerHTML=n.normalize(u,e.settings),e.code=e.element.textContent}else e.code=o+e.code+a,e.code=n.normalize(e.code,e.settings)}}}))}();\n"
  },
  {
    "path": "shepherd.js/dummy/assets/favicons/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo src=\"/mstile-150x150.png\"/>\n            <TileColor>#00aba9</TileColor>\n        </tile>\n    </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "shepherd.js/dummy/assets/favicons/manifest.json",
    "content": "{\n  \"name\": \"Ship Shape\",\n  \"short_name\": \"Ship Shape\",\n  \"icons\": [\n    {\n      \"src\": \"\\/favicons\\/android-chrome-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image\\/png\"\n    },\n    {\n      \"src\": \"\\/favicons\\/android-chrome-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image\\/png\"\n    }\n  ],\n  \"theme_color\": \"#ffffff\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "shepherd.js/dummy/css/fonts.css",
    "content": "@font-face {\n  font-family: 'GT Pressura';\n  src: url('../../landing/public/assets/fonts/GTPressura-Bold.woff2') format('woff2'),\n  url('../../landing/public/assets/fonts/GTPressura-Bold.woff') format('woff');\n  font-weight: bold;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'Founders Grotesk';\n  src: url('../../landing/public/assets/fonts/FoundersGrotesk-Regular.woff2') format('woff2'),\n  url('../../landing/public/assets/fonts/FoundersGrotesk-Regular.woff') format('woff');\n  font-weight: normal;\n  font-style: normal;\n}\n"
  },
  {
    "path": "shepherd.js/dummy/css/prism.css",
    "content": "/*\n\nName:       Base16 Ocean Dark\nAuthor:     Chris Kempson (http://chriskempson.com)\n\nPrism template by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/prism/)\nOriginal Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\ncode[class*=\"language-\"],\npre[class*=\"language-\"] {\n  font-family: Consolas, Menlo, Monaco, \"Andale Mono WT\", \"Andale Mono\", \"Lucida Console\", \"Lucida Sans Typewriter\", \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\", \"Liberation Mono\", \"Nimbus Mono L\", \"Courier New\", Courier, monospace;\n  font-size: 14px;\n  line-height: 1.375;\n  direction: ltr;\n  text-align: left;\n  white-space: pre;\n  word-spacing: normal;\n  word-break: normal;\n  -moz-tab-size: 4;\n  -o-tab-size: 4;\n  tab-size: 4;\n  -webkit-hyphens: none;\n  -ms-hyphens: none;\n  hyphens: none;\n  background: #2b303b;\n  color: #c0c5ce;\n}\n\npre[class*=\"language-\"]::-moz-selection, pre[class*=\"language-\"] ::-moz-selection,\ncode[class*=\"language-\"]::-moz-selection, code[class*=\"language-\"] ::-moz-selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\npre[class*=\"language-\"]::selection, pre[class*=\"language-\"] ::selection,\ncode[class*=\"language-\"]::selection, code[class*=\"language-\"] ::selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\n/* Code blocks */\npre[class*=\"language-\"] {\n  padding: 2rem;\n  margin: .5em 0;\n  overflow: auto;\n}\n\n/* Inline code */\n:not(pre) > code[class*=\"language-\"] {\n  padding: .1em;\n  border-radius: .3em;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n  color: #65737e;\n}\n\n.token.punctuation {\n  color: #c0c5ce;\n}\n\n.token.namespace {\n  opacity: .7;\n}\n\n.token.operator,\n.token.boolean,\n.token.number {\n  color: #d08770;\n}\n\n.token.property {\n  color: #ebcb8b;\n}\n\n.token.tag {\n  color: #8fa1b3;\n}\n\n.token.string {\n  color: #96b5b4;\n}\n\n.token.selector {\n  color: #b48ead;\n}\n\n.token.attr-name {\n  color: #d08770;\n}\n\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n  color: #96b5b4;\n}\n\n.token.attr-value,\n.token.keyword,\n.token.control,\n.token.directive,\n.token.unit {\n  color: #a3be8c;\n}\n\n.token.statement,\n.token.regex,\n.token.atrule {\n  color: #96b5b4;\n}\n\n.token.placeholder,\n.token.variable {\n  color: #8fa1b3;\n}\n\n.token.deleted {\n  text-decoration: line-through;\n}\n\n.token.inserted {\n  border-bottom: 1px dotted #eff1f5;\n  text-decoration: none;\n}\n\n.token.italic {\n  font-style: italic;\n}\n\n.token.important,\n.token.bold {\n  font-weight: bold;\n}\n\n.token.important {\n  color: #bf616a;\n}\n\n.token.entity {\n  cursor: help;\n}\n\npre > code.highlight {\n  outline: 0.4em solid #bf616a;\n  outline-offset: .4em;\n}\n\n.line-numbers .line-numbers-rows {\n  border-right-color: #343d46 !important;\n}\n\n.line-numbers-rows > span:before {\n  color: #4f5b66 !important;\n}\n\n.line-highlight {\n  background: rgba(239, 241, 245, 0.2) !important;\n  background: -webkit-linear-gradient(left, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n  background: linear-gradient(to right, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n}\n"
  },
  {
    "path": "shepherd.js/dummy/css/welcome.css",
    "content": "html, body {\n  font-family: \"Pier Sans\", \"proxima-nova\", \"Helvetica Neue\", sans-serif;\n}\n\nbody {\n  background-color: rgba(236, 243, 246, 50);\n  color: #5F6976;\n  height: 100%;\n  margin: 0;\n}\n\n.button {\n  border: 2px solid #5F6976;\n  color: #5F6976;\n  cursor: pointer;\n  display: inline-block;\n  font-size: 0.8em;\n  font-weight: 500;\n  letter-spacing: 3px;\n  line-height: 1.3em;\n  padding: 1em 1.25em;\n  text-decoration: none;\n  text-transform: uppercase;\n  width: 140px;\n}\n\n.button:hover {\n  background-color: #5F6976;\n  color: #ffffff;\n}\n\n@media (max-width: 568px) {\n  .button {\n    display: block;\n    margin: 1em auto 0;\n  }\n}\n\n.hero-outer {\n  -webkit-box-sizing: border-box;\n  box-sizing: border-box;\n  display: table;\n  height: 100%;\n  padding: 20px 0;\n  width: 100%;\n}\n\n.hero-inner {\n  max-width: 700px;\n  width: 90%;\n}\n\n@media (max-width: 600px) {\n  .hero-inner {\n    width: 340px;\n  }\n}\n\n@media (max-width: 360px) {\n  .hero-inner {\n    width: 200px;\n  }\n}\n\n.hero-outer .hero-inner {\n  margin: 0 auto 1em;\n  text-align: center;\n}\n\n.demo-heading {\n  color: #00213B;\n}\n\nh1.demo-heading {\n  font-size: 3rem;\n  font-weight: bold;\n  padding-top: 10px;\n}\n\nh3.demo-heading {\n  font-size: 1.3em;\n  padding-top: 13px;\n}\n\nh2.demo-heading,\nh3.demo-heading {\n  font-weight: normal;\n}\n\n.hero-outer .hero-followup {\n  padding-top: 20px;\n}\n\npre {\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  line-height: 1.4em;\n}\n\n.shepherd-button {\n  background: #00213b;\n  font-size: 0.7rem;\n  text-transform: uppercase;\n}\n\n.shepherd-button:hover {\n  background: #ececec;\n  color: #00213b;\n}\n\n.shepherd-text a,\n.shepherd-text a:visited,\n.shepherd-text a:active {\n  border-bottom: 1px dotted;\n  border-bottom-color: rgba(0, 0, 0, 0.75);\n  color: rgba(0, 0, 0, 0.75);\n  text-decoration: none;\n}\n\n.shepherd-text a:hover,\n.shepherd-text a:visited:hover,\n.shepherd-text a:active:hover {\n  border-bottom-style: solid;\n}"
  },
  {
    "path": "shepherd.js/dummy/index.html",
    "content": "<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <title>Shepherd — Guide your users through a tour of your app.</title>\n    <meta\n      name=\"description\"\n      content=\"Guide your users through a tour of your app.\"\n    />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width, initial-scale=1, user-scalable=no\"\n    />\n\n    <!--favicons-->\n\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"assets/favicons/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"32x32\"\n      href=\"assets/favicons/favicon-32x32.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"16x16\"\n      href=\"assets/favicons/favicon-16x16.png\"\n    />\n    <link rel=\"manifest\" href=\"assets/favicons/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"assets/favicons/safari-pinned-tab.svg\"\n      color=\"#426170\"\n    />\n    <link rel=\"shortcut icon\" href=\"assets/favicons/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"assets/favicons/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Welcome docs styles -->\n    <link rel=\"stylesheet\" href=\"../dist/css/shepherd.css\" />\n    <link rel=\"stylesheet\" href=\"./css/fonts.css\" />\n    <link rel=\"stylesheet\" href=\"./css/prism.css\" />\n    <link rel=\"stylesheet\" href=\"./css/welcome.css\" />\n  </head>\n\n  <body>\n    <div class=\"hero-outer\" data-test-hero-outer>\n      <div class=\"hero-inner\">\n        <div class=\"hero-welcome\" data-test-hero-welcome>\n          <h1>Shepherd</h1>\n\n          <h2>Guide your users through a tour of your app.</h2>\n        </div>\n\n        <div class=\"hero-including\" data-test-hero-including>\n          <h3>Including</h3>\n\n          <script\n            type=\"text/plain\"\n            class=\"language-markup\"\n            id=\"hero-including-code\"\n          >\n            <script type=\"module\" src=\"shepherd.min.js\">&lt;/script>\n          </script>\n        </div>\n\n        <div class=\"hero-example\">\n          <h3>Example</h3>\n\n          <pre id=\"hero-example-code\">\n          <code class=\"language-javascript\">\n            const tour = new Shepherd.Tour({\n              defaultStepOptions: {\n                classes: 'shadow-md bg-purple-dark',\n                scrollTo: true\n              }\n            });\n\n            tour.addStep({\n              title: 'Example Shepherd',\n              text: 'Creating a Shepherd is easy too! Just create ...',\n              attachTo: {\n                element: '.hero-example',\n                on: 'bottom'\n              },\n              advanceOn: {\n                selector: '.docs-link',\n                event: 'click'\n              },\n              id: 'example'\n            });\n\n            tour.start();\n          </code>\n        </pre>\n        </div>\n\n        <div class=\"hero-followup\">\n          <p>\n            <a\n              class=\"button star\"\n              href=\"https://github.com/shipshapecode/shepherd\"\n              >★ on Github</a\n            >\n            &nbsp;&nbsp;\n            <a class=\"button\" href=\"https://shepherdjs.dev/docs/\">View Docs</a>\n          </p>\n        </div>\n        <div>\n          <img src=\"sheep.svg\" />\n        </div>\n      </div>\n    </div>\n\n    <!-- Shepherd -->\n    <script type=\"module\">\n      import Shepherd from '../dist/js/shepherd.mjs';\n\n      window.Shepherd = Shepherd;\n\n      const shepherd = new Shepherd.Tour({\n        defaultStepOptions: {\n          cancelIcon: {\n            enabled: true\n          }\n        },\n        useModalOverlay: true\n      });\n\n      const steps = [\n        {\n          text: `\n         <p>\n           Shepherd is a JavaScript library for guiding users through your app.\n           It uses <a href=\"https://floating-ui.com/\" data-test-popper-link>Floating UI</a>,\n           another open source library, to render dialogs for each tour \"step\".\n         </p>\n        \n         <p>\n           Among many things, Floating UI makes sure your steps never end up off screen or cropped by an overflow.\n           (Try resizing your browser to see what we mean.)\n         </p>`,\n          attachTo: {\n            element: '.hero-welcome',\n            on: 'bottom'\n          },\n          classes: 'shepherd-step-element shepherd-transparent-text first-step',\n          buttons: [\n            {\n              action: shepherd.cancel,\n              classes: 'shepherd-button-secondary',\n              text: 'Exit'\n            },\n            {\n              action: shepherd.next,\n              classes: 'shepherd-button-example-primary',\n              text: 'Next'\n            }\n          ],\n          id: 'welcome'\n        },\n        {\n          title: 'Including',\n          text: 'Including Shepherd is easy! Just include shepherd.js. The styles are bundled with the JS.',\n          attachTo: {\n            element: '.hero-including',\n            on: 'bottom'\n          },\n          buttons: [\n            {\n              action: shepherd.back,\n              classes: 'shepherd-button-secondary',\n              text: 'Back'\n            },\n            {\n              action: shepherd.next,\n              classes: 'shepherd-button-example-primary',\n              text: 'Next'\n            }\n          ],\n          id: 'including',\n          classes: 'shepherd-step-element second-step'\n        },\n        {\n          title: 'Example Shepherd',\n          text: 'Creating a Shepherd is easy too! Just create Shepherd and add as many steps as you want. Check out the <a href=\"https://shepherdjs.dev/docs/\">documentation</a> to learn more.',\n          attachTo: {\n            element: '.hero-example',\n            on: 'bottom'\n          },\n          buttons: [\n            {\n              action: shepherd.back,\n              classes: 'shepherd-button-secondary',\n              text: 'Back'\n            },\n            {\n              action: shepherd.next,\n              classes: 'shepherd-button-example-primary',\n              text: 'Next'\n            }\n          ],\n          id: 'example',\n          classes: 'shepherd-step-element third-step'\n        },\n        {\n          title: 'Learn more',\n          text: 'Star Shepherd on Github so you remember it for your next project',\n          attachTo: {\n            element: '.hero-followup',\n            on: 'left'\n          },\n          buttons: [\n            {\n              action: shepherd.back,\n              classes: 'shepherd-button-secondary',\n              text: 'Back'\n            },\n            {\n              action: shepherd.next,\n              classes: 'shepherd-button-example-primary',\n              text: 'Done'\n            }\n          ],\n          id: 'followup',\n          classes: 'shepherd-step-element fourth-step'\n        }\n      ];\n\n      shepherd.addSteps(steps);\n      shepherd.start();\n    </script>\n\n    <!-- Welcome page -->\n    <script src=\"js/prism.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "shepherd.js/dummy/js/prism.js",
    "content": "/* PrismJS 1.15.0\nhttps://prismjs.com/download.html#themes=prism&languages=markup+clike+javascript&plugins=unescaped-markup+normalize-whitespace */\nvar _self=\"undefined\"!=typeof window?window:\"undefined\"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\\blang(?:uage)?-([\\w-]+)\\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):\"Array\"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/\\u00a0/g,\" \")},type:function(e){return Object.prototype.toString.call(e).match(/\\[object (\\w+)\\]/)[1]},objId:function(e){return e.__id||Object.defineProperty(e,\"__id\",{value:++t}),e.__id},clone:function(e,t){var r=n.util.type(e);switch(t=t||{},r){case\"Object\":if(t[n.util.objId(e)])return t[n.util.objId(e)];var a={};t[n.util.objId(e)]=a;for(var l in e)e.hasOwnProperty(l)&&(a[l]=n.util.clone(e[l],t));return a;case\"Array\":if(t[n.util.objId(e)])return t[n.util.objId(e)];var a=[];return t[n.util.objId(e)]=a,e.forEach(function(e,r){a[r]=n.util.clone(e,t)}),a}return e}},languages:{extend:function(e,t){var r=n.util.clone(n.languages[e]);for(var a in t)r[a]=t[a];return r},insertBefore:function(e,t,r,a){a=a||n.languages;var l=a[e];if(2==arguments.length){r=arguments[1];for(var i in r)r.hasOwnProperty(i)&&(l[i]=r[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==t)for(var i in r)r.hasOwnProperty(i)&&(o[i]=r[i]);o[s]=l[s]}return n.languages.DFS(n.languages,function(t,n){n===a[e]&&t!=e&&(this[t]=o)}),a[e]=o},DFS:function(e,t,r,a){a=a||{};for(var l in e)e.hasOwnProperty(l)&&(t.call(e,l,e[l],r||l),\"Object\"!==n.util.type(e[l])||a[n.util.objId(e[l])]?\"Array\"!==n.util.type(e[l])||a[n.util.objId(e[l])]||(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,l,a)):(a[n.util.objId(e[l])]=!0,n.languages.DFS(e[l],t,null,a)))}},plugins:{},highlightAll:function(e,t){n.highlightAllUnder(document,e,t)},highlightAllUnder:function(e,t,r){var a={callback:r,selector:'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'};n.hooks.run(\"before-highlightall\",a);for(var l,i=a.elements||e.querySelectorAll(a.selector),o=0;l=i[o++];)n.highlightElement(l,t===!0,a.callback)},highlightElement:function(t,r,a){for(var l,i,o=t;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,\"\"])[1].toLowerCase(),i=n.languages[l]),t.className=t.className.replace(e,\"\").replace(/\\s+/g,\" \")+\" language-\"+l,t.parentNode&&(o=t.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,\"\").replace(/\\s+/g,\" \")+\" language-\"+l));var s=t.textContent,u={element:t,language:l,grammar:i,code:s};if(n.hooks.run(\"before-sanity-check\",u),!u.code||!u.grammar)return u.code&&(n.hooks.run(\"before-highlight\",u),u.element.textContent=u.code,n.hooks.run(\"after-highlight\",u)),n.hooks.run(\"complete\",u),void 0;if(n.hooks.run(\"before-highlight\",u),r&&_self.Worker){var g=new Worker(n.filename);g.onmessage=function(e){u.highlightedCode=e.data,n.hooks.run(\"before-insert\",u),u.element.innerHTML=u.highlightedCode,a&&a.call(u.element),n.hooks.run(\"after-highlight\",u),n.hooks.run(\"complete\",u)},g.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=n.highlight(u.code,u.grammar,u.language),n.hooks.run(\"before-insert\",u),u.element.innerHTML=u.highlightedCode,a&&a.call(t),n.hooks.run(\"after-highlight\",u),n.hooks.run(\"complete\",u)},highlight:function(e,t,a){var l={code:e,grammar:t,language:a};return n.hooks.run(\"before-tokenize\",l),l.tokens=n.tokenize(l.code,l.grammar),n.hooks.run(\"after-tokenize\",l),r.stringify(n.util.encode(l.tokens),l.language)},matchGrammar:function(e,t,r,a,l,i,o){var s=n.Token;for(var u in r)if(r.hasOwnProperty(u)&&r[u]){if(u==o)return;var g=r[u];g=\"Array\"===n.util.type(g)?g:[g];for(var c=0;c<g.length;++c){var h=g[c],f=h.inside,d=!!h.lookbehind,m=!!h.greedy,p=0,y=h.alias;if(m&&!h.pattern.global){var v=h.pattern.toString().match(/[imuy]*$/)[0];h.pattern=RegExp(h.pattern.source,v+\"g\")}h=h.pattern||h;for(var b=a,k=l;b<t.length;k+=t[b].length,++b){var w=t[b];if(t.length>e.length)return;if(!(w instanceof s)){if(m&&b!=t.length-1){h.lastIndex=k;var _=h.exec(e);if(!_)break;for(var j=_.index+(d?_[1].length:0),P=_.index+_[0].length,A=b,x=k,O=t.length;O>A&&(P>x||!t[A].type&&!t[A-1].greedy);++A)x+=t[A].length,j>=x&&(++b,k=x);if(t[b]instanceof s)continue;I=A-b,w=e.slice(k,x),_.index-=k}else{h.lastIndex=0;var _=h.exec(w),I=1}if(_){d&&(p=_[1]?_[1].length:0);var j=_.index+p,_=_[0].slice(p),P=j+_.length,N=w.slice(0,j),S=w.slice(P),C=[b,I];N&&(++b,k+=N.length,C.push(N));var E=new s(u,f?n.tokenize(_,f):_,y,_,m);if(C.push(E),S&&C.push(S),Array.prototype.splice.apply(t,C),1!=I&&n.matchGrammar(e,t,r,b,k,!0,u),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||\"\").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if(\"string\"==typeof e)return e;if(\"Array\"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join(\"\");var l={type:e.type,content:r.stringify(e.content,t,a),tag:\"span\",classes:[\"token\",e.type],attributes:{},language:t,parent:a};if(e.alias){var i=\"Array\"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run(\"wrap\",l);var o=Object.keys(l.attributes).map(function(e){return e+'=\"'+(l.attributes[e]||\"\").replace(/\"/g,\"&quot;\")+'\"'}).join(\" \");return\"<\"+l.tag+' class=\"'+l.classes.join(\" \")+'\"'+(o?\" \"+o:\"\")+\">\"+l.content+\"</\"+l.tag+\">\"},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener(\"message\",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName(\"script\")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute(\"data-manual\")||(\"loading\"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener(\"DOMContentLoaded\",n.highlightAll))),_self.Prism}();\"undefined\"!=typeof module&&module.exports&&(module.exports=Prism),\"undefined\"!=typeof global&&(global.Prism=Prism);\nPrism.languages.markup={comment:/<!--[\\s\\S]*?-->/,prolog:/<\\?[\\s\\S]+?\\?>/,doctype:/<!DOCTYPE[\\s\\S]+?>/i,cdata:/<!\\[CDATA\\[[\\s\\S]*?]]>/i,tag:{pattern:/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s+[^\\s>\\/=]+(?:=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+))?)*\\s*\\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\\/?[^\\s>\\/]+/i,inside:{punctuation:/^<\\/?/,namespace:/^[^\\s>\\/:]+:/}},\"attr-value\":{pattern:/=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\\\])[\"']/,lookbehind:!0}]}},punctuation:/\\/?>/,\"attr-name\":{pattern:/[^\\s>\\/]+/,inside:{namespace:/^[^\\s>\\/:]+:/}}}},entity:/&#?[\\da-z]{1,8};/i},Prism.languages.markup.tag.inside[\"attr-value\"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add(\"wrap\",function(a){\"entity\"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,\"&\"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;\nPrism.languages.clike={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":{pattern:/((?:\\b(?:class|interface|extends|implements|trait|instanceof|new)\\s+)|(?:catch\\s+\\())[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\\b/,\"boolean\":/\\b(?:true|false)\\b/,\"function\":/[a-z0-9_]+(?=\\()/i,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/--?|\\+\\+?|!=?=?|<=?|>=?|==?=?|&&?|\\|\\|?|\\?|\\*|\\/|~|\\^|%/,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.javascript=Prism.languages.extend(\"clike\",{keyword:/\\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\\b/,number:/\\b(?:0[xX][\\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:[Ee][+-]?\\d+)?/,\"function\":/[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*\\()/i,operator:/-[-=]?|\\+[+=]?|!=?=?|<<?=?|>>?>?=?|=(?:==?|>)?|&[&=]?|\\|[|=]?|\\*\\*?=?|\\/=?|~|\\^=?|%=?|\\?|\\.{3}/}),Prism.languages.insertBefore(\"javascript\",\"keyword\",{regex:{pattern:/((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s])\\s*)\\/(\\[[^\\]\\r\\n]+]|\\\\.|[^\\/\\\\\\[\\r\\n])+\\/[gimyu]{0,5}(?=\\s*($|[\\r\\n,.;})\\]]))/,lookbehind:!0,greedy:!0},\"function-variable\":{pattern:/[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*=\\s*(?:function\\b|(?:\\([^()]*\\)|[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*)\\s*=>))/i,alias:\"function\"},constant:/\\b[A-Z][A-Z\\d_]*\\b/}),Prism.languages.insertBefore(\"javascript\",\"string\",{\"template-string\":{pattern:/`(?:\\\\[\\s\\S]|\\${[^}]+}|[^\\\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\\${[^}]+}/,inside:{\"interpolation-punctuation\":{pattern:/^\\${|}$/,alias:\"punctuation\"},rest:null}},string:/[\\s\\S]+/}}}),Prism.languages.javascript[\"template-string\"].inside.interpolation.inside.rest=Prism.languages.javascript,Prism.languages.markup&&Prism.languages.insertBefore(\"markup\",\"tag\",{script:{pattern:/(<script[\\s\\S]*?>)[\\s\\S]*?(?=<\\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:\"language-javascript\",greedy:!0}}),Prism.languages.js=Prism.languages.javascript;\n!function(){\"undefined\"!=typeof self&&self.Prism&&self.document&&Prism.languages.markup&&(Prism.plugins.UnescapedMarkup=!0,Prism.hooks.add(\"before-highlightall\",function(e){e.selector+=\", [class*='lang-'] script[type='text/plain'], [class*='language-'] script[type='text/plain'], script[type='text/plain'][class*='lang-'], script[type='text/plain'][class*='language-']\"}),Prism.hooks.add(\"before-sanity-check\",function(e){if((e.element.matches||e.element.msMatchesSelector).call(e.element,\"script[type='text/plain']\")){var t=document.createElement(\"code\"),n=document.createElement(\"pre\");return n.className=t.className=e.element.className,e.element.dataset&&Object.keys(e.element.dataset).forEach(function(t){Object.prototype.hasOwnProperty.call(e.element.dataset,t)&&(n.dataset[t]=e.element.dataset[t])}),e.code=e.code.replace(/&lt;\\/script(>|&gt;)/gi,\"</script>\"),t.textContent=e.code,n.appendChild(t),e.element.parentNode.replaceChild(n,e.element),e.element=t,void 0}var n=e.element.parentNode;!e.code&&n&&\"pre\"==n.nodeName.toLowerCase()&&e.element.childNodes.length&&\"#comment\"==e.element.childNodes[0].nodeName&&(e.element.textContent=e.code=e.element.childNodes[0].textContent)}))}();\n!function(){function e(e){this.defaults=r({},e)}function n(e){return e.replace(/-(\\w)/g,function(e,n){return n.toUpperCase()})}function t(e){for(var n=0,t=0;t<e.length;++t)e.charCodeAt(t)==\"\t\".charCodeAt(0)&&(n+=3);return e.length+n}var r=Object.assign||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);return e};e.prototype={setDefaults:function(e){this.defaults=r(this.defaults,e)},normalize:function(e,t){t=r(this.defaults,t);for(var i in t){var o=n(i);\"normalize\"!==i&&\"setDefaults\"!==o&&t[i]&&this[o]&&(e=this[o].call(this,e,t[i]))}return e},leftTrim:function(e){return e.replace(/^\\s+/,\"\")},rightTrim:function(e){return e.replace(/\\s+$/,\"\")},tabsToSpaces:function(e,n){return n=0|n||4,e.replace(/\\t/g,new Array(++n).join(\" \"))},spacesToTabs:function(e,n){return n=0|n||4,e.replace(new RegExp(\" {\"+n+\"}\",\"g\"),\"\t\")},removeTrailing:function(e){return e.replace(/\\s*?$/gm,\"\")},removeInitialLineFeed:function(e){return e.replace(/^(?:\\r?\\n|\\r)/,\"\")},removeIndent:function(e){var n=e.match(/^[^\\S\\n\\r]*(?=\\S)/gm);return n&&n[0].length?(n.sort(function(e,n){return e.length-n.length}),n[0].length?e.replace(new RegExp(\"^\"+n[0],\"gm\"),\"\"):e):e},indent:function(e,n){return e.replace(/^[^\\S\\n\\r]*(?=\\S)/gm,new Array(++n).join(\"\t\")+\"$&\")},breakLines:function(e,n){n=n===!0?80:0|n||80;for(var r=e.split(\"\\n\"),i=0;i<r.length;++i)if(!(t(r[i])<=n)){for(var o=r[i].split(/(\\s+)/g),a=0,s=0;s<o.length;++s){var l=t(o[s]);a+=l,a>n&&(o[s]=\"\\n\"+o[s],a=l)}r[i]=o.join(\"\")}return r.join(\"\\n\")}},\"undefined\"!=typeof module&&module.exports&&(module.exports=e),\"undefined\"!=typeof Prism&&(Prism.plugins.NormalizeWhitespace=new e({\"remove-trailing\":!0,\"remove-indent\":!0,\"left-trim\":!0,\"right-trim\":!0}),Prism.hooks.add(\"before-sanity-check\",function(e){var n=Prism.plugins.NormalizeWhitespace;if(!e.settings||e.settings[\"whitespace-normalization\"]!==!1){if((!e.element||!e.element.parentNode)&&e.code)return e.code=n.normalize(e.code,e.settings),void 0;var t=e.element.parentNode,r=/\\bno-whitespace-normalization\\b/;if(e.code&&t&&\"pre\"===t.nodeName.toLowerCase()&&!r.test(t.className)&&!r.test(e.element.className)){for(var i=t.childNodes,o=\"\",a=\"\",s=!1,l=0;l<i.length;++l){var c=i[l];c==e.element?s=!0:\"#text\"===c.nodeName&&(s?a+=c.nodeValue:o+=c.nodeValue,t.removeChild(c),--l)}if(e.element.children.length&&Prism.plugins.KeepMarkup){var u=o+e.element.innerHTML+a;e.element.innerHTML=n.normalize(u,e.settings),e.code=e.element.textContent}else e.code=o+e.code+a,e.code=n.normalize(e.code,e.settings)}}}))}();\n"
  },
  {
    "path": "shepherd.js/eslint.config.js",
    "content": "import js from '@eslint/js';\nimport cypress from 'eslint-plugin-cypress/flat';\nimport globals from 'globals';\nimport ts from '@typescript-eslint/eslint-plugin';\nimport tsParser from '@typescript-eslint/parser';\n\nexport default [\n  // Base config for all files\n  js.configs.recommended,\n  {\n    languageOptions: {\n      ecmaVersion: 'latest',\n      sourceType: 'module',\n      globals: {\n        ...globals.browser,\n        ...globals.es2020\n      }\n    },\n    rules: {\n      'no-console': 'off',\n      'prefer-const': 'off',\n      'no-unused-vars': [\n        'error',\n        { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }\n      ]\n    }\n  },\n\n  // TypeScript files\n  {\n    files: ['**/*.ts'],\n    ignores: ['vitest.config.ts'],\n    languageOptions: {\n      parser: tsParser,\n      parserOptions: {\n        project: './tsconfig.json'\n      }\n    },\n    plugins: {\n      '@typescript-eslint': ts\n    },\n    rules: {\n      '@typescript-eslint/no-unused-vars': [\n        'error',\n        {\n          argsIgnorePattern: '^_',\n          varsIgnorePattern: '^_',\n          caughtErrorsIgnorePattern: '^_'\n        }\n      ],\n      '@typescript-eslint/no-explicit-any': 'error',\n      'no-unused-vars': 'off', // Use TypeScript version instead\n      'prefer-rest-params': 'off'\n    }\n  },\n\n  // Config files (vitest, babel, etc.)\n  {\n    files: ['vitest.config.ts', '**/*.config.*'],\n    languageOptions: {\n      globals: {\n        ...globals.node\n      }\n    }\n  },\n\n  // Cypress test files\n  {\n    files: ['test/cypress/**/*.cy.js', 'test/cypress/utils/**/*.js'],\n    ...cypress.configs.recommended,\n    rules: {\n      'cypress/no-unnecessary-waiting': 'off',\n      'cypress/no-async-tests': 'off'\n    }\n  },\n\n  // Cypress support files (uses CommonJS)\n  {\n    files: ['test/cypress/support/**/*.js'],\n    languageOptions: {\n      globals: {\n        ...globals.node\n      }\n    }\n  },\n\n  // Vitest setup file (uses Node globals)\n  {\n    files: ['test/unit/setupTests.js'],\n    languageOptions: {\n      globals: {\n        ...globals.node\n      }\n    }\n  },\n\n  // Node config files\n  {\n    files: [\n      '.eslintrc.js',\n      '.prettierrc.js',\n      'rollup.config.mjs',\n      'eslint.config.js',\n      'test/unit/babel.config.cjs'\n    ],\n    languageOptions: {\n      globals: {\n        ...globals.node\n      }\n    }\n  },\n\n  // Ignore patterns\n  {\n    ignores: [\n      'dev/',\n      'dist/',\n      'dummy/',\n      'tmp/',\n      'test/cypress/dummy/js/prism.js',\n      'node_modules/',\n      'coverage/',\n      'test/coverage/',\n      '.eslintrc.cjs'\n    ]\n  }\n];\n"
  },
  {
    "path": "shepherd.js/package.json",
    "content": "{\n  \"name\": \"shepherd.js\",\n  \"version\": \"15.2.2\",\n  \"description\": \"Guide your users through a tour of your app.\",\n  \"keywords\": [\n    \"site tour\",\n    \"tour\",\n    \"tutorial\",\n    \"shepherd\"\n  ],\n  \"homepage\": \"https://shepherdjs.dev\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/shipshapecode/shepherd.git\"\n  },\n  \"license\": \"AGPL-3.0\",\n  \"authors\": [\n    \"Robbie Wagner <rwwagner90@gmail.com>\",\n    \"Chuck Carpenter <chuck@shipshape.io>\"\n  ],\n  \"files\": [\n    \"dist\",\n    \"LICENSE.md\",\n    \"README.md\"\n  ],\n  \"main\": \"./dist/cjs/shepherd.cjs\",\n  \"module\": \"./dist/js/shepherd.mjs\",\n  \"exports\": {\n    \".\": {\n      \"import\": {\n        \"types\": \"./dist/js/shepherd.d.mts\",\n        \"default\": \"./dist/js/shepherd.mjs\"\n      },\n      \"require\": {\n        \"types\": \"./dist/cjs/shepherd.d.cts\",\n        \"default\": \"./dist/cjs/shepherd.cjs\"\n      }\n    },\n    \"./dist/*\": \"./dist/*\"\n  },\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"pnpm clean && rollup -c\",\n    \"clean\": \"rimraf ./dist ./tmp\",\n    \"cy:open\": \"cypress open --config-file test/cypress/cypress.config.js\",\n    \"cy:run:chrome\": \"cypress run --browser chrome --config-file test/cypress/cypress.config.js\",\n    \"cypress:install\": \"cypress install\",\n    \"esdoc\": \"esdoc\",\n    \"lint\": \"concurrently \\\"npm:lint:*(!fix)\\\" --names \\\"lint:\\\"\",\n    \"lint:fix\": \"concurrently \\\"npm:lint:*:fix\\\" --names \\\"fix:\\\"\",\n    \"lint:js\": \"eslint . --cache\",\n    \"lint:js:fix\": \"eslint . --fix\",\n    \"lint:prettier\": \"prettier --check '**/*.{js,ts}'\",\n    \"lint:prettier:fix\": \"prettier --write '**/*.{js,ts}'\",\n    \"prepack\": \"pnpm build\",\n    \"start-test-server\": \"http-server . -p 9002\",\n    \"test\": \"vitest\",\n    \"test:all\": \"pnpm test:unit:ci && pnpm test:cy:ci\",\n    \"test:ci\": \"pnpm test:unit:ci && pnpm test:cy:ci\",\n    \"test:cy:ci\": \"start-server-and-test start-test-server http://127.0.0.1:9002 cy:run:chrome\",\n    \"test:cy:watch\": \"start-server-and-test start-test-server http://127.0.0.1:9002 cy:open\",\n    \"test:unit\": \"vitest\",\n    \"test:unit:ci\": \"vitest run --coverage\",\n    \"test:unit:watch\": \"vitest\",\n    \"types:check\": \"pnpm types:check:esm && pnpm types:check:attw\",\n    \"types:check:attw\": \"pnpm attw --pack . --exclude-entrypoints ./dist/css/shepherd.css\",\n    \"types:check:esm\": \"pnpm tsc --module esnext --moduleResolution bundler --noEmit true --emitDeclarationOnly false\",\n    \"view-coverage\": \"http-server -p 9003 ./test/coverage/lcov-report -o\",\n    \"watch\": \"pnpm clean && rollup -c --environment DEVELOPMENT --watch\"\n  },\n  \"dependencies\": {\n    \"@floating-ui/dom\": \"^1.7.5\",\n    \"deepmerge-ts\": \"^7.1.5\"\n  },\n  \"devDependencies\": {\n    \"@arethetypeswrong/cli\": \"^0.18.2\",\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/plugin-transform-typescript\": \"^7.28.6\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@rollup/plugin-babel\": \"^6.1.0\",\n    \"@rollup/plugin-node-resolve\": \"^16.0.3\",\n    \"@rollup/plugin-replace\": \"^6.0.3\",\n    \"@rollup/plugin-terser\": \"^0.4.4\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@vitest/coverage-v8\": \"^4.0.18\",\n    \"@vitest/expect\": \"^4.0.18\",\n    \"autoprefixer\": \"^10.4.27\",\n    \"chai\": \"^6.2.2\",\n    \"cssnano\": \"^7.1.2\",\n    \"cypress\": \"^14.5.4\",\n    \"cypress-plugin-tab\": \"^1.0.5\",\n    \"del\": \"^7.1.0\",\n    \"dts-bundle-generator\": \"^9.5.1\",\n    \"eslint\": \"^9.39.3\",\n    \"eslint-plugin-cypress\": \"^5.3.0\",\n    \"eslint-plugin-vitest\": \"^0.5.4\",\n    \"execa\": \"^9.6.1\",\n    \"globals\": \"^17.4.0\",\n    \"happy-dom\": \"^20.7.0\",\n    \"http-server\": \"^14.1.1\",\n    \"lodash\": \"^4.17.23\",\n    \"postcss\": \"^8.5.8\",\n    \"prettier\": \"^3.8.1\",\n    \"replace\": \"^1.2.2\",\n    \"resize-observer-polyfill\": \"^1.5.1\",\n    \"rimraf\": \"^6.1.3\",\n    \"rollup\": \"^4.59.0\",\n    \"rollup-plugin-analyzer\": \"^4.0.0\",\n    \"rollup-plugin-filesize\": \"^10.0.0\",\n    \"rollup-plugin-license\": \"^3.7.0\",\n    \"rollup-plugin-livereload\": \"^2.0.5\",\n    \"rollup-plugin-postcss\": \"^4.0.2\",\n    \"rollup-plugin-serve\": \"^2.0.3\",\n    \"rollup-plugin-visualizer\": \"^5.14.0\",\n    \"start-server-and-test\": \"^2.1.5\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.3.1\",\n    \"vitest\": \"^4.0.18\"\n  },\n  \"packageManager\": \"pnpm@10.28.2\",\n  \"engines\": {\n    \"node\": \">= 20\"\n  },\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npmjs.org\"\n  }\n}\n"
  },
  {
    "path": "shepherd.js/rollup.config.mjs",
    "content": "import autoprefixer from 'autoprefixer';\nimport { execaCommand } from 'execa';\nimport fs from 'fs';\nimport cssnanoPlugin from 'cssnano';\nimport { babel } from '@rollup/plugin-babel';\nimport serve from 'rollup-plugin-serve';\nimport livereload from 'rollup-plugin-livereload';\nimport filesize from 'rollup-plugin-filesize';\nimport license from 'rollup-plugin-license';\nimport postcss from 'rollup-plugin-postcss';\nimport replace from '@rollup/plugin-replace';\nimport { nodeResolve } from '@rollup/plugin-node-resolve';\nimport { visualizer } from 'rollup-plugin-visualizer';\nimport terser from '@rollup/plugin-terser';\n\nconst pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));\nconst banner = ['/*!', pkg.name, pkg.version, '*/\\n'].join(' ');\n\nconst isDev = process.env.DEVELOPMENT;\nconst env = isDev ? 'development' : 'production';\n\nconst plugins = [\n  nodeResolve({\n    browser: true,\n    extensions: ['.js', '.json', '.mjs', '.ts'],\n    preferBuiltins: false\n  }),\n  replace({\n    'process.env.NODE_ENV': JSON.stringify(env),\n    preventAssignment: true\n  }),\n  babel({\n    extensions: ['.cjs', '.js', '.ts', '.mjs'],\n    babelHelpers: 'bundled',\n    presets: ['@babel/preset-typescript'],\n    exclude: 'node_modules/**'\n  }),\n  postcss({\n    plugins: isDev ? [autoprefixer] : [autoprefixer, cssnanoPlugin],\n    extract: 'css/shepherd.css'\n  }),\n  license({\n    banner\n  }),\n  filesize(),\n  visualizer()\n];\n\n// If we are running with --environment DEVELOPMENT, serve via browsersync for local development\nif (process.env.DEVELOPMENT) {\n  plugins.push(\n    serve({ contentBase: ['.', 'dist', 'dev', 'dummy'], open: true })\n  );\n  plugins.push(livereload());\n} else {\n  plugins.push(\n    terser({\n      compress: {\n        drop_console: true,\n        drop_debugger: true,\n        pure_funcs: ['console.log', 'console.debug']\n      },\n      mangle: {\n        properties: false\n      }\n    })\n  );\n}\n\nconst sharedConfig = {\n  input: 'src/shepherd.ts',\n  // More aggressive tree shaking\n  treeshake: {\n    moduleSideEffects: (id) => id.endsWith('.css'),\n    propertyReadSideEffects: false,\n    unknownGlobalSideEffects: false\n  }\n};\n\nexport default [\n  // ESM build\n  {\n    ...sharedConfig,\n    output: {\n      dir: 'tmp/js',\n      entryFileNames: '[name].mjs',\n      format: 'es',\n      sourcemap: true\n    },\n    plugins: [\n      ...plugins,\n      {\n        name: 'After ESM build tweaks',\n        closeBundle: async () => {\n          console.log('Copying CSS to the root');\n\n          await execaCommand(`mkdir -p ./dist/css`, {\n            stdio: 'inherit'\n          });\n\n          await execaCommand(`mkdir -p ./dist/js`, {\n            stdio: 'inherit'\n          });\n\n          await execaCommand(\n            `cp ./tmp/js/css/shepherd.css ./dist/css/shepherd.css`,\n            {\n              stdio: 'inherit'\n            }\n          );\n\n          console.log('Generating TypeScript declarations');\n\n          await execaCommand(\n            `npx tsc --declaration --emitDeclarationOnly --declarationDir tmp/js --skipLibCheck`,\n            {\n              stdio: 'inherit'\n            }\n          );\n\n          console.log('Rollup TS declarations to one file');\n\n          await execaCommand(\n            `pnpm dts-bundle-generator --no-check -o ./dist/js/shepherd.d.mts ./tmp/js/shepherd.d.ts`,\n            {\n              stdio: 'inherit'\n            }\n          );\n\n          console.log('Move shepherd.mjs from tmp to dist');\n\n          await execaCommand(\n            `mv ./tmp/js/shepherd.mjs ./tmp/js/shepherd.mjs.map ./dist/js/`,\n            {\n              stdio: 'inherit'\n            }\n          );\n\n          console.log('Copying README and LICENSE from root to shepherd.js');\n\n          await execaCommand(`cp ../README.md ./README.md`, {\n            stdio: 'inherit'\n          });\n\n          await execaCommand(`cp ../LICENSE.md ./LICENSE.md`, {\n            stdio: 'inherit'\n          });\n        }\n      }\n    ]\n  },\n  // CJS build\n  {\n    ...sharedConfig,\n    output: {\n      dir: 'tmp/cjs',\n      entryFileNames: '[name].cjs',\n      format: 'cjs',\n      sourcemap: true,\n      exports: 'named'\n    },\n    plugins: [\n      ...plugins,\n      {\n        name: 'After CJS build tweaks',\n        closeBundle: async () => {\n          await execaCommand(`mkdir -p ./dist/cjs`, {\n            stdio: 'inherit'\n          });\n\n          console.log('Move shepherd.cjs from tmp to dist');\n\n          await execaCommand(\n            `mv ./tmp/cjs/shepherd.cjs ./tmp/cjs/shepherd.cjs.map ./dist/cjs/`,\n            {\n              stdio: 'inherit'\n            }\n          );\n\n          console.log('Copy CJS declarations');\n\n          await execaCommand(\n            `cp ./dist/js/shepherd.d.mts ./dist/cjs/shepherd.d.cts`,\n            {\n              stdio: 'inherit'\n            }\n          );\n        }\n      }\n    ]\n  }\n];\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-button.css",
    "content": ".shepherd-button {\n  background: rgb(50, 136, 230);\n  border: 0;\n  border-radius: 3px;\n  color: rgba(255, 255, 255, 0.75);\n  cursor: pointer;\n  margin-right: 0.5rem;\n  padding: 0.5rem 1.5rem;\n  transition: all 0.5s ease;\n}\n\n.shepherd-button:not(:disabled):hover {\n  background: rgb(25, 111, 204);\n  color: rgba(255, 255, 255, 0.75);\n}\n\n.shepherd-button.shepherd-button-secondary {\n  background: rgb(241, 242, 243);\n  color: rgba(0, 0, 0, 0.75);\n}\n\n.shepherd-button.shepherd-button-secondary:not(:disabled):hover {\n  background: rgb(214, 217, 219);\n  color: rgba(0, 0, 0, 0.75);\n}\n\n.shepherd-button:disabled {\n  cursor: not-allowed;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-button.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport { isFunction } from '../utils/type-check.ts';\nimport type { Step, StepOptionsButton } from '../step.ts';\nimport './shepherd-button.css';\n\nfunction getConfigOption(option: unknown, step: Step): unknown {\n  if (isFunction(option)) {\n    return option.call(step);\n  }\n  return option;\n}\n\nexport function createShepherdButton(\n  config: StepOptionsButton,\n  step: Step\n): HTMLButtonElement {\n  const action = config.action ? config.action.bind(step.tour) : null;\n  const disabled = config.disabled\n    ? getConfigOption(config.disabled, step)\n    : false;\n  const label = config.label ? getConfigOption(config.label, step) : null;\n  const text = config.text ? getConfigOption(config.text, step) : null;\n\n  const btn = h('button', {\n    ...(config.attrs || {}),\n    'aria-label': label || null,\n    class: `${config.classes || ''} shepherd-button ${\n      config.secondary ? 'shepherd-button-secondary' : ''\n    }`,\n    disabled: disabled || null,\n    onclick: action,\n    tabindex: '0',\n    type: 'button'\n  }) as HTMLButtonElement;\n\n  if (text) {\n    btn.innerHTML = text as string;\n  }\n\n  return btn;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-cancel-icon.css",
    "content": ".shepherd-cancel-icon {\n  background: transparent;\n  border: none;\n  color: rgba(128, 128, 128, 0.75);\n  font-size: 2em;\n  cursor: pointer;\n  font-weight: normal;\n  margin: 0;\n  padding: 0;\n  transition: color 0.5s ease;\n}\n\n.shepherd-cancel-icon:hover {\n  color: rgba(0, 0, 0, 0.75);\n}\n\n.shepherd-has-title .shepherd-content .shepherd-cancel-icon {\n  color: rgba(128, 128, 128, 0.75);\n}\n\n.shepherd-has-title .shepherd-content .shepherd-cancel-icon:hover {\n  color: rgba(0, 0, 0, 0.75);\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-cancel-icon.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport type { Step, StepOptionsCancelIcon } from '../step.ts';\nimport './shepherd-cancel-icon.css';\n\nexport function createShepherdCancelIcon(\n  cancelIcon: StepOptionsCancelIcon,\n  step: Step\n): HTMLButtonElement {\n  const handleCancelClick = (e: Event) => {\n    e.preventDefault();\n    step.cancel();\n  };\n\n  const btn = h(\n    'button',\n    {\n      ...(cancelIcon.attrs || {}),\n      'aria-label': cancelIcon.label ? cancelIcon.label : 'Close Tour',\n      class: 'shepherd-cancel-icon',\n      onclick: handleCancelClick,\n      type: 'button'\n    },\n    h('span', { 'aria-hidden': 'true' }, '\\u00D7')\n  ) as HTMLButtonElement;\n\n  return btn;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-content.css",
    "content": ".shepherd-content {\n  border-radius: 5px;\n  outline: none;\n  padding: 0;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-content.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport { createShepherdFooter } from './shepherd-footer.ts';\nimport { createShepherdHeader } from './shepherd-header.ts';\nimport { createShepherdText } from './shepherd-text.ts';\nimport { isUndefined } from '../utils/type-check.ts';\nimport type { Step } from '../step.ts';\nimport './shepherd-content.css';\n\nexport function createShepherdContent(\n  descriptionId: string,\n  labelId: string,\n  step: Step\n): HTMLDivElement {\n  const content = h('div', { class: 'shepherd-content' }) as HTMLDivElement;\n\n  if (\n    !isUndefined(step.options.title) ||\n    (step.options.cancelIcon && step.options.cancelIcon.enabled)\n  ) {\n    content.append(createShepherdHeader(labelId, step));\n  }\n\n  if (!isUndefined(step.options.text)) {\n    content.append(createShepherdText(descriptionId, step));\n  }\n\n  if (Array.isArray(step.options.buttons) && step.options.buttons.length) {\n    content.append(createShepherdFooter(step));\n  }\n\n  return content;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-element.css",
    "content": ".shepherd-element {\n  background: #fff;\n  border: none;\n  border-radius: 5px;\n  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);\n  margin: 0;\n  max-width: 400px;\n  opacity: 0;\n  outline: none;\n  padding: 0;\n  transition:\n    opacity 0.3s,\n    visibility 0.3s;\n  visibility: hidden;\n  width: 100%;\n  z-index: 9999;\n}\n\n.shepherd-enabled.shepherd-element {\n  opacity: 1;\n  visibility: visible;\n}\n\n.shepherd-element[data-popper-reference-hidden]:not(.shepherd-centered) {\n  opacity: 0;\n  pointer-events: none;\n  visibility: hidden;\n}\n\n.shepherd-element,\n.shepherd-element *,\n.shepherd-element *:after,\n.shepherd-element *:before {\n  box-sizing: border-box;\n}\n\n.shepherd-arrow,\n.shepherd-arrow::before {\n  position: absolute;\n  width: 16px;\n  height: 16px;\n  z-index: -1;\n}\n\n.shepherd-arrow:before {\n  content: '';\n  transform: rotate(45deg);\n  background: #fff;\n}\n\n.shepherd-element[data-popper-placement^='top'] > .shepherd-arrow {\n  bottom: -8px;\n}\n\n.shepherd-element[data-popper-placement^='bottom'] > .shepherd-arrow {\n  top: -8px;\n}\n\n.shepherd-element[data-popper-placement^='left'] > .shepherd-arrow {\n  right: -8px;\n}\n\n.shepherd-element[data-popper-placement^='right'] > .shepherd-arrow {\n  left: -8px;\n}\n\n.shepherd-element.shepherd-centered > .shepherd-arrow {\n  opacity: 0;\n}\n\n/**\n* Arrow on top of tooltip centered horizontally, with title color\n*/\n.shepherd-element.shepherd-has-title[data-popper-placement^='bottom']\n  > .shepherd-arrow::before {\n  background-color: #e6e6e6;\n}\n\n.shepherd-target-click-disabled.shepherd-enabled.shepherd-target,\n.shepherd-target-click-disabled.shepherd-enabled.shepherd-target * {\n  pointer-events: none;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-element.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport { createShepherdContent } from './shepherd-content.ts';\nimport { isUndefined, isString } from '../utils/type-check.ts';\nimport type { Step } from '../step.ts';\nimport './shepherd-element.css';\n\nconst KEY_TAB = 9;\nconst KEY_ESC = 27;\nconst LEFT_ARROW = 37;\nconst RIGHT_ARROW = 39;\n\nexport interface ShepherdElementOptions {\n  classPrefix?: string;\n  descriptionId: string;\n  labelId: string;\n  step: Step;\n}\n\nexport interface ShepherdElementResult {\n  element: HTMLDialogElement;\n  cleanup: () => void;\n}\n\nexport function createShepherdElement(\n  options: ShepherdElementOptions\n): ShepherdElementResult {\n  const { classPrefix, descriptionId, labelId, step } = options;\n\n  let attachToElement: HTMLElement | null | undefined;\n\n  // Focusable attachTo elements\n  let focusableAttachToElements: Element[] | undefined;\n  let firstFocusableAttachToElement: Element | undefined;\n  let lastFocusableAttachToElement: Element | undefined;\n\n  // Focusable dialog elements\n  let firstFocusableDialogElement: Element | undefined;\n  let focusableDialogElements: Element[] | undefined;\n  let lastFocusableDialogElement: Element | undefined;\n\n  const hasCancelIcon = step.options?.cancelIcon?.enabled ?? false;\n  const hasTitle = step.options?.title ?? false;\n\n  /**\n   * Setup keydown events to allow closing the modal with ESC\n   *\n   * Borrowed from this great post! https://bitsofco.de/accessible-modal-dialog/\n   */\n  const handleKeyDown = (e: KeyboardEvent) => {\n    const { tour } = step;\n    switch (e.keyCode) {\n      case KEY_TAB:\n        if (\n          (!focusableAttachToElements ||\n            focusableAttachToElements.length === 0) &&\n          focusableDialogElements &&\n          focusableDialogElements.length === 0\n        ) {\n          e.preventDefault();\n          break;\n        }\n        // Backward tab\n        if (e.shiftKey) {\n          if (\n            document.activeElement === firstFocusableDialogElement ||\n            document.activeElement?.classList.contains('shepherd-element')\n          ) {\n            e.preventDefault();\n            (\n              (lastFocusableAttachToElement ??\n                lastFocusableDialogElement) as HTMLElement\n            )?.focus();\n          } else if (document.activeElement === firstFocusableAttachToElement) {\n            e.preventDefault();\n            (lastFocusableDialogElement as HTMLElement)?.focus();\n          }\n        } else {\n          if (document.activeElement === lastFocusableDialogElement) {\n            e.preventDefault();\n            (\n              (firstFocusableAttachToElement ??\n                firstFocusableDialogElement) as HTMLElement\n            )?.focus();\n          } else if (document.activeElement === lastFocusableAttachToElement) {\n            e.preventDefault();\n            (firstFocusableDialogElement as HTMLElement)?.focus();\n          }\n        }\n        break;\n      case KEY_ESC:\n        if (tour.options.exitOnEsc) {\n          e.preventDefault();\n          e.stopPropagation();\n          step.cancel();\n        }\n        break;\n      case LEFT_ARROW:\n        if (tour.options.keyboardNavigation) {\n          e.preventDefault();\n          e.stopPropagation();\n          tour.back();\n        }\n        break;\n      case RIGHT_ARROW:\n        if (tour.options.keyboardNavigation) {\n          e.preventDefault();\n          e.stopPropagation();\n          tour.next();\n        }\n        break;\n      default:\n        break;\n    }\n  };\n\n  // Build the dialog element\n  const element = h('dialog', {\n    'aria-describedby': !isUndefined(step.options.text) ? descriptionId : null,\n    'aria-labelledby': step.options.title ? labelId : null,\n    class: [\n      'shepherd-element',\n      hasCancelIcon ? 'shepherd-has-cancel-icon' : '',\n      hasTitle ? 'shepherd-has-title' : ''\n    ]\n      .filter(Boolean)\n      .join(' '),\n    [`data-${classPrefix}shepherd-step-id`]: step.id,\n    onkeydown: handleKeyDown,\n    open: 'true'\n  }) as HTMLDialogElement;\n\n  // Add arrow if needed\n  if (\n    step.options.arrow &&\n    step.options.attachTo &&\n    step.options.attachTo.element &&\n    step.options.attachTo.on\n  ) {\n    element.append(\n      h('div', { class: 'shepherd-arrow', 'data-popper-arrow': '' })\n    );\n  }\n\n  // Add content\n  element.append(createShepherdContent(descriptionId, labelId, step));\n\n  // Dynamic class management\n  if (isString(step.options.classes)) {\n    const classes = step.options.classes.split(' ').filter((c) => !!c.length);\n    if (classes.length) {\n      element.classList.add(...classes);\n    }\n  }\n\n  // Setup focusable element tracking (equivalent of onMount)\n  const focusableSelector =\n    'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex=\"0\"]';\n\n  focusableDialogElements = [...element.querySelectorAll(focusableSelector)];\n  firstFocusableDialogElement = focusableDialogElements[0];\n  lastFocusableDialogElement =\n    focusableDialogElements[focusableDialogElements.length - 1];\n\n  const attachTo = step._getResolvedAttachToOptions();\n  if (attachTo?.element) {\n    attachToElement = attachTo.element as HTMLElement;\n    step._storeOriginalTabIndex(attachToElement);\n    attachToElement.tabIndex = 0;\n    focusableAttachToElements = [\n      attachToElement,\n      ...attachToElement.querySelectorAll(focusableSelector)\n    ];\n    firstFocusableAttachToElement = focusableAttachToElements[0];\n    lastFocusableAttachToElement =\n      focusableAttachToElements[focusableAttachToElements.length - 1];\n    attachToElement.addEventListener('keydown', handleKeyDown);\n  }\n\n  const cleanup = () => {\n    attachToElement?.removeEventListener('keydown', handleKeyDown);\n  };\n\n  return { element, cleanup };\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-footer.css",
    "content": ".shepherd-footer {\n  border-bottom-left-radius: 5px;\n  border-bottom-right-radius: 5px;\n  display: flex;\n  justify-content: flex-end;\n  padding: 0 0.75rem 0.75rem;\n}\n\n.shepherd-footer .shepherd-button:last-child {\n  margin-right: 0;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-footer.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport { createShepherdButton } from './shepherd-button.ts';\nimport type { Step } from '../step.ts';\nimport './shepherd-footer.css';\n\nexport function createShepherdFooter(step: Step): HTMLElement {\n  const footer = h('footer', { class: 'shepherd-footer' });\n\n  if (step.options.buttons) {\n    for (const config of step.options.buttons) {\n      footer.append(createShepherdButton(config, step));\n    }\n  }\n\n  return footer;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-header.css",
    "content": ".shepherd-header {\n  align-items: center;\n  border-top-left-radius: 5px;\n  border-top-right-radius: 5px;\n  display: flex;\n  justify-content: flex-end;\n  line-height: 2em;\n  padding: 0.75rem 0.75rem 0;\n}\n\n.shepherd-has-title .shepherd-content .shepherd-header {\n  background: #e6e6e6;\n  padding: 1em;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-header.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport { createShepherdCancelIcon } from './shepherd-cancel-icon.ts';\nimport { createShepherdTitle } from './shepherd-title.ts';\nimport type { Step } from '../step.ts';\nimport './shepherd-header.css';\n\nexport function createShepherdHeader(labelId: string, step: Step): HTMLElement {\n  const header = h('header', { class: 'shepherd-header' });\n\n  if (step.options.title) {\n    header.append(createShepherdTitle(labelId, step.options.title));\n  }\n\n  if (step.options.cancelIcon && step.options.cancelIcon.enabled) {\n    header.append(createShepherdCancelIcon(step.options.cancelIcon, step));\n  }\n\n  return header;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-modal.css",
    "content": ".shepherd-modal-overlay-container {\n  height: 0;\n  left: 0;\n  opacity: 0;\n  overflow: hidden;\n  pointer-events: none;\n  position: fixed;\n  top: 0;\n  transition:\n    all 0.3s ease-out,\n    height 0ms 0.3s,\n    opacity 0.3s 0ms;\n  width: 100vw;\n  z-index: 9997;\n}\n\n.shepherd-modal-overlay-container.shepherd-modal-is-visible {\n  height: 100vh;\n  opacity: 0.5;\n  transition:\n    all 0.3s ease-out,\n    height 0s 0s,\n    opacity 0.3s 0s;\n  transform: translateZ(0);\n}\n\n.shepherd-modal-overlay-container.shepherd-modal-is-visible path {\n  pointer-events: all;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-modal.ts",
    "content": "import { svgEl } from '../utils/dom.ts';\nimport { makeOverlayPath } from '../utils/overlay-path.ts';\nimport type { Step } from '../step.ts';\nimport './shepherd-modal.css';\n\ninterface OpeningProperty {\n  width: number;\n  height: number;\n  x: number;\n  y: number;\n  r:\n    | number\n    | {\n        topLeft: number;\n        bottomLeft: number;\n        bottomRight: number;\n        topRight: number;\n      };\n}\n\ntype ModalRadiusType =\n  | number\n  | {\n      topLeft?: number;\n      bottomLeft?: number;\n      bottomRight?: number;\n      topRight?: number;\n    };\n\nexport interface ShepherdModalAPI {\n  closeModalOpening: () => void;\n  destroy: () => void;\n  hide: () => void;\n  positionModal: (\n    modalOverlayOpeningPadding?: number,\n    modalOverlayOpeningRadius?: ModalRadiusType,\n    modalOverlayOpeningXOffset?: number,\n    modalOverlayOpeningYOffset?: number,\n    scrollParent?: HTMLElement | null,\n    targetElement?: HTMLElement | null,\n    extraHighlights?: HTMLElement[]\n  ) => void;\n  setupForStep: (step: Step) => void;\n  show: () => void;\n  getElement: () => SVGElement;\n}\n\nexport function createShepherdModal(container: HTMLElement): ShepherdModalAPI {\n  let rafId: number | undefined;\n  let openingProperties: OpeningProperty[] = [\n    { width: 0, height: 0, x: 0, y: 0, r: 0 }\n  ];\n\n  // Build SVG elements\n  const pathEl = svgEl('path');\n  const element = svgEl(\n    'svg',\n    { class: 'shepherd-modal-overlay-container' },\n    pathEl\n  );\n\n  element.addEventListener('touchmove', _preventModalOverlayTouch);\n\n  // Initial render\n  _updatePath();\n\n  container.append(element);\n\n  function _updatePath() {\n    pathEl.setAttribute('d', makeOverlayPath(openingProperties));\n  }\n\n  function closeModalOpening() {\n    openingProperties = [{ width: 0, height: 0, x: 0, y: 0, r: 0 }];\n    _updatePath();\n  }\n\n  function hide() {\n    element.classList.remove('shepherd-modal-is-visible');\n    _cleanupStepEventListeners();\n  }\n\n  function show() {\n    element.classList.add('shepherd-modal-is-visible');\n  }\n\n  function positionModal(\n    modalOverlayOpeningPadding = 0,\n    modalOverlayOpeningRadius: ModalRadiusType = 0,\n    modalOverlayOpeningXOffset = 0,\n    modalOverlayOpeningYOffset = 0,\n    scrollParent?: HTMLElement | null,\n    targetElement?: HTMLElement | null,\n    extraHighlights?: HTMLElement[]\n  ) {\n    if (targetElement) {\n      const elementsToHighlight = [targetElement, ...(extraHighlights || [])];\n      const newOpenings: OpeningProperty[] = [];\n\n      for (const el of elementsToHighlight) {\n        if (!el) continue;\n\n        // Skip duplicate elements\n        if (\n          elementsToHighlight.indexOf(el) !==\n          elementsToHighlight.lastIndexOf(el)\n        ) {\n          continue;\n        }\n\n        const { y, height } = _getVisibleHeight(el, scrollParent);\n        const { x, width, left } = el.getBoundingClientRect();\n\n        // Check if the element is contained by another element.\n        // Use _getVisibleHeight for otherElement too so both sides\n        // compare scroll-clipped geometry on the y-axis.\n        const isContained = elementsToHighlight.some((otherElement) => {\n          if (otherElement === el) return false;\n          const otherRect = otherElement.getBoundingClientRect();\n          const { y: otherY, height: otherHeight } = _getVisibleHeight(\n            otherElement,\n            scrollParent\n          );\n          return (\n            x >= otherRect.left &&\n            x + width <= otherRect.left + otherRect.width &&\n            y >= otherY &&\n            y + height <= otherY + otherHeight\n          );\n        });\n\n        if (isContained) continue;\n\n        newOpenings.push({\n          width: width + modalOverlayOpeningPadding * 2,\n          height: height + modalOverlayOpeningPadding * 2,\n          x:\n            (x || left) +\n            modalOverlayOpeningXOffset -\n            modalOverlayOpeningPadding,\n          y: y + modalOverlayOpeningYOffset - modalOverlayOpeningPadding,\n          r: modalOverlayOpeningRadius as OpeningProperty['r']\n        });\n      }\n\n      openingProperties = newOpenings;\n    } else {\n      closeModalOpening();\n      return;\n    }\n\n    _updatePath();\n  }\n\n  function setupForStep(step: Step) {\n    _cleanupStepEventListeners();\n\n    if (step.tour.options.useModalOverlay) {\n      _styleForStep(step);\n      show();\n    } else {\n      hide();\n    }\n  }\n\n  function destroy() {\n    _cleanupStepEventListeners();\n    element.removeEventListener('touchmove', _preventModalOverlayTouch);\n    element.remove();\n  }\n\n  function getElement() {\n    return element;\n  }\n\n  // --- Private helpers ---\n\n  function _preventModalOverlayTouch(e: Event) {\n    e.stopPropagation();\n  }\n\n  const _preventModalBodyTouch = (e: Event) => {\n    e.preventDefault();\n  };\n\n  function _addStepEventListeners() {\n    window.addEventListener('touchmove', _preventModalBodyTouch, {\n      passive: false\n    });\n  }\n\n  function _cleanupStepEventListeners() {\n    if (rafId) {\n      cancelAnimationFrame(rafId);\n      rafId = undefined;\n    }\n\n    window.removeEventListener('touchmove', _preventModalBodyTouch, {\n      passive: false\n    } as EventListenerOptions);\n  }\n\n  function _styleForStep(step: Step) {\n    const {\n      modalOverlayOpeningPadding,\n      modalOverlayOpeningRadius,\n      modalOverlayOpeningXOffset = 0,\n      modalOverlayOpeningYOffset = 0\n    } = step.options;\n\n    const iframeOffset = _getIframeOffset(step.target);\n    const scrollParent = _getScrollParent(step.target);\n\n    const rafLoop = () => {\n      rafId = undefined;\n      positionModal(\n        modalOverlayOpeningPadding,\n        modalOverlayOpeningRadius,\n        modalOverlayOpeningXOffset + iframeOffset.left,\n        modalOverlayOpeningYOffset + iframeOffset.top,\n        scrollParent,\n        step.target,\n        step._resolvedExtraHighlightElements\n      );\n      rafId = requestAnimationFrame(rafLoop);\n    };\n\n    rafLoop();\n    _addStepEventListeners();\n  }\n\n  function _getScrollParent(el?: HTMLElement | null): HTMLElement | null {\n    if (!el) return null;\n\n    const isHtmlElement = el instanceof HTMLElement;\n    const overflowY = isHtmlElement && window.getComputedStyle(el).overflowY;\n    const isScrollable = overflowY !== 'hidden' && overflowY !== 'visible';\n\n    if (isScrollable && el.scrollHeight >= el.clientHeight) {\n      return el;\n    }\n\n    return _getScrollParent(el.parentElement);\n  }\n\n  function _getIframeOffset(el?: HTMLElement | null) {\n    const offset = { top: 0, left: 0 };\n\n    if (!el) return offset;\n\n    let targetWindow: Window | null = el.ownerDocument.defaultView;\n\n    try {\n      while (targetWindow && targetWindow !== window.top) {\n        const targetIframe = targetWindow?.frameElement;\n\n        if (targetIframe) {\n          const rect = targetIframe.getBoundingClientRect();\n          offset.top += rect.top + targetIframe.scrollTop;\n          offset.left += rect.left + targetIframe.scrollLeft;\n        }\n\n        targetWindow = targetWindow.parent;\n      }\n    } catch {\n      // Cross-origin iframe — stop traversal and use the offset accumulated so far.\n    }\n\n    return offset;\n  }\n\n  function _getVisibleHeight(\n    el: HTMLElement,\n    scrollParent?: HTMLElement | null\n  ) {\n    const elementRect = el.getBoundingClientRect();\n    let top = elementRect.y || elementRect.top;\n    let bottom = elementRect.bottom || top + elementRect.height;\n\n    if (scrollParent) {\n      const scrollRect = scrollParent.getBoundingClientRect();\n      const scrollTop = scrollRect.y || scrollRect.top;\n      const scrollBottom = scrollRect.bottom || scrollTop + scrollRect.height;\n\n      top = Math.max(top, scrollTop);\n      bottom = Math.min(bottom, scrollBottom);\n    }\n\n    const height = Math.max(bottom - top, 0);\n    return { y: top, height };\n  }\n\n  return {\n    closeModalOpening,\n    destroy,\n    hide,\n    positionModal,\n    setupForStep,\n    show,\n    getElement\n  };\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-text.css",
    "content": ".shepherd-text {\n  color: rgba(0, 0, 0, 0.75);\n  font-size: 1rem;\n  line-height: 1.3em;\n  padding: 0.75em;\n}\n\n.shepherd-text p {\n  margin-top: 0;\n}\n\n.shepherd-text p:last-child {\n  margin-bottom: 0;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-text.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport { isHTMLElement, isFunction } from '../utils/type-check.ts';\nimport type { Step } from '../step.ts';\nimport './shepherd-text.css';\n\nexport function createShepherdText(\n  descriptionId: string,\n  step: Step\n): HTMLDivElement {\n  const el = h('div', {\n    class: 'shepherd-text',\n    id: descriptionId\n  }) as HTMLDivElement;\n\n  let text = step.options.text;\n\n  if (isFunction(text)) {\n    text = text.call(step);\n  }\n\n  if (isHTMLElement(text)) {\n    el.appendChild(text);\n  } else {\n    el.innerHTML = text as string;\n  }\n\n  return el;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-title.css",
    "content": ".shepherd-title {\n  color: rgba(0, 0, 0, 0.75);\n  display: flex;\n  font-size: 1rem;\n  font-weight: normal;\n  flex: 1 0 auto;\n  margin: 0;\n  padding: 0;\n}\n"
  },
  {
    "path": "shepherd.js/src/components/shepherd-title.ts",
    "content": "import { h } from '../utils/dom.ts';\nimport { isFunction } from '../utils/type-check.ts';\nimport type { StringOrStringFunction } from '../step.ts';\nimport './shepherd-title.css';\n\nexport function createShepherdTitle(\n  labelId: string,\n  title: StringOrStringFunction\n): HTMLHeadingElement {\n  const el = h('h3', {\n    id: labelId,\n    class: 'shepherd-title'\n  }) as HTMLHeadingElement;\n\n  const resolvedTitle = isFunction(title) ? title() : title;\n  el.innerHTML = resolvedTitle;\n\n  return el;\n}\n"
  },
  {
    "path": "shepherd.js/src/evented.ts",
    "content": "import { isUndefined } from './utils/type-check.ts';\n\nexport type Bindings = {\n  [key: string]: Array<{ handler: () => void; ctx?: unknown; once?: boolean }>;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyHandler = (...args: any[]) => void;\n\nexport class Evented {\n  declare bindings: Bindings;\n\n  /**\n   * Adds an event listener for the given event string.\n   *\n   * @param {string} event\n   * @param {Function} handler\n   * @param ctx\n   * @param {boolean} once\n   * @returns\n   */\n  on(event: string, handler: AnyHandler, ctx?: unknown, once = false) {\n    if (isUndefined(this.bindings)) {\n      this.bindings = {};\n    }\n    if (isUndefined(this.bindings[event])) {\n      this.bindings[event] = [];\n    }\n    this.bindings[event]?.push({ handler, ctx, once });\n\n    return this;\n  }\n\n  /**\n   * Adds an event listener that only fires once for the given event string.\n   *\n   * @param {string} event\n   * @param {Function} handler\n   * @param ctx\n   * @returns\n   */\n  once(event: string, handler: AnyHandler, ctx?: unknown) {\n    return this.on(event, handler, ctx, true);\n  }\n\n  /**\n   * Removes an event listener for the given event string.\n   *\n   * @param {string} event\n   * @param {Function} handler\n   * @returns\n   */\n  off(event: string, handler?: AnyHandler) {\n    if (isUndefined(this.bindings) || isUndefined(this.bindings[event])) {\n      return this;\n    }\n\n    if (isUndefined(handler)) {\n      delete this.bindings[event];\n    } else {\n      this.bindings[event]?.forEach((binding, index) => {\n        if (binding.handler === handler) {\n          this.bindings[event]?.splice(index, 1);\n        }\n      });\n    }\n\n    return this;\n  }\n\n  /**\n   * Triggers an event listener for the given event string.\n   *\n   * @param {string} event\n   * @returns\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  trigger(event: string, ...args: any[]) {\n    if (!isUndefined(this.bindings) && this.bindings[event]) {\n      this.bindings[event]?.forEach((binding, index) => {\n        const { ctx, handler, once } = binding;\n\n        const context = ctx || this;\n\n        handler.apply(context, args as []);\n\n        if (once) {\n          this.bindings[event]?.splice(index, 1);\n        }\n      });\n    }\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "shepherd.js/src/shepherd.ts",
    "content": "import { Shepherd, Tour } from './tour.ts';\nimport { StepNoOp, TourNoOp } from './utils/general.ts';\nimport { Step } from './step.ts';\n\nconst isServerSide = typeof window === 'undefined';\n\nShepherd.Step = (isServerSide ? StepNoOp : Step) as unknown as typeof Step;\nShepherd.Tour = (isServerSide ? TourNoOp : Tour) as unknown as typeof Tour;\n\nexport { ShepherdBase } from './tour.ts';\nexport default Shepherd;\n// Reexport types so they can be more easily used.\nexport type * from './evented.ts';\nexport type * from './step.ts';\nexport type * from './tour.ts';\n"
  },
  {
    "path": "shepherd.js/src/step.ts",
    "content": "import { deepmerge } from 'deepmerge-ts';\nimport { Evented } from './evented.ts';\nimport autoBind from './utils/auto-bind.ts';\nimport {\n  isElement,\n  isHTMLElement,\n  isFunction,\n  isUndefined\n} from './utils/type-check.ts';\nimport { bindAdvance } from './utils/bind.ts';\nimport {\n  parseAttachTo,\n  normalizePrefix,\n  uuid,\n  parseExtraHighlights\n} from './utils/general.ts';\nimport {\n  setupTooltip,\n  destroyTooltip,\n  mergeTooltipConfig\n} from './utils/floating-ui.ts';\nimport {\n  createShepherdElement,\n  type ShepherdElementResult\n} from './components/shepherd-element.ts';\nimport { type Tour } from './tour.ts';\nimport type { ComputePositionConfig } from '@floating-ui/dom';\n\nexport type StepText =\n  | string\n  | ReadonlyArray<string>\n  | HTMLElement\n  | (() => string | ReadonlyArray<string> | HTMLElement);\n\nexport type StringOrStringFunction = string | (() => string);\n\n/**\n * The options for the step\n */\nexport interface StepOptions {\n  /**\n   * The element the step should be attached to on the page.\n   * An object with properties `element` and `on`.\n   *\n   * ```js\n   * const step = new Step(tour, {\n   *   attachTo: { element: '.some .selector-path', on: 'left' },\n   *   ...moreOptions\n   * });\n   * ```\n   *\n   * If you don’t specify an attachTo the element will appear in the middle of the screen.\n   * If you omit the `on` portion of `attachTo`, the element will still be highlighted, but the tooltip will appear\n   * in the middle of the screen, without an arrow pointing to the target.\n   */\n  attachTo?: StepOptionsAttachTo;\n\n  /**\n   * An action on the page which should advance shepherd to the next step.\n   * It should be an object with a string `selector` and an `event` name\n   * ```js\n   * const step = new Step(tour, {\n   *   advanceOn: { selector: '.some .selector-path', event: 'click' },\n   *   ...moreOptions\n   * });\n   * ```\n   * `event` doesn’t have to be an event inside the tour, it can be any event fired on any element on the page.\n   * You can also always manually advance the Tour by calling `myTour.next()`.\n   */\n  advanceOn?: StepOptionsAdvanceOn;\n\n  /**\n   * Whether to display the arrow for the tooltip or not, or options for the arrow.\n   */\n  arrow?: boolean | StepOptionsArrow;\n\n  /**\n   * A function that returns a promise.\n   * When the promise resolves, the rest of the `show` code for the step will execute.\n   */\n  beforeShowPromise?: () => Promise<unknown>;\n\n  /**\n   * An array of buttons to add to the step. These will be rendered in a\n   * footer below the main body text.\n   */\n  buttons?: ReadonlyArray<StepOptionsButton>;\n\n  /**\n   * Should a cancel “✕” be shown in the header of the step?\n   */\n  cancelIcon?: StepOptionsCancelIcon;\n\n  /**\n   * A boolean, that when set to false, will set `pointer-events: none` on the target.\n   */\n  canClickTarget?: boolean;\n\n  /**\n   * A string of extra classes to add to the step's content element.\n   */\n  classes?: string;\n\n  /**\n   * An array of extra element selectors to highlight when the overlay is shown\n   * The tooltip won't be fixed to these elements, but they will be highlighted\n   * just like the `attachTo` element.\n   * ```js\n   * const step = new Step(tour, {\n   *   extraHighlights: [ '.pricing', '#docs' ],\n   *   ...moreOptions\n   * });\n   * ```\n   */\n  extraHighlights?: ReadonlyArray<string>;\n\n  /**\n   * An extra class to apply to the `attachTo` element when it is\n   * highlighted (that is, when its step is active). You can then target that selector in your CSS.\n   */\n  highlightClass?: string;\n\n  /**\n   * The string to use as the `id` for the step.\n   */\n  id?: string;\n\n  /**\n   * An amount of padding to add around the modal overlay opening\n   */\n  modalOverlayOpeningPadding?: number;\n\n  /**\n   * An amount of border radius to add around the modal overlay opening\n   */\n  modalOverlayOpeningRadius?:\n    | number\n    | {\n        topLeft?: number;\n        bottomLeft?: number;\n        bottomRight?: number;\n        topRight?: number;\n      };\n\n  /**\n   * An amount to offset the modal overlay opening in the x-direction\n   */\n  modalOverlayOpeningXOffset?: number;\n\n  /**\n   * An amount to offset the modal overlay opening in the y-direction\n   */\n  modalOverlayOpeningYOffset?: number;\n\n  /**\n   * Extra [options to pass to FloatingUI]{@link https://floating-ui.com/docs/tutorial/}\n   */\n  floatingUIOptions?: ComputePositionConfig;\n\n  /**\n   * Should the element be scrolled to when this step is shown?\n   */\n  scrollTo?: boolean | ScrollIntoViewOptions;\n\n  /**\n   * A function that lets you override the default scrollTo behavior and\n   * define a custom action to do the scrolling, and possibly other logic.\n   */\n  scrollToHandler?: (element: HTMLElement) => void;\n\n  /**\n   * A function that, when it returns `true`, will show the step.\n   * If it returns `false`, the step will be skipped.\n   */\n  showOn?: () => boolean;\n\n  /**\n   * The text in the body of the step. It can be one of four types:\n   * ```\n   * - HTML string\n   * - Array of HTML strings\n   * - `HTMLElement` object\n   * - `Function` to be executed when the step is built. It must return one of the three options above.\n   * ```\n   */\n  text?: StepText;\n\n  /**\n   * The step's title. It becomes an `h3` at the top of the step.\n   * ```\n   * - HTML string\n   * - `Function` to be executed when the step is built. It must return HTML string.\n   * ```\n   */\n  title?: StringOrStringFunction;\n\n  /**\n   * You can define `show`, `hide`, etc events inside `when`. For example:\n   * ```js\n   * when: {\n   *   show: function() {\n   *     window.scrollTo(0, 0);\n   *   }\n   * }\n   * ```\n   */\n  when?: StepOptionsWhen;\n}\n\nexport type PopperPlacement =\n  | 'auto'\n  | 'auto-start'\n  | 'auto-end'\n  | 'top'\n  | 'top-start'\n  | 'top-end'\n  | 'bottom'\n  | 'bottom-start'\n  | 'bottom-end'\n  | 'right'\n  | 'right-start'\n  | 'right-end'\n  | 'left'\n  | 'left-start'\n  | 'left-end';\n\nexport interface StepOptionsArrow {\n  /*\n   * The padding from the edge for the arrow.\n   * Not used if this is not a -start or -end placement.\n   */\n  padding?: number;\n}\n\nexport interface StepOptionsAttachTo {\n  element?:\n    | HTMLElement\n    | string\n    | null\n    | (() => HTMLElement | string | null | undefined);\n  on?: PopperPlacement;\n}\n\nexport interface StepOptionsAdvanceOn {\n  event: string;\n  selector: string;\n}\n\nexport interface StepOptionsButton {\n  /**\n   * A function executed when the button is clicked on\n   * It is automatically bound to the `tour` the step is associated with, so things like `this.next` will\n   * work inside the action.\n   * You can use action to skip steps or navigate to specific steps, with something like:\n   * ```js\n   * action() {\n   *   return this.show('some_step_name');\n   * }\n   * ```\n   */\n  action?: (this: Tour) => void;\n\n  /**\n   * Additional HTML attributes to apply to the button element.\n   *\n   * This is useful for adding data attributes for testing or analytics,\n   * or other custom attributes that don't have dedicated properties.\n   *\n   * Note: These attributes are applied before Shepherd's core attributes,\n   * so they cannot override critical properties like `type`, `onclick`,\n   * `class`, `disabled`, `aria-label`, or `tabindex`. Use the dedicated\n   * properties (`classes`, `disabled`, `label`, `action`) to control those.\n   *\n   * @example\n   * ```js\n   * {\n   *   text: 'Next',\n   *   action: tour.next,\n   *   attrs: {\n   *     'data-test': 'next-button',\n   *     'data-analytics-id': 'tour-next',\n   *     'title': 'Proceed to the next step'\n   *   }\n   * }\n   * ```\n   */\n  attrs?: Record<string, string | number | boolean>;\n\n  /**\n   * Extra classes to apply to the `<a>`\n   */\n  classes?: string;\n\n  /**\n   * Whether the button should be disabled\n   * When the value is `true`, or the function returns `true` the button will be disabled\n   */\n  disabled?: boolean | (() => boolean);\n\n  /**\n   * The aria-label text of the button\n   */\n  label?: StringOrStringFunction;\n\n  /**\n   * A boolean, that when true, adds a `shepherd-button-secondary` class to the button.\n   */\n  secondary?: boolean;\n\n  /**\n   * The HTML text of the button\n   */\n  text?: StringOrStringFunction;\n}\n\nexport interface StepOptionsButtonEvent {\n  [key: string]: () => void;\n}\n\nexport interface StepOptionsCancelIcon {\n  /**\n   * Additional HTML attributes to apply to the cancel icon button element.\n   *\n   * This is useful for adding data attributes for testing or analytics,\n   * or other custom attributes that don't have dedicated properties.\n   *\n   * Note: These attributes are applied before Shepherd's core attributes,\n   * so they cannot override critical properties like `type`, `onclick`,\n   * `class`, or `aria-label`. Use the dedicated `label` property to\n   * control the aria-label.\n   *\n   * @example\n   * ```js\n   * cancelIcon: {\n   *   enabled: true,\n   *   label: 'Close Tour',\n   *   attrs: {\n   *     'data-test': 'close-tour-button',\n   *     'data-analytics-id': 'tour-close'\n   *   }\n   * }\n   * ```\n   */\n  attrs?: Record<string, string | number | boolean>;\n  /**\n   * Should a cancel \"✕\" be shown in the header of the step?\n   */\n  enabled?: boolean;\n  /**\n   * The label to add for `aria-label`\n   */\n  label?: string;\n}\n\nexport interface StepOptionsWhen {\n  [key: string]: (this: Step) => void;\n}\n\n/**\n * A class representing steps to be added to a tour.\n * @extends {Evented}\n */\nexport class Step extends Evented {\n  _resolvedAttachTo: StepOptionsAttachTo | null;\n  _resolvedExtraHighlightElements?: HTMLElement[];\n  _originalTabIndexes: Map<Element, string>;\n  classPrefix?: string;\n  declare cleanup: Function | null;\n  el?: HTMLElement | null;\n  declare id: string;\n  declare options: StepOptions;\n  shepherdElementComponent?: ShepherdElementResult;\n  target?: HTMLElement | null;\n  tour: Tour;\n\n  constructor(tour: Tour, options: StepOptions = {}) {\n    super();\n\n    this.tour = tour;\n    this.classPrefix = this.tour.options\n      ? normalizePrefix(this.tour.options.classPrefix)\n      : '';\n    // @ts-expect-error TODO: investigate where styles comes from\n    this.styles = tour.styles;\n\n    /**\n     * Resolved attachTo options. Due to lazy evaluation, we only resolve the options during `before-show` phase.\n     * Do not use this directly, use the _getResolvedAttachToOptions method instead.\n     * @type {StepOptionsAttachTo | null}\n     * @private\n     */\n    this._resolvedAttachTo = null;\n\n    /**\n     * Map to store original tabIndex values of elements that are modified during the tour.\n     * @type {Map<Element, string | null>}\n     * @private\n     */\n    this._originalTabIndexes = new Map();\n\n    autoBind(this);\n\n    this._setOptions(options);\n\n    return this;\n  }\n\n  /**\n   * Cancel the tour\n   * Triggers the `cancel` event\n   */\n  cancel() {\n    this.tour.cancel();\n    this.trigger('cancel');\n  }\n\n  /**\n   * Complete the tour\n   * Triggers the `complete` event\n   */\n  complete() {\n    this.tour.complete();\n    this.trigger('complete');\n  }\n\n  /**\n   * Remove the step, delete the step's element, and destroy the FloatingUI instance for the step.\n   * Triggers `destroy` event\n   */\n  destroy() {\n    this._teardownElements();\n    this.trigger('destroy');\n  }\n\n  /**\n   * Internal cleanup that tears down the tooltip, component, and DOM element\n   * without emitting the public \"destroy\" event.\n   * @private\n   */\n  _teardownElements() {\n    destroyTooltip(this);\n\n    if (this.shepherdElementComponent) {\n      this.shepherdElementComponent.cleanup();\n      this.shepherdElementComponent = undefined;\n    }\n\n    if (isHTMLElement(this.el)) {\n      this.el.remove();\n      this.el = null;\n    }\n\n    this._updateStepTargetOnHide();\n    this._originalTabIndexes.clear();\n  }\n\n  /**\n   * Returns the tour for the step\n   * @return The tour instance\n   */\n  getTour() {\n    return this.tour;\n  }\n\n  /**\n   * Hide the step\n   */\n  hide() {\n    this.tour.modal?.hide();\n\n    this.trigger('before-hide');\n\n    if (this.el) {\n      this.el.hidden = true;\n    }\n\n    this._updateStepTargetOnHide();\n\n    this.trigger('hide');\n  }\n\n  /**\n   * Resolves attachTo options.\n   * @returns {{}|{element, on}}\n   */\n  _resolveExtraHiglightElements() {\n    this._resolvedExtraHighlightElements = parseExtraHighlights(this);\n    return this._resolvedExtraHighlightElements;\n  }\n\n  /**\n   * Resolves attachTo options.\n   * @returns {{}|{element, on}}\n   */\n  _resolveAttachToOptions() {\n    this._resolvedAttachTo = parseAttachTo(this);\n    return this._resolvedAttachTo;\n  }\n\n  /**\n   * A selector for resolved attachTo options.\n   * @returns {{}|{element, on}}\n   * @private\n   */\n  _getResolvedAttachToOptions() {\n    if (this._resolvedAttachTo === null) {\n      return this._resolveAttachToOptions();\n    }\n\n    return this._resolvedAttachTo;\n  }\n\n  /**\n   * Check if the step is open and visible\n   * @return True if the step is open and visible\n   */\n  isOpen() {\n    return Boolean(this.el && !this.el.hidden);\n  }\n\n  /**\n   * Wraps `_show` and ensures `beforeShowPromise` resolves before calling show\n   */\n  show() {\n    if (isFunction(this.options.beforeShowPromise)) {\n      return Promise.resolve(this.options.beforeShowPromise()).then(() =>\n        this._show()\n      );\n    }\n    return Promise.resolve(this._show());\n  }\n\n  /**\n   * Updates the options of the step.\n   *\n   * @param {StepOptions} options The options for the step\n   */\n  updateStepOptions(options: StepOptions) {\n    Object.assign(this.options, options);\n\n    if (this.shepherdElementComponent) {\n      // Recreate the element with updated options\n      if (this.el) {\n        this._teardownElements();\n        this._setupElements();\n      }\n    }\n  }\n\n  /**\n   * Returns the element for the step\n   * @return {HTMLElement|null|undefined} The element instance. undefined if it has never been shown, null if it has been destroyed\n   */\n  getElement() {\n    return this.el;\n  }\n\n  /**\n   * Returns the target for the step\n   * @return {HTMLElement|null|undefined} The element instance. undefined if it has never been shown, null if query string has not been found\n   */\n  getTarget() {\n    return this.target;\n  }\n\n  /**\n   * Stores the original tabIndex value of an element before modifying it.\n   * Only stores the value if the element has a tabindex attribute.\n   * @param {Element} element The element whose tabIndex will be stored\n   * @private\n   */\n  _storeOriginalTabIndex(element: Element): void {\n    const originalValue = element.getAttribute('tabindex');\n    if (originalValue !== null) {\n      this._originalTabIndexes.set(element, originalValue);\n    }\n  }\n\n  /**\n   * Restores the original tabIndex values for all elements that were modified during the tour.\n   * If an element is in the map, restores its original value.\n   * If an element is not in the map, removes the tabindex attribute (it didn't have one originally).\n   * Note: Does not clear the map to allow for multiple show/hide cycles.\n   * @private\n   */\n  _restoreOriginalTabIndexes(): void {\n    const target = this.target;\n    if (target) {\n      if (this._originalTabIndexes.has(target)) {\n        target.setAttribute('tabindex', this._originalTabIndexes.get(target)!);\n      } else {\n        target.removeAttribute('tabindex');\n      }\n    }\n  }\n\n  /**\n   * Creates Shepherd element for step based on options\n   *\n   * @return {HTMLElement} The DOM element for the step tooltip\n   * @private\n   */\n  _createTooltipContent() {\n    const descriptionId = `${this.id}-description`;\n    const labelId = `${this.id}-label`;\n\n    this.shepherdElementComponent = createShepherdElement({\n      classPrefix: this.classPrefix,\n      descriptionId,\n      labelId,\n      step: this\n    });\n\n    const target = this.tour.options.stepsContainer || document.body;\n    target.append(this.shepherdElementComponent.element);\n\n    return this.shepherdElementComponent.element;\n  }\n\n  /**\n   * If a custom scrollToHandler is defined, call that, otherwise do the generic\n   * scrollIntoView call.\n   *\n   * @param {boolean | ScrollIntoViewOptions} scrollToOptions - If true, uses the default `scrollIntoView`,\n   * if an object, passes that object as the params to `scrollIntoView` i.e. `{ behavior: 'smooth', block: 'center' }`\n   * @private\n   */\n  _scrollTo(scrollToOptions: boolean | ScrollIntoViewOptions) {\n    const { element } = this._getResolvedAttachToOptions();\n\n    if (isFunction(this.options.scrollToHandler)) {\n      this.options.scrollToHandler(element as HTMLElement);\n    } else if (\n      isElement(element) &&\n      typeof element.scrollIntoView === 'function'\n    ) {\n      element.scrollIntoView(scrollToOptions);\n    }\n  }\n\n  /**\n   * _getClassOptions gets all possible classes for the step\n   * @param {StepOptions} stepOptions The step specific options\n   * @returns {string} unique string from array of classes\n   */\n  _getClassOptions(stepOptions: StepOptions) {\n    const defaultStepOptions =\n      this.tour && this.tour.options && this.tour.options.defaultStepOptions;\n    const stepClasses = stepOptions.classes ? stepOptions.classes : '';\n    const defaultStepOptionsClasses =\n      defaultStepOptions && defaultStepOptions.classes\n        ? defaultStepOptions.classes\n        : '';\n    const allClasses = [\n      ...stepClasses.split(' '),\n      ...defaultStepOptionsClasses.split(' ')\n    ];\n    const uniqClasses = new Set(allClasses);\n\n    return Array.from(uniqClasses).join(' ').trim();\n  }\n\n  /**\n   * Sets the options for the step, maps `when` to events, sets up buttons\n   * @param options - The options for the step\n   */\n  _setOptions(options: StepOptions = {}) {\n    let tourOptions =\n      this.tour && this.tour.options && this.tour.options.defaultStepOptions;\n\n    tourOptions = deepmerge({}, tourOptions || {});\n\n    this.options = Object.assign(\n      {\n        arrow: true\n      },\n      tourOptions,\n      options,\n      mergeTooltipConfig(tourOptions, options)\n    );\n\n    const { when } = this.options;\n\n    this.options.classes = this._getClassOptions(options);\n\n    this.destroy();\n    this.id = this.options.id || `step-${uuid()}`;\n\n    if (when) {\n      Object.keys(when).forEach((event) => {\n        // @ts-expect-error TODO: fix this type error\n        this.on(event, when[event], this);\n      });\n    }\n  }\n\n  /**\n   * Create the element and set up the FloatingUI instance\n   * @private\n   */\n  _setupElements() {\n    if (!isUndefined(this.el)) {\n      this.destroy();\n    }\n\n    this.el = this._createTooltipContent();\n\n    if (this.options.advanceOn) {\n      bindAdvance(this);\n    }\n\n    // The tooltip implementation details are handled outside of the Step\n    // object.\n    setupTooltip(this);\n  }\n\n  /**\n   * Triggers `before-show`, generates the tooltip DOM content,\n   * sets up a FloatingUI instance for the tooltip, then triggers `show`.\n   * @private\n   */\n  _show() {\n    this.trigger('before-show');\n\n    // Force resolve to make sure the options are updated on subsequent shows.\n    this._resolveAttachToOptions();\n    this._resolveExtraHiglightElements();\n    this._setupElements();\n\n    if (!this.tour.modal) {\n      this.tour.setupModal();\n    }\n\n    this.tour.modal?.setupForStep(this);\n    this._styleTargetElementForStep(this);\n\n    if (this.el) {\n      this.el.hidden = false;\n    }\n\n    // start scrolling to target before showing the step\n    if (this.options.scrollTo) {\n      setTimeout(() => {\n        this._scrollTo(\n          this.options.scrollTo as boolean | ScrollIntoViewOptions\n        );\n      });\n    }\n\n    if (this.el) {\n      this.el.hidden = false;\n    }\n\n    const content = this.shepherdElementComponent!.element;\n    const target = this.target || document.body;\n    const extraHighlightElements = this._resolvedExtraHighlightElements;\n\n    target.classList.add(`${this.classPrefix}shepherd-enabled`);\n    target.classList.add(`${this.classPrefix}shepherd-target`);\n    content.classList.add('shepherd-enabled');\n\n    extraHighlightElements?.forEach((el) => {\n      el.classList.add(`${this.classPrefix}shepherd-enabled`);\n      el.classList.add(`${this.classPrefix}shepherd-target`);\n    });\n\n    this.trigger('show');\n  }\n\n  /**\n   * Modulates the styles of the passed step's target element, based on the step's options and\n   * the tour's `modal` option, to visually emphasize the element\n   *\n   * @param {Step} step The step object that attaches to the element\n   * @private\n   */\n  _styleTargetElementForStep(step: Step) {\n    const targetElement = step.target;\n    const extraHighlightElements = step._resolvedExtraHighlightElements;\n\n    if (!targetElement) {\n      return;\n    }\n\n    const highlightClass = step.options.highlightClass;\n    if (highlightClass) {\n      targetElement.classList.add(highlightClass);\n      extraHighlightElements?.forEach((el) => el.classList.add(highlightClass));\n    }\n\n    targetElement.classList.remove('shepherd-target-click-disabled');\n    extraHighlightElements?.forEach((el) =>\n      el.classList.remove('shepherd-target-click-disabled')\n    );\n\n    if (step.options.canClickTarget === false) {\n      targetElement.classList.add('shepherd-target-click-disabled');\n      extraHighlightElements?.forEach((el) =>\n        el.classList.add('shepherd-target-click-disabled')\n      );\n    }\n  }\n\n  /**\n   * When a step is hidden, remove the highlightClass and 'shepherd-enabled'\n   * and 'shepherd-target' classes\n   * @private\n   */\n  _updateStepTargetOnHide() {\n    const target = this.target || document.body;\n    const extraHighlightElements = this._resolvedExtraHighlightElements;\n\n    const highlightClass = this.options.highlightClass;\n    if (highlightClass) {\n      target.classList.remove(highlightClass);\n      extraHighlightElements?.forEach((el) =>\n        el.classList.remove(highlightClass)\n      );\n    }\n\n    target.classList.remove(\n      'shepherd-target-click-disabled',\n      `${this.classPrefix}shepherd-enabled`,\n      `${this.classPrefix}shepherd-target`\n    );\n    extraHighlightElements?.forEach((el) => {\n      el.classList.remove(\n        'shepherd-target-click-disabled',\n        `${this.classPrefix}shepherd-enabled`,\n        `${this.classPrefix}shepherd-target`\n      );\n    });\n\n    this._restoreOriginalTabIndexes();\n  }\n}\n"
  },
  {
    "path": "shepherd.js/src/tour.ts",
    "content": "import { Evented } from './evented.ts';\nimport { Step, type StepOptions } from './step.ts';\nimport autoBind from './utils/auto-bind.ts';\nimport {\n  isHTMLElement,\n  isFunction,\n  isString,\n  isUndefined\n} from './utils/type-check.ts';\nimport { cleanupSteps } from './utils/cleanup.ts';\nimport { normalizePrefix, uuid } from './utils/general.ts';\nimport {\n  createShepherdModal,\n  type ShepherdModalAPI\n} from './components/shepherd-modal.ts';\n\nexport interface EventOptions {\n  previous?: Step | null;\n  step?: Step | null;\n  tour: Tour;\n}\n\nexport type TourConfirmCancel =\n  | boolean\n  | (() => boolean)\n  | Promise<boolean>\n  | (() => Promise<boolean>);\n\n/**\n * The options for the tour\n */\nexport interface TourOptions {\n  /**\n   * If true, will issue a `window.confirm` before cancelling.\n   * If it is a function(support Async Function), it will be called and wait for the return value,\n   * and will only be cancelled if the value returned is true.\n   */\n  confirmCancel?: TourConfirmCancel;\n  /**\n   * The message to display in the `window.confirm` dialog.\n   */\n  confirmCancelMessage?: string;\n  /**\n   * The prefix to add to the `shepherd-enabled` and `shepherd-target` class names as well as the `data-shepherd-step-id`.\n   */\n  classPrefix?: string;\n  /**\n   * Default options for Steps ({@link Step#constructor}), created through `addStep`.\n   */\n  defaultStepOptions?: StepOptions;\n  /**\n   * Exiting the tour with the escape key will be enabled unless this is explicitly\n   * set to false.\n   */\n  exitOnEsc?: boolean;\n  /**\n   * Explicitly set the id for the tour. If not set, the id will be a generated uuid.\n   */\n  id?: string;\n  /**\n   * Navigating the tour via left and right arrow keys will be enabled\n   * unless this is explicitly set to false.\n   */\n  keyboardNavigation?: boolean;\n  /**\n   * An optional container element for the modal.\n   * If not set, the modal will be appended to `document.body`.\n   */\n  modalContainer?: HTMLElement;\n  /**\n   * An optional container element for the steps.\n   * If not set, the steps will be appended to `document.body`.\n   */\n  stepsContainer?: HTMLElement;\n  /**\n   * An array of step options objects or Step instances to initialize the tour with.\n   */\n  steps?: Array<StepOptions> | Array<Step>;\n  /**\n   * An optional \"name\" for the tour. This will be appended to the the tour's\n   * dynamically generated `id` property.\n   */\n  tourName?: string;\n  /**\n   * Whether or not steps should be placed above a darkened\n   * modal overlay. If true, the overlay will create an opening around the target element so that it\n   * can remain interactive\n   */\n  useModalOverlay?: boolean;\n}\n\nexport class ShepherdBase extends Evented {\n  activeTour?: Tour | null;\n  declare Step: typeof Step;\n  declare Tour: typeof Tour;\n\n  constructor() {\n    super();\n\n    autoBind(this);\n  }\n}\n\n/**\n * Class representing the site tour\n * @extends {Evented}\n */\nexport class Tour extends Evented {\n  trackedEvents = ['active', 'cancel', 'complete', 'show'];\n\n  classPrefix: string;\n  currentStep?: Step | null;\n  focusedElBeforeOpen?: HTMLElement | null;\n  id?: string;\n  modal?: ShepherdModalAPI | null;\n  options: TourOptions;\n  steps: Array<Step>;\n\n  constructor(options: TourOptions = {}) {\n    super();\n\n    autoBind(this);\n\n    const defaultTourOptions = {\n      exitOnEsc: true,\n      keyboardNavigation: true\n    };\n\n    this.options = Object.assign({}, defaultTourOptions, options);\n    this.classPrefix = normalizePrefix(this.options.classPrefix);\n    this.steps = [];\n    this.addSteps(this.options.steps);\n\n    // Pass these events onto the global Shepherd object\n    const events = [\n      'active',\n      'cancel',\n      'complete',\n      'inactive',\n      'show',\n      'start'\n    ];\n    events.map((event) => {\n      ((e) => {\n        this.on(e, (opts?: { [key: string]: unknown }) => {\n          opts = opts || {};\n          opts['tour'] = this;\n          Shepherd.trigger(e, opts);\n        });\n      })(event);\n    });\n\n    this._setTourID(options.id);\n\n    return this;\n  }\n\n  /**\n   * Adds a new step to the tour\n   * @param {StepOptions} options - An object containing step options or a Step instance\n   * @param {number | undefined} index - The optional index to insert the step at. If undefined, the step\n   * is added to the end of the array.\n   * @return The newly added step\n   */\n  addStep(options: StepOptions | Step, index?: number) {\n    let step = options;\n\n    if (!(step instanceof Step)) {\n      step = new Step(this, step);\n    } else {\n      step.tour = this;\n    }\n\n    if (!isUndefined(index)) {\n      this.steps.splice(index, 0, step as Step);\n    } else {\n      this.steps.push(step as Step);\n    }\n\n    return step;\n  }\n\n  /**\n   * Add multiple steps to the tour\n   * @param {Array<StepOptions> | Array<Step> | undefined} steps - The steps to add to the tour\n   */\n  addSteps(steps?: Array<StepOptions> | Array<Step>) {\n    if (Array.isArray(steps)) {\n      steps.forEach((step) => {\n        this.addStep(step);\n      });\n    }\n\n    return this;\n  }\n\n  /**\n   * Go to the previous step in the tour\n   */\n  back() {\n    const index = this.steps.indexOf(this.currentStep as Step);\n    this.show(index - 1, false);\n  }\n\n  /**\n   * Calls _done() triggering the 'cancel' event\n   * If `confirmCancel` is true, will show a window.confirm before cancelling\n   * If `confirmCancel` is a function, will call it and wait for the return value,\n   * and only cancel when the value returned is true\n   */\n  async cancel() {\n    if (this.options.confirmCancel) {\n      const cancelMessage =\n        this.options.confirmCancelMessage ||\n        'Are you sure you want to stop the tour?';\n      let stopTour;\n\n      if (isFunction(this.options.confirmCancel)) {\n        stopTour = await this.options.confirmCancel();\n      } else {\n        stopTour = window.confirm(cancelMessage);\n      }\n\n      if (stopTour) {\n        this._done('cancel');\n      }\n    } else {\n      this._done('cancel');\n    }\n  }\n\n  /**\n   * Calls _done() triggering the `complete` event\n   */\n  complete() {\n    this._done('complete');\n  }\n\n  /**\n   * Gets the step from a given id\n   * @param {number | string} id - The id of the step to retrieve\n   * @return The step corresponding to the `id`\n   */\n  getById(id: number | string) {\n    return this.steps.find((step) => {\n      return step.id === id;\n    });\n  }\n\n  /**\n   * Gets the current step\n   */\n  getCurrentStep() {\n    return this.currentStep;\n  }\n\n  /**\n   * Hide the current step\n   */\n  hide() {\n    const currentStep = this.getCurrentStep();\n\n    if (currentStep) {\n      return currentStep.hide();\n    }\n  }\n\n  /**\n   * Check if the tour is active\n   */\n  isActive() {\n    return Shepherd.activeTour === this;\n  }\n\n  /**\n   * Go to the next step in the tour\n   * If we are at the end, call `complete`\n   */\n  next() {\n    const index = this.steps.indexOf(this.currentStep as Step);\n\n    if (index === this.steps.length - 1) {\n      this.complete();\n    } else {\n      this.show(index + 1, true);\n    }\n  }\n\n  /**\n   * Removes the step from the tour\n   * @param {string} name - The id for the step to remove\n   */\n  removeStep(name: string) {\n    const current = this.getCurrentStep();\n\n    // Find the step, destroy it and remove it from this.steps\n    this.steps.some((step, i) => {\n      if (step.id === name) {\n        if (step.isOpen()) {\n          step.hide();\n        }\n\n        step.destroy();\n        this.steps.splice(i, 1);\n\n        return true;\n      }\n    });\n\n    if (current && current.id === name) {\n      this.currentStep = undefined;\n\n      // If we have steps left, show the first one, otherwise just cancel the tour\n      this.steps.length ? this.show(0) : this.cancel();\n    }\n  }\n\n  /**\n   * Show a specific step in the tour\n   * @param {number | string} key - The key to look up the step by\n   * @param {boolean} forward - True if we are going forward, false if backward\n   */\n  show(key: number | string = 0, forward = true) {\n    const step = isString(key) ? this.getById(key) : this.steps[key];\n\n    if (step) {\n      this._updateStateBeforeShow();\n\n      const shouldSkipStep =\n        isFunction(step.options.showOn) && !step.options.showOn();\n\n      // If `showOn` returns false, we want to skip the step, otherwise, show the step like normal\n      if (shouldSkipStep) {\n        this._skipStep(step, forward);\n      } else {\n        this.currentStep = step;\n        this.trigger('show', {\n          step,\n          previous: this.currentStep\n        });\n\n        step.show();\n      }\n    }\n  }\n\n  /**\n   * Start the tour\n   */\n  async start() {\n    this.trigger('start');\n\n    // Save the focused element before the tour opens\n    this.focusedElBeforeOpen = document.activeElement as HTMLElement | null;\n\n    this.currentStep = null;\n\n    this.setupModal();\n\n    this._setupActiveTour();\n    this.next();\n  }\n\n  /**\n   * Called whenever the tour is cancelled or completed, basically anytime we exit the tour\n   * @param {string} event - The event name to trigger\n   * @private\n   */\n  _done(event: string) {\n    const index = this.steps.indexOf(this.currentStep as Step);\n    if (Array.isArray(this.steps)) {\n      this.steps.forEach((step) => step.destroy());\n    }\n\n    cleanupSteps(this);\n\n    this.trigger(event, { index });\n\n    Shepherd.activeTour = null;\n    this.trigger('inactive', { tour: this });\n\n    if (this.modal) {\n      this.modal.hide();\n    }\n\n    if (event === 'cancel' || event === 'complete') {\n      if (this.modal) {\n        this.modal.destroy();\n        this.modal = null;\n      }\n    }\n\n    // Focus the element that was focused before the tour started\n    if (isHTMLElement(this.focusedElBeforeOpen)) {\n      this.focusedElBeforeOpen.focus();\n    }\n  }\n\n  /**\n   * Make this tour \"active\"\n   */\n  _setupActiveTour() {\n    this.trigger('active', { tour: this });\n\n    Shepherd.activeTour = this;\n  }\n\n  /**\n   * setupModal create the modal container and instance\n   */\n  setupModal() {\n    const container = this.options.modalContainer || document.body;\n    this.modal = createShepherdModal(container);\n  }\n\n  /**\n   * Called when `showOn` evaluates to false, to skip the step or complete/cancel the tour if there are no more steps\n   * @param {Step} step - The step to skip\n   * @param {boolean} forward - True if we are going forward, false if backward\n   * @private\n   */\n  _skipStep(step: Step, forward: boolean) {\n    const index = this.steps.indexOf(step);\n    const nextIndex = forward ? index + 1 : index - 1;\n\n    if (nextIndex < 0) {\n      this.cancel();\n    } else if (nextIndex >= this.steps.length) {\n      this.complete();\n    } else {\n      this.show(nextIndex, forward);\n    }\n  }\n\n  /**\n   * Before showing, hide the current step and if the tour is not\n   * already active, call `this._setupActiveTour`.\n   * @private\n   */\n  _updateStateBeforeShow() {\n    if (this.currentStep) {\n      this.currentStep.hide();\n    }\n\n    if (!this.isActive()) {\n      this._setupActiveTour();\n    }\n  }\n\n  /**\n   * Sets this.id to a provided tourName and id or `${tourName}--${uuid}`\n   * @param {string} optionsId - True if we are going forward, false if backward\n   * @private\n   */\n  _setTourID(optionsId: string | undefined) {\n    const tourName = this.options.tourName || 'tour';\n    const tourId = optionsId || uuid();\n\n    this.id = `${tourName}--${tourId}`;\n  }\n}\n\n/**\n * @public\n */\nconst Shepherd = new ShepherdBase();\n\nexport { Shepherd };\n"
  },
  {
    "path": "shepherd.js/src/utils/auto-bind.ts",
    "content": "/**\n * Binds all the methods on a JS Class to the `this` context of the class.\n * Adapted from https://github.com/sindresorhus/auto-bind\n * @param self The `this` context of the class\n * @return The `this` context of the class\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default function autoBind(self: any) {\n  const keys = Object.getOwnPropertyNames(self.constructor.prototype);\n  for (let i = 0; i < keys.length; i++) {\n    const key = keys[i] as keyof typeof self;\n    const val = self[key];\n    if (key !== 'constructor' && typeof val === 'function') {\n      self[key] = val.bind(self);\n    }\n  }\n\n  return self;\n}\n"
  },
  {
    "path": "shepherd.js/src/utils/bind.ts",
    "content": "import type { Step } from '../step.ts';\nimport { isUndefined } from './type-check.ts';\n\n/**\n * Sets up the handler to determine if we should advance the tour\n * @param step The step instance\n * @param selector\n * @private\n */\nfunction _setupAdvanceOnHandler(step: Step, selector?: string) {\n  return (event: Event) => {\n    if (step.isOpen()) {\n      const targetIsEl = step.el && event.currentTarget === step.el;\n      const targetIsSelector =\n        !isUndefined(selector) &&\n        (event.currentTarget as HTMLElement).matches(selector);\n\n      if (targetIsSelector || targetIsEl) {\n        step.tour.next();\n      }\n    }\n  };\n}\n\n/**\n * Bind the event handler for advanceOn\n * @param step The step instance\n */\nexport function bindAdvance(step: Step) {\n  // An empty selector matches the step element\n  const { event, selector } = step.options.advanceOn || {};\n  if (event) {\n    const handler = _setupAdvanceOnHandler(step, selector);\n\n    // TODO: this should also bind/unbind on show/hide\n    let el: Element | null = null;\n\n    if (!isUndefined(selector)) {\n      el = document.querySelector(selector);\n\n      if (!el) {\n        return console.error(\n          `No element was found for the selector supplied to advanceOn: ${selector}`\n        );\n      }\n    }\n\n    if (el) {\n      el.addEventListener(event, handler);\n      step.on('destroy', () => {\n        return (el as HTMLElement).removeEventListener(event, handler);\n      });\n    } else {\n      document.body.addEventListener(event, handler, true);\n      step.on('destroy', () => {\n        return document.body.removeEventListener(event, handler, true);\n      });\n    }\n  } else {\n    return console.error(\n      'advanceOn was defined, but no event name was passed.'\n    );\n  }\n}\n"
  },
  {
    "path": "shepherd.js/src/utils/cleanup.ts",
    "content": "import type { Tour } from '../tour.ts';\nimport { isHTMLElement } from './type-check.ts';\n\n/**\n * Cleanup the steps and set pointerEvents back to 'auto'\n * @param tour The tour object\n */\nexport function cleanupSteps(tour: Tour) {\n  if (tour) {\n    const { steps } = tour;\n\n    steps.forEach((step) => {\n      if (\n        step.options &&\n        step.options.canClickTarget === false &&\n        step.options.attachTo\n      ) {\n        if (isHTMLElement(step.target)) {\n          step.target.classList.remove('shepherd-target-click-disabled');\n        }\n\n        if (step._resolvedExtraHighlightElements) {\n          step._resolvedExtraHighlightElements.forEach((element) => {\n            if (isHTMLElement(element)) {\n              element.classList.remove('shepherd-target-click-disabled');\n            }\n          });\n        }\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "shepherd.js/src/utils/dom.ts",
    "content": "type Attrs = Record<string, unknown>;\ntype Child = Node | string | null | undefined | false;\n\n/**\n * Create an HTML element with attributes and children.\n * Attributes starting with \"on\" are added as event listeners.\n * Null/undefined/false attribute values are skipped.\n */\nexport function h(\n  tag: string,\n  attrs?: Attrs | null,\n  ...children: Child[]\n): HTMLElement {\n  const el = document.createElement(tag);\n  applyAttrs(el, attrs);\n  appendChildren(el, children);\n  return el;\n}\n\n/**\n * Create an SVG element with attributes and children.\n */\nexport function svgEl(\n  tag: string,\n  attrs?: Attrs | null,\n  ...children: Child[]\n): SVGElement {\n  const el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n  applyAttrs(el, attrs);\n  appendChildren(el, children);\n  return el;\n}\n\nfunction applyAttrs(el: Element, attrs?: Attrs | null) {\n  if (!attrs) return;\n\n  for (const [key, value] of Object.entries(attrs)) {\n    if (value === null || value === undefined || value === false) continue;\n\n    if (key.startsWith('on') && typeof value === 'function') {\n      el.addEventListener(key.slice(2).toLowerCase(), value as EventListener);\n    } else if (key === 'disabled' && value === true) {\n      (el as HTMLButtonElement).disabled = true;\n    } else {\n      el.setAttribute(key, String(value));\n    }\n  }\n}\n\nfunction appendChildren(el: Element, children: Child[]) {\n  for (const child of children) {\n    if (child != null && child !== false) {\n      el.append(\n        typeof child === 'string' ? document.createTextNode(child) : child\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "shepherd.js/src/utils/floating-ui.ts",
    "content": "import { deepmerge } from 'deepmerge-ts';\nimport { shouldCenterStep } from './general.ts';\nimport {\n  autoUpdate,\n  arrow,\n  computePosition,\n  flip,\n  autoPlacement,\n  limitShift,\n  shift,\n  type ComputePositionConfig,\n  type MiddlewareData,\n  type Placement,\n  type Alignment\n} from '@floating-ui/dom';\nimport type { Step, StepOptions, StepOptionsAttachTo } from '../step.ts';\nimport { isHTMLElement } from './type-check.ts';\n\n/**\n * Determines options for the tooltip and initializes event listeners.\n *\n * @param step The step instance\n */\nexport function setupTooltip(step: Step): ComputePositionConfig {\n  if (step.cleanup) {\n    step.cleanup();\n  }\n\n  const attachToOptions = step._getResolvedAttachToOptions();\n\n  let target = attachToOptions.element as HTMLElement;\n  const floatingUIOptions = getFloatingUIOptions(attachToOptions, step);\n  const shouldCenter = shouldCenterStep(attachToOptions);\n\n  if (shouldCenter) {\n    target = document.body;\n    const content = step.shepherdElementComponent?.element;\n    content?.classList.add('shepherd-centered');\n  }\n\n  step.cleanup = autoUpdate(target, step.el as HTMLElement, () => {\n    // The element might have already been removed by the end of the tour.\n    if (!step.el) {\n      step.cleanup?.();\n      return;\n    }\n\n    setPosition(target, step, floatingUIOptions, shouldCenter);\n  });\n\n  step.target = attachToOptions.element as HTMLElement;\n\n  return floatingUIOptions;\n}\n\n/**\n * Merge tooltip options handling nested keys.\n *\n * @param tourOptions - The default tour options.\n * @param options - Step specific options.\n *\n * @return {floatingUIOptions: FloatingUIOptions}\n */\nexport function mergeTooltipConfig(\n  tourOptions: StepOptions,\n  options: StepOptions\n): { floatingUIOptions: ComputePositionConfig } {\n  return {\n    floatingUIOptions: deepmerge(\n      tourOptions.floatingUIOptions || {},\n      options.floatingUIOptions || {}\n    )\n  };\n}\n\n/**\n * Cleanup function called when the step is closed/destroyed.\n *\n * @param step\n */\nexport function destroyTooltip(step: Step) {\n  if (step.cleanup) {\n    step.cleanup();\n  }\n\n  step.cleanup = null;\n}\n\nfunction setPosition(\n  target: HTMLElement,\n  step: Step,\n  floatingUIOptions: ComputePositionConfig,\n  shouldCenter: boolean\n) {\n  return (\n    computePosition(target, step.el as HTMLElement, floatingUIOptions)\n      .then(floatingUIposition(step, shouldCenter))\n      // Wait before forcing focus.\n      .then(\n        (step: Step) =>\n          new Promise<Step>((resolve) => {\n            setTimeout(() => resolve(step), 300);\n          })\n      )\n      // Replaces focusAfterRender modifier.\n      .then((step: Step) => {\n        if (step?.el) {\n          step.el.tabIndex = 0;\n          step.el.focus({ preventScroll: true });\n        }\n      })\n  );\n}\n\nfunction floatingUIposition(step: Step, shouldCenter: boolean) {\n  return ({\n    x,\n    y,\n    placement,\n    middlewareData\n  }: {\n    x: number;\n    y: number;\n    placement: Placement;\n    middlewareData: MiddlewareData;\n  }) => {\n    if (!step.el) {\n      return step;\n    }\n\n    if (shouldCenter) {\n      Object.assign(step.el.style, {\n        position: 'fixed',\n        left: '50%',\n        top: '50%',\n        transform: 'translate(-50%, -50%)'\n      });\n    } else {\n      Object.assign(step.el.style, {\n        position: 'absolute',\n        left: `${x}px`,\n        top: `${y}px`\n      });\n    }\n\n    step.el.dataset['popperPlacement'] = placement;\n\n    placeArrow(step.el, middlewareData);\n\n    return step;\n  };\n}\n\nfunction placeArrow(el: HTMLElement, middlewareData: MiddlewareData) {\n  const arrowEl = el.querySelector('.shepherd-arrow');\n  if (isHTMLElement(arrowEl) && middlewareData.arrow) {\n    const { x: arrowX, y: arrowY } = middlewareData.arrow;\n    Object.assign(arrowEl.style, {\n      left: arrowX != null ? `${arrowX}px` : '',\n      top: arrowY != null ? `${arrowY}px` : ''\n    });\n  }\n}\n\n/**\n * Gets the `Floating UI` options from a set of base `attachTo` options\n * @param attachToOptions\n * @param step The step instance\n * @private\n */\nexport function getFloatingUIOptions(\n  attachToOptions: StepOptionsAttachTo,\n  step: Step\n): ComputePositionConfig {\n  const options: ComputePositionConfig = {\n    strategy: 'absolute'\n  };\n\n  options.middleware = [];\n\n  const arrowEl = addArrow(step);\n\n  const shouldCenter = shouldCenterStep(attachToOptions);\n\n  const hasAutoPlacement = attachToOptions.on?.includes('auto');\n\n  const hasEdgeAlignment =\n    attachToOptions?.on?.includes('-start') ||\n    attachToOptions?.on?.includes('-end');\n\n  if (!shouldCenter) {\n    if (hasAutoPlacement) {\n      options.middleware.push(\n        autoPlacement({\n          crossAxis: true,\n          alignment: hasEdgeAlignment\n            ? (attachToOptions?.on?.split('-').pop() as Alignment)\n            : null\n        })\n      );\n    } else {\n      options.middleware.push(flip());\n    }\n\n    options.middleware.push(\n      // Replicate PopperJS default behavior.\n      shift({\n        limiter: limitShift(),\n        crossAxis: true\n      })\n    );\n\n    if (arrowEl) {\n      const arrowOptions =\n        typeof step.options.arrow === 'object'\n          ? step.options.arrow\n          : { padding: 4 };\n\n      options.middleware.push(\n        arrow({\n          element: arrowEl,\n          padding: hasEdgeAlignment ? arrowOptions.padding : 0\n        })\n      );\n    }\n\n    if (!hasAutoPlacement) options.placement = attachToOptions.on as Placement;\n  }\n\n  return deepmerge(options, step.options.floatingUIOptions || {});\n}\n\nfunction addArrow(step: Step) {\n  if (step.options.arrow && step.el) {\n    return step.el.querySelector('.shepherd-arrow');\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "shepherd.js/src/utils/general.ts",
    "content": "import { type Tour, type TourOptions } from '../tour.ts';\nimport {\n  type StepOptionsAttachTo,\n  type Step,\n  type StepOptions\n} from '../step.ts';\nimport { isFunction, isString } from './type-check.ts';\n\nexport class StepNoOp {\n  constructor(_options: StepOptions) {}\n}\n\nexport class TourNoOp {\n  constructor(_tour: Tour, _options: TourOptions) {}\n}\n\n/**\n * Ensure class prefix ends in `-`\n * @param prefix - The prefix to prepend to the class names generated by nano-css\n * @return The prefix ending in `-`\n */\nexport function normalizePrefix(prefix?: string) {\n  if (!isString(prefix) || prefix === '') {\n    return '';\n  }\n\n  return prefix.charAt(prefix.length - 1) !== '-' ? `${prefix}-` : prefix;\n}\n\n/**\n * Resolves attachTo options, converting element option value to a qualified HTMLElement.\n * @param step - The step instance\n * @returns {{}|{element, on}}\n * `element` is a qualified HTML Element\n * `on` is a string position value\n */\nexport function parseAttachTo(step: Step) {\n  const options = step.options.attachTo || {};\n  const returnOpts = Object.assign({}, options);\n\n  if (isFunction(returnOpts.element)) {\n    // Bind the callback to step so that it has access to the object, to enable running additional logic\n    returnOpts.element = returnOpts.element.call(step);\n  }\n\n  if (isString(returnOpts.element)) {\n    // Can't override the element in user opts reference because we can't\n    // guarantee that the element will exist in the future.\n    try {\n      returnOpts.element = document.querySelector(\n        returnOpts.element\n      ) as HTMLElement;\n    } catch (_e) {\n      // TODO\n    }\n    if (!returnOpts.element) {\n      console.error(\n        `The element for this Shepherd step was not found ${options.element}`\n      );\n    }\n  }\n\n  return returnOpts;\n}\n\n/*\n * Resolves the step's `extraHighlights` option, converting any locator values to HTMLElements.\n */\nexport function parseExtraHighlights(step: Step): HTMLElement[] {\n  if (step.options.extraHighlights) {\n    return step.options.extraHighlights.flatMap((highlight) => {\n      return Array.from(document.querySelectorAll(highlight)) as HTMLElement[];\n    });\n  }\n  return [];\n}\n\n/**\n * Checks if the step should be centered or not. Does not trigger attachTo.element evaluation, making it a pure\n * alternative for the deprecated step.isCentered() method.\n */\nexport function shouldCenterStep(resolvedAttachToOptions: StepOptionsAttachTo) {\n  if (\n    resolvedAttachToOptions === undefined ||\n    resolvedAttachToOptions === null\n  ) {\n    return true;\n  }\n\n  return !resolvedAttachToOptions.element || !resolvedAttachToOptions.on;\n}\n\n/**\n * Create a unique id for steps, tours, modals, etc\n */\nexport function uuid() {\n  let d = Date.now();\n  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n    const r = ((d + Math.random() * 16) % 16) | 0;\n    d = Math.floor(d / 16);\n    return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);\n  });\n}\n"
  },
  {
    "path": "shepherd.js/src/utils/overlay-path.ts",
    "content": "interface OverlayPathParams {\n  height: number;\n  r?:\n    | number\n    | {\n        bottomLeft: number;\n        bottomRight: number;\n        topLeft: number;\n        topRight: number;\n      };\n  x?: number;\n  y?: number;\n  width: number;\n}\n/**\n * Generates the svg path data for a rounded rectangle overlay\n * @param dimension - Dimensions of rectangle.\n * @param dimension.width - Width.\n * @param dimension.height - Height.\n * @param dimension.x - Offset from top left corner in x axis. default 0.\n * @param dimension.y - Offset from top left corner in y axis. default 0.\n * @param dimension.r - Corner Radius. Keep this smaller than half of width or height.\n * @returns Rounded rectangle overlay path data.\n */\nexport function makeOverlayPath(overlayPaths: OverlayPathParams[]) {\n  let openings = '';\n\n  const { innerWidth: w, innerHeight: h } = window;\n\n  overlayPaths.forEach((overlayPath) => {\n    const { width, height, x = 0, y = 0, r = 0 } = overlayPath;\n    const {\n      topLeft = 0,\n      topRight = 0,\n      bottomRight = 0,\n      bottomLeft = 0\n    } = typeof r === 'number'\n      ? { topLeft: r, topRight: r, bottomRight: r, bottomLeft: r }\n      : r;\n\n    openings +=\n      `M${x + topLeft},${y}` +\n      `a${topLeft},${topLeft},0,0,0-${topLeft},${topLeft}` +\n      `V${height + y - bottomLeft}` +\n      `a${bottomLeft},${bottomLeft},0,0,0,${bottomLeft},${bottomLeft}` +\n      `H${width + x - bottomRight}` +\n      `a${bottomRight},${bottomRight},0,0,0,${bottomRight}-${bottomRight}` +\n      `V${y + topRight}` +\n      `a${topRight},${topRight},0,0,0-${topRight}-${topRight}` +\n      `Z`;\n  });\n\n  return (\n    `M${w},${h}` +\n    `H0` +\n    `V0` +\n    `H${w}` +\n    `V${h}` +\n    `Z` +\n    `${openings}`\n  ).replace(/\\s/g, '');\n}\n"
  },
  {
    "path": "shepherd.js/src/utils/type-check.ts",
    "content": "/**\n * Checks if `value` is classified as an `Element`.\n * @param value The param to check if it is an Element\n */\nexport function isElement<T>(value: T | Element): value is Element {\n  return value instanceof Element;\n}\n\n/**\n * Checks if `value` is classified as an `HTMLElement`.\n * @param value The param to check if it is an HTMLElement\n */\nexport function isHTMLElement<T>(value: T | HTMLElement): value is HTMLElement {\n  return value instanceof HTMLElement;\n}\n\n/**\n * Checks if `value` is classified as a `Function` object.\n * @param value The param to check if it is a function\n */\nexport function isFunction<T>(value: T | Function): value is Function {\n  return typeof value === 'function';\n}\n\n/**\n * Checks if `value` is classified as a `String` object.\n * @param value The param to check if it is a string\n */\nexport function isString<T>(value: T | string): value is string {\n  return typeof value === 'string';\n}\n\n/**\n * Checks if `value` is undefined.\n * @param value The param to check if it is undefined\n */\nexport function isUndefined<T>(value: T | undefined): value is undefined {\n  return value === undefined;\n}\n"
  },
  {
    "path": "shepherd.js/test/cypress/.gitignore",
    "content": "# Editors\n/.idea/\n/.vscode/\n\n/.log/\n/.nyc_output/\n/coverage/\n/cypress/\n/dist/\n/node_modules/\n/.DS_Store\n/.sass-cache\n/npm-debug.log*\n/stats.html\n/yarn-error.log\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n"
  },
  {
    "path": "shepherd.js/test/cypress/cypress.config.js",
    "content": "import { defineConfig } from 'cypress';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport default defineConfig({\n  fixturesFolder: join(__dirname, 'fixtures'),\n  video: false,\n  viewportWidth: 1440,\n  viewportHeight: 900,\n  e2e: {\n    baseUrl: 'http://localhost:9002',\n    specPattern: join(__dirname, 'integration/**/*.cy.{js,jsx,ts,tsx}'),\n    supportFile: join(__dirname, 'support/index.js')\n  }\n});\n"
  },
  {
    "path": "shepherd.js/test/cypress/dummy/assets/favicons/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo src=\"/mstile-150x150.png\"/>\n            <TileColor>#00aba9</TileColor>\n        </tile>\n    </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "shepherd.js/test/cypress/dummy/assets/favicons/manifest.json",
    "content": "{\n  \"name\": \"Ship Shape\",\n  \"short_name\": \"Ship Shape\",\n  \"icons\": [\n    {\n      \"src\": \"\\/favicons\\/android-chrome-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image\\/png\"\n    },\n    {\n      \"src\": \"\\/favicons\\/android-chrome-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image\\/png\"\n    }\n  ],\n  \"theme_color\": \"#ffffff\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "shepherd.js/test/cypress/dummy/css/fonts.css",
    "content": "@font-face {\n  font-family: 'GT Pressura';\n  src: url('../../landing/public/assets/fonts/GTPressura-Bold.woff2') format('woff2'),\n  url('../../landing/public/assets/fonts/GTPressura-Bold.woff') format('woff');\n  font-weight: bold;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'Founders Grotesk';\n  src: url('../../landing/public/assets/fonts/FoundersGrotesk-Regular.woff2') format('woff2'),\n  url('../../landing/public/assets/fonts/FoundersGrotesk-Regular.woff') format('woff');\n  font-weight: normal;\n  font-style: normal;\n}\n"
  },
  {
    "path": "shepherd.js/test/cypress/dummy/css/prism.css",
    "content": "/*\n\nName:       Base16 Ocean Dark\nAuthor:     Chris Kempson (http://chriskempson.com)\n\nPrism template by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/prism/)\nOriginal Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\ncode[class*=\"language-\"],\npre[class*=\"language-\"] {\n  font-family: Consolas, Menlo, Monaco, \"Andale Mono WT\", \"Andale Mono\", \"Lucida Console\", \"Lucida Sans Typewriter\", \"DejaVu Sans Mono\", \"Bitstream Vera Sans Mono\", \"Liberation Mono\", \"Nimbus Mono L\", \"Courier New\", Courier, monospace;\n  font-size: 14px;\n  line-height: 1.375;\n  direction: ltr;\n  text-align: left;\n  white-space: pre;\n  word-spacing: normal;\n  word-break: normal;\n  -moz-tab-size: 4;\n  -o-tab-size: 4;\n  tab-size: 4;\n  -webkit-hyphens: none;\n  -ms-hyphens: none;\n  hyphens: none;\n  background: #2b303b;\n  color: #c0c5ce;\n}\n\npre[class*=\"language-\"]::-moz-selection, pre[class*=\"language-\"] ::-moz-selection,\ncode[class*=\"language-\"]::-moz-selection, code[class*=\"language-\"] ::-moz-selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\npre[class*=\"language-\"]::selection, pre[class*=\"language-\"] ::selection,\ncode[class*=\"language-\"]::selection, code[class*=\"language-\"] ::selection {\n  text-shadow: none;\n  background: #a7adba;\n}\n\n/* Code blocks */\npre[class*=\"language-\"] {\n  padding: 2rem;\n  margin: .5em 0;\n  overflow: auto;\n}\n\n/* Inline code */\n:not(pre) > code[class*=\"language-\"] {\n  padding: .1em;\n  border-radius: .3em;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n  color: #65737e;\n}\n\n.token.punctuation {\n  color: #c0c5ce;\n}\n\n.token.namespace {\n  opacity: .7;\n}\n\n.token.operator,\n.token.boolean,\n.token.number {\n  color: #d08770;\n}\n\n.token.property {\n  color: #ebcb8b;\n}\n\n.token.tag {\n  color: #8fa1b3;\n}\n\n.token.string {\n  color: #96b5b4;\n}\n\n.token.selector {\n  color: #b48ead;\n}\n\n.token.attr-name {\n  color: #d08770;\n}\n\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n  color: #96b5b4;\n}\n\n.token.attr-value,\n.token.keyword,\n.token.control,\n.token.directive,\n.token.unit {\n  color: #a3be8c;\n}\n\n.token.statement,\n.token.regex,\n.token.atrule {\n  color: #96b5b4;\n}\n\n.token.placeholder,\n.token.variable {\n  color: #8fa1b3;\n}\n\n.token.deleted {\n  text-decoration: line-through;\n}\n\n.token.inserted {\n  border-bottom: 1px dotted #eff1f5;\n  text-decoration: none;\n}\n\n.token.italic {\n  font-style: italic;\n}\n\n.token.important,\n.token.bold {\n  font-weight: bold;\n}\n\n.token.important {\n  color: #bf616a;\n}\n\n.token.entity {\n  cursor: help;\n}\n\npre > code.highlight {\n  outline: 0.4em solid #bf616a;\n  outline-offset: .4em;\n}\n\n.line-numbers .line-numbers-rows {\n  border-right-color: #343d46 !important;\n}\n\n.line-numbers-rows > span:before {\n  color: #4f5b66 !important;\n}\n\n.line-highlight {\n  background: rgba(239, 241, 245, 0.2) !important;\n  background: -webkit-linear-gradient(left, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n  background: linear-gradient(to right, rgba(239, 241, 245, 0.2) 70%, rgba(239, 241, 245, 0)) !important;\n}\n"
  },
  {
    "path": "shepherd.js/test/cypress/dummy/css/welcome.css",
    "content": "html, body {\n  font-family: \"Pier Sans\", \"proxima-nova\", \"Helvetica Neue\", sans-serif;\n}\n\nbody {\n  background-color: rgba(236, 243, 246, 50);\n  color: #5F6976;\n  height: 100%;\n  margin: 0;\n}\n\n.button {\n  border: 2px solid #5F6976;\n  color: #5F6976;\n  cursor: pointer;\n  display: inline-block;\n  font-size: 0.8em;\n  font-weight: 500;\n  letter-spacing: 3px;\n  line-height: 1.3em;\n  padding: 1em 1.25em;\n  text-decoration: none;\n  text-transform: uppercase;\n  width: 140px;\n}\n\n.button:hover {\n  background-color: #5F6976;\n  color: #ffffff;\n}\n\n@media (max-width: 568px) {\n  .button {\n    display: block;\n    margin: 1em auto 0;\n  }\n}\n\n.hero-outer {\n  -webkit-box-sizing: border-box;\n  box-sizing: border-box;\n  display: table;\n  height: 100%;\n  padding: 20px 0;\n  width: 100%;\n}\n\n.hero-inner {\n  max-width: 700px;\n  width: 90%;\n}\n\n@media (max-width: 600px) {\n  .hero-inner {\n    width: 340px;\n  }\n}\n\n@media (max-width: 360px) {\n  .hero-inner {\n    width: 200px;\n  }\n}\n\n.hero-outer .hero-inner {\n  margin: 0 auto 1em;\n  text-align: center;\n}\n\n.demo-heading {\n  color: #00213B;\n}\n\nh1.demo-heading {\n  font-size: 3rem;\n  font-weight: bold;\n  padding-top: 10px;\n}\n\nh3.demo-heading {\n  font-size: 1.3em;\n  padding-top: 13px;\n}\n\nh2.demo-heading,\nh3.demo-heading {\n  font-weight: normal;\n}\n\n.hero-outer .hero-followup {\n  padding-top: 20px;\n}\n\npre {\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  line-height: 1.4em;\n}\n\n.shepherd-button {\n  background: #00213b;\n  font-size: 0.7rem;\n  text-transform: uppercase;\n}\n\n.shepherd-button:hover {\n  background: #ececec;\n  color: #00213b;\n}\n\n.shepherd-text a,\n.shepherd-text a:visited,\n.shepherd-text a:active {\n  border-bottom: 1px dotted;\n  border-bottom-color: rgba(0, 0, 0, 0.75);\n  color: rgba(0, 0, 0, 0.75);\n  text-decoration: none;\n}\n\n.shepherd-text a:hover,\n.shepherd-text a:visited:hover,\n.shepherd-text a:active:hover {\n  border-bottom-style: solid;\n}"
  },
  {
    "path": "shepherd.js/test/cypress/dummy/index.html",
    "content": "<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n    <title>Shepherd — Guide your users through a tour of your app.</title>\n    <meta\n      name=\"description\"\n      content=\"Guide your users through a tour of your app.\"\n    />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width, initial-scale=1, user-scalable=no\"\n    />\n\n    <!--favicons-->\n\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"assets/favicons/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"32x32\"\n      href=\"assets/favicons/favicon-32x32.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      sizes=\"16x16\"\n      href=\"assets/favicons/favicon-16x16.png\"\n    />\n    <link rel=\"manifest\" href=\"assets/favicons/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"assets/favicons/safari-pinned-tab.svg\"\n      color=\"#426170\"\n    />\n    <link rel=\"shortcut icon\" href=\"assets/favicons/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"assets/favicons/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Welcome docs styles -->\n    <link\n      rel=\"stylesheet\"\n      href=\"../../../dist/css/shepherd.css\"\n    />\n    <link rel=\"stylesheet\" href=\"./css/fonts.css\" />\n    <link rel=\"stylesheet\" href=\"./css/prism.css\" />\n    <link rel=\"stylesheet\" href=\"./css/welcome.css\" />\n  </head>\n\n  <body>\n    <div class=\"hero-outer\" data-test-hero-outer>\n      <div class=\"hero-inner\">\n        <div class=\"hero-welcome\" data-test-hero-welcome>\n          <h1>Shepherd</h1>\n\n          <h2>Guide your users through a tour of your app.</h2>\n        </div>\n\n        <div class=\"hero-including\" data-test-hero-including>\n          <h3>Including</h3>\n\n          <script\n            type=\"text/plain\"\n            class=\"language-markup\"\n            id=\"hero-including-code\"\n          >\n            <script type=\"module\" src=\"shepherd.min.js\">&lt;/script>\n          </script>\n        </div>\n\n        <div class=\"hero-example\">\n          <h3>Example</h3>\n\n          <pre id=\"hero-example-code\">\n          <code class=\"language-javascript\">\n            const tour = new Shepherd.Tour({\n              defaultStepOptions: {\n                classes: 'shadow-md bg-purple-dark',\n                scrollTo: true\n              }\n            });\n\n            tour.addStep({\n              title: 'Example Shepherd',\n              text: 'Creating a Shepherd is easy too! Just create ...',\n              attachTo: {\n                element: '.hero-example',\n                on: 'bottom'\n              },\n              advanceOn: {\n                selector: '.docs-link',\n                event: 'click'\n              },\n              id: 'example'\n            });\n\n            tour.start();\n          </code>\n        </pre>\n        </div>\n\n        <div class=\"hero-followup\">\n          <p>\n            <a\n              class=\"button star\"\n              href=\"https://github.com/shipshapecode/shepherd\"\n              >★ on Github</a\n            >\n            &nbsp;&nbsp;\n            <a class=\"button\" href=\"https://shepherdjs.dev/docs/\">View Docs</a>\n          </p>\n        </div>\n        <div>\n          <img src=\"sheep.svg\" />\n        </div>\n\n        <div id=\"complex-attach-to\" tabindex=\"0\">\n          <button id=\"nested-button-1\">Button 1</button>\n          <input id=\"nested-input\" type=\"text\" placeholder=\"Input\" />\n          <button id=\"nested-button-2\">Button 2</button>\n        </div>\n      </div>\n    </div>\n\n    <!-- Shepherd -->\n    <script type=\"module\">\n      import Shepherd from '../../../dist/js/shepherd.mjs';\n      window.Shepherd = Shepherd;\n    </script>\n\n    <!-- Welcome page -->\n    <script src=\"js/prism.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "shepherd.js/test/cypress/dummy/js/prism.js",
    "content": "/* PrismJS 1.15.0\nhttps://prismjs.com/download.html#themes=prism&languages=markup+clike+javascript&plugins=unescaped-markup+normalize-whitespace */\nvar _self =\n    'undefined' != typeof window\n      ? window\n      : 'undefined' != typeof WorkerGlobalScope &&\n          self instanceof WorkerGlobalScope\n        ? self\n        : {},\n  Prism = (function () {\n    var e = /\\blang(?:uage)?-([\\w-]+)\\b/i,\n      t = 0,\n      n = (_self.Prism = {\n        manual: _self.Prism && _self.Prism.manual,\n        disableWorkerMessageHandler:\n          _self.Prism && _self.Prism.disableWorkerMessageHandler,\n        util: {\n          encode: function (e) {\n            return e instanceof r\n              ? new r(e.type, n.util.encode(e.content), e.alias)\n              : 'Array' === n.util.type(e)\n                ? e.map(n.util.encode)\n                : e\n                    .replace(/&/g, '&amp;')\n                    .replace(/</g, '&lt;')\n                    .replace(/\\u00a0/g, ' ');\n          },\n          type: function (e) {\n            return Object.prototype.toString\n              .call(e)\n              .match(/\\[object (\\w+)\\]/)[1];\n          },\n          objId: function (e) {\n            return (\n              e.__id || Object.defineProperty(e, '__id', { value: ++t }),\n              e.__id\n            );\n          },\n          clone: function (e, t) {\n            var r = n.util.type(e);\n            switch (((t = t || {}), r)) {\n              case 'Object':\n                if (t[n.util.objId(e)]) return t[n.util.objId(e)];\n                var a = {};\n                t[n.util.objId(e)] = a;\n                for (var l in e)\n                  e.hasOwnProperty(l) && (a[l] = n.util.clone(e[l], t));\n                return a;\n              case 'Array':\n                if (t[n.util.objId(e)]) return t[n.util.objId(e)];\n                var a = [];\n                return (\n                  (t[n.util.objId(e)] = a),\n                  e.forEach(function (e, r) {\n                    a[r] = n.util.clone(e, t);\n                  }),\n                  a\n                );\n            }\n            return e;\n          }\n        },\n        languages: {\n          extend: function (e, t) {\n            var r = n.util.clone(n.languages[e]);\n            for (var a in t) r[a] = t[a];\n            return r;\n          },\n          insertBefore: function (e, t, r, a) {\n            a = a || n.languages;\n            var l = a[e];\n            if (2 == arguments.length) {\n              r = arguments[1];\n              for (var i in r) r.hasOwnProperty(i) && (l[i] = r[i]);\n              return l;\n            }\n            var o = {};\n            for (var s in l)\n              if (l.hasOwnProperty(s)) {\n                if (s == t)\n                  for (var i in r) r.hasOwnProperty(i) && (o[i] = r[i]);\n                o[s] = l[s];\n              }\n            return (\n              n.languages.DFS(n.languages, function (t, n) {\n                n === a[e] && t != e && (this[t] = o);\n              }),\n              (a[e] = o)\n            );\n          },\n          DFS: function (e, t, r, a) {\n            a = a || {};\n            for (var l in e)\n              e.hasOwnProperty(l) &&\n                (t.call(e, l, e[l], r || l),\n                'Object' !== n.util.type(e[l]) || a[n.util.objId(e[l])]\n                  ? 'Array' !== n.util.type(e[l]) ||\n                    a[n.util.objId(e[l])] ||\n                    ((a[n.util.objId(e[l])] = !0),\n                    n.languages.DFS(e[l], t, l, a))\n                  : ((a[n.util.objId(e[l])] = !0),\n                    n.languages.DFS(e[l], t, null, a)));\n          }\n        },\n        plugins: {},\n        highlightAll: function (e, t) {\n          n.highlightAllUnder(document, e, t);\n        },\n        highlightAllUnder: function (e, t, r) {\n          var a = {\n            callback: r,\n            selector:\n              'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'\n          };\n          n.hooks.run('before-highlightall', a);\n          for (\n            var l, i = a.elements || e.querySelectorAll(a.selector), o = 0;\n            (l = i[o++]);\n          )\n            n.highlightElement(l, t === !0, a.callback);\n        },\n        highlightElement: function (t, r, a) {\n          for (var l, i, o = t; o && !e.test(o.className); ) o = o.parentNode;\n          (o &&\n            ((l = (o.className.match(e) || [, ''])[1].toLowerCase()),\n            (i = n.languages[l])),\n            (t.className =\n              t.className.replace(e, '').replace(/\\s+/g, ' ') +\n              ' language-' +\n              l),\n            t.parentNode &&\n              ((o = t.parentNode),\n              /pre/i.test(o.nodeName) &&\n                (o.className =\n                  o.className.replace(e, '').replace(/\\s+/g, ' ') +\n                  ' language-' +\n                  l)));\n          var s = t.textContent,\n            u = { element: t, language: l, grammar: i, code: s };\n          if ((n.hooks.run('before-sanity-check', u), !u.code || !u.grammar))\n            return (\n              u.code &&\n                (n.hooks.run('before-highlight', u),\n                (u.element.textContent = u.code),\n                n.hooks.run('after-highlight', u)),\n              n.hooks.run('complete', u),\n              void 0\n            );\n          if ((n.hooks.run('before-highlight', u), r && _self.Worker)) {\n            var g = new Worker(n.filename);\n            ((g.onmessage = function (e) {\n              ((u.highlightedCode = e.data),\n                n.hooks.run('before-insert', u),\n                (u.element.innerHTML = u.highlightedCode),\n                a && a.call(u.element),\n                n.hooks.run('after-highlight', u),\n                n.hooks.run('complete', u));\n            }),\n              g.postMessage(\n                JSON.stringify({\n                  language: u.language,\n                  code: u.code,\n                  immediateClose: !0\n                })\n              ));\n          } else\n            ((u.highlightedCode = n.highlight(u.code, u.grammar, u.language)),\n              n.hooks.run('before-insert', u),\n              (u.element.innerHTML = u.highlightedCode),\n              a && a.call(t),\n              n.hooks.run('after-highlight', u),\n              n.hooks.run('complete', u));\n        },\n        highlight: function (e, t, a) {\n          var l = { code: e, grammar: t, language: a };\n          return (\n            n.hooks.run('before-tokenize', l),\n            (l.tokens = n.tokenize(l.code, l.grammar)),\n            n.hooks.run('after-tokenize', l),\n            r.stringify(n.util.encode(l.tokens), l.language)\n          );\n        },\n        matchGrammar: function (e, t, r, a, l, i, o) {\n          var s = n.Token;\n          for (var u in r)\n            if (r.hasOwnProperty(u) && r[u]) {\n              if (u == o) return;\n              var g = r[u];\n              g = 'Array' === n.util.type(g) ? g : [g];\n              for (var c = 0; c < g.length; ++c) {\n                var h = g[c],\n                  f = h.inside,\n                  d = !!h.lookbehind,\n                  m = !!h.greedy,\n                  p = 0,\n                  y = h.alias;\n                if (m && !h.pattern.global) {\n                  var v = h.pattern.toString().match(/[imuy]*$/)[0];\n                  h.pattern = RegExp(h.pattern.source, v + 'g');\n                }\n                h = h.pattern || h;\n                for (var b = a, k = l; b < t.length; k += t[b].length, ++b) {\n                  var w = t[b];\n                  if (t.length > e.length) return;\n                  if (!(w instanceof s)) {\n                    if (m && b != t.length - 1) {\n                      h.lastIndex = k;\n                      var _ = h.exec(e);\n                      if (!_) break;\n                      for (\n                        var j = _.index + (d ? _[1].length : 0),\n                          P = _.index + _[0].length,\n                          A = b,\n                          x = k,\n                          O = t.length;\n                        O > A && (P > x || (!t[A].type && !t[A - 1].greedy));\n                        ++A\n                      )\n                        ((x += t[A].length), j >= x && (++b, (k = x)));\n                      if (t[b] instanceof s) continue;\n                      ((I = A - b), (w = e.slice(k, x)), (_.index -= k));\n                    } else {\n                      h.lastIndex = 0;\n                      var _ = h.exec(w),\n                        I = 1;\n                    }\n                    if (_) {\n                      d && (p = _[1] ? _[1].length : 0);\n                      var j = _.index + p,\n                        _ = _[0].slice(p),\n                        P = j + _.length,\n                        N = w.slice(0, j),\n                        S = w.slice(P),\n                        C = [b, I];\n                      N && (++b, (k += N.length), C.push(N));\n                      var E = new s(u, f ? n.tokenize(_, f) : _, y, _, m);\n                      if (\n                        (C.push(E),\n                        S && C.push(S),\n                        Array.prototype.splice.apply(t, C),\n                        1 != I && n.matchGrammar(e, t, r, b, k, !0, u),\n                        i)\n                      )\n                        break;\n                    } else if (i) break;\n                  }\n                }\n              }\n            }\n        },\n        tokenize: function (e, t) {\n          var r = [e],\n            a = t.rest;\n          if (a) {\n            for (var l in a) t[l] = a[l];\n            delete t.rest;\n          }\n          return (n.matchGrammar(e, r, t, 0, 0, !1), r);\n        },\n        hooks: {\n          all: {},\n          add: function (e, t) {\n            var r = n.hooks.all;\n            ((r[e] = r[e] || []), r[e].push(t));\n          },\n          run: function (e, t) {\n            var r = n.hooks.all[e];\n            if (r && r.length) for (var a, l = 0; (a = r[l++]); ) a(t);\n          }\n        }\n      }),\n      r = (n.Token = function (e, t, n, r, a) {\n        ((this.type = e),\n          (this.content = t),\n          (this.alias = n),\n          (this.length = 0 | (r || '').length),\n          (this.greedy = !!a));\n      });\n    if (\n      ((r.stringify = function (e, t, a) {\n        if ('string' == typeof e) return e;\n        if ('Array' === n.util.type(e))\n          return e\n            .map(function (n) {\n              return r.stringify(n, t, e);\n            })\n            .join('');\n        var l = {\n          type: e.type,\n          content: r.stringify(e.content, t, a),\n          tag: 'span',\n          classes: ['token', e.type],\n          attributes: {},\n          language: t,\n          parent: a\n        };\n        if (e.alias) {\n          var i = 'Array' === n.util.type(e.alias) ? e.alias : [e.alias];\n          Array.prototype.push.apply(l.classes, i);\n        }\n        n.hooks.run('wrap', l);\n        var o = Object.keys(l.attributes)\n          .map(function (e) {\n            return (\n              e + '=\"' + (l.attributes[e] || '').replace(/\"/g, '&quot;') + '\"'\n            );\n          })\n          .join(' ');\n        return (\n          '<' +\n          l.tag +\n          ' class=\"' +\n          l.classes.join(' ') +\n          '\"' +\n          (o ? ' ' + o : '') +\n          '>' +\n          l.content +\n          '</' +\n          l.tag +\n          '>'\n        );\n      }),\n      !_self.document)\n    )\n      return _self.addEventListener\n        ? (n.disableWorkerMessageHandler ||\n            _self.addEventListener(\n              'message',\n              function (e) {\n                var t = JSON.parse(e.data),\n                  r = t.language,\n                  a = t.code,\n                  l = t.immediateClose;\n                (_self.postMessage(n.highlight(a, n.languages[r], r)),\n                  l && _self.close());\n              },\n              !1\n            ),\n          _self.Prism)\n        : _self.Prism;\n    var a =\n      document.currentScript ||\n      [].slice.call(document.getElementsByTagName('script')).pop();\n    return (\n      a &&\n        ((n.filename = a.src),\n        n.manual ||\n          a.hasAttribute('data-manual') ||\n          ('loading' !== document.readyState\n            ? window.requestAnimationFrame\n              ? window.requestAnimationFrame(n.highlightAll)\n              : window.setTimeout(n.highlightAll, 16)\n            : document.addEventListener('DOMContentLoaded', n.highlightAll))),\n      _self.Prism\n    );\n  })();\n('undefined' != typeof module && module.exports && (module.exports = Prism),\n  'undefined' != typeof global && (global.Prism = Prism));\n((Prism.languages.markup = {\n  comment: /<!--[\\s\\S]*?-->/,\n  prolog: /<\\?[\\s\\S]+?\\?>/,\n  doctype: /<!DOCTYPE[\\s\\S]+?>/i,\n  cdata: /<!\\[CDATA\\[[\\s\\S]*?]]>/i,\n  tag: {\n    pattern:\n      /<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s+[^\\s>\\/=]+(?:=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+))?)*\\s*\\/?>/i,\n    greedy: !0,\n    inside: {\n      tag: {\n        pattern: /^<\\/?[^\\s>\\/]+/i,\n        inside: { punctuation: /^<\\/?/, namespace: /^[^\\s>\\/:]+:/ }\n      },\n      'attr-value': {\n        pattern: /=(?:(\"|')(?:\\\\[\\s\\S]|(?!\\1)[^\\\\])*\\1|[^\\s'\">=]+)/i,\n        inside: {\n          punctuation: [/^=/, { pattern: /(^|[^\\\\])[\"']/, lookbehind: !0 }]\n        }\n      },\n      punctuation: /\\/?>/,\n      'attr-name': {\n        pattern: /[^\\s>\\/]+/,\n        inside: { namespace: /^[^\\s>\\/:]+:/ }\n      }\n    }\n  },\n  entity: /&#?[\\da-z]{1,8};/i\n}),\n  (Prism.languages.markup.tag.inside['attr-value'].inside.entity =\n    Prism.languages.markup.entity),\n  Prism.hooks.add('wrap', function (a) {\n    'entity' === a.type &&\n      (a.attributes.title = a.content.replace(/&amp;/, '&'));\n  }),\n  (Prism.languages.xml = Prism.languages.markup),\n  (Prism.languages.html = Prism.languages.markup),\n  (Prism.languages.mathml = Prism.languages.markup),\n  (Prism.languages.svg = Prism.languages.markup));\nPrism.languages.clike = {\n  comment: [\n    { pattern: /(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/, lookbehind: !0 },\n    { pattern: /(^|[^\\\\:])\\/\\/.*/, lookbehind: !0, greedy: !0 }\n  ],\n  string: {\n    pattern: /([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,\n    greedy: !0\n  },\n  'class-name': {\n    pattern:\n      /((?:\\b(?:class|interface|extends|implements|trait|instanceof|new)\\s+)|(?:catch\\s+\\())[\\w.\\\\]+/i,\n    lookbehind: !0,\n    inside: { punctuation: /[.\\\\]/ }\n  },\n  keyword:\n    /\\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\\b/,\n  boolean: /\\b(?:true|false)\\b/,\n  function: /[a-z0-9_]+(?=\\()/i,\n  number: /\\b0x[\\da-f]+\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,\n  operator: /--?|\\+\\+?|!=?=?|<=?|>=?|==?=?|&&?|\\|\\|?|\\?|\\*|\\/|~|\\^|%/,\n  punctuation: /[{}[\\];(),.:]/\n};\n((Prism.languages.javascript = Prism.languages.extend('clike', {\n  keyword:\n    /\\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\\b/,\n  number:\n    /\\b(?:0[xX][\\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\\b|(?:\\b\\d+\\.?\\d*|\\B\\.\\d+)(?:[Ee][+-]?\\d+)?/,\n  function: /[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*\\()/i,\n  operator:\n    /-[-=]?|\\+[+=]?|!=?=?|<<?=?|>>?>?=?|=(?:==?|>)?|&[&=]?|\\|[|=]?|\\*\\*?=?|\\/=?|~|\\^=?|%=?|\\?|\\.{3}/\n})),\n  Prism.languages.insertBefore('javascript', 'keyword', {\n    regex: {\n      pattern:\n        /((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s])\\s*)\\/(\\[[^\\]\\r\\n]+]|\\\\.|[^\\/\\\\\\[\\r\\n])+\\/[gimyu]{0,5}(?=\\s*($|[\\r\\n,.;})\\]]))/,\n      lookbehind: !0,\n      greedy: !0\n    },\n    'function-variable': {\n      pattern:\n        /[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*(?=\\s*=\\s*(?:function\\b|(?:\\([^()]*\\)|[_$a-z\\xA0-\\uFFFF][$\\w\\xA0-\\uFFFF]*)\\s*=>))/i,\n      alias: 'function'\n    },\n    constant: /\\b[A-Z][A-Z\\d_]*\\b/\n  }),\n  Prism.languages.insertBefore('javascript', 'string', {\n    'template-string': {\n      pattern: /`(?:\\\\[\\s\\S]|\\${[^}]+}|[^\\\\`])*`/,\n      greedy: !0,\n      inside: {\n        interpolation: {\n          pattern: /\\${[^}]+}/,\n          inside: {\n            'interpolation-punctuation': {\n              pattern: /^\\${|}$/,\n              alias: 'punctuation'\n            },\n            rest: null\n          }\n        },\n        string: /[\\s\\S]+/\n      }\n    }\n  }),\n  (Prism.languages.javascript[\n    'template-string'\n  ].inside.interpolation.inside.rest = Prism.languages.javascript),\n  Prism.languages.markup &&\n    Prism.languages.insertBefore('markup', 'tag', {\n      script: {\n        pattern: /(<script[\\s\\S]*?>)[\\s\\S]*?(?=<\\/script>)/i,\n        lookbehind: !0,\n        inside: Prism.languages.javascript,\n        alias: 'language-javascript',\n        greedy: !0\n      }\n    }),\n  (Prism.languages.js = Prism.languages.javascript));\n!(function () {\n  'undefined' != typeof self &&\n    self.Prism &&\n    self.document &&\n    Prism.languages.markup &&\n    ((Prism.plugins.UnescapedMarkup = !0),\n    Prism.hooks.add('before-highlightall', function (e) {\n      e.selector +=\n        \", [class*='lang-'] script[type='text/plain'], [class*='language-'] script[type='text/plain'], script[type='text/plain'][class*='lang-'], script[type='text/plain'][class*='language-']\";\n    }),\n    Prism.hooks.add('before-sanity-check', function (e) {\n      if (\n        (e.element.matches || e.element.msMatchesSelector).call(\n          e.element,\n          \"script[type='text/plain']\"\n        )\n      ) {\n        var t = document.createElement('code'),\n          n = document.createElement('pre');\n        return (\n          (n.className = t.className = e.element.className),\n          e.element.dataset &&\n            Object.keys(e.element.dataset).forEach(function (t) {\n              Object.prototype.hasOwnProperty.call(e.element.dataset, t) &&\n                (n.dataset[t] = e.element.dataset[t]);\n            }),\n          (e.code = e.code.replace(/&lt;\\/script(>|&gt;)/gi, '</script>')),\n          (t.textContent = e.code),\n          n.appendChild(t),\n          e.element.parentNode.replaceChild(n, e.element),\n          (e.element = t),\n          void 0\n        );\n      }\n      var n = e.element.parentNode;\n      !e.code &&\n        n &&\n        'pre' == n.nodeName.toLowerCase() &&\n        e.element.childNodes.length &&\n        '#comment' == e.element.childNodes[0].nodeName &&\n        (e.element.textContent = e.code = e.element.childNodes[0].textContent);\n    }));\n})();\n!(function () {\n  function e(e) {\n    this.defaults = r({}, e);\n  }\n  function n(e) {\n    return e.replace(/-(\\w)/g, function (e, n) {\n      return n.toUpperCase();\n    });\n  }\n  function t(e) {\n    for (var n = 0, t = 0; t < e.length; ++t)\n      e.charCodeAt(t) == '\t'.charCodeAt(0) && (n += 3);\n    return e.length + n;\n  }\n  var r =\n    Object.assign ||\n    function (e, n) {\n      for (var t in n) n.hasOwnProperty(t) && (e[t] = n[t]);\n      return e;\n    };\n  ((e.prototype = {\n    setDefaults: function (e) {\n      this.defaults = r(this.defaults, e);\n    },\n    normalize: function (e, t) {\n      t = r(this.defaults, t);\n      for (var i in t) {\n        var o = n(i);\n        'normalize' !== i &&\n          'setDefaults' !== o &&\n          t[i] &&\n          this[o] &&\n          (e = this[o].call(this, e, t[i]));\n      }\n      return e;\n    },\n    leftTrim: function (e) {\n      return e.replace(/^\\s+/, '');\n    },\n    rightTrim: function (e) {\n      return e.replace(/\\s+$/, '');\n    },\n    tabsToSpaces: function (e, n) {\n      return ((n = 0 | n || 4), e.replace(/\\t/g, new Array(++n).join(' ')));\n    },\n    spacesToTabs: function (e, n) {\n      return ((n = 0 | n || 4), e.replace(new RegExp(' {' + n + '}', 'g'), '\t'));\n    },\n    removeTrailing: function (e) {\n      return e.replace(/\\s*?$/gm, '');\n    },\n    removeInitialLineFeed: function (e) {\n      return e.replace(/^(?:\\r?\\n|\\r)/, '');\n    },\n    removeIndent: function (e) {\n      var n = e.match(/^[^\\S\\n\\r]*(?=\\S)/gm);\n      return n && n[0].length\n        ? (n.sort(function (e, n) {\n            return e.length - n.length;\n          }),\n          n[0].length ? e.replace(new RegExp('^' + n[0], 'gm'), '') : e)\n        : e;\n    },\n    indent: function (e, n) {\n      return e.replace(/^[^\\S\\n\\r]*(?=\\S)/gm, new Array(++n).join('\t') + '$&');\n    },\n    breakLines: function (e, n) {\n      n = n === !0 ? 80 : 0 | n || 80;\n      for (var r = e.split('\\n'), i = 0; i < r.length; ++i)\n        if (!(t(r[i]) <= n)) {\n          for (var o = r[i].split(/(\\s+)/g), a = 0, s = 0; s < o.length; ++s) {\n            var l = t(o[s]);\n            ((a += l), a > n && ((o[s] = '\\n' + o[s]), (a = l)));\n          }\n          r[i] = o.join('');\n        }\n      return r.join('\\n');\n    }\n  }),\n    'undefined' != typeof module && module.exports && (module.exports = e),\n    'undefined' != typeof Prism &&\n      ((Prism.plugins.NormalizeWhitespace = new e({\n        'remove-trailing': !0,\n        'remove-indent': !0,\n        'left-trim': !0,\n        'right-trim': !0\n      })),\n      Prism.hooks.add('before-sanity-check', function (e) {\n        var n = Prism.plugins.NormalizeWhitespace;\n        if (!e.settings || e.settings['whitespace-normalization'] !== !1) {\n          if ((!e.element || !e.element.parentNode) && e.code)\n            return ((e.code = n.normalize(e.code, e.settings)), void 0);\n          var t = e.element.parentNode,\n            r = /\\bno-whitespace-normalization\\b/;\n          if (\n            e.code &&\n            t &&\n            'pre' === t.nodeName.toLowerCase() &&\n            !r.test(t.className) &&\n            !r.test(e.element.className)\n          ) {\n            for (\n              var i = t.childNodes, o = '', a = '', s = !1, l = 0;\n              l < i.length;\n              ++l\n            ) {\n              var c = i[l];\n              c == e.element\n                ? (s = !0)\n                : '#text' === c.nodeName &&\n                  (s ? (a += c.nodeValue) : (o += c.nodeValue),\n                  t.removeChild(c),\n                  --l);\n            }\n            if (e.element.children.length && Prism.plugins.KeepMarkup) {\n              var u = o + e.element.innerHTML + a;\n              ((e.element.innerHTML = n.normalize(u, e.settings)),\n                (e.code = e.element.textContent));\n            } else\n              ((e.code = o + e.code + a),\n                (e.code = n.normalize(e.code, e.settings)));\n          }\n        }\n      })));\n})();\n"
  },
  {
    "path": "shepherd.js/test/cypress/examples/css/no-css-import.html",
    "content": "<html>\n  <head>\n    <script type=\"module\">\n      import Shepherd from '../../../../dist/js/shepherd.mjs';\n      window.Shepherd = Shepherd;\n    </script>\n  </head>\n\n  <body>\n    <div\n      data-test-id=\"fake-modal-overlay\"\n      class=\"shepherd-modal-overlay-container\"\n    >\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "shepherd.js/test/cypress/examples/css/with-css-import.html",
    "content": "<html>\n  <head>\n    <link\n      rel=\"stylesheet\"\n      href=\"../../../../dist/css/shepherd.css\"\n    />\n    <script type=\"module\">\n      import Shepherd from '../../../../dist/js/shepherd.mjs';\n      window.Shepherd = Shepherd;\n    </script>\n  </head>\n\n  <body>\n    <div\n      data-test-id=\"fake-modal-overlay\"\n      class=\"shepherd-modal-overlay-container\"\n    >\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "shepherd.js/test/cypress/examples/destroying-elements.html",
    "content": "<html>\n  <head>\n    <link\n      rel=\"stylesheet\"\n      href=\"../../../dist/css/shepherd.css\"\n    />\n    <script type=\"module\">\n      import Shepherd from '../../../dist/js/shepherd.mjs';\n      window.Shepherd = Shepherd;\n    </script>\n  </head>\n\n  <body>\n    <style>\n      h1,\n      h2 {\n        font-family: Lato;\n      }\n\n      .first,\n      .second {\n        position: absolute;\n\n        display: inline-block;\n        padding: 50px;\n        background: red;\n      }\n\n      .second {\n        right: 0;\n        background: blue;\n      }\n    </style>\n\n    <div class=\"first\">First</div>\n    <div class=\"second\">Second</div>\n  </body>\n</html>\n"
  },
  {
    "path": "shepherd.js/test/cypress/integration/a11y.cy.js",
    "content": "import setupTour from '../utils/setup-tour';\n\ndescribe('a11y', () => {\n  let Shepherd;\n\n  beforeEach(() => {\n    Shepherd = null;\n\n    cy.visit('/test/cypress/dummy/', {\n      onLoad(contentWindow) {\n        if (contentWindow.Shepherd) {\n          return (Shepherd = contentWindow.Shepherd);\n        }\n      }\n    });\n  });\n\n  describe('focus', () => {\n    let tour;\n\n    beforeEach(() => {\n      tour = setupTour(Shepherd, {}, null, {\n        useModalOverlay: true\n      });\n    });\n\n    afterEach(() => {\n      tour.complete();\n    });\n\n    it('shepherd-element should have focus on tour start', () => {\n      tour.start();\n\n      cy.document().then(() => {\n        cy.wait(1000);\n        cy.get('.shepherd-element').should('have.focus');\n      });\n    });\n  });\n\n  describe('focus trapping', () => {\n    let tour;\n\n    beforeEach(() => {\n      // Remove extra elements to prevent scrolling issues\n      cy.document().then((document) => {\n        const heroFollowup = document.querySelector('.hero-followup');\n        heroFollowup?.remove();\n        const img = document.querySelector('img');\n        img?.remove();\n      });\n    });\n\n    afterEach(() => {\n      tour?.complete();\n    });\n\n    describe('without attachTo element', () => {\n      beforeEach(() => {\n        // Create a tour without attachTo elements\n        tour = new Shepherd.Tour({\n          defaultStepOptions: {\n            classes: 'shepherd-theme-arrows',\n            scrollTo: true\n          }\n        });\n\n        tour.addStep({\n          title: 'Test Step',\n          text: 'Testing focus trap without attachTo',\n          buttons: [\n            {\n              text: 'Cancel',\n              classes: 'shepherd-button-secondary cancel-button',\n              action: tour.cancel\n            },\n            {\n              text: 'Back',\n              classes: 'shepherd-button-secondary back-button',\n              action: tour.back\n            },\n            {\n              text: 'Next',\n              classes: 'shepherd-button-primary next-button',\n              action: tour.next\n            }\n          ],\n          cancelIcon: {\n            enabled: true\n          }\n        });\n      });\n\n      it('tabs forward through dialog elements and wraps to first', () => {\n        tour.start();\n\n        cy.document().then(() => {\n          cy.wait(1000);\n          // Start should focus the dialog\n          cy.get('.shepherd-element').should('have.focus');\n\n          // Tab through dialog elements - start from body to get consistent behavior\n          cy.focused().tab(); // to close button\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n\n          cy.focused().tab(); // to cancel button\n          cy.get('.cancel-button').should('have.focus');\n\n          cy.focused().tab(); // to back button\n          cy.get('.back-button').should('have.focus');\n\n          cy.focused().tab(); // to next button\n          cy.get('.next-button').should('have.focus');\n\n          // Tab from last button should wrap to first (close button)\n          cy.focused().tab();\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n        });\n      });\n\n      it('tabs backward through dialog elements and wraps to last', () => {\n        tour.start();\n\n        cy.document().then(() => {\n          cy.wait(1000);\n          // Start at close button\n          cy.focused().tab();\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n\n          // Shift+tab should wrap to last button\n          cy.focused().tab({ shift: true });\n          cy.get('.next-button').should('have.focus');\n\n          // Continue shift+tabbing backward\n          cy.focused().tab({ shift: true });\n          cy.get('.back-button').should('have.focus');\n\n          cy.focused().tab({ shift: true });\n          cy.get('.cancel-button').should('have.focus');\n\n          cy.focused().tab({ shift: true });\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n        });\n      });\n\n      it('prevents focus from escaping to page elements', () => {\n        tour.start();\n\n        cy.document().then(() => {\n          cy.wait(1000);\n          // Start at close button\n          cy.get('body').tab();\n\n          // Try to tab out of modal multiple times\n          cy.focused().tab().tab().tab().tab().tab().tab();\n\n          // Should still be within dialog elements\n          cy.focused().should('satisfy', ($el) => {\n            return $el.closest('.shepherd-element').length > 0;\n          });\n        });\n      });\n    });\n\n    describe('with attachTo element', () => {\n      beforeEach(() => {\n        tour = setupTour(Shepherd, {}, null, {\n          useModalOverlay: true\n        });\n      });\n\n      it('includes attachTo element in focus trap and tabs in correct order', () => {\n        tour.start();\n\n        cy.document().then(() => {\n          cy.wait(1000);\n\n          // First tab must be from body to enter focus trap\n          cy.focused().tab(); // to close button\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n\n          cy.focused().tab();\n          cy.get('[data-test-popper-link]').should('have.focus');\n\n          cy.focused().tab();\n          cy.get('.cancel-button').should('have.focus');\n\n          cy.focused().tab();\n          cy.get('.next-button').should('have.focus');\n\n          // Tab from last dialog element should go to attachTo element\n          cy.focused().tab();\n          cy.get('.hero-welcome').should('have.focus');\n\n          // Tab from attachTo should go back to first dialog element\n          cy.focused().tab();\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n        });\n      });\n\n      it('handles backward tabbing with attachTo element', () => {\n        tour.start();\n\n        cy.document().then(() => {\n          cy.wait(1000);\n\n          // First tab from body to enter focus trap\n          cy.focused().tab();\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n\n          // Shift+tab from first dialog element should go to attachTo\n          cy.focused().tab({ shift: true });\n          cy.get('.hero-welcome').should('have.focus');\n\n          // Shift+tab from attachTo should go to last dialog element\n          cy.focused().tab({ shift: true });\n          cy.get('.next-button').should('have.focus');\n\n          // Continue shift+tabbing backward through dialog\n          cy.focused().tab({ shift: true });\n          cy.get('.cancel-button').should('have.focus');\n\n          cy.focused().tab({ shift: true });\n          cy.get('[data-test-popper-link]').should('have.focus');\n\n          cy.focused().tab({ shift: true });\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n        });\n      });\n\n      it('maintains focus trap boundaries with attachTo element', () => {\n        tour.start();\n\n        cy.document().then(() => {\n          cy.wait(1000);\n\n          cy.get('body')\n            .tab()\n            .tab()\n            .tab()\n            .tab()\n            .tab()\n            .tab()\n            .tab()\n            .tab()\n            .tab()\n            .tab();\n\n          // Should still be within dialog or attachTo element\n          cy.focused().should('satisfy', ($el) => {\n            const isInDialog = $el.closest('.shepherd-element').length > 0;\n            const isAttachTo = $el.is('.hero-welcome');\n            return isInDialog || isAttachTo;\n          });\n        });\n      });\n\n      it('handles attachTo element with focusable children', () => {\n        tour = new Shepherd.Tour({\n          defaultStepOptions: {\n            cancelIcon: {\n              enabled: true\n            },\n            classes: 'shepherd-theme-arrows',\n            scrollTo: true\n          },\n          useModalOverlay: true\n        });\n\n        tour.addStep({\n          title: 'Complex AttachTo Test',\n          text: 'Testing with complex attachTo element',\n          attachTo: {\n            element: '#complex-attach-to',\n            on: 'bottom'\n          },\n          buttons: [\n            {\n              text: 'Next',\n              classes: 'next-button',\n              action: tour.next\n            }\n          ]\n        });\n\n        tour.start();\n\n        cy.document().then(() => {\n          cy.wait(1000);\n\n          cy.focused().tab();\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n\n          cy.focused().tab();\n          cy.get('.next-button').should('have.focus');\n\n          // Tab to attachTo elements\n          cy.focused().tab();\n          cy.get('#complex-attach-to').should('have.focus'); // Parent first\n\n          cy.focused().tab();\n          cy.get('#nested-button-1').should('have.focus');\n\n          cy.focused().tab();\n          cy.get('#nested-input').should('have.focus');\n\n          cy.focused().tab();\n          cy.get('#nested-button-2').should('have.focus');\n\n          // Tab from last attachTo child should go back to dialog\n          cy.focused().tab();\n          cy.get('.shepherd-cancel-icon').should('have.focus');\n        });\n\n        // Clean up the test element\n        cy.get('#complex-attach-to').then(($el) => {\n          $el.remove();\n        });\n      });\n    });\n  });\n\n  describe('keydown events', () => {\n    let tour;\n\n    beforeEach(() => {\n      tour = setupTour(Shepherd, {}, null, {\n        useModalOverlay: true\n      });\n\n      // Remove extra elements to prevent scrolling issues\n      cy.document().then((document) => {\n        const heroFollowup = document.querySelector('.hero-followup');\n        heroFollowup?.remove();\n        const img = document.querySelector('img');\n        img?.remove();\n      });\n    });\n\n    afterEach(() => {\n      tour.complete();\n    });\n\n    it('arrows trigger back/next', () => {\n      tour.start();\n\n      cy.get('.first-step').should('be.visible');\n      cy.get('.first-step').trigger('keydown', { keyCode: 39 });\n      cy.get('.second-step').should('be.visible');\n      cy.get('.second-step').trigger('keydown', { keyCode: 37 });\n      cy.get('.first-step').should('be.visible');\n    });\n\n    it('ESC cancels the tour', () => {\n      tour.start();\n\n      cy.get('.shepherd-element').should('have.attr', 'data-shepherd-step-id');\n      cy.get('.shepherd-element').trigger('keydown', { keyCode: 27 });\n      cy.get('.shepherd-element').should('not.exist');\n    });\n\n    it('Tab is focus trapped inside the modal', () => {\n      tour.start();\n\n      cy.document().then(() => {\n        cy.wait(1000);\n        // Tabbing out of the modal should not be possible and we test this by tabbing from the body\n        cy.get('body').tab().tab().tab().tab().tab().tab();\n        cy.get('.hero-welcome').should('have.focus');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/cypress/integration/css.cy.js",
    "content": "/*\n * The `.shepherd-modal-overlay-container` class is chosen for inspection\n * because the Svelte styles for the modal are added to the import graph as\n * soon as Shepherd's JS is imported at all:\n *\n * shepherd.ts -> tour.ts -> components/shepherd-modal.svelte\n */\ndescribe('CSS Import Behavior', () => {\n  it('includes project styles when explicitly imported', () => {\n    cy.visit('/test/cypress/examples/css/with-css-import');\n    cy.window().should('have.property', 'Shepherd');\n    cy.get('[data-test-id=\"fake-modal-overlay\"]').should(\n      'have.css',\n      'pointer-events',\n      'none'\n    );\n  });\n\n  it('DOES NOT include project styles without explicit import', () => {\n    cy.visit('/test/cypress/examples/css/no-css-import');\n    cy.window().should('have.property', 'Shepherd');\n    cy.get('[data-test-id=\"fake-modal-overlay\"]').should(\n      'not.have.css',\n      'pointer-events',\n      'none'\n    );\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/cypress/integration/destroying-elements.cy.js",
    "content": "import setupTour from '../utils/setup-tour';\n\ndescribe('destroying-elements', () => {\n  let Shepherd;\n\n  beforeEach(() => {\n    Shepherd = null;\n\n    cy.visit('/test/cypress/examples/destroying-elements', {\n      onLoad(contentWindow) {\n        if (contentWindow.Shepherd) {\n          return (Shepherd = contentWindow.Shepherd);\n        }\n      }\n    });\n  });\n\n  it('recalculates positioning when element is removed and added', () => {\n    const steps = () => {\n      return [\n        {\n          attachTo: { element: '.first', on: 'bottom' },\n          id: 'first',\n          title: 'First step',\n          text: 'this is fine the first time'\n        },\n        {\n          attachTo: { element: '.second', on: 'bottom' },\n          id: 'second',\n          title: 'Second step',\n          text: 'Please click the destroy button and then the create button. After the First element is created, please click back'\n        }\n      ];\n    };\n\n    const tour = setupTour(\n      Shepherd,\n      {\n        cancelIcon: {\n          enabled: false\n        }\n      },\n      steps\n    );\n\n    tour.start();\n\n    cy.wait(250);\n\n    let initialPosition;\n    let missingStepElementPosition;\n    let finalPosition;\n\n    cy.get('[data-shepherd-step-id=\"first\"]')\n      .then((stepElement) => {\n        initialPosition = stepElement.css(['position', 'top', 'left']);\n        tour.next();\n\n        return cy.get('.first');\n      })\n      .then((firstElement) => {\n        // Remove the first element\n        firstElement.remove();\n\n        tour.back();\n        cy.wait(250);\n\n        return cy.get('[data-shepherd-step-id=\"first\"]');\n      })\n      .then((stepElement2) => {\n        missingStepElementPosition = stepElement2.css([\n          'position',\n          'top',\n          'left'\n        ]);\n        expect(missingStepElementPosition).to.not.deep.equal(initialPosition);\n\n        tour.next();\n\n        return cy.document();\n      })\n      .then((document) => {\n        // Create the first element again\n        const first = document.createElement('div');\n        first.className = 'first';\n        first.textContent = 'First';\n        document.body.appendChild(first);\n\n        tour.back();\n\n        cy.wait(250);\n\n        return cy.get('[data-shepherd-step-id=\"first\"]');\n      })\n      .then((stepElement3) => {\n        finalPosition = stepElement3.css(['position', 'top', 'left']);\n        expect(finalPosition).to.deep.equal(initialPosition);\n      });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/cypress/integration/element-targeting.cy.js",
    "content": "import setupTour from '../utils/setup-tour';\n\ndescribe('Attaching tooltips to target elements in the DOM on each step', () => {\n  let Shepherd;\n\n  beforeEach(() => {\n    Shepherd = null;\n\n    cy.visit('/test/cypress/dummy/', {\n      onLoad(contentWindow) {\n        if (contentWindow.Shepherd) {\n          return (Shepherd = contentWindow.Shepherd);\n        }\n      }\n    });\n  });\n\n  describe('Adding/Removing class names to the target of the current step', () => {\n    let tour;\n\n    beforeEach(() => {\n      tour = setupTour(Shepherd);\n    });\n\n    afterEach(() => {\n      tour.complete();\n    });\n\n    it('Adds the \"shepherd-target\" and \"shepherd-enabled\" classes upon showing a step', () => {\n      tour.start();\n\n      cy.get('[data-test-hero-welcome]')\n        .should('have.class', 'shepherd-target')\n        .and('have.class', 'shepherd-enabled');\n    });\n\n    it('Removes the \"shepherd-target\" and \"shepherd-enabled\" upon hiding a step', () => {\n      tour.start();\n      tour.next();\n\n      cy.get('[data-test-hero-welcome]')\n        .should('not.have.class', 'shepherd-target')\n        .and('not.have.class', 'shepherd-enabled');\n    });\n  });\n\n  describe('Unique selectors with multiple Tours', function () {\n    let firstTour, secondTour;\n\n    beforeEach(() => {\n      firstTour = setupTour(Shepherd, {}, null, {\n        tourName: 'firstTour',\n        defaultStepOptions: {\n          classes: 'tour-test-1'\n        }\n      });\n      // setup a second tour with a unique name\n      secondTour = setupTour(Shepherd, {}, null, {\n        tourName: 'secondTour',\n        defaultStepOptions: {\n          classes: 'tour-test-2'\n        }\n      });\n    });\n\n    afterEach(() => {\n      firstTour.complete();\n      secondTour.complete();\n    });\n    it('applies default classes only on each individual tour', async function () {\n      firstTour.start();\n      secondTour.start();\n\n      cy.get('.shepherd-element').should('have.length', 2);\n      cy.get('.test-tour-1.shepherd-element').should('have.length', 1);\n      cy.get('.test-tour-2.shepherd-element').should('have.length', 1);\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/cypress/integration/modal.cy.js",
    "content": "import setupTour from '../utils/setup-tour';\nimport { expect } from 'chai';\n\ndescribe('Modal mode', () => {\n  let Shepherd, tour;\n\n  beforeEach(() => {\n    Shepherd = null;\n\n    cy.visit('/test/cypress/dummy/', {\n      onLoad(contentWindow) {\n        if (contentWindow.Shepherd) {\n          return (Shepherd = contentWindow.Shepherd);\n        }\n      }\n    });\n  });\n\n  afterEach(() => {\n    tour.complete();\n  });\n\n  describe('Modal enabled', () => {\n    beforeEach(() => {\n      tour = setupTour(Shepherd, {}, null, {\n        useModalOverlay: true\n      });\n    });\n\n    it('Displaying the modal during tours when modal mode is enabled', () => {\n      tour.start();\n\n      cy.get('.shepherd-modal-overlay-container').should(\n        'have.css',\n        'opacity',\n        '0.5'\n      );\n      cy.get('.shepherd-modal-overlay-container').should(\n        'have.class',\n        'shepherd-modal-is-visible'\n      );\n    });\n  });\n\n  describe('Modal disabled', () => {\n    beforeEach(() => {\n      tour = setupTour(Shepherd, {}, null, {\n        useModalOverlay: false\n      });\n    });\n\n    it('Hiding the modal during tours when modal mode is not enabled', () => {\n      tour.start();\n\n      cy.get('.shepherd-modal-overlay-container').should(\n        'have.css',\n        'opacity',\n        '0'\n      );\n      cy.get('.shepherd-modal-overlay-container').should(\n        'not.have.class',\n        'shepherd-modal-is-visible'\n      );\n    });\n  });\n\n  describe('hide', () => {\n    beforeEach(() => {\n      tour = setupTour(Shepherd, {}, null, { useModalOverlay: true });\n    });\n\n    it('removes shepherd-modal-is-visible class from the overlay', () => {\n      tour.start();\n      cy.get('.shepherd-modal-overlay-container')\n        .should('have.class', 'shepherd-modal-is-visible')\n        .then(() => {\n          tour.hide();\n        });\n      cy.get('.shepherd-modal-overlay-container').should(\n        'not.have.class',\n        'shepherd-modal-is-visible'\n      );\n    });\n  });\n\n  describe('highlight', () => {\n    const steps = () => {\n      return [\n        {\n          attachTo: {\n            element: '.hero-welcome',\n            on: 'bottom'\n          },\n          highlightClass: 'highlight',\n          id: 'test-highlight',\n          text: 'Testing highlight'\n        }\n      ];\n    };\n\n    beforeEach(() => {\n      tour = setupTour(Shepherd, {}, steps, {\n        useModalOverlay: true\n      });\n    });\n\n    it('applying highlight classes to the target element', () => {\n      tour.start();\n\n      expect(tour.getCurrentStep().target.classList.contains('highlight')).to.be\n        .true;\n    });\n  });\n\n  describe('Modal with multiple Tours', function () {\n    it('only activates one SVG overall', async function () {\n      const steps = [\n        {\n          id: 'test',\n          title: 'This is a test step for our tour'\n        },\n        {\n          id: 'test-2',\n          title: 'This is a second test step for our tour'\n        }\n      ];\n      tour = setupTour(Shepherd, {}, steps, {\n        tourName: 'firstTour',\n        useModalOverlay: true\n      });\n      // setup a second tour with a unique name\n      setupTour(Shepherd, {}, null, {\n        tourName: 'secondTour'\n      });\n      tour.start();\n\n      cy.get('.shepherd-modal-overlay-container').should('have.length', 2);\n      cy.get('.shepherd-modal-is-visible').should('have.length', 1);\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/cypress/integration/test.acceptance.cy.js",
    "content": "import setupTour from '../utils/setup-tour';\nimport { assert } from 'chai';\n\nlet Shepherd;\n\ndescribe('Shepherd Acceptance Tests', () => {\n  beforeEach(() => {\n    Shepherd = null;\n\n    cy.visit('/test/cypress/dummy/', {\n      onLoad(contentWindow) {\n        if (contentWindow.Shepherd) {\n          return (Shepherd = contentWindow.Shepherd);\n        }\n      }\n    });\n  });\n\n  describe('Step options', () => {\n    describe('attachTo', () => {\n      it('works with selectors', () => {\n        const steps = () => {\n          return [\n            {\n              text: 'Shepherd is a JavaScript library',\n              attachTo: {\n                element: '.hero-welcome',\n                on: 'bottom'\n              },\n              classes: 'shepherd shepherd-transparent-text',\n              id: 'welcome'\n            }\n          ];\n        };\n\n        const tour = setupTour(\n          Shepherd,\n          {\n            cancelIcon: {\n              enabled: false\n            }\n          },\n          steps\n        );\n\n        tour.start();\n\n        // Step text should be visible\n        cy.get('.shepherd-text')\n          .contains('Shepherd is a JavaScript library')\n          .should('be.visible');\n\n        cy.document().then((document) => {\n          assert.deepEqual(\n            document.querySelector('[data-test-hero-welcome]'),\n            tour.getCurrentStep().target,\n            'hero welcome is the target'\n          );\n        });\n      });\n\n      it('works with DOM elements', () => {\n        cy.document().then((document) => {\n          const heroIncludingElement = document.querySelector(\n            '[data-test-hero-including]'\n          );\n\n          const steps = () => {\n            return [\n              {\n                title: 'Including',\n                text: 'Including Shepherd is easy!',\n                attachTo: {\n                  element: heroIncludingElement,\n                  on: 'bottom'\n                },\n                id: 'including'\n              }\n            ];\n          };\n          const tour = setupTour(\n            Shepherd,\n            {\n              cancelIcon: {\n                enabled: false\n              }\n            },\n            steps\n          );\n          tour.start();\n          // Step text should be visible\n          cy.get('.shepherd-text')\n            .contains('Including Shepherd is easy!')\n            .should('be.visible');\n          assert.deepEqual(\n            heroIncludingElement,\n            tour.getCurrentStep().target,\n            'heroIncludingElement is the target'\n          );\n        });\n      });\n\n      it('works with functions returning DOM elements', () => {\n        cy.document().then((document) => {\n          const steps = () => {\n            return [\n              {\n                text: 'You may provide function returning DOM node references.',\n                attachTo: {\n                  element: () =>\n                    document.querySelector('[data-test-hero-including]'),\n                  on: 'bottom'\n                },\n                id: 'including'\n              }\n            ];\n          };\n          const tour = setupTour(\n            Shepherd,\n            {\n              cancelIcon: {\n                enabled: false\n              }\n            },\n            steps\n          );\n          tour.start();\n          // Step text should be visible\n          cy.get('.shepherd-text')\n            .contains('You may provide function returning DOM node references.')\n            .should('be.visible');\n          assert.deepEqual(\n            document.querySelector('[data-test-hero-including]'),\n            tour.getCurrentStep().target,\n            'heroIncludingElement is the target'\n          );\n        });\n      });\n\n      it('works with functions returning selectors', () => {\n        cy.document().then((document) => {\n          const steps = () => {\n            return [\n              {\n                text: 'You may provide functions returning selectors.',\n                attachTo: {\n                  element: () => '[data-test-hero-including]',\n                  on: 'bottom'\n                },\n                id: 'including'\n              }\n            ];\n          };\n          const tour = setupTour(\n            Shepherd,\n            {\n              cancelIcon: {\n                enabled: false\n              }\n            },\n            steps\n          );\n          tour.start();\n          // Step text should be visible\n          cy.get('.shepherd-text')\n            .contains('You may provide functions returning selectors.')\n            .should('be.visible');\n          assert.deepEqual(\n            document.querySelector('[data-test-hero-including]'),\n            tour.getCurrentStep().target,\n            'heroIncludingElement is the target'\n          );\n        });\n      });\n\n      it('works with functions returning null', () => {\n        cy.document().then(() => {\n          const steps = () => {\n            return [\n              {\n                text: 'When attachTo.element callback returns null, the step is centered.',\n                attachTo: {\n                  element: () => null,\n                  on: 'bottom'\n                },\n                id: 'including'\n              }\n            ];\n          };\n          const tour = setupTour(\n            Shepherd,\n            {\n              cancelIcon: {\n                enabled: false\n              }\n            },\n            steps\n          );\n          tour.start();\n          // Step text should be visible\n          cy.get('.shepherd-text')\n            .contains(\n              'When attachTo.element callback returns null, the step is centered.'\n            )\n            .should('be.visible');\n          cy.document().then(() => {\n            assert.deepEqual(\n              null,\n              tour.getCurrentStep().target,\n              'target is null'\n            );\n          });\n        });\n      });\n\n      it('works when undefined', () => {\n        const steps = () => {\n          return [\n            {\n              id: 'undefined-attachto',\n              title: 'Undefined attachTo',\n              text: 'When attachTo is undefined, the step is centered.'\n            }\n          ];\n        };\n        const tour = setupTour(\n          Shepherd,\n          {\n            cancelIcon: {\n              enabled: false\n            }\n          },\n          steps\n        );\n        tour.start();\n        // Step text should be visible\n        cy.get('.shepherd-text')\n          .contains('When attachTo is undefined, the step is centered.')\n          .should('be.visible');\n        cy.document().then(() => {\n          assert.deepEqual(\n            undefined,\n            tour.getCurrentStep().target,\n            'target is undefined'\n          );\n        });\n      });\n\n      it('works with selectors that do not exist in the DOM', () => {\n        const steps = () => {\n          return [\n            {\n              text: 'When attachTo.element selector is not present in the DOM, the step is centered.',\n              attachTo: {\n                element: '.does-not-exist',\n                on: 'bottom'\n              },\n              classes: 'shepherd shepherd-transparent-text',\n              id: 'welcome'\n            }\n          ];\n        };\n\n        const tour = setupTour(\n          Shepherd,\n          {\n            cancelIcon: {\n              enabled: false\n            }\n          },\n          steps\n        );\n\n        tour.start();\n\n        // Step text should be visible\n        cy.get('.shepherd-text')\n          .contains(\n            'When attachTo.element selector is not present in the DOM, the step is centered.'\n          )\n          .should('be.visible');\n        cy.document().then(() => {\n          assert.deepEqual(\n            null,\n            tour.getCurrentStep().target,\n            'target is undefined'\n          );\n        });\n      });\n\n      // This tests whether we can create and start a tour containing steps attached to elements that do not yet exist.\n      // We create the element between steps to simulate step target rendering upon user action.\n\n      it('correctly attaches to multiple lazily-evaluated elements', () => {\n        cy.document().then((document) => {\n          const steps = () => {\n            return [\n              {\n                text: 'foo'\n              },\n              {\n                text: 'bar',\n                attachTo: {\n                  element: () => document.querySelector('#bar'),\n                  on: 'bottom'\n                },\n                id: 'bar'\n              },\n              {\n                text: 'baz',\n                attachTo: {\n                  element: () => document.querySelector('.baz'),\n                  on: 'bottom'\n                },\n                id: 'baz'\n              }\n            ];\n          };\n\n          const tour = setupTour(\n            Shepherd,\n            {\n              cancelIcon: {\n                enabled: false\n              }\n            },\n            steps\n          );\n\n          tour.start();\n\n          const barTarget = document.createElement('div');\n          barTarget.setAttribute('id', 'bar');\n          document\n            .querySelector('[data-test-hero-including]')\n            .appendChild(barTarget);\n\n          const bazTarget = document.createElement('div');\n          bazTarget.setAttribute('class', 'baz');\n          bazTarget.setAttribute('id', 'baz');\n          document\n            .querySelector('[data-test-hero-including]')\n            .appendChild(bazTarget);\n\n          const quxTarget = document.createElement('div');\n          quxTarget.setAttribute('class', 'baz');\n          quxTarget.setAttribute('id', 'qux');\n          document\n            .querySelector('[data-test-hero-including]')\n            .appendChild(quxTarget);\n\n          tour.next();\n\n          cy.get('[data-shepherd-step-id=\"bar\"] .shepherd-text')\n            .then(() => {\n              cy.get('[data-shepherd-step-id=\"bar\"] .shepherd-text')\n                .contains('bar')\n                .should('be.visible');\n              assert.deepEqual(\n                document.querySelector('#bar'),\n                tour.getCurrentStep().target,\n                '#bar is the target'\n              );\n            })\n            .then(() => {\n              tour.next();\n            });\n\n          cy.get('[data-shepherd-step-id=\"baz\"] .shepherd-text')\n            .then(() => {\n              cy.get('[data-shepherd-step-id=\"baz\"] .shepherd-text')\n                .contains('baz')\n                .should('be.visible');\n              assert.deepEqual(\n                document.querySelector('#baz'),\n                tour.getCurrentStep().target,\n                '#baz is the target'\n              );\n            })\n            .then(() => {\n              bazTarget.remove();\n            })\n            .then(() => {\n              cy.get('[data-shepherd-step-id=\"baz\"] .shepherd-text')\n                .contains('baz')\n                .should('be.visible');\n              cy.get('.shepherd-element').should('have.focus');\n              assert.deepEqual(\n                tour.getCurrentStep()._getResolvedAttachToOptions().on,\n                'bottom',\n                'Resolved attachTo on is maintained'\n              );\n            });\n        });\n      });\n\n      it('correctly attaches to lazily-evaluated elements', () => {\n        cy.document().then((document) => {\n          const steps = () => {\n            return [\n              {\n                text: 'Dummy step'\n              },\n              {\n                text: 'Lazy target evaluation works too!',\n                attachTo: {\n                  element: () => document.querySelector('#lazyTarget'), // this element does not yet exist\n                  on: 'bottom'\n                },\n                id: 'lazyStep'\n              }\n            ];\n          };\n\n          const tour = setupTour(\n            Shepherd,\n            {\n              cancelIcon: {\n                enabled: false\n              }\n            },\n            steps\n          );\n\n          tour.start();\n\n          const lazyTarget = document.createElement('div');\n          lazyTarget.setAttribute('id', 'lazyTarget');\n          // Append to the hero so that the element is in viewport when running the test\n          document\n            .querySelector('[data-test-hero-including]')\n            .appendChild(lazyTarget);\n\n          cy.wait(250);\n\n          tour.next();\n\n          // Step text should be visible\n          cy.get('[data-shepherd-step-id=\"lazyStep\"] .shepherd-text')\n            .contains('Lazy target evaluation works too!')\n            .should('be.visible');\n          assert.deepEqual(\n            document.querySelector('#lazyTarget'),\n            tour.getCurrentStep().target,\n            '#dummyTarget is the target'\n          );\n        });\n      });\n    });\n\n    describe('buttons', () => {\n      beforeEach(() => {\n        // This is a hack removing the extra page elements so the page does not scroll. Cypress hates scrolling for some reason.\n        cy.document().then((document) => {\n          const heroFollowup = document.querySelector('.hero-followup');\n          heroFollowup.remove();\n          const img = document.querySelector('img');\n          img.remove();\n        });\n      });\n\n      it('next/previous buttons work', () => {\n        const tour = setupTour(Shepherd);\n        tour.start();\n\n        // Step one text should be visible\n        cy.get('.shepherd-text')\n          .contains('Shepherd is a JavaScript library')\n          .should('exist')\n          .and('be.visible');\n\n        // Click next\n        cy.contains('Next').click();\n\n        // Step two text should be visible\n        cy.get('.shepherd-text')\n          .contains('Including Shepherd is easy!')\n          .should('exist')\n          .and('be.visible');\n\n        // Click back\n        cy.contains('Back').click();\n\n        // Step one text should be visible again\n        cy.get('.shepherd-text')\n          .contains('Shepherd is a JavaScript library')\n          .should('exist')\n          .and('be.visible');\n      });\n    });\n\n    describe('Cancel Link', () => {\n      beforeEach(() => {\n        // This is a hack removing the extra page elements so the page does not scroll. Cypress hates scrolling for some reason.\n        cy.document().then((document) => {\n          const heroFollowup = document.querySelector('.hero-followup');\n          heroFollowup.remove();\n          const img = document.querySelector('img');\n          img.remove();\n        });\n      });\n\n      it('Cancel link cancels the tour', () => {\n        const tour = setupTour(Shepherd);\n        tour.start();\n        cy.get('.shepherd-element').should(\n          'have.attr',\n          'data-shepherd-step-id'\n        );\n        cy.get('.shepherd-cancel-icon').click();\n        cy.get('.shepherd-element').should('not.exist');\n      });\n\n      it('Cancel link cancels the tour from another step', () => {\n        const tour = setupTour(Shepherd);\n        tour.start();\n        cy.get('.shepherd-element').should(\n          'have.attr',\n          'data-shepherd-step-id'\n        );\n        // Click next\n        cy.contains('Next').click();\n        // Step two text should be visible\n        cy.get('.shepherd-text')\n          .contains('Including Shepherd is easy!')\n          .should('be.visible');\n        cy.get('.shepherd-cancel-icon:nth-child(2)').click();\n        cy.get('.shepherd-element').should('not.exist');\n      });\n\n      it('Hides cancel link', () => {\n        const tour = setupTour(Shepherd, {\n          cancelIcon: {\n            enabled: false\n          }\n        });\n        tour.start();\n        cy.get('.shepherd-cancel-icon').should('not.exist');\n      });\n\n      it('Shows cancel link', () => {\n        const tour = setupTour(Shepherd);\n        tour.start();\n        cy.get('.shepherd-cancel-icon').should('be.visible');\n      });\n    });\n\n    it('Default classes applied', () => {\n      const tour = setupTour(Shepherd, {\n        classes: 'test-defaults test-more-defaults'\n      });\n      tour.start();\n\n      cy.get('.shepherd-element').should('have.class', 'test-defaults');\n      cy.get('.shepherd-element').should('have.class', 'test-more-defaults');\n    });\n\n    describe('scrolling', () => {\n      it('scrollTo:true scrolls', () => {\n        cy.scrollTo(0, 0);\n        const tour = setupTour(Shepherd, {\n          scrollTo: true\n        });\n        tour.start();\n        cy.document().get('body').should('have.prop', 'scrollTop').and('eq', 0);\n        tour.next();\n        cy.document().get('body').should('have.prop', 'scrollTop').and('gt', 0);\n      });\n\n      it('scrollTo:false does not scroll', () => {\n        cy.scrollTo(0, 0);\n        const tour = setupTour(Shepherd, {\n          scrollTo: false\n        });\n        tour.start();\n        cy.document().get('body').should('have.prop', 'scrollTop').and('eq', 0);\n        tour.next();\n        cy.document().get('body').should('have.prop', 'scrollTop').and('eq', 0);\n      });\n\n      it('scrollTo:scrollIntoViewOptions scrolls with options', () => {\n        const scrollIntoViewOptions = {\n          behavior: 'smooth',\n          block: 'center',\n          inline: 'nearest'\n        };\n\n        const calculateCenteredScrollTop = (target) =>\n          target.offsetTop -\n          target.offsetParent.offsetHeight / 2 +\n          target.clientHeight / 2;\n\n        const tour = setupTour(\n          Shepherd,\n          {\n            scrollTo: scrollIntoViewOptions\n          },\n          null,\n          {\n            useModalOverlay: true\n          }\n        );\n\n        // start the tour and skip a few steps ahead, so we scroll down the page a bit\n        tour.start();\n        tour.next();\n        tour.next();\n        tour.next();\n\n        cy.get('.hero-followup')\n          .then((element) => calculateCenteredScrollTop(element[0]))\n          .then((scrollTop) => {\n            const plusOrMinusPx = 10;\n            cy.window()\n              .its('scrollY')\n              .should('be.closeTo', scrollTop, plusOrMinusPx);\n          });\n      });\n    });\n\n    describe('arrow padding', () => {\n      it('uses provided arrow padding', () => {\n        const tour = setupTour(Shepherd, {}, () => [\n          {\n            text: 'Test',\n            attachTo: {\n              element: '.hero-example',\n              on: 'left-end'\n            },\n            arrow: true,\n            classes:\n              'shepherd-step-element shepherd-transparent-text first-step',\n            id: 'welcome'\n          }\n        ]);\n\n        tour.start();\n        cy.wait(250);\n\n        cy.get('[data-shepherd-step-id=\"welcome\"] .shepherd-arrow').then(\n          (arrowElement) => {\n            const finalPosition = arrowElement.css(['top']);\n            expect(finalPosition).to.deep.equal({ top: '4px' });\n          }\n        );\n      });\n\n      it('uses a default arrow padding if not provided', () => {\n        const tour = setupTour(Shepherd, {}, () => [\n          {\n            text: 'Test',\n            attachTo: {\n              element: '.hero-example',\n              on: 'left-end'\n            },\n            arrow: { padding: 10 },\n            classes:\n              'shepherd-step-element shepherd-transparent-text first-step',\n            id: 'welcome'\n          }\n        ]);\n        tour.start();\n        cy.wait(250);\n\n        cy.get('[data-shepherd-step-id=\"welcome\"] .shepherd-arrow').then(\n          (arrowElement) => {\n            const finalPosition = arrowElement.css(['top']);\n            expect(finalPosition).to.deep.equal({ top: '10px' });\n          }\n        );\n      });\n    });\n  });\n\n  describe('Steps: rendering', () => {\n    describe('waiting for activation before creating and showing a step tooltip', () => {\n      it('renders no steps before the tour has started', () => {\n        cy.get('.shepherd-step-element').should('not.exist');\n      });\n\n      it('renders a step when the tour has started', () => {\n        const tour = setupTour(Shepherd);\n\n        tour.start();\n\n        cy.get('.shepherd-step-element').should('exist');\n        cy.get('.shepherd-step-element').should('have.length', 1);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/cypress/support/commands.js",
    "content": "// ***********************************************\n// This example commands.js shows you how to\n// create various custom commands and overwrite\n// existing commands.\n//\n// For more comprehensive examples of custom\n// commands please read more here:\n// https://on.cypress.io/custom-commands\n// ***********************************************\n//\n//\n// -- This is a parent command --\n// Cypress.Commands.add(\"login\", (email, password) => { ... })\n//\n//\n// -- This is a child command --\n// Cypress.Commands.add(\"drag\", { prevSubject: 'element'}, (subject, options) => { ... })\n//\n//\n// -- This is a dual command --\n// Cypress.Commands.add(\"dismiss\", { prevSubject: 'optional'}, (subject, options) => { ... })\n//\n//\n// -- This is will overwrite an existing command --\n// Cypress.Commands.overwrite(\"visit\", (originalFn, url, options) => { ... })\n"
  },
  {
    "path": "shepherd.js/test/cypress/support/index.js",
    "content": "require('cypress-plugin-tab');\n\n// ***********************************************************\n// This example support/index.js is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\n// Import commands.js using ES2015 syntax:\nimport './commands';\n\n// Alternatively you can use CommonJS syntax:\n// require('./commands')\n"
  },
  {
    "path": "shepherd.js/test/cypress/utils/default-buttons.js",
    "content": "export default {\n  cancel: {\n    classes: 'shepherd-button-secondary cancel-button',\n    text: 'Exit',\n    type: 'cancel'\n  },\n  next: {\n    classes: 'shepherd-button-primary next-button',\n    text: 'Next',\n    type: 'next'\n  },\n  back: {\n    classes: 'shepherd-button-primary back-button',\n    text: 'Back',\n    type: 'back'\n  }\n};\n"
  },
  {
    "path": "shepherd.js/test/cypress/utils/default-steps.js",
    "content": "export default function (shepherd) {\n  return [\n    {\n      text: `\n         <p>\n           Shepherd is a JavaScript library for guiding users through your app.\n           It uses <a href=\"https://floating-ui.com/\" data-test-popper-link>Floating UI</a>,\n           another open source library, to render dialogs for each tour \"step\".\n         </p>\n        \n         <p>\n           Among many things, Floating UI makes sure your steps never end up off screen or cropped by an overflow.\n           (Try resizing your browser to see what we mean.)\n         </p>`,\n      attachTo: {\n        element: '.hero-welcome',\n        on: 'bottom'\n      },\n      classes: 'shepherd-step-element shepherd-transparent-text first-step',\n      buttons: [\n        {\n          action: shepherd.cancel,\n          classes: 'shepherd-button-secondary cancel-button',\n          text: 'Exit'\n        },\n        {\n          action: shepherd.next,\n          classes: 'shepherd-button-example-primary next-button',\n          text: 'Next'\n        }\n      ],\n      id: 'welcome'\n    },\n    {\n      title: 'Including',\n      text: 'Including Shepherd is easy! Just include shepherd.js. The styles are bundled with the JS.',\n      attachTo: {\n        element: '.hero-including',\n        on: 'bottom'\n      },\n      buttons: [\n        {\n          action: shepherd.back,\n          classes: 'shepherd-button-secondary back-button',\n          text: 'Back'\n        },\n        {\n          action: shepherd.next,\n          classes: 'shepherd-button-example-primary next-button',\n          text: 'Next'\n        }\n      ],\n      id: 'including',\n      classes: 'shepherd-step-element second-step'\n    },\n    {\n      title: 'Example Shepherd',\n      text: 'Creating a Shepherd is easy too! Just create Shepherd and add as many steps as you want. Check out the <a href=\"https://shepherdjs.dev/docs/\">documentation</a> to learn more.',\n      attachTo: {\n        element: '.hero-example',\n        on: 'bottom'\n      },\n      buttons: [\n        {\n          action: shepherd.back,\n          classes: 'shepherd-button-secondary back-button',\n          text: 'Back'\n        },\n        {\n          action: shepherd.next,\n          classes: 'shepherd-button-example-primary next-button',\n          text: 'Next'\n        }\n      ],\n      id: 'example',\n      classes: 'shepherd-step-element third-step'\n    },\n    {\n      title: 'Learn more',\n      text: 'Star Shepherd on Github so you remember it for your next project',\n      attachTo: {\n        element: '.hero-followup',\n        on: 'left'\n      },\n      buttons: [\n        {\n          action: shepherd.back,\n          classes: 'shepherd-button-secondary back-button',\n          text: 'Back'\n        },\n        {\n          action: shepherd.next,\n          classes: 'shepherd-button-example-primary next-button',\n          text: 'Done'\n        }\n      ],\n      id: 'followup',\n      classes: 'shepherd-step-element fourth-step'\n    }\n  ];\n}\n"
  },
  {
    "path": "shepherd.js/test/cypress/utils/setup-tour.js",
    "content": "import defaultSteps from './default-steps';\n\n/**\n * Setup a tour\n * @param {Shepherd} Shepherd The Shepherd instance\n * @param {Object} globalDefaults A hash of the `defaultStepOptions`\n * @param {function} customSteps An array of the steps to add to the tour\n * @param {Object} otherOptions A hash of other options to pass to Shepherd\n */\nexport default function (Shepherd, globalDefaults, customSteps, otherOptions) {\n  const defaultStepOptions = Object.assign(\n    {},\n    {\n      cancelIcon: {\n        enabled: true\n      }\n    },\n    globalDefaults\n  );\n\n  const shepherdOptions = Object.assign(\n    {},\n    {\n      defaultStepOptions\n    },\n    otherOptions\n  );\n\n  const shepherd = new Shepherd.Tour(shepherdOptions);\n\n  const steps =\n    typeof customSteps === 'function'\n      ? customSteps(shepherd)\n      : defaultSteps(shepherd);\n\n  shepherd.addSteps(steps);\n\n  return shepherd;\n}\n"
  },
  {
    "path": "shepherd.js/test/unit/babel.config.cjs",
    "content": "module.exports = function (api) {\n  api.cache(true);\n\n  return {\n    env: {\n      development: {\n        presets: [\n          [\n            '@babel/preset-env',\n            {\n              loose: true\n            }\n          ]\n        ]\n      },\n      test: {\n        presets: [\n          ['@babel/preset-env', { targets: { node: 'current' } }],\n          ['@babel/preset-typescript', { allowDeclareFields: true }]\n        ]\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-button.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it } from 'vitest';\nimport { createShepherdButton } from '../../../src/components/shepherd-button.ts';\n\ndescribe('component/ShepherdButton', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  describe('disabled', () => {\n    it('should be enabled by default', () => {\n      const button = createShepherdButton({}, undefined);\n      container.appendChild(button);\n\n      expect(button.disabled).toBeFalsy();\n    });\n\n    it('is enabled when false', () => {\n      const button = createShepherdButton({ disabled: false }, undefined);\n      container.appendChild(button);\n\n      expect(button.disabled).toBeFalsy();\n    });\n\n    it('can be disabled with boolean', () => {\n      const button = createShepherdButton({ disabled: true }, undefined);\n      container.appendChild(button);\n\n      expect(button.disabled).toBeTruthy();\n    });\n\n    it('can be disabled with function', () => {\n      const button = createShepherdButton({ disabled: () => true }, undefined);\n      container.appendChild(button);\n\n      expect(button.disabled).toBeTruthy();\n    });\n  });\n\n  describe('label', () => {\n    it('string', () => {\n      const button = createShepherdButton({ label: 'Test' }, undefined);\n      container.appendChild(button);\n\n      expect(button).toHaveAttribute('aria-label', 'Test');\n    });\n\n    it('number', () => {\n      const button = createShepherdButton({ label: 5 }, undefined);\n      container.appendChild(button);\n\n      expect(button).toHaveAttribute('aria-label', '5');\n    });\n\n    it('function', () => {\n      const button = createShepherdButton({ label: () => 'Test' }, undefined);\n      container.appendChild(button);\n\n      expect(button).toHaveAttribute('aria-label', 'Test');\n    });\n\n    it('function re-creation uses updated value', () => {\n      let label = 'Test';\n      const button = createShepherdButton({ label: () => label }, undefined);\n      container.appendChild(button);\n      expect(button).toHaveAttribute('aria-label', 'Test');\n\n      label = 'Test 2';\n      const buttonUpdated = createShepherdButton(\n        { label: () => label },\n        undefined\n      );\n      container.appendChild(buttonUpdated);\n      expect(buttonUpdated).toHaveAttribute('aria-label', 'Test 2');\n    });\n\n    it('null', () => {\n      const button = createShepherdButton({ label: null }, undefined);\n      container.appendChild(button);\n\n      expect(button).not.toHaveAttribute('aria-label');\n    });\n\n    it('undefined', () => {\n      const button = createShepherdButton({}, undefined);\n      container.appendChild(button);\n\n      expect(button).not.toHaveAttribute('aria-label');\n    });\n  });\n\n  describe('text', () => {\n    it('string', () => {\n      const button = createShepherdButton({ text: 'Test' }, undefined);\n      container.appendChild(button);\n\n      expect(button).toHaveTextContent('Test');\n    });\n\n    it('function', () => {\n      const button = createShepherdButton({ text: () => 'Test' }, undefined);\n      container.appendChild(button);\n\n      expect(button).toHaveTextContent('Test');\n    });\n\n    it('function re-creation uses updated value', () => {\n      let text = 'Test';\n      const button = createShepherdButton({ text: () => text }, undefined);\n      container.appendChild(button);\n      expect(button).toHaveTextContent('Test');\n\n      text = 'Test 2';\n      const buttonUpdated = createShepherdButton(\n        { text: () => text },\n        undefined\n      );\n      container.appendChild(buttonUpdated);\n      expect(buttonUpdated).toHaveTextContent('Test 2');\n    });\n  });\n\n  describe('attrs', () => {\n    it('applies single data attribute', () => {\n      const button = createShepherdButton(\n        {\n          attrs: { 'data-test': 'my-button' }\n        },\n        undefined\n      );\n      container.appendChild(button);\n\n      expect(button).toHaveAttribute('data-test', 'my-button');\n    });\n\n    it('applies multiple custom attributes', () => {\n      const button = createShepherdButton(\n        {\n          attrs: {\n            'data-test': 'my-button',\n            'data-step': '1',\n            'data-analytics': 'click-event',\n            title: 'Click me'\n          }\n        },\n        undefined\n      );\n      container.appendChild(button);\n\n      expect(button).toHaveAttribute('data-test', 'my-button');\n      expect(button).toHaveAttribute('data-step', '1');\n      expect(button).toHaveAttribute('data-analytics', 'click-event');\n      expect(button).toHaveAttribute('title', 'Click me');\n    });\n\n    it('converts number and boolean values to strings', () => {\n      const button = createShepherdButton(\n        {\n          attrs: {\n            'data-count': 42,\n            'data-enabled': true,\n            'data-rate': 3.14\n          }\n        },\n        undefined\n      );\n      container.appendChild(button);\n\n      expect(button).toHaveAttribute('data-count', '42');\n      expect(button).toHaveAttribute('data-enabled', 'true');\n      expect(button).toHaveAttribute('data-rate', '3.14');\n    });\n\n    it('does not override core button attributes', () => {\n      const mockAction = () => {};\n      const mockStep = { tour: {} };\n      const button = createShepherdButton(\n        {\n          text: 'Next',\n          classes: 'my-class',\n          disabled: true,\n          label: 'Next Step',\n          action: mockAction,\n          attrs: {\n            type: 'submit', // Should NOT override\n            class: 'wrong-class', // Should NOT override\n            disabled: false, // Should NOT override\n            'aria-label': 'Wrong Label', // Should NOT override\n            tabindex: '5', // Should NOT override\n            'data-test': 'next-btn' // SHOULD apply\n          }\n        },\n        mockStep\n      );\n      container.appendChild(button);\n\n      // Core attributes should be protected\n      expect(button).toHaveAttribute('type', 'button');\n      expect(button.className).toContain('shepherd-button');\n      expect(button.className).toContain('my-class');\n      expect(button.disabled).toBeTruthy();\n      expect(button).toHaveAttribute('aria-label', 'Next Step');\n      expect(button).toHaveAttribute('tabindex', '0');\n\n      // Non-conflicting custom attribute should work\n      expect(button).toHaveAttribute('data-test', 'next-btn');\n    });\n\n    it('works with empty attrs object', () => {\n      const button = createShepherdButton({ attrs: {} }, undefined);\n      container.appendChild(button);\n\n      expect(button).toBeInTheDocument();\n      expect(button).toHaveAttribute('type', 'button');\n      expect(button.className).toContain('shepherd-button');\n    });\n\n    it('works with undefined attrs', () => {\n      const button = createShepherdButton({}, undefined);\n      container.appendChild(button);\n\n      expect(button).toBeInTheDocument();\n      expect(button).toHaveAttribute('type', 'button');\n    });\n\n    it('works alongside all other button properties', () => {\n      const mockAction = () => {};\n      const mockStep = { tour: {} };\n      const button = createShepherdButton(\n        {\n          text: 'Next Step',\n          label: 'Proceed forward',\n          classes: 'custom-class',\n          secondary: true,\n          disabled: false,\n          action: mockAction,\n          attrs: {\n            'data-test': 'next-btn',\n            'data-step-id': '5',\n            id: 'my-button-id'\n          }\n        },\n        mockStep\n      );\n      container.appendChild(button);\n\n      expect(button).toHaveTextContent('Next Step');\n      expect(button).toHaveAttribute('aria-label', 'Proceed forward');\n      expect(button.className).toContain('custom-class');\n      expect(button.className).toContain('shepherd-button-secondary');\n      expect(button.disabled).toBeFalsy();\n      expect(button).toHaveAttribute('data-test', 'next-btn');\n      expect(button).toHaveAttribute('data-step-id', '5');\n      expect(button).toHaveAttribute('id', 'my-button-id');\n    });\n\n    it('handles special characters in attribute values', () => {\n      const button = createShepherdButton(\n        {\n          attrs: {\n            'data-text': 'Hello \"World\"',\n            'data-path': '/api/v1/test',\n            'data-symbol': '<>&'\n          }\n        },\n        undefined\n      );\n      container.appendChild(button);\n\n      expect(button).toHaveAttribute('data-text', 'Hello \"World\"');\n      expect(button).toHaveAttribute('data-path', '/api/v1/test');\n      expect(button).toHaveAttribute('data-symbol', '<>&');\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-content.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it } from 'vitest';\nimport { createShepherdContent } from '../../../src/components/shepherd-content.ts';\n\ndescribe('components/ShepherdContent', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  describe('header', () => {\n    it('is rendered when title is present and cancelIcon is enabled', () => {\n      const step = {\n        options: {\n          title: 'I am some test title.',\n          cancelIcon: {\n            enabled: true\n          }\n        }\n      };\n\n      const el = createShepherdContent('test-desc', 'test-label', step);\n      container.appendChild(el);\n\n      expect(\n        container.querySelector('.shepherd-content .shepherd-header')\n      ).toBeInTheDocument();\n    });\n\n    it('is rendered when title is present', () => {\n      const step = {\n        options: {\n          title: 'I am some test title.'\n        }\n      };\n\n      const el = createShepherdContent('test-desc', 'test-label', step);\n      container.appendChild(el);\n\n      expect(\n        container.querySelector('.shepherd-content .shepherd-header')\n      ).toBeInTheDocument();\n    });\n\n    it('is rendered when cancelIcon is enabled', () => {\n      const step = {\n        options: {\n          cancelIcon: {\n            enabled: true\n          }\n        }\n      };\n\n      const el = createShepherdContent('test-desc', 'test-label', step);\n      container.appendChild(el);\n\n      expect(\n        container.querySelector('.shepherd-content .shepherd-header')\n      ).toBeInTheDocument();\n    });\n\n    it('is not rendered when title is not present and cancelIcon is disabled', () => {\n      const step = {\n        options: {\n          title: undefined\n        }\n      };\n\n      const el = createShepherdContent('test-desc', 'test-label', step);\n      container.appendChild(el);\n\n      expect(\n        container.querySelector('.shepherd-header')\n      ).not.toBeInTheDocument();\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-element.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport { createShepherdElement } from '../../../src/components/shepherd-element.ts';\nimport { Step } from '../../../src/step';\nimport { Tour } from '../../../src/tour';\n\nfunction fireKeyDown(el, keyCode, opts = {}) {\n  el.dispatchEvent(\n    new KeyboardEvent('keydown', { keyCode, bubbles: true, ...opts })\n  );\n}\n\ndescribe('components/ShepherdElement', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  describe('arrow', () => {\n    it('arrows shown by default', () => {\n      const testElement = document.createElement('div');\n      const tour = new Tour();\n      const step = new Step(tour, {\n        attachTo: { element: testElement, on: 'top' }\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      expect(\n        container.querySelectorAll('.shepherd-element .shepherd-arrow').length\n      ).toBe(1);\n\n      cleanup();\n    });\n\n    it('arrow: false hides arrows', () => {\n      const testElement = document.createElement('div');\n      const tour = new Tour();\n      const step = new Step(tour, {\n        arrow: false,\n        attachTo: { element: testElement, on: 'top' }\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      expect(\n        container.querySelectorAll('.shepherd-element .shepherd-arrow').length\n      ).toBe(0);\n\n      cleanup();\n    });\n\n    it('arrow: object with padding shows arrow', () => {\n      const testElement = document.createElement('div');\n      const tour = new Tour();\n      const step = new Step(tour, {\n        arrow: { padding: 10 },\n        attachTo: { element: testElement, on: 'top' }\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      expect(\n        container.querySelectorAll('.shepherd-element .shepherd-arrow').length\n      ).toBe(1);\n\n      cleanup();\n    });\n\n    it('arrow: empty object shows arrow', () => {\n      const testElement = document.createElement('div');\n      const tour = new Tour();\n      const step = new Step(tour, {\n        arrow: {},\n        attachTo: { element: testElement, on: 'top' }\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      expect(\n        container.querySelectorAll('.shepherd-element .shepherd-arrow').length\n      ).toBe(1);\n\n      cleanup();\n    });\n  });\n\n  describe('handleKeyDown', () => {\n    it('exitOnEsc: true - ESC cancels the tour', () => {\n      const tour = new Tour();\n      const step = new Step(tour, {});\n      const stepCancelSpy = vi.spyOn(step, 'cancel');\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      fireKeyDown(element, 27);\n      expect(stepCancelSpy).toHaveBeenCalled();\n\n      cleanup();\n    });\n\n    it('exitOnEsc: false - ESC does not cancel the tour', () => {\n      const tour = new Tour({ exitOnEsc: false });\n      const step = new Step(tour, {});\n      const stepCancelSpy = vi.spyOn(step, 'cancel');\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      fireKeyDown(element, 27);\n      expect(stepCancelSpy).not.toHaveBeenCalled();\n\n      cleanup();\n    });\n\n    it('keyboardNavigation: true - arrow keys move between steps', () => {\n      const tour = new Tour();\n      const step = new Step(tour, {});\n      let propagateValue = 0;\n\n      const tourBackStub = vi.spyOn(tour, 'back').mockImplementation(() => {});\n      const tourNextStub = vi.spyOn(tour, 'next').mockImplementation(() => {});\n\n      // Add a keystroke listener to a parent to test event propagation\n      const propagateHandler = (event) => {\n        if ([27, 37, 39].includes(event.keyCode)) {\n          propagateValue += 1;\n        }\n      };\n      document.body.addEventListener('keydown', propagateHandler);\n\n      expect(tourBackStub).not.toHaveBeenCalled();\n      expect(tourNextStub).not.toHaveBeenCalled();\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      fireKeyDown(element, 39);\n      expect(tourNextStub).toHaveBeenCalled();\n      // There should be no event propagation\n      expect(propagateValue).toBe(0);\n\n      fireKeyDown(element, 37);\n      expect(tourBackStub).toHaveBeenCalled();\n      // There should be no event propagation\n      expect(propagateValue).toBe(0);\n\n      tourBackStub.mockRestore();\n      tourNextStub.mockRestore();\n      document.body.removeEventListener('keydown', propagateHandler);\n      cleanup();\n    });\n\n    it('keyboardNavigation: false - arrow keys do not move between steps', () => {\n      const tour = new Tour({ keyboardNavigation: false });\n      const step = new Step(tour, {});\n      let propagateValue = 0;\n\n      const tourBackStub = vi.spyOn(tour, 'back').mockImplementation(() => {});\n      const tourNextStub = vi.spyOn(tour, 'next').mockImplementation(() => {});\n\n      // Add a keystroke listener to a parent to test event propagation\n      const propagateHandler = (event) => {\n        if ([27, 37, 39].includes(event.keyCode)) {\n          propagateValue += 1;\n        }\n      };\n      document.body.addEventListener('keydown', propagateHandler);\n\n      expect(tourBackStub).not.toHaveBeenCalled();\n      expect(tourNextStub).not.toHaveBeenCalled();\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      fireKeyDown(element, 39);\n      expect(tourNextStub).not.toHaveBeenCalled();\n      // There should be event propagation\n      expect(propagateValue).toBe(1);\n\n      fireKeyDown(element, 37);\n      expect(tourBackStub).not.toHaveBeenCalled();\n      // There should be another event propagation\n      expect(propagateValue).toBe(2);\n\n      tourBackStub.mockRestore();\n      tourNextStub.mockRestore();\n      document.body.removeEventListener('keydown', propagateHandler);\n      cleanup();\n    });\n\n    it('Tab key: prevents default when no focusable elements exist', () => {\n      const tour = new Tour();\n      // Step with no buttons, no cancel icon — dialog has no focusable children\n      const step = new Step(tour, {});\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      const prevented = [];\n      element.addEventListener(\n        'keydown',\n        (e) => {\n          prevented.push(e.defaultPrevented);\n        },\n        { capture: false }\n      );\n\n      fireKeyDown(element, 9, { cancelable: true });\n      expect(prevented[0]).toBe(true);\n\n      cleanup();\n    });\n\n    it('Shift+Tab from first dialog element focuses last attachTo element', () => {\n      const tour = new Tour();\n      const attachToEl = document.createElement('div');\n      const attachToBtn = document.createElement('button');\n      attachToBtn.textContent = 'Attach Button';\n      attachToEl.appendChild(attachToBtn);\n      container.appendChild(attachToEl);\n\n      const step = new Step(tour, {\n        attachTo: { element: attachToEl, on: 'bottom' },\n        buttons: [{ text: 'Next', action: () => {} }]\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      // First focusable dialog element is the \"Next\" button\n      const dialogBtn = element.querySelector('button.shepherd-button');\n      expect(dialogBtn).toBeTruthy();\n      dialogBtn.focus();\n\n      const focusSpy = vi.spyOn(attachToBtn, 'focus');\n      fireKeyDown(element, 9, { shiftKey: true });\n      // The last focusable attachTo element (attachToBtn) should be focused\n      expect(focusSpy).toHaveBeenCalled();\n\n      focusSpy.mockRestore();\n      cleanup();\n    });\n\n    it('Shift+Tab from first attachTo element focuses last dialog element', () => {\n      const tour = new Tour();\n      const attachToEl = document.createElement('button');\n      attachToEl.textContent = 'Target';\n      container.appendChild(attachToEl);\n\n      const step = new Step(tour, {\n        attachTo: { element: attachToEl, on: 'bottom' },\n        buttons: [{ text: 'Next', action: () => {} }]\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      // Focus the attachTo element (first focusable attach-to element)\n      attachToEl.focus();\n\n      const dialogBtn = element.querySelector('button.shepherd-button');\n      const focusSpy = vi.spyOn(dialogBtn, 'focus');\n      // Fire on the attachTo element since it also has the keydown listener\n      fireKeyDown(attachToEl, 9, { shiftKey: true });\n      expect(focusSpy).toHaveBeenCalled();\n\n      focusSpy.mockRestore();\n      cleanup();\n    });\n\n    it('forward Tab from last dialog element focuses first attachTo element', () => {\n      const tour = new Tour();\n      const attachToEl = document.createElement('button');\n      attachToEl.textContent = 'Target';\n      container.appendChild(attachToEl);\n\n      const step = new Step(tour, {\n        attachTo: { element: attachToEl, on: 'bottom' },\n        buttons: [{ text: 'Next', action: () => {} }]\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      // Focus the last dialog element (the button)\n      const dialogBtn = element.querySelector('button.shepherd-button');\n      dialogBtn.focus();\n\n      const focusSpy = vi.spyOn(attachToEl, 'focus');\n      fireKeyDown(element, 9);\n      // First focusable attachTo element should receive focus\n      expect(focusSpy).toHaveBeenCalled();\n\n      focusSpy.mockRestore();\n      cleanup();\n    });\n\n    it('forward Tab from last attachTo element focuses first dialog element', () => {\n      const tour = new Tour();\n      const attachToEl = document.createElement('button');\n      attachToEl.textContent = 'Target';\n      container.appendChild(attachToEl);\n\n      const step = new Step(tour, {\n        attachTo: { element: attachToEl, on: 'bottom' },\n        buttons: [{ text: 'Next', action: () => {} }]\n      });\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      // Focus the last attachTo element (the button itself, since it's the only one)\n      attachToEl.focus();\n\n      const dialogBtn = element.querySelector('button.shepherd-button');\n      const focusSpy = vi.spyOn(dialogBtn, 'focus');\n      // Fire on the attachTo element\n      fireKeyDown(attachToEl, 9);\n      expect(focusSpy).toHaveBeenCalled();\n\n      focusSpy.mockRestore();\n      cleanup();\n    });\n\n    it('unhandled key falls through to default case', () => {\n      const tour = new Tour();\n      const step = new Step(tour, {});\n\n      const { element, cleanup } = createShepherdElement({\n        descriptionId: 'test-desc',\n        labelId: 'test-label',\n        step\n      });\n      container.appendChild(element);\n\n      // Press an unrelated key (e.g. 'A' = keyCode 65) and ensure nothing breaks\n      fireKeyDown(element, 65);\n      // No error thrown, element is still in DOM\n      expect(element.parentNode).toBe(container);\n\n      cleanup();\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-footer.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it } from 'vitest';\nimport { createShepherdFooter } from '../../../src/components/shepherd-footer.ts';\nimport defaultButtons from '../../cypress/utils/default-buttons.js';\n\ndescribe('components/ShepherdFooter', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  it('renders no buttons if an empty array is passed to `options.buttons`', () => {\n    const step = {\n      options: {\n        buttons: []\n      }\n    };\n\n    const el = createShepherdFooter(step);\n    container.appendChild(el);\n\n    const buttons = container.querySelectorAll(\n      '.shepherd-footer .shepherd-button'\n    );\n    expect(buttons.length).toBe(0);\n  });\n\n  it('renders no buttons if nothing is passed to `options.buttons`', () => {\n    const step = { options: {} };\n\n    const el = createShepherdFooter(step);\n    container.appendChild(el);\n\n    const buttons = container.querySelectorAll(\n      '.shepherd-footer .shepherd-button'\n    );\n    expect(buttons.length).toBe(0);\n  });\n\n  it('renders buttons for each item passed to `options.buttons`', () => {\n    const step = {\n      options: {\n        buttons: [defaultButtons.cancel, defaultButtons.next]\n      }\n    };\n\n    const el = createShepherdFooter(step);\n    container.appendChild(el);\n\n    const buttons = container.querySelectorAll(\n      '.shepherd-footer .shepherd-button'\n    );\n    expect(buttons.length).toBe(2);\n\n    const cancelButton = container.querySelector('footer .cancel-button');\n    expect(cancelButton).toHaveAttribute('tabindex', '0');\n    expect(cancelButton).toHaveClass(\n      'shepherd-button-secondary cancel-button shepherd-button'\n    );\n    expect(cancelButton).toHaveTextContent('Exit');\n\n    const nextButton = container.querySelector('footer .next-button');\n    expect(nextButton).toHaveAttribute('tabindex', '0');\n    expect(nextButton).toHaveClass(\n      'shepherd-button-primary next-button shepherd-button'\n    );\n    expect(nextButton).toHaveTextContent('Next');\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-header.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport { createShepherdHeader } from '../../../src/components/shepherd-header.ts';\nimport { Tour } from '../../../src/tour';\nimport { Step } from '../../../src/step';\n\ndescribe('components/ShepherdHeader', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  it('cancel icon is added when cancelIcon.enabled === true', () => {\n    const step = {\n      options: {\n        cancelIcon: {\n          enabled: true\n        }\n      }\n    };\n\n    const el = createShepherdHeader('test-label', step);\n    container.appendChild(el);\n\n    const cancelIcon = container.querySelector('.shepherd-cancel-icon');\n    expect(cancelIcon).toBeInTheDocument();\n    expect(cancelIcon).toHaveAttribute('aria-label', 'Close Tour');\n    expect(cancelIcon).toHaveAttribute('type', 'button');\n  });\n\n  it('cancel icon is not added when cancelIcon.enabled === false', () => {\n    const step = {\n      options: {\n        cancelIcon: {\n          enabled: false\n        }\n      }\n    };\n\n    const el = createShepherdHeader('test-label', step);\n    container.appendChild(el);\n\n    const cancelIcon = container.querySelector('.shepherd-cancel-icon');\n\n    expect(cancelIcon).not.toBeInTheDocument();\n  });\n\n  it('cancel icon aria-label overridden when cancelIcon.label is set', () => {\n    const step = {\n      options: {\n        cancelIcon: {\n          enabled: true,\n          label: 'Test'\n        }\n      }\n    };\n\n    const el = createShepherdHeader('test-label', step);\n    container.appendChild(el);\n\n    expect(container.querySelector('.shepherd-cancel-icon')).toHaveAttribute(\n      'aria-label',\n      'Test'\n    );\n  });\n\n  it('cancel icon cancels the tour', async () => {\n    const tour = new Tour();\n    const step = new Step(tour, {\n      cancelIcon: {\n        enabled: true\n      }\n    });\n    const stepCancelSpy = vi.spyOn(step, 'cancel');\n\n    const el = createShepherdHeader('test-label', step);\n    container.appendChild(el);\n\n    container.querySelector('.shepherd-cancel-icon').click();\n    expect(stepCancelSpy).toHaveBeenCalled();\n  });\n\n  describe('cancel icon attrs', () => {\n    it('applies custom attributes to cancel icon', () => {\n      const step = {\n        options: {\n          cancelIcon: {\n            enabled: true,\n            attrs: {\n              'data-test': 'close-tour',\n              'data-analytics': 'tour-cancel'\n            }\n          }\n        }\n      };\n\n      const el = createShepherdHeader('test-label', step);\n      container.appendChild(el);\n\n      const cancelIcon = container.querySelector('.shepherd-cancel-icon');\n      expect(cancelIcon).toHaveAttribute('data-test', 'close-tour');\n      expect(cancelIcon).toHaveAttribute('data-analytics', 'tour-cancel');\n    });\n\n    it('cancel icon attrs work with custom label', () => {\n      const step = {\n        options: {\n          cancelIcon: {\n            enabled: true,\n            label: 'Custom Close',\n            attrs: {\n              'data-test': 'custom-close',\n              id: 'tour-close-btn'\n            }\n          }\n        }\n      };\n\n      const el = createShepherdHeader('test-label', step);\n      container.appendChild(el);\n\n      const cancelIcon = container.querySelector('.shepherd-cancel-icon');\n      expect(cancelIcon).toHaveAttribute('aria-label', 'Custom Close');\n      expect(cancelIcon).toHaveAttribute('data-test', 'custom-close');\n      expect(cancelIcon).toHaveAttribute('id', 'tour-close-btn');\n    });\n\n    it('cancel icon does not override core attributes via attrs', () => {\n      const step = {\n        options: {\n          cancelIcon: {\n            enabled: true,\n            label: 'Close',\n            attrs: {\n              type: 'submit', // Should NOT override\n              class: 'wrong-class', // Should NOT override\n              'aria-label': 'Wrong Label', // Should NOT override\n              'data-test': 'close-btn' // SHOULD apply\n            }\n          }\n        }\n      };\n\n      const el = createShepherdHeader('test-label', step);\n      container.appendChild(el);\n\n      const cancelIcon = container.querySelector('.shepherd-cancel-icon');\n      expect(cancelIcon).toHaveAttribute('type', 'button');\n      expect(cancelIcon).toHaveClass('shepherd-cancel-icon');\n      expect(cancelIcon).toHaveAttribute('aria-label', 'Close');\n      expect(cancelIcon).toHaveAttribute('data-test', 'close-btn');\n    });\n\n    it('cancel icon works with empty attrs', () => {\n      const step = {\n        options: {\n          cancelIcon: {\n            enabled: true,\n            attrs: {}\n          }\n        }\n      };\n\n      const el = createShepherdHeader('test-label', step);\n      container.appendChild(el);\n\n      const cancelIcon = container.querySelector('.shepherd-cancel-icon');\n      expect(cancelIcon).toBeInTheDocument();\n      expect(cancelIcon).toHaveAttribute('type', 'button');\n    });\n\n    it('cancel icon handles numeric and boolean attrs values', () => {\n      const step = {\n        options: {\n          cancelIcon: {\n            enabled: true,\n            attrs: {\n              'data-count': 5,\n              'data-active': true\n            }\n          }\n        }\n      };\n\n      const el = createShepherdHeader('test-label', step);\n      container.appendChild(el);\n\n      const cancelIcon = container.querySelector('.shepherd-cancel-icon');\n      expect(cancelIcon).toHaveAttribute('data-count', '5');\n      expect(cancelIcon).toHaveAttribute('data-active', 'true');\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-modal.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport { createShepherdModal } from '../../../src/components/shepherd-modal.ts';\nimport { Step } from '../../../src/step';\nimport { Tour } from '../../../src/tour';\n\ndescribe('components/ShepherdModal', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  describe('closeModalOpening()', function () {\n    it('sets values back to 0', () => {\n      const modal = createShepherdModal(container);\n\n      modal.positionModal(0, 0, 0, 0, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 20,\n            y: 20,\n            width: 500\n          };\n        }\n      });\n\n      let modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM20,20a0,0,0,0,0-0,0V270a0,0,0,0,0,0,0H520a0,0,0,0,0,0-0V20a0,0,0,0,0-0-0Z'\n      );\n\n      modal.closeModalOpening();\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n    });\n  });\n\n  describe('positionModal()', function () {\n    it('sets the correct attributes when positioning modal opening', () => {\n      const modal = createShepherdModal(container);\n\n      let modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n\n      modal.closeModalOpening();\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n\n      modal.positionModal(0, 0, 0, 0, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 20,\n            y: 20,\n            width: 500\n          };\n        }\n      });\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM20,20a0,0,0,0,0-0,0V270a0,0,0,0,0,0,0H520a0,0,0,0,0,0-0V20a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('sets the correct attributes with padding', () => {\n      const modal = createShepherdModal(container);\n\n      let modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n\n      modal.positionModal(10, 0, 0, 0, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 20,\n            y: 20,\n            width: 500\n          };\n        }\n      });\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM10,10a0,0,0,0,0-0,0V280a0,0,0,0,0,0,0H530a0,0,0,0,0,0-0V10a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('sets the correct attributes when positioning modal opening with border radius as number', () => {\n      const modal = createShepherdModal(container);\n\n      let modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n\n      modal.closeModalOpening();\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n\n      modal.positionModal(0, 10, 0, 0, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 20,\n            y: 20,\n            width: 500\n          };\n        }\n      });\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM30,20a10,10,0,0,0-10,10V260a10,10,0,0,0,10,10H510a10,10,0,0,0,10-10V30a10,10,0,0,0-10-10Z'\n      );\n    });\n\n    it('sets the correct attributes when positioning modal opening with border radius as object', () => {\n      const modal = createShepherdModal(container);\n\n      let modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n\n      modal.closeModalOpening();\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM0,0a0,0,0,0,0-0,0V0a0,0,0,0,0,0,0H0a0,0,0,0,0,0-0V0a0,0,0,0,0-0-0Z'\n      );\n\n      modal.positionModal(\n        0,\n        { topLeft: 1, bottomLeft: 2, bottomRight: 3 },\n        0,\n        0,\n        null,\n        {\n          getBoundingClientRect() {\n            return {\n              height: 250,\n              x: 20,\n              y: 20,\n              width: 500\n            };\n          }\n        }\n      );\n\n      modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM21,20a1,1,0,0,0-1,1V268a2,2,0,0,0,2,2H517a3,3,0,0,0,3-3V20a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('sets the correct attributes when target is overflowing from scroll parent', () => {\n      const modal = createShepherdModal(container);\n\n      modal.positionModal(\n        0,\n        0,\n        0,\n        0,\n        {\n          getBoundingClientRect() {\n            return {\n              height: 250,\n              x: 10,\n              y: 100,\n              width: 500\n            };\n          }\n        },\n        {\n          getBoundingClientRect() {\n            return {\n              height: 500,\n              x: 10,\n              y: 10,\n              width: 500\n            };\n          }\n        }\n      );\n\n      const modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM10,100a0,0,0,0,0-0,0V350a0,0,0,0,0,0,0H510a0,0,0,0,0,0-0V100a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('sets the correct attributes when target fits inside scroll parent', () => {\n      const modal = createShepherdModal(container);\n\n      modal.positionModal(\n        0,\n        0,\n        0,\n        0,\n        {\n          getBoundingClientRect() {\n            return {\n              height: 500,\n              x: 10,\n              y: 10,\n              width: 500\n            };\n          }\n        },\n        {\n          getBoundingClientRect() {\n            return {\n              height: 250,\n              x: 10,\n              y: 100,\n              width: 500\n            };\n          }\n        }\n      );\n\n      const modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM10,100a0,0,0,0,0-0,0V350a0,0,0,0,0,0,0H510a0,0,0,0,0,0-0V100a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('allows setting an x-axis offset', () => {\n      const modal = createShepherdModal(container);\n\n      modal.positionModal(0, 0, 50, 0, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 10,\n            y: 10,\n            width: 500\n          };\n        }\n      });\n\n      let modalPath = modal.getElement().querySelector('path');\n\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM60,10a0,0,0,0,0-0,0V260a0,0,0,0,0,0,0H560a0,0,0,0,0,0-0V10a0,0,0,0,0-0-0Z'\n      );\n\n      modal.positionModal(0, 0, 100, 0, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 10,\n            y: 10,\n            width: 500\n          };\n        }\n      });\n\n      modalPath = modal.getElement().querySelector('path');\n\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM110,10a0,0,0,0,0-0,0V260a0,0,0,0,0,0,0H610a0,0,0,0,0,0-0V10a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('allows setting a y-axis offset', () => {\n      const modal = createShepherdModal(container);\n\n      modal.positionModal(0, 0, 0, 35, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 10,\n            y: 10,\n            width: 500\n          };\n        }\n      });\n\n      let modalPath = modal.getElement().querySelector('path');\n\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM10,45a0,0,0,0,0-0,0V295a0,0,0,0,0,0,0H510a0,0,0,0,0,0-0V45a0,0,0,0,0-0-0Z'\n      );\n\n      modal.positionModal(0, 0, 0, 75, null, {\n        getBoundingClientRect() {\n          return {\n            height: 250,\n            x: 10,\n            y: 10,\n            width: 500\n          };\n        }\n      });\n\n      modalPath = modal.getElement().querySelector('path');\n\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM10,85a0,0,0,0,0-0,0V335a0,0,0,0,0,0,0H510a0,0,0,0,0,0-0V85a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('sets the correct attributes with extraHighlights', () => {\n      const modal = createShepherdModal(container);\n\n      modal.positionModal(\n        0,\n        0,\n        0,\n        0,\n        null,\n        {\n          getBoundingClientRect() {\n            return {\n              height: 250,\n              x: 20,\n              y: 20,\n              width: 500\n            };\n          }\n        },\n        [\n          {\n            getBoundingClientRect() {\n              return {\n                height: 100,\n                x: 50,\n                y: 50,\n                width: 100\n              };\n            }\n          }\n        ]\n      );\n\n      const modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM20,20a0,0,0,0,0-0,0V270a0,0,0,0,0,0,0H520a0,0,0,0,0,0-0V20a0,0,0,0,0-0-0ZM50,50a0,0,0,0,0-0,0V150a0,0,0,0,0,0,0H150a0,0,0,0,0,0-0V50a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('sets the correct attributes with multiple extraHighlights', () => {\n      const modal = createShepherdModal(container);\n\n      modal.positionModal(\n        0,\n        0,\n        0,\n        0,\n        null,\n        {\n          getBoundingClientRect() {\n            return {\n              height: 250,\n              x: 20,\n              y: 20,\n              width: 500\n            };\n          }\n        },\n        [\n          {\n            getBoundingClientRect() {\n              return {\n                height: 100,\n                x: 50,\n                y: 50,\n                width: 100\n              };\n            }\n          },\n          {\n            getBoundingClientRect() {\n              return {\n                height: 50,\n                x: 200,\n                y: 200,\n                width: 50\n              };\n            }\n          }\n        ]\n      );\n\n      const modalPath = modal.getElement().querySelector('path');\n      expect(modalPath).toHaveAttribute(\n        'd',\n        'M1024,768H0V0H1024V768ZM20,20a0,0,0,0,0-0,0V270a0,0,0,0,0,0,0H520a0,0,0,0,0,0-0V20a0,0,0,0,0-0-0ZM50,50a0,0,0,0,0-0,0V150a0,0,0,0,0,0,0H150a0,0,0,0,0,0-0V50a0,0,0,0,0-0-0ZM200,200a0,0,0,0,0-0,0V250a0,0,0,0,0,0,0H250a0,0,0,0,0,0-0V200a0,0,0,0,0-0-0Z'\n      );\n    });\n\n    it('skips duplicate elements in extraHighlights', () => {\n      const modal = createShepherdModal(container);\n\n      const sharedElement = {\n        getBoundingClientRect() {\n          return {\n            height: 100,\n            x: 50,\n            y: 50,\n            width: 100,\n            top: 50,\n            bottom: 150,\n            left: 50,\n            right: 150\n          };\n        }\n      };\n\n      modal.positionModal(\n        0,\n        0,\n        0,\n        0,\n        null,\n        {\n          getBoundingClientRect() {\n            return {\n              height: 250,\n              x: 20,\n              y: 20,\n              width: 500,\n              top: 20,\n              bottom: 270,\n              left: 20,\n              right: 520\n            };\n          }\n        },\n        // Pass the same element twice — both duplicates are skipped\n        [sharedElement, sharedElement]\n      );\n\n      const modalPath = modal.getElement().querySelector('path');\n      const d = modalPath.getAttribute('d');\n      // Duplicate elements are both skipped, only the main target cutout remains\n      // Outer path close + target cutout close = 2 Z's\n      const cutouts = d.split('Z').length - 1;\n      expect(cutouts).toBe(2);\n    });\n  });\n\n  describe('setupForStep()', function () {\n    it('useModalOverlay: false hides the modal', () => {\n      const modal = createShepherdModal(container);\n      modal.show();\n      expect(modal.getElement()).toHaveClass('shepherd-modal-is-visible');\n\n      const tour = new Tour({ useModalOverlay: false });\n      const step = new Step(tour, {});\n\n      modal.setupForStep(step);\n      expect(modal.getElement()).not.toHaveClass('shepherd-modal-is-visible');\n    });\n\n    it('useModalOverlay: true shows the modal and calls _styleForStep', () => {\n      const modal = createShepherdModal(container);\n      const rafSpy = vi\n        .spyOn(window, 'requestAnimationFrame')\n        .mockImplementation(() => 1);\n\n      const targetEl = document.createElement('div');\n      container.appendChild(targetEl);\n\n      const tour = new Tour({ useModalOverlay: true });\n      const step = new Step(tour, {\n        attachTo: { element: targetEl, on: 'bottom' }\n      });\n      // Resolve attachTo so step.target is set\n      step._resolveAttachToOptions();\n      step.target = targetEl;\n\n      modal.setupForStep(step);\n\n      expect(modal.getElement()).toHaveClass('shepherd-modal-is-visible');\n      // _styleForStep calls rafLoop which calls requestAnimationFrame\n      expect(rafSpy).toHaveBeenCalled();\n\n      rafSpy.mockRestore();\n    });\n  });\n\n  describe('show/hide', function () {\n    it('show adds classes', () => {\n      const modal = createShepherdModal(container);\n\n      modal.show();\n\n      expect(modal.getElement()).toHaveClass('shepherd-modal-is-visible');\n    });\n\n    it('hide removes classes', () => {\n      const modal = createShepherdModal(container);\n      modal.show();\n\n      modal.hide();\n\n      expect(modal.getElement()).not.toHaveClass('shepherd-modal-is-visible');\n    });\n  });\n\n  describe('destroy()', function () {\n    it('removes the modal element from the DOM', () => {\n      const modal = createShepherdModal(container);\n      expect(\n        container.querySelector('.shepherd-modal-overlay-container')\n      ).toBeTruthy();\n\n      modal.destroy();\n      expect(\n        container.querySelector('.shepherd-modal-overlay-container')\n      ).toBeNull();\n    });\n  });\n\n  describe('_getScrollParent (via setupForStep)', function () {\n    it('recurses to find a scrollable parent element', () => {\n      const modal = createShepherdModal(container);\n      const rafSpy = vi\n        .spyOn(window, 'requestAnimationFrame')\n        .mockImplementation(() => 1);\n\n      // Create a scrollable parent\n      const scrollParent = document.createElement('div');\n      Object.defineProperty(scrollParent, 'scrollHeight', { value: 500 });\n      Object.defineProperty(scrollParent, 'clientHeight', { value: 200 });\n\n      container.appendChild(scrollParent);\n\n      const targetEl = document.createElement('div');\n      scrollParent.appendChild(targetEl);\n\n      // Mock getComputedStyle so the target has 'visible' overflow (not scrollable)\n      // and the scroll parent has 'auto' overflow (scrollable), forcing recursion\n      const origGetComputedStyle = window.getComputedStyle;\n      vi.spyOn(window, 'getComputedStyle').mockImplementation((el) => {\n        if (el === targetEl) {\n          return { overflowY: 'visible' };\n        }\n        if (el === scrollParent) {\n          return { overflowY: 'auto' };\n        }\n        return origGetComputedStyle(el);\n      });\n\n      const tour = new Tour({ useModalOverlay: true });\n      const step = new Step(tour, {\n        attachTo: { element: targetEl, on: 'bottom' }\n      });\n      step._resolveAttachToOptions();\n      step.target = targetEl;\n\n      // setupForStep triggers _styleForStep -> _getScrollParent\n      modal.setupForStep(step);\n\n      expect(modal.getElement()).toHaveClass('shepherd-modal-is-visible');\n\n      rafSpy.mockRestore();\n      vi.mocked(window.getComputedStyle).mockRestore();\n    });\n  });\n\n  describe('_preventModalBodyTouch (via _addStepEventListeners)', function () {\n    it('prevents default on window touchmove after setupForStep', () => {\n      const modal = createShepherdModal(container);\n      const rafSpy = vi\n        .spyOn(window, 'requestAnimationFrame')\n        .mockImplementation(() => 1);\n\n      const targetEl = document.createElement('div');\n      container.appendChild(targetEl);\n\n      const tour = new Tour({ useModalOverlay: true });\n      const step = new Step(tour, {\n        attachTo: { element: targetEl, on: 'bottom' }\n      });\n      step._resolveAttachToOptions();\n      step.target = targetEl;\n\n      modal.setupForStep(step);\n\n      // _addStepEventListeners was called, so window has a touchmove listener\n      const touchEvent = new Event('touchmove', {\n        bubbles: true,\n        cancelable: true\n      });\n      const preventSpy = vi.spyOn(touchEvent, 'preventDefault');\n      window.dispatchEvent(touchEvent);\n      expect(preventSpy).toHaveBeenCalled();\n\n      // Clean up: hide triggers _cleanupStepEventListeners which removes the listener\n      modal.hide();\n      rafSpy.mockRestore();\n    });\n  });\n\n  describe('_preventModalOverlayTouch', function () {\n    it('stops propagation on touchmove events', () => {\n      const modal = createShepherdModal(container);\n      const svgEl = modal.getElement();\n\n      const touchEvent = new Event('touchmove', {\n        bubbles: true,\n        cancelable: true\n      });\n      const stopSpy = vi.spyOn(touchEvent, 'stopPropagation');\n\n      svgEl.dispatchEvent(touchEvent);\n      expect(stopSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('_getIframeOffset (via setupForStep)', function () {\n    it('accumulates offset when element is inside an iframe', () => {\n      const modal = createShepherdModal(container);\n      const rafSpy = vi\n        .spyOn(window, 'requestAnimationFrame')\n        .mockImplementation(() => 1);\n\n      const targetEl = document.createElement('div');\n      container.appendChild(targetEl);\n\n      // Simulate the element being inside an iframe by mocking ownerDocument.defaultView\n      const fakeIframe = document.createElement('iframe');\n      Object.defineProperty(fakeIframe, 'getBoundingClientRect', {\n        value: () => ({\n          top: 10,\n          left: 20,\n          width: 100,\n          height: 100,\n          x: 20,\n          y: 10\n        })\n      });\n      Object.defineProperty(fakeIframe, 'scrollTop', { value: 5 });\n      Object.defineProperty(fakeIframe, 'scrollLeft', { value: 3 });\n\n      const fakeChildWindow = {\n        frameElement: fakeIframe,\n        parent: window\n      };\n\n      const origDescriptor = Object.getOwnPropertyDescriptor(\n        targetEl.ownerDocument,\n        'defaultView'\n      );\n      Object.defineProperty(targetEl.ownerDocument, 'defaultView', {\n        value: fakeChildWindow,\n        configurable: true\n      });\n\n      const tour = new Tour({ useModalOverlay: true });\n      const step = new Step(tour, {\n        attachTo: { element: targetEl, on: 'bottom' }\n      });\n      step._resolveAttachToOptions();\n      step.target = targetEl;\n\n      // This triggers _styleForStep -> _getIframeOffset, which should\n      // walk up through fakeChildWindow and accumulate the iframe offset\n      modal.setupForStep(step);\n\n      // Restore defaultView before any assertions (jsdom needs it for instanceof checks)\n      if (origDescriptor) {\n        Object.defineProperty(\n          targetEl.ownerDocument,\n          'defaultView',\n          origDescriptor\n        );\n      } else {\n        Object.defineProperty(targetEl.ownerDocument, 'defaultView', {\n          value: window,\n          configurable: true\n        });\n      }\n\n      expect(modal.getElement()).toHaveClass('shepherd-modal-is-visible');\n\n      rafSpy.mockRestore();\n    });\n\n    it('handles cross-origin iframe SecurityError gracefully', () => {\n      // Regression test for https://github.com/shipshapecode/shepherd/issues/3087\n      // When Shepherd is loaded in a nested cross-origin iframe, accessing\n      // window.frameElement throws a SecurityError due to Same-Origin Policy.\n      // This test ensures the error is caught and handled gracefully.\n      const modal = createShepherdModal(container);\n      const rafSpy = vi\n        .spyOn(window, 'requestAnimationFrame')\n        .mockImplementation(() => 1);\n\n      const targetEl = document.createElement('div');\n      container.appendChild(targetEl);\n\n      // Simulate a cross-origin iframe by making frameElement access throw SecurityError\n      const fakeChildWindow = {\n        get frameElement() {\n          // Simulate browser's SecurityError when accessing cross-origin frameElement\n          const error = new Error(\n            'Blocked a frame with origin \"https://example.com\" from accessing a cross-origin frame.'\n          );\n          error.name = 'SecurityError';\n          throw error;\n        },\n        parent: window\n      };\n\n      const origDescriptor = Object.getOwnPropertyDescriptor(\n        targetEl.ownerDocument,\n        'defaultView'\n      );\n      Object.defineProperty(targetEl.ownerDocument, 'defaultView', {\n        value: fakeChildWindow,\n        configurable: true\n      });\n\n      const tour = new Tour({ useModalOverlay: true });\n      const step = new Step(tour, {\n        attachTo: { element: targetEl, on: 'bottom' }\n      });\n      step._resolveAttachToOptions();\n      step.target = targetEl;\n\n      // This should NOT throw an error, even though frameElement access throws SecurityError\n      expect(() => {\n        modal.setupForStep(step);\n      }).not.toThrow();\n\n      // Restore defaultView before any assertions\n      if (origDescriptor) {\n        Object.defineProperty(\n          targetEl.ownerDocument,\n          'defaultView',\n          origDescriptor\n        );\n      } else {\n        Object.defineProperty(targetEl.ownerDocument, 'defaultView', {\n          value: window,\n          configurable: true\n        });\n      }\n\n      expect(modal.getElement()).toHaveClass('shepherd-modal-is-visible');\n\n      rafSpy.mockRestore();\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-text.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it } from 'vitest';\nimport { createShepherdText } from '../../../src/components/shepherd-text.ts';\n\ndescribe('components/ShepherdText', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  it('adds plain text to the content', () => {\n    const step = {\n      options: {\n        text: 'I am some test text.'\n      }\n    };\n\n    const el = createShepherdText('test-desc', step);\n    container.appendChild(el);\n\n    expect(container.querySelector('.shepherd-text')).toHaveTextContent(\n      'I am some test text.'\n    );\n  });\n\n  it('applies HTML element directly to content', () => {\n    const step = {\n      options: {\n        text: '<p>I am some test text.</p>'\n      }\n    };\n\n    const el = createShepherdText('test-desc', step);\n    container.appendChild(el);\n\n    expect(container.querySelector('.shepherd-text')).toContainHTML(\n      '<p>I am some test text.</p>'\n    );\n  });\n\n  it('applies the text from a function', () => {\n    const step = {\n      options: {\n        text: () => 'I am some test text.'\n      }\n    };\n\n    const el = createShepherdText('test-desc', step);\n    container.appendChild(el);\n\n    expect(container.querySelector('.shepherd-text')).toHaveTextContent(\n      'I am some test text.'\n    );\n  });\n\n  it('appends an HTMLElement when text is a DOM node', () => {\n    const paragraph = document.createElement('p');\n    paragraph.textContent = 'I am a DOM node.';\n\n    const step = {\n      options: {\n        text: paragraph\n      }\n    };\n\n    const el = createShepherdText('test-desc', step);\n    container.appendChild(el);\n\n    const textEl = container.querySelector('.shepherd-text');\n    expect(textEl.contains(paragraph)).toBe(true);\n    expect(textEl).toHaveTextContent('I am a DOM node.');\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/components/shepherd-title.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it } from 'vitest';\nimport { createShepherdTitle } from '../../../src/components/shepherd-title.ts';\n\ndescribe('components/ShepherdTitle', () => {\n  let container;\n\n  beforeEach(() => {\n    container = document.createElement('div');\n    document.body.appendChild(container);\n  });\n\n  afterEach(() => {\n    container.remove();\n  });\n\n  it('adds plain title to the content', () => {\n    const el = createShepherdTitle('test-label', 'I am some test title.');\n    container.appendChild(el);\n\n    expect(container.querySelector('.shepherd-title')).toHaveTextContent(\n      'I am some test title.'\n    );\n  });\n\n  it('applies the title from a function', () => {\n    const el = createShepherdTitle('test-label', () => 'I am some test title.');\n    container.appendChild(el);\n\n    expect(container.querySelector('.shepherd-title')).toHaveTextContent(\n      'I am some test title.'\n    );\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/evented.spec.js",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Evented } from '../../src/evented';\n\ndescribe('Evented', () => {\n  let testEvent, testOnTriggered;\n\n  beforeEach(() => {\n    testEvent = new Evented();\n    testEvent.on('testOn', () => (testOnTriggered = true));\n    testOnTriggered = false;\n  });\n\n  describe('on()', () => {\n    it('adds a new event binding', () => {\n      expect(testEvent.bindings.testOn, 'custom event added').toBeTruthy();\n    });\n  });\n\n  describe('trigger()', () => {\n    it('triggers a created event', () => {\n      testEvent.trigger('testOn');\n      expect(\n        testOnTriggered,\n        'true is returned from event trigger'\n      ).toBeTruthy();\n    });\n\n    it('passes arguments to handler functions', () => {\n      const handlerSpy = vi.fn();\n      testEvent.on('myEvent', handlerSpy);\n      testEvent.trigger('myEvent', {\n        step: { id: 'test', text: 'A step' },\n        previous: null\n      });\n      expect(handlerSpy).toHaveBeenCalledWith({\n        previous: null,\n        step: { id: 'test', text: 'A step' }\n      });\n    });\n  });\n\n  describe('off()', () => {\n    it('removes a generic event binding when no handler passed', () => {\n      testEvent.off('testOn');\n      expect(testEvent.bindings.testOn, 'custom event removed').toBeUndefined();\n    });\n\n    it('removes a specific event binding when handler is passed', () => {\n      const handler = () => {};\n      testEvent.on('testOn', handler);\n      expect(\n        testEvent.bindings.testOn.length,\n        '2 event listeners for testOn'\n      ).toBe(2);\n      testEvent.off('testOn', handler);\n      expect(\n        testEvent.bindings.testOn.length,\n        '1 event listener for testOn'\n      ).toBe(1);\n    });\n\n    it('does not remove uncreated events', () => {\n      testEvent.off('testBlank');\n      expect(\n        testEvent.bindings.testBlank,\n        'returns false for non created events'\n      ).toBeFalsy();\n    });\n  });\n\n  describe('once()', () => {\n    it('adds a new event binding that only triggers once', () => {\n      testEvent.once('testOnce', () => true);\n      testEvent.trigger('testOnce');\n      expect(\n        testEvent.bindings.testOnce,\n        'custom event removed after one trigger'\n      ).toBeTruthy();\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/server.spec.js",
    "content": "/**\n * @jest-environment node\n */\n\nimport { describe, expect, it } from 'vitest';\nimport Shepherd from '../../src/shepherd';\n\ndescribe('Server Side Render', function () {\n  describe('Tour constructor', function () {\n    it('does not start a tour when window is undefined', () => {\n      const instance = new Shepherd.Tour();\n\n      expect(instance).toBeTruthy();\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/setupTests.js",
    "content": "import { vi } from 'vitest';\nimport * as matchers from '@testing-library/jest-dom/matchers';\nimport { expect } from 'vitest';\n\nexpect.extend(matchers);\n\n// Set browser environment\nObject.defineProperty(globalThis, 'IS_BROWSER', {\n  value: true,\n  writable: false\n});\n\n// Console errors are used for user information, do not display them during\n// tests.\nglobal.console = {\n  ...console,\n  error: vi.fn()\n};\n\nglobal.sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\n// Add custom matchers for DOM testing\nif (typeof window !== 'undefined') {\n  Object.defineProperty(window, 'matchMedia', {\n    writable: true,\n    value: vi.fn().mockImplementation((query) => ({\n      matches: false,\n      media: query,\n      onchange: null,\n      addListener: vi.fn(), // deprecated\n      removeListener: vi.fn(), // deprecated\n      addEventListener: vi.fn(),\n      removeEventListener: vi.fn(),\n      dispatchEvent: vi.fn()\n    }))\n  });\n}\n"
  },
  {
    "path": "shepherd.js/test/unit/step.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport Shepherd from '../../src/shepherd';\nimport { Step } from '../../src/step';\nimport { Tour } from '../../src/tour';\nimport ResizeObserver from 'resize-observer-polyfill';\nimport { offset } from '@floating-ui/dom';\n\n// since importing non UMD, needs assignment\nwindow.Shepherd = Shepherd;\nwindow.ResizeObserver = ResizeObserver;\n\nconst DEFAULT_STEP_CLASS = 'shepherd-step-tooltip';\n\ndescribe('Tour | Step', () => {\n  let tour;\n\n  const showOn = () => {\n    return true;\n  };\n\n  const when = {\n    show() {}\n  };\n\n  beforeEach(() => {\n    tour = new Tour();\n  });\n\n  describe('Shepherd.Step()', () => {\n    const defaultOffsetMiddleware = offset({ mainAxis: 0, crossAxis: 32 });\n    const fooMiddleware = { name: 'foo', options: 'bar', fn: (args) => args };\n\n    const instance = new Shepherd.Tour({\n      defaultStepOptions: {\n        classes: DEFAULT_STEP_CLASS,\n        scrollTo: true,\n        floatingUIOptions: {\n          middleware: [defaultOffsetMiddleware]\n        },\n        showOn,\n        when\n      }\n    });\n\n    const testStep = instance.addStep({\n      attachTo: { element: 'body', on: 'top' },\n      highlightClass: 'highlight',\n      text: 'This is a step for testing',\n      buttons: [\n        {\n          text: 'Next',\n          action: instance.next\n        }\n      ],\n      id: 'test',\n      floatingUIOptions: {\n        middleware: [fooMiddleware]\n      }\n    });\n\n    const showTestStep = instance.addStep({\n      buttons: [],\n      id: 'test2',\n      text: 'Another Step'\n    });\n\n    // Add more steps for total _setupButtons coverage\n    instance.addStep({\n      buttons: {\n        text: 'Next',\n        action: instance.next\n      },\n      id: 'test3-id',\n      text: 'Another Step part deux'\n    });\n\n    const stepWithoutNameWithId = instance.addStep({\n      attachTo: { element: 'body' },\n      highlightClass: 'highlight',\n      id: 'no-name',\n      text: 'This is a step without a name, but with an id',\n      buttons: [\n        {\n          text: 'Next',\n          action: instance.next\n        }\n      ]\n    });\n\n    const stepWithoutNameWithoutIdOffsetMiddleware = offset({\n      mainAxis: 0,\n      crossAxis: -32\n    });\n    const stepWithoutNameWithoutId = instance.addStep({\n      attachTo: { element: 'body' },\n      highlightClass: 'highlight',\n      text: 'This is a step without a name, and without an id',\n      buttons: [\n        {\n          text: 'Next',\n          action: instance.next\n        }\n      ],\n      floatingUIOptions: {\n        middleware: [stepWithoutNameWithoutIdOffsetMiddleware]\n      }\n    });\n\n    const beforeShowPromise = () =>\n      new Promise((resolve) => {\n        setTimeout(() => {\n          console.log('beforeShowPromise worked!');\n          resolve('beforeShowPromise worked!');\n        }, 1000);\n      });\n\n    const beforeShowPromiseTestStep = instance.addStep({\n      text: 'Before Show Promise Step',\n      id: 'test3',\n      beforeShowPromise\n    });\n\n    afterEach(() => {\n      instance.complete();\n    });\n\n    it('has all the correct properties', () => {\n      const values = [\n        'arrow',\n        'classes',\n        'scrollTo',\n        'floatingUIOptions',\n        'showOn',\n        'when',\n        'attachTo',\n        'highlightClass',\n        'text',\n        'buttons',\n        'id'\n      ];\n      expect(values).toEqual(Object.keys(testStep.options));\n\n      expect(testStep.id, 'passed name set as id').toBe('test');\n      expect(stepWithoutNameWithId.id, 'no name, id passed is set').toBe(\n        'no-name'\n      );\n      expect(\n        stepWithoutNameWithoutId.id,\n        'id is generated when no name or id passed'\n      ).toMatch(\n        /^step-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/\n      );\n    });\n\n    it('deep clones defaultStepOptions and copies functions', () => {\n      expect(testStep.options).toEqual({\n        arrow: true,\n        attachTo: { element: 'body', on: 'top' },\n        buttons: [\n          {\n            text: 'Next',\n            action: instance.next\n          }\n        ],\n        classes: DEFAULT_STEP_CLASS,\n        highlightClass: 'highlight',\n        id: 'test',\n        scrollTo: true,\n        text: 'This is a step for testing',\n        floatingUIOptions: {\n          middleware: [defaultOffsetMiddleware, fooMiddleware]\n        },\n        showOn,\n        when\n      });\n    });\n\n    it('allows the step to override a previously defined modifier', () => {\n      stepWithoutNameWithoutId.show();\n      const offsetMiddleware =\n        stepWithoutNameWithoutId.options.floatingUIOptions.middleware.filter(\n          ({ name }) => name === 'offset'\n        );\n      const offsetResult = offsetMiddleware.reduce(\n        (agg, current) => {\n          agg.mainAxis += current.options.mainAxis;\n          agg.crossAxis += current.options.crossAxis;\n          return agg;\n        },\n        { mainAxis: 0, crossAxis: 0 }\n      );\n\n      expect(offsetResult).toEqual({ mainAxis: 0, crossAxis: 0 });\n    });\n\n    describe('.hide()', () => {\n      it('detaches from the step target', () => {\n        instance.start();\n\n        const targetElem = document.body;\n\n        expect(targetElem.classList.contains('shepherd-enabled')).toBe(true);\n\n        testStep.hide();\n\n        expect(targetElem.classList.contains('shepherd-enabled')).toBe(false);\n      });\n    });\n\n    describe('.show()', () => {\n      it('beforeShowPromise called before `show`', () => {\n        console.log = vi.fn();\n        const promise = beforeShowPromiseTestStep.show();\n\n        return promise.then(() => {\n          expect(console.log).toHaveBeenCalledWith('beforeShowPromise worked!');\n        });\n      });\n\n      it('shows step evoking method, regardless of order', () => {\n        showTestStep.show();\n\n        expect(\n          document.querySelector('[data-shepherd-step-id=test2]')\n        ).toBeInTheDocument();\n      });\n    });\n  });\n\n  describe('cancel()', () => {\n    it('triggers the cancel event and tour method', () => {\n      let cancelCalled = false;\n      let eventTriggered = false;\n      const step = new Step(\n        {\n          cancel() {\n            cancelCalled = true;\n          }\n        },\n        {}\n      );\n      step.on('cancel', () => (eventTriggered = true));\n      step.cancel();\n\n      expect(cancelCalled, 'cancel method from tour called').toBeTruthy();\n      expect(eventTriggered, 'cancel event was triggered').toBeTruthy();\n    });\n  });\n\n  describe('complete()', () => {\n    it('triggers the complete event and tour method', () => {\n      let completeCalled = false;\n      let eventTriggered = false;\n      const step = new Step(\n        {\n          complete() {\n            completeCalled = true;\n          }\n        },\n        {}\n      );\n      step.on('complete', () => (eventTriggered = true));\n      step.complete();\n\n      expect(completeCalled, 'complete method from tour called').toBeTruthy();\n      expect(eventTriggered, 'complete event was triggered').toBeTruthy();\n    });\n  });\n\n  describe('destroy()', () => {\n    it('triggers the destroy event', () => {\n      const step = new Step(tour, {});\n      let eventTriggered = false;\n      step.on('destroy', () => (eventTriggered = true));\n      step.destroy();\n\n      expect(eventTriggered, 'destroy event was triggered').toBeTruthy();\n    });\n  });\n\n  describe('hide()', () => {\n    let beforeHideTriggered = false;\n    let modalHideCalled = false;\n    const step = new Step(\n      {\n        modal: {\n          hide() {\n            modalHideCalled = true;\n          }\n        }\n      },\n      {}\n    );\n\n    it('triggers the before-hide event', () => {\n      step.on('before-hide', () => (beforeHideTriggered = true));\n      step.hide();\n\n      expect(\n        beforeHideTriggered,\n        'before-hide event was triggered'\n      ).toBeTruthy();\n    });\n\n    it('calls tour.modal.hide', () => {\n      expect(modalHideCalled, 'tour.modal.hide called').toBeTruthy();\n    });\n  });\n\n  describe('updateStepOptions', () => {\n    let step;\n\n    beforeEach(() => {\n      step = new Step(tour, {\n        id: 'test-id',\n        attachTo: { element: 'body', on: 'top' },\n        text: 'Lorem Ipsum',\n        classes: 'classes-test',\n        title: 'Test',\n        scrollTo: false,\n        buttons: [\n          { text: 'button one', disabled: false, classes: 'button1' },\n          { text: 'button two', disabled: true, classes: 'button2' }\n        ]\n      });\n      step.show();\n    });\n\n    afterEach(() => {\n      step.destroy();\n    });\n\n    it('should update passed in properties', async () => {\n      step.updateStepOptions({ text: 'updated', title: 'New title' });\n\n      expect(step.options.text).toBe('updated');\n      expect(step.options.title).toBe('New title');\n\n      await window.requestAnimationFrame(\n        () =>\n          new Promise((resolve) => {\n            return resolve();\n          })\n      );\n\n      expect(document.querySelector('.shepherd-text').textContent).toBe(\n        'updated'\n      );\n      expect(document.querySelector('.shepherd-title').textContent).toBe(\n        'New title'\n      );\n    });\n\n    it('should not affect other properties', async () => {\n      step.updateStepOptions({ text: 'updated', title: 'New title' });\n      expect(step.options.id).toEqual('test-id');\n      expect(step.options.buttons).toEqual([\n        { text: 'button one', disabled: false, classes: 'button1' },\n        { text: 'button two', disabled: true, classes: 'button2' }\n      ]);\n\n      await window.requestAnimationFrame(\n        () =>\n          new Promise((resolve) => {\n            return resolve();\n          })\n      );\n\n      expect(document.querySelector('.button1').textContent).toBe('button one');\n      expect(document.querySelector('.button2').textContent).toBe('button two');\n    });\n\n    it('should update buttons', async () => {\n      const buttons = [\n        { text: 'button one updated', disabled: true, classes: 'button1' },\n        { text: 'button two updated', disabled: false, classes: 'button2' }\n      ];\n\n      step.updateStepOptions({ buttons });\n      expect(step.options.buttons).toEqual(buttons);\n\n      await window.requestAnimationFrame(\n        () =>\n          new Promise((resolve) => {\n            return resolve();\n          })\n      );\n\n      const buttonOne = document.querySelector('.button1');\n      expect(buttonOne.textContent).toBe('button one updated');\n      expect(buttonOne.disabled).toBe(true);\n\n      const buttonTwo = document.querySelector('.button2');\n      expect(buttonTwo.textContent).toBe('button two updated');\n      expect(buttonTwo.disabled).toBe(false);\n    });\n\n    it('removing title should remove class', async () => {\n      step.updateStepOptions({ title: '' });\n      expect(step.options.title).toEqual('');\n\n      await window.requestAnimationFrame(\n        () =>\n          new Promise((resolve) => {\n            return resolve();\n          })\n      );\n\n      const element = document.querySelector('.shepherd-element');\n      expect(element.classList.contains('shepherd-has-title')).toBeFalsy();\n    });\n\n    it('updating classes should update element classes', async () => {\n      step.updateStepOptions({ classes: 'test-1 test-2' });\n      expect(step.options.classes).toEqual('test-1 test-2');\n\n      await window.requestAnimationFrame(\n        () =>\n          new Promise((resolve) => {\n            return resolve();\n          })\n      );\n\n      const element = document.querySelector('.shepherd-element');\n      expect(element.classList.contains('test-1')).toBeTruthy();\n      expect(element.classList.contains('test-2')).toBeTruthy();\n      expect(element.classList.contains('classes-test')).toBeFalsy();\n    });\n  });\n\n  describe('_setupElements()', () => {\n    it('calls destroy on the step if the content element is already set', () => {\n      const step = new Step(tour, {});\n      let destroyCalled = false;\n      step.el = document.createElement('a');\n      step.destroy = () => (destroyCalled = true);\n      step._setupElements();\n      expect(\n        destroyCalled,\n        '_setupElements method called destroy with element set'\n      ).toBeTruthy();\n    });\n\n    it('calls destroy on the tooltip if it already exists', () => {\n      const step = new Step(tour, {});\n      let destroyCalled = false;\n      step.cleanup = () => {\n        destroyCalled = true;\n      };\n      step._setupElements();\n      expect(\n        destroyCalled,\n        '_setupElements method called destroy on the existing tooltip'\n      ).toBe(true);\n    });\n  });\n\n  describe('_scrollTo()', () => {\n    it('calls the scroll native method', () => {\n      const div = document.createElement('div');\n      let handlerCalled = false;\n      div.classList.add('scroll-test');\n      document.body.appendChild(div);\n      const step = new Step('test', {\n        attachTo: { element: '.scroll-test', on: 'center' }\n      });\n      div.scrollIntoView = () => (handlerCalled = true);\n\n      step._scrollTo();\n      expect(handlerCalled).toBeTruthy();\n    });\n\n    it('calls the custom handler', () => {\n      let handlerAdded = false;\n      const step = new Step('test', {\n        scrollToHandler: () => (handlerAdded = true)\n      });\n\n      step._scrollTo();\n      expect(handlerAdded).toBeTruthy();\n    });\n\n    it('calls scroll native method after before-show promise resolution', () => {\n      const resTester = document.createElement('div');\n      let resHandlerCalled = false;\n      resTester.classList.add('post-res-scroll-test');\n      resTester.scrollIntoView = () => (resHandlerCalled = true);\n      const resSpy = vi.spyOn(resTester, 'scrollIntoView');\n      document.body.appendChild(resTester);\n\n      const beforeShowPromise = new Promise((resolve) => {\n        return setTimeout(() => resolve('beforeShowPromise worked!'), 1000);\n      });\n\n      const step = new Step('test', {\n        attachTo: { element: '.post-res-scroll-test', on: 'center' },\n        beforeShowPromise: () => {\n          return beforeShowPromise;\n        }\n      });\n\n      step.show();\n\n      step._scrollTo();\n\n      expect(resHandlerCalled).toBeTruthy();\n      expect(resSpy).toHaveBeenCalled();\n    });\n\n    it('calls the custom handler after before-show promise resolution', () => {\n      let resHandlerAdded = false;\n\n      const beforeShowPromise = new Promise((resolve) => {\n        return setTimeout(() => resolve('beforeShowPromise worked!'), 1000);\n      });\n\n      const step = new Step('test', {\n        scrollToHandler: () => (resHandlerAdded = true),\n        beforeShowPromise: () => {\n          return beforeShowPromise;\n        }\n      });\n\n      const resSpy = vi.spyOn(step.options, 'scrollToHandler');\n\n      step.show();\n\n      step._scrollTo();\n\n      expect(resHandlerAdded).toBeTruthy();\n      expect(resSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('setOptions()', () => {\n    it('calls event handlers passed in as properties to the `when` option', () => {\n      let whenCalled = false;\n      const step = new Step('test', {\n        when: {\n          destroy: () => (whenCalled = true)\n        }\n      });\n\n      step.destroy();\n      expect(whenCalled).toBeTruthy();\n    });\n  });\n\n  describe('getTour()', () => {\n    it('returns the tour value', () => {\n      const step = new Step(new Shepherd.Tour(), {});\n\n      expect(step.getTour() instanceof Shepherd.Tour).toBeTruthy();\n    });\n  });\n\n  describe('_createTooltipContent', () => {\n    it('ARIA attributes set', () => {\n      const step = new Step(tour, {\n        id: 'test-step',\n        text: 'Lorem Ipsum',\n        title: 'Test'\n      });\n\n      const element = step._createTooltipContent();\n\n      expect(element.getAttribute('aria-labelledby')).toBe('test-step-label');\n      expect(element.querySelector('.shepherd-title').id).toBe(\n        'test-step-label'\n      );\n\n      expect(element.getAttribute('aria-describedby')).toBe(\n        'test-step-description'\n      );\n      expect(element.querySelector('.shepherd-text').id).toBe(\n        'test-step-description'\n      );\n    });\n  });\n\n  describe('correct operation of classes on body element when step not attached to an element', () => {\n    const offsetMiddleware = offset({ crossAxis: 32 });\n    const defaultCallback = (args) => args;\n    const instance = new Shepherd.Tour({\n      defaultStepOptions: {\n        classes: DEFAULT_STEP_CLASS,\n        scrollTo: true,\n        floatingUIOptions: {\n          middleware: [offsetMiddleware]\n        },\n        showOn,\n        when\n      }\n    });\n\n    const stepWithoutAttachment = instance.addStep({\n      highlightClass: 'highlight',\n      text: 'This is a step for testing',\n      buttons: [\n        {\n          text: 'Next',\n          action: instance.next\n        }\n      ],\n      id: 'test',\n      floatingUIOptions: {\n        middleware: [{ name: 'foo', options: 'bar', fn: defaultCallback }]\n      }\n    });\n\n    afterEach(() => {\n      instance.complete();\n    });\n\n    describe('.hide()', () => {\n      it('detaches from the step target', () => {\n        instance.start();\n\n        const targetElem = document.body;\n\n        expect(targetElem.classList.contains('shepherd-enabled')).toBe(true);\n\n        stepWithoutAttachment.hide();\n\n        expect(targetElem.classList.contains('shepherd-enabled')).toBe(false);\n      });\n    });\n\n    describe('.destroy()', () => {\n      it('detaches from the step target', () => {\n        instance.start();\n\n        const targetElem = document.body;\n\n        expect(targetElem.classList.contains('shepherd-enabled')).toBe(true);\n\n        stepWithoutAttachment.destroy();\n\n        expect(targetElem.classList.contains('shepherd-enabled')).toBe(false);\n      });\n    });\n  });\n\n  describe('lazy attachTo evaluation', () => {\n    // We test this using attachTo.element callback.\n    // Note that lazy evaluation largely relies on `parseAttachTo`, however this does\n    // not it's implementation, only if the callback is called lazily.\n    it('lazily evaluates attachTo.element callback', () => {\n      const step1AttachToCallback = vi.fn();\n      const step2AttachToCallback = vi.fn();\n\n      const instance = new Shepherd.Tour({\n        steps: [\n          {\n            text: 'step 1',\n            attachTo: { element: step1AttachToCallback, on: 'auto' }\n          },\n          {\n            text: 'step 2',\n            attachTo: { element: step2AttachToCallback, on: 'auto' }\n          }\n        ]\n      });\n\n      instance.start();\n\n      expect(step1AttachToCallback).toHaveBeenCalled();\n      expect(step2AttachToCallback).not.toHaveBeenCalled();\n\n      instance.next();\n\n      expect(step2AttachToCallback).toHaveBeenCalled();\n      expect(step1AttachToCallback).toHaveBeenCalledTimes(1);\n      expect(step2AttachToCallback).toHaveBeenCalledTimes(1);\n    });\n\n    it('lazily evaluates attachTo.element selector', () => {\n      const querySelectorSpy = vi.spyOn(document, 'querySelector');\n\n      const instance = new Shepherd.Tour({\n        steps: [\n          {\n            text: 'step 1',\n            attachTo: { element: '#step-1-attach-to-element', on: 'auto' }\n          },\n          {\n            text: 'step 2',\n            attachTo: { element: '#step-2-attach-to-element', on: 'auto' }\n          }\n        ]\n      });\n\n      instance.start();\n      expect(querySelectorSpy).toHaveBeenCalledWith(\n        '#step-1-attach-to-element'\n      );\n      expect(querySelectorSpy).not.toHaveBeenCalledWith(\n        '#step-2-attach-to-element'\n      );\n      instance.next();\n      expect(querySelectorSpy).toHaveBeenCalledWith(\n        '#step-2-attach-to-element'\n      );\n    });\n\n    it('evaluates attachTo on subsequent shows', () => {\n      const step1AttachToCallback = vi.fn();\n      const step2AttachToCallback = vi.fn();\n\n      const instance = new Shepherd.Tour({\n        steps: [\n          {\n            text: 'step 1',\n            attachTo: { element: step1AttachToCallback, on: 'auto' }\n          },\n          {\n            text: 'step 2',\n            attachTo: { element: step2AttachToCallback, on: 'auto' }\n          }\n        ]\n      });\n\n      instance.start();\n      expect(step1AttachToCallback).toHaveBeenCalledTimes(1);\n      instance.next();\n      instance.back();\n      expect(step1AttachToCallback).toHaveBeenCalledTimes(2);\n    });\n\n    it('evaluates attachTo only once', () => {\n      const instance = new Shepherd.Tour({\n        steps: [\n          {\n            text: 'step 1',\n            attachTo: { element: () => {}, on: 'auto' },\n            id: 'step1'\n          },\n          {\n            text: 'step 2',\n            attachTo: { element: () => {}, on: 'auto' }\n          }\n        ]\n      });\n\n      instance.start();\n\n      expect(instance.getCurrentStep().isOpen()).toBe(true);\n      // Subsequent calls to the getter return the same object\n      const result1 = instance.getCurrentStep()._getResolvedAttachToOptions();\n\n      expect(result1).not.toBeNull();\n\n      instance.next();\n\n      const result2 = instance.getById('step1')._getResolvedAttachToOptions();\n\n      expect(result1).toEqual(result2);\n    });\n\n    it('can evaluate _getResolvedAttachToOptions before step before-show phase', () => {\n      const instance = new Shepherd.Tour({\n        steps: [\n          {\n            text: 'step 1',\n            attachTo: { element: () => {}, on: 'auto' }\n          },\n          {\n            text: 'step 2',\n            attachTo: { element: () => {}, on: 'auto' },\n            id: 'step2'\n          }\n        ]\n      });\n\n      instance.start();\n\n      expect(instance.getById('step2')._getResolvedAttachToOptions()).toEqual({\n        element: undefined,\n        on: 'auto'\n      });\n    });\n  });\n\n  describe('tabIndex preservation', () => {\n    let instance;\n    let testElement;\n\n    beforeEach(() => {\n      // Create a test element\n      testElement = document.createElement('div');\n      testElement.id = 'tabindex-test-element';\n      document.body.appendChild(testElement);\n\n      instance = new Shepherd.Tour({\n        steps: [\n          {\n            id: 'test-step',\n            text: 'Test step',\n            attachTo: { element: '#tabindex-test-element', on: 'top' }\n          }\n        ]\n      });\n    });\n\n    afterEach(() => {\n      instance.complete();\n      testElement?.remove();\n    });\n\n    it('stores and restores original tabIndex when element has no tabindex attribute', () => {\n      // Initially, the element should have no tabindex attribute\n      expect(testElement.hasAttribute('tabindex')).toBe(false);\n\n      // Start the tour\n      instance.start();\n\n      // During the tour, tabIndex should be set to 0\n      expect(testElement.tabIndex).toBe(0);\n      expect(testElement.getAttribute('tabindex')).toBe('0');\n\n      // Hide the step\n      instance.getCurrentStep().hide();\n\n      // After hiding, the tabindex attribute should be removed\n      expect(testElement.hasAttribute('tabindex')).toBe(false);\n    });\n\n    it('stores and restores original tabIndex when element has tabindex=\"-1\"', () => {\n      // Set tabindex to -1 initially\n      testElement.setAttribute('tabindex', '-1');\n      expect(testElement.getAttribute('tabindex')).toBe('-1');\n\n      // Start the tour\n      instance.start();\n\n      // During the tour, tabIndex should be set to 0\n      expect(testElement.tabIndex).toBe(0);\n      expect(testElement.getAttribute('tabindex')).toBe('0');\n\n      // Hide the step\n      instance.getCurrentStep().hide();\n\n      // After hiding, tabIndex should be restored to -1\n      expect(testElement.getAttribute('tabindex')).toBe('-1');\n    });\n\n    it('stores and restores original tabIndex when element has tabindex=\"5\"', () => {\n      // Set tabindex to 5 initially\n      testElement.setAttribute('tabindex', '5');\n      expect(testElement.getAttribute('tabindex')).toBe('5');\n\n      // Start the tour\n      instance.start();\n\n      // During the tour, tabIndex should be set to 0\n      expect(testElement.tabIndex).toBe(0);\n      expect(testElement.getAttribute('tabindex')).toBe('0');\n\n      // Hide the step\n      instance.getCurrentStep().hide();\n\n      // After hiding, tabIndex should be restored to 5\n      expect(testElement.getAttribute('tabindex')).toBe('5');\n    });\n\n    it('restores tabIndex when step is destroyed', () => {\n      // Set tabindex to -1 initially\n      testElement.setAttribute('tabindex', '-1');\n\n      // Start the tour\n      instance.start();\n\n      // During the tour, tabIndex should be set to 0\n      expect(testElement.getAttribute('tabindex')).toBe('0');\n\n      // Destroy the step\n      instance.getCurrentStep().destroy();\n\n      // After destroying, tabIndex should be restored to -1\n      expect(testElement.getAttribute('tabindex')).toBe('-1');\n    });\n\n    it('handles multiple show/hide cycles correctly', () => {\n      // Set tabindex to 2 initially\n      testElement.setAttribute('tabindex', '2');\n\n      // Start the tour (first show)\n      instance.start();\n      expect(testElement.getAttribute('tabindex')).toBe('0');\n\n      // Hide the step\n      instance.getCurrentStep().hide();\n      expect(testElement.getAttribute('tabindex')).toBe('2');\n\n      // Show again\n      instance.getCurrentStep().show();\n      expect(testElement.getAttribute('tabindex')).toBe('0');\n\n      // Hide again\n      instance.getCurrentStep().hide();\n      expect(testElement.getAttribute('tabindex')).toBe('2');\n    });\n\n    it('only stores the original value once, not intermediate values', () => {\n      // Set tabindex to 3 initially\n      testElement.setAttribute('tabindex', '3');\n\n      // Start the tour\n      instance.start();\n      expect(testElement.getAttribute('tabindex')).toBe('0');\n\n      // Manually change tabIndex (simulating some other code changing it)\n      testElement.setAttribute('tabindex', '7');\n\n      // Hide the step - should restore to original value (3), not intermediate (7)\n      instance.getCurrentStep().hide();\n      expect(testElement.getAttribute('tabindex')).toBe('3');\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/tour.spec.js",
    "content": "import _ from 'lodash';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport Shepherd from '../../src/shepherd';\nimport ResizeObserver from 'resize-observer-polyfill';\nimport { setupTooltip } from '../../src/utils/floating-ui';\nimport { offset } from '@floating-ui/dom';\n\nconst { Step } = Shepherd;\n\n// since importing non UMD, needs assignment\nwindow.Shepherd = Shepherd;\nwindow.ResizeObserver = ResizeObserver;\n\nconst DEFAULT_STEP_CLASS = 'shepherd-step-tooltip';\n\ndescribe('Tour | Top-Level Class', function () {\n  let instance, shouldShowStep;\n\n  const showOn = () => {\n    return true;\n  };\n\n  const when = {\n    show() {}\n  };\n\n  const offsetMiddleware = offset({ crossAxis: 32 });\n\n  const defaultStepOptions = {\n    classes: DEFAULT_STEP_CLASS,\n    scrollTo: true,\n    floatingUIOptions: {\n      middleware: [offsetMiddleware]\n    },\n    showOn,\n    when\n  };\n\n  afterEach(() => {\n    instance.complete();\n  });\n\n  describe('constructor', function () {\n    it('creates a new tour instance', function () {\n      instance = new Shepherd.Tour({ defaultStepOptions });\n\n      expect(instance instanceof Shepherd.Tour).toBe(true);\n    });\n\n    it('returns the default options on the instance', function () {\n      instance = new Shepherd.Tour({\n        defaultStepOptions,\n        steps: [\n          {\n            scrollTo: false\n          }\n        ]\n      });\n\n      expect(instance.options.defaultStepOptions).toEqual({\n        classes: DEFAULT_STEP_CLASS,\n        scrollTo: true,\n        floatingUIOptions: {\n          middleware: [offsetMiddleware]\n        },\n        showOn,\n        when\n      });\n    });\n\n    it('sets the correct bindings', function () {\n      instance = new Shepherd.Tour({ defaultStepOptions });\n\n      const bindings = Object.keys(instance.bindings);\n      const tourEvents = [\n        'complete',\n        'cancel',\n        'start',\n        'show',\n        'active',\n        'inactive'\n      ];\n      // Check that all bindings are included\n      const difference = _.difference(tourEvents, bindings);\n      expect(difference.length, 'all tour events bound').toBe(0);\n    });\n\n    it('generates a unique `id` property, optionally based upon the `tourName` option', function () {\n      const instance1 = new Shepherd.Tour();\n      const instance2 = new Shepherd.Tour({ tourName: 'select-avatar' });\n\n      expect(instance1.id.startsWith('tour--')).toBe(true);\n      expect(instance2.id.startsWith('select-avatar--')).toBe(true);\n\n      const [uniqueId1] = instance1.id.split('--')[1];\n      const uniqueId2 = instance2.id.split('--')[1];\n\n      expect(uniqueId1).not.toBe(uniqueId2);\n    });\n  });\n\n  describe('methods', () => {\n    beforeEach(() => {\n      shouldShowStep = false;\n\n      instance = new Shepherd.Tour({\n        defaultStepOptions\n      });\n\n      instance.addStep({\n        id: 'test',\n        title: 'This is a test step for our tour'\n      });\n\n      instance.addStep({\n        id: 'test2',\n        title: 'Another Step'\n      });\n\n      instance.addStep({\n        classes: 'skipped',\n        id: 'skipped-step',\n        title: 'This step should be skipped',\n        showOn() {\n          return shouldShowStep;\n        }\n      });\n\n      instance.addStep({\n        id: 'test3',\n        title: 'Yet, another test step'\n      });\n    });\n\n    describe('.addStep()', function () {\n      it('adds tour steps', function () {\n        expect(instance.steps.length).toBe(4);\n        expect(\n          instance.getById('test').options.classes,\n          'classes passed to step options'\n        ).toBe(DEFAULT_STEP_CLASS);\n      });\n\n      it('adds tour steps at specified index', function () {\n        expect(instance.steps[1].options.id, 'original step at index 1').toBe(\n          'test2'\n        );\n        instance.addStep(\n          {\n            id: 'index-test',\n            title: 'Test index insertion'\n          },\n          1\n        );\n        expect(instance.steps.length).toBe(5);\n        expect(instance.steps[1].options.id, 'step inserted at index 1').toBe(\n          'index-test'\n        );\n      });\n\n      it('adds steps with only one arg', function () {\n        const step = instance.addStep({\n          id: 'one-arg'\n        });\n\n        expect(instance.steps.length).toBe(5);\n        expect(step.id, 'id applied to step with just one arg').toBe('one-arg');\n      });\n\n      it('adds steps that are already Step instances', function () {\n        const step = instance.addStep(\n          new Step(instance, {\n            id: 'already-a-step'\n          })\n        );\n\n        expect(instance.steps.length).toBe(5);\n        expect(step.id, 'id applied to step instance').toBe('already-a-step');\n        expect(step.tour, 'tour is set to `this`').toBe(instance);\n      });\n    });\n\n    describe('.getById()', function () {\n      it('returns the step by ID with the right title', function () {\n        expect(instance.steps.length).toBe(4);\n        expect(instance.getById('test3').options.title).toBe(\n          'Yet, another test step'\n        );\n      });\n    });\n\n    describe('.start()', function () {\n      it('starts a tour that is the current active', function () {\n        instance.start();\n\n        expect(instance).toBe(Shepherd.activeTour);\n      });\n    });\n\n    describe('.getCurrentStep()', function () {\n      it('returns the currently shown step', function () {\n        instance.start();\n        expect(instance.getCurrentStep().id).toBe('test');\n      });\n    });\n\n    describe('.hide()', function () {\n      it('hides the current step', () => {\n        const [firstStep] = instance.steps;\n        const hideStepSpy = vi.spyOn(firstStep, 'hide');\n\n        expect(firstStep.isOpen()).toBe(false);\n\n        instance.start();\n\n        expect(firstStep.isOpen()).toBe(true);\n\n        instance.hide();\n\n        expect(firstStep.isOpen()).toBe(false);\n        expect(hideStepSpy).toHaveBeenCalledTimes(1);\n      });\n    });\n\n    describe('isActive', function () {\n      it('computes whether or not `Shepherd.activeTour` equals the instance', function () {\n        Shepherd.activeTour = '';\n        expect(instance.isActive()).toBe(false);\n\n        Shepherd.activeTour = instance;\n        expect(instance.isActive()).toBe(true);\n\n        Shepherd.activeTour = '';\n        expect(instance.isActive()).toBe(false);\n      });\n    });\n\n    describe('.next()/.back()', function () {\n      it('goes to the next/previous steps', function () {\n        instance.start();\n        instance.next();\n        expect(instance.getCurrentStep().id).toBe('test2');\n        instance.back();\n        expect(instance.getCurrentStep().id).toBe('test');\n      });\n\n      it('next completes tour when on last step', function () {\n        let completeFired = false;\n        instance.on('complete', () => {\n          completeFired = true;\n        });\n\n        instance.start();\n        instance.show('test3');\n        expect(instance.getCurrentStep().id).toBe('test3');\n        instance.next();\n        expect(\n          completeFired,\n          'complete is called when next is clicked on last step'\n        ).toBeTruthy();\n      });\n    });\n\n    describe('.cancel()', function () {\n      it('shows confirm dialog when confirmCancel is true', function () {\n        instance = new Shepherd.Tour({\n          defaultStepOptions,\n          confirmCancel: true,\n          confirmCancelMessage: 'Confirm cancel?'\n        });\n\n        instance.addStep({\n          id: 'test',\n          title: 'This is a test step for our tour'\n        });\n\n        let inactiveFired = false;\n        instance.on('inactive', () => {\n          inactiveFired = true;\n        });\n\n        window.confirm = vi.fn();\n        const windowConfirmStub = vi\n          .spyOn(window, 'confirm')\n          .mockImplementation(() => false);\n\n        instance.start();\n\n        expect(instance, 'activeTour is set to our tour').toBe(\n          Shepherd.activeTour\n        );\n\n        instance.cancel();\n\n        expect(windowConfirmStub).toHaveBeenCalled();\n\n        expect(\n          inactiveFired,\n          'tour still going, since confirm returned false'\n        ).toBeFalsy();\n\n        windowConfirmStub.mockImplementation(() => true);\n\n        instance.cancel();\n\n        expect(windowConfirmStub).toHaveBeenCalled();\n        expect(\n          inactiveFired,\n          'tour inactive, since confirm returned true'\n        ).toBeTruthy();\n      });\n\n      it('tears down tour on cancel', function () {\n        let inactiveFired = false;\n        instance.on('inactive', () => {\n          inactiveFired = true;\n        });\n        instance.start();\n        expect(instance, 'activeTour is set to our tour').toBe(\n          Shepherd.activeTour\n        );\n        instance.cancel();\n        expect(Shepherd.activeTour, 'activeTour is torn down').toBeFalsy();\n        expect(inactiveFired, 'inactive event fired').toBeTruthy();\n      });\n\n      it('triggers cancel event when cancel function is called', function () {\n        let cancelFired = false;\n        instance.on('cancel', () => {\n          cancelFired = true;\n        });\n\n        instance.start();\n        instance.cancel();\n        expect(cancelFired, 'cancel event fired').toBeTruthy();\n      });\n\n      [\n        {\n          status: 'normal',\n          title: 'whether cancel depends on function return value'\n        },\n        {\n          status: 'async',\n          title:\n            'whether cancel will wait for the value returned from the function'\n        }\n      ].map(({ status, title }) => {\n        it('when confirmCancel is function, ' + title, async function () {\n          const myMock = vi.fn();\n          if (status === 'async') {\n            myMock\n              .mockImplementationOnce(() => Promise.resolve(false))\n              .mockImplementationOnce(() => Promise.resolve(true));\n          } else {\n            myMock.mockReturnValueOnce(false).mockReturnValueOnce(true);\n          }\n          instance = new Shepherd.Tour({\n            defaultStepOptions,\n            confirmCancel: myMock,\n            confirmCancelMessage: 'Confirm cancel?'\n          });\n\n          instance.addStep({\n            id: 'test',\n            title: 'This is a test step for our tour'\n          });\n\n          let inactiveFired = false;\n          instance.on('cancel', () => {\n            inactiveFired = true;\n          });\n\n          instance.start();\n          expect(instance, 'activeTour is set to our tour').toBe(\n            Shepherd.activeTour\n          );\n\n          await instance.cancel();\n          expect(\n            myMock.mock.calls.length,\n            'confirmCancel callback called once'\n          ).toBe(1);\n          expect(\n            await myMock.mock.results[0].value,\n            'confirmCancel callback returns false'\n          ).toBe(false);\n          expect(\n            inactiveFired,\n            'tour still going, since confirmCancel callback returned false'\n          ).toBeFalsy();\n\n          await instance.cancel();\n          expect(\n            myMock.mock.calls.length,\n            'confirmCancel callback called twice'\n          ).toBe(2);\n          expect(\n            await myMock.mock.results[1].value,\n            'confirmCancel callback returns true'\n          ).toBe(true);\n          expect(\n            inactiveFired,\n            'tour inactive, since confirm returned true'\n          ).toBeTruthy();\n        });\n      });\n    });\n\n    describe('.complete()', function () {\n      it('triggers complete event when complete function is called', function () {\n        let completeFired = false;\n\n        instance.on('complete', () => {\n          completeFired = true;\n        });\n\n        instance.start();\n        instance.complete();\n        expect(completeFired, 'complete event fired').toBeTruthy();\n      });\n\n      it('calls `done()`', () => {\n        const doneSpy = vi.spyOn(instance, '_done');\n\n        expect(doneSpy).toHaveBeenCalledTimes(0);\n\n        instance.start();\n        instance.complete();\n\n        expect(doneSpy).toHaveBeenCalledTimes(1);\n      });\n    });\n\n    describe('._done()', function () {\n      it('tears down the active tour', function () {\n        instance.start();\n\n        expect(instance, 'activeTour is set to our tour').toBe(\n          Shepherd.activeTour\n        );\n\n        instance.complete();\n\n        expect(\n          Shepherd.activeTour,\n          '`activeTour` is torn down and removed from the `Shepherd` global'\n        ).toBe(null);\n      });\n\n      it('removes any of its `Step` tooltip elements from the DOM', function () {\n        const testStep = {\n          id: 'element-removal-test',\n          classes: 'element-removal-test',\n          title: 'This is a test step for our tour'\n        };\n\n        instance.addStep(testStep);\n        instance.start();\n        instance.show('element-removal-test');\n\n        expect(\n          document.querySelector('.element-removal-test'),\n          'a step is rendered in the DOM after the tour starts'\n        ).toBeInTheDocument();\n\n        instance.complete();\n\n        expect(\n          document.querySelector('.element-removal-test'),\n          'steps are removed from the DOM after the tour completes'\n        ).not.toBeInTheDocument();\n      });\n\n      it('fires the `inactive` event', function () {\n        let inactiveFired = false;\n\n        instance.on('inactive', () => {\n          inactiveFired = true;\n        });\n\n        instance.start();\n\n        expect(\n          inactiveFired,\n          'inactive event does not fire before `complete()`'\n        ).toBe(false);\n\n        instance.complete();\n\n        expect(inactiveFired, 'inactive event fires after `complete()`').toBe(\n          true\n        );\n      });\n    });\n\n    describe('.removeStep()', function () {\n      it('removes the step when passed the id', function () {\n        instance.start();\n        expect(instance.steps.length).toBe(4);\n        instance.removeStep('test2');\n        expect(instance.steps.length).toBe(3);\n      });\n\n      it('hides the step before removing', function () {\n        let hideFired = false;\n        instance.start();\n        expect(instance.steps.length).toBe(4);\n        const step = instance.getById('test');\n        step.on('hide', () => {\n          hideFired = true;\n        });\n        instance.removeStep('test');\n        expect(instance.steps.length).toBe(3);\n        expect(\n          hideFired,\n          'hide is fired before step is destroyed'\n        ).toBeTruthy();\n      });\n    });\n\n    describe('.show()', function () {\n      it('show short-circuits if next is not found', function () {\n        let showFired = false;\n        instance.start();\n        instance.on('show', () => {\n          showFired = true;\n        });\n        instance.show('not-a-real-key');\n        expect(\n          showFired,\n          'showFired is false because show short circuits'\n        ).toBeFalsy();\n      });\n\n      it('showOn determines which steps to skip', function () {\n        instance.start();\n        expect(instance.getCurrentStep().id).toBe('test');\n        instance.next();\n        expect(instance.getCurrentStep().id).toBe('test2');\n        instance.next();\n        expect(instance.getCurrentStep().id).toBe('test3');\n        expect(\n          instance.getCurrentStep().id,\n          'step skipped because `showOn` returns false'\n        ).not.toBe('skipped-step');\n        instance.back();\n        shouldShowStep = true;\n        instance.next();\n        expect(\n          instance.getCurrentStep().id,\n          'step shown because `showOn` returns true'\n        ).toBe('skipped-step');\n      });\n\n      it('fires cancel when going back past first step with showOn returning false', function () {\n        let cancelFired = false;\n        const tourInstance = new Shepherd.Tour();\n\n        tourInstance.addStep({\n          id: 'first-hidden',\n          title: 'This step is always hidden',\n          showOn() {\n            return false;\n          }\n        });\n\n        tourInstance.addStep({\n          id: 'second',\n          title: 'Second step'\n        });\n\n        tourInstance.on('cancel', () => {\n          cancelFired = true;\n        });\n\n        tourInstance.start();\n        expect(\n          tourInstance.getCurrentStep().id,\n          'first hidden step is skipped on start'\n        ).toBe('second');\n\n        tourInstance.back();\n        expect(\n          cancelFired,\n          'cancel is fired when going back past all shown steps'\n        ).toBeTruthy();\n        expect(\n          Shepherd.activeTour,\n          'activeTour is null after cancel'\n        ).toBeNull();\n      });\n\n      it(\"sets the instance on `Shepherd.activeTour` if it's not already set\", function () {\n        const setupFuncSpy = vi.spyOn(instance, '_setupActiveTour');\n        Shepherd.activeTour = null;\n\n        expect(setupFuncSpy).toHaveBeenCalledTimes(0);\n\n        instance.start();\n\n        expect(setupFuncSpy).toHaveBeenCalledTimes(1);\n        expect(Shepherd.activeTour).toBe(instance);\n      });\n    });\n  });\n\n  describe('floatingUIOptions', () => {\n    it('applies the default modifiers from defaultStepOptions', function () {\n      instance = new Shepherd.Tour({ defaultStepOptions });\n\n      const step = instance.addStep({\n        id: 'test',\n        title: 'This is a test step for our tour'\n      });\n\n      instance.start();\n\n      const floatingUIOptions = setupTooltip(step);\n      expect(floatingUIOptions.middleware.length).toBe(1);\n    });\n\n    it('adds a step modifer to default modifiers', function () {\n      instance = new Shepherd.Tour({ defaultStepOptions });\n\n      const step = instance.addStep({\n        id: 'test',\n        title: 'This is a test step for our tour',\n        floatingUIOptions: {\n          middleware: [{ name: 'foo', options: 'bar', fn: (args) => args }]\n        }\n      });\n\n      instance.start();\n\n      const floatingUIOptions = setupTooltip(step);\n      expect(floatingUIOptions.middleware.length).toBe(2);\n    });\n\n    it('correctly changes modifiers when going from centered to attached', function () {\n      const div = document.createElement('div');\n      div.classList.add('modifiers-test');\n      document.body.appendChild(div);\n      instance = new Shepherd.Tour({ defaultStepOptions });\n\n      const centeredStep = instance.addStep({\n        id: 'centered',\n        title: 'This is a centered step for our tour',\n        floatingUIOptions: {\n          middleware: [{ name: 'foo', options: 'bar', fn: (args) => args }]\n        }\n      });\n\n      const attachedStep = instance.addStep({\n        attachTo: { element: '.modifiers-test', on: 'top' },\n        id: 'attached',\n        title: 'This is an attached step for our tour',\n        floatingUIOptions: {\n          middleware: [{ name: 'foo', options: 'bar', fn: (args) => args }]\n        }\n      });\n\n      instance.start();\n\n      const centeredOptions = setupTooltip(centeredStep);\n      const centeredMiddlewareNames = centeredOptions.middleware.map(\n        ({ name }) => name\n      );\n      expect(centeredOptions.middleware.length).toBe(2);\n      expect(centeredMiddlewareNames.includes('offset')).toBe(true);\n      expect(centeredMiddlewareNames.includes('foo')).toBe(true);\n      expect(centeredMiddlewareNames.includes('arrow')).toBe(false);\n\n      instance.next();\n\n      const options = setupTooltip(attachedStep);\n      const middlewareNames = options.middleware.map(({ name }) => name);\n      expect(options.middleware.length).toBe(5);\n      expect(middlewareNames.includes('offset')).toBe(true);\n      expect(middlewareNames.includes('foo')).toBe(true);\n      expect(middlewareNames.includes('shift')).toBe(true);\n      expect(middlewareNames.includes('arrow')).toBe(true);\n\n      document.body.removeChild(div);\n    });\n\n    it('renders step in stepsContainer', () => {\n      const stepsContainer = document.createElement('div');\n      stepsContainer.setAttribute('id', 'customStepTarget');\n      document.body.appendChild(stepsContainer);\n      expect(stepsContainer).toBeInTheDocument();\n\n      instance = new Shepherd.Tour({\n        stepsContainer,\n        defaultStepOptions\n      });\n\n      const step = instance.addStep({\n        title: 'This is a test step for our tour'\n      });\n\n      instance.start();\n\n      const stepElement = step.getElement();\n\n      expect(stepsContainer.contains(stepElement)).toBe(true);\n    });\n\n    it('adds autoPlacement middleware when attachTo.on is set to auto', () => {\n      const div = document.createElement('div');\n      div.classList.add('modifiers-test');\n      document.body.appendChild(div);\n      instance = new Shepherd.Tour();\n\n      const step1 = instance.addStep({\n        id: 'test',\n        title: 'This is a test step for our tour',\n        attachTo: { element: '.modifiers-test', on: 'auto' }\n      });\n\n      const step2 = instance.addStep({\n        id: 'test',\n        title: 'This is a test step for our tour',\n        attachTo: { element: '.modifiers-test', on: 'auto-start' }\n      });\n\n      const step3 = instance.addStep({\n        id: 'test',\n        title: 'This is a test step for our tour',\n        attachTo: { element: '.modifiers-test', on: 'auto-end' }\n      });\n\n      instance.start();\n\n      const step1FloatingUIOptions = setupTooltip(step1);\n      const step1MiddlewareNames = step1FloatingUIOptions.middleware.map(\n        ({ name }) => name\n      );\n      const step1PlacementMiddleware = step1FloatingUIOptions.middleware.find(\n        ({ name }) => name === 'autoPlacement'\n      );\n      expect(step1MiddlewareNames.includes('autoPlacement')).toBe(true);\n      expect(step1MiddlewareNames.includes('flip')).toBe(false);\n      expect(step1PlacementMiddleware.options.alignment).toBe(null);\n\n      instance.next();\n\n      const step2FloatingUIOptions = setupTooltip(step2);\n      const step2PlacementMiddleware = step2FloatingUIOptions.middleware.find(\n        ({ name }) => name === 'autoPlacement'\n      );\n      expect(step2PlacementMiddleware.options.alignment).toBe('start');\n\n      instance.next();\n\n      const step3FloatingUIOptions = setupTooltip(step3);\n      const step3PlacementMiddleware = step3FloatingUIOptions.middleware.find(\n        ({ name }) => name === 'autoPlacement'\n      );\n      expect(step3PlacementMiddleware.options.alignment).toBe('end');\n    });\n  });\n\n  describe('shepherdModalOverlayContainer', function () {\n    beforeEach(() => {\n      instance = new Shepherd.Tour({ useModalOverlay: true });\n    });\n    it('appends shepherdModalOverlayContainer to DOM when it does not exist', async () => {\n      expect(\n        document.querySelector('.shepherd-modal-overlay-container')\n      ).not.toBeInTheDocument();\n\n      instance.start();\n\n      setTimeout(() => {\n        expect(\n          document.querySelector('.shepherd-modal-overlay-container')\n        ).toBeInTheDocument();\n      }, 200);\n    });\n\n    it('removes shepherdModalOverlayContainer from DOM when it is complete', () => {\n      instance.start();\n\n      setTimeout(() => {\n        expect(\n          document.querySelector('.shepherd-modal-overlay-container')\n        ).toBeInTheDocument();\n      }, 200);\n\n      instance.complete();\n\n      expect(\n        document.querySelector('.shepherd-modal-overlay-container')\n      ).not.toBeInTheDocument();\n    });\n\n    it('renders modal in modalContainer', () => {\n      const modalContainer = document.createElement('div');\n      modalContainer.setAttribute('id', 'customModalTarget');\n      document.body.appendChild(modalContainer);\n      expect(modalContainer).toBeInTheDocument();\n\n      instance = new Shepherd.Tour({\n        modalContainer,\n        useModalOverlay: true\n      });\n\n      instance.addStep({\n        title: 'This is a test step for our tour'\n      });\n\n      instance.start();\n\n      const modalElement = instance.modal.getElement();\n\n      expect(modalContainer.contains(modalElement)).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/utils/bind.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { bindAdvance } from '../../../src/utils/bind';\nimport { Step } from '../../../src/step';\n\ndescribe('Bind Utils', function () {\n  describe('bindAdvance()', () => {\n    let event, link;\n    let hasAdvanced = false;\n\n    const advanceOnSelector = 'test-selector';\n    const advanceOnEventName = 'test-event';\n    const tourProto = {\n      next() {\n        hasAdvanced = true;\n      }\n    };\n\n    beforeEach(() => {\n      event = new Event(advanceOnEventName);\n\n      link = document.createElement('a');\n      link.classList.add(advanceOnSelector);\n      link.textContent = 'Click Me 👋';\n\n      document.body.appendChild(link);\n    });\n\n    afterEach(() => {\n      link.remove();\n    });\n\n    it('triggers the `advanceOn` option via object', () => {\n      const step = new Step(tourProto, {\n        advanceOn: {\n          selector: `.${advanceOnSelector}`,\n          event: advanceOnEventName\n        }\n      });\n\n      step.isOpen = () => true;\n\n      bindAdvance(step);\n      link.dispatchEvent(event);\n\n      expect(link.classList.contains(advanceOnSelector)).toBe(true);\n      expect(hasAdvanced, '`next()` triggered for advanceOn').toBe(true);\n    });\n\n    it('captures events attached to no element', () => {\n      const step = new Step(tourProto, {\n        advanceOn: { event: advanceOnEventName }\n      });\n\n      step.isOpen = () => true;\n\n      bindAdvance(step);\n      document.body.dispatchEvent(event);\n\n      expect(hasAdvanced, '`next()` triggered for advanceOn').toBeTruthy();\n    });\n\n    it('should support bubbling events for nodes that do not exist yet', () => {\n      const event = new Event('blur');\n\n      const step = new Step(tourProto, {\n        text: 'Lorem ipsum dolor: <a href=\"https://example.com\">sit amet</a>',\n        advanceOn: {\n          selector: 'a[href=\"https://example.com\"]',\n          event: 'blur'\n        }\n      });\n\n      step.isOpen = () => true;\n\n      bindAdvance(step);\n      document.body.dispatchEvent(event);\n\n      expect(hasAdvanced, '`next()` triggered for advanceOn').toBeTruthy();\n    });\n\n    it('calls `removeEventListener` when destroyed', () => {\n      return new Promise((done) => {\n        const bodySpy = vi.spyOn(document.body, 'removeEventListener');\n        const step = new Step(tourProto, {\n          advanceOn: { event: advanceOnEventName }\n        });\n\n        step.isOpen = () => true;\n\n        bindAdvance(step);\n        step.trigger('destroy');\n\n        expect(bodySpy).toHaveBeenCalled();\n        bodySpy.mockRestore();\n\n        done();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/utils/cleanup.spec.js",
    "content": "import { describe, expect, it } from 'vitest';\nimport { cleanupSteps } from '../../../src/utils/cleanup';\n\ndescribe('Cleanup Utils', function () {\n  // Create some elements to use to attach to\n  const firstAttachElement = document.createElement('div');\n  firstAttachElement.classList.add('first-attach-to');\n  firstAttachElement.classList.add('shepherd-target-click-disabled');\n  document.body.appendChild(firstAttachElement);\n\n  const secondAttachElement = document.createElement('div');\n  secondAttachElement.classList.add('second-attach-to');\n  secondAttachElement.classList.add('shepherd-target-click-disabled');\n  document.body.appendChild(secondAttachElement);\n\n  // Element with extra highlights\n  const thirdAttachElement = document.createElement('div');\n  thirdAttachElement.classList.add('third-attach-to');\n  thirdAttachElement.classList.add('shepherd-target-click-disabled');\n  document.body.appendChild(thirdAttachElement);\n\n  // Extra highlight elements for the third step\n  const extraHighlightElement = document.createElement('div');\n  extraHighlightElement.classList.add('extra-highlight');\n  extraHighlightElement.classList.add('shepherd-target-click-disabled');\n  document.body.appendChild(extraHighlightElement);\n  const extraHighlightElement2 = document.createElement('div');\n  extraHighlightElement2.classList.add('extra-highlight');\n  extraHighlightElement2.classList.add('shepherd-target-click-disabled');\n  document.body.appendChild(extraHighlightElement2);\n\n  const mockedTour = {\n    steps: [\n      {\n        options: {\n          attachTo: {\n            element: '.first-attach-to',\n            on: 'bottom'\n          },\n          canClickTarget: false\n        },\n        // Manually add the target. The tour would do this, if it were a real tour\n        target: firstAttachElement\n      },\n      {\n        options: {\n          attachTo: {\n            element: '.second-attach-to',\n            on: 'bottom'\n          },\n          canClickTarget: false\n        },\n        // Manually add the target. The tour would do this, if it were a real tour\n        target: secondAttachElement\n      },\n      {\n        options: {\n          attachTo: {\n            element: '.third-attach-to',\n            on: 'bottom'\n          },\n          canClickTarget: false\n        },\n        // Manually add the target. The tour would do this, if it were a real tour\n        target: thirdAttachElement,\n        // Add extra highlights\n        _resolvedExtraHighlightElements: [\n          extraHighlightElement,\n          extraHighlightElement2\n        ]\n      }\n    ]\n  };\n\n  describe('cleanupSteps', function () {\n    it('cleans up steps and removes shepherd-target-click-disabled class', () => {\n      expect(firstAttachElement).toHaveClass('shepherd-target-click-disabled');\n      expect(secondAttachElement).toHaveClass('shepherd-target-click-disabled');\n      expect(thirdAttachElement).toHaveClass('shepherd-target-click-disabled');\n      expect(extraHighlightElement).toHaveClass(\n        'shepherd-target-click-disabled'\n      );\n      expect(extraHighlightElement2).toHaveClass(\n        'shepherd-target-click-disabled'\n      );\n\n      cleanupSteps(mockedTour);\n\n      expect(firstAttachElement).not.toHaveClass(\n        'shepherd-target-click-disabled'\n      );\n      expect(secondAttachElement).not.toHaveClass(\n        'shepherd-target-click-disabled'\n      );\n      expect(thirdAttachElement).not.toHaveClass(\n        'shepherd-target-click-disabled'\n      );\n      expect(extraHighlightElement).not.toHaveClass(\n        'shepherd-target-click-disabled'\n      );\n      expect(extraHighlightElement2).not.toHaveClass(\n        'shepherd-target-click-disabled'\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/test/unit/utils/general.spec.js",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\nimport { Step } from '../../../src/step';\nimport {\n  parseAttachTo,\n  shouldCenterStep,\n  parseExtraHighlights\n} from '../../../src/utils/general';\nimport { getFloatingUIOptions } from '../../../src/utils/floating-ui';\n\ndescribe('General Utils', function () {\n  let optionsElement;\n\n  beforeEach(() => {\n    optionsElement = document.createElement('div');\n    optionsElement.classList.add('options-test');\n    document.body.appendChild(optionsElement);\n  });\n\n  afterEach(() => {\n    document.body.removeChild(optionsElement);\n  });\n\n  describe('parseAttachTo()', function () {\n    it('fails if element does not exist', function () {\n      const step = new Step(\n        {},\n        {\n          attachTo: { element: '.element-does-not-exist', on: 'center' }\n        }\n      );\n\n      const { element } = parseAttachTo(step);\n      expect(element).toBeFalsy();\n    });\n\n    it('accepts callback function as element', function () {\n      const callback = vi.fn();\n\n      const step = new Step(\n        {},\n        {\n          attachTo: { element: callback, on: 'center' }\n        }\n      );\n\n      parseAttachTo(step);\n      expect(callback).toHaveBeenCalled();\n    });\n\n    it('correctly resolves elements when given function that returns a selector', function () {\n      const step = new Step(\n        {},\n        {\n          attachTo: { element: () => 'body', on: 'center' }\n        }\n      );\n\n      const { element } = parseAttachTo(step);\n      expect(element).toBe(document.body);\n    });\n\n    it('binds element callback to step', function () {\n      const step = new Step(\n        {},\n        {\n          attachTo: {\n            element() {\n              expect(this).toBe(step);\n            },\n            on: 'center'\n          }\n        }\n      );\n\n      parseAttachTo(step);\n    });\n  });\n\n  describe('parseExtraHighlights()', function () {\n    it('returns empty array if extraHighlights is not defined', function () {\n      const step = new Step({}, {});\n\n      const highlights = parseExtraHighlights(step);\n      expect(highlights).toEqual([]);\n    });\n\n    it('returns empty array if extraHighlights is an empty array', function () {\n      const step = new Step({}, { extraHighlights: [] });\n\n      const highlights = parseExtraHighlights(step);\n      expect(highlights).toEqual([]);\n    });\n\n    it('resolves extraHighlights selectors to HTMLElements', function () {\n      const step = new Step({}, { extraHighlights: ['.options-test'] });\n\n      const highlights = parseExtraHighlights(step);\n      expect(highlights).toEqual([optionsElement]);\n    });\n\n    it('returns empty array if no elements match the extraHighlights selectors', function () {\n      const step = new Step({}, { extraHighlights: ['.non-existent-class'] });\n\n      const highlights = parseExtraHighlights(step);\n      expect(highlights).toEqual([]);\n    });\n  });\n\n  describe('floatingUIOptions', function () {\n    it('middleware options are passed in last', function () {\n      const step = new Step(\n        {},\n        {\n          attachTo: { element: '.options-test', on: 'right' },\n          floatingUIOptions: {\n            middleware: [\n              {\n                name: 'preventOverflow',\n                options: {\n                  altAxis: false\n                }\n              }\n            ]\n          }\n        }\n      );\n\n      const floatingUIOptions = getFloatingUIOptions(\n        step.options.attachTo,\n        step\n      );\n      // Shepherd pushes in flip and shift by default, so this is 3rd\n      expect(floatingUIOptions.middleware[2].options.altAxis).toBe(false);\n    });\n\n    it('positioning strategy is explicitly set', function () {\n      const step = new Step(\n        {},\n        {\n          attachTo: { element: '.options-test', on: 'center' },\n          options: {\n            floatingUIOptions: {\n              strategy: 'absolute'\n            }\n          }\n        }\n      );\n\n      const floatingUIOptions = getFloatingUIOptions(\n        step.options.attachTo,\n        step\n      );\n      expect(floatingUIOptions.strategy).toBe('absolute');\n    });\n  });\n\n  describe('shouldCenterStep()', () => {\n    it('Returns true when resolved attachTo options are falsy', () => {\n      const emptyObjAttachTo = {};\n      const emptyArrAttachTo = [];\n      const nullAttachTo = null; // FAILS Cannot read properties of null (reading 'element')\n      const undefAttachTo = undefined; // FAILS Cannot read properties of undefined (reading 'element')\n\n      expect(shouldCenterStep(emptyObjAttachTo)).toBe(true);\n      expect(shouldCenterStep(emptyArrAttachTo)).toBe(true);\n      expect(shouldCenterStep(nullAttachTo)).toBe(true);\n      expect(shouldCenterStep(undefAttachTo)).toBe(true);\n    });\n\n    it('Returns false when element and on properties are truthy', () => {\n      const testAttachTo = {\n        element: '.pseudo',\n        on: 'right'\n      };\n\n      expect(shouldCenterStep(testAttachTo)).toBe(false);\n    });\n\n    it('Returns true when element property is null', () => {\n      const elementAttachTo = { element: null }; // FAILS\n\n      expect(shouldCenterStep(elementAttachTo)).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "shepherd.js/tsconfig.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/tsconfig\",\n  \"compilerOptions\": {\n    \"target\": \"es2021\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    // We don't want to include types dependencies in our compiled output, so tell TypeScript\n    // to enforce using `import type` instead of `import` for Types.\n    \"verbatimModuleSyntax\": true,\n    \"allowJs\": true,\n    \"strict\": true,\n    \"noUncheckedIndexedAccess\": true,\n    \"allowArbitraryExtensions\": true,\n    \"allowSyntheticDefaultImports\": false,\n    \"allowImportingTsExtensions\": true,\n    \"esModuleInterop\": true,\n    // --- Lint-style rules\n\n    // TypeScript also supplies some lint-style checks; nearly all of them are\n    // better handled by ESLint with the `@typescript-eslint`. This one is more\n    // like a safety check, though, so we leave it on.\n    \"noPropertyAccessFromIndexSignature\": true,\n    // --- Compilation/integration settings\n    // Setting `noEmitOnError` here allows tools trying to respect the tsconfig\n    // to still emit code without breaking on errors.\n    // Errors are still reported in the CLI when running `tsc`,\n    // but the errors won't prevent code from being emitted.\n    // This helps hasten development by allowing devs to prototype before coming\n    // to a decision on what they want their types to be.\n    \"noEmitOnError\": false,\n    // We use Babel for emitting runtime code, because it's very important that\n    // we always and only use the same transpiler for non-stable features.\n    // If you were to change this to `true`, it could lead to accidentally\n    // generating code with `tsc` instead of Babel, and could thereby\n    // result in broken code at runtime.\n    \"emitDeclarationOnly\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"declarationDir\": \"dist\",\n    \"inlineSourceMap\": true,\n    \"inlineSources\": true,\n    \"skipLibCheck\": true,\n    \"paths\": {\n      \"src/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "shepherd.js/vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  test: {\n    globals: true,\n    environment: 'happy-dom',\n    setupFiles: ['./test/unit/setupTests.js'],\n    coverage: {\n      provider: 'v8',\n      reporter: ['text', 'lcov', 'html'],\n      reportsDirectory: './test/coverage',\n      include: ['src/**/*.ts'],\n      exclude: [\n        '**/*.spec.{js,ts}',\n        '**/*.test.{js,ts}',\n        '**/node_modules/**',\n        '**/dist/**',\n        '**/tmp/**',\n        '**/test/**'\n      ]\n    }\n  },\n  resolve: {\n    alias: {\n      'shepherd.js': './src'\n    },\n    conditions: ['browser']\n  },\n  define: {\n    'import.meta.vitest': undefined,\n    'import.meta.env.SSR': false\n  }\n});\n"
  },
  {
    "path": "stderr.log",
    "content": "Warning: unknown package \"shepherd-docs\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"cypress-tests\"\nWarning: unknown package \"unit-tests\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"cypress-tests\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"unit-tests\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"unit-tests\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"landing\"\n(node:2262) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.\n(Use `node --trace-deprecation ...` to show where the warning was created)\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"unit-tests\"\n(node:2337) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.\n(Use `node --trace-deprecation ...` to show where the warning was created)\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"unit-tests\"\n(node:2278) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.\n(Use `node --trace-deprecation ...` to show where the warning was created)\n(node:2403) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.\n(Use `node --trace-deprecation ...` to show where the warning was created)\nWarning: unknown package \"cypress-tests\"\nWarning: unknown package \"landing\"\n(node:2504) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.\n(Use `node --trace-deprecation ...` to show where the warning was created)\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"cypress-tests\"\nWarning: unknown package \"unit-tests\"\nWarning: unknown package \"shepherd-docs\"\nWarning: unknown package \"landing\"\nWarning: unknown package \"cypress-tests\"\nWarning: unknown package \"unit-tests\"\n"
  }
]