jaml-ui 0.24.6 → 0.24.7

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.
@@ -11,14 +11,13 @@ export function JamlIdeToolbar({ mode, onModeChange, resultCount = 0, className
11
11
  { id: "results", label: resultCount > 0 ? `Results (${resultCount})` : "Results" },
12
12
  ];
13
13
  return (_jsxs("div", { className: className, style: {
14
- display: "flex",
14
+ display: "grid",
15
+ gridTemplateColumns: onSearch ? "1fr auto 1fr" : "1fr",
15
16
  alignItems: "center",
16
- justifyContent: "space-between",
17
- flexWrap: "nowrap",
18
17
  gap: 8,
19
18
  minWidth: 0,
20
19
  padding: "10px 10px 6px",
21
20
  borderBottom: `1px solid ${JimboColorOption.PANEL_EDGE}`,
22
21
  background: JimboColorOption.DARKEST,
23
- }, children: [_jsx("div", { style: { flex: "1 1 auto", minWidth: 0, overflow: "hidden" }, children: _jsx(JimboTabs, { tabs: tabs, activeTab: mode, onTabChange: (id) => onModeChange(id) }) }), onSearch ? (_jsx("div", { style: { flexShrink: 0 }, children: _jsx(JimboButton, { tone: isSearching ? "red" : "blue", size: "xs", onClick: onSearch, children: isSearching ? "Stop" : "Search" }) })) : null] }));
22
+ }, children: [onSearch ? _jsx("div", {}) : null, _jsx("div", { style: { minWidth: 0, overflow: "hidden", width: "100%" }, children: _jsx(JimboTabs, { tabs: tabs, activeTab: mode, onTabChange: (id) => onModeChange(id) }) }), onSearch ? (_jsx("div", { style: { justifySelf: "end" }, children: _jsx(JimboButton, { tone: isSearching ? "red" : "blue", size: "xs", onClick: onSearch, children: isSearching ? "Stop" : "Search" }) })) : null] }));
24
23
  }
@@ -78,7 +78,7 @@ function ClauseCard({ clause, zone, onRemove, onEdit, onDragStart, }) {
78
78
  borderRadius: 3,
79
79
  letterSpacing: 0.5,
80
80
  lineHeight: 1,
81
- }, children: ["+", clause.score] }))] })] }), _jsx("button", { onClick: (e) => {
81
+ }, children: ["+", clause.score] }))] })] }), _jsx("button", { onMouseDown: (e) => e.stopPropagation(), onTouchStart: (e) => e.stopPropagation(), onClick: (e) => {
82
82
  e.stopPropagation();
83
83
  onRemove();
84
84
  }, "aria-label": `Remove ${clause.label || clause.value}`, style: {
@@ -134,9 +134,8 @@ function ZoneRail({ zone, clauses, onAdd, onRemove, onEdit, onDragStart, highlig
134
134
  return (_jsxs("div", { "data-zone": zone, style: {
135
135
  border: `2px dashed ${highlight ? z.color : "transparent"}`,
136
136
  borderRadius: 6,
137
- padding: highlight ? 6 : 0,
137
+ padding: 6,
138
138
  background: highlight ? `${z.color}11` : "transparent",
139
- transition: "background 100ms, border-color 100ms",
140
139
  }, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, marginBottom: 6 }, children: [_jsx("div", { style: {
141
140
  fontFamily: "m6x11plus, ui-monospace, monospace",
142
141
  fontSize: 12,
@@ -203,7 +202,6 @@ export function JamlIdeVisual({ filter, onChange, onEditClause, onAddClause }) {
203
202
  top: drag.y - drag.offY,
204
203
  pointerEvents: "none",
205
204
  zIndex: 999,
206
- transform: "rotate(-2deg) scale(1.05)",
207
205
  filter: `drop-shadow(0 4px 6px ${C.BLACK}99)`,
208
206
  opacity: 0.92,
209
207
  }, children: _jsx(ClauseCard, { clause: drag.clause, zone: drag.fromZone, onRemove: () => { }, onEdit: () => { }, onDragStart: () => { } }) }))] }));
package/dist/ui/hooks.js CHANGED
@@ -492,11 +492,12 @@ export function useAnteTracker(antes, options = {}) {
492
492
  */
493
493
  export function useJamlIdeDrag(filter, onChange, rootRef) {
494
494
  const [drag, setDrag] = useState(null);
495
+ const [pendingDrag, setPendingDrag] = useState(null);
495
496
  const [hoverZone, setHoverZone] = useState(null);
496
497
  const onDragStart = useCallback((e, clause, fromZone) => {
497
498
  const t = 'touches' in e ? e.touches[0] : e;
498
499
  const rect = e.currentTarget.getBoundingClientRect();
499
- setDrag({
500
+ setPendingDrag({
500
501
  clause,
501
502
  fromZone,
502
503
  x: t.clientX,
@@ -504,13 +505,38 @@ export function useJamlIdeDrag(filter, onChange, rootRef) {
504
505
  offX: t.clientX - rect.left,
505
506
  offY: t.clientY - rect.top,
506
507
  });
508
+ setHoverZone(null);
507
509
  }, []);
508
510
  useEffect(() => {
509
- if (!drag)
511
+ if (!pendingDrag && !drag)
510
512
  return;
511
513
  const move = (e) => {
512
- const t = 'touches' in e ? e.touches[0] : e;
513
- setDrag((d) => d && { ...d, x: t.clientX, y: t.clientY });
514
+ const touchEvent = 'touches' in e ? e : null;
515
+ const t = touchEvent ? touchEvent.touches[0] : e;
516
+ if (!t)
517
+ return;
518
+ let activeDrag = drag;
519
+ if (!activeDrag && pendingDrag) {
520
+ const dx = t.clientX - pendingDrag.x;
521
+ const dy = t.clientY - pendingDrag.y;
522
+ if (Math.hypot(dx, dy) < 8)
523
+ return;
524
+ activeDrag = {
525
+ ...pendingDrag,
526
+ x: t.clientX,
527
+ y: t.clientY,
528
+ };
529
+ setPendingDrag(null);
530
+ setDrag(activeDrag);
531
+ }
532
+ else if (activeDrag) {
533
+ activeDrag = { ...activeDrag, x: t.clientX, y: t.clientY };
534
+ setDrag(activeDrag);
535
+ }
536
+ if (!activeDrag)
537
+ return;
538
+ if (touchEvent?.cancelable)
539
+ touchEvent.preventDefault();
514
540
  const rails = rootRef.current?.querySelectorAll('[data-zone]') ?? [];
515
541
  let found = null;
516
542
  for (const r of rails) {
@@ -523,7 +549,7 @@ export function useJamlIdeDrag(filter, onChange, rootRef) {
523
549
  setHoverZone(found);
524
550
  };
525
551
  const up = () => {
526
- if (hoverZone && hoverZone !== drag.fromZone) {
552
+ if (drag && hoverZone && hoverZone !== drag.fromZone) {
527
553
  const to = hoverZone;
528
554
  onChange({
529
555
  ...filter,
@@ -531,6 +557,7 @@ export function useJamlIdeDrag(filter, onChange, rootRef) {
531
557
  [to]: [...filter[to], { ...drag.clause }],
532
558
  });
533
559
  }
560
+ setPendingDrag(null);
534
561
  setDrag(null);
535
562
  setHoverZone(null);
536
563
  };
@@ -544,7 +571,7 @@ export function useJamlIdeDrag(filter, onChange, rootRef) {
544
571
  window.removeEventListener('touchmove', move);
545
572
  window.removeEventListener('touchend', up);
546
573
  };
547
- }, [drag, hoverZone, filter, onChange, rootRef]);
574
+ }, [pendingDrag, drag, hoverZone, filter, onChange, rootRef]);
548
575
  return {
549
576
  drag,
550
577
  hoverZone,
package/dist/ui/jimbo.css CHANGED
@@ -9,6 +9,7 @@
9
9
  scrollbar-width: none !important;
10
10
  -ms-overflow-style: none !important;
11
11
  }
12
+
12
13
  *::-webkit-scrollbar {
13
14
  display: none !important;
14
15
  }
@@ -86,7 +87,11 @@
86
87
  text-shadow: var(--j-text-shadow);
87
88
  color: var(--j-white);
88
89
  }
89
- .j-text--no-shadow { text-shadow: none; }
90
+
91
+ .j-text--no-shadow {
92
+ text-shadow: none;
93
+ }
94
+
90
95
  .j-text--upper {
91
96
  text-transform: uppercase;
92
97
  letter-spacing: 0.08em;
@@ -104,35 +109,113 @@
104
109
  }
105
110
 
106
111
  @keyframes j-font-dance {
107
- 0%, 100% { transform: translate(0, 0); }
108
- 25% { transform: translate(1px, -1px); }
109
- 50% { transform: translate(0, -2px); }
110
- 75% { transform: translate(-1px, -1px); }
112
+
113
+ 0%,
114
+ 100% {
115
+ transform: translate(0, 0);
116
+ }
117
+
118
+ 25% {
119
+ transform: translate(1px, -1px);
120
+ }
121
+
122
+ 50% {
123
+ transform: translate(0, -2px);
124
+ }
125
+
126
+ 75% {
127
+ transform: translate(-1px, -1px);
128
+ }
111
129
  }
112
130
 
113
131
  /* Sizes (from DESIGN.md typography scale) */
114
- .j-text--display { font-size: 26px; letter-spacing: 0.04em; line-height: 1; }
115
- .j-text--xl { font-size: 24px; letter-spacing: 0.04em; }
116
- .j-text--lg { font-size: 18px; letter-spacing: 0.04em; }
117
- .j-text--heading { font-size: 14px; letter-spacing: 0.08em; line-height: 1.2; }
118
- .j-text--md { font-size: 14px; }
119
- .j-text--sm { font-size: 12px; }
120
- .j-text--body { font-size: 11px; letter-spacing: 0.05em; line-height: 1.3; }
121
- .j-text--xs { font-size: 10px; }
122
- .j-text--label { font-size: 9px; letter-spacing: 0.1em; line-height: 1; text-transform: uppercase; }
123
- .j-text--micro { font-size: 8px; letter-spacing: 0.08em; line-height: 1; }
132
+ .j-text--display {
133
+ font-size: 26px;
134
+ letter-spacing: 0.04em;
135
+ line-height: 1;
136
+ }
137
+
138
+ .j-text--xl {
139
+ font-size: 24px;
140
+ letter-spacing: 0.04em;
141
+ }
142
+
143
+ .j-text--lg {
144
+ font-size: 18px;
145
+ letter-spacing: 0.04em;
146
+ }
147
+
148
+ .j-text--heading {
149
+ font-size: 14px;
150
+ letter-spacing: 0.08em;
151
+ line-height: 1.2;
152
+ }
153
+
154
+ .j-text--md {
155
+ font-size: 14px;
156
+ }
157
+
158
+ .j-text--sm {
159
+ font-size: 12px;
160
+ }
161
+
162
+ .j-text--body {
163
+ font-size: 11px;
164
+ letter-spacing: 0.05em;
165
+ line-height: 1.3;
166
+ }
167
+
168
+ .j-text--xs {
169
+ font-size: 10px;
170
+ }
171
+
172
+ .j-text--label {
173
+ font-size: 9px;
174
+ letter-spacing: 0.1em;
175
+ line-height: 1;
176
+ text-transform: uppercase;
177
+ }
178
+
179
+ .j-text--micro {
180
+ font-size: 8px;
181
+ letter-spacing: 0.08em;
182
+ line-height: 1;
183
+ }
124
184
 
125
185
  /* Tones */
126
- .j-text--default { color: var(--j-white); }
186
+ .j-text--default {
187
+ color: var(--j-white);
188
+ }
189
+
127
190
  .j-text--mult,
128
- .j-text--red { color: var(--j-red); }
191
+ .j-text--red {
192
+ color: var(--j-red);
193
+ }
194
+
129
195
  .j-text--chips,
130
- .j-text--blue { color: var(--j-blue); }
131
- .j-text--gold { color: var(--j-gold-text); }
132
- .j-text--green { color: var(--j-green-text); }
133
- .j-text--orange { color: var(--j-orange-text); }
134
- .j-text--purple { color: var(--j-purple); }
135
- .j-text--grey { color: var(--j-grey); }
196
+ .j-text--blue {
197
+ color: var(--j-blue);
198
+ }
199
+
200
+ .j-text--gold {
201
+ color: var(--j-gold-text);
202
+ }
203
+
204
+ .j-text--green {
205
+ color: var(--j-green-text);
206
+ }
207
+
208
+ .j-text--orange {
209
+ color: var(--j-orange-text);
210
+ }
211
+
212
+ .j-text--purple {
213
+ color: var(--j-purple);
214
+ }
215
+
216
+ .j-text--grey {
217
+ color: var(--j-grey);
218
+ }
136
219
 
137
220
 
138
221
  /* ── Panel ─────────────────────────────────────────────────────────────── */
@@ -143,7 +226,7 @@
143
226
  border-bottom-color: var(--j-border-south);
144
227
  border-radius: var(--j-radius-md);
145
228
  box-shadow: 0 3px 0 0 rgba(0, 0, 0, 0.55),
146
- inset 0 0 0 1px rgba(255, 255, 255, 0.04);
229
+ inset 0 0 0 1px rgba(255, 255, 255, 0.04);
147
230
  padding: var(--j-space-lg);
148
231
  display: flex;
149
232
  flex-direction: column;
@@ -163,6 +246,11 @@
163
246
  flex-shrink: 0;
164
247
  }
165
248
 
249
+ .j-back-btn .j-btn__face {
250
+ padding-top: 8px;
251
+ padding-bottom: 8px;
252
+ }
253
+
166
254
  .j-inner-panel {
167
255
  background-color: var(--j-inner-border);
168
256
  border: 2px solid var(--j-panel-edge);
@@ -176,12 +264,18 @@
176
264
  press sinks the face +3px and collapses the shadow. */
177
265
 
178
266
  .j-btn {
267
+ appearance: none;
268
+ -webkit-appearance: none;
179
269
  display: inline-block;
180
270
  position: relative;
181
271
  cursor: pointer;
272
+ border: none;
273
+ padding: 0;
274
+ background: transparent;
182
275
  -webkit-user-select: none;
183
276
  user-select: none;
184
277
  }
278
+
185
279
  /* Invisible stable hit target to prevent hover jitter when the child transforms */
186
280
  .j-btn::after {
187
281
  content: '';
@@ -190,7 +284,11 @@
190
284
  background: transparent;
191
285
  z-index: 10;
192
286
  }
193
- .j-btn--full { width: 100%; }
287
+
288
+ .j-btn--full {
289
+ width: 100%;
290
+ }
291
+
194
292
  .j-btn--disabled {
195
293
  opacity: 0.55;
196
294
  cursor: not-allowed;
@@ -206,29 +304,66 @@
206
304
  transform: translate(0, 0);
207
305
  transition: transform var(--j-press-speed) linear, box-shadow var(--j-press-speed) linear;
208
306
  }
307
+
209
308
  .j-btn[data-pressed="true"] .j-btn__face,
210
309
  .j-btn:active:not(:disabled):not(.j-btn--disabled) .j-btn__face {
211
310
  transform: translateY(var(--j-press-y));
212
311
  box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.6);
213
312
  }
313
+
214
314
  .j-btn:not(.j-btn--disabled):hover .j-btn__face {
215
315
  filter: brightness(1.1);
216
316
  }
217
317
 
218
318
  /* Sizes */
219
- .j-btn--xs .j-btn__face { padding: 4px 8px; font-size: 11px; }
220
- .j-btn--sm .j-btn__face { padding: 6px 12px; font-size: 13px; }
221
- .j-btn--md .j-btn__face { padding: 10px 18px; font-size: 16px; }
222
- .j-btn--lg .j-btn__face { padding: 8px 18px; font-size: 20px; }
319
+ .j-btn--xs .j-btn__face {
320
+ padding: 4px 8px;
321
+ font-size: 11px;
322
+ }
323
+
324
+ .j-btn--sm .j-btn__face {
325
+ padding: 6px 12px;
326
+ font-size: 13px;
327
+ }
328
+
329
+ .j-btn--md .j-btn__face {
330
+ padding: 10px 18px;
331
+ font-size: 16px;
332
+ }
333
+
334
+ .j-btn--lg .j-btn__face {
335
+ padding: 8px 18px;
336
+ font-size: 20px;
337
+ }
223
338
 
224
339
  /* Tone colors — set via CSS custom properties */
225
- .j-btn--orange { --j-btn-face-color: var(--j-orange); }
226
- .j-btn--red { --j-btn-face-color: var(--j-red); }
227
- .j-btn--blue { --j-btn-face-color: var(--j-blue); }
228
- .j-btn--green { --j-btn-face-color: var(--j-green); }
229
- .j-btn--tarot { --j-btn-face-color: var(--j-tarot-btn); }
230
- .j-btn--planet { --j-btn-face-color: var(--j-planet-btn); }
231
- .j-btn--spectral { --j-btn-face-color: var(--j-spectral-btn); }
340
+ .j-btn--orange {
341
+ --j-btn-face-color: var(--j-orange);
342
+ }
343
+
344
+ .j-btn--red {
345
+ --j-btn-face-color: var(--j-red);
346
+ }
347
+
348
+ .j-btn--blue {
349
+ --j-btn-face-color: var(--j-blue);
350
+ }
351
+
352
+ .j-btn--green {
353
+ --j-btn-face-color: var(--j-green);
354
+ }
355
+
356
+ .j-btn--tarot {
357
+ --j-btn-face-color: var(--j-tarot-btn);
358
+ }
359
+
360
+ .j-btn--planet {
361
+ --j-btn-face-color: var(--j-planet-btn);
362
+ }
363
+
364
+ .j-btn--spectral {
365
+ --j-btn-face-color: var(--j-spectral-btn);
366
+ }
232
367
 
233
368
 
234
369
  /* ── Badge ─────────────────────────────────────────────────────────────── */
@@ -244,25 +379,58 @@
244
379
  text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.8);
245
380
  border: none;
246
381
  }
247
- .j-badge--sm { padding: 2px 6px; font-size: 10px; }
248
- .j-badge--md { padding: 4px 8px; font-size: 12px; }
382
+
383
+ .j-badge--sm {
384
+ padding: 2px 6px;
385
+ font-size: 10px;
386
+ }
387
+
388
+ .j-badge--md {
389
+ padding: 4px 8px;
390
+ font-size: 12px;
391
+ }
249
392
 
250
393
  /* Badge tones — flat, no shadow, no edges */
251
- .j-badge--dark { background: var(--j-darkest); color: var(--j-white); }
252
- .j-badge--blue { background: var(--j-blue); color: var(--j-white); }
253
- .j-badge--red { background: var(--j-red); color: var(--j-white); }
254
- .j-badge--green { background: var(--j-green); color: var(--j-white); }
255
- .j-badge--orange { background: var(--j-orange); color: var(--j-white); }
256
- .j-badge--purple { background: var(--j-purple); color: var(--j-white); }
394
+ .j-badge--dark {
395
+ background: var(--j-darkest);
396
+ color: var(--j-white);
397
+ }
398
+
399
+ .j-badge--blue {
400
+ background: var(--j-blue);
401
+ color: var(--j-white);
402
+ }
403
+
404
+ .j-badge--red {
405
+ background: var(--j-red);
406
+ color: var(--j-white);
407
+ }
408
+
409
+ .j-badge--green {
410
+ background: var(--j-green);
411
+ color: var(--j-white);
412
+ }
413
+
414
+ .j-badge--orange {
415
+ background: var(--j-orange);
416
+ color: var(--j-white);
417
+ }
418
+
419
+ .j-badge--purple {
420
+ background: var(--j-purple);
421
+ color: var(--j-white);
422
+ }
257
423
 
258
424
 
259
425
  /* ── Tabs ──────────────────────────────────────────────────────────────── */
260
426
 
261
427
  .j-tabs {
262
428
  display: flex;
263
- gap: var(--j-space-md);
429
+ gap: var(--j-space-sm);
264
430
  align-items: flex-end;
431
+ justify-content: center;
265
432
  flex-wrap: wrap;
433
+ width: 100%;
266
434
  }
267
435
 
268
436
  .j-tab {
@@ -270,51 +438,74 @@
270
438
  flex-direction: column;
271
439
  align-items: center;
272
440
  position: relative;
441
+ flex: 0 0 auto;
273
442
  }
274
443
 
275
444
  .j-tab__indicator {
276
- margin-bottom: var(--j-space-sm);
445
+ height: 10px;
446
+ margin-bottom: 3px;
277
447
  display: flex;
278
448
  justify-content: center;
449
+ align-items: flex-end;
279
450
  }
451
+
280
452
  .j-tab__indicator svg {
281
- fill: var(--j-gold, #e4b643);
453
+ fill: var(--j-red);
282
454
  display: block;
283
455
  }
456
+
284
457
  .j-tab__indicator[data-active="true"] {
285
458
  animation: jimbo-bounce 0.8s cubic-bezier(0.68, 0, 0.68, 1) infinite;
286
459
  }
460
+
287
461
  .j-tab__indicator[data-active="false"] {
288
462
  visibility: hidden;
289
463
  }
290
464
 
291
465
  .j-tab__btn {
466
+ appearance: none;
467
+ -webkit-appearance: none;
292
468
  border: none;
293
469
  cursor: pointer;
294
- border-radius: var(--j-radius-sm);
295
- padding: 4px 12px;
296
- background-color: transparent;
297
- box-shadow: none;
298
- transition: none;
470
+ border-radius: var(--j-radius-md);
471
+ padding: 6px 14px;
472
+ min-height: 28px;
473
+ background: var(--j-red);
474
+ box-shadow: 0 3px 0 0 rgba(0, 0, 0, 0.6);
475
+ color: var(--j-white);
476
+ text-align: center;
477
+ text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.8);
478
+ transition: filter 80ms linear, opacity 80ms linear;
479
+ outline: none;
299
480
  }
481
+
300
482
  .j-tab__btn[data-active="true"] {
301
- background-color: var(--j-gold);
302
- box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.3);
483
+ opacity: 1;
303
484
  }
485
+
304
486
  .j-tab__btn[data-active="true"]:hover {
305
- background-color: var(--j-gold);
487
+ background: var(--j-red);
306
488
  }
489
+
307
490
  .j-tab__btn[data-active="false"]:hover {
308
- background-color: rgba(255, 255, 255, 0.06);
491
+ background: var(--j-red);
492
+ filter: brightness(1.08);
309
493
  }
310
- .j-tab__btn[data-pressed="true"] {
311
- transform: translateY(2px);
312
- box-shadow: none;
494
+
495
+ .j-tab__btn[data-active="false"] {
496
+ opacity: 0.82;
313
497
  }
314
498
 
315
499
  @keyframes jimbo-bounce {
316
- 0%, 100% { transform: translateY(0); }
317
- 50% { transform: translateY(-3px); }
500
+
501
+ 0%,
502
+ 100% {
503
+ transform: translateY(0);
504
+ }
505
+
506
+ 50% {
507
+ transform: translateY(-3px);
508
+ }
318
509
  }
319
510
 
320
511
  /* Vertical tabs */
@@ -335,6 +526,7 @@
335
526
  transform: rotate(180deg);
336
527
  transition: none;
337
528
  }
529
+
338
530
  .j-vtab[data-active="true"] {
339
531
  background-color: var(--j-gold, #e4b643);
340
532
  color: var(--j-black, #000000);
@@ -382,8 +574,14 @@
382
574
  border: 1px solid var(--j-dark-grey);
383
575
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5);
384
576
  }
385
- .j-toggle-check[data-on="true"] { background: var(--j-orange); }
386
- .j-toggle-check[data-on="false"] { background: var(--j-darkest); }
577
+
578
+ .j-toggle-check[data-on="true"] {
579
+ background: var(--j-orange);
580
+ }
581
+
582
+ .j-toggle-check[data-on="false"] {
583
+ background: var(--j-darkest);
584
+ }
387
585
 
388
586
 
389
587
  /* ── Tooltip ──────────────────────────────────────────────────────────── */
@@ -437,13 +635,15 @@
437
635
  justify-content: center;
438
636
  box-shadow: 0 var(--j-press-y) 0 0 var(--j-dark-red);
439
637
  transition: transform var(--j-press-speed) ease,
440
- box-shadow var(--j-press-speed) ease,
441
- background-color var(--j-press-speed) ease;
638
+ box-shadow var(--j-press-speed) ease,
639
+ background-color var(--j-press-speed) ease;
442
640
  }
641
+
443
642
  .j-flank__btn[data-pressed="true"] {
444
643
  transform: translateY(var(--j-press-y));
445
644
  box-shadow: none;
446
645
  }
646
+
447
647
  .j-flank__btn:disabled {
448
648
  background-color: var(--j-dark-red);
449
649
  cursor: default;
@@ -484,11 +684,13 @@
484
684
  flex-shrink: 0;
485
685
  transition: color 0.15s, background 0.15s, border-color 0.15s;
486
686
  }
687
+
487
688
  .j-copy-row__btn[data-copied="false"] {
488
689
  color: var(--j-gold-text);
489
690
  background: rgba(228, 182, 67, 0.12);
490
691
  border: 1px solid var(--j-gold-text);
491
692
  }
693
+
492
694
  .j-copy-row__btn[data-copied="true"] {
493
695
  color: var(--j-green-text);
494
696
  background: rgba(53, 189, 134, 0.12);
@@ -542,8 +744,14 @@
542
744
  cursor: pointer;
543
745
  display: flex;
544
746
  }
545
- .j-code-block__copy[data-copied="false"] { color: rgba(255, 255, 255, 0.5); }
546
- .j-code-block__copy[data-copied="true"] { color: #4ade80; }
747
+
748
+ .j-code-block__copy[data-copied="false"] {
749
+ color: rgba(255, 255, 255, 0.5);
750
+ }
751
+
752
+ .j-code-block__copy[data-copied="true"] {
753
+ color: #4ade80;
754
+ }
547
755
 
548
756
  .j-code-block__pre {
549
757
  padding: 12px;
@@ -721,6 +929,7 @@
721
929
  width: 100%;
722
930
  transition: opacity 200ms;
723
931
  }
932
+
724
933
  .j-footer--hidden {
725
934
  pointer-events: none;
726
935
  opacity: 0;
@@ -754,7 +963,10 @@
754
963
 
755
964
  /* ── Floating ─────────────────────────────────────────────────────────── */
756
965
 
757
- .j-floating { position: absolute; z-index: 20; }
966
+ .j-floating {
967
+ position: absolute;
968
+ z-index: 20;
969
+ }
758
970
 
759
971
 
760
972
  /* ── Background (canvas is styled inline because it's fixed fullscreen) ── */
@@ -766,55 +978,157 @@
766
978
  box-shadow: 0 0 0 2px var(--j-blue), 0 0 10px var(--j-blue);
767
979
  animation: j-glow-pulse 1.6s ease-in-out infinite;
768
980
  }
981
+
769
982
  .j-glow--should {
770
983
  box-shadow: 0 0 0 2px var(--j-gold), 0 0 10px var(--j-gold);
771
984
  animation: j-glow-pulse 1.6s ease-in-out infinite;
772
985
  }
773
986
 
774
987
  @keyframes j-glow-pulse {
775
- 0%, 100% { opacity: 0.55; }
776
- 50% { opacity: 1; }
988
+
989
+ 0%,
990
+ 100% {
991
+ opacity: 0.55;
992
+ }
993
+
994
+ 50% {
995
+ opacity: 1;
996
+ }
777
997
  }
778
998
 
779
999
 
780
1000
  /* ── Utility ──────────────────────────────────────────────────────────── */
781
1001
 
782
- .j-flex { display: flex; }
783
- .j-flex-col { display: flex; flex-direction: column; }
784
- .j-flex-wrap { flex-wrap: wrap; }
785
- .j-items-center { align-items: center; }
786
- .j-justify-center { justify-content: center; }
787
- .j-gap-xs { gap: var(--j-space-xs); }
788
- .j-gap-sm { gap: var(--j-space-sm); }
789
- .j-gap-md { gap: var(--j-space-md); }
790
- .j-gap-lg { gap: var(--j-space-lg); }
791
- .j-gap-xl { gap: var(--j-space-xl); }
792
- .j-w-full { width: 100%; }
793
- .j-shrink-0 { flex-shrink: 0; }
794
- .j-flex-1 { flex: 1; }
795
- .j-min-w-0 { min-width: 0; }
796
- .j-text-center { text-align: center; }
797
- .j-overflow-hidden { overflow: hidden; }
798
- .j-overflow-auto { overflow: auto; }
799
- .j-relative { position: relative; }
1002
+ .j-flex {
1003
+ display: flex;
1004
+ }
1005
+
1006
+ .j-flex-col {
1007
+ display: flex;
1008
+ flex-direction: column;
1009
+ }
1010
+
1011
+ .j-flex-wrap {
1012
+ flex-wrap: wrap;
1013
+ }
1014
+
1015
+ .j-items-center {
1016
+ align-items: center;
1017
+ }
1018
+
1019
+ .j-justify-center {
1020
+ justify-content: center;
1021
+ }
1022
+
1023
+ .j-gap-xs {
1024
+ gap: var(--j-space-xs);
1025
+ }
1026
+
1027
+ .j-gap-sm {
1028
+ gap: var(--j-space-sm);
1029
+ }
1030
+
1031
+ .j-gap-md {
1032
+ gap: var(--j-space-md);
1033
+ }
1034
+
1035
+ .j-gap-lg {
1036
+ gap: var(--j-space-lg);
1037
+ }
1038
+
1039
+ .j-gap-xl {
1040
+ gap: var(--j-space-xl);
1041
+ }
1042
+
1043
+ .j-w-full {
1044
+ width: 100%;
1045
+ }
1046
+
1047
+ .j-shrink-0 {
1048
+ flex-shrink: 0;
1049
+ }
1050
+
1051
+ .j-flex-1 {
1052
+ flex: 1;
1053
+ }
1054
+
1055
+ .j-min-w-0 {
1056
+ min-width: 0;
1057
+ }
1058
+
1059
+ .j-text-center {
1060
+ text-align: center;
1061
+ }
1062
+
1063
+ .j-overflow-hidden {
1064
+ overflow: hidden;
1065
+ }
1066
+
1067
+ .j-overflow-auto {
1068
+ overflow: auto;
1069
+ }
1070
+
1071
+ .j-relative {
1072
+ position: relative;
1073
+ }
800
1074
 
801
1075
  /* Tone border utilities */
802
- .j-border--red { border-color: var(--j-red); }
803
- .j-border--blue { border-color: var(--j-blue); }
804
- .j-border--green { border-color: var(--j-green); }
805
- .j-border--gold { border-color: var(--j-gold); }
806
- .j-border--orange { border-color: var(--j-orange); }
807
- .j-border--purple { border-color: var(--j-purple); }
1076
+ .j-border--red {
1077
+ border-color: var(--j-red);
1078
+ }
1079
+
1080
+ .j-border--blue {
1081
+ border-color: var(--j-blue);
1082
+ }
1083
+
1084
+ .j-border--green {
1085
+ border-color: var(--j-green);
1086
+ }
1087
+
1088
+ .j-border--gold {
1089
+ border-color: var(--j-gold);
1090
+ }
1091
+
1092
+ .j-border--orange {
1093
+ border-color: var(--j-orange);
1094
+ }
1095
+
1096
+ .j-border--purple {
1097
+ border-color: var(--j-purple);
1098
+ }
808
1099
 
809
1100
  /* Tone background utilities */
810
- .j-bg--red { background-color: var(--j-red); }
811
- .j-bg--blue { background-color: var(--j-blue); }
812
- .j-bg--green { background-color: var(--j-green); }
813
- .j-bg--gold { background-color: var(--j-gold); }
814
- .j-bg--orange { background-color: var(--j-orange); }
815
- .j-bg--purple { background-color: var(--j-purple); }
816
- .j-bg--dark-grey { background-color: var(--j-dark-grey); }
817
- .j-bg--darkest { background-color: var(--j-darkest); }
1101
+ .j-bg--red {
1102
+ background-color: var(--j-red);
1103
+ }
1104
+
1105
+ .j-bg--blue {
1106
+ background-color: var(--j-blue);
1107
+ }
1108
+
1109
+ .j-bg--green {
1110
+ background-color: var(--j-green);
1111
+ }
1112
+
1113
+ .j-bg--gold {
1114
+ background-color: var(--j-gold);
1115
+ }
1116
+
1117
+ .j-bg--orange {
1118
+ background-color: var(--j-orange);
1119
+ }
1120
+
1121
+ .j-bg--purple {
1122
+ background-color: var(--j-purple);
1123
+ }
1124
+
1125
+ .j-bg--dark-grey {
1126
+ background-color: var(--j-dark-grey);
1127
+ }
1128
+
1129
+ .j-bg--darkest {
1130
+ background-color: var(--j-darkest);
1131
+ }
818
1132
 
819
1133
  /* ── App Shell ────────────────────────────────────────────────────────── */
820
1134
  /* Mobile-first 375px layout container for ALL Jimbo UI screens.
@@ -870,7 +1184,10 @@
870
1184
  scrollbar-width: none;
871
1185
  -ms-overflow-style: none;
872
1186
  }
873
- .j-app__scroll::-webkit-scrollbar { display: none; }
1187
+
1188
+ .j-app__scroll::-webkit-scrollbar {
1189
+ display: none;
1190
+ }
874
1191
 
875
1192
  .j-app__footer {
876
1193
  flex-shrink: 0;
@@ -889,9 +1206,11 @@
889
1206
  .j-app__content {
890
1207
  padding: var(--j-space-xl) var(--j-space-xl) var(--j-space-lg);
891
1208
  }
1209
+
892
1210
  .j-app__scroll {
893
1211
  padding: var(--j-space-xl) var(--j-space-xl) var(--j-space-lg);
894
1212
  }
1213
+
895
1214
  .j-app__footer {
896
1215
  padding: var(--j-space-md) var(--j-space-xl) var(--j-space-lg);
897
1216
  }
@@ -901,12 +1220,15 @@
901
1220
  .j-stat-grid__value {
902
1221
  font-size: 20px;
903
1222
  }
1223
+
904
1224
  .j-info-card {
905
1225
  padding: var(--j-space-md) var(--j-space-lg);
906
1226
  }
1227
+
907
1228
  .j-info-card__title {
908
1229
  font-size: 14px;
909
1230
  }
1231
+
910
1232
  .j-section-header__tag {
911
1233
  font-size: 12px;
912
1234
  }
@@ -987,6 +1309,7 @@
987
1309
  cursor: pointer;
988
1310
  border: 2px solid transparent;
989
1311
  }
1312
+
990
1313
  .j-info-card:hover {
991
1314
  filter: brightness(1.08);
992
1315
  }
@@ -1090,6 +1413,7 @@
1090
1413
  transition: border-color 100ms ease;
1091
1414
  box-sizing: border-box;
1092
1415
  }
1416
+
1093
1417
  .j-seed-input__field::placeholder {
1094
1418
  color: var(--j-grey);
1095
1419
  opacity: 0.6;
@@ -1097,15 +1421,19 @@
1097
1421
  letter-spacing: 0.06em;
1098
1422
  font-size: 12px;
1099
1423
  }
1424
+
1100
1425
  .j-seed-input__field:focus {
1101
1426
  border-color: var(--j-gold);
1102
1427
  }
1428
+
1103
1429
  .j-seed-input__field[data-valid="true"] {
1104
1430
  border-color: var(--j-green);
1105
1431
  }
1432
+
1106
1433
  .j-seed-input__field[data-valid="false"] {
1107
1434
  border-color: var(--j-red);
1108
1435
  }
1436
+
1109
1437
  .j-seed-input__field[data-valid="partial"] {
1110
1438
  border-color: var(--j-panel-edge);
1111
1439
  }
@@ -1148,10 +1476,12 @@
1148
1476
  transition: border-color 100ms ease, background 100ms ease, color 100ms ease;
1149
1477
  box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.3);
1150
1478
  }
1479
+
1151
1480
  .j-aesthetic-pill:hover {
1152
1481
  border-color: var(--j-gold);
1153
1482
  color: var(--j-gold-text);
1154
1483
  }
1484
+
1155
1485
  .j-aesthetic-pill[data-active="true"] {
1156
1486
  border-color: var(--j-gold);
1157
1487
  background: rgba(228, 182, 67, 0.13);
@@ -1393,11 +1723,25 @@
1393
1723
  /* ── Font Dance Animation ─────────────────────────────────────────────── */
1394
1724
 
1395
1725
  @keyframes j-font-dance {
1396
- 0% { transform: translateY(0); }
1397
- 25% { transform: translateY(-1px); }
1398
- 50% { transform: translateY(0); }
1399
- 75% { transform: translateY(1px); }
1400
- 100% { transform: translateY(0); }
1726
+ 0% {
1727
+ transform: translateY(0);
1728
+ }
1729
+
1730
+ 25% {
1731
+ transform: translateY(-1px);
1732
+ }
1733
+
1734
+ 50% {
1735
+ transform: translateY(0);
1736
+ }
1737
+
1738
+ 75% {
1739
+ transform: translateY(1px);
1740
+ }
1741
+
1742
+ 100% {
1743
+ transform: translateY(0);
1744
+ }
1401
1745
  }
1402
1746
 
1403
1747
  .j-text--dance-container {
@@ -1413,8 +1757,16 @@
1413
1757
  scrollbar-width: none;
1414
1758
  -ms-overflow-style: none;
1415
1759
  }
1760
+
1416
1761
  .hide-scrollbar::-webkit-scrollbar {
1417
1762
  display: none;
1418
1763
  }
1419
- .j-juice-hover { transition: transform 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275); }
1420
- .j-juice-hover:hover { transform: scale(1.05) translateY(-2px); z-index: 5; }
1764
+
1765
+ .j-juice-hover {
1766
+ transition: transform 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
1767
+ }
1768
+
1769
+ .j-juice-hover:hover {
1770
+ transform: scale(1.05) translateY(-2px);
1771
+ z-index: 5;
1772
+ }
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from 'react';
4
3
  import { JimboText } from './jimboText.js';
5
4
  /**
6
5
  * Horizontal tab navigation with bouncing triangle indicator on the active
@@ -10,8 +9,7 @@ export function JimboTabs({ tabs, activeTab, onTabChange, className = '', style
10
9
  return (_jsx("div", { className: `j-tabs ${className}`, style: style, children: tabs.map((tab) => (_jsx(TabButton, { label: tab.label, active: activeTab === tab.id, onClick: () => onTabChange(tab.id) }, tab.id))) }));
11
10
  }
12
11
  function TabButton({ label, active, onClick }) {
13
- const [pressed, setPressed] = useState(false);
14
- return (_jsxs("div", { className: "j-tab", children: [_jsx("div", { className: "j-tab__indicator", "data-active": active, "aria-hidden": true, children: _jsx("svg", { width: 14, height: 10, viewBox: "0 0 14 10", children: _jsx("polygon", { points: "7,10 0,0 14,0" }) }) }), _jsx("button", { type: "button", className: "j-tab__btn", "data-active": active, "data-pressed": pressed, onClick: onClick, onMouseDown: () => setPressed(true), onMouseUp: () => setPressed(false), onMouseEnter: () => { }, onMouseLeave: () => { setPressed(false); }, onTouchStart: () => setPressed(true), onTouchEnd: () => setPressed(false), children: _jsx(JimboText, { size: "sm", tone: active ? 'default' : 'grey', children: label }) })] }));
12
+ return (_jsxs("div", { className: "j-tab", "data-active": active, children: [_jsx("div", { className: "j-tab__indicator", "data-active": active, "aria-hidden": true, children: _jsx("svg", { width: 14, height: 10, viewBox: "0 0 14 10", children: _jsx("polygon", { points: "7,10 0,0 14,0" }) }) }), _jsx("button", { type: "button", className: "j-tab__btn", "data-active": active, onClick: onClick, children: _jsx(JimboText, { size: "sm", tone: "default", children: label }) })] }));
15
13
  }
16
14
  /**
17
15
  * Vertical tab strip — rotated labels (writing-mode) for space efficiency.
package/dist/ui/panel.js CHANGED
@@ -15,7 +15,7 @@ export function JimboButton({ tone = 'orange', size = 'md', fullWidth = false, d
15
15
  return (_jsx("button", { type: "button", className: `j-btn j-btn--${tone} j-btn--${size} ${fullWidth ? 'j-btn--full' : ''} ${disabled ? 'j-btn--disabled' : ''} ${className}`, disabled: disabled, onClick: onClick, style: style, children: _jsx("div", { className: "j-btn__face", children: _jsx(JimboText, { size: textSize, uppercase: uppercase, children: children }) }) }));
16
16
  }
17
17
  export function JimboBackButton({ onClick }) {
18
- return (_jsx("div", { className: "j-flex j-justify-center j-w-full", style: { padding: '4px 0' }, children: _jsx(JimboButton, { tone: "orange", size: "md", fullWidth: true, onClick: onClick, children: "Back" }) }));
18
+ return (_jsx("div", { className: "j-flex j-justify-center j-w-full", style: { padding: '4px 0' }, children: _jsx(JimboButton, { tone: "orange", size: "md", fullWidth: true, onClick: onClick, className: "j-back-btn", children: "Back" }) }));
19
19
  }
20
20
  export function JimboModal({ children, open, onClose, title, className }) {
21
21
  if (!open)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaml-ui",
3
- "version": "0.24.6",
3
+ "version": "0.24.7",
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",