morphico 0.1.0 → 0.3.0

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/LICENSE-lucide ADDED
@@ -0,0 +1,43 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Lucide Icons and Contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+
17
+ ---
18
+
19
+ The following Lucide icons are derived from the Feather project:
20
+
21
+ airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
22
+
23
+ The MIT License (MIT) (for the icons listed above)
24
+
25
+ Copyright (c) 2013-present Cole Bemis
26
+
27
+ Permission is hereby granted, free of charge, to any person obtaining a copy
28
+ of this software and associated documentation files (the "Software"), to deal
29
+ in the Software without restriction, including without limitation the rights
30
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31
+ copies of the Software, and to permit persons to whom the Software is
32
+ furnished to do so, subject to the following conditions:
33
+
34
+ The above copyright notice and this permission notice shall be included in all
35
+ copies or substantial portions of the Software.
36
+
37
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43
+ SOFTWARE.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Or from a CDN, as a classic script with the global `morphico`:
19
19
  ```html
20
20
  <script src="https://cdn.jsdelivr.net/npm/morphico"></script>
21
21
  <script>
22
- const { icon, text } = morphico;
22
+ const { icon, text, clip } = morphico;
23
23
  </script>
24
24
  ```
25
25
 
@@ -33,7 +33,35 @@ digit.to('8', { onEnd: (result) => {} }); // or pass a callback
33
33
  digit.destroy(); // stops and removes it (e.g. when a component unmounts)
34
34
  ```
35
35
 
36
- States: `'0'`…`'9'`, `'-'`, and `' '` (empty: nothing drawn, shapes grow out of it and fade).
36
+ States of the digit sets: `'0'`…`'9'`, `'-'` `'/'` `'.'` `','` `':'`, and `' '` (empty: nothing drawn, shapes grow
37
+ out of it and fade). A digit morphing into `-` `/` `.` `,` is pressed flat onto it; into `:` it splits into the two dots.
38
+
39
+ Icon sets (based on [Lucide](https://lucide.dev)):
40
+
41
+ | Set | States |
42
+ | --- | --- |
43
+ | `media` | `play`, `pause`, `stop` |
44
+ | `menu` | `menu` (☰), `close` (✕), `back` (←) |
45
+ | `checkbox` | `unchecked` (☐), `checked` (☑), `checked-big` (✓ breaking out of the box) |
46
+ | `radio` | `unchecked` (○), `checked` (✓ in a circle), `checked-big` (✓ breaking out of the circle) |
47
+ | `folder` | `closed`, `open` |
48
+ | `theme` | `light` (sun), `dark` (moon) |
49
+ | `weather` | `sunny`, `frosty`, `partly-cloudy`, `showers`, `cloudy`, `thunder`, `rain`, `snow`, `drizzle` |
50
+ | `eye` | `visible`, `hidden` (slashed) |
51
+ | `volume` | `muted` (✕), `low` (no waves), `medium`, `high` |
52
+ | `toggle` | `plus`, `minus`, `close` (✕), `check` |
53
+ | `lock` | `locked`, `unlocked` |
54
+ | `bell` | `on`, `off` (slashed) |
55
+ | `mic` | `on`, `off` (slashed) |
56
+ | `chevron` | `up`, `right`, `down`, `left` |
57
+ | `copy` | `copy`, `copied` (✓) |
58
+ | `wifi` | `none`, `low`, `medium`, `high` |
59
+ | `battery` | `empty`, `low`, `medium`, `full` |
60
+
61
+ ```ts
62
+ const player = icon(button, { set: 'media', state: 'play' });
63
+ player.to('pause');
64
+ ```
37
65
 
38
66
  ## A line of characters: `text(element, options)`
39
67
 
@@ -44,21 +72,61 @@ clock.set('05:00'); // only the digits that changed morph
44
72
  clock.destroy();
45
73
  ```
46
74
 
47
- - Supported characters: digits `0`–`9`, `-` and space morph; `:` `.` `,` `/` stay still.
75
+ - Supported characters: digits `0`–`9`, space, `-` `:` `.` `,` `/` — all of them morph.
48
76
  **Any other character is removed** (with the regex `/[^0-9 :.,\/-]/g`): `'12:09 AM'` shows `12:09 `.
49
- - If the length or the places of `:` `.` `,` `/` change, the line is rebuilt without animation. Pad counters with
50
- spaces to keep them morphing: `counter.set(String(count).padStart(3, ' '))`.
77
+ - Cells: digits, space and `-` have one width, `:` `.` `,` half of it, `/` 0.7 of it. A change morphs when the length
78
+ and every cell's width stay the same (`5` ↔ `-`, `.` ↔ `,`); otherwise the line is rebuilt without animation
79
+ (`5` ↔ `:`). Pad counters with spaces to keep them morphing: `counter.set(String(count).padStart(3, ' '))`.
51
80
  - Digits sit on the text baseline, and every cell has the same width, so clocks don't jiggle.
52
81
 
82
+ ## A cut-out: `clip(element, options)`
83
+
84
+ Cuts any element (an `<img>`, a `<div>`, a `<main>` …) out by a shape, and morphs, moves, resizes and turns it.
85
+
86
+ ```ts
87
+ const photo = clip(document.querySelector('#photo'), { state: 'star', x: 50, y: 50, size: '80%' });
88
+
89
+ await photo.to('heart'); // morph
90
+ photo.to('shield', { rotation: 360, x: 30, size: '120px' }); // morph + turn + move together
91
+ photo.to({ x: 70, y: '150px' }); // move only, the shape stays
92
+ photo.set({ rotation: 15 }); // jump, no animation (e.g. while dragging a slider)
93
+ photo.set({ outline: { width: 16 } }); // only a 16 px band along the edge shows
94
+ photo.destroy(); // the element is whole again
95
+ ```
96
+
97
+ Shapes (based on [Lucide](https://lucide.dev)): `circle`, `ellipse`, `heart`, `sparkle`, `astroid`, `bookmark`,
98
+ `shield`, `moon`, `tag`, `square`, `badge`, `triangle`, `droplet`, `pentagon`, `hexagon`, `octagon`, `squircle`,
99
+ `star`, `rectangle-horizontal`, `rectangle-vertical`, `message-circle`, `message-square`, `diamond`, `cloud`, `puzzle`.
100
+
101
+ | Option | Default | |
102
+ | --- | --- | --- |
103
+ | `state` | `'circle'` | The shape |
104
+ | `x`, `y` | `50` | The shape's **centre**. A number is %, or a string `'40%'` / `'120px'` (% of the element's width for `x`, height for `y`) |
105
+ | `size` | fits | The side of the shape's square (% of the element's width, or px). The shape keeps its own proportions inside that square. Default: the largest square that fits the element |
106
+ | `rotation` | `0` | Degrees, clockwise, **absolute**: `rotation: 360` ends one full turn from 0. The shape turns rigidly, also in a wide or tall element |
107
+ | `roundness` | `1` | Corners: `0` = sharp … `1` = the shape's own (the maximum) |
108
+ | `outline` | `false` | `{ width, band }`: only a band of `width` px along the edge shows; `band`: `'inside'` (default), `'centre'` or `'outside'` the edge. Not animated |
109
+ | `duration`, `easing` | `400`, `'easeInOutCubic'` | As for icons; also per `to()` call |
110
+
111
+ Everything except `outline` animates together in `to()`. How it works: a filled shape uses CSS `clip-path: url(#…)`,
112
+ an outlined one `mask: url(#…)` (clip-path has no line width); the `<clipPath>` / `<mask>` sit in a small hidden
113
+ `<svg>` that `clip()` adds to the page. It follows the element's size (`ResizeObserver`). Overflow beyond the element is
114
+ cut off, as with any clip-path.
115
+
53
116
  ## Options
54
117
 
55
118
  | Option | For | Default | |
56
119
  | --- | --- | --- | --- |
57
- | `set` | both | `'round'` | `'round'`, `'square'`, `'condensed'`, `'slim'`, `'handwritten'` |
120
+ | `set` | both | `'round'` | digits: `'round'`, `'square'`, `'condensed'`, `'slim'`, `'handwritten'`; icons (`icon()` only): `'media'`, `'menu'`, `'checkbox'`, `'radio'`, `'folder'`, `'theme'`, `'weather'`, `'eye'`, `'volume'`, `'toggle'`, `'lock'`, `'bell'`, `'mic'`, `'chevron'`, `'copy'`, `'wifi'`, `'battery'` |
58
121
  | `state` / `value` | icon / text | empty | What is shown first |
59
122
  | `size` | both | `'1em'` | CSS size (icon: width and height; text: height). `1em` follows the font size |
60
123
  | `duration` | both | `400` | Milliseconds |
61
124
  | `easing` | both | `'easeInOutCubic'` | `'linear'`, `'easeInOutCubic'`, `'easeOutBack'`, `'easeOutElastic'`, or a function `(progress) => easedProgress` |
125
+ | `strokeWidth` | both | per set | Line width. A number is in grid units (an icon is 24 × 24; digits use about 1.1–1.6, icon sets 1.78) and scales with the size; a CSS length (`'2px'`, `'0.1rem'`, `'0.08em'`) stays that wide at any size |
126
+ | `lineCap` | both | per set | `'round'`, `'butt'`, `'square'` |
127
+ | `lineJoin` | both | per set | `'round'`, `'miter'`, `'bevel'` |
128
+ | `fill` | both | `false` | `true` fills closed shapes with the CSS color, or pass a CSS color |
129
+ | `roundness` | icon | `1` | Corner roundness: `0` = sharp … `1` = the icon's own corners (the maximum). Icon sets only |
62
130
  | `cellWidth` | text | per set | Width of a digit cell in grid units (a digit is 16 high) |
63
131
  | `spacing` | text | per set | Gap between cells in grid units |
64
132
 
@@ -72,7 +140,7 @@ clock.destroy();
72
140
  The earlier promise resolves with `{ interrupted: true }`; promises never stay pending.
73
141
  - **Reduced motion:** when the user's system asks for reduced motion, shapes change without animation.
74
142
  - **Accessibility:** the icon / line has `role="img"` and an `aria-label` with the current value.
75
- - **Server-side rendering:** importing does not touch the DOM; only `icon()` / `text()` do.
143
+ - **Server-side rendering:** importing does not touch the DOM; only `icon()` / `text()` / `clip()` do.
76
144
 
77
145
  ## Development
78
146
 
@@ -87,4 +155,5 @@ npm run build # src/ → dist/
87
155
 
88
156
  ## License
89
157
 
90
- [MIT](LICENSE)
158
+ [MIT](LICENSE). The icon sets and clip shapes are based on [Lucide](https://lucide.dev) icons (ISC; some from Feather, MIT):
159
+ see [LICENSE-lucide](LICENSE-lucide).