jaml-ui 0.9.0 → 0.10.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/assets.js +1 -1
- package/dist/components/CardFan.d.ts +22 -0
- package/dist/components/CardFan.js +80 -0
- package/dist/components/DeckSprite.d.ts +26 -0
- package/dist/components/DeckSprite.js +73 -0
- package/dist/components/MotelyVersionBadge.d.ts +30 -0
- package/dist/components/MotelyVersionBadge.js +31 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/ui/jimboBackground.d.ts +14 -0
- package/dist/ui/jimboBackground.js +155 -0
- package/dist/ui/jimboFilterBar.d.ts +25 -0
- package/dist/ui/jimboFilterBar.js +77 -0
- package/dist/ui/jimboFlankNav.d.ts +18 -0
- package/dist/ui/jimboFlankNav.js +43 -0
- package/dist/ui/jimboTabs.d.ts +25 -0
- package/dist/ui/jimboTabs.js +59 -0
- package/dist/ui/jimboText.d.ts +26 -0
- package/dist/ui/jimboText.js +45 -0
- package/dist/ui/jimboTooltip.d.ts +35 -0
- package/dist/ui/jimboTooltip.js +109 -0
- package/dist/ui/panel.js +4 -6
- package/dist/ui/tokens.d.ts +2 -1
- package/dist/ui/tokens.js +2 -0
- package/dist/ui.d.ts +6 -0
- package/dist/ui.js +6 -0
- package/fonts.css +5 -0
- package/package.json +6 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface JimboTabItem {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export interface JimboTabsProps {
|
|
7
|
+
tabs: JimboTabItem[];
|
|
8
|
+
activeTab: string;
|
|
9
|
+
onTabChange: (tabId: string) => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: React.CSSProperties;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Horizontal tab navigation with bouncing triangle indicator on the active
|
|
15
|
+
* tab. Ported from JAMMY's jimbo-ui/Tabs.tsx — triangle attaches to each
|
|
16
|
+
* button and animates only on the active one.
|
|
17
|
+
*/
|
|
18
|
+
export declare function JimboTabs({ tabs, activeTab, onTabChange, className, style }: JimboTabsProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
/**
|
|
20
|
+
* Vertical tab strip — rotated labels (writing-mode) for space efficiency.
|
|
21
|
+
* Ported from JAMMY's JimboVerticalTabs. Typical use: inline on the left
|
|
22
|
+
* side of a content panel to pick between content categories
|
|
23
|
+
* (e.g. JOKERS / CONSUMABLES / VOUCHERS).
|
|
24
|
+
*/
|
|
25
|
+
export declare function JimboVerticalTabs({ tabs, activeTab, onTabChange, className, style }: JimboTabsProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { JimboColorOption, JIMBO_ANIMATIONS } from './tokens.js';
|
|
5
|
+
import { JimboText } from './jimboText.js';
|
|
6
|
+
/**
|
|
7
|
+
* Horizontal tab navigation with bouncing triangle indicator on the active
|
|
8
|
+
* tab. Ported from JAMMY's jimbo-ui/Tabs.tsx — triangle attaches to each
|
|
9
|
+
* button and animates only on the active one.
|
|
10
|
+
*/
|
|
11
|
+
export function JimboTabs({ tabs, activeTab, onTabChange, className = '', style }) {
|
|
12
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: className, style: { display: 'flex', gap: 8, alignItems: 'flex-end', ...style }, children: tabs.map((tab) => (_jsx(TabButton, { label: tab.label, active: activeTab === tab.id, onClick: () => onTabChange(tab.id) }, tab.id))) }), _jsx("style", { children: JIMBO_BOUNCE_KEYFRAMES })] }));
|
|
13
|
+
}
|
|
14
|
+
const JIMBO_BOUNCE_KEYFRAMES = `
|
|
15
|
+
@keyframes jimbo-bounce {
|
|
16
|
+
0%, 100% { transform: translateY(0); }
|
|
17
|
+
50% { transform: translateY(-3px); }
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
function TabButton({ label, active, onClick }) {
|
|
21
|
+
const [pressed, setPressed] = useState(false);
|
|
22
|
+
return (_jsxs("div", { style: { position: 'relative', display: 'flex', flexDirection: 'column', alignItems: 'center' }, children: [_jsx("div", { style: {
|
|
23
|
+
marginBottom: 4,
|
|
24
|
+
opacity: active ? 1 : 0,
|
|
25
|
+
transition: 'opacity 150ms',
|
|
26
|
+
animation: active ? 'jimbo-bounce 0.8s cubic-bezier(0.68, 0, 0.68, 1) infinite' : 'none',
|
|
27
|
+
}, "aria-hidden": true, children: _jsx("svg", { width: 14, height: 10, viewBox: "0 0 14 10", fill: JimboColorOption.RED, children: _jsx("polygon", { points: "7,10 0,0 14,0" }) }) }), _jsx("button", { type: "button", onClick: onClick, onMouseDown: () => setPressed(true), onMouseUp: () => setPressed(false), onMouseLeave: () => setPressed(false), onTouchStart: () => setPressed(true), onTouchEnd: () => setPressed(false), style: {
|
|
28
|
+
border: 'none',
|
|
29
|
+
cursor: 'pointer',
|
|
30
|
+
borderRadius: 8,
|
|
31
|
+
padding: '8px 16px',
|
|
32
|
+
backgroundColor: JimboColorOption.RED,
|
|
33
|
+
transform: pressed ? `translateY(${JIMBO_ANIMATIONS.PRESS_TRANSLATE_Y}px)` : 'translateY(0)',
|
|
34
|
+
boxShadow: pressed ? 'none' : `0 ${JIMBO_ANIMATIONS.PRESS_TRANSLATE_Y}px 0 0 ${JimboColorOption.BLACK}80`,
|
|
35
|
+
transition: `transform ${JIMBO_ANIMATIONS.PRESS_DURATION}ms ease, box-shadow ${JIMBO_ANIMATIONS.PRESS_DURATION}ms ease`,
|
|
36
|
+
}, children: _jsx(JimboText, { size: "sm", uppercase: true, children: label }) })] }));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Vertical tab strip — rotated labels (writing-mode) for space efficiency.
|
|
40
|
+
* Ported from JAMMY's JimboVerticalTabs. Typical use: inline on the left
|
|
41
|
+
* side of a content panel to pick between content categories
|
|
42
|
+
* (e.g. JOKERS / CONSUMABLES / VOUCHERS).
|
|
43
|
+
*/
|
|
44
|
+
export function JimboVerticalTabs({ tabs, activeTab, onTabChange, className = '', style }) {
|
|
45
|
+
return (_jsx("div", { className: className, style: { display: 'flex', flexDirection: 'column', gap: 4, ...style }, children: tabs.map((tab) => {
|
|
46
|
+
const isActive = activeTab === tab.id;
|
|
47
|
+
return (_jsx("button", { type: "button", onClick: () => onTabChange(tab.id), style: {
|
|
48
|
+
border: 'none',
|
|
49
|
+
cursor: 'pointer',
|
|
50
|
+
borderRadius: '8px 0 0 8px',
|
|
51
|
+
padding: '16px 8px',
|
|
52
|
+
backgroundColor: isActive ? JimboColorOption.DARK_GREY : JimboColorOption.INNER_BORDER,
|
|
53
|
+
writingMode: 'vertical-rl',
|
|
54
|
+
textOrientation: 'mixed',
|
|
55
|
+
transform: 'rotate(180deg)',
|
|
56
|
+
transition: 'background-color 120ms ease',
|
|
57
|
+
}, children: _jsx(JimboText, { size: "sm", uppercase: true, tone: isActive ? 'default' : 'grey', children: tab.label }) }, tab.id));
|
|
58
|
+
}) }));
|
|
59
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type JimboTextTone = 'default' | 'mult' | 'chips' | 'gold' | 'green' | 'red' | 'blue' | 'orange' | 'purple' | 'grey';
|
|
3
|
+
export type JimboTextSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
export interface JimboTextProps extends React.HTMLAttributes<HTMLElement> {
|
|
5
|
+
tone?: JimboTextTone;
|
|
6
|
+
size?: JimboTextSize;
|
|
7
|
+
/** Canonical Balatro drop shadow (1px right, 1px down, ${BLACK}cc). Default true. */
|
|
8
|
+
shadow?: boolean;
|
|
9
|
+
/** Uppercase + spacing — Balatro button/pill label treatment. Default false. */
|
|
10
|
+
uppercase?: boolean;
|
|
11
|
+
/** Letter-spacing override; defaults depend on uppercase prop. */
|
|
12
|
+
letterSpacing?: number | string;
|
|
13
|
+
as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label';
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Canonical pixel-font text wrapper. Uses `m6x11plus` as its family and
|
|
18
|
+
* applies the authentic Balatro drop shadow by default. Prefer this over
|
|
19
|
+
* hand-rolling `fontFamily: 'm6x11plus, monospace'` + `textShadow` strings
|
|
20
|
+
* throughout consumers — it keeps the styling drift-free.
|
|
21
|
+
*
|
|
22
|
+
* Requires `import 'jaml-ui/fonts.css'` somewhere in the consumer bundle
|
|
23
|
+
* so the @font-face declaration lands (font is base64-embedded, no
|
|
24
|
+
* runtime fetch).
|
|
25
|
+
*/
|
|
26
|
+
export declare function JimboText({ tone, size, shadow, uppercase, letterSpacing, as: Tag, style, children, ...rest }: JimboTextProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { JimboColorOption } from './tokens.js';
|
|
4
|
+
const TONE_COLOR = {
|
|
5
|
+
default: JimboColorOption.WHITE,
|
|
6
|
+
mult: JimboColorOption.RED,
|
|
7
|
+
chips: JimboColorOption.BLUE,
|
|
8
|
+
gold: JimboColorOption.GOLD_TEXT,
|
|
9
|
+
green: JimboColorOption.GREEN_TEXT,
|
|
10
|
+
red: JimboColorOption.RED,
|
|
11
|
+
blue: JimboColorOption.BLUE,
|
|
12
|
+
orange: JimboColorOption.ORANGE_TEXT,
|
|
13
|
+
purple: JimboColorOption.PURPLE,
|
|
14
|
+
grey: JimboColorOption.GREY,
|
|
15
|
+
};
|
|
16
|
+
const SIZE_PX = {
|
|
17
|
+
xs: 10,
|
|
18
|
+
sm: 12,
|
|
19
|
+
md: 14,
|
|
20
|
+
lg: 18,
|
|
21
|
+
xl: 24,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Canonical pixel-font text wrapper. Uses `m6x11plus` as its family and
|
|
25
|
+
* applies the authentic Balatro drop shadow by default. Prefer this over
|
|
26
|
+
* hand-rolling `fontFamily: 'm6x11plus, monospace'` + `textShadow` strings
|
|
27
|
+
* throughout consumers — it keeps the styling drift-free.
|
|
28
|
+
*
|
|
29
|
+
* Requires `import 'jaml-ui/fonts.css'` somewhere in the consumer bundle
|
|
30
|
+
* so the @font-face declaration lands (font is base64-embedded, no
|
|
31
|
+
* runtime fetch).
|
|
32
|
+
*/
|
|
33
|
+
export function JimboText({ tone = 'default', size = 'md', shadow = true, uppercase = false, letterSpacing, as: Tag = 'span', style, children, ...rest }) {
|
|
34
|
+
const resolvedLetterSpacing = letterSpacing ?? (uppercase ? 2 : undefined);
|
|
35
|
+
return (_jsx(Tag, { style: {
|
|
36
|
+
fontFamily: "'m6x11plus', 'Courier New', monospace",
|
|
37
|
+
fontSize: SIZE_PX[size],
|
|
38
|
+
color: TONE_COLOR[tone],
|
|
39
|
+
textShadow: shadow ? `1px 1px 0 ${JimboColorOption.BLACK}cc` : 'none',
|
|
40
|
+
textTransform: uppercase ? 'uppercase' : 'none',
|
|
41
|
+
letterSpacing: resolvedLetterSpacing,
|
|
42
|
+
lineHeight: 1.2,
|
|
43
|
+
...style,
|
|
44
|
+
}, ...rest, children: children }));
|
|
45
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type JimboTooltipMode = 'snap' | 'mouse';
|
|
3
|
+
export type JimboTooltipPlacement = 'top' | 'bottom' | 'auto';
|
|
4
|
+
export interface JimboTooltipProps {
|
|
5
|
+
/** Content rendered inside the tooltip panel. Typically a card's ability text, joker description, etc. */
|
|
6
|
+
content: React.ReactNode;
|
|
7
|
+
/** The target element the tooltip anchors to. */
|
|
8
|
+
children: React.ReactElement;
|
|
9
|
+
/** `snap` (default): tooltip sits above/below the target's bounding rect.
|
|
10
|
+
* `mouse`: tooltip follows the mouse position while hovering. */
|
|
11
|
+
mode?: JimboTooltipMode;
|
|
12
|
+
/** Only used in `snap` mode. Default `auto` picks top if there's room, else bottom. */
|
|
13
|
+
placement?: JimboTooltipPlacement;
|
|
14
|
+
/** Hover delay in ms before the tooltip appears. Default 80. */
|
|
15
|
+
delay?: number;
|
|
16
|
+
/** Max width of the tooltip panel (px). Default 280. */
|
|
17
|
+
maxWidth?: number;
|
|
18
|
+
/** Disable the tooltip entirely (e.g. when the target is disabled). */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Canonical Balatro-style tooltip: dark panel, silver border, pixel font.
|
|
23
|
+
* Wrap any target to get a hover/focus popover.
|
|
24
|
+
*
|
|
25
|
+
* <JimboTooltip content={<JimboText size="sm">Gains +4 mult per face card</JimboText>}>
|
|
26
|
+
* <GameCard joker="Blueprint" />
|
|
27
|
+
* </JimboTooltip>
|
|
28
|
+
*
|
|
29
|
+
* Modes:
|
|
30
|
+
* - `snap` (default): anchored to the target's bounding rect, chooses
|
|
31
|
+
* top or bottom automatically so it stays in viewport.
|
|
32
|
+
* - `mouse`: follows the mouse position — useful for large targets
|
|
33
|
+
* (full card fans, zone rails) where "above the element" is imprecise.
|
|
34
|
+
*/
|
|
35
|
+
export declare function JimboTooltip({ content, children, mode, placement, delay, maxWidth, disabled, }: JimboTooltipProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { JimboColorOption } from './tokens.js';
|
|
5
|
+
/**
|
|
6
|
+
* Canonical Balatro-style tooltip: dark panel, silver border, pixel font.
|
|
7
|
+
* Wrap any target to get a hover/focus popover.
|
|
8
|
+
*
|
|
9
|
+
* <JimboTooltip content={<JimboText size="sm">Gains +4 mult per face card</JimboText>}>
|
|
10
|
+
* <GameCard joker="Blueprint" />
|
|
11
|
+
* </JimboTooltip>
|
|
12
|
+
*
|
|
13
|
+
* Modes:
|
|
14
|
+
* - `snap` (default): anchored to the target's bounding rect, chooses
|
|
15
|
+
* top or bottom automatically so it stays in viewport.
|
|
16
|
+
* - `mouse`: follows the mouse position — useful for large targets
|
|
17
|
+
* (full card fans, zone rails) where "above the element" is imprecise.
|
|
18
|
+
*/
|
|
19
|
+
export function JimboTooltip({ content, children, mode = 'snap', placement = 'auto', delay = 80, maxWidth = 280, disabled = false, }) {
|
|
20
|
+
const [visible, setVisible] = useState(false);
|
|
21
|
+
const [pos, setPos] = useState(null);
|
|
22
|
+
const targetRef = useRef(null);
|
|
23
|
+
const tooltipRef = useRef(null);
|
|
24
|
+
const delayTimerRef = useRef(null);
|
|
25
|
+
useEffect(() => () => {
|
|
26
|
+
if (delayTimerRef.current)
|
|
27
|
+
clearTimeout(delayTimerRef.current);
|
|
28
|
+
}, []);
|
|
29
|
+
const show = () => {
|
|
30
|
+
if (disabled)
|
|
31
|
+
return;
|
|
32
|
+
if (delayTimerRef.current)
|
|
33
|
+
clearTimeout(delayTimerRef.current);
|
|
34
|
+
delayTimerRef.current = setTimeout(() => setVisible(true), delay);
|
|
35
|
+
};
|
|
36
|
+
const hide = () => {
|
|
37
|
+
if (delayTimerRef.current)
|
|
38
|
+
clearTimeout(delayTimerRef.current);
|
|
39
|
+
setVisible(false);
|
|
40
|
+
setPos(null);
|
|
41
|
+
};
|
|
42
|
+
const computeSnapPos = () => {
|
|
43
|
+
const el = targetRef.current;
|
|
44
|
+
const tip = tooltipRef.current;
|
|
45
|
+
if (!el || !tip)
|
|
46
|
+
return;
|
|
47
|
+
const rect = el.getBoundingClientRect();
|
|
48
|
+
const tipRect = tip.getBoundingClientRect();
|
|
49
|
+
const roomAbove = rect.top;
|
|
50
|
+
const align = placement === 'top' ? 'top'
|
|
51
|
+
: placement === 'bottom' ? 'bottom'
|
|
52
|
+
: roomAbove >= tipRect.height + 12 ? 'top' : 'bottom';
|
|
53
|
+
const left = rect.left + rect.width / 2 - tipRect.width / 2;
|
|
54
|
+
const top = align === 'top' ? rect.top - tipRect.height - 8 : rect.bottom + 8;
|
|
55
|
+
setPos({ left: Math.max(8, Math.min(window.innerWidth - tipRect.width - 8, left)), top, align });
|
|
56
|
+
};
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!visible || mode !== 'snap')
|
|
59
|
+
return;
|
|
60
|
+
// Recompute after the tooltip renders so its size is known.
|
|
61
|
+
const raf = requestAnimationFrame(computeSnapPos);
|
|
62
|
+
window.addEventListener('resize', computeSnapPos);
|
|
63
|
+
window.addEventListener('scroll', computeSnapPos, true);
|
|
64
|
+
return () => {
|
|
65
|
+
cancelAnimationFrame(raf);
|
|
66
|
+
window.removeEventListener('resize', computeSnapPos);
|
|
67
|
+
window.removeEventListener('scroll', computeSnapPos, true);
|
|
68
|
+
};
|
|
69
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
|
+
}, [visible, mode, placement]);
|
|
71
|
+
const handleMouseMove = (e) => {
|
|
72
|
+
if (mode !== 'mouse')
|
|
73
|
+
return;
|
|
74
|
+
setPos({ left: e.clientX + 12, top: e.clientY + 16, align: 'bottom' });
|
|
75
|
+
};
|
|
76
|
+
const child = React.Children.only(children);
|
|
77
|
+
const refHandler = (node) => {
|
|
78
|
+
targetRef.current = node;
|
|
79
|
+
const childRef = child.ref;
|
|
80
|
+
if (typeof childRef === 'function')
|
|
81
|
+
childRef(node);
|
|
82
|
+
else if (childRef && 'current' in childRef)
|
|
83
|
+
childRef.current = node;
|
|
84
|
+
};
|
|
85
|
+
const wrapped = React.cloneElement(child, {
|
|
86
|
+
ref: refHandler,
|
|
87
|
+
onMouseEnter: (e) => { show(); child.props.onMouseEnter?.(e); },
|
|
88
|
+
onMouseLeave: (e) => { hide(); child.props.onMouseLeave?.(e); },
|
|
89
|
+
onFocus: (e) => { show(); child.props.onFocus?.(e); },
|
|
90
|
+
onBlur: (e) => { hide(); child.props.onBlur?.(e); },
|
|
91
|
+
onMouseMove: (e) => { handleMouseMove(e); child.props.onMouseMove?.(e); },
|
|
92
|
+
});
|
|
93
|
+
return (_jsxs(_Fragment, { children: [wrapped, visible ? (_jsx("div", { ref: tooltipRef, role: "tooltip", style: {
|
|
94
|
+
position: 'fixed',
|
|
95
|
+
left: pos?.left ?? -9999,
|
|
96
|
+
top: pos?.top ?? -9999,
|
|
97
|
+
maxWidth,
|
|
98
|
+
padding: '6px 10px',
|
|
99
|
+
borderRadius: 6,
|
|
100
|
+
background: JimboColorOption.DARKEST,
|
|
101
|
+
border: `2px solid ${JimboColorOption.BORDER_SILVER}`,
|
|
102
|
+
boxShadow: `0 2px 0 ${JimboColorOption.BLACK}cc`,
|
|
103
|
+
color: JimboColorOption.WHITE,
|
|
104
|
+
pointerEvents: 'none',
|
|
105
|
+
zIndex: 10000,
|
|
106
|
+
opacity: pos ? 1 : 0,
|
|
107
|
+
transition: 'opacity 120ms ease',
|
|
108
|
+
}, children: content })) : null] }));
|
|
109
|
+
}
|
package/dist/ui/panel.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useEffect, useRef, memo } from 'react';
|
|
4
4
|
import { JimboColorOption, JIMBO_ANIMATIONS } from './tokens.js';
|
|
5
|
+
import { JimboText } from './jimboText.js';
|
|
5
6
|
export const JimboPanel = memo(({ children, className = '', sway = false, onBack, hideBack = false, style, ...props }) => {
|
|
6
7
|
const panelRef = useRef(null);
|
|
7
8
|
useEffect(() => {
|
|
@@ -44,7 +45,7 @@ export function JimboButton({ tone = 'orange', size = 'md', fullWidth = false, d
|
|
|
44
45
|
const [pressed, setPressed] = useState(false);
|
|
45
46
|
const [fg, sh] = JIMBO_TONE_PAIRS[tone] ?? JIMBO_TONE_PAIRS.orange;
|
|
46
47
|
const pad = size === 'xs' ? '2px 8px' : size === 'sm' ? '4px 10px' : size === 'lg' ? '14px 18px' : '9px 14px';
|
|
47
|
-
const
|
|
48
|
+
const textSize = size === 'xs' ? 'xs' : size === 'sm' ? 'sm' : size === 'lg' ? 'lg' : 'md';
|
|
48
49
|
return (_jsxs("div", { onMouseDown: () => { if (!disabled)
|
|
49
50
|
setPressed(true); }, onMouseUp: () => setPressed(false), onMouseLeave: () => setPressed(false), onTouchStart: () => { if (!disabled)
|
|
50
51
|
setPressed(true); }, onTouchEnd: () => setPressed(false), onClick: () => { if (!disabled)
|
|
@@ -53,10 +54,7 @@ export function JimboButton({ tone = 'orange', size = 'md', fullWidth = false, d
|
|
|
53
54
|
transform: pressed ? 'translate(1px, 3px)' : 'translate(0,0)',
|
|
54
55
|
transition: 'transform 55ms linear',
|
|
55
56
|
textAlign: 'center',
|
|
56
|
-
|
|
57
|
-
color: '#fff', textShadow: '1px 1px 0 rgba(0,0,0,0.8)',
|
|
58
|
-
textTransform: 'uppercase', lineHeight: 1.1,
|
|
59
|
-
}, children: children })] }));
|
|
57
|
+
}, children: _jsx(JimboText, { size: textSize, uppercase: true, children: children }) })] }));
|
|
60
58
|
}
|
|
61
59
|
export function JimboBackButton({ onClick }) {
|
|
62
60
|
return (_jsx("div", { style: { display: 'flex', justifyContent: 'center', width: '100%', padding: '8px 10px 10px' }, children: _jsx(JimboButton, { tone: "orange", size: "md", onClick: onClick, style: { width: '66.666%' }, children: "Back" }) }));
|
|
@@ -77,5 +75,5 @@ export function JimboModal({ children, open, onClose, title, className }) {
|
|
|
77
75
|
}, [open]);
|
|
78
76
|
if (!visible)
|
|
79
77
|
return null;
|
|
80
|
-
return (_jsx("div", { style: { position: 'fixed', inset: 0, zIndex: 50, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '1rem', background: 'rgba(0,0,0,0.7)', opacity, transition: `opacity ${JIMBO_ANIMATIONS.MENU_SINK_DURATION}ms ease` }, onClick: onClose, children: _jsxs(JimboPanel, { sway: true, onBack: onClose, className: 'w-full flex flex-col max-h-[90vh] ' + (className ?? 'max-w-lg'), onClick: (e) => e.stopPropagation(), children: [title && _jsx(
|
|
78
|
+
return (_jsx("div", { style: { position: 'fixed', inset: 0, zIndex: 50, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '1rem', background: 'rgba(0,0,0,0.7)', opacity, transition: `opacity ${JIMBO_ANIMATIONS.MENU_SINK_DURATION}ms ease` }, onClick: onClose, children: _jsxs(JimboPanel, { sway: true, onBack: onClose, className: 'w-full flex flex-col max-h-[90vh] ' + (className ?? 'max-w-lg'), onClick: (e) => e.stopPropagation(), children: [title && _jsx(JimboText, { as: "h2", size: "lg", style: { textAlign: 'center', margin: '0 0 1rem' }, children: title }), children] }) }));
|
|
81
79
|
}
|
package/dist/ui/tokens.d.ts
CHANGED
|
@@ -61,10 +61,11 @@ export declare const JIMBO_ANIMATIONS: {
|
|
|
61
61
|
readonly CARD_TILT_MAX: 6;
|
|
62
62
|
readonly MENU_SINK_DURATION: 200;
|
|
63
63
|
readonly MENU_RISE_DURATION: 300;
|
|
64
|
+
readonly MENU_ORBIT_DURATION: 320;
|
|
64
65
|
readonly LETTER_POP_RATE: 3;
|
|
65
66
|
readonly LETTER_BUMP_RATE: 2.666;
|
|
66
67
|
};
|
|
67
|
-
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'back' | 'ghost';
|
|
68
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'action' | 'back' | 'ghost';
|
|
68
69
|
export declare const BUTTON_COLORS: Record<ButtonVariant, {
|
|
69
70
|
bg: string;
|
|
70
71
|
hover: string;
|
package/dist/ui/tokens.js
CHANGED
|
@@ -66,6 +66,7 @@ export const JIMBO_ANIMATIONS = {
|
|
|
66
66
|
CARD_TILT_MAX: 6,
|
|
67
67
|
MENU_SINK_DURATION: 200,
|
|
68
68
|
MENU_RISE_DURATION: 300,
|
|
69
|
+
MENU_ORBIT_DURATION: 320,
|
|
69
70
|
LETTER_POP_RATE: 3,
|
|
70
71
|
LETTER_BUMP_RATE: 2.666,
|
|
71
72
|
};
|
|
@@ -73,6 +74,7 @@ export const BUTTON_COLORS = {
|
|
|
73
74
|
primary: { bg: JimboColorOption.RED, hover: JimboColorOption.DARK_RED, text: JimboColorOption.WHITE },
|
|
74
75
|
secondary: { bg: JimboColorOption.BLUE, hover: JimboColorOption.DARK_BLUE, text: JimboColorOption.WHITE },
|
|
75
76
|
danger: { bg: JimboColorOption.RED, hover: JimboColorOption.DARK_RED, text: JimboColorOption.WHITE },
|
|
77
|
+
action: { bg: JimboColorOption.RED, hover: JimboColorOption.DARK_RED, text: JimboColorOption.WHITE },
|
|
76
78
|
back: { bg: JimboColorOption.ORANGE, hover: JimboColorOption.DARK_ORANGE, text: JimboColorOption.WHITE },
|
|
77
79
|
ghost: { bg: 'transparent', hover: 'rgba(255,255,255,0.1)', text: JimboColorOption.WHITE },
|
|
78
80
|
};
|
package/dist/ui.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export * from './ui/tokens.js';
|
|
2
|
+
export * from './ui/jimboText.js';
|
|
2
3
|
export * from './ui/panel.js';
|
|
4
|
+
export * from './ui/jimboTabs.js';
|
|
5
|
+
export * from './ui/jimboFlankNav.js';
|
|
6
|
+
export * from './ui/jimboFilterBar.js';
|
|
7
|
+
export * from './ui/jimboBackground.js';
|
|
8
|
+
export * from './ui/jimboTooltip.js';
|
|
3
9
|
export * from './ui/codeBlock.js';
|
|
4
10
|
export * from './ui/footer.js';
|
|
5
11
|
export * from './ui/sprites.js';
|
package/dist/ui.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export * from './ui/tokens.js';
|
|
2
|
+
export * from './ui/jimboText.js';
|
|
2
3
|
export * from './ui/panel.js';
|
|
4
|
+
export * from './ui/jimboTabs.js';
|
|
5
|
+
export * from './ui/jimboFlankNav.js';
|
|
6
|
+
export * from './ui/jimboFilterBar.js';
|
|
7
|
+
export * from './ui/jimboBackground.js';
|
|
8
|
+
export * from './ui/jimboTooltip.js';
|
|
3
9
|
export * from './ui/codeBlock.js';
|
|
4
10
|
export * from './ui/footer.js';
|
|
5
11
|
export * from './ui/sprites.js';
|