Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .babelrc

This file was deleted.

24 changes: 24 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
root: true,
env: { browser: true, es2021: true },
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
],
ignorePatterns: ["dist", ".eslintrc.js"],
parserOptions: { ecmaVersion: "latest", sourceType: "module" },
settings: { react: { version: "18.2.0" } },
plugins: ["react-refresh", "@typescript-eslint"],
rules: {
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
"@typescript-eslint/no-unused-vars": "error",
// to enforce using type for object type definitions, can be type or interface
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
},
};
28 changes: 24 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
.cache/
dist/
node_modules/
build/
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
163 changes: 129 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,167 @@
# 👣 react-footnotes

dead simple footnotes, in React
Dead simple footnotes, in React!
Works with React 18!

<img width="399" alt="react-footnotes" src="https://user-images.githubusercontent.com/182661/44605190-611d5980-a7b6-11e8-858b-0e640965a7b6.png">
- Removes `react-tree-walker` for a super tiny, pure component with no side-effects!
- Doesn't alter wrapped element (NO EXTRA divs or spans!)
- Automatic number increments for each Footnote
- Automatic footnote anchoring and linking

## Authors

- [@moimikey](https://www.github.com/moimikey)

## Demo

Insert gif or link to demo

## Screenshots

![App Screenshot](https://via.placeholder.com/468x300?text=App+Screenshot+Here)

## Installation

```sh
npm install --save react-footnotes
npm install react-footnotes
# OR
yarn add react-footnotes
# OR
pnpm install react-footnotes
# OR
bun install react-footnotes
```

## Usage/Examples

### 1. Import the `Footnotes` component

```js
// esmodules
import { Footnotes } from 'react-footnotes'
import { Footnotes } from "react-footnotes";

// commonjs
var Footnotes = require('react-footnotes').Footnotes
const { Footnotes } = require("react-footnotes");
```

## Usage
### 2. Use the built-in Footnote component, or make your own

Pass any props you want to read from `getFootnotes`, to `Footnote`.
```tsx
{({ Footnote, FootnotesProvider, footnotes }) => {
return (
<FootnotesProvider>
<Footnote>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</Footnote>{" "}
...
```

or create your own:

```jsx
import * as React from 'react'
import { Footnotes } from 'react-footnotes'
function SpecialFootnote({ children, id }) {
return (
<React.Fragment key={`footnote-${id}}`}>
{children}
<a rel="footnote" href={`#footnote-${id}`} id={`footnote-link-${id}`}>
<sup>{id}</sup>
</a>
</React.Fragment>
);
}
...
{({ FootnotesProvider, footnotes }) => {
return (
<FootnotesProvider>
<SpecialFootnote>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</SpecialFootnote>
...
```

### 3. Render it

class App extends React.Component {
render() {
return (
```tsx
export function App() {
return (
<ErrorBoundary>
<Footnotes>
{({ Footnote, getFootnotes }) => (
<React.Fragment>
<Footnote i={1} desc={`this is a description.`}>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Footnote> Text that doesnt need to be footnoted, can be passed as normal text.
<Footnote i={2} desc={`this is a description.`}>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</Footnote>
<Footnote i={3} desc={`this is a description.`}>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</Footnote>
<Footnote i={4} desc={`this is a description.`}>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</Footnote>
<ol>
{Object.keys(getFootnotes()).map(i => {
{({ FootnotesProvider, footnotes }) => {
return (
<FootnotesProvider>
<SpecialFootnote>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</SpecialFootnote>{" "}
<Footnote>
Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</Footnote>{" "}
<hr />
References: should only show {footnotes.size}
{Array.from(footnotes).map(([id, footnote]: FootnoteEntry) => {
return (
<li key={`footnote-${i}`} id={`footnote-${i}`}>{getFootnotes()[i].desc}</li>
)
<div id={`footnote-${id}`} key={`footnote-fragment-${id}`}>
<a
href={`#footnote-link-${id}`}
key={`footnote-link-${id}`}
>
<sup>{id}</sup>
</a>{" "}
{footnote}
</div>
);
})}
</ol>
</React.Fragment>
)}
</FootnotesProvider>
);
}}
</Footnotes>
)
}
</ErrorBoundary>
);
}
```

## TODO
## Run Locally

- [ ] automatically generate the index number so it doesn't have to be passed manually...
Clone the project

```sh
git clone [email protected]:moimikey/react-footnotes.git
```

## Development
Go to the project directory

```sh
npm run dev
cd react-footnotes
```

Install dependencies

# go to http://localhost:1234
```sh
pnpm install
```

Start the server

```sh
pnpm dev
```

### Distribution
## Running Tests

To run tests, run the following command

```sh
npm run build
pnpm run test
```

## Contributing

Contributions are always welcome!

See `contributing.md` for ways to get started.

Please adhere to this project's `code of conduct`.

## License

[MIT](https://choosealicense.com/licenses/mit/)
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
15 changes: 15 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// eslint-disable-next-line
module.exports = {
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
testMatch: [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}",
"<rootDir>/test/**/*.{spec,test}.{js,jsx,ts,tsx}",
],
transform: {
"^.+\\.(js|jsx|ts|tsx)?$": "@swc/jest",
},
moduleNameMapper: {
"\\.(css|sass|scss)$": "identity-obj-proxy",
},
};
1 change: 1 addition & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
self.IS_REACT_ACT_ENVIRONMENT = true;
31 changes: 31 additions & 0 deletions lib/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Component } from "react";

export class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

componentDidCatch(error, info) {
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
console.error(error, info.componentStack);
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return this.props.fallback;
}

return this.props.children;
}
}
Loading