├── .circleci └── config.yml ├── .eslintrc.js ├── .github ├── codeql │ └── codeql-config.yml └── workflows │ └── codeql.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── demo ├── src │ ├── AutoAlignment.tsx │ ├── Demo.tsx │ ├── PositionAlignOverview.tsx │ ├── hooks │ │ ├── index.ts │ │ └── useWatcher.ts │ ├── index.html │ ├── index.tsx │ └── regressions │ │ ├── ButtonOverlay.tsx │ │ ├── FitOnPage.tsx │ │ ├── Regression.tsx │ │ ├── Regressions.tsx │ │ ├── SameWidth.tsx │ │ ├── ScrollPosition.tsx │ │ ├── StickInSvg.tsx │ │ ├── StickNodeWidth.tsx │ │ ├── StickOnHover.tsx │ │ ├── StyledWithDataAttributes.tsx │ │ ├── TransportToFixedContainer.tsx │ │ └── index.ts ├── tsconfig.json └── vite.config.ts ├── package-lock.json ├── package.json ├── renovate.json ├── src ├── Stick.tsx ├── StickContext.ts ├── StickInline.tsx ├── StickNode.tsx ├── StickPortal.tsx ├── defaultPosition.ts ├── hooks │ ├── index.ts │ ├── useAutoFlip.ts │ └── useWatcher.ts ├── index.ts ├── tsconfig.json ├── types.ts └── utils │ ├── fit.ts │ ├── getDefaultAlign.ts │ ├── getModifiers.ts │ ├── index.ts │ ├── scroll.ts │ └── uniqueId.ts ├── tests ├── cypress.config.ts ├── node │ └── ssr.spec.tsx ├── src │ ├── autoPositioning.test.tsx │ ├── customComponent.test.tsx │ ├── nodeWidth.test.tsx │ ├── onClickOutside.test.tsx │ ├── positioning.test.tsx │ ├── scroll.test.tsx │ ├── updates.test.tsx │ └── utils.tsx ├── support │ ├── commands.ts │ ├── component-index.html │ └── component.ts ├── tsconfig.json └── vitest.config.ts └── tsconfig.base.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | fortify: signavio/fortify@2.0.0 5 | blackduck: signavio/blackduck@2.1.0 6 | codecov: codecov/codecov@3.3.0 7 | 8 | executors: 9 | fortify: 10 | machine: 11 | image: &ubuntu "ubuntu-2204:current" 12 | resource_class: medium 13 | 14 | commands: 15 | install-codecov-requirements: 16 | steps: 17 | - run: 18 | name: "Install codecov requirements" 19 | command: | 20 | apt-get -y update && apt-get install -y git curl gpg 21 | 22 | install-cypress-requirements: 23 | steps: 24 | - run: 25 | name: "Install cypress requirements" 26 | command: | 27 | apt-get -y install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb 28 | 29 | fortify_scan: 30 | parameters: 31 | build_id: 32 | type: string 33 | path: 34 | type: string 35 | translate_opts: 36 | type: string 37 | default: "" 38 | steps: 39 | - fortify/setup 40 | - run: 41 | name: Fortify translate << parameters.build_id >> 42 | command: sourceanalyzer -b << parameters.build_id >> -verbose << parameters.translate_opts >> << parameters.path >> 43 | - run: 44 | name: Fortify scan << parameters.build_id >> 45 | command: sourceanalyzer -b << parameters.build_id >> -verbose -scan -f << parameters.build_id >>.fpr 46 | - run: 47 | name: "Fortify: upload" 48 | command: | 49 | fortifyclient \ 50 | -url "$FORTIFY_SSC" \ 51 | -authtoken "$SSC_API_TOKEN" \ 52 | uploadFPR \ 53 | -file << parameters.build_id >>.fpr \ 54 | -project signavio-react-stick \ 55 | -version production 56 | 57 | references: 58 | defaults: &defaults 59 | working_directory: ~/repo 60 | docker: 61 | # use SAP Approved Build Container for gradle / jdk 62 | - image: node:20-slim 63 | 64 | restore_cache: &restore_cache 65 | restore_cache: 66 | keys: 67 | - deps-v5-{{ .Branch }}-{{ checksum "package-lock.json" }} 68 | - deps-v5-{{ .Branch }} 69 | - deps-v5 70 | 71 | jobs: 72 | install: 73 | <<: *defaults 74 | 75 | steps: 76 | - checkout 77 | 78 | - *restore_cache 79 | 80 | - run: npm ci --force 81 | 82 | - save_cache: 83 | key: deps-v5-{{ .Branch }}-{{ checksum "package-lock.json" }} 84 | paths: 85 | - node_modules 86 | - ~/.cache/Cypress 87 | 88 | lint: 89 | <<: *defaults 90 | 91 | steps: 92 | - checkout 93 | 94 | - *restore_cache 95 | 96 | - run: 97 | name: Lint 98 | command: npm run lint 99 | 100 | test: 101 | <<: *defaults 102 | steps: 103 | - checkout 104 | - install-codecov-requirements 105 | - install-cypress-requirements 106 | 107 | - *restore_cache 108 | 109 | - run: 110 | name: Test 111 | command: npm run test 112 | 113 | test-ssr: 114 | <<: *defaults 115 | steps: 116 | - checkout 117 | - install-codecov-requirements 118 | 119 | - *restore_cache 120 | 121 | - run: 122 | name: Test SSR 123 | command: npm run test:ssr -- --coverage 124 | 125 | release: 126 | <<: *defaults 127 | steps: 128 | - checkout 129 | - install-codecov-requirements 130 | - *restore_cache 131 | - run: 132 | name: Fix host authenticity for github.com 133 | command: mkdir -p ~/.ssh/ && ssh-keyscan github.com >> ~/.ssh/known_hosts 134 | - run: 135 | name: Build 136 | command: npm run build 137 | - run: 138 | name: Release 139 | command: npm run semantic-release 140 | 141 | fortify_scan: 142 | executor: fortify 143 | steps: 144 | - checkout 145 | - fortify_scan: 146 | build_id: signavio-react-stick 147 | path: src 148 | 149 | lint_commit_message: 150 | <<: *defaults 151 | steps: 152 | - checkout 153 | - install-codecov-requirements 154 | - *restore_cache 155 | - run: 156 | name: Define environment variable with lastest commit's message 157 | command: | 158 | echo 'export COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")' >> $BASH_ENV 159 | source $BASH_ENV 160 | - run: 161 | name: Lint commit message 162 | command: echo "$COMMIT_MESSAGE" | npx commitlint 163 | 164 | workflows: 165 | version: 2 166 | qa-publish-release: 167 | jobs: 168 | - install 169 | - lint: 170 | requires: 171 | - install 172 | - test: 173 | requires: 174 | - install 175 | filters: 176 | branches: 177 | ignore: master 178 | post-steps: 179 | - codecov/upload: 180 | file: tests/coverage/clover.xml 181 | flags: e2e 182 | - test-ssr: 183 | requires: 184 | - install 185 | filters: 186 | branches: 187 | ignore: master 188 | post-steps: 189 | - codecov/upload: 190 | file: coverage/clover.xml 191 | flags: ssr 192 | - lint_commit_message: 193 | requires: 194 | - install 195 | - release: 196 | context: NPM_AUTOMATION 197 | requires: 198 | - install 199 | - lint_commit_message 200 | filters: 201 | branches: 202 | only: master 203 | 204 | blackduck-nightly-scan: 205 | triggers: 206 | - schedule: 207 | cron: "0 0 * * *" # UTC 208 | filters: 209 | branches: 210 | only: master 211 | jobs: 212 | - install: 213 | context: ECR 214 | - blackduck/blackduck-scan: 215 | context: 216 | - ECR 217 | - BlackDuck 218 | blackduck-project-group: SAP_Signavio_Process_Governance 219 | blackduck-project-name: react-stick 220 | blackduck-project-path: /home/circleci/project 221 | npm-types-excluded: DEV 222 | requires: 223 | - install 224 | 225 | # Run fortify scan twice a month schedueled 226 | schedueled_fortify_scan: 227 | triggers: 228 | - schedule: 229 | # every 1st and 15th of the month 230 | cron: "0 0 1,15 * *" 231 | filters: 232 | branches: 233 | only: 234 | - master 235 | jobs: 236 | - fortify_scan: 237 | context: fortify 238 | 239 | # Run fortify scan on demand 240 | on_demand_fortify_scan: 241 | jobs: 242 | - approve-fortify-scan: 243 | type: approval 244 | filters: 245 | branches: 246 | only: 247 | - master 248 | - fortify_scan: 249 | requires: 250 | - approve-fortify-scan 251 | context: 252 | - fortify 253 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['react-app', 'prettier'], 3 | plugins: ['prettier'], 4 | rules: { 5 | 'prettier/prettier': [ 6 | 'error', 7 | { 8 | semi: false, 9 | singleQuote: true, 10 | trailingComma: 'es5', 11 | }, 12 | ], 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | paths-ignore: 2 | - '**/*.min.js' 3 | - build/ 4 | - dist/ 5 | - packages/**/dist 6 | - '**/*.readonly.js' 7 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master", "codeQlAct"] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ,"codeQlAct"] 20 | schedule: 21 | - cron: '45 7 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | queries: security-extended 50 | config-file: ./.github/codeql/codeql-config.yml 51 | languages: ${{ matrix.language }} 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v3 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 60 | 61 | # If the Autobuild fails above, remove it and uncomment the following three lines. 62 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 63 | 64 | # - run: | 65 | # echo "Run, Build Application using script" 66 | # ./location_of_script_within_repo/buildscript.sh 67 | 68 | - name: Perform CodeQL Analysis 69 | uses: github/codeql-action/analyze@v3 70 | with: 71 | category: "/language:${{matrix.language}}" 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /demo/dist 2 | /es 3 | /lib 4 | /node_modules 5 | npm-debug.log* 6 | /build 7 | .DS_Store 8 | /tests/.nyc_output 9 | cypress 10 | pnpm-lock.yaml 11 | yarn.lock 12 | /.vscode 13 | coverage -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit "${1}" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | "dbaeumer.vscode-eslint", 8 | "drknoxy.eslint-disable-snippets", 9 | "esbenp.prettier-vscode", 10 | ], 11 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 12 | "unwantedRecommendations": [] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "javascript.validate.enable": false, 3 | "editor.tabSize": 2, 4 | "search.exclude": { 5 | ".git": true, 6 | "**/node_modules": true, 7 | "**/lib": true, 8 | "**/lib-es6": true, 9 | "target": true 10 | }, 11 | "editor.formatOnSave": true, 12 | "[typescript]": { 13 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 14 | }, 15 | "[javascript]": { 16 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 17 | }, 18 | "[typescriptreact]": { 19 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 20 | }, 21 | "[css]": { 22 | "editor.defaultFormatter": "esbenp.prettier-vscode" 23 | }, 24 | "[jsonc]": { 25 | "editor.defaultFormatter": "esbenp.prettier-vscode" 26 | }, 27 | "[html]": { 28 | "editor.defaultFormatter": "esbenp.prettier-vscode" 29 | }, 30 | "[json]": { 31 | "editor.defaultFormatter": "esbenp.prettier-vscode" 32 | }, 33 | "[less]": { 34 | "editor.defaultFormatter": "esbenp.prettier-vscode" 35 | }, 36 | "[yaml]": { 37 | "editor.defaultFormatter": "esbenp.prettier-vscode" 38 | }, 39 | "editor.codeActionsOnSave": { 40 | "source.fixAll.eslint": true 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | [Node.js](http://nodejs.org/) >= v6 must be installed. 4 | 5 | ## Installation 6 | 7 | - Running `npm install` in the component's root directory will install everything you need for development. 8 | 9 | ## Demo Development Server 10 | 11 | - `npm start` will run a development server with the component's demo app at [http://localhost:3000](http://localhost:3000) with hot module reloading. 12 | 13 | ## Running Tests 14 | 15 | - `npm test` will run the tests in command line. 16 | 17 | - `npm run test:open` will open the Cypress UI to run the cases interactively 18 | 19 | ## Building 20 | 21 | - `npm run build` will build the component for publishing to npm and also bundle the demo app. 22 | 23 | - `npm run clean` will delete built resources. 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Signavio GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-stick 2 | 3 | [![CircleCI][build-badge]][build] 4 | [![codecov][codecov-badge]][codecov] 5 | [![npm package][npm-badge]][npm] 6 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 7 | 8 | _Stick_ is a component that allows to attach an absolutely positioned node to a statically 9 | positioned anchor element. Per default, the node will be rendered in a portal as a direct 10 | child of the `body` element. 11 | 12 | ```bash 13 | npm install --save react-stick 14 | ``` 15 | 16 | ```javascript 17 | import Stick from 'react-stick' 18 | 19 | The stick node

} position="bottom center" align="top center"> 20 |

The anchor node

21 |
22 | ``` 23 | 24 | ## Props 25 | 26 | | prop name | type | description | 27 | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 28 | | `children` | node | The content of the anchor element | 29 | | `node` | node | The node to stick to the anchor element | 30 | | `position` | one of: `"bottom left"`, `"bottom center"`, `"bottom right"`, `"middle left"`, `"middle center"`, `"middle right"`, `"top left"`, `"top center"`, `"top right"` (default value: `"bottom left"`) | The reference point on the anchor element at which to position the stick node | 31 | | `align` | one of: `"bottom left"`, `"bottom center"`, `"bottom right"`, `"middle left"`, `"middle center"`, `"middle right"`, `"top left"`, `"top center"`, `"top right"` (default value depends on the `position`) | The alignment of the stick node. You can also think of this as the reference point on the stick node that is placed on the `position` reference point of the anchor node. For example `position="top left" align="bottom right"` means "put the bottom right point of the stick not onto the top left point of the anchor node". | 32 | | `sameWidth` | boolean | If set to `true`, the container of the stick node will have the same width as the anchor node. This enforces a maximum width on the content of the stick node. | 33 | | `autoFlipVertically` | boolean | If a node has been attached to the bottom but there isn't enough space on the screen it will automatically be positioned to the top. | 34 | | `autoFlipHorizontally` | boolean | If a node has been attached to the left but there isn't enough space on the screen it will automatically be positioned to the right. | 35 | | `onClickOutside` | function: (event: Event) => void | A handler that is called on every click on any element outside of the anchor element and the stick node. | 36 | | `inline` | boolean | If set to `true`, the stick node will not be rendered detached but inside the same container as the anchor node. | 37 | | `updateOnAnimationFrame` | boolean | If set to `true`, will update the stick node position on every animation frame. Per default, it will only update on idle callback. | 38 | | `component` | string | Pass any string-type React component that shall be rendered as the wrapper element around the children. Per default, `"div"` is used. | 39 | 40 | [build-badge]: https://dl.circleci.com/status-badge/img/gh/signavio/react-stick/tree/master.svg?style=svg 41 | [build]: https://circleci.com/gh/signavio/react-stick/tree/master 42 | [npm-badge]: https://img.shields.io/npm/v/react-stick.svg 43 | [npm]: https://www.npmjs.org/package/react-stick 44 | [codecov-badge]: https://img.shields.io/codecov/c/github/signavio/react-stick.svg 45 | [codecov]: https://codecov.io/gh/signavio/react-stick 46 | -------------------------------------------------------------------------------- /demo/src/AutoAlignment.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Stick from '../../es' 4 | 5 | function AutoAlignment() { 6 | return ( 7 |
8 |

Auto-Alignment

9 | 10 |

Vertical flipping

11 |
12 | 18 | This is the content of the node 19 |
20 | } 21 | > 22 |
29 | The node of this stick should move to the top if it can't fit to the 30 | bottom 31 |
32 | 33 |
34 | 35 |

Horizontal flipping

36 | 37 |
40 |
41 | 49 | This is the content of the node 50 |
51 | } 52 | > 53 |
60 | The node of this stick should move to the right if it can't fit to 61 | the left 62 |
63 | 64 |
65 | 66 | 67 | ) 68 | } 69 | 70 | export default AutoAlignment 71 | -------------------------------------------------------------------------------- /demo/src/Demo.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import AutoAlignment from './AutoAlignment' 4 | import PositionAlignOverview from './PositionAlignOverview' 5 | import Regressions from './regressions' 6 | 7 | export default function Demo() { 8 | return ( 9 |
10 |

react-stick

11 | 12 |

13 | 14 | Open documention on Github 15 | 16 |

17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /demo/src/PositionAlignOverview.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useRef, useState } from 'react' 2 | 3 | import Stick from '../../es' 4 | import { useWatcher } from './hooks' 5 | import { WatcherOptions } from './hooks/useWatcher' 6 | 7 | function formPairs( 8 | listA: readonly A[], 9 | listB: readonly B[] 10 | ): `${A} ${B}`[][] { 11 | return listA.map((a) => listB.map((b) => `${a} ${b}`)) as `${A} ${B}`[][] 12 | } 13 | 14 | const verticals = ['top', 'middle', 'bottom'] as const 15 | const horizontals = ['left', 'center', 'right'] as const 16 | 17 | const positionGroups = formPairs(verticals, horizontals) 18 | const alignmentGroups = formPairs(verticals, horizontals) 19 | 20 | const Anchor = () => ( 21 |
28 | ) 29 | 30 | const Node = () => ( 31 |
38 | ) 39 | 40 | function FramesPerSecond({ updateOnAnimationFrame }: WatcherOptions) { 41 | const [fps, setFps] = useState(0) 42 | const lastUpdated = useRef(Date.now()) 43 | const framesSinceLastUpdate = useRef(0) 44 | 45 | const measure = useCallback(() => { 46 | framesSinceLastUpdate.current += 1 47 | 48 | const duration = Date.now() - lastUpdated.current 49 | if (duration >= 1000) { 50 | setFps(framesSinceLastUpdate.current) 51 | 52 | framesSinceLastUpdate.current = 0 53 | lastUpdated.current = Date.now() 54 | } 55 | }, []) 56 | 57 | useWatcher(measure, { updateOnAnimationFrame }) 58 | 59 | return
FPS: {fps}
60 | } 61 | 62 | function PositionAlignOverview() { 63 | const [updateOnAnimationFrame, setUpdateOnAnimationFrame] = useState(false) 64 | const [inline, setInline] = useState(false) 65 | const [showNode, setShowNode] = useState(true) 66 | 67 | return ( 68 |
69 |

70 | The table shows all combinations of possible values for the{' '} 71 | position and align props. The{' '} 72 | node elements are colors in red while the anchor elements ( 73 | children) are colored in blue. 74 |

75 |
76 | setInline(!inline)} 80 | /> 81 | inline 82 |
83 |
84 | setUpdateOnAnimationFrame(!updateOnAnimationFrame)} 88 | /> 89 | updateOnAnimationFrame 90 |
91 |
92 | setShowNode(!showNode)} 96 | /> 97 | showNode 98 |
99 |
100 |