jaml-ui 0.19.0 → 0.20.1

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.
@@ -42,7 +42,7 @@ export function CategoryPicker({ config, onSelect, onCancel }) {
42
42
  clauseKey: config.clauseKey,
43
43
  });
44
44
  }, [onSelect, config]);
45
- const renderItem = (item, isMuted = false) => (_jsxs("div", { onClick: () => handleSelect(item), title: item.name, style: {
45
+ const renderItem = (item, isMuted = false) => (_jsxs("div", { className: "j-juice-hover", onClick: () => handleSelect(item), title: item.name, style: {
46
46
  display: "flex",
47
47
  flexDirection: "column",
48
48
  alignItems: "center",
@@ -51,8 +51,8 @@ export function CategoryPicker({ config, onSelect, onCancel }) {
51
51
  borderRadius: 4,
52
52
  cursor: "pointer",
53
53
  opacity: isMuted ? 0.3 : 1,
54
- }, children: [_jsx(JimboSprite, { name: item.name, sheet: config.sheet, width: 48 }), _jsx(JimboText, { size: "micro", tone: "grey", style: { maxWidth: 60, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: item.name })] }, item.name));
55
- return (_jsxs("div", { style: { padding: 0, maxWidth: 420, maxHeight: "80vh", display: "flex", flexDirection: "column" }, children: [_jsxs("div", { className: "j-flex j-gap-sm", style: { padding: "8px 10px 4px" }, children: [_jsx("input", { className: "j-seed-input__field", type: "text", placeholder: `Search ${config.title.toLowerCase()}...`, value: search, onChange: (e) => setSearch(e.target.value), style: { fontSize: 13, padding: "6px 10px", textTransform: "none", letterSpacing: "0.04em" } }), _jsx(JimboButton, { tone: "gold", size: "sm", onClick: handleAny, children: "Any" })] }), config.hint && (_jsx("div", { className: "j-inner-panel", style: { margin: "4px 10px 6px", padding: "6px 10px" }, children: _jsx(JimboText, { size: "xs", tone: "grey", children: config.hint }) })), _jsxs("div", { style: {
54
+ }, children: [_jsx(JimboSprite, { name: item.name, sheet: config.sheet, width: 48 }), _jsx(JimboText, { size: "micro", tone: "white", style: { lineHeight: 1.1, whiteSpace: "normal", textAlign: "center" }, children: item.name })] }, item.name));
55
+ return (_jsxs("div", { style: { padding: 0, maxWidth: 420, maxHeight: "80vh", display: "flex", flexDirection: "column" }, children: [_jsxs("div", { className: "j-flex j-gap-sm", style: { padding: "8px 10px 4px" }, children: [_jsx("input", { className: "j-seed-input__field", type: "text", placeholder: `Search ${config.title.toLowerCase()}...`, value: search, onChange: (e) => setSearch(e.target.value), style: { fontSize: 13, padding: "6px 10px", textTransform: "none", letterSpacing: "0.04em" } }), _jsx(JimboButton, { tone: "red", size: "sm", onClick: handleAny, children: "Any" })] }), config.hint && (_jsx("div", { className: "j-inner-panel", style: { margin: "4px 10px 6px", padding: "6px 10px" }, children: _jsx(JimboText, { size: "xs", tone: "grey", children: config.hint }) })), _jsxs("div", { className: "hide-scrollbar", style: {
56
56
  display: "flex",
57
57
  flexWrap: "wrap",
58
58
  gap: 6,
@@ -86,7 +86,7 @@ export const VOUCHER_PICKER_CONFIG = {
86
86
  clauseKey: "voucher",
87
87
  sheet: "Vouchers",
88
88
  items: VOUCHERS,
89
- accent: C.GOLD,
89
+ accent: C.ORANGE,
90
90
  };
91
91
  export const TAG_PICKER_CONFIG = {
92
92
  title: "Tags",
@@ -12,7 +12,7 @@ import { JimboSprite } from "../../ui/sprites.js";
12
12
  const C = JimboColorOption;
13
13
  const CATEGORIES = [
14
14
  { key: "joker", label: "Joker", sprite: "Joker", sheet: "Jokers", tone: "blue", hint: "Shop, Buffoon Pack" },
15
- { key: "voucher", label: "Voucher", sprite: "Blank", sheet: "Vouchers", tone: "gold", hint: "1 per Ante in shop" },
15
+ { key: "voucher", label: "Voucher", sprite: "Blank", sheet: "Vouchers", tone: "orange", hint: "1 per Ante in shop" },
16
16
  { key: "tarot", label: "Tarot Card", sprite: "The Fool", sheet: "Tarots", tone: "tarot", hint: "Arcana Pack, shop" },
17
17
  { key: "planet", label: "Planet Card", sprite: "Mercury", sheet: "Tarots", tone: "planet", hint: "Celestial Pack, shop" },
18
18
  { key: "spectral", label: "Spectral Card", sprite: "Grim", sheet: "Tarots", tone: "spectral", hint: "Ghost Deck, Spectral Pack" },
@@ -100,7 +100,7 @@ export function JamlMapEditor({ zone: initialZone = "must", onChange, }) {
100
100
  const sel = (antesState[anteIndex] || {})[id];
101
101
  return (_jsx(MysterySlot, { zone: sel ? sel.zone : currentZone, sheetType: sheetType, selection: sel, width: width, onTap: () => handleSlotTap(anteIndex, id, forceCategory), onClear: sel ? () => handleSlotClear(anteIndex, id) : undefined, style: { flexShrink: 0 } }, id));
102
102
  };
103
- return (_jsxs("div", { style: { width: "100%", height: "100%", display: "flex", flexDirection: "column" }, children: [_jsx("style", { children: `.hide-scrollbar { scrollbar-width: none; ms-overflow-style: none; } .hide-scrollbar::-webkit-scrollbar { display: none; }` }), _jsx("div", { style: { position: "sticky", top: 0, zIndex: 10, background: C.DARKEST, padding: "max(8px, env(safe-area-inset-top, 8px)) 0 8px 0", borderBottom: `2px solid ${C.PANEL_EDGE}` }, children: _jsx("div", { className: "j-flex j-gap-sm", style: { justifyContent: "center" }, children: ["must", "should", "mustnot"].map((z) => (_jsx(JimboButton, { tone: currentZone === z ? ZONE_TONE[z] : "grey", size: "sm", onClick: () => setCurrentZone(z), children: ZONE_LABEL[z] }, z))) }) }), _jsx("div", { className: "hide-scrollbar", style: {
103
+ return (_jsxs("div", { style: { width: "100%", height: "100%", display: "flex", flexDirection: "column" }, children: [_jsxs("div", { style: { position: "sticky", top: 0, zIndex: 10, background: C.DARKEST, padding: "max(32px, env(safe-area-inset-top, 32px)) 0 8px 0", borderBottom: `2px solid ${C.PANEL_EDGE}` }, children: [_jsx(JimboText, { size: "md", tone: "white", dance: true, style: { textAlign: "center", marginBottom: 12 }, children: "JAML VISUAL BUILDER" }), _jsx("div", { className: "j-flex j-gap-sm", style: { justifyContent: "center" }, children: ["must", "should", "mustnot"].map((z) => (_jsx(JimboButton, { tone: currentZone === z ? ZONE_TONE[z] : "blue", size: "sm", onClick: () => setCurrentZone(z), style: { opacity: currentZone === z ? 1 : 0.4 }, children: ZONE_LABEL[z] }, z))) })] }), _jsx("div", { className: "hide-scrollbar", style: {
104
104
  flex: 1,
105
105
  overflowY: "auto",
106
106
  scrollSnapType: "y mandatory",
@@ -117,14 +117,14 @@ export function JamlMapEditor({ zone: initialZone = "must", onChange, }) {
117
117
  }
118
118
  // ─── Category Selection Menu ─────────────────────────────────────────────────
119
119
  function CategoryMenu({ onSelect, }) {
120
- return (_jsx("div", { style: {
121
- display: "grid",
122
- gridTemplateColumns: "1fr 1fr",
123
- gap: 6,
124
- padding: 10,
120
+ return (_jsx("div", { className: "hide-scrollbar", style: {
121
+ display: "flex",
122
+ flexDirection: "column",
123
+ gap: 12,
124
+ padding: "10px 4px",
125
125
  maxHeight: "70vh",
126
126
  overflowY: "auto",
127
- }, children: CATEGORIES.map((cat) => (_jsx(JimboButton, { tone: cat.tone, size: "sm", fullWidth: true, onClick: () => onSelect(cat.key), style: { padding: "8px 6px" }, children: _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, width: "100%", textAlign: "left" }, children: [_jsx(JimboSprite, { name: cat.sprite, sheet: cat.sheet, width: 24 }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 1 }, children: [_jsx("span", { style: { fontSize: 11 }, children: cat.label }), _jsx("span", { style: { fontSize: 8, opacity: 0.7, letterSpacing: "0.04em", lineHeight: 1 }, children: cat.hint })] })] }) }, cat.key))) }));
127
+ }, children: CATEGORIES.map((cat) => (_jsx(JimboButton, { tone: cat.tone, size: "sm", fullWidth: true, onClick: () => onSelect(cat.key), children: _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, width: "100%", textAlign: "left" }, children: [_jsx(JimboSprite, { name: cat.sprite, sheet: cat.sheet, width: 24 }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 1 }, children: [_jsx("span", { style: { fontSize: 11 }, children: cat.label }), _jsx("span", { style: { fontSize: 8, opacity: 0.7, letterSpacing: "0.04em", lineHeight: 1, whiteSpace: "normal" }, children: cat.hint })] })] }) }, cat.key))) }));
128
128
  }
129
129
  // ─── Build JSON tree from slots ──────────────────────────────────────────────
130
130
  function buildJsonTree(antes) {
@@ -62,63 +62,67 @@ export function MysterySlot({ zone, sheetType, selection, width = 56, onTap, onC
62
62
  setPressed(false);
63
63
  setTilt({ rx: 0, ry: 0, tx: 0, ty: 0 });
64
64
  };
65
- return (_jsxs("div", { ref: cardRef, onClick: onTap, onMouseEnter: () => setHover(true), onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, onMouseDown: () => setPressed(true), onMouseUp: () => setPressed(false), style: {
65
+ return (_jsx("div", { ref: cardRef, onClick: onTap, onMouseEnter: () => setHover(true), onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, onMouseDown: () => setPressed(true), onMouseUp: () => setPressed(false), style: {
66
66
  position: "relative",
67
67
  width: width + 8,
68
68
  height: cardH + 8,
69
- display: "flex",
70
- alignItems: "center",
71
- justifyContent: "center",
72
69
  cursor: onTap ? "pointer" : "default",
73
- borderRadius: 6,
74
- border: isEmpty
75
- ? `2px dashed ${withAlpha(borderColor, 0.4)}`
76
- : `3px solid ${borderColor}`,
77
- background: isEmpty
78
- ? withAlpha(borderColor, 0.06)
79
- : withAlpha(C.DARKEST, 0.8),
80
- transform: `perspective(600px) scale(${scale}) rotateX(${tilt.rx}deg) rotateY(${tilt.ry}deg) translate(${tilt.tx}px, ${tilt.ty}px)`,
81
- transformStyle: "preserve-3d",
82
- transition: hover
83
- ? `border-color 200ms`
84
- : `transform 400ms ${JIMBO_ANIMATIONS.JUICE_EASING}, border-color 200ms`,
85
- boxShadow: hover ? `0 8px 16px ${withAlpha(C.BLACK, 0.4)}` : `0 2px 4px ${withAlpha(C.BLACK, 0.2)}`,
86
- zIndex: hover ? 10 : 1,
87
70
  ...style,
88
- }, children: [_jsx(JimboSprite, { name: spriteName, sheet: spriteSheet, width: width, style: {
89
- opacity: isEmpty ? 0.5 : 1,
90
- filter: isEmpty ? "saturate(0.3)" : "none",
91
- transition: "opacity 200ms, filter 200ms",
92
- } }), selection && onClear && (_jsx("div", { onClick: (e) => { e.stopPropagation(); onClear(); }, style: {
93
- position: "absolute",
94
- top: -6,
95
- right: -6,
96
- width: 18,
97
- height: 18,
98
- borderRadius: "50%",
99
- background: C.RED,
100
- color: C.WHITE,
101
- display: "flex",
102
- alignItems: "center",
103
- justifyContent: "center",
104
- fontSize: 11,
105
- fontFamily: "m6x11plus, ui-monospace, monospace",
106
- cursor: "pointer",
107
- lineHeight: 1,
108
- boxShadow: `0 1px 4px ${withAlpha(C.BLACK, 0.5)}`,
109
- transform: "translateZ(10px)", // Pop out in 3D
110
- }, children: "\u00D7" })), isEmpty && hover && (_jsx("div", { style: {
111
- position: "absolute",
112
- bottom: -16,
113
- left: "50%",
114
- transform: "translateX(-50%) translateZ(10px)",
115
- fontFamily: "m6x11plus, ui-monospace, monospace",
116
- fontSize: 10,
117
- color: borderColor,
118
- whiteSpace: "nowrap",
119
- textTransform: "uppercase",
120
- letterSpacing: 1,
121
- }, children: "+ tap" }))] }));
71
+ }, children: _jsxs("div", { style: {
72
+ position: "absolute",
73
+ inset: 0,
74
+ display: "flex",
75
+ alignItems: "center",
76
+ justifyContent: "center",
77
+ borderRadius: 6,
78
+ border: isEmpty
79
+ ? `2px dashed ${withAlpha(borderColor, 0.4)}`
80
+ : `3px solid ${borderColor}`,
81
+ background: isEmpty
82
+ ? withAlpha(borderColor, 0.06)
83
+ : withAlpha(C.DARKEST, 0.8),
84
+ transform: `perspective(600px) scale(${scale}) rotateX(${tilt.rx}deg) rotateY(${tilt.ry}deg) translate(${tilt.tx}px, ${tilt.ty}px)`,
85
+ transformStyle: "preserve-3d",
86
+ transition: hover
87
+ ? `border-color 200ms`
88
+ : `transform 400ms ${JIMBO_ANIMATIONS.JUICE_EASING}, border-color 200ms`,
89
+ boxShadow: hover ? `0 8px 16px ${withAlpha(C.BLACK, 0.4)}` : `0 2px 4px ${withAlpha(C.BLACK, 0.2)}`,
90
+ zIndex: hover ? 10 : 1,
91
+ pointerEvents: "none",
92
+ }, children: [_jsx(JimboSprite, { name: spriteName, sheet: spriteSheet, width: width, style: {
93
+ opacity: isEmpty ? 0.5 : 1,
94
+ filter: isEmpty ? "saturate(0.3)" : "none",
95
+ transition: "opacity 200ms, filter 200ms",
96
+ } }), selection && onClear && (_jsx("div", { onClick: (e) => { e.stopPropagation(); onClear(); }, style: {
97
+ position: "absolute",
98
+ top: -6,
99
+ right: -6,
100
+ width: 18,
101
+ height: 18,
102
+ borderRadius: "50%",
103
+ background: C.RED,
104
+ color: C.WHITE,
105
+ display: "flex",
106
+ alignItems: "center",
107
+ justifyContent: "center",
108
+ fontSize: 11,
109
+ fontFamily: "m6x11plus, ui-monospace, monospace",
110
+ cursor: "pointer",
111
+ lineHeight: 1,
112
+ boxShadow: `0 1px 4px ${withAlpha(C.BLACK, 0.5)}`,
113
+ transform: "translateZ(10px)", // Pop out in 3D
114
+ }, children: "\u00D7" })), isEmpty && hover && (_jsx("div", { style: {
115
+ position: "absolute",
116
+ bottom: -16,
117
+ left: "50%",
118
+ transform: "translateX(-50%) translateZ(10px)",
119
+ fontFamily: "m6x11plus, ui-monospace, monospace",
120
+ fontSize: 10,
121
+ color: borderColor,
122
+ whiteSpace: "nowrap",
123
+ textTransform: "uppercase",
124
+ letterSpacing: 1,
125
+ }, children: "+ tap" }))] }) }));
122
126
  }
123
127
  // ─── Helpers ─────────────────────────────────────────────────────────────────
124
128
  function categoryToSheet(cat) {
@@ -66,5 +66,5 @@ export const Card3D = memo(function Card3D({ sprite, position = [0, 0, 0], rotat
66
66
  const reset = () => { target.current = { rx: 0, ry: 0, rz: 0, ox: 0, oy: 0 }; };
67
67
  if (!texture)
68
68
  return null;
69
- return (_jsx(animated.group, { "position-x": position[0], "position-y": posY.to((y) => position[1] + y), "position-z": position[2], "rotation-x": rotation[0], "rotation-y": rotation[1], "rotation-z": rotation[2], scale: scale, children: _jsxs("group", { ref: tiltRef, children: [highlighted && (_jsx("pointLight", { color: glowColor, intensity: 1.5, distance: 1, position: [0, 0, 0.1] })), _jsxs("mesh", { onClick: (e) => { e.stopPropagation(); onClick?.(); }, onPointerMove: onMove, onPointerEnter: (e) => { e.stopPropagation(); setHovered(true); onPointerEnter?.(); document.body.style.cursor = 'pointer'; }, onPointerLeave: (e) => { e.stopPropagation(); setHovered(false); reset(); onPointerLeave?.(); document.body.style.cursor = 'auto'; }, castShadow: true, receiveShadow: true, children: [_jsx("boxGeometry", { args: [CARD_DIMENSIONS.WIDTH, CARD_DIMENSIONS.HEIGHT, CARD_DIMENSIONS.DEPTH] }), _jsx("meshBasicMaterial", { attach: "material-4", map: texture, toneMapped: false }), _jsx("meshStandardMaterial", { attach: "material-5", color: "#1a1a2e", metalness: 0.2, roughness: 0.8 }), _jsx("meshStandardMaterial", { attach: "material-0", color: "#f5f5dc" }), _jsx("meshStandardMaterial", { attach: "material-1", color: "#f5f5dc" }), _jsx("meshStandardMaterial", { attach: "material-2", color: "#f5f5dc" }), _jsx("meshStandardMaterial", { attach: "material-3", color: "#f5f5dc" })] }), selected && (_jsxs("mesh", { position: [0, 0, -CARD_DIMENSIONS.DEPTH], children: [_jsx("ringGeometry", { args: [0.45, 0.5, 32] }), _jsx("meshBasicMaterial", { color: "#e4b643", transparent: true, opacity: 0.8 })] }))] }) }));
69
+ return (_jsxs(animated.group, { "position-x": position[0], "position-y": posY.to((y) => position[1] + y), "position-z": position[2], "rotation-x": rotation[0], "rotation-y": rotation[1], "rotation-z": rotation[2], scale: scale, children: [_jsxs("mesh", { visible: false, onClick: (e) => { e.stopPropagation(); onClick?.(); }, onPointerMove: onMove, onPointerEnter: (e) => { e.stopPropagation(); setHovered(true); onPointerEnter?.(); document.body.style.cursor = 'pointer'; }, onPointerLeave: (e) => { e.stopPropagation(); setHovered(false); reset(); onPointerLeave?.(); document.body.style.cursor = 'auto'; }, children: [_jsx("boxGeometry", { args: [CARD_DIMENSIONS.WIDTH, CARD_DIMENSIONS.HEIGHT, CARD_DIMENSIONS.DEPTH * 2] }), _jsx("meshBasicMaterial", {})] }), _jsxs("group", { ref: tiltRef, children: [highlighted && (_jsx("pointLight", { color: glowColor, intensity: 1.5, distance: 1, position: [0, 0, 0.1] })), _jsxs("mesh", { castShadow: true, receiveShadow: true, children: [_jsx("boxGeometry", { args: [CARD_DIMENSIONS.WIDTH, CARD_DIMENSIONS.HEIGHT, CARD_DIMENSIONS.DEPTH] }), _jsx("meshBasicMaterial", { attach: "material-4", map: texture, toneMapped: false }), _jsx("meshStandardMaterial", { attach: "material-5", color: "#1a1a2e", metalness: 0.2, roughness: 0.8 }), _jsx("meshStandardMaterial", { attach: "material-0", color: "#f5f5dc" }), _jsx("meshStandardMaterial", { attach: "material-1", color: "#f5f5dc" }), _jsx("meshStandardMaterial", { attach: "material-2", color: "#f5f5dc" }), _jsx("meshStandardMaterial", { attach: "material-3", color: "#f5f5dc" })] }), selected && (_jsxs("mesh", { position: [0, 0, -CARD_DIMENSIONS.DEPTH], children: [_jsx("ringGeometry", { args: [0.45, 0.5, 32] }), _jsx("meshBasicMaterial", { color: "#e4b643", transparent: true, opacity: 0.8 })] }))] })] }));
70
70
  });
package/dist/ui/hooks.js CHANGED
@@ -405,18 +405,18 @@ export function useJamlCardRenderer({ layers, invert = false, hoverTilt = false,
405
405
  aspectRatio: String(ratio),
406
406
  width: '100%',
407
407
  display: 'flex',
408
- transition: hoverTilt && !isHovered ? 'transform 0.4s ease' : undefined,
409
- transform: hoverTilt ? (isHovered ? transform : 'none') : undefined,
410
- transformStyle: hoverTilt ? 'preserve-3d' : undefined,
411
- transformOrigin: hoverTilt ? 'center center' : undefined,
408
+ perspective: hoverTilt ? '1000px' : undefined,
412
409
  userSelect: 'none',
413
410
  WebkitUserSelect: 'none',
414
411
  };
415
412
  const canvasStyle = {
413
+ transition: hoverTilt && !isHovered ? 'transform 0.4s ease, box-shadow 0.4s ease-out' : 'transform 0.1s ease-out',
414
+ transform: hoverTilt ? (isHovered ? transform : 'none') : undefined,
415
+ transformStyle: hoverTilt ? 'preserve-3d' : undefined,
416
+ transformOrigin: hoverTilt ? 'center center' : undefined,
416
417
  borderRadius: '6px',
417
418
  boxShadow: hoverTilt && isHovered ? '0 2px 12px rgba(0,0,0,0.3)' : '0 2px 8px rgba(0,0,0,0.2)',
418
419
  imageRendering: 'pixelated',
419
- transition: hoverTilt && !isHovered ? 'box-shadow 0.4s ease-out' : undefined,
420
420
  pointerEvents: 'none',
421
421
  };
422
422
  return {
package/dist/ui/jimbo.css CHANGED
@@ -1066,3 +1066,21 @@
1066
1066
  display: inline-block;
1067
1067
  animation: j-font-dance 3s infinite ease-in-out;
1068
1068
  }
1069
+
1070
+ .hide-scrollbar {
1071
+ scrollbar-width: none;
1072
+ -ms-overflow-style: none;
1073
+ }
1074
+ .hide-scrollbar::-webkit-scrollbar {
1075
+ display: none;
1076
+ }
1077
+ .j-juice-hover { transition: transform 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275); } .j-juice-hover:hover { transform: scale(1.05) translateY(-2px); z-index: 5; }
1078
+ .hide-scrollbar
1079
+ -ms-overflow-style: none; scrollbar-width: none;
1080
+ .hide-scrollbar::-webkit-scrollbar
1081
+ display: none;
1082
+
1083
+ .hide-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
1084
+ .hide-scrollbar::-webkit-scrollbar { display: none; }
1085
+ .j-juice-hover { transition: transform 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275); }
1086
+ .j-juice-hover:hover { transform: scale(1.05) translateY(-2px); z-index: 5; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaml-ui",
3
- "version": "0.19.0",
3
+ "version": "0.20.1",
4
4
  "description": "Balatro rendering components, sprite metadata, and optional Motely helpers for React apps.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",