@editora/react-icons 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,242 +1,267 @@
1
- # @editora/react-icons
2
-
3
- [![Version](https://img.shields.io/npm/v/@editora/react-icons)](https://www.npmjs.com/package/@editora/react-icons)
4
- [![License](https://img.shields.io/npm/l/@editora/react-icons)](https://github.com/ajaykr089/Editora/blob/main/LICENSE)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
6
- [![Size](https://img.shields.io/bundlephobia/minzip/@editora/react-icons)](https://bundlephobia.com/package/@editora/react-icons)
7
-
8
- > [!IMPORTANT]
9
- > **Live Website:** https://editora-ecosystem.netlify.app/
10
- > **Storybook:** https://editora-ecosystem-storybook.netlify.app/?path=/story/ui-icons-catalog--all-icons
11
-
12
-
13
- React icon components and theming context for `@editora/icons`, covering 500+ ready-to-use icons.
14
-
15
- `@editora/react-icons` gives you:
16
- - a generic `<Icon name="...">` renderer,
17
- - named React icon components for 500+ icons (e.g. `CheckIcon`, `ChartLineIcon`),
18
- - shared defaults via `IconProvider`,
19
- - type-safe icon names via `IconName`.
20
-
21
- <div align="center">
22
- <img src="../../images/icon-catalog.png" alt="Icon Catalog" width="600" style="max-width: 100%;" height="auto">
23
- </div>
24
- ## Installation
1
+ <h1 align="center">@editora/react-icons</h1>
2
+
3
+ <p align="center">
4
+ The Editora icons as React components. <code>&lt;SearchIcon /&gt;</code> for every icon, <code>&lt;Icon name="…" /&gt;</code>
5
+ for names that come from data, and an <code>IconProvider</code> to set size, colour and weight once.
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="https://www.npmjs.com/package/@editora/react-icons"><img src="https://img.shields.io/npm/v/@editora/react-icons.svg" alt="npm version"></a>
10
+ <a href="https://www.npmjs.com/package/@editora/react-icons"><img src="https://img.shields.io/npm/dm/@editora/react-icons.svg" alt="npm downloads"></a>
11
+ <a href="https://github.com/ajaykr089/Editora/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@editora/react-icons.svg" alt="license"></a>
12
+ <a href="https://www.npmjs.com/package/@editora/react-icons"><img src="https://img.shields.io/npm/types/@editora/react-icons.svg" alt="TypeScript types included"></a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <a href="https://editora-ecosystem-storybook.netlify.app/?path=/story/ui-icons-catalog--all-icons">Icon catalog</a> ·
17
+ <a href="https://editora-ecosystem.netlify.app/">Website</a> ·
18
+ <a href="https://github.com/ajaykr089/Editora">GitHub</a>
19
+ </p>
20
+
21
+ <p align="center">
22
+ <img src="https://raw.githubusercontent.com/ajaykr089/Editora/main/packages/react-icons/docs/images/quick-start.png" alt="Three square icon buttons holding a search icon, a solid blue bell and a settings icon, the line Changes saved with a green check mark, and a duotone blue shield and pie chart" width="340">
23
+ </p>
24
+
25
+ ## Features
26
+
27
+ - **A component for every icon**: <!-- components:507 -->507 of them (`CheckIcon`, `ChartLineIcon`, `SettingsIcon`...),
28
+ from [`@editora/icons`](https://www.npmjs.com/package/@editora/icons), and `<Icon name="…">` for any name.
29
+ - **Typed names.** `IconName` is the union of every name, so a typo in a menu configuration is a compile error.
30
+ - **One place for the defaults.** An `IconProvider` sets the size, colour, weight and variant of everything inside it,
31
+ and providers nest.
32
+ - **Accessible by default.** An icon is hidden from screen readers unless you give it a title or a label.
33
+ - **Inline SVG** that follows `currentColor`, so icons take the colour of the text, in light and dark themes alike.
34
+ They render to markup on the server too.
35
+ - Outline for every icon, solid for <!-- solid:21 -->21 of them and duotone for <!-- duotone:2 -->2, three weights, rotate, flip and right-to-left mirroring.
36
+ - Written in TypeScript. Components forward their `ref` to the `<svg>` and accept any SVG prop.
37
+
38
+ ## Install
25
39
 
26
40
  ```bash
27
- npm install @editora/react-icons @editora/icons
41
+ npm install @editora/react-icons
28
42
  ```
29
43
 
30
- Peer dependencies:
31
- - `react` `^16.8 || ^17 || ^18 || ^19`
44
+ It needs React 16.8 or later, up to React 20. [`@editora/icons`](https://www.npmjs.com/package/@editora/icons), which holds the
45
+ icon drawings, is installed with it.
32
46
 
33
- ## Quick Start
47
+ ## Quick start
34
48
 
35
49
  ```tsx
36
- import { IconProvider, Icon, CheckIcon, ChartLineIcon } from '@editora/react-icons';
50
+ import { BellIcon, CheckIcon, ChartPieIcon, Icon, IconProvider, SearchIcon, SettingsIcon } from '@editora/react-icons';
37
51
 
38
- export function Example() {
52
+ const button = { display: 'grid', placeItems: 'center', width: 36, height: 36, padding: 0, border: '1px solid #d0d7de', borderRadius: 8, background: '#fff', color: '#24292f' };
53
+
54
+ export default function App() {
39
55
  return (
40
- <IconProvider
41
- value={{
42
- variant: 'outline',
43
- size: 18,
44
- color: 'var(--ui-fg)',
45
- strokeWidth: 1.5
46
- }}
47
- >
48
- <CheckIcon ariaLabel="Saved" />
49
- <ChartLineIcon variant="duotone" secondaryColor="var(--ui-muted)" />
50
- <Icon name="command" title="Command palette" />
56
+ <IconProvider value={{ size: 18 }}>
57
+ <div style={{ display: 'flex', gap: 8 }}>
58
+ {/* A labelled button: the icon in it is decorative, so it needs no name of its own. */}
59
+ <button type="button" aria-label="Search" style={button}>
60
+ <SearchIcon />
61
+ </button>
62
+ <button type="button" aria-label="Notifications" style={button}>
63
+ <BellIcon variant="solid" color="#2563eb" />
64
+ </button>
65
+ <button type="button" aria-label="Settings" style={button}>
66
+ <SettingsIcon />
67
+ </button>
68
+ </div>
69
+
70
+ {/* An icon that stands alone gets a name. */}
71
+ <p style={{ display: 'flex', alignItems: 'center', gap: 8, color: '#1a7f37' }}>
72
+ <CheckIcon ariaLabel="Success" /> Changes saved
73
+ </p>
74
+
75
+ {/* Any icon by name, and the duotone variant of the few icons that have one. */}
76
+ <p style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
77
+ <Icon name="shield" variant="duotone" color="#2563eb" secondaryColor="#93c5fd" title="Protected" />
78
+ <ChartPieIcon variant="duotone" color="#2563eb" secondaryColor="#93c5fd" size={24} />
79
+ </p>
51
80
  </IconProvider>
52
81
  );
53
82
  }
54
83
  ```
55
84
 
56
- ## Exported API
57
-
58
- ### Core components
59
- - `Icon`
60
- - `IconProvider`
61
- - `IconContext`
62
- - `useIconContext()`
63
- - `defaultIconContext`
64
-
65
- ### Lookup and helpers
66
- - `icons` / `Icons` map (`Record<IconName, IconComponent>`)
67
- - `iconNames` (`IconName[]`)
68
- - `getIconComponent(name)`
69
- - `createIcon(name, displayName?)`
85
+ An icon next to text, or inside a button that has its own label, is decorative: it is hidden from screen readers and
86
+ needs no name. An icon that stands alone needs one, with `title` (also a tooltip) or `ariaLabel`. Icons are 15 pixels
87
+ wide unless the provider or a `size` says otherwise.
70
88
 
71
- ### Named icons
72
- All generated named exports from `src/icons.tsx`, for example:
73
- - `CheckIcon`, `XIcon`, `SearchIcon`, `ChartBarIcon`, `CalendarIcon`, `SettingsIcon`, `CommandIcon`, and many more.
89
+ ## Props
74
90
 
75
- ### Type exports
76
- - `IconName`
77
- - `IconProps`
78
- - `NamedIconProps`
79
- - `IconContextValue`
80
- - `IconComponent`
81
- - `IconFlip`
82
- - `IconBaseProps`
83
-
84
- ## `Icon` Props
85
-
86
- `Icon` accepts standard SVG props plus icon-specific props:
91
+ `Icon` and every named component take these props, and any SVG attribute or event handler (`className`, `style`,
92
+ `onClick`, `data-*`, `aria-*`). `Icon` also takes `name`, which is required; the named components have their name built
93
+ in.
87
94
 
88
95
  | Prop | Type | Default | Notes |
89
- |---|---|---|---|
90
- | `name` | `IconName \| string` | required | Icon key from `@editora/icons`. |
91
- | `variant` | `'outline' \| 'solid' \| 'duotone'` | `'outline'` | Glyph variant. |
92
- | `size` | `number \| string` | `15` | Sets `width` and `height`. |
93
- | `color` | `string` | `'currentColor'` | Primary icon color. |
94
- | `secondaryColor` | `string` | `color` | Used by duotone secondary paths. |
95
- | `strokeWidth` | `number` | `1.5` | Stroke thickness for stroked paths. |
96
- | `absoluteStrokeWidth` | `boolean` | `false` | Keeps visual stroke thickness stable across icon sizes. |
97
- | `strokeLinecap` | `'butt' \| 'round' \| 'square'` | `'round'` | Applied when stroke exists. |
98
- | `strokeLinejoin` | `'miter' \| 'round' \| 'bevel'` | `'round'` | Applied when stroke exists. |
99
- | `decorative` | `boolean` | inferred | If `true`, icon is hidden from AT. |
100
- | `title` | `string` | `undefined` | Adds `<title>` and accessible name fallback. |
101
- | `ariaLabel` | `string` | `undefined` | Explicit accessible label. |
102
- | `rotate` | `number` | `0` | Degrees around icon center. |
103
- | `flip` | `'horizontal' \| 'vertical' \| 'both'` | `undefined` | Geometric flip transform. |
104
- | `rtl` | `boolean` | `false` | Mirrors icons marked `rtlMirror` in RTL contexts. |
105
-
106
- If an icon name cannot be resolved, `Icon` returns `null`.
107
-
108
- ## `IconProvider` (Shared Defaults)
109
-
110
- `IconProvider` merges with parent context, so nested providers work as expected.
96
+ | --- | --- | --- | --- |
97
+ | `name` | `IconName \| string` | required | The icon. A name that does not exist renders nothing. |
98
+ | `variant` | `'outline' \| 'solid' \| 'duotone'` | `'outline'` | An icon without the variant you ask for is drawn as an outline. |
99
+ | `size` | `number \| string` | `15` | Width and height: pixels, or a CSS length such as `'1.5rem'`. |
100
+ | `color` | `string` | `'currentColor'` | The icon's colour. |
101
+ | `secondaryColor` | `string` | `color` | The second colour of a duotone icon. |
102
+ | `iconWeight` | `'thin' \| 'regular' \| 'bold'` | `'regular'` | Stroke width 1.25, 1.5 or 1.75. |
103
+ | `strokeWidth` | `number` | `1.5` | Stroke width in pixels. Wins over `iconWeight`. |
104
+ | `strokeLinecap`, `strokeLinejoin` | `'butt' \| 'round' \| 'square'`, `'miter' \| 'round' \| 'bevel'` | `'round'` | The ends and the corners of lines. |
105
+ | `title` | `string` | none | Adds a `<title>` and names the icon. |
106
+ | `ariaLabel` | `string` | none | Names the icon (the `aria-label` attribute does the same). |
107
+ | `decorative` | `boolean` | `true` unless it has a name | `true` hides the icon from screen readers. |
108
+ | `rotate` | `number` | `0` | Degrees, clockwise. |
109
+ | `flip` | `'horizontal' \| 'vertical' \| 'both'` | none | Mirrors the icon. |
110
+ | `rtl` | `boolean` | `false` | Mirrors the icons that point a direction (arrows, chevrons, carets). |
111
+ | `absoluteStrokeWidth` | `boolean` | none | Does nothing: strokes are the same width on screen at every size. |
112
+
113
+ Strokes are drawn in screen pixels, so a 1.5 stroke is 1.5 pixels at 12 and at 48. When several settings give a stroke
114
+ width, the first of these wins: the `strokeWidth` prop, the `iconWeight` prop, the provider's `strokeWidth`, the
115
+ provider's `iconWeight`, and 1.5.
116
+
117
+ ## Set the defaults once
118
+
119
+ `IconProvider` gives everything inside it a `variant`, `size`, `color`, `secondaryColor`, `iconWeight`, `strokeWidth`,
120
+ `strokeLinecap`, `strokeLinejoin`, `decorative`, `className` or `rtl`. A provider inside another one changes what it
121
+ sets and keeps the rest, and a prop on an icon beats them all. `useIconContext()` reads the values that are in force.
111
122
 
112
123
  ```tsx
113
- import { IconProvider, SearchIcon, SettingsIcon } from '@editora/react-icons';
124
+ import { BellIcon, HeartIcon, IconProvider, StarIcon, useIconContext } from '@editora/react-icons';
125
+
126
+ // Reads what the nearest IconProvider decided, as an icon would.
127
+ function Readout() {
128
+ const { size, color, iconWeight } = useIconContext();
129
+ return <code style={{ font: '12px ui-monospace, monospace', color: '#57606a' }}>size {String(size)}, {color}, weight {iconWeight ?? 'regular'}</code>;
130
+ }
131
+
132
+ const row = { display: 'flex', alignItems: 'center', gap: 12, margin: '12px 0' };
114
133
 
115
- export function HeaderActions() {
134
+ export default function App() {
116
135
  return (
117
- <IconProvider value={{ size: 16, color: 'var(--color-fg-muted)' }}>
118
- <SearchIcon ariaLabel="Search" />
119
- <IconProvider value={{ color: 'var(--color-primary)' }}>
120
- <SettingsIcon ariaLabel="Settings" />
136
+ <>
137
+ <IconProvider value={{ size: 28, color: '#24292f' }}>
138
+ <div style={row}>
139
+ <BellIcon /> <StarIcon /> <HeartIcon />
140
+ <Readout />
141
+ </div>
142
+
143
+ {/* A nested provider changes what it sets and keeps the rest. */}
144
+ <IconProvider value={{ color: '#2563eb', iconWeight: 'bold' }}>
145
+ <div style={row}>
146
+ <BellIcon /> <StarIcon /> <HeartIcon />
147
+ <Readout />
148
+ </div>
149
+ </IconProvider>
121
150
  </IconProvider>
122
- </IconProvider>
151
+
152
+ {/* A prop beats the provider. */}
153
+ <IconProvider value={{ size: 28, color: '#24292f' }}>
154
+ <div style={row}>
155
+ <BellIcon /> <StarIcon color="#d97706" size={40} /> <HeartIcon variant="solid" color="#dc2626" />
156
+ </div>
157
+ </IconProvider>
158
+ </>
123
159
  );
124
160
  }
125
161
  ```
126
162
 
127
- Default context values:
128
- - `variant: 'outline'`
129
- - `size: 15`
130
- - `color: 'currentColor'`
131
- - `secondaryColor: 'currentColor'`
132
- - `strokeWidth: 1.5`
133
- - `strokeLinecap: 'round'`
134
- - `strokeLinejoin: 'round'`
135
-
136
- ## Usage Patterns
163
+ <p align="center">
164
+ <img src="https://raw.githubusercontent.com/ajaykr089/Editora/main/packages/react-icons/docs/images/provider.png" alt="Three rows of icons: a bell, a star and a heart in dark grey at size 28; the same three in blue and a bolder weight from a nested provider, each followed by the values it read; and a grey bell, a larger orange star and a solid red heart whose props beat the provider" width="392">
165
+ </p>
137
166
 
138
- ### 1) Named icon imports (best tree-shaking)
167
+ ## Names from data, and your own icons
139
168
 
140
- ```tsx
141
- import { CheckIcon, AlertTriangleIcon } from '@editora/react-icons';
142
-
143
- export function Status({ ok }: { ok: boolean }) {
144
- return ok ? <CheckIcon ariaLabel="Healthy" /> : <AlertTriangleIcon ariaLabel="Warning" />;
145
- }
146
- ```
147
-
148
- ### 2) Dynamic icon rendering from string names
169
+ Name an icon with a string where the name comes from data. `IconName` makes that string a checked one, and
170
+ `getIconComponent(name)` gives you the component when you need one. For an icon of your own, register it with
171
+ [`@editora/icons`](https://www.npmjs.com/package/@editora/icons#your-own-icons) and use it as `<Icon name="brand-mark" />`,
172
+ or wrap it with `createIcon(name, displayName?)` to get a component like the built-in ones. Install `@editora/icons`
173
+ yourself for that, so that your code can import it under pnpm and other strict layouts.
149
174
 
150
175
  ```tsx
151
- import { Icon, type IconName } from '@editora/react-icons';
152
-
176
+ import { registerIcon } from '@editora/icons';
177
+ import { createIcon, getIconComponent, Icon, type IconName } from '@editora/react-icons';
178
+
179
+ // Your own icon: register it once, and give it a component if you like.
180
+ registerIcon({
181
+ name: 'brand-mark',
182
+ variants: {
183
+ outline: {
184
+ nodes: [
185
+ { tag: 'path', attrs: { d: 'M12 3l8 4.5v9L12 21l-8-4.5v-9z' } },
186
+ { tag: 'path', attrs: { d: 'M12 8v8M8.5 10l7 4' } },
187
+ ],
188
+ },
189
+ },
190
+ });
191
+ export const BrandIcon = createIcon('brand-mark', 'BrandIcon');
192
+
193
+ // Names that come from data are typed: a typo is a compile error.
153
194
  type Item = { label: string; icon: IconName };
154
195
 
155
196
  const items: Item[] = [
156
197
  { label: 'Dashboard', icon: 'dashboard' },
157
198
  { label: 'Orders', icon: 'order' },
158
- { label: 'Reports', icon: 'report' }
199
+ { label: 'Reports', icon: 'report' },
200
+ { label: 'Settings', icon: 'settings' },
159
201
  ];
160
202
 
161
- export function Sidebar() {
203
+ // A component looked up by name, for a UI whose icons are configured elsewhere.
204
+ function PluginIcon({ name }: { name: IconName }) {
205
+ const Component = getIconComponent(name);
206
+ return <Component size={16} />;
207
+ }
208
+
209
+ export default function App() {
162
210
  return (
163
- <ul>
164
- {items.map((item) => (
165
- <li key={item.label}>
166
- <Icon name={item.icon} aria-hidden size={16} />
167
- <span>{item.label}</span>
211
+ <nav style={{ width: 220, font: '14px system-ui, sans-serif', color: '#24292f' }}>
212
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 0', fontWeight: 600 }}>
213
+ <BrandIcon size={20} color="#2563eb" title="Brand" /> Acme
214
+ </div>
215
+ <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
216
+ {items.map((item) => (
217
+ <li key={item.label} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 0' }}>
218
+ <Icon name={item.icon} size={16} />
219
+ {item.label}
220
+ </li>
221
+ ))}
222
+ <li style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 0' }}>
223
+ <PluginIcon name="command" />
224
+ Command palette
168
225
  </li>
169
- ))}
170
- </ul>
226
+ </ul>
227
+ </nav>
171
228
  );
172
229
  }
173
230
  ```
174
231
 
175
- ### 3) Runtime lookup for plugin-like UIs
176
-
177
- ```tsx
178
- import { getIconComponent, type IconName } from '@editora/react-icons';
179
-
180
- export function PluginIcon({ name }: { name: IconName }) {
181
- const Comp = getIconComponent(name);
182
- return <Comp size={18} aria-hidden />;
183
- }
184
- ```
185
-
186
- ### 4) Create custom named wrappers
232
+ <p align="center">
233
+ <img src="https://raw.githubusercontent.com/ajaykr089/Editora/main/packages/react-icons/docs/images/dynamic.png" alt="A navigation menu with a blue custom brand icon and the name Acme, then Dashboard, Orders, Reports, Settings and Command palette, each with an icon" width="230">
234
+ </p>
187
235
 
188
- ```tsx
189
- import { createIcon } from '@editora/react-icons';
236
+ ## API
190
237
 
191
- export const BillingIcon = createIcon('invoice', 'BillingIcon');
192
- ```
238
+ | Export | What it is |
239
+ | --- | --- |
240
+ | `Icon` | The component for any name. |
241
+ | `CheckIcon`, `SearchIcon`, … | A component for every icon, named after it in PascalCase (`chart-line` is `ChartLineIcon`). |
242
+ | `IconProvider`, `IconContext`, `useIconContext()` | Shared defaults, and a way to read them. |
243
+ | `defaultIconContext` | The built-in defaults: outline, 15 pixels, `currentColor`, a 1.5 stroke with round caps and joins. |
244
+ | `icons` (also `Icons`), `iconNames` | The map from name to component, and the list of names. |
245
+ | `getIconComponent(name)` | The component of a built-in icon, by name. |
246
+ | `createIcon(name, displayName?)` | A component for any icon, including one you registered. |
193
247
 
194
- ## Accessibility
248
+ The types are `IconName`, `IconProps`, `NamedIconProps`, `IconContextValue`, `IconComponent`, `IconFlip`,
249
+ `IconBaseProps` and `IconWeight`.
195
250
 
196
- - For decorative icons, use `aria-hidden` or leave `title`/`ariaLabel` unset (decorative mode is inferred).
197
- - For meaningful icons, provide `ariaLabel` or `title`.
198
- - Icons render with `role="img"` when semantic and `role="presentation"` when decorative.
251
+ ## Size, servers and Next.js
199
252
 
200
- Examples:
253
+ Every icon component and the whole catalog are one module, so importing one icon costs the same as importing them all:
254
+ about 164 KB minified and 57 KB gzipped, without React. Named imports are not smaller than `<Icon name="…">`. If a
255
+ page needs a handful of icons and every kilobyte counts, render them with
256
+ [`@editora/icons`](https://www.npmjs.com/package/@editora/icons) and keep the strings.
201
257
 
202
- ```tsx
203
- <CheckIcon aria-hidden />
204
- <CheckIcon ariaLabel="Saved successfully" />
205
- <Icon name="alert-circle" title="Validation error" />
206
- ```
207
-
208
- ## Theming
209
-
210
- The library is `currentColor`-first. Prefer CSS tokens/classes instead of hardcoded colors.
211
-
212
- ```tsx
213
- <IconProvider value={{ color: 'var(--ui-fg)', secondaryColor: 'var(--ui-fg-muted)' }}>
214
- <Icon name="chart-pie" variant="duotone" />
215
- </IconProvider>
216
- ```
217
-
218
- ## Performance Notes
219
-
220
- - Prefer named imports for static icon usage.
221
- - Use dynamic `Icon name="..."` when icon names are data-driven.
222
- - `@editora/react-icons` has `"sideEffects": false` for better tree-shaking.
223
-
224
- ## Development
225
-
226
- ```bash
227
- cd packages/react-icons
228
- npm run build
229
- ```
258
+ The components are plain, and render to markup on the server. They use React
259
+ context, and the package carries no `'use client'` directive, so in the Next.js App Router use them from a Client
260
+ Component, a file that starts with `'use client'`.
230
261
 
231
- Build notes:
232
- - `build` and `build:tsc` run `@editora/icons` type build first.
262
+ If you use [`@editora/ui-react`](https://www.npmjs.com/package/@editora/ui-react), its `Icon` draws the same icons as the
263
+ `<ui-icon>` web component instead.
233
264
 
234
- ## Troubleshooting
265
+ ## License
235
266
 
236
- - Missing icon output:
237
- - Verify icon name exists in `iconNames`.
238
- - Check spelling for dynamic names from API/CMS data.
239
- - Icon appears but not semantic to screen readers:
240
- - Provide `ariaLabel` or `title` for meaningful usage.
241
- - Stroke thickness looks inconsistent across sizes:
242
- - Try `absoluteStrokeWidth`.
267
+ MIT © [Ajay Kumar](https://github.com/ajaykr089)