jaml-ui 0.24.14 → 0.24.16

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.
@@ -40,7 +40,7 @@ export function JamlCurator({ motely, motelyWasmUrl }) {
40
40
  };
41
41
  return (_jsx("div", { style: {
42
42
  width: "100%",
43
- maxWidth: 375,
43
+ maxWidth: 320,
44
44
  height: "100svh",
45
45
  margin: "0 auto",
46
46
  position: "relative",
@@ -11,7 +11,6 @@ import { JimboColorOption } from "../ui/tokens.js";
11
11
  import { JimboModal } from "../ui/panel.js";
12
12
  import { jamlTextToVisualFilter, visualFilterToJamlText } from "../utils/jamlVisualFilter.js";
13
13
  import { DeckSprite } from "./DeckSprite.js";
14
- import { DECK_OPTIONS, STAKE_OPTIONS } from "../lib/data/constants.js";
15
14
  const CATEGORY_CONFIG_MAP = {
16
15
  voucher: VOUCHER_PICKER_CONFIG,
17
16
  tag: TAG_PICKER_CONFIG,
@@ -104,25 +103,20 @@ function setRootValue(jaml, key, value) {
104
103
  const trimmed = jaml.trimEnd();
105
104
  return trimmed.length > 0 ? `${line}\n${trimmed}` : line;
106
105
  }
107
- function DeckStakeSelector({ jaml, onChange, }) {
106
+ import { RunConfigModal } from "./RunConfigModal.js";
107
+ function DeckStakeSelector({ jaml, onChange, onSearch, }) {
108
108
  const deck = readRootValue(jaml, "deck", "Red");
109
109
  const stake = readRootValue(jaml, "stake", "White");
110
- const setDeck = (nextDeck) => onChange(setRootValue(jaml, "deck", nextDeck));
111
- const setStake = (nextStake) => onChange(setRootValue(jaml, "stake", nextStake));
112
- return (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 }, children: [_jsx(DeckSprite, { deck: deck, stake: stake, size: compactDeckSpriteSize }), _jsx("select", { value: deck, onChange: (event) => setDeck(event.currentTarget.value), style: selectorStyle, children: DECK_OPTIONS.map((option) => (_jsx("option", { value: option, children: option }, option))) }), _jsx("select", { value: stake, onChange: (event) => setStake(event.currentTarget.value), style: selectorStyle, children: STAKE_OPTIONS.map((option) => (_jsx("option", { value: option, children: option }, option))) })] }));
110
+ const [modalOpen, setModalOpen] = useState(false);
111
+ const handleApply = (nextDeck, nextStake) => {
112
+ let next = setRootValue(jaml, "deck", nextDeck);
113
+ next = setRootValue(next, "stake", nextStake);
114
+ onChange(next);
115
+ onSearch?.();
116
+ };
117
+ return (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => setModalOpen(true), className: "j-btn j-btn--red", style: { height: 32, padding: 0, borderRadius: 8, overflow: 'hidden' }, children: _jsxs("div", { className: "j-btn__face", style: { display: 'flex', alignItems: 'center', gap: 8, padding: '0 8px 0 4px', height: '100%' }, children: [_jsx(DeckSprite, { deck: deck, stake: stake, size: compactDeckSpriteSize }), _jsxs("span", { style: { fontFamily: "m6x11plus, monospace", fontSize: 14 }, children: [deck, " / ", stake] })] }) }), _jsx(RunConfigModal, { open: modalOpen, onClose: () => setModalOpen(false), deck: deck, stake: stake, onChange: handleApply })] }));
113
118
  }
114
119
  const compactDeckSpriteSize = 24;
115
- const selectorStyle = {
116
- minWidth: 0,
117
- height: 28,
118
- borderRadius: 8,
119
- border: `1px solid ${JimboColorOption.PANEL_EDGE}`,
120
- background: JimboColorOption.DARKEST,
121
- color: JimboColorOption.WHITE,
122
- fontFamily: "m6x11plus, monospace",
123
- fontSize: 12,
124
- padding: "0 8px",
125
- };
126
120
  export function JamlIde({ jaml, defaultJaml, onChange, defaultMode = "code", searchResults = [], className = "", style, title = "JAML IDE", subtitle = "Jimbo's Ante Markup Language", compactHeader = false, actions, codePlaceholder = "Enter JAML...", onSearch, isSearching = false, hideFooter = false, visualFilter, onVisualFilterChange, }) {
127
121
  const [mode, setMode] = useState(defaultMode);
128
122
  const [internalText, setInternalText] = useState(jaml ?? defaultJaml ?? "");
@@ -223,5 +217,5 @@ export function JamlIde({ jaml, defaultJaml, onChange, defaultMode = "code", sea
223
217
  padding: compactHeader ? "8px 10px" : "10px 14px",
224
218
  borderBottom: `1px solid ${JimboColorOption.PANEL_EDGE}`,
225
219
  background: JimboColorOption.TEAL_GREY,
226
- }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: 16, fontWeight: "normal", fontFamily: "m6x11plus, monospace", color: JimboColorOption.GOLD_TEXT }, children: title }), subtitle ? _jsx("div", { style: { fontSize: 11, color: JimboColorOption.GREY }, children: subtitle }) : null] }), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", justifyContent: "flex-end" }, children: [_jsx(DeckStakeSelector, { jaml: text, onChange: handleTextChange }), actions] })] }), _jsx(JamlIdeToolbar, { mode: mode, onModeChange: setMode, resultCount: results.length, onSearch: onSearch, isSearching: isSearching }), _jsxs("div", { style: { flex: 1, minHeight: 0, overflow: mode === "map" ? "hidden" : "auto", background: JimboColorOption.DARKEST }, children: [mode === "visual" ? (_jsx(JamlIdeVisual, { filter: activeFilter, onChange: handleVisualFilterChange, onAddClause: handleAddClause })) : null, mode === "code" ? (_jsx(JamlCodeEditor, { value: text, onChange: handleTextChange, placeholder: codePlaceholder })) : null, mode === "map" ? _jsx(JamlMapEditor, { onChange: handleTextChange }) : null, mode === "results" ? (_jsx("div", { style: { padding: 12 }, children: _jsx(ResultsView, { results: results, jaml: text }) })) : null] }), !hideFooter && _jsx(JimboBalatroFooter, {}), _jsx(JimboModal, { open: addZone !== null, onClose: handlePickerClose, children: addZone !== null && (pickerFlow === "category" ? (_jsx(CategoryMenu, { onSelect: (cat) => setPickerFlow(cat) })) : pickerFlow === "joker" ? (_jsx(JokerPicker, { onSelect: handlePickerSelect, onCancel: handlePickerClose })) : (_jsx(CategoryPicker, { config: CATEGORY_CONFIG_MAP[pickerFlow], onSelect: handlePickerSelect, onCancel: handlePickerClose }))) })] }));
220
+ }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: 16, fontWeight: "normal", fontFamily: "m6x11plus, monospace", color: JimboColorOption.GOLD_TEXT }, children: title }), subtitle ? _jsx("div", { style: { fontSize: 11, color: JimboColorOption.GREY }, children: subtitle }) : null] }), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", justifyContent: "flex-end" }, children: [_jsx(DeckStakeSelector, { jaml: text, onChange: handleTextChange, onSearch: onSearch }), actions] })] }), _jsx(JamlIdeToolbar, { mode: mode, onModeChange: setMode, resultCount: results.length, onSearch: onSearch, isSearching: isSearching }), _jsxs("div", { style: { flex: 1, minHeight: 0, overflow: mode === "map" ? "hidden" : "auto", background: JimboColorOption.DARKEST }, children: [mode === "visual" ? (_jsx(JamlIdeVisual, { filter: activeFilter, onChange: handleVisualFilterChange, onAddClause: handleAddClause })) : null, mode === "code" ? (_jsx(JamlCodeEditor, { value: text, onChange: handleTextChange, placeholder: codePlaceholder })) : null, mode === "map" ? _jsx(JamlMapEditor, { onChange: handleTextChange }) : null, mode === "results" ? (_jsx("div", { style: { padding: 12 }, children: _jsx(ResultsView, { results: results, jaml: text }) })) : null] }), !hideFooter && _jsx(JimboBalatroFooter, {}), _jsx(JimboModal, { open: addZone !== null, onClose: handlePickerClose, children: addZone !== null && (pickerFlow === "category" ? (_jsx(CategoryMenu, { onSelect: (cat) => setPickerFlow(cat) })) : pickerFlow === "joker" ? (_jsx(JokerPicker, { onSelect: handlePickerSelect, onCancel: handlePickerClose })) : (_jsx(CategoryPicker, { config: CATEGORY_CONFIG_MAP[pickerFlow], onSelect: handlePickerSelect, onCancel: handlePickerClose }))) })] }));
227
221
  }
@@ -0,0 +1,8 @@
1
+ export interface RunConfigModalProps {
2
+ open: boolean;
3
+ onClose: () => void;
4
+ deck: string;
5
+ stake: string;
6
+ onChange: (deck: string, stake: string) => void;
7
+ }
8
+ export declare function RunConfigModal({ open, onClose, deck, stake, onChange, }: RunConfigModalProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,198 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState } from "react";
3
+ import { JimboModal } from "../ui/panel.js";
4
+ import { DECK_OPTIONS, STAKE_OPTIONS } from "../lib/data/constants.js";
5
+ import { DeckSprite } from "./DeckSprite.js";
6
+ import { StakeSprite } from "../ui/sprites.js";
7
+ import { JimboColorOption } from "../ui/tokens.js";
8
+ const DECK_DESCRIPTIONS = {
9
+ "Red": "+1 discard every round",
10
+ "Blue": "+1 hand every round",
11
+ "Yellow": "Start with extra $10",
12
+ "Green": "At end of each Round:\n$2 per remaining Hand,\n$1 per remaining Discard.\nEarn no Interest",
13
+ "Black": "+1 Joker slot\n-1 hand every round",
14
+ "Magic": "Start run with the\nCrystal Ball voucher\nand 2 copies of The Fool",
15
+ "Nebula": "Start run with the\nTelescope voucher\n-1 consumable slot",
16
+ "Ghost": "Spectral cards may\nappear in the shop,\nstart with a Hex card",
17
+ "Abandoned": "Start run with no\nFace Cards in your deck",
18
+ "Checkered": "Start run with\n26 Spades and\n26 Hearts in deck",
19
+ "Zodiac": "Start run with\nTarot Merchant,\nPlanet Merchant,\nand Overstock vouchers",
20
+ "Painted": "+2 hand size,\n-1 Joker slot",
21
+ "Anaglyph": "After defeating each\nBoss Blind, gain a\nDouble Tag",
22
+ "Plasma": "Balance Chips and\nMult when calculating\nscore for played hand.\nX2 base Blind size",
23
+ "Erratic": "All Ranks and Suits\nin deck are randomized",
24
+ };
25
+ const STAKE_DESCRIPTIONS = {
26
+ "White": "Base Difficulty",
27
+ "Red": "Small Blind gives\nno reward money\nApplies all previous Stakes",
28
+ "Green": "Required score scales\nfaster for each Ante\nApplies all previous Stakes",
29
+ "Black": "Shop can have Jokers\nwith Eternal\nApplies all previous Stakes",
30
+ "Blue": "-1 Discard\nApplies all previous Stakes",
31
+ "Purple": "Required score scales\nfaster for each Ante\nApplies all previous Stakes",
32
+ "Orange": "Shop can have Jokers\nwith Perishable\nApplies all previous Stakes",
33
+ "Gold": "-1 hand size\nShop can have Jokers\nwith Rental\nApplies all previous Stakes",
34
+ };
35
+ function formatTextWithColors(text) {
36
+ // Hacky basic coloration for Balatro text
37
+ const parts = text.split(/(\d+|Spades|Hearts|Clubs|Diamonds|\$[\d]+|Eternal|Perishable|Rental|Chips|Mult)/g);
38
+ return parts.map((part, i) => {
39
+ let color = JimboColorOption.WHITE;
40
+ if (/^\d+$/.test(part))
41
+ color = JimboColorOption.RED;
42
+ else if (part === 'Spades')
43
+ color = JimboColorOption.BLUE; // Spades are typically blue in high contrast
44
+ else if (part === 'Hearts')
45
+ color = JimboColorOption.RED;
46
+ else if (part === 'Clubs')
47
+ color = JimboColorOption.GREEN_TEXT;
48
+ else if (part === 'Diamonds')
49
+ color = JimboColorOption.ORANGE_TEXT;
50
+ else if (part.startsWith('$'))
51
+ color = JimboColorOption.GOLD_TEXT;
52
+ else if (['Eternal', 'Perishable', 'Rental'].includes(part))
53
+ color = JimboColorOption.GOLD_TEXT; // Should be specific colours
54
+ else if (part === 'Chips')
55
+ color = JimboColorOption.BLUE;
56
+ else if (part === 'Mult')
57
+ color = JimboColorOption.RED;
58
+ if (color !== JimboColorOption.WHITE) {
59
+ return _jsx("span", { style: { color }, children: part }, i);
60
+ }
61
+ return _jsx("span", { children: part }, i);
62
+ });
63
+ }
64
+ export function RunConfigModal({ open, onClose, deck, stake, onChange, }) {
65
+ const [activeDeck, setActiveDeck] = useState(deck);
66
+ const [activeStake, setActiveStake] = useState(stake);
67
+ // Sync state if props change when opened
68
+ React.useEffect(() => {
69
+ if (open) {
70
+ setActiveDeck(deck);
71
+ setActiveStake(stake);
72
+ }
73
+ }, [open, deck, stake]);
74
+ if (!open)
75
+ return null;
76
+ const deckIdx = DECK_OPTIONS.indexOf(activeDeck) >= 0 ? DECK_OPTIONS.indexOf(activeDeck) : 0;
77
+ const stakeIdx = STAKE_OPTIONS.indexOf(activeStake) >= 0 ? STAKE_OPTIONS.indexOf(activeStake) : 0;
78
+ const nextDeck = () => setActiveDeck(DECK_OPTIONS[(deckIdx + 1) % DECK_OPTIONS.length]);
79
+ const prevDeck = () => setActiveDeck(DECK_OPTIONS[(deckIdx - 1 + DECK_OPTIONS.length) % DECK_OPTIONS.length]);
80
+ const nextStake = () => setActiveStake(STAKE_OPTIONS[(stakeIdx + 1) % STAKE_OPTIONS.length]);
81
+ const prevStake = () => setActiveStake(STAKE_OPTIONS[(stakeIdx - 1 + STAKE_OPTIONS.length) % STAKE_OPTIONS.length]);
82
+ const handleApply = () => {
83
+ onChange(activeDeck, activeStake);
84
+ onClose();
85
+ };
86
+ const CarouselButton = ({ onClick, children }) => (_jsx("button", { onClick: onClick, style: {
87
+ width: 32,
88
+ height: "100%",
89
+ borderRadius: 8,
90
+ background: JimboColorOption.RED,
91
+ border: `2px solid ${JimboColorOption.WHITE}`, // Should be dark edge with inner shadow but let's use standard red btn style
92
+ color: JimboColorOption.WHITE,
93
+ fontSize: 24,
94
+ fontFamily: "m6x11plus, monospace",
95
+ display: "flex",
96
+ alignItems: "center",
97
+ justifyContent: "center",
98
+ cursor: "pointer",
99
+ flexShrink: 0,
100
+ }, className: "j-btn j-btn--red" // piggyback on Jimbo button styles
101
+ , children: _jsx("div", { className: "j-btn__face", style: { padding: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: children }) }));
102
+ return (_jsx(JimboModal, { open: open, onClose: onClose, children: _jsxs("div", { style: {
103
+ width: 600,
104
+ maxWidth: "95vw",
105
+ background: JimboColorOption.TEAL_GREY, // A greenish-grey slate color
106
+ borderRadius: 16,
107
+ border: `3px solid ${JimboColorOption.BORDER_SILVER}`,
108
+ boxShadow: `inset 0 0 0 2px ${JimboColorOption.DARKEST}, 0 8px 16px rgba(0,0,0,0.5)`,
109
+ padding: "24px 20px",
110
+ display: "flex",
111
+ flexDirection: "column",
112
+ gap: 24,
113
+ position: "relative",
114
+ }, children: [_jsx("div", { style: {
115
+ position: "absolute",
116
+ top: -20,
117
+ left: 0,
118
+ right: 0,
119
+ display: "flex",
120
+ justifyContent: "center",
121
+ gap: 8,
122
+ }, children: _jsx("div", { className: "j-btn j-btn--red", style: { height: 36, pointerEvents: "none" }, children: _jsx("div", { className: "j-btn__face", style: { fontSize: 16, padding: "0 16px" }, children: "Seed Finder" }) }) }), _jsxs("div", { style: { display: "flex", height: 160, gap: 12 }, children: [_jsx(CarouselButton, { onClick: prevDeck, children: "<" }), _jsxs("div", { style: {
123
+ flex: 1,
124
+ background: JimboColorOption.DARK_GREY,
125
+ borderRadius: 12,
126
+ border: `2px solid ${JimboColorOption.PANEL_EDGE}`,
127
+ display: "flex",
128
+ alignItems: "center",
129
+ padding: "16px",
130
+ gap: 16,
131
+ }, children: [_jsx(DeckSprite, { deck: activeDeck, size: 100, style: { flexShrink: 0 } }), _jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center" }, children: [_jsxs("h2", { style: {
132
+ fontFamily: "m6x11plus, monospace",
133
+ fontSize: 28,
134
+ color: JimboColorOption.WHITE,
135
+ margin: "0 0 8px 0",
136
+ textShadow: `1px 1px 0 ${JimboColorOption.DARKEST}`,
137
+ }, children: [activeDeck, " Deck"] }), _jsx("div", { style: {
138
+ background: JimboColorOption.WHITE,
139
+ borderRadius: 8,
140
+ padding: "12px",
141
+ width: "100%",
142
+ minHeight: 80,
143
+ display: "flex",
144
+ flexDirection: "column",
145
+ alignItems: "center",
146
+ justifyContent: "center",
147
+ boxShadow: `inset 0 -2px 0 0 ${JimboColorOption.PANEL_EDGE}`,
148
+ }, children: _jsx("div", { style: {
149
+ fontFamily: "m6x11plus, monospace",
150
+ fontSize: 16,
151
+ color: JimboColorOption.DARKEST,
152
+ textAlign: "center",
153
+ whiteSpace: "pre-line",
154
+ lineHeight: 1.2,
155
+ }, children: formatTextWithColors(DECK_DESCRIPTIONS[activeDeck] || "Standard 52 card deck") }) })] }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, paddingRight: 4 }, children: [_jsx("div", { style: { width: 8, height: 8, borderRadius: 4, background: JimboColorOption.GREY } }), _jsx("div", { style: { width: 8, height: 8, borderRadius: 4, background: JimboColorOption.GREY } }), _jsx("div", { style: { width: 8, height: 8, borderRadius: 4, background: JimboColorOption.GREEN } }), _jsx("div", { style: { width: 8, height: 8, borderRadius: 4, background: JimboColorOption.RED } }), _jsx("div", { style: { width: 8, height: 8, borderRadius: 4, background: JimboColorOption.WHITE } })] })] }), _jsx(CarouselButton, { onClick: nextDeck, children: ">" })] }), _jsxs("div", { style: { display: "flex", height: 120, gap: 12 }, children: [_jsx(CarouselButton, { onClick: prevStake, children: "<" }), _jsxs("div", { style: {
156
+ flex: 1,
157
+ background: JimboColorOption.DARK_GREY,
158
+ borderRadius: 12,
159
+ border: `2px solid ${JimboColorOption.PANEL_EDGE}`,
160
+ display: "flex",
161
+ alignItems: "center",
162
+ padding: "12px 16px",
163
+ gap: 16,
164
+ position: "relative",
165
+ }, children: [_jsx("div", { style: {
166
+ position: 'absolute',
167
+ left: -14, // Cut out effect text
168
+ top: '50%',
169
+ transform: 'translateY(-50%) rotate(-90deg)',
170
+ fontFamily: "m6x11plus, monospace",
171
+ fontSize: 16,
172
+ color: JimboColorOption.GREY,
173
+ }, children: "Stake" }), _jsx("div", { style: { paddingLeft: 20 }, children: _jsx(StakeSprite, { stake: activeStake, width: 64, style: { flexShrink: 0 } }) }), _jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center" }, children: [_jsxs("h2", { style: {
174
+ fontFamily: "m6x11plus, monospace",
175
+ fontSize: 22,
176
+ color: JimboColorOption.WHITE,
177
+ margin: "0 0 6px 0",
178
+ textShadow: `1px 1px 0 ${JimboColorOption.DARKEST}`,
179
+ }, children: [activeStake, " Stake"] }), _jsx("div", { style: {
180
+ background: JimboColorOption.WHITE,
181
+ borderRadius: 8,
182
+ padding: "8px 12px",
183
+ width: "100%",
184
+ minHeight: 60,
185
+ display: "flex",
186
+ flexDirection: "column",
187
+ alignItems: "center",
188
+ justifyContent: "center",
189
+ boxShadow: `inset 0 -2px 0 0 ${JimboColorOption.PANEL_EDGE}`,
190
+ }, children: _jsx("div", { style: {
191
+ fontFamily: "m6x11plus, monospace",
192
+ fontSize: 14,
193
+ color: JimboColorOption.DARKEST,
194
+ textAlign: "center",
195
+ whiteSpace: "pre-line",
196
+ lineHeight: 1.2,
197
+ }, children: formatTextWithColors(STAKE_DESCRIPTIONS[activeStake] || "Base Difficulty") }) })] })] }), _jsx(CarouselButton, { onClick: nextStake, children: ">" })] }), _jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12, marginTop: 8 }, children: [_jsx("button", { onClick: handleApply, className: "j-btn j-btn--blue j-btn--lg", style: { width: "80%", height: 50, fontSize: 24, padding: 0 }, children: _jsx("div", { className: "j-btn__face", style: { display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: "APPLY" }) }), _jsx("button", { onClick: onClose, className: "j-btn j-btn--orange j-btn--md", style: { width: "100%", height: 40, fontSize: 18, padding: 0 }, children: _jsx("div", { className: "j-btn__face", style: { display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: "Back" }) })] })] }) }));
198
+ }
package/dist/ui/jimbo.css CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  :root {
20
20
  /* Colors — eyedropped from Balatro's rendered shader output */
21
- --j-red: #ff4c40;
21
+ --j-red: #fe5148;
22
22
  --j-blue: #0093ff;
23
23
  --j-green: #429f79;
24
24
  --j-orange: #ff9800;
@@ -915,7 +915,7 @@
915
915
 
916
916
  .j-modal {
917
917
  width: 100%;
918
- max-width: 375px;
918
+ max-width: 320px;
919
919
  max-height: 90vh;
920
920
  display: flex;
921
921
  flex-direction: column;
@@ -1142,9 +1142,9 @@
1142
1142
  }
1143
1143
 
1144
1144
  /* ── App Shell ────────────────────────────────────────────────────────── */
1145
- /* Mobile-first 375px layout container for ALL Jimbo UI screens.
1145
+ /* Mobile-first 320px layout container for ALL Jimbo UI screens.
1146
1146
  * Supports container queries for responsive breakpoints:
1147
- * compact ≤400px — iPhone SE, fixed 667px height, NO scroll
1147
+ * compact ≤400px — iPhone SE, fixed 568px height, NO scroll
1148
1148
  * cozy 401-750px — MCP inline / wider phones, flexible height, scroll OK
1149
1149
  * wide 751px+ — tablet/desktop, two-column layouts (future)
1150
1150
  *
@@ -1154,10 +1154,10 @@
1154
1154
  .j-app {
1155
1155
  container-type: inline-size;
1156
1156
  container-name: jimbo;
1157
- width: 375px;
1158
- max-width: 375px;
1159
- height: 667px;
1160
- max-height: 667px;
1157
+ width: 320px;
1158
+ max-width: 320px;
1159
+ height: 568px;
1160
+ max-height: 568px;
1161
1161
  margin: 0 auto;
1162
1162
  display: flex;
1163
1163
  flex-direction: column;
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
  export interface JimboAppProps extends React.HTMLAttributes<HTMLDivElement> {
3
3
  children: React.ReactNode;
4
- /** Unlock width/height for MCP inline or desktop use. Default: false (375×667 locked). */
4
+ /** Unlock width/height for MCP inline or desktop use. Default: false (320×568 locked). */
5
5
  fluid?: boolean;
6
6
  }
7
- /** Standard mobile-first app shell. 375px locked, or fluid for MCP/desktop. */
7
+ /** Standard mobile-first app shell. 320px locked, or fluid for MCP/desktop. */
8
8
  export declare function JimboApp({ children, fluid, className, ...props }: JimboAppProps): import("react/jsx-runtime").JSX.Element;
9
9
  /** Scrollable content area inside JimboApp. Hidden scrollbar, snap-friendly. */
10
10
  export declare function JimboAppScroll({ children, className, ...props }: Omit<JimboAppProps, 'fluid'>): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- /** Standard mobile-first app shell. 375px locked, or fluid for MCP/desktop. */
3
+ /** Standard mobile-first app shell. 320px locked, or fluid for MCP/desktop. */
4
4
  export function JimboApp({ children, fluid, className = '', ...props }) {
5
5
  const classes = `j-app${fluid ? ' j-app--fluid' : ''} ${className}`.trim();
6
6
  return (_jsx("div", { className: classes, ...props, children: children }));
@@ -80,7 +80,7 @@ function layoutOrbitalEllipse(items, Rx, Ry, startAngle, stepRad, mascotSizePx)
80
80
  */
81
81
  export function RadialMenu({ items, showClosing, mascotSizePx, orbitRadiusX, orbitRadiusY, mascotTranslateY, currentMenu, onItemClick, onBack, breadcrumb, showPageControls = false, onPagePrev, onPageNext, }) {
82
82
  const rootRef = useRef(null);
83
- const [containerW, setContainerW] = useState(375);
83
+ const [containerW, setContainerW] = useState(320);
84
84
  useLayoutEffect(() => {
85
85
  const el = rootRef.current;
86
86
  if (!el)
@@ -21,7 +21,7 @@ function readGeometry() {
21
21
  return { baseRadius: 66, keyboardHeight: 0 };
22
22
  }
23
23
  const w = window.innerWidth;
24
- const baseRadius = w < 375 ? 58 : 66;
24
+ const baseRadius = w < 320 ? 58 : 66;
25
25
  const vv = window.visualViewport;
26
26
  let keyboardHeight = 0;
27
27
  if (vv) {
@@ -32,7 +32,7 @@ export interface ShowcaseProps {
32
32
  onFilterClick?: (filter: ShowcaseFilter, index: number) => void;
33
33
  }
34
34
  /**
35
- * Landing/showcase screen — 375×667, NO SCROLL.
35
+ * Landing/showcase screen — 320×568, NO SCROLL.
36
36
  * Every pixel accounted for. No flex stretching. No gaps.
37
37
  */
38
38
  export declare function Showcase({ title, subtitle, hotFilters, recentFinds, mcpInfo, onNewSearch, onBrowseFilters, onFilterClick, }: ShowcaseProps): import("react/jsx-runtime").JSX.Element;
@@ -8,7 +8,7 @@ import { JimboBalatroFooter } from './footer.js';
8
8
  import { JimboSectionHeader } from './jimboSectionHeader.js';
9
9
  import { JimboInfoCard, JimboInfoCardBody, JimboInfoCardTitle, JimboInfoCardSub, JimboInfoCardAside } from './jimboInfoCard.js';
10
10
  /**
11
- * Landing/showcase screen — 375×667, NO SCROLL.
11
+ * Landing/showcase screen — 320×568, NO SCROLL.
12
12
  * Every pixel accounted for. No flex stretching. No gaps.
13
13
  */
14
14
  export function Showcase({ title = 'Balatro', subtitle = 'Seed Curator', hotFilters = [], recentFinds = [], mcpInfo, onNewSearch, onBrowseFilters, onFilterClick, }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaml-ui",
3
- "version": "0.24.14",
3
+ "version": "0.24.16",
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",