Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions examples/storybook/src/stories/helpers/streamingWidgetStories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,19 @@ function createAdapter(
// MiniAppShell must sit inside a provider: without one it first paints before any
// Tamagui theme is registered, and the theme that the widget's own provider registers
// then flips its internal Theme hook path on the next re-render ("Should have a queue").
function StoryShell({ children, dataTestId }: { children: React.ReactNode; dataTestId: string }) {
// The shell provider shares the widget's defaultTheme so the light theme is not framed
// by the dark shell background.
function StoryShell({
children,
dataTestId,
defaultTheme = 'dark',
}: {
children: React.ReactNode
dataTestId: string
defaultTheme?: 'light' | 'dark'
}) {
return (
<GoodWidgetProvider>
<GoodWidgetProvider defaultTheme={defaultTheme}>
<MiniAppShell>
<YStack
data-testid={dataTestId}
Expand Down Expand Up @@ -292,7 +302,7 @@ function PreviewStoryShell({
themeOverrides?: StreamingWidgetProps['themeOverrides']
}) {
return (
<StoryShell dataTestId={dataTestId}>
<StoryShell dataTestId={dataTestId} defaultTheme={defaultTheme}>
<StreamingWidgetPreview
adapter={adapter}
initialTab={initialTab}
Expand Down Expand Up @@ -320,7 +330,7 @@ function StreamingWidgetStoryShell({
const trimmedApiKey = apiKey?.trim()

return (
<StoryShell dataTestId={dataTestId}>
<StoryShell dataTestId={dataTestId} defaultTheme={defaultTheme}>
<StreamingWidget
provider={provider}
environment="production"
Expand Down Expand Up @@ -515,14 +525,12 @@ export function PopulatedStateStory({ defaultTheme, themeOverrides }: ThemeArgs

export function LightThemePopulatedStory({ themeOverrides }: Pick<ThemeArgs, 'themeOverrides'> = {}) {
return (
<GoodWidgetProvider defaultTheme="light">
<PreviewStoryShell
adapter={createAdapter()}
dataTestId="StreamingWidget-light-theme-populated"
defaultTheme="light"
themeOverrides={themeOverrides}
/>
</GoodWidgetProvider>
<PreviewStoryShell
adapter={createAdapter()}
dataTestId="StreamingWidget-light-theme-populated"
defaultTheme="light"
themeOverrides={themeOverrides}
/>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Canvas, Meta } from '@storybook/blocks';
import * as ShowcaseStories from './StreamingWidget.stories';
import * as ShowcaseStories from './StreamingWidgetShowcase.stories';
import * as ThemeOverridesStories from './StreamingWidgetThemeOverrides.stories';
import { DocsCallout, DocsCard, DocsGrid, DocsPage, DocsSection } from '../docs/DocsLayout';

Expand Down Expand Up @@ -34,7 +34,7 @@ import { DocsCallout, DocsCard, DocsGrid, DocsPage, DocsSection } from '../docs/
>
Wallet gates, network handling, loading, empty, error, stream forms, pool claims, and SUP
reserve states live in `QA / StreamingWidget / Runtime Fixtures`. Dark theme is the default;
`LightThemePopulated` demonstrates the explicit light-theme branch.
every fixture renders in light or dark via the `defaultTheme` control.
</DocsCard>
</DocsSection>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
* components that fall back to Card's field set since they don't have their
* own preset entries. See packages/streaming-widget/src/components/shared.tsx.
*
* Controls are wired for `dark_Button` and the two targets rendered in the
* PopulatedStateStory fixture (`dark_StreamRow`, `dark_BalanceCard`) — a
* couple of high-impact targets that visibly shift the default brand, not
* exhaustive coverage of every value. The remaining Card-derived targets
* follow the same field shape and are documented below for reference.
* Controls are wired for `Button` and the two targets rendered in the
* PopulatedStateStory fixture (`StreamRow`, `BalanceCard`) — a couple of
* high-impact targets that visibly shift the default brand, not exhaustive
* coverage of every value. Each control writes both the `light_*` and
* `dark_*` key so the `defaultTheme` control can flip between themes with the
* same overrides applied. The remaining Card-derived targets follow the same
* field shape and are documented below for reference.
*/
import React from 'react'
import type { Meta, StoryObj } from '@storybook/react'
import type { StreamingWidgetProps } from '@goodwidget/streaming-widget'
import { PopulatedStateStory } from '../helpers/streamingWidgetStories'
import { withDefaultPreset } from '../helpers/withDefaultPreset'
import { DocsCallout, DocsList } from '../docs/DocsLayout'

type ThemeOverrides = NonNullable<StreamingWidgetProps['themeOverrides']>
Expand Down Expand Up @@ -74,6 +75,7 @@ function CodeBlock({ children }: { children: string }) {
}

interface OverridesArgs {
defaultTheme: 'light' | 'dark'
buttonBackground: string
buttonBackgroundHover: string
buttonBackgroundPress: string
Expand All @@ -85,22 +87,31 @@ interface OverridesArgs {
}

function buildThemeOverrides(args: OverridesArgs): ThemeOverrides {
const componentThemes = {
Button: {
background: args.buttonBackground,
backgroundHover: args.buttonBackgroundHover,
backgroundPress: args.buttonBackgroundPress,
backgroundFocus: args.buttonBackgroundFocus,
color: args.buttonColor,
},
StreamRow: {
borderColor: args.streamRowBorderColor,
},
BalanceCard: {
borderColor: args.balanceCardBorderColor,
shadowColor: args.balanceCardShadowColor,
},
}

return {
themes: {
dark_Button: {
background: args.buttonBackground,
backgroundHover: args.buttonBackgroundHover,
backgroundPress: args.buttonBackgroundPress,
backgroundFocus: args.buttonBackgroundFocus,
color: args.buttonColor,
},
dark_StreamRow: {
borderColor: args.streamRowBorderColor,
},
dark_BalanceCard: {
borderColor: args.balanceCardBorderColor,
shadowColor: args.balanceCardShadowColor,
},
dark_Button: componentThemes.Button,
light_Button: componentThemes.Button,
dark_StreamRow: componentThemes.StreamRow,
light_StreamRow: componentThemes.StreamRow,
dark_BalanceCard: componentThemes.BalanceCard,
light_BalanceCard: componentThemes.BalanceCard,
},
}
}
Expand All @@ -109,8 +120,12 @@ const meta: Meta<OverridesArgs> = {
title: 'Widgets/StreamingWidget/Theme overrides',
tags: ['integrator', 'showcase'],
parameters: { layout: 'padded' },
decorators: [withDefaultPreset],
argTypes: {
defaultTheme: {
control: 'radio',
options: ['light', 'dark'],
description: 'Base theme applied via the widget’s own defaultTheme prop.',
},
buttonBackground: { control: 'color', description: 'themes.dark_Button.background' },
buttonBackgroundHover: { control: 'color', description: 'themes.dark_Button.backgroundHover' },
buttonBackgroundPress: { control: 'color', description: 'themes.dark_Button.backgroundPress' },
Expand All @@ -121,6 +136,7 @@ const meta: Meta<OverridesArgs> = {
balanceCardShadowColor: { control: 'color', description: 'themes.dark_BalanceCard.shadowColor' },
},
args: {
defaultTheme: 'light',
buttonBackground: '#7C3AED',
buttonBackgroundHover: '#6D28D9',
buttonBackgroundPress: '#5B21B6',
Expand Down Expand Up @@ -164,7 +180,7 @@ export const Playground: Story = {
</DocsList>
</DocsCallout>

<PopulatedStateStory defaultTheme="dark" themeOverrides={themeOverrides} />
<PopulatedStateStory defaultTheme={args.defaultTheme} themeOverrides={themeOverrides} />
</div>
)
},
Expand Down
7 changes: 4 additions & 3 deletions packages/streaming-widget/src/components/BalancesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Anchor,
Badge,
BadgeText,
Button,
ButtonText,
Icon,
Spinner,
Expand All @@ -20,7 +21,7 @@ import {
superfluidReserveUrl,
tokenSymbol,
} from './format'
import { ActionButton, BalanceCard, StreamingTabContent } from './shared'
import { compactButtonProps, BalanceCard, StreamingTabContent } from './shared'

interface ExternalLinkProps {
href: string
Expand Down Expand Up @@ -72,9 +73,9 @@ export function BalancesTab({
<BalanceCard>
<XStack justifyContent="space-between" alignItems="center">
<Text variant="label">Super Token Balance</Text>
<ActionButton onPress={onRefresh}>
<Button size="sm" {...compactButtonProps} onPress={onRefresh}>
<ButtonText>Refresh</ButtonText>
</ActionButton>
</Button>
</XStack>

{balanceLoading && <Spinner size="sm" />}
Expand Down
33 changes: 23 additions & 10 deletions packages/streaming-widget/src/components/HistoryTab.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { useState } from 'react'
import { ButtonText, Heading, Spinner, Text, XStack, YStack } from '@goodwidget/ui'
import { Button, ButtonText, Heading, Spinner, Text, XStack, YStack } from '@goodwidget/ui'
import type { StreamListItem, StreamStatusFilter } from '../widgetRuntimeContract'
import { tokenSymbol } from './format'
import { StreamCard } from './StreamCard'
import {
EmptyStateCard,
ErrorStateCard,
ActionButton,
compactButtonProps,
secondaryButtonStateProps,
SecondaryButtonText,
StreamingTabContent,
} from './shared'
Expand Down Expand Up @@ -61,24 +62,33 @@ export function HistoryTab({
<StreamingTabContent>
<XStack justifyContent="space-between" alignItems="center">
<Heading level={4}>Stream history</Heading>
<ActionButton variant="secondary" onPress={onRefresh}>
<Button
size="sm"
{...compactButtonProps}
variant="secondary"
{...secondaryButtonStateProps}
onPress={onRefresh}
>
<SecondaryButtonText>Refresh</SecondaryButtonText>
</ActionButton>
</Button>
</XStack>

<XStack gap="$2">
{(['all', 'active', 'ended'] as StreamStatusFilter[]).map((filter) => (
<ActionButton
<Button
size="sm"
{...compactButtonProps}
key={filter}
onPress={() => selectStatus(filter)}
variant={status === filter ? 'primary' : 'secondary'}
{...(status === filter ? {} : secondaryButtonStateProps)}
>
{status === filter ? (
<ButtonText>{STATUS_LABELS[filter]}</ButtonText>
) : (
<SecondaryButtonText>{STATUS_LABELS[filter]}</SecondaryButtonText>
)}
</ActionButton>
</Button>
))}
</XStack>

Expand All @@ -92,9 +102,9 @@ export function HistoryTab({
{!loading && error && (
<ErrorStateCard>
<Text color="$error">{error}</Text>
<ActionButton onPress={onRefresh}>
<Button size="sm" {...compactButtonProps} onPress={onRefresh}>
<ButtonText>Retry</ButtonText>
</ActionButton>
</Button>
</ErrorStateCard>
)}

Expand All @@ -113,12 +123,15 @@ export function HistoryTab({
))}

{!loading && !error && hasMoreHistory && (
<ActionButton
<Button
size="sm"
{...compactButtonProps}
variant="secondary"
{...secondaryButtonStateProps}
onPress={() => setHistoryLimit((count) => count + PAGE_SIZE)}
>
<SecondaryButtonText>Show more</SecondaryButtonText>
</ActionButton>
</Button>
)}
</StreamingTabContent>
)
Expand Down
34 changes: 25 additions & 9 deletions packages/streaming-widget/src/components/PoolCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AddressDisplay,
Badge,
BadgeText,
Button,
ButtonText,
Spinner,
Text,
Expand All @@ -14,7 +15,8 @@ import type { PoolMembershipItem, WriteStatus } from '../widgetRuntimeContract'
import { formatWeiAmount } from './format'
import {
PoolRow,
ActionButton,
compactButtonProps,
secondaryButtonStateProps,
SecondaryButtonText,
WriteStatusBadge,
type SuperTokenSymbol,
Expand Down Expand Up @@ -87,18 +89,27 @@ export function PoolCard({
<Text color="$error" variant="caption">
Could not load claimable amount.
</Text>
<ActionButton variant="secondary" onPress={onRetryClaimable}>
<Button
size="sm"
{...compactButtonProps}
variant="secondary"
{...secondaryButtonStateProps}
onPress={onRetryClaimable}
>
<SecondaryButtonText>Retry</SecondaryButtonText>
</ActionButton>
</Button>
</XStack>
)}

<XStack gap="$2" alignItems="center" flexWrap="wrap">
{pool.isConnected ? (
<>
<WriteStatusBadge status={claimStatus} />
<ActionButton
<Button
size="sm"
{...compactButtonProps}
variant="secondary"
{...secondaryButtonStateProps}
disabled={isConnectPending}
borderColor="$error"
onPress={() => onDisconnect(pool.poolId)}
Expand All @@ -108,20 +119,25 @@ export function PoolCard({
) : (
<ButtonText color="$error">Disconnect</ButtonText>
)}
</ActionButton>
</Button>
</>
) : (
<>
<WriteStatusBadge status={claimStatus} />
<ActionButton
<Button
size="sm"
{...compactButtonProps}
disabled={!canClaim || isClaimPending || claimStatus === 'success'}
onPress={() => onClaim(pool.poolId)}
>
{isClaimPending ? <Spinner size="sm" /> : <ButtonText>Claim</ButtonText>}
</ActionButton>
</Button>
<WriteStatusBadge status={connectStatus} />
<ActionButton
<Button
size="sm"
{...compactButtonProps}
variant="secondary"
{...secondaryButtonStateProps}
disabled={isConnectPending}
onPress={() => onConnect(pool.poolId)}
>
Expand All @@ -130,7 +146,7 @@ export function PoolCard({
) : (
<SecondaryButtonText>Connect</SecondaryButtonText>
)}
</ActionButton>
</Button>
</>
)}
</XStack>
Expand Down
Loading
Loading