craft-library 0.1.3 → 0.2.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Craft Library
2
2
 
3
- Interface pieces by [Sara Lobo](https://www.saralobodesign.com/), designed, tested and polished one detail at a time: a liquid glass nav bar, a bursting heart and a magnetic icon. Each one is the exact piece from the library, with its own CSS and motion, no dependencies, for React 18+ or plain HTML.
3
+ Interface pieces by [Sara Lobo](https://www.saralobodesign.com/), designed, tested and polished one detail at a time: a liquid glass nav bar, a bursting heart, a magnetic icon and an iridescent 3D card. Each one is the exact piece from the library, with its own CSS and motion, for React 18+ or plain HTML. The only dependency is three.js, for the card, and it loads only when a card is on the page.
4
4
 
5
5
  ```bash
6
6
  npm install craft-library
@@ -58,9 +58,31 @@ import { MagneticIcon } from 'craft-library';
58
58
  | `label` | `string` | The accessible name. Default `"Search"`. |
59
59
  | `onClick` | `(event) => void` | |
60
60
 
61
+ ## Iridescent card
62
+
63
+ A 3D metal credit card: a brushed iridescent plate, a fine struck frame along the edge, a chip and the Visa mark. It arrives showing its back and makes a slow half turn to its face; a tap or a drag turns it over to show the numbers, heavy and without bounce. At rest it breathes slowly, and the light slides across the metal with its angle.
64
+
65
+ ```jsx
66
+ import { IridescentCard } from 'craft-library';
67
+
68
+ <IridescentCard height={480} onTurn={(face) => console.log(face)} />
69
+ ```
70
+
71
+ | Prop | | |
72
+ |---|---|---|
73
+ | `height` | `number \| string` | The box the card fills: 100% wide (at least 300px) and this tall, the card centred in it. Default `480`. |
74
+ | `size` | `0–1` | The card's height as a share of the box's. Default `0.72`. |
75
+ | `onTurn` | `(face) => void` | After every turn: `"front"` or `"back"`. |
76
+ | `name`, `number`, `expiry`, `cvv` | `string` | What the back shows. `number` as `"4532 8890 1274 3306"`. |
77
+ | `entrance` | `boolean` | `false` skips the half turn on mount. Default `true`. |
78
+ | `logo` | `string` | An image URL for the mark on the face, printed in white. Default: the Visa mark. |
79
+ | `label` | `string` | The accessible name. |
80
+
81
+ It is WebGL (three.js 0.169, which comes with the package and loads the first time a card mounts), so one card per screen is best. It is made for a dark background; black is best. The Visa mark is a trademark of Visa Inc., there to show a card: pass your own `logo` for anything real.
82
+
61
83
  ## Plain HTML
62
84
 
63
- One script registers three tags. Same pieces, same props as attributes.
85
+ One script registers four tags. Same pieces, same props as attributes.
64
86
 
65
87
  ```html
66
88
  <script src="https://cdn.jsdelivr.net/npm/craft-library@0/dist/craft.js"></script>
@@ -68,12 +90,13 @@ One script registers three tags. Same pieces, same props as attributes.
68
90
  <glass-nav active="0"></glass-nav> <!-- "select" event: e.detail.index -->
69
91
  <like-button></like-button> <!-- "change" event: e.detail.liked -->
70
92
  <magnetic-icon size="40"></magnetic-icon>
93
+ <iridescent-card></iridescent-card> <!-- "cardturn" event: e.detail.face; 100% wide, 480px tall unless you size it -->
71
94
  ```
72
95
 
73
96
  With a bundler and no React: `import 'craft-library/elements'`.
74
97
 
75
98
  ## Motion and access
76
99
 
77
- Every item is a real `<button>` with an accessible name; the nav marks the chosen one with `aria-current` and moves with the arrow keys. With `prefers-reduced-motion`, the heart only changes colour, the nav only slides and the magnet stays still.
100
+ Every item is a real `<button>` with an accessible name; the nav marks the chosen one with `aria-current` and moves with the arrow keys. The card is a `role="button"` that Enter, Space and the arrow keys turn over. With `prefers-reduced-motion`, the heart only changes colour, the nav only slides, the magnet stays still and the card swaps faces with a fade, with no entrance and no breathing.
78
101
 
79
102
  MIT · [Craft Library](https://claude.ai/artifact/LBBWCfEHJGvfBSynV3wDuR)
@@ -0,0 +1,2 @@
1
+ // where the card comes from: for bundlers, the package's card.js (it imports the `three` dependency)
2
+ export const loadCard = () => import('./card.js');
@@ -0,0 +1,32 @@
1
+ // Iridescent card: the mount around the library's card.js. card.js, and three.js with it, loads only when a card is
2
+ // mounted, so the other pieces stay light.
3
+ import { loadCard } from './card-load.js';
4
+
5
+ const LABEL = 'Credit card. Press to turn it over and see the back.';
6
+ const KEYS = ['name', 'number', 'expiry', 'cvv', 'logo', 'size', 'entrance', 'interactive'];
7
+
8
+ // host: the element the card fills (give it a size; the card sits centred at `size` of its height).
9
+ // o: { name, number ('4532 8890 1274 3306' or four groups), expiry, cvv, logo (an image URL), size (0–1, default 0.72),
10
+ // entrance (false: no half turn on mount), interactive (false: no tap or drag), label, onTurn(face) }
11
+ export function mountIridescentCard(host, o = {}) {
12
+ let card = null, gone = false;
13
+ const opts = { label: o.label || LABEL };
14
+ for (const k of KEYS) if (o[k] !== undefined && o[k] !== null) opts[k] = o[k];
15
+ if (typeof opts.number === 'string') opts.number = opts.number.trim().split(/\s+/);
16
+ const turned = (e) => { if (o.onTurn) o.onTurn(e.detail.face); };
17
+ host.addEventListener('cardturn', turned);
18
+ const ready = loadCard().then((m) => {
19
+ if (gone) return null;
20
+ if (!opts.logo && m.LOGO) opts.logo = m.LOGO; // the Visa mark, carried in the module
21
+ card = m.mountCard(host, opts);
22
+ return card.ready.then(() => card);
23
+ });
24
+ return {
25
+ ready,
26
+ turn: (dir) => { if (card) card.turn(dir); },
27
+ show: (face) => { if (card) card.show(face); },
28
+ play: () => { if (card) card.play(); },
29
+ get face() { return card ? card.face : 'front'; },
30
+ destroy() { gone = true; host.removeEventListener('cardturn', turned); if (card) card.destroy(); card = null; }
31
+ };
32
+ }
Binary file