├── .babelrc ├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ └── main.yml ├── .gitignore ├── .npmrc ├── .storybook ├── main.js └── manager.js ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── package.json ├── rollup.config.js ├── src └── index.ts ├── stories └── index.js └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "production": { 4 | "plugins": [ 5 | "@babel/plugin-transform-react-constant-elements", 6 | "@babel/plugin-transform-runtime" 7 | ] 8 | } 9 | }, 10 | "presets": [ 11 | ["@babel/preset-env", { 12 | "targets": { "browsers": [ 13 | ">0.25%", 14 | "not ie 11", 15 | "not op_mini all" 16 | ] } 17 | }], 18 | "@babel/preset-react" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | max_line_length = 100 13 | indent_brace_style = 1TBS 14 | spaces_around_operators = true 15 | quote_type = auto 16 | 17 | [package.json] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | # Check for updates to GitHub Actions every weekday 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | with: 18 | token: ${{ secrets.GITHUB_TOKEN }} 19 | - name: Setup Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: lts/* 23 | - name: Setup PNPM 24 | uses: pnpm/action-setup@v4 25 | with: 26 | version: latest 27 | run_install: true 28 | - name: Test 29 | run: npm test 30 | - name: Release 31 | if: ${{ github.ref == 'refs/heads/master' && !startsWith(github.event.head_commit.message, 'chore(release):') && !startsWith(github.event.head_commit.message, 'docs:') }} 32 | env: 33 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 34 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 35 | run: | 36 | git config --global user.email ${{ secrets.GIT_EMAIL }} 37 | git config --global user.name ${{ secrets.GIT_USERNAME }} 38 | npm run release 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | yarn.lock 4 | dist 5 | .envrc 6 | stats.html 7 | storybook-static 8 | .vercel 9 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | unsafe-perm=true 2 | save-prefix=~ 3 | save=false 4 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ['../stories/*.js'], 3 | core: { builder: 'webpack5' } 4 | } 5 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/addons' 2 | import { create } from '@storybook/theming' 3 | 4 | const theme = create({ 5 | base: 'light', 6 | brandTitle: 'nanoclamp', 7 | brandUrl: 'https://github.com/microlinkhq/nanoclamp', 8 | appBg: 'white', 9 | appContentBg: 'white', 10 | appBorderColor: 'white' 11 | }) 12 | 13 | addons.setConfig({ theme }) 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### 2.0.14 (2025-03-24) 6 | 7 | ### 2.0.13 (2025-03-24) 8 | 9 | ### 2.0.12 (2024-12-07) 10 | 11 | ### 2.0.11 (2024-12-06) 12 | 13 | ### 2.0.10 (2024-05-09) 14 | 15 | ### 2.0.9 (2024-03-26) 16 | 17 | ### 2.0.8 (2024-03-25) 18 | 19 | ### 2.0.7 (2023-10-24) 20 | 21 | ### 2.0.6 (2023-09-07) 22 | 23 | ### 2.0.5 (2023-05-13) 24 | 25 | ### [2.0.4](https://github.com/microlinkhq/nanoclamp/compare/v2.0.3...v2.0.4) (2022-11-13) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * cleanup dist before build ([a43e475](https://github.com/microlinkhq/nanoclamp/commit/a43e4753a863087a6d4a9bfd8cd0306753886b92)) 31 | 32 | ### [2.0.3](https://github.com/microlinkhq/nanoclamp/compare/v2.0.2...v2.0.3) (2022-11-13) 33 | 34 | ### 2.0.2 (2022-11-13) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * avoid run contributors on CI ([4c591b7](https://github.com/microlinkhq/nanoclamp/commit/4c591b72b3bc2a1c795d40790cf6d8f1507190c0)) 40 | 41 | ### 2.0.1 (2022-11-13) 42 | 43 | ## [2.0.0](https://github.com/microlinkhq/nanoclamp/compare/v1.2.3...v2.0.0) (2022-11-12) 44 | 45 | 46 | ### Features 47 | 48 | * typescript ([620950e](https://github.com/microlinkhq/nanoclamp/commit/620950ef3c29f65fd0766240c187415b4673edcb)) 49 | 50 | 51 | ### Bug Fixes 52 | 53 | * add missing dependency ([1fca48b](https://github.com/microlinkhq/nanoclamp/commit/1fca48b8e7b843c55454e7d23d85f81d52cfb333)) 54 | * add missing node types ([c4715d5](https://github.com/microlinkhq/nanoclamp/commit/c4715d5755caf24c83d2b75c63fd0e405e36da9f)) 55 | * add types into the npm bundle ([870d35d](https://github.com/microlinkhq/nanoclamp/commit/870d35d5f36944ba51a039925f7157d5f09ab82e)) 56 | * linter ([2b7294f](https://github.com/microlinkhq/nanoclamp/commit/2b7294fac26962016299bf82b6d47b49e7f5339f)) 57 | * malformed yaml ([d0a3826](https://github.com/microlinkhq/nanoclamp/commit/d0a382625ca286753e92adbdd77bec0bdf610600)) 58 | * typo ([1f4b1ca](https://github.com/microlinkhq/nanoclamp/commit/1f4b1ca2cac83ba5302f17e52b0826fd353c2d5a)) 59 | 60 | ## 1.4.0 (2020-11-20) 61 | 62 | * build: update dependencies ([7c75175](https://github.com/microlinkhq/nanoclamp/commit/7c75175)) 63 | 64 | 65 | 66 | ## 1.3.4 (2020-07-02) 67 | 68 | * fix: add types into the npm bundle ([870d35d](https://github.com/microlinkhq/nanoclamp/commit/870d35d)) 69 | 70 | 71 | 72 | ## 1.3.3 (2020-02-12) 73 | 74 | * build: remove babel plugin ([1403676](https://github.com/microlinkhq/nanoclamp/commit/1403676)) 75 | * build: tweaks ([df9509f](https://github.com/microlinkhq/nanoclamp/commit/df9509f)) 76 | 77 | 78 | 79 | ## 1.3.2 (2020-02-09) 80 | 81 | * build: ensure to don't add babel helpers ([8af3a39](https://github.com/microlinkhq/nanoclamp/commit/8af3a39)) 82 | 83 | 84 | 85 | ## 1.3.1 (2020-02-09) 86 | 87 | * fix: typo ([1f4b1ca](https://github.com/microlinkhq/nanoclamp/commit/1f4b1ca)) 88 | 89 | 90 | 91 | ## 1.3.0 (2020-02-09) 92 | 93 | * build: ignore common files ([be1692a](https://github.com/microlinkhq/nanoclamp/commit/be1692a)) 94 | * build: use rollup instead of microbundle ([5f9ae77](https://github.com/microlinkhq/nanoclamp/commit/5f9ae77)) 95 | 96 | 97 | 98 | ## 1.2.12 (2020-02-09) 99 | 100 | * build: update build system ([0350d9e](https://github.com/microlinkhq/nanoclamp/commit/0350d9e)) 101 | * Update LICENSE ([97d91a9](https://github.com/microlinkhq/nanoclamp/commit/97d91a9)) 102 | * Update README.md ([1b4790e](https://github.com/microlinkhq/nanoclamp/commit/1b4790e)) 103 | * Update README.md ([4a95931](https://github.com/microlinkhq/nanoclamp/commit/4a95931)) 104 | 105 | 106 | 107 | 108 | ## 1.2.11 (2019-04-25) 109 | 110 | * build: fix meta ([64b2c45](https://github.com/microlinkhq/nanoclamp/commit/64b2c45)) 111 | 112 | 113 | 114 | 115 | ## 1.2.10 (2019-04-25) 116 | 117 | * build: update workflow ([2a48887](https://github.com/microlinkhq/nanoclamp/commit/2a48887)) 118 | 119 | 120 | 121 | 122 | ## 1.2.9 (2019-03-07) 123 | 124 | * Add Typescript types ([4da4c75](https://github.com/microlinkhq/nanoclamp/commit/4da4c75)) 125 | * migrate hooks ([85c6659](https://github.com/microlinkhq/nanoclamp/commit/85c6659)) 126 | * Release 1.2.8 ([e684ded](https://github.com/microlinkhq/nanoclamp/commit/e684ded)) 127 | 128 | 129 | 130 | 131 | ## 1.2.8 (2019-03-07) 132 | 133 | * Add Typescript types ([4da4c75](https://github.com/microlinkhq/nanoclamp/commit/4da4c75)) 134 | * migrate hooks ([85c6659](https://github.com/microlinkhq/nanoclamp/commit/85c6659)) 135 | 136 | 137 | 138 | 139 | ## 1.2.7 (2018-04-26) 140 | 141 | * prepublish → prepublishOnly ([6ed7e7d](https://github.com/microlinkhq/nanoclamp/commit/6ed7e7d)) 142 | * Remove unnecessary build step ([6deff03](https://github.com/microlinkhq/nanoclamp/commit/6deff03)) 143 | * Update browser targets ([aefb9e8](https://github.com/microlinkhq/nanoclamp/commit/aefb9e8)) 144 | * Update README.md ([112fcf8](https://github.com/microlinkhq/nanoclamp/commit/112fcf8)) 145 | 146 | 147 | 148 | 149 | ## 1.2.6 (2018-03-18) 150 | 151 | * Add prepublish script ([85aa87f](https://github.com/microlinkhq/nanoclamp/commit/85aa87f)) 152 | * Check for `this.original` before clamping lines ([e415f02](https://github.com/microlinkhq/nanoclamp/commit/e415f02)) 153 | 154 | 155 | 156 | 157 | ## 1.2.5 (2018-03-09) 158 | 159 | * Fix `accessibility` prop’s `propType` ([f1c799b](https://github.com/microlinkhq/nanoclamp/commit/f1c799b)) 160 | * Fix README license ([df06bd2](https://github.com/microlinkhq/nanoclamp/commit/df06bd2)) 161 | 162 | 163 | 164 | 165 | ## 1.2.4 (2018-02-24) 166 | 167 | * Add `accessibility` prop ([04d9ecd](https://github.com/microlinkhq/nanoclamp/commit/04d9ecd)) 168 | * Update README ([db5ad1c](https://github.com/microlinkhq/nanoclamp/commit/db5ad1c)) 169 | 170 | 171 | 172 | 173 | ## 1.2.1 (2018-02-23) 174 | 175 | * Fix unnecessary clamping ([af92865](https://github.com/microlinkhq/nanoclamp/commit/af92865)) 176 | 177 | 178 | 179 | 180 | # 1.2.0 (2018-02-23) 181 | 182 | * Avoid pass component props to children props ([f571af0](https://github.com/microlinkhq/nanoclamp/commit/f571af0)) 183 | * Build lib ([562070d](https://github.com/microlinkhq/nanoclamp/commit/562070d)) 184 | * Improve ellipsis size calculation ([67529c4](https://github.com/microlinkhq/nanoclamp/commit/67529c4)) 185 | * Increase default debounce value ([271aa82](https://github.com/microlinkhq/nanoclamp/commit/271aa82)) 186 | * Prettier storybook ([e3de8f5](https://github.com/microlinkhq/nanoclamp/commit/e3de8f5)) 187 | * Refactor ([836e238](https://github.com/microlinkhq/nanoclamp/commit/836e238)) 188 | * Refactor ([5a06ebd](https://github.com/microlinkhq/nanoclamp/commit/5a06ebd)) 189 | * Update README ([5d83b67](https://github.com/microlinkhq/nanoclamp/commit/5d83b67)) 190 | * Update storybook ([c6557b6](https://github.com/microlinkhq/nanoclamp/commit/c6557b6)) 191 | * Update storybook styles ([bc58b06](https://github.com/microlinkhq/nanoclamp/commit/bc58b06)) 192 | 193 | 194 | 195 | 196 | ## 1.1.4 (2018-02-22) 197 | 198 | * Avoid umd bundle ([2ee8675](https://github.com/microlinkhq/nanoclamp/commit/2ee8675)) 199 | * Update README.md ([afa2348](https://github.com/microlinkhq/nanoclamp/commit/afa2348)) 200 | * Update README.md ([b7f4670](https://github.com/microlinkhq/nanoclamp/commit/b7f4670)) 201 | 202 | 203 | 204 | 205 | ## 1.1.3 (2018-02-22) 206 | 207 | * Fix release message ([669777e](https://github.com/microlinkhq/nanoclamp/commit/669777e)) 208 | * Release react-microlink@1.1.2 ([2745a17](https://github.com/microlinkhq/nanoclamp/commit/2745a17)) 209 | * Update README.md ([784ab03](https://github.com/microlinkhq/nanoclamp/commit/784ab03)) 210 | * Update README.md ([d5a8450](https://github.com/microlinkhq/nanoclamp/commit/d5a8450)) 211 | * Update README.md ([99aec90](https://github.com/microlinkhq/nanoclamp/commit/99aec90)) 212 | 213 | 214 | 215 | 216 | ## 1.1.2 (2018-02-22) 217 | 218 | * Update README.md ([784ab03](https://github.com/microlinkhq/nanoclamp/commit/784ab03)) 219 | * Update README.md ([d5a8450](https://github.com/microlinkhq/nanoclamp/commit/d5a8450)) 220 | * Update README.md ([99aec90](https://github.com/microlinkhq/nanoclamp/commit/99aec90)) 221 | 222 | 223 | 224 | 225 | ## 1.1.1 (2018-02-22) 226 | 227 | * 1.1.1 ([805e27c](https://github.com/microlinkhq/nanoclamp/commit/805e27c)) 228 | * Add meta files ([ac0896c](https://github.com/microlinkhq/nanoclamp/commit/ac0896c)) 229 | * Add missing dependencies ([9ef26d9](https://github.com/microlinkhq/nanoclamp/commit/9ef26d9)) 230 | * Add netlify link to README ([32cceb1](https://github.com/microlinkhq/nanoclamp/commit/32cceb1)) 231 | * Improve build process ([031aecf](https://github.com/microlinkhq/nanoclamp/commit/031aecf)) 232 | * Update README.md ([654dd5d](https://github.com/microlinkhq/nanoclamp/commit/654dd5d)) 233 | * Update README.md ([741983b](https://github.com/microlinkhq/nanoclamp/commit/741983b)) 234 | * Update unnecessary script ([d5d95a7](https://github.com/microlinkhq/nanoclamp/commit/d5d95a7)) 235 | 236 | 237 | 238 | 239 | # 1.1.0 (2018-02-22) 240 | 241 | * 1.1.0 ([30d432e](https://github.com/microlinkhq/nanoclamp/commit/30d432e)) 242 | * Add `is` prop ([3f8f798](https://github.com/microlinkhq/nanoclamp/commit/3f8f798)) 243 | * Add `key` prop to story components ([c532404](https://github.com/microlinkhq/nanoclamp/commit/c532404)) 244 | * Add package.json homepage ([b556e88](https://github.com/microlinkhq/nanoclamp/commit/b556e88)) 245 | * Add storybook ([44f569a](https://github.com/microlinkhq/nanoclamp/commit/44f569a)) 246 | * Build lib ([0e84ccd](https://github.com/microlinkhq/nanoclamp/commit/0e84ccd)) 247 | * Refactoring ([72a3d7c](https://github.com/microlinkhq/nanoclamp/commit/72a3d7c)) 248 | * Update .gitignore ([2ec96ef](https://github.com/microlinkhq/nanoclamp/commit/2ec96ef)) 249 | * Update storybook ([bcfb5c1](https://github.com/microlinkhq/nanoclamp/commit/bcfb5c1)) 250 | 251 | 252 | 253 | 254 | ## 1.0.1 (2018-02-22) 255 | 256 | * 0.1.1 ([c56b2ed](https://github.com/microlinkhq/nanoclamp/commit/c56b2ed)) 257 | * 0.1.2 ([7fb6791](https://github.com/microlinkhq/nanoclamp/commit/7fb6791)) 258 | * 1.0.1 ([499bd1f](https://github.com/microlinkhq/nanoclamp/commit/499bd1f)) 259 | * Add CI yml ([062d601](https://github.com/microlinkhq/nanoclamp/commit/062d601)) 260 | * Bug #3 fixed - DOM manipulation was firing even with empty string ([38aa956](https://github.com/microlinkhq/nanoclamp/commit/38aa956)) 261 | * demo page added ([f16215a](https://github.com/microlinkhq/nanoclamp/commit/f16215a)) 262 | * demo url added ([3df9721](https://github.com/microlinkhq/nanoclamp/commit/3df9721)) 263 | * file structure fixed ([6b4b596](https://github.com/microlinkhq/nanoclamp/commit/6b4b596)) 264 | * image updated ([45bce17](https://github.com/microlinkhq/nanoclamp/commit/45bce17)) 265 | * image url updated ([8873519](https://github.com/microlinkhq/nanoclamp/commit/8873519)) 266 | * index.js location fixed ([e637c06](https://github.com/microlinkhq/nanoclamp/commit/e637c06)) 267 | * Initial commit ([a9b4391](https://github.com/microlinkhq/nanoclamp/commit/a9b4391)) 268 | * Initial commit ([b85412a](https://github.com/microlinkhq/nanoclamp/commit/b85412a)) 269 | * Initial refactoring ([dee3893](https://github.com/microlinkhq/nanoclamp/commit/dee3893)) 270 | * latest react v16.2.0 and import bug fixed ([d22f1bf](https://github.com/microlinkhq/nanoclamp/commit/d22f1bf)) 271 | * npm code ([95a3fd2](https://github.com/microlinkhq/nanoclamp/commit/95a3fd2)) 272 | * README nobr added for props table's values ([0a80bd2](https://github.com/microlinkhq/nanoclamp/commit/0a80bd2)) 273 | * README updated ([2de05c7](https://github.com/microlinkhq/nanoclamp/commit/2de05c7)) 274 | * README updated ([94d2c6b](https://github.com/microlinkhq/nanoclamp/commit/94d2c6b)) 275 | * Rename clamp component ([6533606](https://github.com/microlinkhq/nanoclamp/commit/6533606)) 276 | * reverted the version number ([def527b](https://github.com/microlinkhq/nanoclamp/commit/def527b)) 277 | * simplified the docs content ([d17b161](https://github.com/microlinkhq/nanoclamp/commit/d17b161)) 278 | * table column title updated ([53580a6](https://github.com/microlinkhq/nanoclamp/commit/53580a6)) 279 | * typo fixed ([6781a85](https://github.com/microlinkhq/nanoclamp/commit/6781a85)) 280 | * Update license 👉 MIT ([82fbaa3](https://github.com/microlinkhq/nanoclamp/commit/82fbaa3)) 281 | * Update package.json ([f3c6751](https://github.com/microlinkhq/nanoclamp/commit/f3c6751)) 282 | * Update README ([347c756](https://github.com/microlinkhq/nanoclamp/commit/347c756)) 283 | * Update README ([5258cd9](https://github.com/microlinkhq/nanoclamp/commit/5258cd9)) 284 | * Updated demo link in README ([890b76a](https://github.com/microlinkhq/nanoclamp/commit/890b76a)) 285 | * url fixed for css and js ([b95b75d](https://github.com/microlinkhq/nanoclamp/commit/b95b75d)) 286 | * Version bumped up in package.json ([1bd3539](https://github.com/microlinkhq/nanoclamp/commit/1bd3539)) 287 | * version number updated to 1.0.0 ([419370e](https://github.com/microlinkhq/nanoclamp/commit/419370e)) 288 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2019 Microlink (microlink.io) 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | microlink logo 3 | microlink logo 4 |
5 |
6 |
7 | 8 | [![Last version](https://img.shields.io/github/tag/microlinkhq/nanoclamp.svg?style=flat-square)](https://github.com/microlinkhq/nanoclamp/releases) 9 | [![NPM Status](https://img.shields.io/npm/dm/nanoclamp.svg?style=flat-square)](https://www.npmjs.org/package/nanoclamp) 10 | 11 | ###### [Storybook](https://nanoclamp.netlify.com/) 12 | 13 | > Responsive text clamping component. Inspired by [react-clamp-lines](https://github.com/zoltantothcom/react-clamp-lines), but smaller (~1KB). 14 | 15 | ## Install 16 | 17 | ``` 18 | npm install nanoclamp --save 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```jsx 24 | import NanoClamp from 'nanoclamp'; 25 | 26 | 32 | ``` 33 | 34 | ## API 35 | 36 | | prop | type | default | description | 37 | |---------------|-----------|---------|-------------------------------------------------------------------------| 38 | | accessibility | `boolean` | `true` | Pass the full _unclamped_ string to the DOM element's `title` attribute | 39 | | className | `string` | | CSS classname(s) added to the string | 40 | | debounce | `number` | `300` | Time in milliseconds used for debounce | 41 | | ellipsis | `string` | `'…'` | String displayed after the clamped `text` | 42 | | is | `string` | `'div'` | DOM selector used to render the string | 43 | | lines | `number` | `3` | Number of visible lines | 44 | | text | `string` | | Text you wish to clamp | 45 | 46 | ## License 47 | 48 | **nanoclamp** © [Microlink](https://microlink.io), released under the [MIT](https://github.com/microlinkhq/nanoclamp/blob/master/LICENSE.md) License.
49 | Adapted from [`react-clamp-lines`](https://github.com/zoltantothcom/react-clamp-lines) by Brad Adams with help from [contributors](https://github.com/microlinkhq/nanoclamp/contributors). 50 | 51 | > [microlink.io](https://microlink.io) · GitHub [microlinkhq](https://github.com/microlinkhq) · X [@microlinkhq](https://x.com/microlinkhq) 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nanoclamp", 3 | "description": "Responsive text clamping component for React", 4 | "homepage": "https://github.com/microlinkhq/nanoclamp", 5 | "version": "2.0.14", 6 | "types": "dist/index.d.ts", 7 | "main": "dist/nanoclamp.js", 8 | "module": "dist/nanoclamp.mjs", 9 | "author": { 10 | "name": "Brad Adams" 11 | }, 12 | "contributors": [ 13 | { 14 | "name": "Kiko Beats", 15 | "email": "josefrancisco.verdu@gmail.com" 16 | }, 17 | { 18 | "name": "Brad Adams", 19 | "email": "hi@breadadams.com" 20 | }, 21 | { 22 | "name": "Zoltan Toth", 23 | "email": "ztoth@indigo.ca" 24 | }, 25 | { 26 | "name": "Axel Hernández Ferrera", 27 | "email": "axelhzf@gmail.com" 28 | } 29 | ], 30 | "repository": { 31 | "type": "git", 32 | "url": "git+https://github.com/microlinkhq/nanoclamp.git" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/microlinkhq/nanoclamp/issues" 36 | }, 37 | "keywords": [ 38 | "clamp", 39 | "clamping", 40 | "components", 41 | "ellipsis", 42 | "lines", 43 | "react" 44 | ], 45 | "devDependencies": { 46 | "@babel/eslint-parser": "latest", 47 | "@babel/plugin-transform-react-constant-elements": "latest", 48 | "@babel/plugin-transform-runtime": "latest", 49 | "@babel/preset-env": "latest", 50 | "@babel/preset-react": "latest", 51 | "@babel/runtime": "latest", 52 | "@commitlint/cli": "latest", 53 | "@commitlint/config-conventional": "latest", 54 | "@ksmithut/prettier-standard": "latest", 55 | "@rollup/plugin-babel": "latest", 56 | "@rollup/plugin-terser": "latest", 57 | "@rollup/plugin-typescript": "latest", 58 | "@storybook/addons": "latest", 59 | "@storybook/builder-webpack5": "latest", 60 | "@storybook/manager-webpack5": "latest", 61 | "@storybook/react": "latest", 62 | "@storybook/theming": "latest", 63 | "@types/react": "^19", 64 | "babel-loader": "latest", 65 | "ci-publish": "latest", 66 | "finepack": "latest", 67 | "git-authors-cli": "latest", 68 | "github-generate-release": "latest", 69 | "nano-staged": "latest", 70 | "prop-types": "latest", 71 | "react": "^19", 72 | "react-dom": "^19", 73 | "rollup": "latest", 74 | "rollup-plugin-filesize": "latest", 75 | "rollup-plugin-peer-deps-external": "latest", 76 | "rollup-plugin-visualizer": "latest", 77 | "simple-git-hooks": "latest", 78 | "standard-markdown": "latest", 79 | "standard-version": "latest", 80 | "ts-standard": "latest", 81 | "typescript": "latest" 82 | }, 83 | "engines": { 84 | "node": ">= 8" 85 | }, 86 | "files": [ 87 | "dist", 88 | "typings" 89 | ], 90 | "scripts": { 91 | "build": "NODE_ENV=production rollup -c rollup.config.js --bundleConfigAsCjs", 92 | "build-storybook": "NODE_ENV=production build-storybook", 93 | "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true", 94 | "dev": "start-storybook -p 6006", 95 | "lint": "standard-markdown && ts-standard src && ts-standard stories", 96 | "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)", 97 | "prebuild": "rm -rf dist", 98 | "prepare": "npx simple-git-hooks", 99 | "prepublishOnly": "npm run build", 100 | "prerelease": "npm run update:check && [[ -z \"${CI}\" ]] && npm run contributors || exit 0", 101 | "pretest": "npm run lint", 102 | "release": "standard-version -a", 103 | "release:github": "github-generate-release", 104 | "release:tags": "git push --follow-tags origin HEAD:master", 105 | "test": "exit 0" 106 | }, 107 | "license": "MIT", 108 | "commitlint": { 109 | "extends": [ 110 | "@commitlint/config-conventional" 111 | ], 112 | "rules": { 113 | "body-max-line-length": [ 114 | 0 115 | ] 116 | } 117 | }, 118 | "nano-staged": { 119 | "*.js": [ 120 | "prettier-standard", 121 | "standard --fix" 122 | ], 123 | "*.md": [ 124 | "standard-markdown" 125 | ], 126 | "package.json": [ 127 | "finepack" 128 | ] 129 | }, 130 | "peerDependencies": { 131 | "react": "^19" 132 | }, 133 | "simple-git-hooks": { 134 | "commit-msg": "npx commitlint --edit", 135 | "pre-commit": "npx nano-staged" 136 | }, 137 | "ts-standard": { 138 | "globals": [ 139 | "React" 140 | ], 141 | "ignore": [ 142 | "/dist/" 143 | ], 144 | "parser": "@babel/eslint-parser" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import external from 'rollup-plugin-peer-deps-external' 2 | import { visualizer } from 'rollup-plugin-visualizer' 3 | import typescript from '@rollup/plugin-typescript' 4 | import filesize from 'rollup-plugin-filesize' 5 | import terser from '@rollup/plugin-terser' 6 | import babel from '@rollup/plugin-babel' 7 | import fs from 'fs' 8 | 9 | import pkg from './package.json' 10 | 11 | const babelRc = JSON.parse(fs.readFileSync('./.babelrc')) 12 | 13 | export default { 14 | input: 'src/index.ts', 15 | external: [/@babel\/runtime/], 16 | output: [ 17 | { 18 | file: pkg.main, 19 | format: 'cjs', 20 | sourcemap: true 21 | }, 22 | { 23 | file: pkg.module, 24 | format: 'es', 25 | sourcemap: true 26 | } 27 | ], 28 | plugins: [ 29 | external({ 30 | includeDependencies: true 31 | }), 32 | babel({ 33 | babelrc: false, 34 | babelHelpers: 'runtime', 35 | ...babelRc 36 | }), 37 | typescript(), 38 | terser(), 39 | filesize(), 40 | visualizer({ template: 'treemap' }) 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { createElement, useCallback, useLayoutEffect, useMemo, useRef } from 'react' 2 | 3 | interface Props extends React.HTMLAttributes { 4 | accessibility?: boolean 5 | debounce?: number 6 | ellipsis?: string 7 | is?: string 8 | lines?: number 9 | text: string 10 | } 11 | 12 | const DEFAULT_ELLIPSIS = '…' 13 | const DEFAULT_TEXT = '.' 14 | 15 | const debounceFn = (func: () => void, timeoutMs: number): () => void => { 16 | let timeout: ReturnType | undefined 17 | 18 | const later = (): void => { 19 | timeout = undefined 20 | func() 21 | } 22 | 23 | return () => { 24 | const callNow = timeout == null 25 | clearTimeout(timeout) 26 | timeout = setTimeout(later, timeoutMs) 27 | if (callNow) func() 28 | } 29 | } 30 | 31 | const NanoClamp = ({ 32 | accessibility = true, 33 | debounce = 300, 34 | ellipsis = DEFAULT_ELLIPSIS, 35 | is = 'div', 36 | lines = 3, 37 | text, 38 | ...props 39 | }: Props): React.ReactElement | null => { 40 | const elementRef = useRef(null) 41 | const textRef = useRef(DEFAULT_TEXT) 42 | 43 | const clampProps = { 44 | ref: elementRef, 45 | ...(accessibility ? { title: text } : {}), 46 | ...props 47 | } 48 | 49 | const hasText = useMemo(() => typeof text === 'string' && text.length > 0, [text]) 50 | 51 | const clampLines = useCallback(() => { 52 | if (!hasText) return 53 | 54 | const updateTextRefs = (newText: string): void => { 55 | textRef.current = newText 56 | 57 | if (elementRef.current != null) { 58 | elementRef.current.textContent = newText 59 | } 60 | } 61 | 62 | const elementHeight = (): number => elementRef.current?.clientHeight ?? 0 63 | 64 | updateTextRefs(DEFAULT_TEXT) 65 | 66 | const lineHeight = elementHeight() + 1 67 | const maxHeight = lineHeight * lines + 1 68 | 69 | updateTextRefs(text) 70 | if (elementHeight() <= maxHeight) { 71 | return 72 | } 73 | 74 | let start = 0 75 | let middle = 0 76 | let end = text.length 77 | 78 | while (start <= end) { 79 | middle = Math.floor((start + end) / 2) 80 | 81 | const slicedText = text.slice(0, middle).trim() + ellipsis 82 | updateTextRefs(slicedText) 83 | 84 | if (elementHeight() <= maxHeight) { 85 | start = middle + 1 86 | } else { 87 | end = middle - 1 88 | } 89 | } 90 | 91 | const textPlusEllipsis = text.slice(0, middle - 1).trim() + ellipsis 92 | 93 | updateTextRefs(textPlusEllipsis) 94 | }, [ellipsis, hasText, lines, text]) 95 | 96 | useLayoutEffect(() => { 97 | clampLines() 98 | 99 | if (elementRef.current == null) return 100 | 101 | const observer = new ResizeObserver(debounceFn(clampLines, debounce)) 102 | observer.observe(elementRef.current) 103 | return () => observer.disconnect() 104 | }, [clampLines, debounce]) 105 | 106 | return hasText ? createElement(is, clampProps, textRef.current) : null 107 | } 108 | 109 | export default NanoClamp 110 | -------------------------------------------------------------------------------- /stories/index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { storiesOf } from '@storybook/react' 3 | import NanoClamp from '../src/index' 4 | 5 | const string = 6 | 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Incidunt, dignissimos totam nam cumque ipsum autem placeat. Doloribus nesciunt id saepe quasi, quod, quis voluptatibus rerum at perspiciatis impedit ab nostrum.' 7 | 8 | const NanoClampWrap = ({ background, width, ...props }) => ( 9 |
23 | 24 |
25 | ) 26 | 27 | const examples = [ 28 | { 29 | background: '#0984e3', 30 | key: 1, 31 | lines: 1, 32 | width: 500 33 | }, 34 | { 35 | background: '#6c5ce7', 36 | key: 2, 37 | lines: 2, 38 | width: 370 39 | }, 40 | { 41 | background: '#e84393', 42 | key: 3, 43 | lines: 3, 44 | width: 270 45 | } 46 | ] 47 | 48 | storiesOf('NanoClamp', module) 49 | .add('default', () => ( 50 | <> 51 | {examples.map(({ ...props }) => ( 52 | 53 | ))} 54 | 55 | )) 56 | .add('with ellipsis prop', () => ( 57 | <> 58 | {examples.map(({ ...props }) => ( 59 | 64 | ))} 65 | 66 | )) 67 | .add('with is prop', () => ( 68 | <> 69 | {examples.map(({ ...props }) => ( 70 | 71 | ))} 72 | 73 | )) 74 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "removeComments": false, 5 | "sourceMap": true, 6 | "target": "es2018", 7 | "outDir": "dist", 8 | "declaration": true, 9 | "strict": true, 10 | "module": "esnext", 11 | "noEmitOnError": true, 12 | "lib": ["dom", "es2017"], 13 | "esModuleInterop": false 14 | }, 15 | "include": ["src"] 16 | } 17 | --------------------------------------------------------------------------------