@ramme-io/ui 4.0.1 → 4.1.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.
- package/README.md +159 -7
- package/dist/blocks/ai/Actions.js +2 -2
- package/dist/blocks/ai/PromptInput.js +6 -6
- package/dist/component-registry.js +389 -359
- package/dist/components/ai/AIChatThread/AIChatThread.js +81 -73
- package/dist/components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard.d.ts +28 -0
- package/dist/components/ai/ArchitectureReferenceCard/ArchitectureReferenceCard.js +70 -0
- package/dist/components/ai/ArchitectureReferenceCard/index.d.ts +2 -0
- package/dist/components/ai/CounterpartyGraphCard/CounterpartyGraphCard.d.ts +30 -0
- package/dist/components/ai/CounterpartyGraphCard/CounterpartyGraphCard.js +82 -0
- package/dist/components/ai/CounterpartyGraphCard/index.d.ts +2 -0
- package/dist/components/ai/DivergenceMetricsCard/DivergenceMetricsCard.d.ts +29 -0
- package/dist/components/ai/DivergenceMetricsCard/DivergenceMetricsCard.js +69 -0
- package/dist/components/ai/DivergenceMetricsCard/index.d.ts +2 -0
- package/dist/components/ai/KeyInjectionOverlay.d.ts +10 -0
- package/dist/components/ai/KeyInjectionOverlay.js +11 -11
- package/dist/components/ai/NewsSummaryCard/NewsSummaryCard.js +17 -17
- package/dist/components/ai/StockChart/StockChart.js +4 -4
- package/dist/components/auth/AuthLayout.js +4 -4
- package/dist/components/auth/LoginPage.d.ts +22 -0
- package/dist/components/auth/LoginPage.js +50 -42
- package/dist/components/data-display/CodeBlock.d.ts +33 -7
- package/dist/components/data-display/CodeBlock.js +134 -41
- package/dist/components/data-display/Table.js +8 -8
- package/dist/components/feedback/EmptyState.js +9 -9
- package/dist/components/feedback/ToastProvider.js +4 -4
- package/dist/components/forms/Checkbox.js +5 -5
- package/dist/components/forms/ComboBox.js +2 -2
- package/dist/components/forms/DatePicker.js +37 -32
- package/dist/components/forms/FileUpload.js +39 -37
- package/dist/components/forms/Input.js +19 -18
- package/dist/components/forms/MultiSelect.js +9 -8
- package/dist/components/forms/Radio.js +6 -6
- package/dist/components/forms/SegmentedControl.d.ts +1 -1
- package/dist/components/forms/SegmentedControl.js +28 -11
- package/dist/components/forms/Select.js +9 -8
- package/dist/components/forms/Textarea.d.ts +13 -11
- package/dist/components/forms/Textarea.js +36 -16
- package/dist/components/forms/ToggleSwitch.js +9 -9
- package/dist/components/layout/AboutRamme.d.ts +8 -0
- package/dist/components/layout/Accordion.js +25 -32
- package/dist/components/layout/AppShell.js +7 -7
- package/dist/components/layout/Card.js +38 -21
- package/dist/components/layout/DetailDrawer.js +37 -38
- package/dist/components/layout/Drawer.js +50 -51
- package/dist/components/layout/List.js +9 -9
- package/dist/components/layout/Modal.js +5 -5
- package/dist/components/layout/PageHeader.js +7 -7
- package/dist/components/layout/SectionHeader.js +4 -4
- package/dist/components/layout/SettingsContainer.d.ts +12 -0
- package/dist/components/layout/SettingsContainer.js +30 -18
- package/dist/components/layout/Sheet.d.ts +58 -0
- package/dist/components/layout/Sheet.js +144 -0
- package/dist/components/layout/Sidebar.js +1 -1
- package/dist/components/layout/UserNav.d.ts +13 -0
- package/dist/components/layout/UserNav.js +17 -17
- package/dist/components/molecular/ConnectorOverlay.d.ts +12 -0
- package/dist/components/navigation/Breadcrumbs.js +8 -8
- package/dist/components/navigation/Menu.js +6 -6
- package/dist/components/navigation/MobileNav.d.ts +44 -1
- package/dist/components/navigation/MobileNav.js +97 -71
- package/dist/components/navigation/Pagination.js +46 -41
- package/dist/components/navigation/Stepper.js +17 -17
- package/dist/components/navigation/Tabs.js +18 -11
- package/dist/components/theme/ThemeLab.d.ts +7 -1
- package/dist/components/theme/ThemeLab.js +175 -154
- package/dist/components/ui/icon-loader.d.ts +1 -1
- package/dist/contexts/ThemeContext.js +111 -82
- package/dist/data/mockData.d.ts +0 -3
- package/dist/index.css +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +222 -197
- package/dist/lib/hooks/useBodyScrollLock.d.ts +27 -0
- package/dist/lib/hooks/useBodyScrollLock.js +18 -0
- package/dist/lib/hooks/useSheetGesture.d.ts +81 -0
- package/dist/lib/hooks/useSheetGesture.js +70 -0
- package/dist/lib/theme/themeUtils.d.ts +21 -0
- package/dist/lib/theme/themeUtils.js +31 -17
- package/dist/setupTests.d.ts +1 -0
- package/dist/wizardManifest.js +364 -19
- package/package.json +10 -4
- package/src/wizardManifest.ts +364 -19
- package/tailwind.preset.js +98 -10
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gesture behind a bottom sheet.
|
|
3
|
+
*
|
|
4
|
+
* This is the library's first pointer-driven interaction. Nothing else in
|
|
5
|
+
* @ramme-io/ui uses Pointer Events at all — every interactive component is an
|
|
6
|
+
* HTML form element — so the rules it establishes are worth stating once:
|
|
7
|
+
*
|
|
8
|
+
* - **Pointer Events only.** One code path for touch, mouse, pen and trackpad.
|
|
9
|
+
* Separate `mousemove` and `touchmove` handlers are how you end up with a
|
|
10
|
+
* control that works on one and jitters on the other.
|
|
11
|
+
* - **`setPointerCapture`.** A drag must survive the finger leaving the
|
|
12
|
+
* element. Without capture, dragging a sheet up past its own top edge stops
|
|
13
|
+
* tracking, which reads as the sheet sticking.
|
|
14
|
+
* - **`touch-action: none`** on the drag surface, applied by the component.
|
|
15
|
+
* Without it the browser claims the gesture for scrolling and the sheet
|
|
16
|
+
* never moves.
|
|
17
|
+
*
|
|
18
|
+
* WHY THE SETTLE MATH IS A PURE FUNCTION
|
|
19
|
+
*
|
|
20
|
+
* jsdom has no layout and cannot drag, so the only honest way to test a gesture
|
|
21
|
+
* is to make its decisions independent of the DOM. `settleTo` below takes
|
|
22
|
+
* numbers and returns a number; every interesting rule — flick beats position,
|
|
23
|
+
* dragging below the smallest detent dismisses, a slow drag snaps to nearest —
|
|
24
|
+
* is checkable without a browser.
|
|
25
|
+
*/
|
|
26
|
+
/** Pixels per millisecond past which a drag counts as a flick rather than a move. */
|
|
27
|
+
export declare const FLICK_VELOCITY = 0.5;
|
|
28
|
+
/**
|
|
29
|
+
* How far below the smallest detent the sheet must be dragged before release
|
|
30
|
+
* dismisses it. Expressed as a fraction of the viewport so it scales with the
|
|
31
|
+
* screen rather than being generous on a tablet and twitchy on a phone.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DISMISS_THRESHOLD = 0.12;
|
|
34
|
+
export interface SettleInput {
|
|
35
|
+
/** Current height of the sheet as a fraction of the viewport, 0–1. */
|
|
36
|
+
current: number;
|
|
37
|
+
/** Allowed resting heights, ascending fractions of the viewport. */
|
|
38
|
+
detents: number[];
|
|
39
|
+
/**
|
|
40
|
+
* Vertical velocity in px/ms. NEGATIVE is upward (the sheet growing), matching
|
|
41
|
+
* pointer coordinates where y decreases toward the top of the screen.
|
|
42
|
+
*/
|
|
43
|
+
velocity: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Where the sheet should come to rest when the finger lifts.
|
|
47
|
+
*
|
|
48
|
+
* Returns the target detent, or `null` meaning "dismiss".
|
|
49
|
+
*
|
|
50
|
+
* Order matters: a flick is honoured before position, because a fast downward
|
|
51
|
+
* flick from near the top should close the sheet rather than snap it to the
|
|
52
|
+
* detent it happens to be nearest. That is what every native sheet does, and
|
|
53
|
+
* getting it backwards makes the sheet feel like it is fighting you.
|
|
54
|
+
*/
|
|
55
|
+
export declare function settleTo({ current, detents, velocity }: SettleInput): number | null;
|
|
56
|
+
export interface SheetGestureOptions {
|
|
57
|
+
detents: number[];
|
|
58
|
+
initialDetent?: number;
|
|
59
|
+
onDismiss: () => void;
|
|
60
|
+
/** Skips the drag entirely; the sheet still opens and closes, just without motion. */
|
|
61
|
+
reducedMotion?: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface SheetGesture {
|
|
64
|
+
/** Current height as a fraction of the viewport. */
|
|
65
|
+
height: number;
|
|
66
|
+
/** True while a finger is down — the component uses this to drop its transition. */
|
|
67
|
+
dragging: boolean;
|
|
68
|
+
/** True when the sheet is at its tallest detent. */
|
|
69
|
+
expanded: boolean;
|
|
70
|
+
/** Attach to the grabber and header. */
|
|
71
|
+
onPointerDown: (e: React.PointerEvent) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Attach to the scrollable body. Implements the behaviour the pattern is
|
|
74
|
+
* named for: at a partial detent, dragging up grows the sheet instead of
|
|
75
|
+
* scrolling; once expanded, the content scrolls normally; and at the top of
|
|
76
|
+
* the content, dragging down shrinks the sheet again.
|
|
77
|
+
*/
|
|
78
|
+
onBodyPointerDown: (e: React.PointerEvent) => void;
|
|
79
|
+
setHeight: (h: number) => void;
|
|
80
|
+
}
|
|
81
|
+
export declare function useSheetGesture({ detents, initialDetent, onDismiss, reducedMotion, }: SheetGestureOptions): SheetGesture;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useState as M, useRef as u, useCallback as T, useEffect as C } from "react";
|
|
2
|
+
const D = 0.5, P = 0.12;
|
|
3
|
+
function y({ current: l, detents: f, velocity: a }) {
|
|
4
|
+
if (!f.length) return null;
|
|
5
|
+
const s = [...f].sort((r, e) => r - e), n = s[0], c = s[s.length - 1];
|
|
6
|
+
if (Math.abs(a) >= D) {
|
|
7
|
+
if (a > 0) {
|
|
8
|
+
const e = s.filter((g) => g < l - 0.01);
|
|
9
|
+
return e.length ? e[e.length - 1] : null;
|
|
10
|
+
}
|
|
11
|
+
const r = s.filter((e) => e > l + 0.01);
|
|
12
|
+
return r.length ? r[0] : c;
|
|
13
|
+
}
|
|
14
|
+
return l < n - P ? null : s.reduce(
|
|
15
|
+
(r, e) => Math.abs(e - l) < Math.abs(r - l) ? e : r
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
function R({
|
|
19
|
+
detents: l,
|
|
20
|
+
initialDetent: f = 0,
|
|
21
|
+
onDismiss: a,
|
|
22
|
+
reducedMotion: s = !1
|
|
23
|
+
}) {
|
|
24
|
+
const n = [...l].sort((t, i) => t - i), [c, r] = M(n[f] ?? n[0]), [e, g] = M(!1), L = u(0), S = u(0), w = u(0), v = u(0), E = u(0), d = u(null), h = T(
|
|
25
|
+
(t, i) => {
|
|
26
|
+
if (!s && t.isPrimary) {
|
|
27
|
+
if (d.current = i ? t.currentTarget : null, i) {
|
|
28
|
+
const o = t.currentTarget.scrollTop <= 0;
|
|
29
|
+
if (c >= n[n.length - 1] - 1e-3 && !o) return;
|
|
30
|
+
}
|
|
31
|
+
L.current = t.clientY, w.current = t.clientY, v.current = t.timeStamp, S.current = c, E.current = 0, g(!0), t.currentTarget.setPointerCapture(t.pointerId);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
[c, s, n]
|
|
35
|
+
), b = T((t) => h(t, !1), [h]), H = T((t) => h(t, !0), [h]);
|
|
36
|
+
return C(() => {
|
|
37
|
+
if (!e) return;
|
|
38
|
+
const t = (o) => {
|
|
39
|
+
const Y = window.innerHeight || 1, I = o.clientY - L.current, x = o.timeStamp - v.current;
|
|
40
|
+
x > 0 && (E.current = (o.clientY - w.current) / x), w.current = o.clientY, v.current = o.timeStamp;
|
|
41
|
+
let p = S.current - I / Y;
|
|
42
|
+
const m = n[n.length - 1];
|
|
43
|
+
p > m && (p = m + (p - m) * 0.25), r(Math.max(0, Math.min(p, m + 0.05))), d.current && (d.current.scrollTop = 0);
|
|
44
|
+
}, i = () => {
|
|
45
|
+
g(!1);
|
|
46
|
+
const o = y({
|
|
47
|
+
current: c,
|
|
48
|
+
detents: n,
|
|
49
|
+
velocity: E.current
|
|
50
|
+
});
|
|
51
|
+
o === null ? a() : r(o), d.current = null;
|
|
52
|
+
};
|
|
53
|
+
return window.addEventListener("pointermove", t), window.addEventListener("pointerup", i), window.addEventListener("pointercancel", i), () => {
|
|
54
|
+
window.removeEventListener("pointermove", t), window.removeEventListener("pointerup", i), window.removeEventListener("pointercancel", i);
|
|
55
|
+
};
|
|
56
|
+
}, [e, c, a, n]), {
|
|
57
|
+
height: c,
|
|
58
|
+
dragging: e,
|
|
59
|
+
expanded: c >= n[n.length - 1] - 1e-3,
|
|
60
|
+
onPointerDown: b,
|
|
61
|
+
onBodyPointerDown: H,
|
|
62
|
+
setHeight: r
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
P as DISMISS_THRESHOLD,
|
|
67
|
+
D as FLICK_VELOCITY,
|
|
68
|
+
y as settleTo,
|
|
69
|
+
R as useSheetGesture
|
|
70
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_THEME_TOKENS } from '@ramme-io/shared';
|
|
1
2
|
/**
|
|
2
3
|
* Advanced Contrast Guard
|
|
3
4
|
* Adjusts for perceived darkness (like scanline overlays)
|
|
@@ -14,6 +15,26 @@ export declare const loadGoogleFont: (headingFont: string, bodyFont: string) =>
|
|
|
14
15
|
* @example hexToRgbTriplet('#0D6EFD') → '13 110 253'
|
|
15
16
|
*/
|
|
16
17
|
export declare const hexToRgbTriplet: (hex: string) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Every CSS variable `tokensToVars` writes.
|
|
20
|
+
*
|
|
21
|
+
* Exported so the code that removes them cannot drift from the code that adds
|
|
22
|
+
* them — RULE-005 asks for symmetrical purging, and these six were injected on
|
|
23
|
+
* to documentElement.style and never removed by anything.
|
|
24
|
+
*/
|
|
25
|
+
export declare const THEME_TOKEN_VARS: readonly ["--app-primary-color", "--app-secondary-color", "--app-success-color", "--app-warning-color", "--app-danger-color", "--app-border-radius-md"];
|
|
26
|
+
/**
|
|
27
|
+
* Has the visitor actually themed anything?
|
|
28
|
+
*
|
|
29
|
+
* `activeTheme`/`savedTheme` are always populated — they are seeded with
|
|
30
|
+
* DEFAULT_THEME_TOKENS — so their presence proves nothing. Only a value that
|
|
31
|
+
* differs from those defaults means a real choice was made.
|
|
32
|
+
*
|
|
33
|
+
* Every place that decides whether to paint the user's layer must agree, or the
|
|
34
|
+
* layers fight: injecting unconditionally painted the framework's defaults over
|
|
35
|
+
* the app's own theme for every first-time visitor.
|
|
36
|
+
*/
|
|
37
|
+
export declare const isCustomTheme: (tokens: Partial<Record<keyof typeof DEFAULT_THEME_TOKENS, string>> | null | undefined) => boolean;
|
|
17
38
|
export declare const tokensToVars: (t: Partial<{
|
|
18
39
|
primary: string;
|
|
19
40
|
neutral: string;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import { DEFAULT_THEME_TOKENS as d } from "@ramme-io/shared";
|
|
1
2
|
const m = (o, p) => {
|
|
2
3
|
const a = o.split(" ").map(Number);
|
|
3
4
|
if (a.length !== 3) return o;
|
|
4
5
|
const r = (t) => Math.max(0, Math.min(255, t));
|
|
5
6
|
return `${r(a[0] + p)} ${r(a[1] + p)} ${r(a[2] + p)}`;
|
|
6
|
-
},
|
|
7
|
+
}, g = (o) => {
|
|
7
8
|
const [p, a, r] = o.split(" ").map(Number);
|
|
8
9
|
return (0.2126 * p + 0.7152 * a + 0.0722 * r) / 255 > 0.45 ? "15 23 42" : "255 255 255";
|
|
9
|
-
},
|
|
10
|
+
}, f = (o, p) => {
|
|
10
11
|
if (!o || typeof o != "object") return;
|
|
11
12
|
const a = p || document.documentElement, r = { ...o }, t = r["--app-primary-color"];
|
|
12
|
-
t && (r["--app-primary-foreground-color"] =
|
|
13
|
+
t && (r["--app-primary-foreground-color"] = g(t));
|
|
13
14
|
const l = r["--app-bg-color"];
|
|
14
|
-
l && (r["--app-text-color"] =
|
|
15
|
+
l && (r["--app-text-color"] = g(l)), Object.entries({
|
|
15
16
|
"--primary": "--app-primary-color",
|
|
16
17
|
"--bg": "--app-bg-color",
|
|
17
18
|
"--text": "--app-text-color",
|
|
@@ -32,33 +33,44 @@ const m = (o, p) => {
|
|
|
32
33
|
].join(", "), r["--app-secondary-color"] || (r["--app-secondary-color"] = "100 116 139"), r["--app-accent-color"] || (r["--app-accent-color"] = r["--app-primary-color"]), r["--app-input-bg-color"] || (r["--app-input-bg-color"] = r["--app-card-bg-color"]), r["--app-input-border-color"] || (r["--app-input-border-color"] = r["--app-border-color"]), r["--app-border-radius-md"] || (r["--app-border-radius-md"] = "0.375rem"), Object.entries(r).forEach(([s, i]) => {
|
|
33
34
|
s.startsWith("--app-") && a.style.setProperty(s, String(i));
|
|
34
35
|
});
|
|
35
|
-
},
|
|
36
|
+
}, b = (o, p) => {
|
|
36
37
|
const a = document.head, r = "dynamic-google-fonts", t = document.getElementById(r);
|
|
37
38
|
t && a.removeChild(t);
|
|
38
39
|
const l = `${o.replace(/ /g, "+")}:wght@400;700&family=${p.replace(/ /g, "+")}:wght@400;500;700`, n = document.createElement("link");
|
|
39
40
|
n.id = r, n.rel = "stylesheet", n.crossOrigin = "anonymous", n.href = `https://fonts.googleapis.com/css2?family=${l}&display=swap`, a.insertBefore(n, a.firstChild);
|
|
40
41
|
const e = document.documentElement;
|
|
41
42
|
e.style.setProperty("--app-font-sans", `"${p}", sans-serif`), e.style.setProperty("--app-font-serif", `"${o}", serif`), console.log(`[FontEngine] Applied: ${o} (H) / ${p} (B)`);
|
|
42
|
-
},
|
|
43
|
+
}, y = (o) => {
|
|
43
44
|
const p = o.replace("#", ""), a = parseInt(p.substring(0, 2), 16), r = parseInt(p.substring(2, 4), 16), t = parseInt(p.substring(4, 6), 16);
|
|
44
45
|
return `${a} ${r} ${t}`;
|
|
45
|
-
},
|
|
46
|
+
}, u = {
|
|
46
47
|
none: "0",
|
|
47
48
|
sm: "0.25rem",
|
|
48
49
|
md: "0.375rem",
|
|
49
50
|
lg: "0.5rem",
|
|
50
51
|
full: "9999px"
|
|
51
|
-
},
|
|
52
|
+
}, $ = [
|
|
53
|
+
"--app-primary-color",
|
|
54
|
+
"--app-secondary-color",
|
|
55
|
+
"--app-success-color",
|
|
56
|
+
"--app-warning-color",
|
|
57
|
+
"--app-danger-color",
|
|
58
|
+
"--app-border-radius-md"
|
|
59
|
+
], E = (o) => o ? Object.keys(d).some((p) => o[p] !== void 0 && o[p] !== d[p]) : !1, M = (o) => ({
|
|
52
60
|
"--app-primary-color": o.primary ?? "13 110 253",
|
|
53
61
|
"--app-secondary-color": o.neutral ?? "24 24 27",
|
|
54
62
|
"--app-success-color": o.success ?? "34 197 94",
|
|
55
63
|
"--app-warning-color": o.warning ?? "234 179 8",
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
// NOT `--app-destructive-color`, which this wrote until now: that variable
|
|
65
|
+
// is defined nowhere in index.css and read by nothing, so the Destructive
|
|
66
|
+
// swatch in ThemeLab changed a value no stylesheet consumed. The token the
|
|
67
|
+
// preset actually maps `destructive` on to is `--app-danger-color`.
|
|
68
|
+
"--app-danger-color": o.destructive ?? "239 68 68",
|
|
69
|
+
"--app-border-radius-md": u[o.radius ?? "md"] ?? "0.375rem"
|
|
58
70
|
}), c = (o = 0, p = 255) => {
|
|
59
71
|
const a = Math.floor(Math.random() * (p - o) + o), r = Math.floor(Math.random() * (p - o) + o), t = Math.floor(Math.random() * (p - o) + o);
|
|
60
72
|
return `${a} ${r} ${t}`;
|
|
61
|
-
},
|
|
73
|
+
}, T = () => {
|
|
62
74
|
const o = Math.random() > 0.5, p = o ? c(10, 40) : c(240, 255), a = o ? c(220, 255) : c(20, 60), r = c(50, 200);
|
|
63
75
|
return {
|
|
64
76
|
"--app-primary-color": r,
|
|
@@ -73,11 +85,13 @@ const m = (o, p) => {
|
|
|
73
85
|
};
|
|
74
86
|
};
|
|
75
87
|
export {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
$ as THEME_TOKEN_VARS,
|
|
89
|
+
f as applyThemeToDom,
|
|
90
|
+
T as generateRandomTheme,
|
|
91
|
+
g as getContrastColor,
|
|
92
|
+
y as hexToRgbTriplet,
|
|
93
|
+
E as isCustomTheme,
|
|
94
|
+
b as loadGoogleFont,
|
|
81
95
|
c as randomRgb,
|
|
82
|
-
|
|
96
|
+
M as tokensToVars
|
|
83
97
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|