{"_id":"@alex-fitzgerald/parchment","_rev":"3-debc32201a1ff4788d0a5a9d9ef3ac37","name":"@alex-fitzgerald/parchment","dist-tags":{"latest":"0.0.5"},"versions":{"0.0.1":{"name":"@alex-fitzgerald/parchment","version":"0.0.1","license":"MIT","_id":"@alex-fitzgerald/parchment@0.0.1","maintainers":[{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"}],"homepage":"https://github.com/alex-fitzgerald/parchment#readme","bugs":{"url":"https://github.com/alex-fitzgerald/parchment/issues"},"dist":{"shasum":"0cedb7496d1aabbb5ee7b693a8d447198dcedd95","tarball":"https://registry.npmjs.org/@alex-fitzgerald/parchment/-/parchment-0.0.1.tgz","fileCount":2,"integrity":"sha512-7Wm5hXuoAHFgXq49Q6t5zezR4K8CMvrd+9yDxXJcdoW9VbFuNevSjUbkXWUq/1Y04Uze7J9sY85snAZbFnIDaw==","signatures":[{"sig":"MEQCICxLHYvOC8GeCxUWgI3QpA6whBWzG2QzVEPptlkCLi8IAiAUr1XquNvwPrvLvmyLlTFf1B0LoR7GBGqogIeVDScoDw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alex-fitzgerald%2fparchment@0.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":6361},"type":"module","gitHead":"44024a0b031a2bc61693a1da2c7c64a60cc64ed3","private":false,"scripts":{"ci":"npm run lint && npm run test && npm run build","dev":"vite","lint":"eslint .","test":"vitest run","build":"tsc -b && vite build","preview":"vite preview"},"_npmUser":{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"},"repository":{"url":"git+https://github.com/alex-fitzgerald/parchment.git","type":"git"},"_npmVersion":"10.8.2","description":"I love little scrollspies, particularly `notion's`. While they're simple as anything, I wanted to make my own.","directories":{},"_nodeVersion":"20.18.2","dependencies":{"react":"^18.3.1","react-dom":"^18.3.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vite":"^6.0.5","jsdom":"^26.0.0","eslint":"^9.17.0","vitest":"^2.1.9","globals":"^15.14.0","@eslint/js":"^9.17.0","typescript":"~5.6.2","@types/react":"^18.3.18","@types/react-dom":"^18.3.5","typescript-eslint":"^8.18.2","eslint-plugin-react":"^7.37.2","@vitejs/plugin-react":"^4.3.4","@testing-library/react":"^16.2.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","@stylistic/eslint-plugin":"^2.12.1","@testing-library/jest-dom":"^6.6.3","eslint-plugin-react-hooks":"^5.0.0","@testing-library/user-event":"^14.6.1","eslint-plugin-react-refresh":"^0.4.16"},"_npmOperationalInternal":{"tmp":"tmp/parchment_0.0.1_1739405856670_0.69192624536097","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@alex-fitzgerald/parchment","version":"0.0.2","license":"MIT","_id":"@alex-fitzgerald/parchment@0.0.2","maintainers":[{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"}],"homepage":"https://github.com/alex-fitzgerald/parchment#readme","bugs":{"url":"https://github.com/alex-fitzgerald/parchment/issues"},"dist":{"shasum":"a5b175e2bb313bffc20cad0fb19892bf9ce089e3","tarball":"https://registry.npmjs.org/@alex-fitzgerald/parchment/-/parchment-0.0.2.tgz","fileCount":29,"integrity":"sha512-gLWJNxI0fZctw+d/Wzd6MHinQDrtTyOpHBJ8qSywC4TXzgMnci0gUADjubfGOHtRlrBR72u7S7/dHIwCNG4ShA==","signatures":[{"sig":"MEQCIBT+wwzGRFbYtGzl4T2UUtEvnj7ZnbHz+ZsDqTJHenycAiAQGCSWNb5gTgKpnNF1VaX6oO8JAHsb45uQJOIeXur0fw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alex-fitzgerald%2fparchment@0.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":51852},"type":"module","gitHead":"dee743499b8b84ce0d910b0482fbc2f43f2bf601","private":false,"scripts":{"ci":"npm run lint && npm run test && npm run build","dev":"vite","lint":"eslint .","test":"vitest run","build":"tsc -b && vite build","preview":"vite preview"},"_npmUser":{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"},"repository":{"url":"git+https://github.com/alex-fitzgerald/parchment.git","type":"git"},"_npmVersion":"10.8.2","description":"I love little scrollspies, particularly `notion's`. While they're simple as anything, I wanted to make my own.","directories":{},"_nodeVersion":"20.18.2","dependencies":{"react":"^18.3.1","react-dom":"^18.3.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vite":"^6.0.5","jsdom":"^26.0.0","eslint":"^9.17.0","vitest":"^2.1.9","globals":"^15.14.0","@eslint/js":"^9.17.0","typescript":"~5.6.2","@types/react":"^18.3.18","@types/react-dom":"^18.3.5","typescript-eslint":"^8.18.2","eslint-plugin-react":"^7.37.2","@vitejs/plugin-react":"^4.3.4","@testing-library/react":"^16.2.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","@stylistic/eslint-plugin":"^2.12.1","@testing-library/jest-dom":"^6.6.3","eslint-plugin-react-hooks":"^5.0.0","@testing-library/user-event":"^14.6.1","eslint-plugin-react-refresh":"^0.4.16"},"_npmOperationalInternal":{"tmp":"tmp/parchment_0.0.2_1739410862224_0.9571784758681501","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@alex-fitzgerald/parchment","version":"0.0.4","license":"MIT","_id":"@alex-fitzgerald/parchment@0.0.4","maintainers":[{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"}],"homepage":"https://github.com/alex-fitzgerald/parchment#readme","bugs":{"url":"https://github.com/alex-fitzgerald/parchment/issues"},"dist":{"shasum":"2c91d7877b0c3390b82c478e70d193153c2eb771","tarball":"https://registry.npmjs.org/@alex-fitzgerald/parchment/-/parchment-0.0.4.tgz","fileCount":16,"integrity":"sha512-SzsA3I7Uo93YDhN0wazjymeA0u6OauySy7sL4iKJpkhDz2E9otQWa08VmGIGwx9dtYlXBHgtjwIPOzS9OvfbYA==","signatures":[{"sig":"MEYCIQCZCA1QhrKFeSFHOM7JtRwusjHLUXuSfHzDOdvLtEEk5AIhALwHhrF7bpADnJk5BWms3G/71Sa7DmTscBo9YUruluTW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alex-fitzgerald%2fparchment@0.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":34182},"type":"module","gitHead":"ed12a56ed8b91c906ab579f783ef8d5819e58d0c","private":false,"scripts":{"ci":"npm run lint && npm run test && npm run build","dev":"vite","lint":"eslint .","test":"vitest run","build":"tsc -b && vite build","preview":"vite preview"},"_npmUser":{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"},"repository":{"url":"git+https://github.com/alex-fitzgerald/parchment.git","type":"git"},"_npmVersion":"10.8.2","description":"I love little scrollspies, particularly `notion's`. While they're simple as anything, I wanted to make my own.","directories":{},"_nodeVersion":"20.18.2","dependencies":{"react":"^18.3.1","react-dom":"^18.3.1","@alex-fitzgerald/noise":"^1.0.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vite":"^6.0.5","jsdom":"^26.0.0","eslint":"^9.17.0","vitest":"^2.1.9","globals":"^15.14.0","@eslint/js":"^9.17.0","typescript":"~5.6.2","@types/react":"^18.3.18","@types/react-dom":"^18.3.5","typescript-eslint":"^8.18.2","eslint-plugin-react":"^7.37.2","@vitejs/plugin-react":"^4.3.4","@testing-library/react":"^16.2.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","@stylistic/eslint-plugin":"^2.12.1","@testing-library/jest-dom":"^6.6.3","eslint-plugin-react-hooks":"^5.0.0","@testing-library/user-event":"^14.6.1","eslint-plugin-react-refresh":"^0.4.16"},"_npmOperationalInternal":{"tmp":"tmp/parchment_0.0.4_1739517156056_0.16694203850027645","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@alex-fitzgerald/parchment","private":false,"license":"MIT","version":"0.0.5","type":"module","repository":{"type":"git","url":"git+https://github.com/alex-fitzgerald/parchment.git"},"scripts":{"dev":"vite","test":"vitest run","build":"tsc -b && vite build","lint":"eslint .","preview":"vite preview","ci":"npm run lint && npm run test && npm run build"},"devDependencies":{"@alex-fitzgerald/noise":"^1.0.1","@eslint/js":"^9.17.0","@stylistic/eslint-plugin":"^2.12.1","@testing-library/jest-dom":"^6.6.3","@testing-library/react":"^16.2.0","@testing-library/user-event":"^14.6.1","@types/react":"^18.3.18","@types/react-dom":"^18.3.5","@vitejs/plugin-react":"^4.3.4","eslint":"^9.17.0","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","eslint-plugin-react":"^7.37.2","eslint-plugin-react-hooks":"^5.0.0","eslint-plugin-react-refresh":"^0.4.16","globals":"^15.14.0","jsdom":"^26.0.0","tsup":"^8.3.5","typescript":"~5.6.2","typescript-eslint":"^8.18.2","vite":"^6.0.5","vitest":"^2.1.9"},"dependencies":{"react":"^18.3.1","react-dom":"^18.3.1"},"_id":"@alex-fitzgerald/parchment@0.0.5","gitHead":"fcaa92d617fb8eda0e6640b2176c058e84b1734d","description":"I love little scrollspies, particularly `notion's`. While they're simple as anything, I wanted to make my own.","bugs":{"url":"https://github.com/alex-fitzgerald/parchment/issues"},"homepage":"https://github.com/alex-fitzgerald/parchment#readme","_nodeVersion":"20.18.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-WnFxSv/O8/kZ1YOY+a0ZIg1ytWLxvK2hPwk1aGto5LoK+cwaG0xaU0/3GhNl/Fh0f8QLT4cFZtKlhqMAgY2T2Q==","shasum":"e7de7e878ac051112045cf7ccef835a8de9d1395","tarball":"https://registry.npmjs.org/@alex-fitzgerald/parchment/-/parchment-0.0.5.tgz","fileCount":16,"unpackedSize":34182,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alex-fitzgerald%2fparchment@0.0.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCYP/h/T38uSlVNL9mq9ERcTfHKzsfT8tZ4LVwoLVAcBQIgJhSyvpDsxLii5U7t2gmNlKN2yB3ssDzDEFqF5iS/Vcg="}]},"_npmUser":{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"},"directories":{},"maintainers":[{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/parchment_0.0.5_1739517371777_0.48672667271235803"},"_hasShrinkwrap":false}},"time":{"created":"2025-02-13T00:17:36.557Z","modified":"2025-02-14T07:16:12.487Z","0.0.1":"2025-02-13T00:17:36.868Z","0.0.2":"2025-02-13T01:41:02.472Z","0.0.4":"2025-02-14T07:12:36.246Z","0.0.5":"2025-02-14T07:16:12.013Z"},"bugs":{"url":"https://github.com/alex-fitzgerald/parchment/issues"},"license":"MIT","homepage":"https://github.com/alex-fitzgerald/parchment#readme","repository":{"type":"git","url":"git+https://github.com/alex-fitzgerald/parchment.git"},"description":"I love little scrollspies, particularly `notion's`. While they're simple as anything, I wanted to make my own.","maintainers":[{"name":"alex-fitzgerald","email":"fitzgerald.s.alexander@gmail.com"}],"readme":"# 📜 Parchment\n\nI love little scrollspies, particularly `notion's`. While they're simple as anything, I wanted to make my own.\n\n<img alt=\"Notion's cute wee scrollspy\" src=\"https://github.com/user-attachments/assets/b2ad4bbe-835e-4ea2-aac4-81d29b445158\" width=\"150px\" />\n\nParchment is a simple wee handful of headless components to help compose scrollspies. No dependencies other than the usual `react`\n\n<small>_Scroll_able... Parchment... 📜</small>\n\n<a href=\"https://parchment.alexfitzgerald.io/\">Check out the demo here</a>\n\n## Installation\n```bash\nnpm install parchment\n```\n\nDone. No dependencies outside of `react` and `react-dom`.\n\n## Usage\nFirst off the bat: we're using Context, so you'll need to wrap any parchment fellas with the `ParchmentProvider`.\n\n## `Parchment`\nThe scroll, which will have sections that can be scrolled to. Can accept any `ReactNode` children.\nOnly `ParchmentSections` are observed by our `parchment` scrollspy. \n\n```tsx\nimport { Parchment } from 'parchment';\n\ninterface ParchmentOptions {\n    /**\n     * Sets the intersection threshold for all parchment sections.\n     *\n     * @default 0.5\n     */\n    intersectionThreshold?: number;\n    /**\n     * Sets options for the `scrollIntoView` method, when a ParchmentButton is clicked.\n     *\n     * @default { behavior: 'smooth', block: 'center' }\n     */\n    scrollIntoViewOptions?: ScrollIntoViewOptions;\n    /**\n     * Whether to enable scroll-snapping on the parchment container.\n     *\n     * @default false\n     */\n    snap?: boolean;\n}\n\nreturn (\n    <Parchment snap={true} scrollIntoViewOptions={{ block: 'start' }} intersectionThreshold={0.3}>\n        {...sections}\n    </Parchment>\n)\n\n```\n\n## Sections\nAny 'scrollable' sections should be wrapped in a `ParchmentSection` component. This will register the section with the context.\n\n```jsx\nimport { Parchment, ParchmentSection } from 'parchment';\n\nfunction MyScrollableSections() {\n    return (\n        <Parchment>\n            <ParchmentSection section=\"my-section\">\n                {/* Your content here */}\n            </ParchmentSection>\n        </Parchment>\n    );\n}\n```\n\n## Buttons\nParchment buttons are wired up to know when their associated section is in view. An 'active' class is\napplied to the button, or passed as a boolean argument to a function.\n\n### .active class\n```jsx\nimport ParchmentButton from 'parchment';\n\n/*\n * .parchment-button.active {\n *      color: rebeccapurple;\n * }\n */\nfunction MyButton() {\n  return (\n    <ParchmentButton section=\"my-section\">\n        My Section Name\n    </ParchmentButton>\n  );\n}\n```\n\n### active argument\n```jsx\n/**\n * If the `ParchmentButton` child is a function, it is called\n * with a boolean reflecting whether the section is in view.\n */\nfunction MyButton() {\n  return (\n    <ParchmentButton section=\"my-section\">\n        {(active) => (\n            <div style={{ color: active ? 'rebeccapurple' : 'blue' }}>\n                My Section Name\n            </div>\n        )}\n    </ParchmentButton> \n  );\n}\n```\n\nSo, at the end of the day, we're up and away with the following:\n\n```jsx\nimport { Parchment, ParchmentSection, ParchmentButton } from 'parchment';\n\nfunction MyScrollableSections() {\n    return (\n        <ParchmentProvider>\n            <ParchmentButton section=\"my-section\">\n                My Section Name\n            </ParchmentButton>\n            <Parchment>\n                <ParchmentSection section=\"my-section\">\n                    {/* Your content here */}\n                </ParchmentSection>\n            </Parchment>\n        </ParchmentProvider>\n    );\n}\n```\n\n## Other APIS\n### `useParchment`\n\nThe `useParchment` hook provides a few useful functions for interacting with the Parchment context.\n\n#### `scrollTo`\nUses the window's native `scrollIntoView` method to scroll to a section by key, but with options loaded in the parchment context.\n\n#### `inView`\nReturns the key of the section currently in viewport, e.g.:\n\n```jsx\nimport { useParchment } from 'parchment';\n\nfunction MyComponent() {\n    const { scrollTo, inView } = useParchment();\n\n    console.log(inView); // 'my-section'\n\n    return (\n        <button onClick={() => scrollTo('my-section')}>\n            Scroll to my section\n        </button>\n    );\n}\n```\n\n#### ScrollOptions\n`Parchment` accepts the global [`ScrollIntoViewOptions`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#scrollintoviewoptions) object as a `prop`.\n\n## Contributions\nFeel free to contribute. Has the default vite scripts, so to get up and running after cloning just run `npm run dev`.\n\n## TODO:\n- [ ] Add tests\n- [ ] Add more features\n- [ ] Add horizontal/vertical option\n- [ ] Add `asChild` prop to `ParchmentButton` to allow for custom components\n- [ ] Add `threshold` prop to `ParchmentButton` to allow for custom scroll thresholds\n- [ ] Add `percentInView` option?\n- [ ] Review from performance perspective - what needs to be memoised?\n","readmeFilename":"README.md"}