craft-library 0.1.3 → 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/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 five tags and exposes the mount functions (the 3D pieces' scenes
2
+ // are fetched from next to this file the first time one is mounted)
3
+ import { mountLike, mountMagnet, mountGlassNav, mountIridescentCard, mountPiggyBank } from './elements.js';
4
+ window.CraftLibrary = { mountLike, mountMagnet, mountGlassNav, mountIridescentCard, mountPiggyBank };
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 piggy bank · <glass-nav>, <like-button>, <magnetic-icon>, <iridescent-card>, <piggy-bank> */
2
2
  (() => {
3
3
  // dist/style.js
4
4
  var done = /* @__PURE__ */ new Set();
@@ -1309,6 +1309,89 @@
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
+
1358
+ // src/piggy-load-cdn.js
1359
+ var me2 = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : "";
1360
+ var base2 = me2 ? me2.slice(0, me2.lastIndexOf("/") + 1) : "https://cdn.jsdelivr.net/npm/craft-library@0/dist/";
1361
+ var loadPiggy = () => import(base2 + "piggy.cdn.js");
1362
+
1363
+ // dist/piggy-mount.js
1364
+ var LABEL2 = "A glass piggy bank hops in, coins drop in through its slot and it closes its eyes, happy.";
1365
+ function mountPiggyBank(host, o = {}) {
1366
+ let pig = null, gone = false, wantPlay = false;
1367
+ const opts = { label: o.label || LABEL2 };
1368
+ if (o.autoplay === false) opts.autoplay = false;
1369
+ if (o.interactive === false) opts.interactive = false;
1370
+ const done2 = () => {
1371
+ if (o.onDone) o.onDone();
1372
+ };
1373
+ host.addEventListener("piggydone", done2);
1374
+ const ready = loadPiggy().then((m) => {
1375
+ if (gone) return null;
1376
+ pig = m.mountPiggy(host, opts);
1377
+ if (wantPlay) pig.play();
1378
+ return pig.ready.then(() => pig);
1379
+ });
1380
+ return {
1381
+ ready,
1382
+ play: () => {
1383
+ if (pig) pig.play();
1384
+ else wantPlay = true;
1385
+ },
1386
+ destroy() {
1387
+ gone = true;
1388
+ host.removeEventListener("piggydone", done2);
1389
+ if (pig) pig.destroy();
1390
+ pig = null;
1391
+ }
1392
+ };
1393
+ }
1394
+
1312
1395
  // dist/elements.js
1313
1396
  function define(name, mount, options) {
1314
1397
  if (typeof customElements === "undefined" || customElements.get(name)) return;
@@ -1342,7 +1425,30 @@
1342
1425
  send(el, "select", { index });
1343
1426
  }
1344
1427
  }));
1428
+ define("iridescent-card", (el, o) => {
1429
+ css("craft-card-host", ":where(iridescent-card){display:block;position:relative;width:100%;min-width:300px;height:480px}");
1430
+ return mountIridescentCard(el, o);
1431
+ }, (el) => ({
1432
+ name: el.getAttribute("name") || void 0,
1433
+ number: el.getAttribute("number") || void 0,
1434
+ expiry: el.getAttribute("expiry") || void 0,
1435
+ cvv: el.getAttribute("cvv") || void 0,
1436
+ logo: el.getAttribute("logo") || void 0,
1437
+ size: el.getAttribute("size") ? +el.getAttribute("size") : void 0,
1438
+ entrance: el.getAttribute("entrance") === "false" ? false : void 0,
1439
+ label: el.getAttribute("label") || void 0
1440
+ }));
1441
+ define("piggy-bank", (el, o) => {
1442
+ css("craft-piggy-host", ":where(piggy-bank){display:block;position:relative;width:100%;min-width:280px;height:560px}");
1443
+ const m = mountPiggyBank(el, o);
1444
+ el.play = m.play;
1445
+ return m;
1446
+ }, (el) => ({
1447
+ autoplay: el.getAttribute("autoplay") === "false" ? false : void 0,
1448
+ interactive: el.getAttribute("interactive") === "false" ? false : void 0,
1449
+ label: el.getAttribute("label") || void 0
1450
+ }));
1345
1451
 
1346
1452
  // dist/cdn.js
1347
- window.CraftLibrary = { mountLike, mountMagnet, mountGlassNav };
1453
+ window.CraftLibrary = { mountLike, mountMagnet, mountGlassNav, mountIridescentCard, mountPiggyBank };
1348
1454
  })();
package/dist/elements.js CHANGED
@@ -1,8 +1,10 @@
1
- // <glass-nav>, <like-button> and <magnetic-icon>: the pieces as HTML tags, for pages without React.
1
+ // <glass-nav>, <like-button>, <magnetic-icon>, <iridescent-card> and <piggy-bank>: 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';
7
+ import { mountPiggyBank } from './piggy-mount.js';
6
8
  import { css } from './style.js';
7
9
 
8
10
  function define(name, mount, options) {
@@ -33,4 +35,34 @@ define('glass-nav', mountGlassNav, (el) => ({
33
35
  onSelect: (index) => { el.setAttribute('active', index); send(el, 'select', { index }); }
34
36
  }));
35
37
 
36
- export { mountLike, mountMagnet, mountGlassNav };
38
+ // 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
39
+ // unless the page sizes it (zero specificity, so any rule wins). Each turn bubbles up from inside as a "cardturn"
40
+ // event, with e.detail.face.
41
+ define('iridescent-card', (el, o) => {
42
+ css('craft-card-host', ':where(iridescent-card){display:block;position:relative;width:100%;min-width:300px;height:480px}');
43
+ return mountIridescentCard(el, o);
44
+ }, (el) => ({
45
+ name: el.getAttribute('name') || undefined,
46
+ number: el.getAttribute('number') || undefined,
47
+ expiry: el.getAttribute('expiry') || undefined,
48
+ cvv: el.getAttribute('cvv') || undefined,
49
+ logo: el.getAttribute('logo') || undefined,
50
+ size: el.getAttribute('size') ? +el.getAttribute('size') : undefined,
51
+ entrance: el.getAttribute('entrance') === 'false' ? false : undefined,
52
+ label: el.getAttribute('label') || undefined
53
+ }));
54
+
55
+ // the piggy bank fills the tag: a block, 100% wide (at least 280px) and 560px tall unless the page sizes it. It plays
56
+ // the first time it comes into view; each play ends with a "piggydone" event. el.play() plays it again.
57
+ define('piggy-bank', (el, o) => {
58
+ css('craft-piggy-host', ':where(piggy-bank){display:block;position:relative;width:100%;min-width:280px;height:560px}');
59
+ const m = mountPiggyBank(el, o);
60
+ el.play = m.play;
61
+ return m;
62
+ }, (el) => ({
63
+ autoplay: el.getAttribute('autoplay') === 'false' ? false : undefined,
64
+ interactive: el.getAttribute('interactive') === 'false' ? false : undefined,
65
+ label: el.getAttribute('label') || undefined
66
+ }));
67
+
68
+ export { mountLike, mountMagnet, mountGlassNav, mountIridescentCard, mountPiggyBank };
package/dist/index.js CHANGED
@@ -4,6 +4,8 @@ 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';
8
+ import { mountPiggyBank } from './piggy-mount.js';
7
9
 
8
10
  const HOST = { display: 'inline-block', lineHeight: 0, verticalAlign: 'middle' };
9
11
 
@@ -40,4 +42,30 @@ export function GlassNav({ active = 2, labels, label, onSelect, className, style
40
42
  return createElement('span', { ref: host, className, style });
41
43
  }
42
44
 
43
- export { mountLike, mountMagnet, mountGlassNav };
45
+ // The card fills the box it renders (100% wide and `height` tall, 480px by default) and sits centred in it. The box
46
+ // keeps at least 300px of width, so a parent that shrinks to its content (a centring flex row) can't fold it to nothing.
47
+ // It loads its 3D scene (three.js) the first time it mounts. onTurn reports each turn with the face now showing.
48
+ export function IridescentCard({ height = 480, size, name, number, expiry, cvv, logo, entrance, label, onTurn, className, style }) {
49
+ const host = useRef(null), turn = useLatest(onTurn);
50
+ const num = Array.isArray(number) ? number.join(' ') : number;
51
+ useEffect(() => {
52
+ const m = mountIridescentCard(host.current, { size, name, number: num, expiry, cvv, logo, entrance, label, onTurn: (f) => turn.current && turn.current(f) });
53
+ return () => m.destroy();
54
+ }, [size, name, num, expiry, cvv, logo, entrance, label]);
55
+ return createElement('div', { ref: host, className, style: { position: 'relative', width: '100%', minWidth: 300, height, ...style } });
56
+ }
57
+
58
+ // The piggy bank fills the box it renders (100% wide and `height` tall, 560px by default; it is made for a phone screen)
59
+ // and plays its moment the first time it comes into view; a tap plays it again. replay: change it (a counter) to play
60
+ // it again from code. It loads its 3D scene (three.js) the first time it mounts. onDone reports the end of each play.
61
+ export function PiggyBank({ height = 560, autoplay, interactive, replay, label, onDone, className, style }) {
62
+ const host = useRef(null), pig = useRef(null), last = useRef(replay), done = useLatest(onDone);
63
+ useEffect(() => {
64
+ const m = pig.current = mountPiggyBank(host.current, { autoplay, interactive, label, onDone: () => done.current && done.current() });
65
+ return () => { m.destroy(); pig.current = null; };
66
+ }, [autoplay, interactive, label]);
67
+ useEffect(() => { if (last.current === replay) return; last.current = replay; if (pig.current) pig.current.play(); }, [replay]);
68
+ return createElement('div', { ref: host, className, style: { position: 'relative', width: '100%', minWidth: 280, height, ...style } });
69
+ }
70
+
71
+ export { mountLike, mountMagnet, mountGlassNav, mountIridescentCard, mountPiggyBank };
@@ -0,0 +1,2 @@
1
+ // where the piggy bank comes from: for bundlers, the package's piggy.js (it imports the `three` dependency)
2
+ export const loadPiggy = () => import('./piggy.js');
@@ -0,0 +1,27 @@
1
+ // Glass piggy bank: the mount around the library's piggy.js. piggy.js, and three.js with it, loads only when a piggy
2
+ // bank is mounted, so the other pieces stay light.
3
+ import { loadPiggy } from './piggy-load.js';
4
+
5
+ const LABEL = 'A glass piggy bank hops in, coins drop in through its slot and it closes its eyes, happy.';
6
+
7
+ // host: the element the moment fills (give it a size). o: { autoplay (false: wait for play()), interactive (false: no
8
+ // tap to replay, no drag), label, onDone() after each play }
9
+ export function mountPiggyBank(host, o = {}) {
10
+ let pig = null, gone = false, wantPlay = false;
11
+ const opts = { label: o.label || LABEL };
12
+ if (o.autoplay === false) opts.autoplay = false;
13
+ if (o.interactive === false) opts.interactive = false;
14
+ const done = () => { if (o.onDone) o.onDone(); };
15
+ host.addEventListener('piggydone', done);
16
+ const ready = loadPiggy().then((m) => {
17
+ if (gone) return null;
18
+ pig = m.mountPiggy(host, opts);
19
+ if (wantPlay) pig.play();
20
+ return pig.ready.then(() => pig);
21
+ });
22
+ return {
23
+ ready,
24
+ play: () => { if (pig) pig.play(); else wantPlay = true; },
25
+ destroy() { gone = true; host.removeEventListener('piggydone', done); if (pig) pig.destroy(); pig = null; }
26
+ };
27
+ }