@jsamr/counter-style
A slim CSS Counter Styles Level 3 compliant library with 47 presets including
Arabic, Persian, Thai, Hebrew, Roman, Katana...
The core is less than 1.7kB minified and gzipped.
Each preset is distributed as a separate module.
Available in both CommonJS and ECMAScript modules.
Targets ECMAScript 2015.
Optimized for metro (React Native) and Webpack bundlers.
Based on prior work from Whang Shuwei.
### Install
```sh
npm add --save @jsamr/counter-style
```
```sh
yarn add @jsamr/counter-style
```
### Using presets
**This library exports 47 presets. [Find your preset here.](./src/presets)** Each preset is accessible in a separate module to limit bundle size.
```js
import arabicIndic from '@jsamr/counter-style/presets/arabicIndic';
expect(arabicIndic.renderMarker(78)).toBe('٧٨. ');
```
> PRs are welcomed to support other presets. Very easy to implement thanks to [this W3C resource](https://www.w3.org/TR/predefined-counter-styles/).
### Creating custom style renderers
The API follows closely the specs for CSS `@counter-style` at rule. The default export ([CounterStyle](./docs/counter-style.counterstyle.md)) is a static object with methods to build [CounterStyleRenderer](./docs/counter-style.counterstylerenderer.md).
#### Example 1: a lower Russian alphabet renderer
In the
below example, we're using [the alphabetic counter system](https://www.w3.org/TR/css-counter-styles-3/#alphabetic-system) and `alphabeticFromUnicodeRange` builder which allows to specify a contiguous unicode range. For non-contiguous ranges, use the `alphabetic` builder.
```js
import CounterStyle from '@jsamr/counter-style';
const lowerRussian = CounterStyle.alphabeticFromUnicodeRange(
0x430, // а
28
).withSuffix(') ');
// Expect comes from jest testing framework.
// Just a showcase of expected returned values.
expect(lowerRussian.renderCounter(1)).toBe('а');
expect(lowerRussian.renderMarker(1)).toBe('а) ');
expect(lowerRussian.renderCounter(2)).toBe('б');
expect(lowerRussian.renderCounter(3)).toBe('в');
expect(lowerRussian.renderMarker(4)).toBe('г) ');
expect(lowerRussian.renderMarker(5)).toBe('д) ');
expect(lowerRussian.renderCounter(29)).toBe('аа');
expect(lowerRussian.maxMarkerLenInRange(1, 5)).toBe(3);
expect(lowerRussian.maxCounterLenInRange(1, 5)).toBe(1);
```
Reference: [W3C Ready-made Counter Styles: Cyrillic styles](https://www.w3.org/TR/predefined-counter-styles/#cyrillic-styles).
#### Example 2: a "Funky" symbolic renderer
In the
below example, we're using [the symbolic counter system](https://www.w3.org/TR/css-counter-styles-3/#symbolic-system).
Note that `withSuffix(null)` removes default suffix.
```js
import CounterStyle from '@jsamr/counter-style';
// Default suffix is ". ", as per the specs.
const funky = CounterStyle.symbolic('*', '&').withSuffix(null);
// Expect comes from jest testing framework.
// Just a showcase of expected returned values.
expect(funky.renderMarker(1)).toBe('*');
expect(funky.renderMarker(2)).toBe('&');
expect(funky.renderMarker(3)).toBe('**');
expect(funky.renderMarker(4)).toBe('&&');
expect(funky.renderMarker(5)).toBe('***');
expect(funky.maxMarkerLenInRange(1, 5)).toBe(3);
expect(funky.maxCounterLenInRange(1, 5)).toBe(3);
```
All renderers can be chained to create variants, such as `withSuffix`,
`withPaddingLeft`, ... See [available methods in the docs.](./docs/counter-style.counterstylerenderer.md)
### API reference
**The API reference [is available here](./docs/counter-style.md).**
### Caveats
- Instead of a normal space character, a non-breaking space is used for default
prefixes. This is because this library primary usage is for React Native. On
iOS, `Text` elements get trimmed of normal space characters.
- In **numeric** and **alphabetic** systems , one UTF-16 code unit per symbol
must be used. Otherwise, length computation will be erroneous. If you really
need multi code units per symbol however, you can still set a custom length
computer via `withMaxLenComputer`.
- When using padding (`withPadding`) and negative (`withNegative`) symbols, one
UTF-16 code unit per symbol must be used. Otherwise, length computation will
be erroneous.
- Never use combining characters. [Grapheme
clusters](https://www.w3.org/TR/css-text-3/#grapheme-cluster) will be
considered distinct characters. Beware that is the case for some emojis, see
[this SO thread](https://stackoverflow.com/q/54369513/2779871).
- Don't define incomplete additive systems which have holes in their range
coverage. For example, an additive system which has no representation for "1"
will not translate odd indexes.
### Limitations
- `speakAs` hasn't been implemented yet.
- [Chinese renderers](https://www.w3.org/TR/css-counter-styles-3/#limited-chinese)
haven't been implemented, requiring custom logic. PRs welcomed!
- Only textual symbols are supported. Images are not.