@graineai/inapp-react-native 0.38.0 → 0.39.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/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/react-native/voice-bar.js +4 -2
- package/dist/react-native/widget.js +8 -3
- package/dist/react-native/window-chrome.d.ts +30 -0
- package/dist/react-native/window-chrome.js +30 -0
- package/dist/theme.d.ts +5 -0
- package/dist/theme.js +122 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -35,5 +35,5 @@ export { GraineLauncherButton, type GraineLauncherButtonProps } from "./react-na
|
|
|
35
35
|
export { faceFor, facesForDesign, fontUrl, FONT_ASSET_VERSION, type FontLoader, type FontFace } from "./react-native/fonts.js";
|
|
36
36
|
export { GraineVoiceLauncher, CAPTION_HISTORY, type GraineVoiceLauncherProps, type GraineVoiceApi, } from "./react-native/voice-launcher.js";
|
|
37
37
|
export { LauncherVisibilityTracker, activeRouteName, type LauncherInset, type LauncherContinuity, type LauncherDelayPolicy, type LauncherGroup, type LauncherVisibility, type VisibilityDecision, } from "./react-native/navigation.js";
|
|
38
|
-
export { DESIGN_PRESETS, DEFAULT_DESIGN_PRESET, DESIGN_FONTS, LAUNCHER_ICONS, SDK_ICONS, designPreset, normaliseDesignConfig, designFromAppearance, resolveTokens, resolveDesign, pickTokens, contrastRatio, readableOn, glyphUrl, type DesignConfig, type DesignPreset, type ThemeTokens, type ThemeColors, type ThemeShadow, type ResolvedDesign, type DesignBubbles, type LauncherShape, type MotionEasing, type IconStyle, type SdkIconName, } from "./theme.js";
|
|
38
|
+
export { DESIGN_PRESETS, DEFAULT_DESIGN_PRESET, DESIGN_FONTS, LAUNCHER_ICONS, SDK_ICONS, DESIGN_CHROMES, designPreset, normaliseDesignConfig, designFromAppearance, resolveTokens, resolveDesign, pickTokens, contrastRatio, readableOn, glyphUrl, type DesignConfig, type DesignPreset, type ThemeTokens, type ThemeColors, type ThemeShadow, type ResolvedDesign, type DesignBubbles, type DesignChrome, type LauncherShape, type MotionEasing, type IconStyle, type SdkIconName, } from "./theme.js";
|
|
39
39
|
export { sessionDesign } from "./design.js";
|
package/dist/index.js
CHANGED
|
@@ -26,5 +26,5 @@ export { GraineLauncherButton } from "./react-native/fab.js";
|
|
|
26
26
|
export { faceFor, facesForDesign, fontUrl, FONT_ASSET_VERSION } from "./react-native/fonts.js";
|
|
27
27
|
export { GraineVoiceLauncher, CAPTION_HISTORY, } from "./react-native/voice-launcher.js";
|
|
28
28
|
export { LauncherVisibilityTracker, activeRouteName, } from "./react-native/navigation.js";
|
|
29
|
-
export { DESIGN_PRESETS, DEFAULT_DESIGN_PRESET, DESIGN_FONTS, LAUNCHER_ICONS, SDK_ICONS, designPreset, normaliseDesignConfig, designFromAppearance, resolveTokens, resolveDesign, pickTokens, contrastRatio, readableOn, glyphUrl, } from "./theme.js";
|
|
29
|
+
export { DESIGN_PRESETS, DEFAULT_DESIGN_PRESET, DESIGN_FONTS, LAUNCHER_ICONS, SDK_ICONS, DESIGN_CHROMES, designPreset, normaliseDesignConfig, designFromAppearance, resolveTokens, resolveDesign, pickTokens, contrastRatio, readableOn, glyphUrl, } from "./theme.js";
|
|
30
30
|
export { sessionDesign } from "./design.js";
|
|
@@ -10,6 +10,7 @@ import { glyphPixels, launcherRadius, letterSpacing, lineHeight, shadowStyle, su
|
|
|
10
10
|
import { useKeyboardLift } from "./keyboard.js";
|
|
11
11
|
import { useDraggablePlacement } from "./placement.js";
|
|
12
12
|
import { glyphUrl, SDK_ICONS } from "../theme.js";
|
|
13
|
+
import { TitleBar, windowed } from "./window-chrome.js";
|
|
13
14
|
const BAR_HEIGHT = 60;
|
|
14
15
|
const BUTTON = 38;
|
|
15
16
|
const METER = [0.55, 1, 0.7, 0.4];
|
|
@@ -184,10 +185,11 @@ function CaptionCard({ look, role, text, live }) {
|
|
|
184
185
|
const t = look.tokens;
|
|
185
186
|
const c = t.colors;
|
|
186
187
|
const rise = useRise(look);
|
|
188
|
+
const win = windowed(t);
|
|
187
189
|
return (_jsx(Animated.View, { style: rise, children: _jsx(Raised, { t: t, level: "card", radius: t.shape.radius.lg, children: _jsxs(View, { style: {
|
|
188
190
|
backgroundColor: surfaceFill(c.surface, t), borderWidth: t.shape.borderWidth, borderColor: c.border,
|
|
189
191
|
borderRadius: t.shape.radius.lg, paddingHorizontal: 12, paddingVertical: 8, ...softShadow(t, "card"),
|
|
190
|
-
}, children: [role === "customer" ? (_jsx(Text, { style: { ...look.face(t.font.body, t.font.weights.strong), color: c.accent, fontSize: 10.5, letterSpacing: 0.6, textTransform: "uppercase", marginBottom: 2 }, children: "You" })) : null, _jsx(Text, { numberOfLines: 2, style: { ...look.face(t.font.body, t.font.weights.strong), color: c.text, fontSize: 13, lineHeight: 17.5, opacity: live ? 0.75 : 1 }, children: text })] }) }) }));
|
|
192
|
+
}, children: [win ? (_jsx(View, { style: { marginBottom: 6 }, children: _jsx(TitleBar, { t: t, title: "captions", size: "caption", radius: t.shape.radius.lg, bleed: { horizontal: 12, top: 8 } }) })) : null, role === "customer" ? (_jsx(Text, { style: { ...look.face(t.font.body, t.font.weights.strong), color: c.accent, fontSize: 10.5, letterSpacing: 0.6, textTransform: "uppercase", marginBottom: 2 }, children: "You" })) : null, _jsx(Text, { numberOfLines: 2, style: { ...look.face(t.font.body, t.font.weights.strong), color: c.text, fontSize: 13, lineHeight: 17.5, opacity: live ? 0.75 : 1 }, children: text })] }) }) }));
|
|
191
193
|
}
|
|
192
194
|
function ChatWindow({ look, kit, origin, heading, logoUrl, messages, send, online, lifted, onCollapse, }) {
|
|
193
195
|
const t = look.tokens;
|
|
@@ -215,7 +217,7 @@ function ChatWindow({ look, kit, origin, heading, logoUrl, messages, send, onlin
|
|
|
215
217
|
letterSpacing: letterSpacing(size, t.font.letterSpacing.body),
|
|
216
218
|
});
|
|
217
219
|
const titleSize = Math.min(t.font.scale.title, 16);
|
|
218
|
-
return (_jsx(Animated.View, { style: rise, children: _jsx(Raised, { t: t, level: "floating", radius: r.xl, children: _jsx(View, { style: { backgroundColor: c.background, borderWidth: bw, borderColor: c.border, borderRadius: r.xl, ...softShadow(t, "floating") }, children: _jsxs(View, { style: { borderRadius: Math.max(0, r.xl - bw), overflow: "hidden" }, children: [_jsxs(View, { style: { height: 50, flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 12, backgroundColor: surfaceFill(c.surface, t), borderBottomWidth: bw, borderBottomColor: c.border }, children: [_jsx(View, { style: { width: 30, height: 30, borderRadius: launcherRadius(markShape, 30, t), backgroundColor: c.accent, alignItems: "center", justifyContent: "center", overflow: "hidden", ...(Platform.OS === "ios" && markShape === "squircle" ? { borderCurve: "continuous" } : null) }, children: _jsx(Mark, { t: t, size: 30, glyph: 14, kit: kit, origin: origin, logoUrl: logoUrl, initial: heading.charAt(0).toUpperCase() || "A" }) }), _jsxs(View, { style: { flex: 1, minWidth: 0 }, children: [_jsx(Text, { numberOfLines: 1, style: { ...look.face(t.font.heading, t.font.weights.title), color: c.text, fontSize: titleSize, lineHeight: lineHeight(titleSize, t.font.lineHeight.title), letterSpacing: letterSpacing(titleSize, t.font.letterSpacing.title) }, children: heading }), _jsxs(View, { style: { flexDirection: "row", alignItems: "center", gap: 4 }, children: [online ? _jsx(View, { style: { width: 6, height: 6, borderRadius: 3, backgroundColor: c.success } }) : null, _jsx(Text, { style: { ...text(t.font.scale.caption, t.font.weights.body), color: c.textMuted, lineHeight: lineHeight(t.font.scale.caption, 1.2) }, children: online ? "Online" : "Connecting…" })] })] }), _jsx(Pressable, { onPress: onCollapse, hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Collapse", children: _jsx(Icon, { name: "chevron", t: t, color: c.textMuted, kit: kit, rotate: true }) })] }), _jsxs(ScrollView, { ref: scroll, style: { maxHeight: lifted ? 150 : 260 }, contentContainerStyle: { padding: 12, gap: t.spacing.gap }, keyboardShouldPersistTaps: "handled", children: [messages.length === 0 ? (_jsx(Text, { style: { ...text(t.font.scale.body, t.font.weights.body), color: c.textMuted, lineHeight: lineHeight(t.font.scale.body, t.font.lineHeight.body) }, children: online ? `${heading} can see what you’re looking at — ask it anything.` : "Connecting…" })) : null, messages.map((m, i) => {
|
|
220
|
+
return (_jsx(Animated.View, { style: rise, children: _jsx(Raised, { t: t, level: "floating", radius: r.xl, children: _jsx(View, { style: { backgroundColor: c.background, borderWidth: bw, borderColor: c.border, borderRadius: r.xl, ...softShadow(t, "floating") }, children: _jsxs(View, { style: { borderRadius: Math.max(0, r.xl - bw), overflow: "hidden" }, children: [windowed(t) ? (_jsx(TitleBar, { t: t, title: heading, online: online, radius: r.xl, right: _jsx(Pressable, { onPress: onCollapse, hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Collapse", children: _jsx(Icon, { name: "chevron", t: t, color: c.textMuted, kit: kit, size: 16, rotate: true }) }) })) : (_jsxs(View, { style: { height: 50, flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 12, backgroundColor: surfaceFill(c.surface, t), borderBottomWidth: bw, borderBottomColor: c.border }, children: [_jsx(View, { style: { width: 30, height: 30, borderRadius: launcherRadius(markShape, 30, t), backgroundColor: c.accent, alignItems: "center", justifyContent: "center", overflow: "hidden", ...(Platform.OS === "ios" && markShape === "squircle" ? { borderCurve: "continuous" } : null) }, children: _jsx(Mark, { t: t, size: 30, glyph: 14, kit: kit, origin: origin, logoUrl: logoUrl, initial: heading.charAt(0).toUpperCase() || "A" }) }), _jsxs(View, { style: { flex: 1, minWidth: 0 }, children: [_jsx(Text, { numberOfLines: 1, style: { ...look.face(t.font.heading, t.font.weights.title), color: c.text, fontSize: titleSize, lineHeight: lineHeight(titleSize, t.font.lineHeight.title), letterSpacing: letterSpacing(titleSize, t.font.letterSpacing.title) }, children: heading }), _jsxs(View, { style: { flexDirection: "row", alignItems: "center", gap: 4 }, children: [online ? _jsx(View, { style: { width: 6, height: 6, borderRadius: 3, backgroundColor: c.success } }) : null, _jsx(Text, { style: { ...text(t.font.scale.caption, t.font.weights.body), color: c.textMuted, lineHeight: lineHeight(t.font.scale.caption, 1.2) }, children: online ? "Online" : "Connecting…" })] })] }), _jsx(Pressable, { onPress: onCollapse, hitSlop: 10, accessibilityRole: "button", accessibilityLabel: "Collapse", children: _jsx(Icon, { name: "chevron", t: t, color: c.textMuted, kit: kit, rotate: true }) })] })), _jsxs(ScrollView, { ref: scroll, style: { maxHeight: lifted ? 150 : 260 }, contentContainerStyle: { padding: 12, gap: t.spacing.gap }, keyboardShouldPersistTaps: "handled", children: [messages.length === 0 ? (_jsx(Text, { style: { ...text(t.font.scale.body, t.font.weights.body), color: c.textMuted, lineHeight: lineHeight(t.font.scale.body, t.font.lineHeight.body) }, children: online ? `${heading} can see what you’re looking at — ask it anything.` : "Connecting…" })) : null, messages.map((m, i) => {
|
|
219
221
|
const b = bubble(t, m.role !== "agent");
|
|
220
222
|
return (_jsx(View, { style: [{ maxWidth: "84%" }, b.box], children: _jsx(Text, { style: { ...text(t.font.scale.body, t.font.weights.body), color: b.color, lineHeight: lineHeight(t.font.scale.body, t.font.lineHeight.body), opacity: m.live ? 0.75 : 1 }, children: m.text }) }, i));
|
|
221
223
|
})] }), _jsxs(View, { style: { height: 58, flexDirection: "row", alignItems: "center", gap: 8, paddingHorizontal: 10, backgroundColor: c.background }, children: [_jsx(TextInput, { value: draft, onChangeText: setDraft, onSubmitEditing: submit, returnKeyType: "send", blurOnSubmit: false, placeholder: "Message\u2026", placeholderTextColor: c.textMuted, style: {
|
|
@@ -7,6 +7,7 @@ import { resolveNativeAppearance, resolveWidgetPalette } from "./appearance.js";
|
|
|
7
7
|
import { useDesign } from "./use-design.js";
|
|
8
8
|
import { alpha, letterSpacing, lineHeight, onAccentFor, shadowStyle, softFor } from "./design-math.js";
|
|
9
9
|
import { DEFAULT_DESIGN_PRESET, designPreset } from "../theme.js";
|
|
10
|
+
import { TitleBar, windowed } from "./window-chrome.js";
|
|
10
11
|
import { PLATFORM_GRAMMAR, manySummary, resolveLoader, resolvePlatform, resolveWidgetLook, widgetSurface } from "../protocol.js";
|
|
11
12
|
function tint(hex, alpha) {
|
|
12
13
|
const m = /^#?([0-9a-f]{6})$/i.exec(String(hex).trim());
|
|
@@ -19,6 +20,7 @@ const CLASSIC_SCALE = designPreset(DEFAULT_DESIGN_PRESET).font.scale;
|
|
|
19
20
|
function classicSkin(theme, accent, radius) {
|
|
20
21
|
return {
|
|
21
22
|
classic: true,
|
|
23
|
+
window: null,
|
|
22
24
|
size: (today) => today,
|
|
23
25
|
weight: (today) => today,
|
|
24
26
|
family: () => undefined,
|
|
@@ -50,6 +52,7 @@ function designSkin(look, theme, accent, radius, ownRadius, surfaceOverride) {
|
|
|
50
52
|
const density = t.spacing.cardPadding / 14;
|
|
51
53
|
return {
|
|
52
54
|
classic: false,
|
|
55
|
+
window: windowed(t) ? t : null,
|
|
53
56
|
size: (today, role, exact) => (exact ? f.scale[role] : Math.round(((today * f.scale[role]) / CLASSIC_SCALE[role]) * 10) / 10),
|
|
54
57
|
weight: (_today, which) => String(f.weights[which]),
|
|
55
58
|
family: (heading) => look.font(heading ? f.heading : f.body),
|
|
@@ -411,9 +414,11 @@ export function GraineWidget(props) {
|
|
|
411
414
|
paddingHorizontal: 16, borderRadius: 999, backgroundColor: tint(theme.border, 0.4),
|
|
412
415
|
}, children: _jsx(Text, { style: { color: theme.text, fontSize: k.size(13.5, "body"), fontWeight: k.weight("700", "strong"), fontFamily: k.family() }, children: "None of these" }) })] })] }) })] }));
|
|
413
416
|
}
|
|
417
|
+
const cardPad = k.pad(14, 12);
|
|
418
|
+
const cardFill = k.window && !props.theme?.surface ? k.window.colors.surface : theme.surface;
|
|
414
419
|
return (_jsxs(_Fragment, { children: [chosen, _jsxs(Raised, { k: k, style: {
|
|
415
|
-
backgroundColor:
|
|
416
|
-
...
|
|
420
|
+
backgroundColor: cardFill, borderRadius: radius, borderWidth: k.borderWidth, borderColor: theme.border,
|
|
421
|
+
...cardPad, marginBottom: 8,
|
|
417
422
|
...(k.classic ? k.depth.shadow : null),
|
|
418
|
-
}, children: [title ? (_jsx(Text, { style: { color: theme.text, ...titleType(14.5), marginBottom: 2 }, children: title })) : null, prompt ? (_jsx(Text, { style: { color: theme.muted, fontSize: k.size(12.5, "caption", true), lineHeight: k.line(17, k.size(12.5, "caption", true)), fontFamily: k.family(), marginBottom: 8 }, children: prompt })) : _jsx(View, { style: { height: 6 } }), body, _jsx(Pressable, { onPress: dismiss, accessibilityRole: "button", accessibilityLabel: "Dismiss", hitSlop: 8, style: { alignSelf: "flex-end", marginTop: 10, minHeight: 44, justifyContent: "center" }, children: _jsx(Text, { style: { color: theme.muted, fontSize: k.size(12.5, "caption", true), fontWeight: k.weight("600", "body"), fontFamily: k.family() }, children: "Dismiss" }) })] })] }));
|
|
423
|
+
}, children: [k.window ? (_jsx(View, { style: { marginBottom: 10 }, children: _jsx(TitleBar, { t: k.window, title: title, radius: radius, bleed: { horizontal: cardPad.paddingHorizontal, top: cardPad.paddingVertical } }) })) : title ? (_jsx(Text, { style: { color: theme.text, ...titleType(14.5), marginBottom: 2 }, children: title })) : null, prompt ? (_jsx(Text, { style: { color: theme.muted, fontSize: k.size(12.5, "caption", true), lineHeight: k.line(17, k.size(12.5, "caption", true)), fontFamily: k.family(), marginBottom: 8 }, children: prompt })) : _jsx(View, { style: { height: 6 } }), body, _jsx(Pressable, { onPress: dismiss, accessibilityRole: "button", accessibilityLabel: "Dismiss", hitSlop: 8, style: { alignSelf: "flex-end", marginTop: 10, minHeight: 44, justifyContent: "center" }, children: _jsx(Text, { style: { color: theme.muted, fontSize: k.size(12.5, "caption", true), fontWeight: k.weight("600", "body"), fontFamily: k.family() }, children: "Dismiss" }) })] })] }));
|
|
419
424
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { ThemeTokens } from "../theme.js";
|
|
3
|
+
export declare const WINDOW_CHROME: {
|
|
4
|
+
readonly height: {
|
|
5
|
+
readonly window: 32;
|
|
6
|
+
readonly caption: 24;
|
|
7
|
+
};
|
|
8
|
+
readonly dot: {
|
|
9
|
+
readonly window: 10;
|
|
10
|
+
readonly caption: 8;
|
|
11
|
+
};
|
|
12
|
+
readonly gap: 6;
|
|
13
|
+
readonly inset: 12;
|
|
14
|
+
readonly lights: readonly ["#FF5F57", "#FEBC2E", "#28C840"];
|
|
15
|
+
readonly online: 6;
|
|
16
|
+
};
|
|
17
|
+
export declare const windowed: (t: ThemeTokens) => boolean;
|
|
18
|
+
export declare const MONO: string;
|
|
19
|
+
export declare function TitleBar({ t, title, size, online, right, radius, bleed, }: {
|
|
20
|
+
t: ThemeTokens;
|
|
21
|
+
title: string;
|
|
22
|
+
size?: "window" | "caption";
|
|
23
|
+
online?: boolean;
|
|
24
|
+
right?: React.ReactNode;
|
|
25
|
+
radius?: number;
|
|
26
|
+
bleed?: {
|
|
27
|
+
horizontal: number;
|
|
28
|
+
top: number;
|
|
29
|
+
};
|
|
30
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Platform, Text, View } from "react-native";
|
|
3
|
+
export const WINDOW_CHROME = {
|
|
4
|
+
height: { window: 32, caption: 24 },
|
|
5
|
+
dot: { window: 10, caption: 8 },
|
|
6
|
+
gap: 6,
|
|
7
|
+
inset: 12,
|
|
8
|
+
lights: ["#FF5F57", "#FEBC2E", "#28C840"],
|
|
9
|
+
online: 6,
|
|
10
|
+
};
|
|
11
|
+
export const windowed = (t) => t.chrome === "window";
|
|
12
|
+
export const MONO = Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
|
|
13
|
+
export function TitleBar({ t, title, size = "window", online = false, right, radius = 0, bleed, }) {
|
|
14
|
+
const c = t.colors;
|
|
15
|
+
const h = WINDOW_CHROME.height[size];
|
|
16
|
+
const d = WINDOW_CHROME.dot[size];
|
|
17
|
+
const inner = Math.max(0, radius - t.shape.borderWidth);
|
|
18
|
+
return (_jsxs(View, { accessibilityRole: "header", style: {
|
|
19
|
+
height: h,
|
|
20
|
+
flexDirection: "row",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
paddingHorizontal: WINDOW_CHROME.inset,
|
|
23
|
+
backgroundColor: c.surfaceRaised,
|
|
24
|
+
borderBottomWidth: t.shape.borderWidth,
|
|
25
|
+
borderBottomColor: c.border,
|
|
26
|
+
borderTopLeftRadius: inner,
|
|
27
|
+
borderTopRightRadius: inner,
|
|
28
|
+
...(bleed ? { marginHorizontal: -bleed.horizontal, marginTop: -bleed.top } : null),
|
|
29
|
+
}, children: [_jsx(View, { style: { flexDirection: "row", gap: WINDOW_CHROME.gap }, accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: WINDOW_CHROME.lights.map((color) => (_jsx(View, { style: { width: d, height: d, borderRadius: d / 2, backgroundColor: color } }, color))) }), _jsxs(View, { pointerEvents: "none", style: { position: "absolute", left: 0, right: 0, top: 0, bottom: 0, flexDirection: "row", alignItems: "center", justifyContent: "center", paddingHorizontal: 64 }, children: [online ? (_jsx(View, { style: { width: WINDOW_CHROME.online, height: WINDOW_CHROME.online, borderRadius: WINDOW_CHROME.online / 2, backgroundColor: c.success, marginRight: 6 } })) : null, _jsx(Text, { numberOfLines: 1, style: { fontFamily: MONO, fontSize: t.font.scale.caption, color: c.textMuted }, children: title.toLowerCase() })] }), right ? _jsx(View, { style: { marginLeft: "auto" }, children: right }) : null] }));
|
|
30
|
+
}
|
package/dist/theme.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type LauncherShape = "circle" | "squircle" | "rounded-square" | "square"
|
|
|
8
8
|
export type IconStyle = "outline" | "filled" | "duotone" | "sharp";
|
|
9
9
|
export type MotionEasing = "standard" | "emphasized" | "spring" | "linear" | "none";
|
|
10
10
|
export type DesignFamily = "graine" | "native" | "modern" | "enterprise" | "expressive";
|
|
11
|
+
export type DesignChrome = "none" | "window";
|
|
11
12
|
export interface DesignConfig {
|
|
12
13
|
preset: string;
|
|
13
14
|
accent?: string;
|
|
@@ -24,6 +25,7 @@ export interface DesignConfig {
|
|
|
24
25
|
launcherIcon?: string;
|
|
25
26
|
launcherShape?: LauncherShape;
|
|
26
27
|
iconStyle?: IconStyle;
|
|
28
|
+
chrome?: DesignChrome;
|
|
27
29
|
}
|
|
28
30
|
export interface ThemeColors {
|
|
29
31
|
background: string;
|
|
@@ -121,6 +123,7 @@ export interface ThemeTokens {
|
|
|
121
123
|
surfaceOpacity: number;
|
|
122
124
|
} | null;
|
|
123
125
|
bubbles: DesignBubbles;
|
|
126
|
+
chrome: DesignChrome;
|
|
124
127
|
}
|
|
125
128
|
export interface ResolvedDesign {
|
|
126
129
|
config: DesignConfig;
|
|
@@ -145,6 +148,7 @@ export interface DesignPreset {
|
|
|
145
148
|
};
|
|
146
149
|
glass: ThemeTokens["glass"];
|
|
147
150
|
bubbles: DesignBubbles;
|
|
151
|
+
chrome?: DesignChrome;
|
|
148
152
|
colors: {
|
|
149
153
|
light: Omit<ThemeColors, "accentSoft">;
|
|
150
154
|
dark: Omit<ThemeColors, "accentSoft">;
|
|
@@ -158,6 +162,7 @@ export declare const DESIGN_NEUTRALS: ReadonlyArray<DesignNeutral>;
|
|
|
158
162
|
export declare const DESIGN_BUBBLES: ReadonlyArray<DesignBubbles>;
|
|
159
163
|
export declare const LAUNCHER_SHAPES: ReadonlyArray<LauncherShape>;
|
|
160
164
|
export declare const ICON_STYLES: ReadonlyArray<IconStyle>;
|
|
165
|
+
export declare const DESIGN_CHROMES: ReadonlyArray<DesignChrome>;
|
|
161
166
|
export declare function normaliseHex(value: unknown): string | null;
|
|
162
167
|
export declare function mixHex(a: string, b: string, t: number): string;
|
|
163
168
|
export declare function luminanceOf(hex: string): number;
|
package/dist/theme.js
CHANGED
|
@@ -6,6 +6,7 @@ export const DESIGN_NEUTRALS = ["preset", "cool", "neutral", "warm"];
|
|
|
6
6
|
export const DESIGN_BUBBLES = ["filled", "outline", "minimal"];
|
|
7
7
|
export const LAUNCHER_SHAPES = ["circle", "squircle", "rounded-square", "square", "pill"];
|
|
8
8
|
export const ICON_STYLES = ["outline", "filled", "duotone", "sharp"];
|
|
9
|
+
export const DESIGN_CHROMES = ["none", "window"];
|
|
9
10
|
const HEX6 = /^#?([0-9a-f]{6})$/i;
|
|
10
11
|
const HEX3 = /^#?([0-9a-f]{3})$/i;
|
|
11
12
|
export function normaliseHex(value) {
|
|
@@ -75,6 +76,7 @@ export const LAUNCHER_ICONS = [
|
|
|
75
76
|
{ id: "star", label: "Star", stroke: true, path: "M11.525 2.295a0.53 0.53 0 0 1 0.95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166 0.756a0.53 0.53 0 0 1 0.294 0.904l-3.736 3.638a2.123 2.123 0 0 0 -0.611 1.878l0.882 5.14a0.53 0.53 0 0 1 -0.771 0.56l-4.618 -2.428a2.122 2.122 0 0 0 -1.973 0L6.396 21.01a0.53 0.53 0 0 1 -0.77 -0.56l0.881 -5.139a2.122 2.122 0 0 0 -0.611 -1.879L2.16 9.795a0.53 0.53 0 0 1 0.294 -0.906l5.165 -0.755a2.122 2.122 0 0 0 1.597 -1.16z" },
|
|
76
77
|
{ id: "orbit", label: "Orbit", stroke: true, path: "M20.341 6.484A10 10 0 0 1 10.266 21.85M3.659 17.516A10 10 0 0 1 13.74 2.152M9 12a3 3 0 1 0 6 0a3 3 0 1 0 -6 0zM17 5a2 2 0 1 0 4 0a2 2 0 1 0 -4 0zM3 19a2 2 0 1 0 4 0a2 2 0 1 0 -4 0z" },
|
|
77
78
|
{ id: "sparkle-filled", label: "Sparkle (filled)", stroke: false, path: "M19.5 13.5a1.479 1.479 0 0 1 -0.977 1.401L13.688 16.688l-1.781 4.839a1.492 1.492 0 0 1 -2.801 0L7.312 16.688l-4.839 -1.781a1.492 1.492 0 0 1 0 -2.801L7.312 10.312l1.781 -4.839a1.492 1.492 0 0 1 2.801 0L13.688 10.312l4.839 1.781A1.479 1.479 0 0 1 19.5 13.5ZM14.25 4.5h1.5V6a0.75 0.75 0 0 0 1.5 0V4.5h1.5a0.75 0.75 0 0 0 0 -1.5H17.25V1.5a0.75 0.75 0 0 0 -1.5 0V3H14.25a0.75 0.75 0 0 0 0 1.5Zm8.25 3h-0.75V6.75a0.75 0.75 0 0 0 -1.5 0v0.75h-0.75a0.75 0.75 0 0 0 0 1.5h0.75v0.75a0.75 0.75 0 0 0 1.5 0V9h0.75a0.75 0.75 0 0 0 0 -1.5Z" },
|
|
79
|
+
{ id: "buddy", label: "Buddy", stroke: true, path: "M12 3c4.97 0 8 3.03 8 8.5S16.97 21 12 21 4 17.97 4 11.5 7.03 3 12 3z M9.25 10.25v1.75 M14.75 10.25v1.75 M9.5 15.1c1.4 1.15 3.6 1.15 5 0" },
|
|
78
80
|
{ id: "chat-dots-filled", label: "Chat dots (filled)", stroke: false, path: "M12 2.25A9.75 9.75 0 0 0 3.392 16.582L2.328 19.775a1.5 1.5 0 0 0 1.897 1.897l3.192 -1.064A9.75 9.75 0 1 0 12 2.25ZM7.875 13.125a1.125 1.125 0 1 1 1.125 -1.125A1.125 1.125 0 0 1 7.875 13.125Zm4.125 0a1.125 1.125 0 1 1 1.125 -1.125A1.125 1.125 0 0 1 12 13.125Zm4.125 0a1.125 1.125 0 1 1 1.125 -1.125A1.125 1.125 0 0 1 16.125 13.125Z" },
|
|
79
81
|
{ id: "graphic-eq", label: "Voice equalizer (filled)", stroke: false, path: "M7 17v-10q0 -0.425 0.288 -0.713T8 6q0.425 0 0.713 0.288T9 7v10q0 0.425 -0.288 0.713T8 18q-0.425 0 -0.713 -0.288T7 17Zm4 4v-18q0 -0.425 0.288 -0.713T12 2q0.425 0 0.713 0.288T13 3v18q0 0.425 -0.288 0.713T12 22q-0.425 0 -0.713 -0.288T11 21ZM3 13v-2q0 -0.425 0.288 -0.713T4 10q0.425 0 0.713 0.288T5 11v2q0 0.425 -0.288 0.713T4 14q-0.425 0 -0.713 -0.288T3 13Zm12 4v-10q0 -0.425 0.288 -0.713T16 6q0.425 0 0.713 0.288T17 7v10q0 0.425 -0.288 0.713T16 18q-0.425 0 -0.713 -0.288T15 17Zm4 -4v-2q0 -0.425 0.288 -0.713T20 10q0.425 0 0.713 0.288T21 11v2q0 0.425 -0.288 0.713T20 14q-0.425 0 -0.713 -0.288T19 13Z" },
|
|
80
82
|
];
|
|
@@ -1071,6 +1073,121 @@ const P_SOFT_PLAYFUL = {
|
|
|
1071
1073
|
}
|
|
1072
1074
|
}
|
|
1073
1075
|
};
|
|
1076
|
+
const P_DESKTOP_BUDDY = {
|
|
1077
|
+
"id": "desktop-buddy",
|
|
1078
|
+
"name": "Desktop Buddy",
|
|
1079
|
+
"tagline": "A friendly little computer — clean white windows, a blue pointer and a bit of bounce.",
|
|
1080
|
+
"family": "modern",
|
|
1081
|
+
"inspiredBy": [
|
|
1082
|
+
"heyclicky.com — the playful desktop landing: Inter, glossy pills, a soft 0 10px 24px shadow, #0f7fff"
|
|
1083
|
+
],
|
|
1084
|
+
"font": {
|
|
1085
|
+
"body": "Inter",
|
|
1086
|
+
"heading": "Inter",
|
|
1087
|
+
"scale": {
|
|
1088
|
+
"caption": 12,
|
|
1089
|
+
"body": 15,
|
|
1090
|
+
"title": 18,
|
|
1091
|
+
"display": 28
|
|
1092
|
+
},
|
|
1093
|
+
"weights": {
|
|
1094
|
+
"body": 400,
|
|
1095
|
+
"strong": 600,
|
|
1096
|
+
"title": 600
|
|
1097
|
+
},
|
|
1098
|
+
"letterSpacing": {
|
|
1099
|
+
"body": 0,
|
|
1100
|
+
"title": -0.01
|
|
1101
|
+
},
|
|
1102
|
+
"lineHeight": {
|
|
1103
|
+
"body": 1.5,
|
|
1104
|
+
"title": 1.25
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
"shape": {
|
|
1108
|
+
"radius": {
|
|
1109
|
+
"sm": 8,
|
|
1110
|
+
"md": 12,
|
|
1111
|
+
"lg": 16,
|
|
1112
|
+
"xl": 24
|
|
1113
|
+
},
|
|
1114
|
+
"borderWidth": 1,
|
|
1115
|
+
"launcher": "circle"
|
|
1116
|
+
},
|
|
1117
|
+
"spacing": {
|
|
1118
|
+
"unit": 4,
|
|
1119
|
+
"cardPadding": 16,
|
|
1120
|
+
"gap": 10
|
|
1121
|
+
},
|
|
1122
|
+
"elevation": {
|
|
1123
|
+
"card": {
|
|
1124
|
+
"y": 10,
|
|
1125
|
+
"blur": 24,
|
|
1126
|
+
"spread": 0,
|
|
1127
|
+
"opacity": 0.12,
|
|
1128
|
+
"color": "#000000"
|
|
1129
|
+
},
|
|
1130
|
+
"floating": {
|
|
1131
|
+
"y": 14,
|
|
1132
|
+
"blur": 32,
|
|
1133
|
+
"spread": 0,
|
|
1134
|
+
"opacity": 0.16,
|
|
1135
|
+
"color": "#000000"
|
|
1136
|
+
},
|
|
1137
|
+
"hardOffset": null
|
|
1138
|
+
},
|
|
1139
|
+
"motion": {
|
|
1140
|
+
"durationMs": 320,
|
|
1141
|
+
"easing": "spring",
|
|
1142
|
+
"bounce": 0.25
|
|
1143
|
+
},
|
|
1144
|
+
"icons": {
|
|
1145
|
+
"style": "outline",
|
|
1146
|
+
"stroke": 2,
|
|
1147
|
+
"launcher": "buddy"
|
|
1148
|
+
},
|
|
1149
|
+
"glass": null,
|
|
1150
|
+
"bubbles": "filled",
|
|
1151
|
+
"chrome": "window",
|
|
1152
|
+
"colors": {
|
|
1153
|
+
"light": {
|
|
1154
|
+
"background": "#FBFBFB",
|
|
1155
|
+
"surface": "#FFFFFF",
|
|
1156
|
+
"surfaceRaised": "#F5F5F5",
|
|
1157
|
+
"text": "#0A0A0A",
|
|
1158
|
+
"textMuted": "#626262",
|
|
1159
|
+
"border": "#E7E7E7",
|
|
1160
|
+
"accent": "#0F7FFF",
|
|
1161
|
+
"onAccent": "#FFFFFF",
|
|
1162
|
+
"success": "#1F9D55",
|
|
1163
|
+
"warning": "#FF7800",
|
|
1164
|
+
"danger": "#ED1B26",
|
|
1165
|
+
"userBubble": "#0F7FFF",
|
|
1166
|
+
"userBubbleText": "#FFFFFF",
|
|
1167
|
+
"agentBubble": "#F0F0F0",
|
|
1168
|
+
"agentBubbleText": "#0A0A0A",
|
|
1169
|
+
"scrim": "#000000"
|
|
1170
|
+
},
|
|
1171
|
+
"dark": {
|
|
1172
|
+
"background": "#0B0B0C",
|
|
1173
|
+
"surface": "#161618",
|
|
1174
|
+
"surfaceRaised": "#1F1F22",
|
|
1175
|
+
"text": "#F5F5F5",
|
|
1176
|
+
"textMuted": "#A1A1A6",
|
|
1177
|
+
"border": "#2C2C30",
|
|
1178
|
+
"accent": "#3D8BFF",
|
|
1179
|
+
"onAccent": "#FFFFFF",
|
|
1180
|
+
"success": "#34C759",
|
|
1181
|
+
"warning": "#FF9F0A",
|
|
1182
|
+
"danger": "#FF453A",
|
|
1183
|
+
"userBubble": "#3D8BFF",
|
|
1184
|
+
"userBubbleText": "#FFFFFF",
|
|
1185
|
+
"agentBubble": "#1F1F22",
|
|
1186
|
+
"agentBubbleText": "#F5F5F5",
|
|
1187
|
+
"scrim": "#000000"
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1074
1191
|
const P_NEO_BRUTALISM = {
|
|
1075
1192
|
"id": "neo-brutalism",
|
|
1076
1193
|
"name": "Neo-Brutalist",
|
|
@@ -1761,7 +1878,7 @@ const P_HIGH_CONTRAST = {
|
|
|
1761
1878
|
}
|
|
1762
1879
|
}
|
|
1763
1880
|
};
|
|
1764
|
-
export const DESIGN_PRESETS = [GRAINE_CLASSIC, P_CHAT_NEUTRAL, P_MATERIAL_3, P_IOS_NATIVE, P_MINIMAL_MONO, P_FLUENT_2, P_CARBON, P_LIQUID_GLASS, P_SOFT_PLAYFUL, P_NEO_BRUTALISM, P_EDITORIAL, P_LUXURY, P_RETRO_TERMINAL, P_WARM_EARTHY, P_HIGH_CONTRAST];
|
|
1881
|
+
export const DESIGN_PRESETS = [GRAINE_CLASSIC, P_CHAT_NEUTRAL, P_MATERIAL_3, P_IOS_NATIVE, P_MINIMAL_MONO, P_FLUENT_2, P_CARBON, P_LIQUID_GLASS, P_SOFT_PLAYFUL, P_DESKTOP_BUDDY, P_NEO_BRUTALISM, P_EDITORIAL, P_LUXURY, P_RETRO_TERMINAL, P_WARM_EARTHY, P_HIGH_CONTRAST];
|
|
1765
1882
|
export const DEFAULT_DESIGN_PRESET = "graine-classic";
|
|
1766
1883
|
export function designPreset(id) {
|
|
1767
1884
|
const want = String(id ?? "").trim().toLowerCase();
|
|
@@ -1822,6 +1939,9 @@ export function normaliseDesignConfig(raw) {
|
|
|
1822
1939
|
const iconStyle = pick(r.iconStyle, ICON_STYLES);
|
|
1823
1940
|
if (iconStyle)
|
|
1824
1941
|
out.iconStyle = iconStyle;
|
|
1942
|
+
const chrome = pick(r.chrome, DESIGN_CHROMES);
|
|
1943
|
+
if (chrome)
|
|
1944
|
+
out.chrome = chrome;
|
|
1825
1945
|
return out;
|
|
1826
1946
|
}
|
|
1827
1947
|
export function designFromAppearance(appearance) {
|
|
@@ -1959,6 +2079,7 @@ export function resolveTokens(configInput, scheme) {
|
|
|
1959
2079
|
},
|
|
1960
2080
|
glass,
|
|
1961
2081
|
bubbles,
|
|
2082
|
+
chrome: config.chrome ?? p.chrome ?? "none",
|
|
1962
2083
|
};
|
|
1963
2084
|
}
|
|
1964
2085
|
export function resolveDesign(configInput) {
|
package/package.json
CHANGED