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/dist/cdn.js CHANGED
@@ -1,3 +1,4 @@
1
- // the one-file build for a <script> tag: registers the three tags and exposes the mount functions
2
- import { mountLike, mountMagnet, mountGlassNav } from './elements.js';
3
- window.CraftLibrary = { mountLike, mountMagnet, mountGlassNav };
1
+ // the one-file build for a <script> tag: registers the four tags and exposes the mount functions (the card's 3D scene
2
+ // is fetched from next to this file the first time a card is mounted)
3
+ import { mountLike, mountMagnet, mountGlassNav, mountIridescentCard } from './elements.js';
4
+ window.CraftLibrary = { mountLike, mountMagnet, mountGlassNav, mountIridescentCard };
package/dist/craft.js CHANGED
@@ -1,4 +1,4 @@
1
- /* Craft Library, by Sara Lobo · liquid glass nav bar, bursting heart, magnetic icon · <glass-nav>, <like-button>, <magnetic-icon> */
1
+ /* Craft Library, by Sara Lobo · liquid glass nav bar, bursting heart, magnetic icon, iridescent card · <glass-nav>, <like-button>, <magnetic-icon>, <iridescent-card> */
2
2
  (() => {
3
3
  // dist/style.js
4
4
  var done = /* @__PURE__ */ new Set();
@@ -1309,6 +1309,52 @@
1309
1309
  };
1310
1310
  }
1311
1311
 
1312
+ // src/card-load-cdn.js
1313
+ var me = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : "";
1314
+ var base = me ? me.slice(0, me.lastIndexOf("/") + 1) : "https://cdn.jsdelivr.net/npm/craft-library@0/dist/";
1315
+ var loadCard = () => import(base + "card.cdn.js");
1316
+
1317
+ // dist/card-mount.js
1318
+ var LABEL = "Credit card. Press to turn it over and see the back.";
1319
+ var KEYS = ["name", "number", "expiry", "cvv", "logo", "size", "entrance", "interactive"];
1320
+ function mountIridescentCard(host, o = {}) {
1321
+ let card = null, gone = false;
1322
+ const opts = { label: o.label || LABEL };
1323
+ for (const k of KEYS) if (o[k] !== void 0 && o[k] !== null) opts[k] = o[k];
1324
+ if (typeof opts.number === "string") opts.number = opts.number.trim().split(/\s+/);
1325
+ const turned = (e) => {
1326
+ if (o.onTurn) o.onTurn(e.detail.face);
1327
+ };
1328
+ host.addEventListener("cardturn", turned);
1329
+ const ready = loadCard().then((m) => {
1330
+ if (gone) return null;
1331
+ if (!opts.logo && m.LOGO) opts.logo = m.LOGO;
1332
+ card = m.mountCard(host, opts);
1333
+ return card.ready.then(() => card);
1334
+ });
1335
+ return {
1336
+ ready,
1337
+ turn: (dir) => {
1338
+ if (card) card.turn(dir);
1339
+ },
1340
+ show: (face) => {
1341
+ if (card) card.show(face);
1342
+ },
1343
+ play: () => {
1344
+ if (card) card.play();
1345
+ },
1346
+ get face() {
1347
+ return card ? card.face : "front";
1348
+ },
1349
+ destroy() {
1350
+ gone = true;
1351
+ host.removeEventListener("cardturn", turned);
1352
+ if (card) card.destroy();
1353
+ card = null;
1354
+ }
1355
+ };
1356
+ }
1357
+
1312
1358
  // dist/elements.js
1313
1359
  function define(name, mount, options) {
1314
1360
  if (typeof customElements === "undefined" || customElements.get(name)) return;
@@ -1342,7 +1388,20 @@
1342
1388
  send(el, "select", { index });
1343
1389
  }
1344
1390
  }));
1391
+ define("iridescent-card", (el, o) => {
1392
+ css("craft-card-host", ":where(iridescent-card){display:block;position:relative;width:100%;min-width:300px;height:480px}");
1393
+ return mountIridescentCard(el, o);
1394
+ }, (el) => ({
1395
+ name: el.getAttribute("name") || void 0,
1396
+ number: el.getAttribute("number") || void 0,
1397
+ expiry: el.getAttribute("expiry") || void 0,
1398
+ cvv: el.getAttribute("cvv") || void 0,
1399
+ logo: el.getAttribute("logo") || void 0,
1400
+ size: el.getAttribute("size") ? +el.getAttribute("size") : void 0,
1401
+ entrance: el.getAttribute("entrance") === "false" ? false : void 0,
1402
+ label: el.getAttribute("label") || void 0
1403
+ }));
1345
1404
 
1346
1405
  // dist/cdn.js
1347
- window.CraftLibrary = { mountLike, mountMagnet, mountGlassNav };
1406
+ window.CraftLibrary = { mountLike, mountMagnet, mountGlassNav, mountIridescentCard };
1348
1407
  })();
package/dist/elements.js CHANGED
@@ -1,8 +1,9 @@
1
- // <glass-nav>, <like-button> and <magnetic-icon>: the pieces as HTML tags, for pages without React.
1
+ // <glass-nav>, <like-button>, <magnetic-icon> and <iridescent-card>: the pieces as HTML tags, for pages without React.
2
2
  // They render into the page itself (no shadow root), so the glass can blend with what is behind it.
3
3
  import { mountLike } from './like.js';
4
4
  import { mountMagnet } from './magnet.js';
5
5
  import { mountGlassNav } from './glassnav.js';
6
+ import { mountIridescentCard } from './card-mount.js';
6
7
  import { css } from './style.js';
7
8
 
8
9
  function define(name, mount, options) {
@@ -33,4 +34,21 @@ define('glass-nav', mountGlassNav, (el) => ({
33
34
  onSelect: (index) => { el.setAttribute('active', index); send(el, 'select', { index }); }
34
35
  }));
35
36
 
36
- export { mountLike, mountMagnet, mountGlassNav };
37
+ // the card fills the tag: a block, 100% wide (at least 300px, so a shrink-to-fit parent can't fold it) and 480px tall
38
+ // unless the page sizes it (zero specificity, so any rule wins). Each turn bubbles up from inside as a "cardturn"
39
+ // event, with e.detail.face.
40
+ define('iridescent-card', (el, o) => {
41
+ css('craft-card-host', ':where(iridescent-card){display:block;position:relative;width:100%;min-width:300px;height:480px}');
42
+ return mountIridescentCard(el, o);
43
+ }, (el) => ({
44
+ name: el.getAttribute('name') || undefined,
45
+ number: el.getAttribute('number') || undefined,
46
+ expiry: el.getAttribute('expiry') || undefined,
47
+ cvv: el.getAttribute('cvv') || undefined,
48
+ logo: el.getAttribute('logo') || undefined,
49
+ size: el.getAttribute('size') ? +el.getAttribute('size') : undefined,
50
+ entrance: el.getAttribute('entrance') === 'false' ? false : undefined,
51
+ label: el.getAttribute('label') || undefined
52
+ }));
53
+
54
+ export { mountLike, mountMagnet, mountGlassNav, mountIridescentCard };
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { createElement, useEffect, useRef } from 'react';
4
4
  import { mountLike } from './like.js';
5
5
  import { mountMagnet } from './magnet.js';
6
6
  import { mountGlassNav } from './glassnav.js';
7
+ import { mountIridescentCard } from './card-mount.js';
7
8
 
8
9
  const HOST = { display: 'inline-block', lineHeight: 0, verticalAlign: 'middle' };
9
10
 
@@ -40,4 +41,17 @@ export function GlassNav({ active = 2, labels, label, onSelect, className, style
40
41
  return createElement('span', { ref: host, className, style });
41
42
  }
42
43
 
43
- export { mountLike, mountMagnet, mountGlassNav };
44
+ // The card fills the box it renders (100% wide and `height` tall, 480px by default) and sits centred in it. The box
45
+ // keeps at least 300px of width, so a parent that shrinks to its content (a centring flex row) can't fold it to nothing.
46
+ // It loads its 3D scene (three.js) the first time it mounts. onTurn reports each turn with the face now showing.
47
+ export function IridescentCard({ height = 480, size, name, number, expiry, cvv, logo, entrance, label, onTurn, className, style }) {
48
+ const host = useRef(null), turn = useLatest(onTurn);
49
+ const num = Array.isArray(number) ? number.join(' ') : number;
50
+ useEffect(() => {
51
+ const m = mountIridescentCard(host.current, { size, name, number: num, expiry, cvv, logo, entrance, label, onTurn: (f) => turn.current && turn.current(f) });
52
+ return () => m.destroy();
53
+ }, [size, name, num, expiry, cvv, logo, entrance, label]);
54
+ return createElement('div', { ref: host, className, style: { position: 'relative', width: '100%', minWidth: 300, height, ...style } });
55
+ }
56
+
57
+ export { mountLike, mountMagnet, mountGlassNav, mountIridescentCard };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "craft-library",
3
- "version": "0.1.3",
4
- "description": "Craft Library by Sara Lobo: a liquid glass nav bar, a bursting heart and a magnetic icon, for React or plain HTML",
3
+ "version": "0.2.0",
4
+ "description": "Craft Library by Sara Lobo: a liquid glass nav bar, a bursting heart, a magnetic icon and an iridescent 3D card, for React or plain HTML",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -41,9 +41,15 @@
41
41
  "animation",
42
42
  "micro-interaction",
43
43
  "navbar",
44
- "like-button"
44
+ "like-button",
45
+ "3d",
46
+ "three",
47
+ "credit-card"
45
48
  ],
46
49
  "author": "Sara Lobo",
47
50
  "license": "MIT",
48
- "homepage": "https://claude.ai/artifact/LBBWCfEHJGvfBSynV3wDuR"
51
+ "homepage": "https://claude.ai/artifact/LBBWCfEHJGvfBSynV3wDuR",
52
+ "dependencies": {
53
+ "three": "0.169.0"
54
+ }
49
55
  }