Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .repos/effect
Submodule effect updated 1097 files
35 changes: 31 additions & 4 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"!**/region-iso-3166-codes.ts",
"!**/mockServiceWorker.js",
"!**/package.json",
"!**/.repos"
"!**/.repos",
"!**/CHANGELOG.md",
"!!**/@dedot/api/chaintypes/substrate/tx.d.ts"
]
},
"formatter": {
Expand All @@ -37,7 +39,7 @@
"rules": {
"preset": "recommended",
"style": {
"noNonNullAssertion": "off",
"noNonNullAssertion": "error",
"noParameterAssign": "error",
"useAsConstAssertion": "error",
"useDefaultParameterLast": "error",
Expand All @@ -59,14 +61,19 @@
},
"correctness": {
"useJsxKeyInIterable": "off",
"useUniqueElementIds": "off"
"useUniqueElementIds": "off",
"noComponentHookFactories": "off"
},
"complexity": {
"noForEach": "off",
"useIndexOf": "off"
},
"nursery": {
"useReactCompiler": "error"
"useReactCompiler": "error",
"useExhaustiveSwitchCases": "error",
"noFloatingPromises": "error",
"noMisusedPromises": "error",
"noUselessTypeConversion": "error"
}
},
"domains": {
Expand All @@ -76,6 +83,26 @@
}
},
"overrides": [
{
"includes": ["packages/widget/src/**"],
"linter": {
"rules": {
"nursery": {
"noUnsafeTypeAssertion": "error"
}
}
}
},
{
"includes": ["packages/widget/tests/**"],
"linter": {
"rules": {
"style": {
"noNonNullAssertion": "off"
}
}
}
},
{
"includes": [
"packages/widget/src/**",
Expand Down
6 changes: 0 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@
],
"author": "Petar Todorovic <petar@omni.app> (https://github.com)",
"license": "MIT",
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "12"
}
},
"scripts": {
"dev": "mise run dev --",
"build": "mise run build --",
Expand Down
1 change: 1 addition & 0 deletions packages/examples/with-angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"tslib": "catalog:"
},
"devDependencies": {
"@types/node": "catalog:",
"@angular/build": "catalog:",
"@angular/cli": "catalog:",
"@angular/compiler-cli": "catalog:",
Expand Down
1 change: 1 addition & 0 deletions packages/examples/with-vite-bundled/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@stakekit/widget": "workspace:*"
},
"devDependencies": {
"@types/node": "catalog:",
"@typescript/native": "catalog:",
"vite": "catalog:"
}
Expand Down
5 changes: 4 additions & 1 deletion packages/examples/with-vite-bundled/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import "./style.css";
import "@stakekit/widget/style.css";
import { darkTheme, renderSKWidget } from "@stakekit/widget/bundle";

const container = document.querySelector<HTMLDivElement>("#app");
if (!container) throw new Error("Missing #app container");

renderSKWidget({
container: document.querySelector<HTMLDivElement>("#app")!,
container,
apiKey: import.meta.env.VITE_API_KEY,
theme: darkTheme,
});
1 change: 1 addition & 0 deletions packages/examples/with-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"react-dom": "catalog:"
},
"devDependencies": {
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"@typescript/native": "catalog:",
Expand Down
5 changes: 4 additions & 1 deletion packages/examples/with-vite/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";

ReactDOM.createRoot(document.getElementById("root")!).render(
const root = document.getElementById("root");
if (!root) throw new Error("Missing #root element");

ReactDOM.createRoot(root).render(
<React.StrictMode>
<App />
</React.StrictMode>
Expand Down
1 change: 1 addition & 0 deletions packages/widget/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
"@tronweb3/tronwallet-adapter-bitkeep": "catalog:",
"@tronweb3/tronwallet-adapter-ledger": "catalog:",
"@tronweb3/tronwallet-adapter-tronlink": "catalog:",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"@typescript/native": "catalog:",
Expand Down
4 changes: 2 additions & 2 deletions packages/widget/playground/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const Choice = <Value extends string>({
value,
}: {
readonly disabled?: boolean;
readonly hint?: string;
readonly hint?: string | undefined;
readonly label: string;
readonly onChange: (value: Value) => void;
readonly options: ReadonlyArray<Value>;
Expand Down Expand Up @@ -75,7 +75,7 @@ const Toggle = ({
}: {
readonly checked: boolean;
readonly disabled?: boolean;
readonly hint?: string;
readonly hint?: string | undefined;
readonly label: string;
readonly onChange: (checked: boolean) => void;
}) => (
Expand Down
2 changes: 1 addition & 1 deletion packages/widget/playground/playground-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export type PlaygroundConfig = typeof PlaygroundConfigSchema.Type;
export const defaultPlaygroundConfig: PlaygroundConfig = {
wallet: "builtin",
scriptedAddress: scriptedWalletAccount,
trackingLog: true,
trackingLog: false,
variant: "default",
theme: "dark",
language: "auto",
Expand Down
1 change: 0 additions & 1 deletion packages/widget/scripts/architecture/check-architecture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const { options: configuredOptions = {}, ...ruleSet } =
const cruiseOutput = await cruise(["src"], {
...configuredOptions,
baseDir: widgetRoot,
outputType: undefined,
ruleSet,
validate: true,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,11 @@ const compileCollection = (
sameOwnerInterfacePath: `^${declaration.root}/$1/${interfacePattern}\\.ts$`,
interfacePaths,
interfaceImporters,
parentInterfacePath:
declaration.parent === undefined
? undefined
: `^${declaration.parent}/${interfacePattern}\\.ts$`,
...(declaration.parent === undefined
? {}
: {
parentInterfacePath: `^${declaration.parent}/${interfacePattern}\\.ts$`,
}),
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ const schemaMemberName = (expression: ts.Expression): string | undefined => {
) {
return current.expression.name.text;
}

return undefined;
};

const isEmptyStruct = (expression: ts.Expression): boolean => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,16 @@ const assertEncryptWorkerStarts = async (
name: string;
}) => Worker)
: undefined;
if (scriptUrl === null && InlineWorker === undefined) {
// Code here runs in the page: a named helper would be compiled to
// `__name(...)`, which the page does not define.
const worker =
InlineWorker === undefined
? scriptUrl !== null &&
new Worker(scriptUrl, { name: "zama-fhe-encrypt", type: "module" })
: new InlineWorker({ name: "zama-fhe-encrypt" });
if (worker === false) {
return `${chunk} does not export an inline worker constructor`;
}
const worker = InlineWorker
? new InlineWorker({ name: "zama-fhe-encrypt" })
: new Worker(scriptUrl!, { name: "zama-fhe-encrypt", type: "module" });
const { promise, resolve } = Promise.withResolvers<string>();
worker.addEventListener("message", (event) => {
if (event.data === "zama-encrypt-worker-ready") resolve("ready");
Expand Down
35 changes: 30 additions & 5 deletions packages/widget/src/app/composition/providers/theme-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { assignInlineVars } from "@vanilla-extract/dynamic";
import { Predicate } from "effect";
import type { PropsWithChildren } from "react";
import { useWidgetConfig } from "../../../features/widget-configuration/index";
import type { WidgetConfig } from "../../../services/config/widget-config-model";
import { mergeDeep } from "../../../shared/effect/merge-deep";
import { vars } from "../../../shared/styles/theme/contract.css";
import { id, rootSelector } from "../../../shared/styles/theme/ids";
import { lightTheme } from "../../../shared/styles/theme/themes";
import { getFineryThemeOverrides } from "../../../shared/styles/theme/variant-overrides/finery";
import {
type FineryBaseTheme,
getFineryThemeOverrides,
} from "../../../shared/styles/theme/variant-overrides/finery";
import { portoThemeOverrides } from "../../../shared/styles/theme/variant-overrides/porto";
import { utilaThemeOverrides } from "../../../shared/styles/theme/variant-overrides/utila";
import type { RecursivePartial } from "../../../shared/types/utils";
Expand All @@ -15,7 +19,7 @@ export const getThemeOverrides = ({
baseTheme,
variant,
}: {
baseTheme: typeof lightTheme;
baseTheme: FineryBaseTheme;
variant: WidgetConfig["variant"];
}): RecursivePartial<typeof lightTheme> => {
if (variant === "utila") {
Expand All @@ -33,6 +37,25 @@ export const getThemeOverrides = ({
return {};
};

/**
* CSS variable assignments for a merged theme, read through the theme
* contract: each contract leaf (a `var(--…)` reference) takes the merged value
* at the same path. Values off the contract are not emitted.
*/
const themeVarEntries = (
contract: unknown,
tokens: unknown
): ReadonlyArray<readonly [string, string]> => {
if (typeof contract === "string") {
return typeof tokens === "string" ? [[contract, tokens]] : [];
}
if (!Predicate.isObject(contract) || !Predicate.isObject(tokens)) return [];

return Object.entries(contract).flatMap(([key, node]) =>
themeVarEntries(node, tokens[key])
);
};

/** Theme variables for a host theme and variant, read from props. */
export const ThemeStyles = ({
children,
Expand All @@ -42,19 +65,21 @@ export const ThemeStyles = ({
readonly theme: WidgetConfig["theme"];
readonly variant: WidgetConfig["variant"];
}>) => {
const baseTheme = mergeDeep(lightTheme, theme);
const overrides = getThemeOverrides({
baseTheme,
baseTheme: {
color: { primary: theme?.color?.primary ?? lightTheme.color.primary },
},
variant,
});
const finalTheme = mergeDeep(lightTheme, theme, overrides);
const themeVars = Object.fromEntries(themeVarEntries(vars, finalTheme));

return (
<div data-rk={id}>
<style
// biome-ignore lint: false
dangerouslySetInnerHTML={{
__html: `${rootSelector} {${assignInlineVars(vars, finalTheme)}}`,
__html: `${rootSelector} {${assignInlineVars(themeVars)}}`,
}}
/>
{children}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Schema } from "effect";
import type { PropsWithChildren } from "react";
import { useTranslation } from "react-i18next";
import type { Network } from "../../../domain/network/network";
import { Network } from "../../../domain/network/network";
import type { Token } from "../../../domain/token/token";
import { isWalletNetwork } from "../../../domain/wallet/network";
import { useWidgetConfig } from "../../../features/widget-configuration/index";
Expand All @@ -9,6 +10,8 @@ import {
WidgetPresentationProvider,
} from "../../../shared/ui/widget-presentation";

const isNetwork = Schema.is(Network);

/**
* Populates the shared UI kit's rendering environment from widget config, so
* `shared/ui` components render host preferences without importing
Expand All @@ -33,7 +36,7 @@ export const WidgetPresentationAdapter = ({ children }: PropsWithChildren) => {
hostTokenIconMapping,
layout: layout === "Dashboard" ? "dashboard" : "compact",
locale: i18n.resolvedLanguage ?? i18n.language,
mapNetworkIconUrl: (network: Network) => {
mapNetworkIconUrl: (network: Token["network"]) => {
if (!isWalletNetwork(network)) return undefined;

return typeof chainIconMapping === "function"
Expand All @@ -42,10 +45,14 @@ export const WidgetPresentationAdapter = ({ children }: PropsWithChildren) => {
},
mapTokenIconUrl: (token: Token) => {
if (!tokenIconMapping) return undefined;
if (typeof tokenIconMapping !== "function") {
return tokenIconMapping[token.symbol];
}

return typeof tokenIconMapping === "function"
? tokenIconMapping(token as Parameters<typeof tokenIconMapping>[0])
: tokenIconMapping[token.symbol];
// Hosts receive an `SKToken`, whose network is limited to `Network`.
return isNetwork(token.network)
? tokenIconMapping({ ...token, network: token.network })
: undefined;
},
portalContainer,
variant,
Expand Down
14 changes: 11 additions & 3 deletions packages/widget/src/app/layouts/dashboard/dashboard-routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import { WalletScopeRouteGuard } from "../../../features/wallet/composition";
import { GlobalModals } from "../../../features/widget-shell/composition";
// import { RewardsTabPage } from "../../../domain/portfolio/rewards";
import { createYieldFlowRoutes } from "../../../features/yield-transaction-flow/composition";
import { widgetRoutes } from "../../../services/navigation/widget-routes";
import {
type WidgetPath,
widgetRoutes,
} from "../../../services/navigation/widget-routes";
import { BorrowFeatureRoute } from "../../routes/ui/borrow-feature-route";
import { dashboardEarnRoute } from "./dashboard-earn-route";
import {
Expand All @@ -33,7 +36,10 @@ import {
DashboardOverview,
} from "./dashboard-overview";
import { DashboardShell } from "./dashboard-shell";
import { resolveDashboardRouteTab } from "./dashboard-tabs";
import {
type DashboardRouteTab,
resolveDashboardRouteTab,
} from "./dashboard-tabs";

const borrowRouteComposition = {
WalletScopeRouteGuard,
Expand All @@ -48,7 +54,9 @@ export const shouldRegisterDashboardEarnFooterButton = (pathname: string) =>
* transition (exit, then enter); steps inside one page, such as the Earn form
* into its Review or a position into its unstake flow, keep the same key.
*/
const resolveDashboardPageKey = (pathname: string): string => {
const resolveDashboardPageKey = (
pathname: string
): Exclude<DashboardRouteTab, "manage"> | WidgetPath => {
const tab = resolveDashboardRouteTab(pathname);
if (tab !== "manage") return tab;
// A position's pages share its key: a market position, a yield position,
Expand Down
Loading
Loading