From 190011d97e14f2353ba88a8924670539db174b38 Mon Sep 17 00:00:00 2001
From: Pavel <14926950+prichodko@users.noreply.github.com>
Date: Fri, 7 Oct 2022 21:30:22 +0200
Subject: [PATCH] Fetch history (#292)
---
packages/status-js/src/client/chat.ts | 7 +-
.../src/helpers/contains-only-emoji.test.ts | 5 +
.../src/helpers/contains-only-emoji.ts | 5 +-
packages/status-react/package.json | 1 +
.../community-info/community-dialog.tsx | 12 +-
packages/status-react/src/protocol/index.tsx | 3 +-
.../status-react/src/protocol/provider.tsx | 23 +--
.../status-react/src/protocol/use-account.tsx | 2 +-
.../src/protocol/use-active-chat.tsx | 2 +-
.../src/protocol/use-activity-center.tsx | 2 +-
.../status-react/src/protocol/use-chat.tsx | 2 +-
.../status-react/src/protocol/use-members.tsx | 2 +-
.../src/protocol/use-messages.tsx | 21 ++-
.../src/protocol/use-protocol.tsx | 22 +++
.../src/protocol/use-sorted-chats.tsx | 2 +-
.../chat/components/chat-input/index.tsx | 3 +-
.../chat/components/chat-message/index.tsx | 165 ++++++++----------
.../components/chat-message/message-reply.tsx | 40 ++---
.../chat/components/date-divider/index.tsx | 32 ++++
.../chat/components/loading-toast/index.tsx | 68 ++++++++
.../chat/components/message-loader/index.tsx | 21 +++
.../status-react/src/routes/chat/index.tsx | 64 +++++--
.../status-react/src/system/button/button.tsx | 58 +++---
.../status-react/src/system/button/styles.tsx | 3 +
yarn.lock | 19 ++
25 files changed, 382 insertions(+), 202 deletions(-)
create mode 100644 packages/status-react/src/protocol/use-protocol.tsx
create mode 100644 packages/status-react/src/routes/chat/components/date-divider/index.tsx
create mode 100644 packages/status-react/src/routes/chat/components/loading-toast/index.tsx
create mode 100644 packages/status-react/src/routes/chat/components/message-loader/index.tsx
diff --git a/packages/status-js/src/client/chat.ts b/packages/status-js/src/client/chat.ts
index 2a2a9e4d..1cb694dc 100644
--- a/packages/status-js/src/client/chat.ts
+++ b/packages/status-js/src/client/chat.ts
@@ -240,9 +240,10 @@ export class Chat {
return
}
- if (!this.#messages.size) {
- return
- }
+ // fixme?: to stop the loading we need to let the listeners know even if there are no messages
+ // if (!this.#messages.size) {
+ // return
+ // }
const messages = this.getMessages()
diff --git a/packages/status-js/src/helpers/contains-only-emoji.test.ts b/packages/status-js/src/helpers/contains-only-emoji.test.ts
index 2bb668a7..4a44fd1d 100644
--- a/packages/status-js/src/helpers/contains-only-emoji.test.ts
+++ b/packages/status-js/src/helpers/contains-only-emoji.test.ts
@@ -5,6 +5,8 @@ import { containsOnlyEmoji } from './contains-only-emoji'
test('should be truthy', () => {
expect(containsOnlyEmoji('💩')).toBeTruthy()
expect(containsOnlyEmoji('💩💩💩💩💩💩')).toBeTruthy()
+ // expect(containsOnlyEmoji('1️⃣')).toBeTruthy()
+ // expect(containsOnlyEmoji('👨👩👧')).toBeTruthy()
})
test('should be falsy', () => {
@@ -14,4 +16,7 @@ test('should be falsy', () => {
expect(containsOnlyEmoji('💩 ')).toBeFalsy()
expect(containsOnlyEmoji('text 💩')).toBeFalsy()
expect(containsOnlyEmoji('💩 text')).toBeFalsy()
+ expect(containsOnlyEmoji('123')).toBeFalsy()
+ expect(containsOnlyEmoji('💩 123')).toBeFalsy()
+ expect(containsOnlyEmoji('123 💩💩💩 ')).toBeFalsy()
})
diff --git a/packages/status-js/src/helpers/contains-only-emoji.ts b/packages/status-js/src/helpers/contains-only-emoji.ts
index 60525bbc..0ef68c73 100644
--- a/packages/status-js/src/helpers/contains-only-emoji.ts
+++ b/packages/status-js/src/helpers/contains-only-emoji.ts
@@ -1,4 +1,7 @@
// todo?: should ignore whitespaces with replace(/\s+/g, '').trim()
+/**
+ * https://www.unicode.org/reports/tr51/#def_emoji_presentation
+ */
export function containsOnlyEmoji(text: string): boolean {
- return /^\p{Emoji}+$/gu.test(text)
+ return /^\p{Emoji_Presentation}+$/gu.test(text)
}
diff --git a/packages/status-react/package.json b/packages/status-react/package.json
index 61bff02d..df19fe45 100644
--- a/packages/status-react/package.json
+++ b/packages/status-react/package.json
@@ -42,6 +42,7 @@
"@radix-ui/react-label": "^0.1.5",
"@radix-ui/react-popover": "^0.1.6",
"@radix-ui/react-separator": "^0.1.4",
+ "@radix-ui/react-toast": "^0.1.1",
"@radix-ui/react-tabs": "^1.0.0",
"@radix-ui/react-toggle-group": "^0.1.5",
"@radix-ui/react-tooltip": "^1.0.0",
diff --git a/packages/status-react/src/components/main-sidebar/components/community-info/community-dialog.tsx b/packages/status-react/src/components/main-sidebar/components/community-info/community-dialog.tsx
index f54a17ab..f8c13530 100644
--- a/packages/status-react/src/components/main-sidebar/components/community-info/community-dialog.tsx
+++ b/packages/status-react/src/components/main-sidebar/components/community-info/community-dialog.tsx
@@ -56,17 +56,7 @@ export const CommunityDialog = () => {
fill="currentColor"
/>
-
+
diff --git a/packages/status-react/src/protocol/index.tsx b/packages/status-react/src/protocol/index.tsx
index 666c0f45..f89b0dc4 100644
--- a/packages/status-react/src/protocol/index.tsx
+++ b/packages/status-react/src/protocol/index.tsx
@@ -1,4 +1,4 @@
-export { ProtocolProvider, useProtocol } from './provider'
+export { ProtocolProvider } from './provider'
export type { Account } from './use-account'
export { useAccount } from './use-account'
export { useActivityCenter } from './use-activity-center'
@@ -8,4 +8,5 @@ export type { Member } from './use-members'
export { useMembers } from './use-members'
export type { Message, Reaction, Reactions } from './use-messages'
export { useMessages } from './use-messages'
+export { useProtocol } from './use-protocol'
export { useSortedChats } from './use-sorted-chats'
diff --git a/packages/status-react/src/protocol/provider.tsx b/packages/status-react/src/protocol/provider.tsx
index 781bfc5f..a7517513 100644
--- a/packages/status-react/src/protocol/provider.tsx
+++ b/packages/status-react/src/protocol/provider.tsx
@@ -1,4 +1,4 @@
-import React, { createContext, useContext, useEffect, useReducer } from 'react'
+import React, { createContext, useEffect, useReducer } from 'react'
import { createClient } from '@status-im/js'
@@ -6,9 +6,9 @@ import { Loading } from '../components/loading'
import type { Account, Client, ClientOptions, Community } from '@status-im/js'
-const Context = createContext(undefined)
+export const Context = createContext(undefined)
-type State = {
+export type State = {
loading: boolean
client: Client | undefined
community: Community['description'] | undefined
@@ -16,7 +16,7 @@ type State = {
dispatch?: React.Dispatch
}
-type Action =
+export type Action =
| { type: 'INIT'; client: Client }
| { type: 'UPDATE_COMMUNITY'; community: Community['description'] }
| { type: 'SET_ACCOUNT'; account: Account | undefined }
@@ -99,18 +99,3 @@ export const ProtocolProvider = (props: Props) => {
)
}
-
-export function useProtocol() {
- const context = useContext(Context)
-
- if (!context) {
- throw new Error(`useProtocol must be used within a ProtocolProvider`)
- }
-
- // we enforce initialization of client before rendering children
- return context as State & {
- client: Client
- community: Community['description']
- dispatch: React.Dispatch
- }
-}
diff --git a/packages/status-react/src/protocol/use-account.tsx b/packages/status-react/src/protocol/use-account.tsx
index fd942949..2b6ede98 100644
--- a/packages/status-react/src/protocol/use-account.tsx
+++ b/packages/status-react/src/protocol/use-account.tsx
@@ -1,4 +1,4 @@
-import { useProtocol } from './provider'
+import { useProtocol } from './use-protocol'
import type { Account } from '@status-im/js'
diff --git a/packages/status-react/src/protocol/use-active-chat.tsx b/packages/status-react/src/protocol/use-active-chat.tsx
index e3531572..14e55334 100644
--- a/packages/status-react/src/protocol/use-active-chat.tsx
+++ b/packages/status-react/src/protocol/use-active-chat.tsx
@@ -1,6 +1,6 @@
import { useMatch } from 'react-router-dom'
-import { useProtocol } from './provider'
+import { useProtocol } from './use-protocol'
export const useActiveChat = () => {
const { client } = useProtocol()
diff --git a/packages/status-react/src/protocol/use-activity-center.tsx b/packages/status-react/src/protocol/use-activity-center.tsx
index a4f6f07d..92738f21 100644
--- a/packages/status-react/src/protocol/use-activity-center.tsx
+++ b/packages/status-react/src/protocol/use-activity-center.tsx
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
-import { useProtocol } from './provider'
+import { useProtocol } from './use-protocol'
import type { ActivityCenterLatest } from '@status-im/js'
diff --git a/packages/status-react/src/protocol/use-chat.tsx b/packages/status-react/src/protocol/use-chat.tsx
index 05df3cf1..c838a970 100644
--- a/packages/status-react/src/protocol/use-chat.tsx
+++ b/packages/status-react/src/protocol/use-chat.tsx
@@ -1,6 +1,6 @@
import { useMemo } from 'react'
-import { useProtocol } from './provider'
+import { useProtocol } from './use-protocol'
import type { Community } from '@status-im/js'
diff --git a/packages/status-react/src/protocol/use-members.tsx b/packages/status-react/src/protocol/use-members.tsx
index e3f1cace..aa930731 100644
--- a/packages/status-react/src/protocol/use-members.tsx
+++ b/packages/status-react/src/protocol/use-members.tsx
@@ -1,4 +1,4 @@
-import { useProtocol } from './provider'
+import { useProtocol } from './use-protocol'
import type { Member } from '@status-im/js'
diff --git a/packages/status-react/src/protocol/use-messages.tsx b/packages/status-react/src/protocol/use-messages.tsx
index 2a5d3aeb..2c03b363 100644
--- a/packages/status-react/src/protocol/use-messages.tsx
+++ b/packages/status-react/src/protocol/use-messages.tsx
@@ -1,6 +1,8 @@
import { useEffect, useState } from 'react'
-import { useProtocol } from './provider'
+import sub from 'date-fns/sub'
+
+import { useProtocol } from './use-protocol'
import type { Message, Reactions } from '@status-im/js'
@@ -9,21 +11,20 @@ type Reaction = keyof Reactions
interface Result {
data: Message[]
loading: boolean
- // error?: Error
- // fetchMore: () => void
}
-export const useMessages = (channelId: string): Result => {
+export const useMessages = (chatId: string): Result => {
const { client } = useProtocol()
- const chat = client.community.chats.get(channelId)!
- // const [state, dispatch] = useReducer((state,action) => {}, {})
+ const chat = client.community.chats.get(chatId)!
const [data, setData] = useState(() => chat.getMessages())
const [loading, setLoading] = useState(true)
// const [error, setError] = useState()
useEffect(() => {
+ const messages = chat.getMessages()
+
setData(chat.getMessages())
const handleUpdate = (messages: Message[]) => {
@@ -31,15 +32,21 @@ export const useMessages = (channelId: string): Result => {
setData(messages)
}
+ if (messages.length === 0) {
+ setLoading(true)
+ chat.fetchMessages({ start: sub(new Date(), { days: 30 }) })
+ }
+
return chat.onMessage(handleUpdate)
}, [chat])
return {
data,
loading,
+ // fetchMore,
+ // fetching,
// error,
// hasMore
- // fetchMore,
// refetch
}
}
diff --git a/packages/status-react/src/protocol/use-protocol.tsx b/packages/status-react/src/protocol/use-protocol.tsx
new file mode 100644
index 00000000..f898d03f
--- /dev/null
+++ b/packages/status-react/src/protocol/use-protocol.tsx
@@ -0,0 +1,22 @@
+import { useContext } from 'react'
+
+import { Context } from './provider'
+
+import type { Action, State } from './provider'
+import type { Client, Community } from '@status-im/js'
+import type React from 'react'
+
+export function useProtocol() {
+ const context = useContext(Context)
+
+ if (!context) {
+ throw new Error(`useProtocol must be used within a ProtocolProvider`)
+ }
+
+ // we enforce initialization of client before rendering children
+ return context as State & {
+ client: Client
+ community: Community['description']
+ dispatch: React.Dispatch
+ }
+}
diff --git a/packages/status-react/src/protocol/use-sorted-chats.tsx b/packages/status-react/src/protocol/use-sorted-chats.tsx
index 093656b2..d6a792fd 100644
--- a/packages/status-react/src/protocol/use-sorted-chats.tsx
+++ b/packages/status-react/src/protocol/use-sorted-chats.tsx
@@ -1,6 +1,6 @@
import { useMemo } from 'react'
-import { useProtocol } from './provider'
+import { useProtocol } from './use-protocol'
import type { Community } from '@status-im/js'
diff --git a/packages/status-react/src/routes/chat/components/chat-input/index.tsx b/packages/status-react/src/routes/chat/components/chat-input/index.tsx
index 618a5756..3db7bb52 100644
--- a/packages/status-react/src/routes/chat/components/chat-input/index.tsx
+++ b/packages/status-react/src/routes/chat/components/chat-input/index.tsx
@@ -82,7 +82,8 @@ const Wrapper = styled('div', {
display: 'flex',
overflow: 'hidden',
alignItems: 'flex-end',
- padding: '12px 8px 12px 4px',
+ // padding: '12px 8px 12px 4px',
+ padding: '12px 8px 12px 8px',
gap: 4,
})
diff --git a/packages/status-react/src/routes/chat/components/chat-message/index.tsx b/packages/status-react/src/routes/chat/components/chat-message/index.tsx
index de1125c6..d42f4eef 100644
--- a/packages/status-react/src/routes/chat/components/chat-message/index.tsx
+++ b/packages/status-react/src/routes/chat/components/chat-message/index.tsx
@@ -31,7 +31,7 @@ import type { Message, Reaction } from '../../../../protocol'
interface Props {
message: Message
- prevMessage?: Message
+ collapse: boolean
highlight?: boolean
}
@@ -57,16 +57,17 @@ interface Props {
// })
export const ChatMessage = (props: Props) => {
+ const { message, collapse, highlight } = props
+
const { client, account } = useProtocol()
const { params } = useMatch(':id')!
const chatId = params.id!
- const { message, highlight } = props
const mention = false
const pinned = false
- const { messageId, contentType, clock, reactions, signer, responseTo } =
+ const { messageId, contentType, timestamp, reactions, signer, responseTo } =
message
// TODO: remove usage of 0x prefix
@@ -74,6 +75,7 @@ export const ChatMessage = (props: Props) => {
const chat = client.community.getChat(chatId)!
const member = client.community.getMember(signer)!
+ const response = client.community.getChat(params.id!)!.getMessage(responseTo)
const [editing, setEditing] = useState(false)
const [reacting, setReacting] = useState(false)
@@ -82,6 +84,7 @@ export const ChatMessage = (props: Props) => {
// const userProfileDialog = useDialog(UserProfileDialog)
+ // TODO: fix saving of edited message
const handleMessageSubmit = (message: string) => {
chat.sendTextMessage(message)
}
@@ -107,7 +110,7 @@ export const ChatMessage = (props: Props) => {
// TODO: pin message
}
- const renderMessage = () => {
+ const renderContent = () => {
if (editing) {
return (
@@ -170,100 +173,85 @@ export const ChatMessage = (props: Props) => {
}
}
- return (
- <>
- {/* */}
-
- {responseTo && }
-
-
- {/*
- */}
- {/*
-
-
- {member!.username}
-
-
-
- }
- onSelect={() => userProfileDialog.open({ member })}
- >
- View Profile
-
- }>
- Send Message
-
- }>
- Verify Identity
-
- }>
- Send Contact Request
-
-
- } danger>
- Mark as Untrustworthy
-
-
- */}
-
+ const renderMessage = () => {
+ if (collapse) {
+ return (
+
+ {renderContent()}
+
+
+ )
+ }
-
- {/* {pinned && (
+ return (
+
+
+
+
+
+
+ {/* {pinned && (
+
+
+
+ {/* {pinned && (
Pinned by {contact.name}
)} */}
-
-
- {member!.username}
-
-
- {new Date(Number(clock)).toLocaleTimeString([], {
- hour: '2-digit',
- minute: '2-digit',
- })}
-
-
+
+
+ {member!.username}
+
+
+ {new Date(Number(timestamp)).toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ })}
+
+
- {renderMessage()}
+ {renderContent()}
-
-
-
+
+
+
+ )
+ }
- setEditing(true)}
- onReplyClick={handleReplyClick}
- onPinClick={handlePinClick}
- onDeleteClick={handleMessageDelete}
- onReactionClick={handleReaction}
- reacting={reacting}
- onReactingChange={setReacting}
- reactions={reactions}
- />
+ return (
+ <>
+ {/* */}
+
+ {response && }
+ {renderMessage()}
+
+ {account && (
+ setEditing(true)}
+ onReplyClick={handleReplyClick}
+ onPinClick={handlePinClick}
+ onDeleteClick={handleMessageDelete}
+ onReactionClick={handleReaction}
+ reacting={reacting}
+ onReactingChange={setReacting}
+ reactions={reactions}
+ />
+ )}
- {/*
- Reply
- Pin
- */}
- {/* */}
>
)
}
@@ -280,7 +268,8 @@ const backgroundAnimation = keyframes({
// TODO: Use compound variants https://stitches.dev/docs/variants#compound-variants
const Wrapper = styled('div', {
position: 'relative',
- padding: '10px 16px',
+ padding: '2px 16px',
+ marginTop: 14,
gap: '$2',
transitionProperty: 'background-color, border-color, color, fill, stroke',
diff --git a/packages/status-react/src/routes/chat/components/chat-message/message-reply.tsx b/packages/status-react/src/routes/chat/components/chat-message/message-reply.tsx
index 3c33a6f6..683f5745 100644
--- a/packages/status-react/src/routes/chat/components/chat-message/message-reply.tsx
+++ b/packages/status-react/src/routes/chat/components/chat-message/message-reply.tsx
@@ -1,47 +1,37 @@
import React from 'react'
-import { useMatch } from 'react-router-dom'
-
import { useProtocol } from '../../../../protocol'
import { styled } from '../../../../styles/config'
import { Avatar, Box, Flex, Image, Text } from '../../../../system'
+import type { Message } from '../../../../protocol'
+
interface Props {
- messageId: string
+ message: Message
}
export const MessageReply = (props: Props) => {
- const { messageId } = props
+ const { message } = props
const { client } = useProtocol()
- // TODO: use protocol hook
- const { params } = useMatch(':id')! // eslint-disable-line @typescript-eslint/no-non-null-assertion
- const message = client.community.getChat(params.id!)!.getMessage(messageId)
-
- if (!message) {
- return (
-
-
- Message not available.
-
-
- )
- }
+ // if (!message) {
+ // return (
+ //
+ //
+ // Message not available.
+ //
+ //
+ // )
+ // }
const { contentType, text, signer } = message
-
- // TODO: can this happen?
- const member = client.community.getMember(signer)
-
- if (!member) {
- return null
- }
+ const member = client.community.getMember(signer)!
return (
-
+
{member.username}
diff --git a/packages/status-react/src/routes/chat/components/date-divider/index.tsx b/packages/status-react/src/routes/chat/components/date-divider/index.tsx
new file mode 100644
index 00000000..0a7ec31d
--- /dev/null
+++ b/packages/status-react/src/routes/chat/components/date-divider/index.tsx
@@ -0,0 +1,32 @@
+import React from 'react'
+
+import isSameDay from 'date-fns/isSameDay'
+
+import { Flex, Text } from '../../../../system'
+
+interface Props {
+ date: Date
+}
+
+export const DateDivider = (props: Props) => {
+ const { date } = props
+
+ let label = date.toLocaleDateString([], { weekday: 'long' })
+
+ const today = new Date()
+ const yesterday = new Date().setDate(today.getDate() - 1)
+
+ if (isSameDay(date, today)) {
+ label = 'Today'
+ } else if (isSameDay(date, yesterday)) {
+ label = 'Yesterday'
+ }
+
+ return (
+
+
+ {label}
+
+
+ )
+}
diff --git a/packages/status-react/src/routes/chat/components/loading-toast/index.tsx b/packages/status-react/src/routes/chat/components/loading-toast/index.tsx
new file mode 100644
index 00000000..5766063d
--- /dev/null
+++ b/packages/status-react/src/routes/chat/components/loading-toast/index.tsx
@@ -0,0 +1,68 @@
+import React from 'react'
+
+import { keyframes } from '../../../../styles/config'
+import { Box, Text } from '../../../../system'
+
+interface Props {
+ label: string
+}
+const fadeIn = keyframes({
+ from: { opacity: 0, top: 0 },
+ to: { opacity: 1 },
+})
+
+const spin = keyframes({
+ to: {
+ transform: 'rotate(1turn)',
+ },
+})
+
+export const LoadingToast = (props: Props) => {
+ const { label } = props
+
+ return (
+
+
+
+
+ Loading {label}...
+
+
+ )
+}
diff --git a/packages/status-react/src/routes/chat/components/message-loader/index.tsx b/packages/status-react/src/routes/chat/components/message-loader/index.tsx
new file mode 100644
index 00000000..369f61bd
--- /dev/null
+++ b/packages/status-react/src/routes/chat/components/message-loader/index.tsx
@@ -0,0 +1,21 @@
+import React from 'react'
+
+import ContentLoader from 'react-content-loader'
+
+export const MessageLoader = () => {
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/packages/status-react/src/routes/chat/index.tsx b/packages/status-react/src/routes/chat/index.tsx
index 5346567c..cd0f909b 100644
--- a/packages/status-react/src/routes/chat/index.tsx
+++ b/packages/status-react/src/routes/chat/index.tsx
@@ -1,5 +1,6 @@
-import React, { useEffect, useRef } from 'react'
+import React, { Fragment, useEffect, useRef } from 'react'
+import isSameDay from 'date-fns/isSameDay'
import { useLocation, useMatch } from 'react-router-dom'
import { MemberSidebar } from '../../components/member-sidebar'
@@ -10,6 +11,9 @@ import { styled } from '../../styles/config'
import { Avatar, Flex, Heading, Text } from '../../system'
import { ChatInput } from './components/chat-input'
import { ChatMessage } from './components/chat-message'
+import { DateDivider } from './components/date-divider'
+import { LoadingToast } from './components/loading-toast'
+import { MessageLoader } from './components/message-loader'
import { Navbar } from './components/navbar'
interface ChatStartProps {
@@ -75,20 +79,52 @@ const Body = () => {
chat.sendTextMessage(message, state.reply?.message.messageId)
}
+ const renderContent = () => {
+ if (messages.loading) {
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+ }
+
+ if (messages.data.length === 0) {
+ return
+ }
+
+ return messages.data.map((message, index) => {
+ const sentDate = new Date(Number(message.timestamp))
+ const previousMessage = messages.data[index - 1]
+
+ let hasDateSeparator = true
+
+ if (previousMessage) {
+ const prevSentDate = new Date(Number(previousMessage.timestamp))
+
+ if (isSameDay(prevSentDate, sentDate)) {
+ hasDateSeparator = false
+ }
+ }
+
+ const shouldCollapse =
+ !message.responseTo && message.signer === previousMessage?.signer
+
+ return (
+
+ {hasDateSeparator && }
+
+
+ )
+ })
+ }
+
return (
<>
-
-
- {messages.data.map(message => {
- return (
-
- )
- })}
-
+ {renderContent()}
{account && }
>
)
@@ -130,7 +166,7 @@ const ContentWrapper = styled('div', {
overscrollBehavior: 'contain',
// scrollSnapType: 'y proximity',
-
+ paddingBottom: 16,
// '& > div:last-child': {
// scrollSnapAlign: 'end',
// scrollMarginBlockEnd: '1px',
diff --git a/packages/status-react/src/system/button/button.tsx b/packages/status-react/src/system/button/button.tsx
index c8882407..36e763da 100644
--- a/packages/status-react/src/system/button/button.tsx
+++ b/packages/status-react/src/system/button/button.tsx
@@ -5,40 +5,46 @@ import { Base } from './styles'
import type { Variants } from './styles'
import type { Ref } from 'react'
-type ButtonProps = React.ButtonHTMLAttributes
-
-interface Props {
- children: string
- disabled?: boolean
+type ButtonProps = React.ButtonHTMLAttributes & {
loading?: boolean
- active?: boolean
- type?: ButtonProps['type']
- onClick?: ButtonProps['onClick']
+}
+type AnchorProps = React.AnchorHTMLAttributes & {
+ href: string
+}
+
+type Props = (AnchorProps | ButtonProps) & {
+ children: string
variant?: Variants['variant']
size?: Variants['size']
+ disabled?: boolean
}
const Button = (props: Props, ref: Ref) => {
- const {
- type = 'button',
- children,
- disabled,
- loading,
- onClick,
- variant = 'default',
- ...buttonProps
- } = props
+ const { children } = props
+
+ if ('href' in props) {
+ const { href, ...linkProps } = props
+ const external = href.startsWith('http')
+
+ return (
+
+ {children}
+
+ )
+ }
+
+ const { type = 'button', loading, ...buttonProps } = props
return (
-
+
{children}
)
diff --git a/packages/status-react/src/system/button/styles.tsx b/packages/status-react/src/system/button/styles.tsx
index 65fa7401..f4c804b2 100644
--- a/packages/status-react/src/system/button/styles.tsx
+++ b/packages/status-react/src/system/button/styles.tsx
@@ -81,4 +81,7 @@ export const Base = styled('button', {
},
},
},
+ defaultVariants: {
+ variant: 'default',
+ },
})
diff --git a/yarn.lock b/yarn.lock
index 971d4795..770d0875 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1916,6 +1916,24 @@
"@radix-ui/react-roving-focus" "1.0.0"
"@radix-ui/react-use-controllable-state" "1.0.0"
+"@radix-ui/react-toast@^0.1.1":
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-0.1.1.tgz#d544e796b307e56f1298e40f356f468680958e93"
+ integrity sha512-9JWC4mPP78OE6muDrpaPf/71dIeozppdcnik1IvsjTxZpDnt9PbTtQj94DdWjlCphbv3S5faD3KL0GOpqKBpTQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "0.1.0"
+ "@radix-ui/react-compose-refs" "0.1.0"
+ "@radix-ui/react-context" "0.1.1"
+ "@radix-ui/react-dismissable-layer" "0.1.5"
+ "@radix-ui/react-portal" "0.1.4"
+ "@radix-ui/react-presence" "0.1.2"
+ "@radix-ui/react-primitive" "0.1.4"
+ "@radix-ui/react-use-callback-ref" "0.1.0"
+ "@radix-ui/react-use-controllable-state" "0.1.0"
+ "@radix-ui/react-use-layout-effect" "0.1.0"
+ "@radix-ui/react-visually-hidden" "0.1.4"
+
"@radix-ui/react-toggle-group@^0.1.5":
version "0.1.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-0.1.5.tgz#9e4d65e22c4fc0ba3a42fbc8d5496c430e5e9852"
@@ -5397,6 +5415,7 @@ netmask@^2.0.2:
node-fetch@^2.x.x:
version "2.6.7"
+ uid "1b5d62978f2ed07b99444f64f0df39f960a6d34d"
resolved "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz#1b5d62978f2ed07b99444f64f0df39f960a6d34d"
node-forge@^1.1.0, node-forge@^1.3.1: