Skip to content
Draft
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
2 changes: 1 addition & 1 deletion packages/mini-app-react/src/hooks/useBackButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function useBackButton({
const { backButton } = useMiniApp()
useEffect(() => {
backButton.stateStore.setState({ visible })
}, [backButton, visible])
}, [backButton.stateStore, visible])
useEffect(() => {
if (onClick) {
return backButton.onClick(onClick)
Expand Down
34 changes: 14 additions & 20 deletions packages/mini-app-react/src/hooks/useMainButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,34 @@ import { useMiniApp } from './useMiniApp'

export interface UseMainButtonOptions {
text?: string
visible?: boolean
active?: boolean
loading?: boolean
shining?: boolean
bgColor?: string | null
textColor?: string | null
bgColor?: string
textColor?: string
onClick?: () => void
}

export function useMainButton({
text,
visible,
loading,
active,
shining,
text = '',
loading = false,
shining = false,
bgColor,
textColor,
onClick,
}: UseMainButtonOptions): void {
const { mainButton } = useMiniApp()
useEffect(() => {
mainButton.stateStore.setState(prev => ({
text: text ?? prev.text,
visible: visible ?? prev.visible,
loading: loading ?? prev.loading,
active: active ?? prev.active,
shining: shining ?? prev.shining,
bgColor: bgColor === undefined ? prev.bgColor : bgColor,
textColor: textColor === undefined ? prev.textColor : textColor,
}))
}, [mainButton, text, visible, loading, active, shining, bgColor, textColor])
mainButton.setup({
text,
loading,
shining,
bgColor,
textColor,
})
}, [mainButton.setup, text, loading, shining, bgColor, textColor])
useEffect(() => {
if (onClick) {
return mainButton.onClick(onClick)
}
}, [mainButton, onClick])
}, [mainButton.onClick, onClick])
}
2 changes: 1 addition & 1 deletion packages/mini-app-react/src/hooks/useSettingsButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function useSettingsButton({
const { settingsButton } = useMiniApp()
useEffect(() => {
settingsButton.stateStore.setState({ visible })
}, [settingsButton, visible])
}, [settingsButton.stateStore, visible])
useEffect(() => {
if (onClick) {
return settingsButton.onClick(onClick)
Expand Down
20 changes: 4 additions & 16 deletions packages/mini-app/src/BackButton.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,26 @@
import type { Bridge } from './Bridge.ts'
import type { UnsubscribeFn } from './internal/EventBus.ts'
import type { SessionStorage } from './SessionStorage.ts'
import { Store } from '@tanstack/store'

/**
* Module for controlling the back button.
*/
export interface BackButton {
stateStore: Store<State>
setVisible: (visible: boolean) => void
onClick: (listener: () => void) => UnsubscribeFn
offClick: (listener: any) => void
}

export interface State {
visible: boolean
}

export interface InitOptions {
storage: SessionStorage
bridge: Bridge
}

export const init = ({
storage,
bridge,
}: InitOptions): BackButton => {
const storedState = storage.storedState<State>('BackButton')
const stateStore = new Store<State>(storedState.load() ?? { visible: false })
stateStore.subscribe(({ currentVal }) => {
bridge.emit('setup_back_button', { is_visible: currentVal.visible })
storedState.save(currentVal)
})
return {
stateStore,
setVisible: (visible) => {
bridge.emit('setup_back_button', { is_visible: visible })
},
onClick: (listener) => {
return bridge.on('back_button_pressed', listener)
},
Expand Down
8 changes: 4 additions & 4 deletions packages/mini-app/src/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,9 @@ export interface OutgoingEventMap {
request_theme: void
ready: void
setup_main_button: {
is_visible?: boolean
is_visible: boolean
is_active?: boolean
text: string
text?: string
color?: string
text_color?: string
is_progress_visible?: boolean
Expand All @@ -286,9 +286,9 @@ export interface OutgoingEventMap {
color: string
}
setup_secondary_button: {
is_visible?: boolean
is_visible: boolean
is_active?: boolean
text: string
text?: string
color?: string
text_color?: string
is_progress_visible?: boolean
Expand Down
75 changes: 26 additions & 49 deletions packages/mini-app/src/MainButton.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,56 @@
import type { Bridge } from './Bridge.ts'
import type { UnsubscribeFn } from './internal/EventBus.ts'
import type { SessionStorage } from './SessionStorage.ts'
import type { Theme } from './Theme.ts'
import { Effect, Store } from '@tanstack/store'
import * as Color from './internal/Color.ts'

/**
* Module for controlling main button.
*/
export interface MainButton {
stateStore: Store<State>
setup: (state: null | State) => void
onClick: (listener: () => void) => UnsubscribeFn
offClick: (listener: any) => void
}

export interface State {
text: string
visible: boolean
active: boolean
loading: boolean
shining: boolean
bgColor: string | null
textColor: string | null
}

const INITIAL_STATE: State = {
text: 'Continue',
visible: false,
active: true,
shining: false,
loading: false,
bgColor: null,
textColor: null,
loading?: boolean
shining?: boolean
bgColor?: string
textColor?: string
}

export interface InitOptions {
storage: SessionStorage
bridge: Bridge
theme: Theme
}

const SETUP_EVENT = 'setup_main_button'
const PRESS_EVENT = 'main_button_pressed'

export const init = ({
storage,
bridge,
theme,
}: InitOptions): MainButton => {
const storedState = storage.storedState<State>('MainButton')
const stateStore = new Store<State>(storedState.load() ?? INITIAL_STATE)
stateStore.subscribe(({ currentVal }) => {
storedState.save(currentVal)
})
const effect = new Effect({
fn: () => {
const state = stateStore.state
const palette = theme.paletteStore.state
bridge.emit('setup_main_button', {
text: state.text,
is_visible: state.visible,
is_active: state.active,
is_progress_visible: state.loading,
has_shine_effect: state.shining,
color: (state.bgColor ? Color.toHex(state.bgColor) : null) ?? palette.button_color ?? '#2481cc',
text_color: (state.textColor ? Color.toHex(state.textColor) : null) ?? palette.button_text_color ?? '#ffffff',
})
},
deps: [stateStore, theme.paletteStore],
})
effect.mount()
return {
stateStore,
setup: (state) => {
if (!state?.text) {
bridge.emit(SETUP_EVENT, { is_visible: false })
}
else {
bridge.emit(SETUP_EVENT, {
is_visible: true,
is_active: true,
text: state.text,
is_progress_visible: state.loading,
has_shine_effect: state.shining,
color: state.bgColor ? Color.toHexUnsafe(state.bgColor) : undefined,
text_color: state.textColor ? Color.toHexUnsafe(state.textColor) : undefined,
})
}
},
onClick: (listener) => {
return bridge.on('main_button_pressed', listener)
return bridge.on(PRESS_EVENT, listener)
},
offClick: (listener) => {
bridge.off('main_button_pressed', listener)
bridge.off(PRESS_EVENT, listener)
},
}
}
80 changes: 28 additions & 52 deletions packages/mini-app/src/SecondaryButton.ts
Original file line number Diff line number Diff line change
@@ -1,82 +1,58 @@
import type { Bridge } from './Bridge.ts'
import type { UnsubscribeFn } from './internal/EventBus.ts'
import type { SessionStorage } from './SessionStorage.ts'
import type { Theme } from './Theme.ts'
import { Effect, Store } from '@tanstack/store'
import * as Color from './internal/Color.ts'

/**
* Module for controlling secondary button.
*/
export interface SecondaryButton {
stateStore: Store<State>
setup: (state: null | State) => void
onClick: (listener: () => void) => UnsubscribeFn
offClick: (listener: any) => void
}

export interface State {
text: string
visible: boolean
active: boolean
loading: boolean
shining: boolean
position: 'left' | 'right' | 'top' | 'bottom'
bgColor: string | null
textColor: string | null
}

const INITIAL_STATE: State = {
text: 'Cancel',
visible: false,
active: true,
shining: false,
loading: false,
position: 'left',
bgColor: null,
textColor: null,
loading?: boolean
shining?: boolean
position?: 'left' | 'right' | 'top' | 'bottom'
bgColor?: string
textColor?: string
}

export interface InitOptions {
storage: SessionStorage
bridge: Bridge
theme: Theme
}

const PRESS_EVENT = 'secondary_button_pressed'
const SETUP_EVENT = 'setup_secondary_button'

export const init = ({
storage,
bridge,
theme,
}: InitOptions): SecondaryButton => {
const storedState = storage.storedState<State>('SecondaryButton')
const stateStore = new Store<State>(storedState.load() ?? INITIAL_STATE)
stateStore.subscribe(({ currentVal }) => {
storedState.save(currentVal)
})
const effect = new Effect({
fn: () => {
const state = stateStore.state
const palette = theme.paletteStore.state
bridge.emit('setup_secondary_button', {
text: state.text,
is_visible: state.visible,
is_active: state.active,
is_progress_visible: state.loading,
has_shine_effect: state.shining,
position: state.position,
color: (state.bgColor ? Color.toHex(state.bgColor) : null) ?? palette.bottom_bar_bg_color ?? palette.secondary_bg_color ?? '#ffffff',
text_color: (state.textColor ? Color.toHex(state.textColor) : null) ?? palette.button_color ?? '#2481cc',
})
},
deps: [stateStore, theme.paletteStore],
})
effect.mount()
return {
stateStore,
setup: (state) => {
if (!state?.text) {
bridge.emit(SETUP_EVENT, { is_visible: false })
}
else {
bridge.emit(SETUP_EVENT, {
is_visible: true,
is_active: true,
text: state.text,
is_progress_visible: state.loading,
has_shine_effect: state.shining,
position: state.position,
color: state.bgColor ? Color.toHexUnsafe(state.bgColor) : undefined,
text_color: state.textColor ? Color.toHexUnsafe(state.textColor) : undefined,
})
}
},
onClick: (listener) => {
return bridge.on('secondary_button_pressed', listener)
return bridge.on(PRESS_EVENT, listener)
},
offClick: (listener) => {
bridge.off('secondary_button_pressed', listener)
bridge.off(PRESS_EVENT, listener)
},
}
}
Loading