├── .gitignore ├── .travis.yml ├── LICENSE.md ├── CHANGELOG.md ├── index.js ├── package.json ├── README.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .nyc_output 3 | /coverage 4 | /node_modules 5 | *.log 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | notifications: 2 | email: false 3 | 4 | services: 5 | - xvfb 6 | 7 | language: node_js 8 | 9 | node_js: 10 | - 'node' 11 | 12 | script: 13 | - yarn lint 14 | - yarn test && yarn coverage 15 | 16 | after_success: 17 | - yarn add --dev coveralls 18 | - cat coverage/lcov.info | yarn run coveralls 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Lim Yuan Qing 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 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 3.0.0 4 | 5 | - Remove `splitRegex` in favour of a `split` callback 6 | - Allow passing in a `setClassName` callback to set the class name on the inserted DOM element 7 | - Use modern syntax, namely `let`/`const` and default parameters 8 | 9 | ## 2.2.5 10 | 11 | - Bump dependencies 12 | 13 | ## 2.2.4 14 | 15 | - Add `rimraf`, `mkdirp` 16 | - Add `husky` and `lint-staged` 17 | - Bump dependencies 18 | 19 | ## 2.2.3 20 | 21 | - Only publish `index.js` 22 | 23 | ## 2.2.2 24 | 25 | - Add `standard` 26 | - Bump dependencies 27 | 28 | ## 2.2.1 29 | 30 | - Add `weight` script 31 | 32 | ## 2.2.0 33 | 34 | - Add support for passing in a regular expression to control how the contents of the element are wrapped 35 | 36 | ## 2.1.0 37 | 38 | - Add `aria-label` and `aria-hidden` attributes for accessibility 39 | 40 | ## 2.0.1 41 | 42 | - Add a [CodePen demo](https://codepen.io/anon/pen/WOxNqX) 43 | - Use [`prettier-standard`](https://github.com/sheerun/prettier-standard) 44 | 45 | ## 2.0.0 46 | 47 | - Prioritise the general case, where the `element` has a single child [text node](https://developer.mozilla.org/en-US/docs/Web/API/Text) 48 | - Update tooling: [`prettier`](https://github.com/prettier/prettier), [`tape`](https://github.com/substack/tape), [`yarn`](https://github.com/yarnpkg/yarn) 49 | - Drop [Bower](https://bower.io/) support 50 | 51 | ## 1.0.0 52 | 53 | - Initial release 54 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = function ( 2 | element, 3 | { 4 | tagName = 'span', 5 | split, 6 | setClassName = function (index) { 7 | return 'char' + index 8 | } 9 | } = {} 10 | ) { 11 | element.normalize() 12 | let index = 1 13 | function inject (element) { 14 | const parentNode = element.parentNode 15 | const nodeValue = element.nodeValue 16 | const array = split ? split(nodeValue) : nodeValue.split('') 17 | array.forEach(function (string) { 18 | const node = document.createElement(tagName) 19 | const className = setClassName(index++, string) 20 | if (className) { 21 | node.className = className 22 | } 23 | node.appendChild(document.createTextNode(string)) 24 | node.setAttribute('aria-hidden', 'true') 25 | parentNode.insertBefore(node, element) 26 | }) 27 | if (nodeValue.trim() !== '') { 28 | parentNode.setAttribute('aria-label', nodeValue) 29 | } 30 | parentNode.removeChild(element) 31 | } 32 | ;(function traverse (element) { 33 | // `element` is itself a text node 34 | if (element.nodeType === 3) { 35 | return inject(element) 36 | } 37 | // `element` has a single child text node 38 | const childNodes = Array.prototype.slice.call(element.childNodes) // static array of nodes 39 | const length = childNodes.length 40 | if (length === 1 && childNodes[0].nodeType === 3) { 41 | return inject(childNodes[0]) 42 | } 43 | // `element` has more than one child node 44 | childNodes.forEach(function (childNode) { 45 | traverse(childNode) 46 | }) 47 | })(element) 48 | } 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "charming", 3 | "version": "3.0.2", 4 | "description": "Lettering.js in vanilla JavaScript", 5 | "author": "Lim Yuan Qing", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/yuanqing/charming.git" 10 | }, 11 | "devDependencies": { 12 | "browserify": "^16.5.0", 13 | "browserify-istanbul": "^3.0.1", 14 | "gzip-size-cli": "^3.0.0", 15 | "husky": "^4.2.3", 16 | "lint-staged": "^10.0.8", 17 | "mkdirp": "^1.0.3", 18 | "nyc": "^15.0.0", 19 | "prettier-standard": "^16.2.1", 20 | "rimraf": "^3.0.2", 21 | "standard": "^14.3.1", 22 | "tape": "^4.13.2", 23 | "tape-istanbul": "^1.2.0", 24 | "tape-run": "^6.0.1", 25 | "terser": "^4.6.6" 26 | }, 27 | "scripts": { 28 | "clean": "rimraf '*.log' coverage .nyc_output", 29 | "coverage": "yarn run coverage-test && yarn run coverage-report", 30 | "coverage-test": "rimraf .nyc_output && mkdirp .nyc_output && browserify test.js --plugin tape-istanbul/plugin | tape-run | tape-istanbul --output .nyc_output/coverage.json", 31 | "coverage-report": "rimraf coverage && nyc report --reporter text --reporter html", 32 | "fix": "prettier-standard '*.js'", 33 | "lint": "standard '*.js'", 34 | "test": "browserify test.js | tape-run", 35 | "weight": "terser index.js --compress --mangle --toplevel | gzip-size" 36 | }, 37 | "husky": { 38 | "hooks": { 39 | "pre-commit": "lint-staged" 40 | } 41 | }, 42 | "lint-staged": { 43 | "*.js": [ 44 | "standard", 45 | "prettier-standard" 46 | ] 47 | }, 48 | "files": [ 49 | "index.js" 50 | ], 51 | "keywords": [ 52 | "kerning", 53 | "lettering", 54 | "letteringjs", 55 | "span", 56 | "typography" 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # charming [](https://www.npmjs.org/package/charming) [](https://travis-ci.org/yuanqing/charming) [](https://coveralls.io/r/yuanqing/charming) [](https://bundlephobia.com/result?p=charming) 2 | 3 | > [Lettering.js](https://github.com/davatron5000/Lettering.js) in vanilla JavaScript 4 | 5 | - Supports changing the tag name or class name of the inserted DOM elements 6 | - Supports controlling how the contents of the element are wrapped 7 | 8 | ## Usage 9 | 10 | > [**Editable demo (CodePen)**](https://codepen.io/lyuanqing/pen/YeYdrm) 11 | 12 | HTML: 13 | 14 | ```html 15 |