From 42eb4013d02c6f71886d5f206edb62bc81139194 Mon Sep 17 00:00:00 2001 From: Josh Perez <60019601+josh-signal@users.noreply.github.com> Date: Mon, 6 Jun 2022 20:48:02 -0400 Subject: [PATCH] Upgrade react and storybook --- .storybook/addons.js | 5 - .storybook/config.js | 141 - .storybook/main.js | 17 + .storybook/preview.tsx | 87 + .storybook/styles.scss | 13 +- .storybook/webpack.config.js | 9 +- .yarnclean | 1 - package.json | 58 +- .../components/ShareButtons.stories.tsx | 13 +- .../components/StickerFrame.stories.tsx | 13 +- .../components/StickerPackPreview.stories.tsx | 34 +- .../components/Toaster.stories.tsx | 9 +- sticker-creator/elements/Button.stories.tsx | 9 +- .../elements/ConfirmDialog.stories.tsx | 13 +- sticker-creator/elements/CopyText.stories.tsx | 13 +- sticker-creator/elements/DropZone.stories.tsx | 13 +- .../elements/LabeledCheckbox.stories.tsx | 9 +- .../elements/LabeledInput.stories.tsx | 13 +- .../elements/MessageBubble.stories.tsx | 13 +- .../elements/MessageSticker.stories.tsx | 13 +- .../elements/PageHeader.stories.tsx | 13 +- .../elements/ProgressBar.stories.tsx | 13 +- .../elements/StickerPreview.stories.tsx | 13 +- sticker-creator/elements/Toast.stories.tsx | 9 +- .../elements/Typography.stories.tsx | 9 +- .../AddGroupMemberErrorDialog.stories.tsx | 21 +- ts/components/Alert.stories.tsx | 37 +- ts/components/AnimatedEmojiGalore.stories.tsx | 9 +- ts/components/Avatar.stories.tsx | 388 +- ts/components/AvatarColorPicker.stories.tsx | 13 +- ts/components/AvatarEditor.stories.tsx | 28 +- ts/components/AvatarIconEditor.stories.tsx | 13 +- ts/components/AvatarLightbox.stories.tsx | 17 +- ts/components/AvatarModalButtons.stories.tsx | 21 +- ts/components/AvatarPopup.stories.tsx | 33 +- ts/components/AvatarPreview.stories.tsx | 61 +- ts/components/AvatarTextEditor.stories.tsx | 23 +- ts/components/AvatarUploadButton.stories.tsx | 9 +- ts/components/BadgeDescription.stories.tsx | 21 +- ts/components/BadgeDialog.stories.tsx | 69 +- ts/components/BetterAvatar.stories.tsx | 17 +- ts/components/BetterAvatarBubble.stories.tsx | 17 +- ts/components/Button.stories.tsx | 29 +- ts/components/CallManager.stories.tsx | 43 +- ts/components/CallScreen.stories.tsx | 105 +- .../CallingAudioIndicator.stories.tsx | 13 +- ts/components/CallingButton.stories.tsx | 49 +- .../CallingDeviceSelection.stories.tsx | 21 +- ts/components/CallingHeader.stories.tsx | 39 +- ts/components/CallingLobby.stories.tsx | 93 +- .../CallingParticipantsList.stories.tsx | 25 +- ts/components/CallingPip.stories.tsx | 29 +- ts/components/CallingPreCallInfo.stories.tsx | 275 +- ...CallingScreenSharingController.stories.tsx | 17 +- ...ngSelectPresentingSourcesModal.stories.tsx | 12 +- ts/components/CaptchaDialog.stories.tsx | 13 +- ts/components/ChatColorPicker.stories.tsx | 13 +- ts/components/Checkbox.stories.tsx | 20 +- ts/components/ClearingData.stories.tsx | 13 +- ts/components/CompositionArea.stories.tsx | 61 +- ts/components/CompositionInput.stories.tsx | 33 +- .../ConfirmDiscardDialog.stories.tsx | 9 +- ts/components/ConfirmationDialog.stories.tsx | 99 +- ts/components/ContactPills.stories.tsx | 43 +- ts/components/ContextMenu.stories.tsx | 9 +- ts/components/ConversationList.stories.tsx | 670 +- ts/components/CrashReportDialog.stories.tsx | 13 +- ts/components/CustomColorEditor.stories.tsx | 9 +- ...omizingPreferredReactionsModal.stories.tsx | 33 +- ts/components/DebugLogWindow.stories.tsx | 13 +- ts/components/DialogExpiredBuild.stories.tsx | 46 +- ts/components/DialogNetworkStatus.stories.tsx | 183 +- ts/components/DialogRelink.stories.tsx | 47 +- ts/components/DialogUpdate.stories.tsx | 367 +- .../DisappearingTimeDialog.stories.tsx | 61 +- .../DisappearingTimerSelect.stories.tsx | 21 +- ts/components/ErrorModal.stories.tsx | 15 +- ts/components/ForwardMessageModal.stories.tsx | 57 +- .../GroupCallOverflowArea.stories.tsx | 37 +- .../GroupCallRemoteParticipant.stories.tsx | 25 +- .../GroupDescriptionInput.stories.tsx | 12 +- ts/components/GroupTitleInput.stories.tsx | 12 +- .../GroupV1MigrationDialog.stories.tsx | 70 +- ts/components/GroupV2JoinDialog.stories.tsx | 45 +- ts/components/IdenticonSVG.stories.tsx | 30 +- ts/components/InContactsIcon.stories.tsx | 10 +- ts/components/IncomingCallBar.stories.tsx | 186 +- ts/components/Input.stories.tsx | 63 +- ts/components/Intl.stories.tsx | 104 +- ts/components/LeftPane.stories.tsx | 383 +- ts/components/Lightbox.stories.tsx | 77 +- ts/components/MainHeader.stories.tsx | 25 +- ts/components/MediaEditor.stories.tsx | 21 +- .../MediaQualitySelector.stories.tsx | 13 +- ts/components/Modal.stories.tsx | 93 +- ...atedGroupInvitedContactsDialog.stories.tsx | 24 +- .../OutgoingGiftBadgeModal.stories.tsx | 17 +- ts/components/Preferences.stories.tsx | 25 +- ts/components/ProfileEditor.stories.tsx | 73 +- ts/components/ProgressDialog.stories.tsx | 9 +- ts/components/ProgressModal.stories.tsx | 9 +- ts/components/QrCode.stories.tsx | 9 +- .../SafetyNumberChangeDialog.stories.tsx | 228 +- ts/components/SafetyNumberViewer.stories.tsx | 49 +- ts/components/Select.stories.tsx | 17 +- ts/components/ShortcutGuide.stories.tsx | 18 +- ts/components/Slider.stories.tsx | 11 +- ts/components/Spinner.stories.tsx | 41 +- ts/components/Stories.stories.tsx | 12 +- ts/components/StoryImage.stories.tsx | 69 +- ts/components/StoryListItem.stories.tsx | 25 +- ts/components/StoryViewer.stories.tsx | 45 +- .../StoryViewsNRepliesModal.stories.tsx | 37 +- ts/components/TextAttachment.stories.tsx | 130 +- .../ToastAlreadyGroupMember.stories.tsx | 13 +- .../ToastAlreadyRequestedToJoin.stories.tsx | 13 +- ts/components/ToastBlocked.stories.tsx | 13 +- ts/components/ToastBlockedGroup.stories.tsx | 13 +- ...MixImageAndNonImageAttachments.stories.tsx | 16 +- ts/components/ToastCaptchaFailed.stories.tsx | 13 +- ts/components/ToastCaptchaSolved.stories.tsx | 13 +- .../ToastConversationArchived.stories.tsx | 13 +- .../ToastConversationMarkedUnread.stories.tsx | 13 +- .../ToastConversationUnarchived.stories.tsx | 13 +- .../ToastDangerousFileType.stories.tsx | 13 +- ts/components/ToastDebugLogError.stories.tsx | 13 +- .../ToastDecryptionError.stories.tsx | 13 +- .../ToastDeleteForEveryoneFailed.stories.tsx | 13 +- ts/components/ToastExpired.stories.tsx | 13 +- .../ToastFailedToDeleteUsername.stories.tsx | 13 +- ts/components/ToastFileSaved.stories.tsx | 13 +- ts/components/ToastFileSize.stories.tsx | 13 +- .../ToastGroupLinkCopied.stories.tsx | 13 +- .../ToastInvalidConversation.stories.tsx | 13 +- ts/components/ToastLeftGroup.stories.tsx | 13 +- ts/components/ToastLinkCopied.stories.tsx | 13 +- .../ToastLoadingFullLogs.stories.tsx | 13 +- ts/components/ToastMaxAttachments.stories.tsx | 13 +- .../ToastMessageBodyTooLong.stories.tsx | 13 +- .../ToastOneNonImageAtATime.stories.tsx | 13 +- .../ToastOriginalMessageNotFound.stories.tsx | 13 +- .../ToastPinnedConversationsFull.stories.tsx | 13 +- ts/components/ToastReactionFailed.stories.tsx | 13 +- .../ToastReportedSpamAndBlocked.stories.tsx | 13 +- .../ToastStickerPackInstallFailed.stories.tsx | 13 +- .../ToastTapToViewExpiredIncoming.stories.tsx | 13 +- .../ToastTapToViewExpiredOutgoing.stories.tsx | 13 +- .../ToastUnableToLoadAttachment.stories.tsx | 13 +- ts/components/ToastVoiceNoteLimit.stories.tsx | 13 +- ...tVoiceNoteMustBeOnlyAttachment.stories.tsx | 16 +- ts/components/Tooltip.stories.tsx | 33 +- ts/components/WhatsNewModal.stories.tsx | 9 +- .../conversation/AddNewLines.stories.tsx | 38 +- .../conversation/AtMentionify.stories.tsx | 29 +- .../conversation/AttachmentList.stories.tsx | 25 +- .../conversation/AudioCapture.stories.tsx | 25 +- .../CallingNotification.stories.tsx | 232 +- .../ChangeNumberNotification.stories.tsx | 20 +- .../ChatSessionRefreshedDialog.stories.tsx | 26 +- ...atSessionRefreshedNotification.stories.tsx | 12 +- .../conversation/ContactDetail.stories.tsx | 53 +- .../conversation/ContactModal.stories.tsx | 61 +- .../conversation/ContactName.stories.tsx | 55 +- .../ContactSpoofingReviewDialog.stories.tsx | 98 +- .../ConversationHeader.stories.tsx | 572 +- .../conversation/ConversationHero.stories.tsx | 773 +- .../DeliveryIssueDialog.stories.tsx | 55 +- .../DeliveryIssueNotification.stories.tsx | 24 +- .../conversation/Emojify.stories.tsx | 65 +- .../conversation/ErrorBoundary.stories.tsx | 13 +- .../conversation/ExpireTimer.stories.tsx | 49 +- .../conversation/GroupDescription.stories.tsx | 45 +- .../GroupNotification.stories.tsx | 35 +- .../GroupV1DisabledActions.stories.tsx | 12 +- .../conversation/GroupV1Migration.stories.tsx | 53 +- .../conversation/GroupV2Change.stories.tsx | 2980 +++--- .../GroupV2PendingApprovalActions.stories.tsx | 12 +- ts/components/conversation/Image.stories.tsx | 107 +- .../conversation/ImageGrid.stories.tsx | 54 +- .../LastSeenIndicator.stories.tsx | 17 +- .../conversation/Linkify.stories.tsx | 53 +- ...MandatoryProfileSharingActions.stories.tsx | 35 +- .../conversation/Message.stories.tsx | 737 +- .../conversation/MessageBody.stories.tsx | 61 +- .../MessageBodyReadMore.stories.tsx | 49 +- .../conversation/MessageDetail.stories.tsx | 29 +- .../MessageRequestActions.stories.tsx | 73 +- .../conversation/MessageTimestamp.stories.tsx | 13 +- .../ProfileChangeNotification.stories.tsx | 125 +- ts/components/conversation/Quote.stories.tsx | 206 +- .../conversation/ReactionPicker.stories.tsx | 73 +- .../conversation/ReactionViewer.stories.tsx | 21 +- .../ResetSessionNotification.stories.tsx | 13 +- .../SafetyNumberNotification.stories.tsx | 24 +- .../conversation/ScrollDownButton.stories.tsx | 13 +- .../StagedGenericAttachment.stories.tsx | 20 +- .../StagedLinkPreview.stories.tsx | 70 +- .../StagedPlaceholderAttachment.stories.tsx | 12 +- .../conversation/Timeline.stories.tsx | 85 +- .../TimelineFloatingHeader.stories.tsx | 13 +- .../conversation/TimelineItem.stories.tsx | 795 +- .../TimerNotification.stories.tsx | 25 +- .../conversation/TypingAnimation.stories.tsx | 13 +- .../conversation/TypingBubble.stories.tsx | 21 +- .../UniversalTimerNotification.stories.tsx | 44 +- .../UnsupportedMessage.stories.tsx | 21 +- .../VerificationNotification.stories.tsx | 48 +- .../AddGroupMembersModal.stories.tsx | 44 +- .../ConversationDetails.stories.tsx | 60 +- .../ConversationDetailsActions.stories.tsx | 45 +- .../ConversationDetailsHeader.stories.tsx | 44 +- .../ConversationDetailsIcon.stories.tsx | 36 +- .../ConversationDetailsMediaList.stories.tsx | 12 +- ...versationDetailsMembershipList.stories.tsx | 49 +- ...versationNotificationsSettings.stories.tsx | 33 +- ...ditConversationAttributesModal.stories.tsx | 49 +- .../GroupLinkManagement.stories.tsx | 48 +- .../GroupV2Permissions.stories.tsx | 36 +- .../conversation-details/PanelRow.stories.tsx | 24 +- .../PanelSection.stories.tsx | 24 +- .../PendingInvites.stories.tsx | 20 +- .../AttachmentSection.stories.tsx | 21 +- .../DocumentListItem.stories.tsx | 39 +- .../media-gallery/EmptyState.stories.tsx | 17 +- .../media-gallery/MediaGallery.stories.tsx | 28 +- .../media-gallery/MediaGridItem.stories.tsx | 45 +- .../MessageBodyHighlight.stories.tsx | 43 +- .../MessageSearchResult.stories.tsx | 139 +- ts/components/emoji/Emoji.stories.tsx | 35 +- ts/components/emoji/EmojiButton.stories.tsx | 9 +- ts/components/emoji/EmojiPicker.stories.tsx | 152 +- ...llScreenChoosingDeviceNameStep.stories.tsx | 12 +- .../InstallScreenErrorStep.stories.tsx | 48 +- .../InstallScreenLinkInProgress.stories.tsx | 13 +- ...tallScreenQrCodeNotScannedStep.stories.tsx | 49 +- .../stickers/StickerButton.stories.tsx | 79 +- .../stickers/StickerManager.stories.tsx | 29 +- .../stickers/StickerPackInstallButton.tsx | 3 +- .../stickers/StickerPicker.stories.tsx | 33 +- .../stickers/StickerPreviewModal.stories.tsx | 33 +- ts/util/lint/exceptions.json | 1515 +++- ts/util/lint/linter.ts | 2 + webpack.config.ts | 6 - yarn.lock | 7966 +++++++++-------- 244 files changed, 15341 insertions(+), 10249 deletions(-) delete mode 100644 .storybook/addons.js delete mode 100644 .storybook/config.js create mode 100644 .storybook/main.js create mode 100644 .storybook/preview.tsx diff --git a/.storybook/addons.js b/.storybook/addons.js deleted file mode 100644 index 349f4fe8a..000000000 --- a/.storybook/addons.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2019-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import '@storybook/addon-knobs/register'; -import '@storybook/addon-actions/register'; diff --git a/.storybook/config.js b/.storybook/config.js deleted file mode 100644 index 2230765ff..000000000 --- a/.storybook/config.js +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019-2021 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -import * as React from 'react'; -import { addDecorator, addParameters, configure } from '@storybook/react'; -import { withKnobs, boolean, optionsKnob } from '@storybook/addon-knobs'; -import classnames from 'classnames'; -import * as styles from './styles.scss'; -import messages from '../_locales/en/messages.json'; -import { I18n } from '../sticker-creator/util/i18n'; -import { ThemeType } from '../ts/types/Util'; -import { ClassyProvider } from '../ts/components/PopperRootContext'; -import { StorybookThemeContext } from './StorybookThemeContext'; - -const optionsConfig = { - display: 'inline-radio', -}; - -const persistKnob = id => knob => { - const value = knob(localStorage.getItem(id)); - localStorage.setItem(id, value); - return value; -}; - -const makeThemeKnob = pane => - persistKnob(`${pane}-pane-theme`)(localValue => - optionsKnob( - `${pane} Pane Theme`, - { Light: '', Dark: classnames('dark-theme', styles.darkTheme) }, - localValue || '', - optionsConfig, - `${pane} Pane` - ) - ); - -const parseThemeString = str => (str === '' ? ThemeType.light : ThemeType.dark); - -const makeModeKnob = pane => - persistKnob(`${pane}-pane-mode`)(localValue => - optionsKnob( - `${pane} Pane Mode`, - { Mouse: 'mouse-mode', Keyboard: 'keyboard-mode' }, - localValue || 'mouse-mode', - optionsConfig, - `${pane} Pane` - ) - ); - -addDecorator(withKnobs({ escapeHTML: false })); - -addDecorator((storyFn /* , context */) => { - const contents = storyFn(); - const firstPaneThemeString = makeThemeKnob('First'); - const firstPaneTheme = parseThemeString(firstPaneThemeString); - const firstPaneMode = makeModeKnob('First'); - - const secondPane = persistKnob('second-pane-active')(localValue => - boolean('Second Pane Active', localValue !== 'false', 'Second Pane') - ); - - const secondPaneThemeString = makeThemeKnob('Second'); - const secondPaneTheme = parseThemeString(secondPaneThemeString); - const secondPaneMode = makeModeKnob('Second'); - - // Adding it to the body as well so that we can cover modals and other - // components that are rendered outside of this decorator container - if (firstPaneThemeString === '') { - document.body.classList.remove('dark-theme'); - } else { - document.body.classList.add('dark-theme'); - } - - if (firstPaneMode === 'mouse-mode') { - document.body.classList.remove('keyboard-mode'); - document.body.classList.add('mouse-mode'); - } else { - document.body.classList.remove('mouse-mode'); - document.body.classList.add('keyboard-mode'); - } - - document.body.classList.add('page-is-visible'); - - return ( -
- - -
- {contents} -
-
-
- {secondPane ? ( -
- - {contents} - -
- ) : null} -
- ); -}); - -// Hack to enable hooks in stories: https://github.com/storybookjs/storybook/issues/5721#issuecomment-473869398 -addDecorator(Story => ); - -addDecorator(story => {story()}); - -addParameters({ - axe: { - disabledRules: ['html-has-lang'], - }, -}); - -configure(() => { - // Load main app stories - const tsComponentsContext = require.context( - '../ts/components', - true, - /\.stories.tsx?$/ - ); - tsComponentsContext.keys().forEach(f => tsComponentsContext(f)); - // Load sticker creator stories - const stickerCreatorContext = require.context( - '../sticker-creator', - true, - /\.stories\.tsx?$/ - ); - stickerCreatorContext.keys().forEach(f => stickerCreatorContext(f)); -}, module); diff --git a/.storybook/main.js b/.storybook/main.js new file mode 100644 index 000000000..5d4bfe640 --- /dev/null +++ b/.storybook/main.js @@ -0,0 +1,17 @@ +// Copyright 2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +module.exports = { + stories: [ + '../ts/components/**/*.stories.tsx', + '../sticker-creator/**/*.stories.tsx', + ], + addons: [ + '@storybook/addon-a11y', + '@storybook/addon-actions', + '@storybook/addon-controls', + '@storybook/addon-measure', + '@storybook/addon-toolbars', + '@storybook/addon-viewport', + ], +}; diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx new file mode 100644 index 000000000..a6651621b --- /dev/null +++ b/.storybook/preview.tsx @@ -0,0 +1,87 @@ +// Copyright 2019-2022 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import React from 'react'; +import classnames from 'classnames'; +import { withKnobs, boolean, optionsKnob } from '@storybook/addon-knobs'; + +import * as styles from './styles.scss'; +import messages from '../_locales/en/messages.json'; +import { ClassyProvider } from '../ts/components/PopperRootContext'; +import { I18n } from '../sticker-creator/util/i18n'; +import { StorybookThemeContext } from './StorybookThemeContext'; +import { ThemeType } from '../ts/types/Util'; + +export const globalTypes = { + mode: { + name: 'Mode', + description: 'Application mode', + defaultValue: 'mouse', + toolbar: { + dynamicTitle: true, + icon: 'circlehollow', + items: ['mouse', 'keyboard'], + showName: true, + }, + }, + theme: { + name: 'Theme', + description: 'Global theme for components', + defaultValue: 'light', + toolbar: { + dynamicTitle: true, + icon: 'circlehollow', + items: ['light', 'dark'], + showName: true, + }, + }, +}; + +const withModeAndThemeProvider = (Story, context) => { + const theme = + context.globals.theme === 'light' ? ThemeType.light : ThemeType.dark; + const mode = context.globals.mode; + + // Adding it to the body as well so that we can cover modals and other + // components that are rendered outside of this decorator container + if (theme === 'light') { + document.body.classList.remove('dark-theme'); + } else { + document.body.classList.add('dark-theme'); + } + + if (mode === 'mouse') { + document.body.classList.remove('keyboard-mode'); + document.body.classList.add('mouse-mode'); + } else { + document.body.classList.remove('mouse-mode'); + document.body.classList.add('keyboard-mode'); + } + + document.body.classList.add('page-is-visible'); + + return ( +
+ + + +
+ ); +}; + +const withI18n = (Story, context) => ( + + + +); + +export const decorators = [ + withModeAndThemeProvider, + withI18n, +]; + +export const parameters = { + axe: { + disabledRules: ['html-has-lang'], + }, +}; diff --git a/.storybook/styles.scss b/.storybook/styles.scss index 10eede034..db1f6d12a 100644 --- a/.storybook/styles.scss +++ b/.storybook/styles.scss @@ -4,19 +4,10 @@ @import '../stylesheets/variables'; .container { - display: flex; - flex-direction: row; - align-items: stretch; align-content: stretch; - width: 100vw; + align-items: stretch; height: 100vh; -} - -.panel { - flex: 1; - padding: 16px; - height: 100%; - overflow: auto; + width: 100vw; } .dark-theme { diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index c8c2b58e2..6935444dd 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -1,4 +1,4 @@ -// Copyright 2019-2020 Signal Messenger, LLC +// Copyright 2019-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only const webpack = require('webpack'); @@ -10,11 +10,6 @@ module.exports = ({ config }) => { ); config.module.rules.unshift( - { - test: /\.[jt]sx?$/, - loader: 'babel-loader', - exclude: /node_modules/, - }, { test: /\.scss$/, loaders: [ @@ -25,8 +20,6 @@ module.exports = ({ config }) => { } ); - config.resolve.extensions = ['.tsx', '.ts', '.jsx', '.js']; - config.externals = { net: 'net', }; diff --git a/.yarnclean b/.yarnclean index b1752b166..4593ef707 100644 --- a/.yarnclean +++ b/.yarnclean @@ -5,7 +5,6 @@ tests powered-test # asset directories -docs doc website images diff --git a/package.json b/package.json index 7c87b5e0e..6ca1ac2da 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "dev:typed-scss": "yarn build:typed-scss -w", "dev:storybook": "cross-env SIGNAL_ENV=storybook start-storybook -p 6006 -s ./", "dev:sass": "yarn sass --watch", - "storybook:axe": "build-storybook && axe-storybook", "build": "run-s --print-label generate build:typed-scss build:webpack build:release", "build:acknowledgments": "node scripts/generate-acknowledgments.js", "build:dev": "run-s --print-label generate build:typed-scss build:webpack", @@ -78,7 +77,7 @@ }, "dependencies": { "@popperjs/core": "2.9.2", - "@react-spring/web": "9.4.1", + "@react-spring/web": "9.4.5", "@signalapp/libsignal-client": "0.16.0", "@sindresorhus/is": "0.8.0", "@types/fabric": "4.5.3", @@ -143,19 +142,19 @@ "qrcode-generator": "1.4.4", "quill": "1.3.7", "quill-delta": "4.0.1", - "react": "16.14.0", + "react": "17.0.2", "react-blurhash": "0.1.2", "react-contextmenu": "2.11.0", - "react-dom": "16.14.0", + "react-dom": "17.0.2", "react-dropzone": "10.1.7", - "react-hot-loader": "4.12.11", + "react-hot-loader": "4.13.0", "react-measure": "2.3.0", - "react-popper": "2.2.5", - "react-quill": "2.0.0-beta.2", - "react-redux": "7.1.0", + "react-popper": "2.3.0", + "react-quill": "2.0.0-beta.4", + "react-redux": "7.2.8", "react-router-dom": "5.0.1", - "react-sortable-hoc": "1.9.1", - "react-virtualized": "9.21.0", + "react-sortable-hoc": "2.0.0", + "react-virtualized": "9.22.3", "read-last-lines": "1.8.0", "redux": "4.1.2", "redux-logger": "3.0.6", @@ -179,21 +178,25 @@ }, "devDependencies": { "@babel/core": "7.14.3", - "@babel/plugin-proposal-class-properties": "7.7.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "7.14.5", - "@babel/plugin-proposal-optional-chaining": "7.13.8", - "@babel/plugin-transform-runtime": "7.8.3", - "@babel/plugin-transform-typescript": "7.16.1", - "@babel/preset-react": "7.7.4", - "@babel/preset-typescript": "7.16.0", - "@chanzuckerberg/axe-storybook-testing": "3.0.2", + "@babel/plugin-proposal-class-properties": "7.17.12", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.17.12", + "@babel/plugin-proposal-optional-chaining": "7.17.12", + "@babel/plugin-transform-runtime": "7.18.2", + "@babel/plugin-transform-typescript": "7.18.4", + "@babel/preset-react": "7.17.12", + "@babel/preset-typescript": "7.17.12", "@electron/fuses": "1.5.0", "@mixer/parallel-prettier": "2.0.1", "@signalapp/mock-server": "1.5.1", - "@storybook/addon-actions": "5.1.11", - "@storybook/addon-knobs": "5.1.11", - "@storybook/addons": "5.1.11", - "@storybook/react": "5.1.11", + "@storybook/addon-a11y": "6.5.6", + "@storybook/addon-actions": "6.5.6", + "@storybook/addon-controls": "6.5.6", + "@storybook/addon-knobs": "6.4.0", + "@storybook/addon-measure": "6.5.6", + "@storybook/addon-toolbars": "6.5.6", + "@storybook/addon-viewport": "6.5.6", + "@storybook/addons": "6.5.6", + "@storybook/react": "6.5.6", "@types/backbone": "1.4.5", "@types/better-sqlite3": "7.5.0", "@types/blueimp-load-image": "5.14.1", @@ -229,10 +232,10 @@ "@types/pino": "6.3.6", "@types/pino-multi-stream": "5.1.0", "@types/quill": "1.3.10", - "@types/react": "16.8.6", - "@types/react-dom": "16.8.2", + "@types/react": "17.0.45", + "@types/react-dom": "17.0.17", "@types/react-measure": "2.0.5", - "@types/react-redux": "7.1.2", + "@types/react-redux": "7.1.24", "@types/react-router-dom": "4.3.4", "@types/react-sortable-hoc": "0.6.5", "@types/react-virtualized": "9.18.12", @@ -242,9 +245,6 @@ "@types/sharp": "0.29.4", "@types/sinon": "10.0.2", "@types/split2": "3.2.1", - "@types/storybook__addon-actions": "3.4.3", - "@types/storybook__addon-knobs": "5.0.3", - "@types/storybook__react": "4.0.2", "@types/terser-webpack-plugin": "5.0.3", "@types/underscore": "1.10.3", "@types/uuid": "3.4.4", @@ -301,6 +301,8 @@ }, "resolutions": { "@storybook/react/@storybook/core/node-fetch": "2.6.1", + "@types/react": "17.0.45", + "@types/react-dom": "17.0.17", "dmg-license": "https://registry.yarnpkg.com/nop/-/nop-1.0.0.tgz", "fabric/canvas": "https://registry.yarnpkg.com/nop/-/nop-1.0.0.tgz", "fabric/jsdom": "https://registry.yarnpkg.com/nop/-/nop-1.0.0.tgz", diff --git a/sticker-creator/components/ShareButtons.stories.tsx b/sticker-creator/components/ShareButtons.stories.tsx index 106af82ad..9e90390f0 100644 --- a/sticker-creator/components/ShareButtons.stories.tsx +++ b/sticker-creator/components/ShareButtons.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from '../elements/StoryRow'; import { ShareButtons } from './ShareButtons'; -storiesOf('Sticker Creator/components', module).add('ShareButtons', () => { +export default { + title: 'Sticker Creator/components', +}; + +export const _ShareButtons = (): JSX.Element => { const value = text('value', 'https://signal.org'); return ( @@ -16,4 +19,8 @@ storiesOf('Sticker Creator/components', module).add('ShareButtons', () => { ); -}); +}; + +_ShareButtons.story = { + name: 'ShareButtons', +}; diff --git a/sticker-creator/components/StickerFrame.stories.tsx b/sticker-creator/components/StickerFrame.stories.tsx index 7e766e0bf..18f200627 100644 --- a/sticker-creator/components/StickerFrame.stories.tsx +++ b/sticker-creator/components/StickerFrame.stories.tsx @@ -2,14 +2,17 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { boolean, select, text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; import { StoryRow } from '../elements/StoryRow'; import { StickerFrame } from './StickerFrame'; -storiesOf('Sticker Creator/components', module).add('StickerFrame', () => { +export default { + title: 'Sticker Creator/components', +}; + +export const _StickerFrame = (): JSX.Element => { const image = text('image url', '/fixtures/512x515-thumbs-up-lincoln.webp'); const showGuide = boolean('show guide', true); const mode = select('mode', [null, 'removable', 'pick-emoji', 'add'], null); @@ -34,4 +37,8 @@ storiesOf('Sticker Creator/components', module).add('StickerFrame', () => { /> ); -}); +}; + +_StickerFrame.story = { + name: 'StickerFrame', +}; diff --git a/sticker-creator/components/StickerPackPreview.stories.tsx b/sticker-creator/components/StickerPackPreview.stories.tsx index a50aad36a..89b5354c0 100644 --- a/sticker-creator/components/StickerPackPreview.stories.tsx +++ b/sticker-creator/components/StickerPackPreview.stories.tsx @@ -2,24 +2,28 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from '../elements/StoryRow'; import { StickerPackPreview } from './StickerPackPreview'; -storiesOf('Sticker Creator/components', module).add( - 'StickerPackPreview', - () => { - const image = text('image url', '/fixtures/512x515-thumbs-up-lincoln.webp'); - const title = text('title', 'Sticker pack title'); - const author = text('author', 'Sticker pack author'); - const images = React.useMemo(() => Array(39).fill(image), [image]); +export default { + title: 'Sticker Creator/components', +}; - return ( - - - - ); - } -); +export const _StickerPackPreview = (): JSX.Element => { + const image = text('image url', '/fixtures/512x515-thumbs-up-lincoln.webp'); + const title = text('title', 'Sticker pack title'); + const author = text('author', 'Sticker pack author'); + const images = React.useMemo(() => Array(39).fill(image), [image]); + + return ( + + + + ); +}; + +_StickerPackPreview.story = { + name: 'StickerPackPreview', +}; diff --git a/sticker-creator/components/Toaster.stories.tsx b/sticker-creator/components/Toaster.stories.tsx index aaa48c42f..047cb36e0 100644 --- a/sticker-creator/components/Toaster.stories.tsx +++ b/sticker-creator/components/Toaster.stories.tsx @@ -3,13 +3,16 @@ import * as React from 'react'; import { debounce, dropRight } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { text as textKnob } from '@storybook/addon-knobs'; import { StoryRow } from '../elements/StoryRow'; import { Toaster } from './Toaster'; -storiesOf('Sticker Creator/components', module).add('Toaster', () => { +export default { + title: 'Sticker Creator/components', +}; + +export const _Toaster = (): JSX.Element => { const inputText = textKnob('Slices', ['error 1', 'error 2'].join('|')); const initialState = React.useMemo(() => inputText.split('|'), [inputText]); const [state, setState] = React.useState(initialState); @@ -33,4 +36,4 @@ storiesOf('Sticker Creator/components', module).add('Toaster', () => { /> ); -}); +}; diff --git a/sticker-creator/elements/Button.stories.tsx b/sticker-creator/elements/Button.stories.tsx index d6b3d1198..57948efa5 100644 --- a/sticker-creator/elements/Button.stories.tsx +++ b/sticker-creator/elements/Button.stories.tsx @@ -2,14 +2,17 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { Button } from './Button'; -storiesOf('Sticker Creator/elements', module).add('Button', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _Button = (): JSX.Element => { const onClick = action('onClick'); const child = text('text', 'foo bar'); @@ -55,4 +58,4 @@ storiesOf('Sticker Creator/elements', module).add('Button', () => { ); -}); +}; diff --git a/sticker-creator/elements/ConfirmDialog.stories.tsx b/sticker-creator/elements/ConfirmDialog.stories.tsx index 3d270176a..a58e44b62 100644 --- a/sticker-creator/elements/ConfirmDialog.stories.tsx +++ b/sticker-creator/elements/ConfirmDialog.stories.tsx @@ -2,14 +2,17 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; import { StoryRow } from './StoryRow'; import { ConfirmDialog } from './ConfirmDialog'; -storiesOf('Sticker Creator/elements', module).add('ConfirmDialog', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _ConfirmDialog = (): JSX.Element => { const title = text('title', 'Foo bar banana baz?'); const child = text( 'text', @@ -29,4 +32,8 @@ storiesOf('Sticker Creator/elements', module).add('ConfirmDialog', () => { ); -}); +}; + +_ConfirmDialog.story = { + name: 'ConfirmDialog', +}; diff --git a/sticker-creator/elements/CopyText.stories.tsx b/sticker-creator/elements/CopyText.stories.tsx index 3c649af5b..76d274d7d 100644 --- a/sticker-creator/elements/CopyText.stories.tsx +++ b/sticker-creator/elements/CopyText.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { CopyText } from './CopyText'; -storiesOf('Sticker Creator/elements', module).add('CopyText', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _CopyText = (): JSX.Element => { const label = text('label', 'foo bar'); const value = text('value', 'foo bar'); @@ -17,4 +20,8 @@ storiesOf('Sticker Creator/elements', module).add('CopyText', () => { ); -}); +}; + +_CopyText.story = { + name: 'CopyText', +}; diff --git a/sticker-creator/elements/DropZone.stories.tsx b/sticker-creator/elements/DropZone.stories.tsx index 3d53b91d8..bfb3fb175 100644 --- a/sticker-creator/elements/DropZone.stories.tsx +++ b/sticker-creator/elements/DropZone.stories.tsx @@ -2,11 +2,18 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { DropZone } from './DropZone'; -storiesOf('Sticker Creator/elements', module).add('DropZone', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _DropZone = (): JSX.Element => { return ; -}); +}; + +_DropZone.story = { + name: 'DropZone', +}; diff --git a/sticker-creator/elements/LabeledCheckbox.stories.tsx b/sticker-creator/elements/LabeledCheckbox.stories.tsx index 9b59e1f79..ca89ea77c 100644 --- a/sticker-creator/elements/LabeledCheckbox.stories.tsx +++ b/sticker-creator/elements/LabeledCheckbox.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { LabeledCheckbox } from './LabeledCheckbox'; -storiesOf('Sticker Creator/elements', module).add('Labeled Checkbox', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _LabeledCheckbox = (): JSX.Element => { const child = text('label', 'foo bar'); const [checked, setChecked] = React.useState(false); @@ -19,4 +22,4 @@ storiesOf('Sticker Creator/elements', module).add('Labeled Checkbox', () => { ); -}); +}; diff --git a/sticker-creator/elements/LabeledInput.stories.tsx b/sticker-creator/elements/LabeledInput.stories.tsx index 7ca4d287e..060f40bd8 100644 --- a/sticker-creator/elements/LabeledInput.stories.tsx +++ b/sticker-creator/elements/LabeledInput.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { LabeledInput } from './LabeledInput'; -storiesOf('Sticker Creator/elements', module).add('LabeledInput', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _LabeledInput = (): JSX.Element => { const child = text('label', 'foo bar'); const placeholder = text('placeholder', 'foo bar'); const [value, setValue] = React.useState(''); @@ -20,4 +23,8 @@ storiesOf('Sticker Creator/elements', module).add('LabeledInput', () => { ); -}); +}; + +_LabeledInput.story = { + name: 'LabeledInput', +}; diff --git a/sticker-creator/elements/MessageBubble.stories.tsx b/sticker-creator/elements/MessageBubble.stories.tsx index a52a299aa..79ca45867 100644 --- a/sticker-creator/elements/MessageBubble.stories.tsx +++ b/sticker-creator/elements/MessageBubble.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { number, text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { MessageBubble } from './MessageBubble'; -storiesOf('Sticker Creator/elements', module).add('MessageBubble', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _MessageBubble = (): JSX.Element => { const child = text('text', 'Foo bar banana baz'); const minutesAgo = number('minutesAgo', 3); @@ -17,4 +20,8 @@ storiesOf('Sticker Creator/elements', module).add('MessageBubble', () => { {child} ); -}); +}; + +_MessageBubble.story = { + name: 'MessageBubble', +}; diff --git a/sticker-creator/elements/MessageSticker.stories.tsx b/sticker-creator/elements/MessageSticker.stories.tsx index 0e7288e51..e31a8eca3 100644 --- a/sticker-creator/elements/MessageSticker.stories.tsx +++ b/sticker-creator/elements/MessageSticker.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { number, text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { MessageSticker } from './MessageSticker'; -storiesOf('Sticker Creator/elements', module).add('MessageSticker', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _MessageSticker = (): JSX.Element => { const image = text('image url', '/fixtures/512x515-thumbs-up-lincoln.webp'); const minutesAgo = number('minutesAgo', 3); @@ -17,4 +20,8 @@ storiesOf('Sticker Creator/elements', module).add('MessageSticker', () => { ); -}); +}; + +_MessageSticker.story = { + name: 'MessageSticker', +}; diff --git a/sticker-creator/elements/PageHeader.stories.tsx b/sticker-creator/elements/PageHeader.stories.tsx index b702f86d9..018b0185f 100644 --- a/sticker-creator/elements/PageHeader.stories.tsx +++ b/sticker-creator/elements/PageHeader.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { PageHeader } from './PageHeader'; -storiesOf('Sticker Creator/elements', module).add('PageHeader', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _PageHeader = (): JSX.Element => { const child = text('text', 'foo bar'); return ( @@ -16,4 +19,8 @@ storiesOf('Sticker Creator/elements', module).add('PageHeader', () => { {child} ); -}); +}; + +_PageHeader.story = { + name: 'PageHeader', +}; diff --git a/sticker-creator/elements/ProgressBar.stories.tsx b/sticker-creator/elements/ProgressBar.stories.tsx index 7eb8dded3..91cac357a 100644 --- a/sticker-creator/elements/ProgressBar.stories.tsx +++ b/sticker-creator/elements/ProgressBar.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { number } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { ProgressBar } from './ProgressBar'; -storiesOf('Sticker Creator/elements', module).add('ProgressBar', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _ProgressBar = (): JSX.Element => { const count = number('count', 5); const total = number('total', 10); @@ -17,4 +20,8 @@ storiesOf('Sticker Creator/elements', module).add('ProgressBar', () => { ); -}); +}; + +_ProgressBar.story = { + name: 'ProgressBar', +}; diff --git a/sticker-creator/elements/StickerPreview.stories.tsx b/sticker-creator/elements/StickerPreview.stories.tsx index 9cf6ab35c..6cee1c449 100644 --- a/sticker-creator/elements/StickerPreview.stories.tsx +++ b/sticker-creator/elements/StickerPreview.stories.tsx @@ -2,13 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { StickerPreview } from './StickerPreview'; -storiesOf('Sticker Creator/elements', module).add('StickerPreview', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _StickerPreview = (): JSX.Element => { const image = text('image url', '/fixtures/512x515-thumbs-up-lincoln.webp'); return ( @@ -16,4 +19,8 @@ storiesOf('Sticker Creator/elements', module).add('StickerPreview', () => { ); -}); +}; + +_StickerPreview.story = { + name: 'StickerPreview', +}; diff --git a/sticker-creator/elements/Toast.stories.tsx b/sticker-creator/elements/Toast.stories.tsx index 96d393735..4b80528e4 100644 --- a/sticker-creator/elements/Toast.stories.tsx +++ b/sticker-creator/elements/Toast.stories.tsx @@ -2,14 +2,17 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; import { StoryRow } from './StoryRow'; import { Toast } from './Toast'; -storiesOf('Sticker Creator/elements', module).add('Toast', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const _Toast = (): JSX.Element => { const child = text('text', 'foo bar'); return ( @@ -17,4 +20,4 @@ storiesOf('Sticker Creator/elements', module).add('Toast', () => { {child} ); -}); +}; diff --git a/sticker-creator/elements/Typography.stories.tsx b/sticker-creator/elements/Typography.stories.tsx index 9aaa3e7e7..6c30cbe7b 100644 --- a/sticker-creator/elements/Typography.stories.tsx +++ b/sticker-creator/elements/Typography.stories.tsx @@ -4,13 +4,16 @@ /* eslint-disable no-script-url, jsx-a11y/anchor-is-valid */ import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { StoryRow } from './StoryRow'; import { H1, H2, Text } from './Typography'; -storiesOf('Sticker Creator/elements', module).add('Typography', () => { +export default { + title: 'Sticker Creator/elements', +}; + +export const Typography = (): JSX.Element => { const child = text('text', 'foo bar'); return ( @@ -36,4 +39,4 @@ storiesOf('Sticker Creator/elements', module).add('Typography', () => { ); -}); +}; diff --git a/ts/components/AddGroupMemberErrorDialog.stories.tsx b/ts/components/AddGroupMemberErrorDialog.stories.tsx index 423185eeb..0265ef13d 100644 --- a/ts/components/AddGroupMemberErrorDialog.stories.tsx +++ b/ts/components/AddGroupMemberErrorDialog.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; @@ -15,25 +14,35 @@ import { const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/AddGroupMemberErrorDialog', module); +export default { + title: 'Components/AddGroupMemberErrorDialog', +}; const defaultProps = { i18n, onClose: action('onClose'), }; -story.add('Maximum group size', () => ( +export const _MaximumGroupSize = (): JSX.Element => ( -)); +); -story.add('Maximum recommended group size', () => ( +_MaximumGroupSize.story = { + name: 'Maximum group size', +}; + +export const MaximumRecommendedGroupSize = (): JSX.Element => ( -)); +); + +MaximumRecommendedGroupSize.story = { + name: 'Maximum recommended group size', +}; diff --git a/ts/components/Alert.stories.tsx b/ts/components/Alert.stories.tsx index 2ff277c7f..77bfa8645 100644 --- a/ts/components/Alert.stories.tsx +++ b/ts/components/Alert.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; @@ -12,7 +11,9 @@ import { Alert } from './Alert'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/Alert', module); +export default { + title: 'Components/Alert', +}; const defaultProps = { i18n, @@ -22,15 +23,19 @@ const defaultProps = { const LOREM_IPSUM = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.'; -story.add('Title and body are strings', () => ( +export const TitleAndBodyAreStrings = (): JSX.Element => ( -)); +); -story.add('Body is a ReactNode', () => ( +TitleAndBodyAreStrings.story = { + name: 'Title and body are strings', +}; + +export const BodyIsAReactNode = (): JSX.Element => ( ( } /> -)); +); -story.add('Long body (without title)', () => ( +BodyIsAReactNode.story = { + name: 'Body is a ReactNode', +}; + +export const LongBodyWithoutTitle = (): JSX.Element => ( ( } /> -)); +); -story.add('Long body (with title)', () => ( +LongBodyWithoutTitle.story = { + name: 'Long body (without title)', +}; + +export const LongBodyWithTitle = (): JSX.Element => ( ( } /> -)); +); + +LongBodyWithTitle.story = { + name: 'Long body (with title)', +}; diff --git a/ts/components/AnimatedEmojiGalore.stories.tsx b/ts/components/AnimatedEmojiGalore.stories.tsx index e9c2f4145..67704ade9 100644 --- a/ts/components/AnimatedEmojiGalore.stories.tsx +++ b/ts/components/AnimatedEmojiGalore.stories.tsx @@ -2,13 +2,14 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import type { PropsType } from './AnimatedEmojiGalore'; import { AnimatedEmojiGalore } from './AnimatedEmojiGalore'; -const story = storiesOf('Components/AnimatedEmojiGalore', module); +export default { + title: 'Components/AnimatedEmojiGalore', +}; function getDefaultProps(): PropsType { return { @@ -17,4 +18,6 @@ function getDefaultProps(): PropsType { }; } -story.add('Hearts', () => ); +export const Hearts = (): JSX.Element => ( + +); diff --git a/ts/components/Avatar.stories.tsx b/ts/components/Avatar.stories.tsx index f3dad62ff..22edde775 100644 --- a/ts/components/Avatar.stories.tsx +++ b/ts/components/Avatar.stories.tsx @@ -1,27 +1,23 @@ // Copyright 2020-2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import type { Meta, Story } from '@storybook/react'; import * as React from 'react'; import { isBoolean } from 'lodash'; -import { storiesOf } from '@storybook/react'; -import { boolean, select, text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; import type { Props } from './Avatar'; -import { Avatar, AvatarBlur, AvatarStoryRing } from './Avatar'; +import { Avatar, AvatarBlur, AvatarSize, AvatarStoryRing } from './Avatar'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; import type { AvatarColorType } from '../types/Colors'; import { AvatarColors } from '../types/Colors'; -import { StorybookThemeContext } from '../../.storybook/StorybookThemeContext'; import { getFakeBadge } from '../test-both/helpers/getFakeBadge'; import { ThemeType } from '../types/Util'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/Avatar', module); - const colorMap: Record = AvatarColors.reduce( (m, color) => ({ ...m, @@ -35,224 +31,240 @@ const conversationTypeMap: Record = { group: 'group', }; +export default { + title: 'Components/Avatar', + component: Avatar, + argTypes: { + badge: { + control: false, + }, + blur: { + control: { type: 'radio' }, + defaultValue: AvatarBlur.NoBlur, + options: { + NoBlur: AvatarBlur.NoBlur, + BlurPicture: AvatarBlur.BlurPicture, + BlurPictureWithClickToView: AvatarBlur.BlurPictureWithClickToView, + }, + }, + color: { + defaultValue: AvatarColors[0], + options: colorMap, + }, + conversationType: { + control: { type: 'radio' }, + options: conversationTypeMap, + }, + size: { + control: false, + }, + storyRing: { + control: { type: 'radio' }, + options: [undefined, ...Object.values(AvatarStoryRing)], + }, + theme: { + control: { type: 'radio' }, + defaultValue: ThemeType.light, + options: ThemeType, + }, + }, +} as Meta; + const createProps = (overrideProps: Partial = {}): Props => ({ acceptedMessageRequest: isBoolean(overrideProps.acceptedMessageRequest) ? overrideProps.acceptedMessageRequest : true, - avatarPath: text('avatarPath', overrideProps.avatarPath || ''), + avatarPath: overrideProps.avatarPath || '', badge: overrideProps.badge, - blur: overrideProps.blur, - color: select('color', colorMap, overrideProps.color || AvatarColors[0]), - conversationType: select( - 'conversationType', - conversationTypeMap, - overrideProps.conversationType || 'direct' - ), + blur: overrideProps.blur || AvatarBlur.NoBlur, + color: overrideProps.color || AvatarColors[0], + conversationType: overrideProps.conversationType || 'direct', i18n, isMe: false, - loading: boolean('loading', overrideProps.loading || false), - name: text('name', overrideProps.name || ''), - noteToSelf: boolean('noteToSelf', overrideProps.noteToSelf || false), + loading: Boolean(overrideProps.loading), + name: overrideProps.name || '', + noteToSelf: Boolean(overrideProps.noteToSelf), onClick: action('onClick'), onClickBadge: action('onClickBadge'), - phoneNumber: text('phoneNumber', overrideProps.phoneNumber || ''), - searchResult: boolean( - 'searchResult', - typeof overrideProps.searchResult === 'boolean' - ? overrideProps.searchResult - : false - ), + phoneNumber: overrideProps.phoneNumber || '', + searchResult: Boolean(overrideProps.searchResult), sharedGroupNames: [], size: 80, title: overrideProps.title || '', theme: overrideProps.theme || ThemeType.light, }); -const sizes: Array = [112, 96, 80, 52, 32, 28]; +const sizes = Object.values(AvatarSize).filter( + x => typeof x === 'number' +) as Array; -story.add('Avatar', () => { - const props = createProps({ - avatarPath: '/fixtures/giphy-GVNvOUpeYmI7e.gif', - }); +const Template: Story = args => ( + <> + {sizes.map(size => ( + + ))} + +); - return sizes.map(size => ); +const TemplateSingle: Story = args => ( + +); + +export const Default = Template.bind({}); +Default.args = createProps({ + avatarPath: '/fixtures/giphy-GVNvOUpeYmI7e.gif', +}); +Default.story = { + name: 'Avatar', +}; + +export const WithBadge = Template.bind({}); +WithBadge.args = createProps({ + avatarPath: '/fixtures/kitten-3-64-64.jpg', + badge: getFakeBadge(), +}); +WithBadge.story = { + name: 'With badge', +}; + +export const WideImage = Template.bind({}); +WideImage.args = createProps({ + avatarPath: '/fixtures/wide.jpg', +}); +WideImage.story = { + name: 'Wide image', +}; + +export const OneWordName = Template.bind({}); +OneWordName.args = createProps({ + title: 'John', +}); +OneWordName.story = { + name: 'One-word Name', +}; + +export const TwoWordName = Template.bind({}); +TwoWordName.args = createProps({ + title: 'John Smith', +}); +TwoWordName.story = { + name: 'Two-word Name', +}; + +export const WideInitials = Template.bind({}); +WideInitials.args = createProps({ + title: 'Walter White', +}); +WideInitials.story = { + name: 'Wide initials', +}; + +export const ThreeWordName = Template.bind({}); +ThreeWordName.args = createProps({ + title: 'Walter H. White', +}); +ThreeWordName.story = { + name: 'Three-word name', +}; + +export const NoteToSelf = Template.bind({}); +NoteToSelf.args = createProps({ + noteToSelf: true, +}); +NoteToSelf.story = { + name: 'Note to Self', +}; + +export const ContactIcon = Template.bind({}); +ContactIcon.args = createProps(); + +export const GroupIcon = Template.bind({}); +GroupIcon.args = createProps({ + conversationType: 'group', }); -story.add('With badge', () => { - const Wrapper = () => { - const theme = React.useContext(StorybookThemeContext); - const props = createProps({ - avatarPath: '/fixtures/kitten-3-64-64.jpg', - badge: getFakeBadge(), - theme, - }); - - return ( - <> - {sizes.map(size => ( - - ))} - - ); - }; - - return ; +export const SearchIcon = Template.bind({}); +SearchIcon.args = createProps({ + searchResult: true, }); -story.add('Wide image', () => { - const props = createProps({ - avatarPath: '/fixtures/wide.jpg', - }); - - return sizes.map(size => ); -}); - -story.add('One-word Name', () => { - const props = createProps({ - title: 'John', - }); - - return sizes.map(size => ); -}); - -story.add('Two-word Name', () => { - const props = createProps({ - title: 'John Smith', - }); - - return sizes.map(size => ); -}); - -story.add('Wide initials', () => { - const props = createProps({ - title: 'Walter White', - }); - - return sizes.map(size => ); -}); - -story.add('Three-word name', () => { - const props = createProps({ - title: 'Walter H. White', - }); - - return sizes.map(size => ); -}); - -story.add('Note to Self', () => { - const props = createProps({ - noteToSelf: true, - }); - - return sizes.map(size => ); -}); - -story.add('Contact Icon', () => { +export const Colors = (): JSX.Element => { const props = createProps(); - return sizes.map(size => ); + return ( + <> + {AvatarColors.map(color => ( + + ))} + + ); +}; + +export const BrokenColor = Template.bind({}); +BrokenColor.args = createProps({ + color: 'nope' as AvatarColorType, }); -story.add('Group Icon', () => { - const props = createProps({ - conversationType: 'group', - }); - - return sizes.map(size => ); +export const BrokenAvatar = Template.bind({}); +BrokenAvatar.args = createProps({ + avatarPath: 'badimage.png', }); -story.add('Search Icon', () => { - const props = createProps({ - searchResult: true, - }); +export const BrokenAvatarForGroup = Template.bind({}); +BrokenAvatarForGroup.args = createProps({ + avatarPath: 'badimage.png', + conversationType: 'group', +}); +BrokenAvatarForGroup.story = { + name: 'Broken Avatar for Group', +}; - return sizes.map(size => ); +export const Loading = Template.bind({}); +Loading.args = createProps({ + loading: true, }); -story.add('Colors', () => { - const props = createProps(); - - return AvatarColors.map(color => ( - - )); +export const BlurredBasedOnProps = TemplateSingle.bind({}); +BlurredBasedOnProps.args = createProps({ + acceptedMessageRequest: false, + avatarPath: '/fixtures/kitten-3-64-64.jpg', }); +BlurredBasedOnProps.story = { + name: 'Blurred based on props', +}; -story.add('Broken Color', () => { - const props = createProps({ - color: 'nope' as AvatarColorType, - }); - - return sizes.map(size => ); +export const ForceBlurred = TemplateSingle.bind({}); +ForceBlurred.args = createProps({ + avatarPath: '/fixtures/kitten-3-64-64.jpg', + blur: AvatarBlur.BlurPicture, }); +ForceBlurred.story = { + name: 'Force-blurred', +}; -story.add('Broken Avatar', () => { - const props = createProps({ - avatarPath: 'badimage.png', - }); - - return sizes.map(size => ); +export const BlurredWithClickToView = TemplateSingle.bind({}); +BlurredWithClickToView.args = createProps({ + avatarPath: '/fixtures/kitten-3-64-64.jpg', + blur: AvatarBlur.BlurPictureWithClickToView, }); +BlurredWithClickToView.story = { + name: 'Blurred with "click to view"', +}; -story.add('Broken Avatar for Group', () => { - const props = createProps({ - avatarPath: 'badimage.png', - conversationType: 'group', - }); - - return sizes.map(size => ); +export const StoryUnread = TemplateSingle.bind({}); +StoryUnread.args = createProps({ + avatarPath: '/fixtures/kitten-3-64-64.jpg', + storyRing: AvatarStoryRing.Unread, }); +StoryUnread.story = { + name: 'Story: unread', +}; -story.add('Loading', () => { - const props = createProps({ - loading: true, - }); - - return sizes.map(size => ); +export const StoryRead = TemplateSingle.bind({}); +StoryRead.args = createProps({ + avatarPath: '/fixtures/kitten-3-64-64.jpg', + storyRing: AvatarStoryRing.Read, }); - -story.add('Blurred based on props', () => { - const props = createProps({ - acceptedMessageRequest: false, - avatarPath: '/fixtures/kitten-3-64-64.jpg', - }); - - return sizes.map(size => ); -}); - -story.add('Force-blurred', () => { - const props = createProps({ - avatarPath: '/fixtures/kitten-3-64-64.jpg', - blur: AvatarBlur.BlurPicture, - }); - - return sizes.map(size => ); -}); - -story.add('Blurred with "click to view"', () => { - const props = createProps({ - avatarPath: '/fixtures/kitten-3-64-64.jpg', - blur: AvatarBlur.BlurPictureWithClickToView, - }); - - return ; -}); - -story.add('Story: unread', () => ( - -)); - -story.add('Story: read', () => ( - -)); +StoryRead.story = { + name: 'Story: read', +}; diff --git a/ts/components/AvatarColorPicker.stories.tsx b/ts/components/AvatarColorPicker.stories.tsx index a1a2e90cf..94d23f993 100644 --- a/ts/components/AvatarColorPicker.stories.tsx +++ b/ts/components/AvatarColorPicker.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -20,14 +19,18 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ selectedColor: overrideProps.selectedColor, }); -const story = storiesOf('Components/AvatarColorPicker', module); +export default { + title: 'Components/AvatarColorPicker', +}; -story.add('Default', () => ); +export const Default = (): JSX.Element => ( + +); -story.add('Selected', () => ( +export const Selected = (): JSX.Element => ( -)); +); diff --git a/ts/components/AvatarEditor.stories.tsx b/ts/components/AvatarEditor.stories.tsx index d4c08d553..3cf28f0c4 100644 --- a/ts/components/AvatarEditor.stories.tsx +++ b/ts/components/AvatarEditor.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -79,21 +78,32 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ ], }); -const story = storiesOf('Components/AvatarEditor', module); +export default { + title: 'Components/AvatarEditor', +}; -story.add('No Avatar (group)', () => ( +export const NoAvatarGroup = (): JSX.Element => ( -)); -story.add('No Avatar (me)', () => ( - -)); +); -story.add('Has Avatar', () => ( +NoAvatarGroup.story = { + name: 'No Avatar (group)', +}; + +export const NoAvatarMe = (): JSX.Element => ( + +); + +NoAvatarMe.story = { + name: 'No Avatar (me)', +}; + +export const HasAvatar = (): JSX.Element => ( -)); +); diff --git a/ts/components/AvatarIconEditor.stories.tsx b/ts/components/AvatarIconEditor.stories.tsx index fe7db7cef..e8ba8bd72 100644 --- a/ts/components/AvatarIconEditor.stories.tsx +++ b/ts/components/AvatarIconEditor.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -22,9 +21,11 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onClose: action('onClose'), }); -const story = storiesOf('Components/AvatarIconEditor', module); +export default { + title: 'Components/AvatarIconEditor', +}; -story.add('Personal Icon', () => ( +export const PersonalIcon = (): JSX.Element => ( ( }), })} /> -)); +); -story.add('Group Icon', () => ( +export const GroupIcon = (): JSX.Element => ( ( }), })} /> -)); +); diff --git a/ts/components/AvatarLightbox.stories.tsx b/ts/components/AvatarLightbox.stories.tsx index 29eaddba8..5e7419312 100644 --- a/ts/components/AvatarLightbox.stories.tsx +++ b/ts/components/AvatarLightbox.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { select } from '@storybook/addon-knobs'; @@ -29,17 +28,19 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onClose: action('onClose'), }); -const story = storiesOf('Components/AvatarLightbox', module); +export default { + title: 'Components/AvatarLightbox', +}; -story.add('Group', () => ( +export const Group = (): JSX.Element => ( -)); +); -story.add('Person', () => { +export const Person = (): JSX.Element => { const conversation = getDefaultConversation(); return ( { })} /> ); -}); +}; -story.add('Photo', () => ( +export const Photo = (): JSX.Element => ( -)); +); diff --git a/ts/components/AvatarModalButtons.stories.tsx b/ts/components/AvatarModalButtons.stories.tsx index aa709c2ef..814703954 100644 --- a/ts/components/AvatarModalButtons.stories.tsx +++ b/ts/components/AvatarModalButtons.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import enMessages from '../../_locales/en/messages.json'; @@ -20,14 +19,26 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onSave: action('onSave'), }); -const story = storiesOf('Components/AvatarModalButtons', module); +export default { + title: 'Components/AvatarModalButtons', +}; -story.add('Has changes', () => ( +export const HasChanges = (): JSX.Element => ( -)); +); -story.add('No changes', () => ); +HasChanges.story = { + name: 'Has changes', +}; + +export const NoChanges = (): JSX.Element => ( + +); + +NoChanges.story = { + name: 'No changes', +}; diff --git a/ts/components/AvatarPopup.stories.tsx b/ts/components/AvatarPopup.stories.tsx index 63f61ab67..8fb52ca7a 100644 --- a/ts/components/AvatarPopup.stories.tsx +++ b/ts/components/AvatarPopup.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { boolean, select, text } from '@storybook/addon-knobs'; @@ -59,52 +58,58 @@ const useProps = (overrideProps: Partial = {}): Props => ({ title: text('title', overrideProps.title || ''), }); -const stories = storiesOf('Components/Avatar Popup', module); +export default { + title: 'Components/Avatar Popup', +}; -stories.add('Avatar Only', () => { +export const AvatarOnly = (): JSX.Element => { const props = useProps(); return ; -}); +}; -stories.add('Has badge', () => { +export const HasBadge = (): JSX.Element => { const props = useProps({ badge: getFakeBadge(), title: 'Janet Yellen', }); return ; -}); +}; -stories.add('Title', () => { +HasBadge.story = { + name: 'Has badge', +}; + +export const Title = (): JSX.Element => { const props = useProps({ title: 'My Great Title', }); return ; -}); +}; -stories.add('Profile Name', () => { +export const ProfileName = (): JSX.Element => { const props = useProps({ profileName: 'Sam Neill', }); return ; -}); +}; -stories.add('Phone Number', () => { +export const PhoneNumber = (): JSX.Element => { const props = useProps({ profileName: 'Sam Neill', phoneNumber: '(555) 867-5309', }); return ; -}); +}; -stories.add('Update Available', () => { +export const UpdateAvailable = (): JSX.Element => { const props = useProps({ hasPendingUpdate: true, }); return ; -}); +}; diff --git a/ts/components/AvatarPreview.stories.tsx b/ts/components/AvatarPreview.stories.tsx index 3d11e7670..7633d1f6f 100644 --- a/ts/components/AvatarPreview.stories.tsx +++ b/ts/components/AvatarPreview.stories.tsx @@ -5,7 +5,6 @@ import React from 'react'; import { chunk } from 'lodash'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import type { PropsType } from './AvatarPreview'; import { AvatarPreview } from './AvatarPreview'; @@ -36,27 +35,37 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ style: overrideProps.style, }); -const story = storiesOf('Components/AvatarPreview', module); +export default { + title: 'Components/AvatarPreview', +}; -story.add('No state (personal)', () => ( +export const NoStatePersonal = (): JSX.Element => ( -)); +); -story.add('No state (group)', () => ( +NoStatePersonal.story = { + name: 'No state (personal)', +}; + +export const NoStateGroup = (): JSX.Element => ( -)); +); -story.add('No state (group) + upload me', () => ( +NoStateGroup.story = { + name: 'No state (group)', +}; + +export const NoStateGroupUploadMe = (): JSX.Element => ( ( isGroup: true, })} /> -)); +); -story.add('value', () => ( +NoStateGroupUploadMe.story = { + name: 'No state (group) + upload me', +}; + +export const Value = (): JSX.Element => ( -)); +); -story.add('path', () => ( +Value.story = { + name: 'value', +}; + +export const Path = (): JSX.Element => ( -)); +); -story.add('value & path', () => ( +Path.story = { + name: 'path', +}; + +export const ValuePath = (): JSX.Element => ( -)); +); -story.add('style', () => ( +ValuePath.story = { + name: 'value & path', +}; + +export const Style = (): JSX.Element => ( -)); +); + +Style.story = { + name: 'style', +}; diff --git a/ts/components/AvatarTextEditor.stories.tsx b/ts/components/AvatarTextEditor.stories.tsx index 2c2e0874d..3fc93f159 100644 --- a/ts/components/AvatarTextEditor.stories.tsx +++ b/ts/components/AvatarTextEditor.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -21,11 +20,13 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onDone: action('onDone'), }); -const story = storiesOf('Components/AvatarTextEditor', module); +export default { + title: 'Components/AvatarTextEditor', +}; -story.add('Empty', () => ); +export const Empty = (): JSX.Element => ; -story.add('with Data', () => ( +export const WithData = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('with wide characters', () => ( +WithData.story = { + name: 'with Data', +}; + +export const WithWideCharacters = (): JSX.Element => ( ( }, })} /> -)); +); + +WithWideCharacters.story = { + name: 'with wide characters', +}; diff --git a/ts/components/AvatarUploadButton.stories.tsx b/ts/components/AvatarUploadButton.stories.tsx index 96bfc0216..3251b20a0 100644 --- a/ts/components/AvatarUploadButton.stories.tsx +++ b/ts/components/AvatarUploadButton.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -19,6 +18,10 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onChange: action('onChange'), }); -const story = storiesOf('Components/AvatarUploadButton', module); +export default { + title: 'Components/AvatarUploadButton', +}; -story.add('Default', () => ); +export const Default = (): JSX.Element => ( + +); diff --git a/ts/components/BadgeDescription.stories.tsx b/ts/components/BadgeDescription.stories.tsx index 950fa331e..040b3c7f0 100644 --- a/ts/components/BadgeDescription.stories.tsx +++ b/ts/components/BadgeDescription.stories.tsx @@ -2,23 +2,32 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { BadgeDescription } from './BadgeDescription'; -const story = storiesOf('Components/BadgeDescription', module); +export default { + title: 'Components/BadgeDescription', +}; -story.add('Normal name', () => ( +export const NormalName = (): JSX.Element => ( -)); +); -story.add('Name with RTL overrides', () => ( +NormalName.story = { + name: 'Normal name', +}; + +export const NameWithRtlOverrides = (): JSX.Element => ( -)); +); + +NameWithRtlOverrides.story = { + name: 'Name with RTL overrides', +}; diff --git a/ts/components/BadgeDialog.stories.tsx b/ts/components/BadgeDialog.stories.tsx index 3a6abf5cc..3a155456b 100644 --- a/ts/components/BadgeDialog.stories.tsx +++ b/ts/components/BadgeDialog.stories.tsx @@ -3,7 +3,6 @@ import type { ComponentProps } from 'react'; import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; @@ -15,7 +14,9 @@ import { BadgeDialog } from './BadgeDialog'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/BadgeDialog', module); +export default { + title: 'Components/BadgeDialog', +}; const defaultProps: ComponentProps = { areWeASubscriber: false, @@ -26,15 +27,23 @@ const defaultProps: ComponentProps = { title: 'Alice Levine', }; -story.add('No badges (closed immediately)', () => ( +export const NoBadgesClosedImmediately = (): JSX.Element => ( -)); +); -story.add('One badge', () => ( +NoBadgesClosedImmediately.story = { + name: 'No badges (closed immediately)', +}; + +export const OneBadge = (): JSX.Element => ( -)); +); -story.add('Badge with no image (should be impossible)', () => ( +OneBadge.story = { + name: 'One badge', +}; + +export const BadgeWithNoImageShouldBeImpossible = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Badge with pending image', () => ( +BadgeWithNoImageShouldBeImpossible.story = { + name: 'Badge with no image (should be impossible)', +}; + +export const BadgeWithPendingImage = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Badge with only one, low-detail image', () => ( +BadgeWithPendingImage.story = { + name: 'Badge with pending image', +}; + +export const BadgeWithOnlyOneLowDetailImage = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Five badges', () => ( +BadgeWithOnlyOneLowDetailImage.story = { + name: 'Badge with only one, low-detail image', +}; + +export const FiveBadges = (): JSX.Element => ( -)); +); -story.add('Many badges', () => ( +FiveBadges.story = { + name: 'Five badges', +}; + +export const ManyBadges = (): JSX.Element => ( -)); +); -story.add('Many badges, user is a subscriber', () => ( +ManyBadges.story = { + name: 'Many badges', +}; + +export const ManyBadgesUserIsASubscriber = (): JSX.Element => ( -)); +); + +ManyBadgesUserIsASubscriber.story = { + name: 'Many badges, user is a subscriber', +}; diff --git a/ts/components/BetterAvatar.stories.tsx b/ts/components/BetterAvatar.stories.tsx index 8cc172bb3..b03d05f76 100644 --- a/ts/components/BetterAvatar.stories.tsx +++ b/ts/components/BetterAvatar.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import enMessages from '../../_locales/en/messages.json'; @@ -27,9 +26,11 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ size: 80, }); -const story = storiesOf('Components/BetterAvatar', module); +export default { + title: 'Components/BetterAvatar', +}; -story.add('Text', () => ( +export const Text = (): JSX.Element => ( ( }), })} /> -)); +); -story.add('Personal Icon', () => ( +export const PersonalIcon = (): JSX.Element => ( ( }), })} /> -)); +); -story.add('Group Icon', () => ( +export const GroupIcon = (): JSX.Element => ( ( }), })} /> -)); +); diff --git a/ts/components/BetterAvatarBubble.stories.tsx b/ts/components/BetterAvatarBubble.stories.tsx index 36a7da84d..096093723 100644 --- a/ts/components/BetterAvatarBubble.stories.tsx +++ b/ts/components/BetterAvatarBubble.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import enMessages from '../../_locales/en/messages.json'; @@ -24,27 +23,29 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ style: overrideProps.style, }); -const story = storiesOf('Components/BetterAvatarBubble', module); +export default { + title: 'Components/BetterAvatarBubble', +}; -story.add('Children', () => ( +export const Children = (): JSX.Element => ( HI, color: AvatarColors[8], })} /> -)); +); -story.add('Selected', () => ( +export const Selected = (): JSX.Element => ( -)); +); -story.add('Style', () => ( +export const Style = (): JSX.Element => ( ( color: AvatarColors[2], })} /> -)); +); diff --git a/ts/components/Button.stories.tsx b/ts/components/Button.stories.tsx index dfb38458e..36446b56f 100644 --- a/ts/components/Button.stories.tsx +++ b/ts/components/Button.stories.tsx @@ -2,14 +2,15 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { Button, ButtonSize, ButtonVariant } from './Button'; -const story = storiesOf('Components/Button', module); +export default { + title: 'Components/Button', +}; -story.add('Kitchen sink', () => ( +export const KitchenSink = (): JSX.Element => ( <> {Object.values(ButtonVariant).map(variant => ( @@ -35,18 +36,30 @@ story.add('Kitchen sink', () => ( ))} -)); +); -story.add('aria-label', () => ( +KitchenSink.story = { + name: 'Kitchen sink', +}; + +export const AriaLabel = (): JSX.Element => ( -)); +); + +CustomStyles.story = { + name: 'Custom styles', +}; diff --git a/ts/components/CallManager.stories.tsx b/ts/components/CallManager.stories.tsx index 8e69580b5..c28d7be97 100644 --- a/ts/components/CallManager.stories.tsx +++ b/ts/components/CallManager.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { boolean, select, text } from '@storybook/addon-knobs'; @@ -118,11 +117,13 @@ const createProps = (storyProps: Partial = {}): PropsType => ({ toggleSpeakerView: action('toggle-speaker-view'), }); -const story = storiesOf('Components/CallManager', module); +export default { + title: 'Components/CallManager', +}; -story.add('No Call', () => ); +export const NoCall = (): JSX.Element => ; -story.add('Ongoing Direct Call', () => ( +export const OngoingDirectCall = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Ongoing Group Call', () => ( +export const OngoingGroupCall = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Ringing (direct call)', () => ( +export const RingingDirectCall = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Ringing (group call)', () => ( +RingingDirectCall.story = { + name: 'Ringing (direct call)', +}; + +export const RingingGroupCall = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Call Request Needed', () => ( +RingingGroupCall.story = { + name: 'Ringing (group call)', +}; + +export const CallRequestNeeded = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Group call - Safety Number Changed', () => ( +export const GroupCallSafetyNumberChanged = (): JSX.Element => ( ( }, })} /> -)); +); + +GroupCallSafetyNumberChanged.story = { + name: 'Group call - Safety Number Changed', +}; diff --git a/ts/components/CallScreen.stories.tsx b/ts/components/CallScreen.stories.tsx index b98e60d56..bd37389dd 100644 --- a/ts/components/CallScreen.stories.tsx +++ b/ts/components/CallScreen.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { times } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { boolean, select, number } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -185,13 +184,15 @@ const createProps = ( toggleSpeakerView: action('toggle-speaker-view'), }); -const story = storiesOf('Components/CallScreen', module); +export default { + title: 'Components/CallScreen', +}; -story.add('Default', () => { +export const Default = (): JSX.Element => { return ; -}); +}; -story.add('Pre-Ring', () => { +export const PreRing = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Ringing', () => { +PreRing.story = { + name: 'Pre-Ring', +}; + +export const _Ringing = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Reconnecting', () => { +export const _Reconnecting = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Ended', () => { +export const _Ended = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('hasLocalAudio', () => { +export const HasLocalAudio = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('hasLocalVideo', () => { +HasLocalAudio.story = { + name: 'hasLocalAudio', +}; + +export const HasLocalVideo = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('hasRemoteVideo', () => { +HasLocalVideo.story = { + name: 'hasLocalVideo', +}; + +export const HasRemoteVideo = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Group call - 1', () => ( +HasRemoteVideo.story = { + name: 'hasRemoteVideo', +}; + +export const GroupCall1 = (): JSX.Element => ( ( ], })} /> -)); +); + +GroupCall1.story = { + name: 'Group call - 1', +}; // We generate these upfront so that the list is stable when you move the slider. const allRemoteParticipants = times(MAX_PARTICIPANTS).map(index => ({ @@ -305,7 +326,7 @@ const allRemoteParticipants = times(MAX_PARTICIPANTS).map(index => ({ }), })); -story.add('Group call - Many', () => { +export const GroupCallMany = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Group call - reconnecting', () => ( +GroupCallMany.story = { + name: 'Group call - Many', +}; + +export const GroupCallReconnecting = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Group call - 0', () => ( +GroupCallReconnecting.story = { + name: 'Group call - reconnecting', +}; + +export const GroupCall0 = (): JSX.Element => ( -)); +); -story.add('Group call - someone is sharing screen', () => ( +GroupCall0.story = { + name: 'Group call - 0', +}; + +export const GroupCallSomeoneIsSharingScreen = (): JSX.Element => ( ( })), })} /> -)); +); -story.add( - "Group call - someone is sharing screen and you're reconnecting", - () => ( +GroupCallSomeoneIsSharingScreen.story = { + name: 'Group call - someone is sharing screen', +}; + +export const GroupCallSomeoneIsSharingScreenAndYoureReconnecting = + (): JSX.Element => ( - ) -); + ); + +GroupCallSomeoneIsSharingScreenAndYoureReconnecting.story = { + name: "Group call - someone is sharing screen and you're reconnecting", +}; diff --git a/ts/components/CallingAudioIndicator.stories.tsx b/ts/components/CallingAudioIndicator.stories.tsx index bacf97d76..75f992c2a 100644 --- a/ts/components/CallingAudioIndicator.stories.tsx +++ b/ts/components/CallingAudioIndicator.stories.tsx @@ -2,15 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useState, useEffect } from 'react'; -import { storiesOf } from '@storybook/react'; import { boolean } from '@storybook/addon-knobs'; import { CallingAudioIndicator } from './CallingAudioIndicator'; import { AUDIO_LEVEL_INTERVAL_MS } from '../calling/constants'; -const story = storiesOf('Components/CallingAudioIndicator', module); +export default { + title: 'Components/CallingAudioIndicator', +}; -story.add('Extreme', () => { +export const Extreme = (): JSX.Element => { const [audioLevel, setAudioLevel] = useState(1); useEffect(() => { @@ -29,9 +30,9 @@ story.add('Extreme', () => { audioLevel={audioLevel} /> ); -}); +}; -story.add('Random', () => { +export const Random = (): JSX.Element => { const [audioLevel, setAudioLevel] = useState(1); useEffect(() => { @@ -50,4 +51,4 @@ story.add('Random', () => { audioLevel={audioLevel} /> ); -}); +}; diff --git a/ts/components/CallingButton.stories.tsx b/ts/components/CallingButton.stories.tsx index 722bc012d..3fc0b5049 100644 --- a/ts/components/CallingButton.stories.tsx +++ b/ts/components/CallingButton.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { select } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -29,9 +28,11 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ ), }); -const story = storiesOf('Components/CallingButton', module); +export default { + title: 'Components/CallingButton', +}; -story.add('Kitchen Sink', () => { +export const KitchenSink = (): JSX.Element => { return ( <> {Object.keys(CallingButtonType).map(buttonType => ( @@ -42,67 +43,71 @@ story.add('Kitchen Sink', () => { ))} ); -}); +}; -story.add('Audio On', () => { +export const AudioOn = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.AUDIO_ON, }); return ; -}); +}; -story.add('Audio Off', () => { +export const AudioOff = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.AUDIO_OFF, }); return ; -}); +}; -story.add('Audio Disabled', () => { +export const AudioDisabled = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.AUDIO_DISABLED, }); return ; -}); +}; -story.add('Video On', () => { +export const VideoOn = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.VIDEO_ON, }); return ; -}); +}; -story.add('Video Off', () => { +export const VideoOff = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.VIDEO_OFF, }); return ; -}); +}; -story.add('Video Disabled', () => { +export const VideoDisabled = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.VIDEO_DISABLED, }); return ; -}); +}; -story.add('Tooltip right', () => { +export const TooltipRight = (): JSX.Element => { const props = createProps({ tooltipDirection: TooltipPlacement.Right, }); return ; -}); +}; -story.add('Presenting On', () => { +TooltipRight.story = { + name: 'Tooltip right', +}; + +export const PresentingOn = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.PRESENTING_ON, }); return ; -}); +}; -story.add('Presenting Off', () => { +export const PresentingOff = (): JSX.Element => { const props = createProps({ buttonType: CallingButtonType.PRESENTING_OFF, }); return ; -}); +}; diff --git a/ts/components/CallingDeviceSelection.stories.tsx b/ts/components/CallingDeviceSelection.stories.tsx index a411f030d..bcf5422c1 100644 --- a/ts/components/CallingDeviceSelection.stories.tsx +++ b/ts/components/CallingDeviceSelection.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import type { Props } from './CallingDeviceSelection'; import { CallingDeviceSelection } from './CallingDeviceSelection'; @@ -38,13 +37,15 @@ const createProps = ({ toggleSettings: action('toggle-settings'), }); -const stories = storiesOf('Components/CallingDeviceSelection', module); +export default { + title: 'Components/CallingDeviceSelection', +}; -stories.add('Default', () => { +export const Default = (): JSX.Element => { return ; -}); +}; -stories.add('Some Devices', () => { +export const SomeDevices = (): JSX.Element => { const availableSpeakers = [ { name: 'Default', @@ -71,9 +72,9 @@ stories.add('Some Devices', () => { }); return ; -}); +}; -stories.add('Default Devices', () => { +export const DefaultDevices = (): JSX.Element => { const availableSpeakers = [ { name: 'default (Headphones)', @@ -102,9 +103,9 @@ stories.add('Default Devices', () => { }); return ; -}); +}; -stories.add('All Devices', () => { +export const AllDevices = (): JSX.Element => { const availableSpeakers = [ { name: 'Default', @@ -178,4 +179,4 @@ stories.add('All Devices', () => { }); return ; -}); +}; diff --git a/ts/components/CallingHeader.stories.tsx b/ts/components/CallingHeader.stories.tsx index f4bd7de26..7dde76cb9 100644 --- a/ts/components/CallingHeader.stories.tsx +++ b/ts/components/CallingHeader.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { boolean, number } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -31,29 +30,35 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ toggleSettings: () => action('toggle-settings'), }); -const story = storiesOf('Components/CallingHeader', module); +export default { + title: 'Components/CallingHeader', +}; -story.add('Default', () => ); +export const Default = (): JSX.Element => ; -story.add('Lobby style', () => ( +export const LobbyStyle = (): JSX.Element => ( -)); +); -story.add('With Participants', () => ( +LobbyStyle.story = { + name: 'Lobby style', +}; + +export const WithParticipants = (): JSX.Element => ( -)); +); -story.add('With Participants (shown)', () => ( +export const WithParticipantsShown = (): JSX.Element => ( ( showParticipantsList: true, })} /> -)); +); -story.add('Long Title', () => ( +WithParticipantsShown.story = { + name: 'With Participants (shown)', +}; + +export const LongTitle = (): JSX.Element => ( -)); +); -story.add('Title with message', () => ( +export const TitleWithMessage = (): JSX.Element => ( -)); +); + +TitleWithMessage.story = { + name: 'Title with message', +}; diff --git a/ts/components/CallingLobby.stories.tsx b/ts/components/CallingLobby.stories.tsx index ff7727711..faef36952 100644 --- a/ts/components/CallingLobby.stories.tsx +++ b/ts/components/CallingLobby.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { times } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { boolean } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -90,21 +89,27 @@ const fakePeekedParticipant = (conversationProps: Partial) => ...conversationProps, }); -const story = storiesOf('Components/CallingLobby', module); +export default { + title: 'Components/CallingLobby', +}; -story.add('Default', () => { +export const Default = (): JSX.Element => { const props = createProps(); return ; -}); +}; -story.add('No Camera, no avatar', () => { +export const NoCameraNoAvatar = (): JSX.Element => { const props = createProps({ availableCameras: [], }); return ; -}); +}; -story.add('No Camera, local avatar', () => { +NoCameraNoAvatar.story = { + name: 'No Camera, no avatar', +}; + +export const NoCameraLocalAvatar = (): JSX.Element => { const props = createProps({ availableCameras: [], me: getDefaultConversation({ @@ -115,36 +120,52 @@ story.add('No Camera, local avatar', () => { }), }); return ; -}); +}; -story.add('Local Video', () => { +NoCameraLocalAvatar.story = { + name: 'No Camera, local avatar', +}; + +export const LocalVideo = (): JSX.Element => { const props = createProps({ hasLocalVideo: true, }); return ; -}); +}; -story.add('Initially muted', () => { +export const InitiallyMuted = (): JSX.Element => { const props = createProps({ hasLocalAudio: false, }); return ; -}); +}; -story.add('Group Call - 0 peeked participants', () => { +InitiallyMuted.story = { + name: 'Initially muted', +}; + +export const GroupCall0PeekedParticipants = (): JSX.Element => { const props = createProps({ isGroupCall: true, peekedParticipants: [] }); return ; -}); +}; -story.add('Group Call - 1 peeked participant', () => { +GroupCall0PeekedParticipants.story = { + name: 'Group Call - 0 peeked participants', +}; + +export const GroupCall1PeekedParticipant = (): JSX.Element => { const props = createProps({ isGroupCall: true, peekedParticipants: [{ title: 'Sam' }].map(fakePeekedParticipant), }); return ; -}); +}; -story.add('Group Call - 1 peeked participant (self)', () => { +GroupCall1PeekedParticipant.story = { + name: 'Group Call - 1 peeked participant', +}; + +export const GroupCall1PeekedParticipantSelf = (): JSX.Element => { const uuid = UUID.generate().toString(); const props = createProps({ isGroupCall: true, @@ -155,9 +176,13 @@ story.add('Group Call - 1 peeked participant (self)', () => { peekedParticipants: [fakePeekedParticipant({ title: 'Ash', uuid })], }); return ; -}); +}; -story.add('Group Call - 4 peeked participants', () => { +GroupCall1PeekedParticipantSelf.story = { + name: 'Group Call - 1 peeked participant (self)', +}; + +export const GroupCall4PeekedParticipants = (): JSX.Element => { const props = createProps({ isGroupCall: true, peekedParticipants: ['Sam', 'Cayce', 'April', 'Logan', 'Carl'].map(title => @@ -165,9 +190,13 @@ story.add('Group Call - 4 peeked participants', () => { ), }); return ; -}); +}; -story.add('Group Call - 4 peeked participants (participants list)', () => { +GroupCall4PeekedParticipants.story = { + name: 'Group Call - 4 peeked participants', +}; + +export const GroupCall4PeekedParticipantsParticipantsList = (): JSX.Element => { const props = createProps({ isGroupCall: true, peekedParticipants: ['Sam', 'Cayce', 'April', 'Logan', 'Carl'].map(title => @@ -176,9 +205,13 @@ story.add('Group Call - 4 peeked participants (participants list)', () => { showParticipantsList: true, }); return ; -}); +}; -story.add('Group Call - call full', () => { +GroupCall4PeekedParticipantsParticipantsList.story = { + name: 'Group Call - 4 peeked participants (participants list)', +}; + +export const GroupCallCallFull = (): JSX.Element => { const props = createProps({ isGroupCall: true, isCallFull: true, @@ -187,12 +220,20 @@ story.add('Group Call - call full', () => { ), }); return ; -}); +}; -story.add('Group Call - 0 peeked participants, big group', () => { +GroupCallCallFull.story = { + name: 'Group Call - call full', +}; + +export const GroupCall0PeekedParticipantsBigGroup = (): JSX.Element => { const props = createProps({ isGroupCall: true, groupMembers: times(100, () => getDefaultConversation()), }); return ; -}); +}; + +GroupCall0PeekedParticipantsBigGroup.story = { + name: 'Group Call - 0 peeked participants, big group', +}; diff --git a/ts/components/CallingParticipantsList.stories.tsx b/ts/components/CallingParticipantsList.stories.tsx index cadb2c8fc..57de5131f 100644 --- a/ts/components/CallingParticipantsList.stories.tsx +++ b/ts/components/CallingParticipantsList.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { sample } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import type { PropsType } from './CallingParticipantsList'; @@ -44,14 +43,20 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ participants: overrideProps.participants || [], }); -const story = storiesOf('Components/CallingParticipantsList', module); +export default { + title: 'Components/CallingParticipantsList', +}; -story.add('No one', () => { +export const NoOne = (): JSX.Element => { const props = createProps(); return ; -}); +}; -story.add('Solo Call', () => { +NoOne.story = { + name: 'No one', +}; + +export const SoloCall = (): JSX.Element => { const props = createProps({ participants: [ createParticipant({ @@ -60,9 +65,9 @@ story.add('Solo Call', () => { ], }); return ; -}); +}; -story.add('Many Participants', () => { +export const ManyParticipants = (): JSX.Element => { const props = createProps({ participants: [ createParticipant({ @@ -90,13 +95,13 @@ story.add('Many Participants', () => { ], }); return ; -}); +}; -story.add('Overflow', () => { +export const Overflow = (): JSX.Element => { const props = createProps({ participants: Array(50) .fill(null) .map(() => createParticipant({ title: 'Kirby' })), }); return ; -}); +}; diff --git a/ts/components/CallingPip.stories.tsx b/ts/components/CallingPip.stories.tsx index fdea87444..546fa4f8e 100644 --- a/ts/components/CallingPip.stories.tsx +++ b/ts/components/CallingPip.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { times } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { boolean, select } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -77,14 +76,16 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ togglePip: action('toggle-pip'), }); -const story = storiesOf('Components/CallingPip', module); +export default { + title: 'Components/CallingPip', +}; -story.add('Default', () => { +export const Default = (): JSX.Element => { const props = createProps({}); return ; -}); +}; -story.add('Contact (with avatar and no video)', () => { +export const ContactWithAvatarAndNoVideo = (): JSX.Element => { const props = createProps({ activeCall: { ...defaultCall, @@ -98,9 +99,13 @@ story.add('Contact (with avatar and no video)', () => { }, }); return ; -}); +}; -story.add('Contact (no color)', () => { +ContactWithAvatarAndNoVideo.story = { + name: 'Contact (with avatar and no video)', +}; + +export const ContactNoColor = (): JSX.Element => { const props = createProps({ activeCall: { ...defaultCall, @@ -111,9 +116,13 @@ story.add('Contact (no color)', () => { }, }); return ; -}); +}; -story.add('Group Call', () => { +ContactNoColor.story = { + name: 'Contact (no color)', +}; + +export const GroupCall = (): JSX.Element => { const props = createProps({ activeCall: { ...getCommonActiveCallData(), @@ -130,4 +139,4 @@ story.add('Group Call', () => { }, }); return ; -}); +}; diff --git a/ts/components/CallingPreCallInfo.stories.tsx b/ts/components/CallingPreCallInfo.stories.tsx index 9a16ff0be..8d1bcc522 100644 --- a/ts/components/CallingPreCallInfo.stories.tsx +++ b/ts/components/CallingPreCallInfo.stories.tsx @@ -2,8 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { times, range } from 'lodash'; -import { storiesOf } from '@storybook/react'; +import { times } from 'lodash'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation'; @@ -21,56 +20,234 @@ const getDefaultGroupConversation = () => }); const otherMembers = times(6, () => getDefaultConversation()); -const story = storiesOf('Components/CallingPreCallInfo', module); +export default { + title: 'Components/CallingPreCallInfo', +}; -story.add('Direct conversation', () => ( +export const DirectConversation = (): JSX.Element => ( -)); +); -times(5, numberOfOtherPeople => { - [true, false].forEach(willRing => { - story.add( - `Group conversation, group has ${numberOfOtherPeople} other member${ - numberOfOtherPeople === 1 ? '' : 's' - }, will ${willRing ? 'ring' : 'notify'}`, - () => ( - - ) - ); - }); -}); +DirectConversation.story = { + name: 'Direct conversation', +}; -range(1, 5).forEach(numberOfOtherPeople => { - story.add( - `Group conversation, ${numberOfOtherPeople} peeked participant${ - numberOfOtherPeople === 1 ? '' : 's' - }`, - () => ( - - ) - ); -}); +export const Ring0 = (): JSX.Element => ( + +); -story.add('Group conversation, you on an other device', () => { +Ring0.story = { + name: 'Group call: Will ring 0 people', +}; + +export const Ring1 = (): JSX.Element => ( + +); + +Ring1.story = { + name: 'Group call: Will ring 1 person', +}; + +export const Ring2 = (): JSX.Element => ( + +); + +Ring2.story = { + name: 'Group call: Will ring 2 people', +}; + +export const Ring3 = (): JSX.Element => ( + +); + +Ring3.story = { + name: 'Group call: Will ring 3 people', +}; + +export const Ring4 = (): JSX.Element => ( + +); + +Ring3.story = { + name: 'Group call: Will ring 4 people', +}; + +export const Notify0 = (): JSX.Element => ( + +); + +Notify0.story = { + name: 'Group call: Will notify 0 people', +}; + +export const Notify1 = (): JSX.Element => ( + +); + +Notify1.story = { + name: 'Group call: Will notify 1 person', +}; + +export const Notify2 = (): JSX.Element => ( + +); + +Notify2.story = { + name: 'Group call: Will notify 2 people', +}; + +export const Notify3 = (): JSX.Element => ( + +); + +Notify3.story = { + name: 'Group call: Will notify 3 people', +}; + +export const Notify4 = (): JSX.Element => ( + +); + +Notify4.story = { + name: 'Group call: Will notify 4 people', +}; + +export const Peek1 = (): JSX.Element => ( + +); + +Peek1.story = { + name: 'Group call: 1 participant peeked', +}; + +export const Peek2 = (): JSX.Element => ( + +); + +Peek2.story = { + name: 'Group call: 2 participants peeked', +}; + +export const Peek3 = (): JSX.Element => ( + +); + +Peek3.story = { + name: 'Group call: 3 participants peeked', +}; + +export const Peek4 = (): JSX.Element => ( + +); + +Peek4.story = { + name: 'Group call: 4 participants peeked', +}; + +export const GroupConversationYouOnAnOtherDevice = (): JSX.Element => { const me = getDefaultConversation(); return ( { ringMode={RingMode.WillRing} /> ); -}); +}; -story.add('Group conversation, call is full', () => ( +GroupConversationYouOnAnOtherDevice.story = { + name: 'Group conversation, you on an other device', +}; + +export const GroupConversationCallIsFull = (): JSX.Element => ( ( peekedParticipants={otherMembers} ringMode={RingMode.WillRing} /> -)); +); + +GroupConversationCallIsFull.story = { + name: 'Group conversation, call is full', +}; diff --git a/ts/components/CallingScreenSharingController.stories.tsx b/ts/components/CallingScreenSharingController.stories.tsx index 32176982a..54832efac 100644 --- a/ts/components/CallingScreenSharingController.stories.tsx +++ b/ts/components/CallingScreenSharingController.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import type { PropsType } from './CallingScreenSharingController'; @@ -20,13 +19,15 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ presentedSourceName: overrideProps.presentedSourceName || 'Application', }); -const story = storiesOf('Components/CallingScreenSharingController', module); +export default { + title: 'Components/CallingScreenSharingController', +}; -story.add('Controller', () => { +export const Controller = (): JSX.Element => { return ; -}); +}; -story.add('Really long app name', () => { +export const ReallyLongAppName = (): JSX.Element => { return ( { })} /> ); -}); +}; + +ReallyLongAppName.story = { + name: 'Really long app name', +}; diff --git a/ts/components/CallingSelectPresentingSourcesModal.stories.tsx b/ts/components/CallingSelectPresentingSourcesModal.stories.tsx index ea2da276a..496a4f3a0 100644 --- a/ts/components/CallingSelectPresentingSourcesModal.stories.tsx +++ b/ts/components/CallingSelectPresentingSourcesModal.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import type { PropsType } from './CallingSelectPresentingSourcesModal'; @@ -54,11 +53,10 @@ const createProps = (): PropsType => ({ setPresenting: action('set-presenting'), }); -const story = storiesOf( - 'Components/CallingSelectPresentingSourcesModal', - module -); +export default { + title: 'Components/CallingSelectPresentingSourcesModal', +}; -story.add('Modal', () => { +export const Modal = (): JSX.Element => { return ; -}); +}; diff --git a/ts/components/CaptchaDialog.stories.tsx b/ts/components/CaptchaDialog.stories.tsx index f9bf885c9..b52aefd6b 100644 --- a/ts/components/CaptchaDialog.stories.tsx +++ b/ts/components/CaptchaDialog.stories.tsx @@ -4,18 +4,19 @@ import React, { useState } from 'react'; import { action } from '@storybook/addon-actions'; import { boolean } from '@storybook/addon-knobs'; -import { storiesOf } from '@storybook/react'; import { CaptchaDialog } from './CaptchaDialog'; import { Button } from './Button'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; -const story = storiesOf('Components/CaptchaDialog', module); +export default { + title: 'Components/CaptchaDialog', +}; const i18n = setupI18n('en', enMessages); -story.add('CaptchaDialog', () => { +export const _CaptchaDialog = (): JSX.Element => { const [isSkipped, setIsSkipped] = useState(false); if (isSkipped) { @@ -30,4 +31,8 @@ story.add('CaptchaDialog', () => { onSkip={() => setIsSkipped(true)} /> ); -}); +}; + +_CaptchaDialog.story = { + name: 'CaptchaDialog', +}; diff --git a/ts/components/ChatColorPicker.stories.tsx b/ts/components/ChatColorPicker.stories.tsx index eb2df8c20..a8f3e5751 100644 --- a/ts/components/ChatColorPicker.stories.tsx +++ b/ts/components/ChatColorPicker.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { select } from '@storybook/addon-knobs'; @@ -13,7 +12,9 @@ import { ChatColorPicker } from './ChatColorPicker'; import { ConversationColors } from '../types/Colors'; import { setupI18n } from '../util/setupI18n'; -const story = storiesOf('Components/ChatColorPicker', module); +export default { + title: 'Components/ChatColorPicker', +}; const i18n = setupI18n('en', enMessages); @@ -40,7 +41,9 @@ const createProps = (): PropsType => ({ ), }); -story.add('Default', () => ); +export const Default = (): JSX.Element => ( + +); const CUSTOM_COLORS = { abc: { @@ -59,7 +62,7 @@ const CUSTOM_COLORS = { }, }; -story.add('Custom Colors', () => ( +export const CustomColors = (): JSX.Element => ( ( value: SAMPLE_CUSTOM_COLOR, }} /> -)); +); diff --git a/ts/components/Checkbox.stories.tsx b/ts/components/Checkbox.stories.tsx index af7db7fec..f7408e440 100644 --- a/ts/components/Checkbox.stories.tsx +++ b/ts/components/Checkbox.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import type { PropsType } from './Checkbox'; import { Checkbox } from './Checkbox'; @@ -15,14 +14,19 @@ const createProps = (): PropsType => ({ onChange: action('onChange'), }); -const story = storiesOf('Components/Checkbox', module); +export default { + title: 'Components/Checkbox', +}; -story.add('Normal', () => ); +export const Normal = (): JSX.Element => ; +export const Checked = (): JSX.Element => ( + +); -story.add('Checked', () => ); - -story.add('Description', () => ( +export const Description = (): JSX.Element => ( -)); +); -story.add('Disabled', () => ); +export const Disabled = (): JSX.Element => ( + +); diff --git a/ts/components/ClearingData.stories.tsx b/ts/components/ClearingData.stories.tsx index ea0288454..3dacf136b 100644 --- a/ts/components/ClearingData.stories.tsx +++ b/ts/components/ClearingData.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -12,8 +11,14 @@ import { ClearingData } from './ClearingData'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/ClearingData', module); +export default { + title: 'Components/ClearingData', +}; -story.add('Clearing data', () => ( +export const _ClearingData = (): JSX.Element => ( -)); +); + +_ClearingData.story = { + name: 'Clearing data', +}; diff --git a/ts/components/CompositionArea.stories.tsx b/ts/components/CompositionArea.stories.tsx index 79ebc77d6..9ab84711c 100644 --- a/ts/components/CompositionArea.stories.tsx +++ b/ts/components/CompositionArea.stories.tsx @@ -1,9 +1,9 @@ // Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import type { DecoratorFunction } from '@storybook/addons'; import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { boolean, select } from '@storybook/addon-knobs'; @@ -21,10 +21,13 @@ import { ConversationColors } from '../types/Colors'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/CompositionArea', module); - -// necessary for the add attachment button to render properly -story.addDecorator(storyFn =>
{storyFn()}
); +export default { + title: 'Components/CompositionArea', + decorators: [ + // necessary for the add attachment button to render properly + storyFn =>
{storyFn()}
, + ] as Array>, +}; const useProps = (overrideProps: Partial = {}): Props => ({ addAttachment: action('addAttachment'), @@ -115,55 +118,63 @@ const useProps = (overrideProps: Partial = {}): Props => ({ isFetchingUUID: overrideProps.isFetchingUUID || false, }); -story.add('Default', () => { +export const Default = (): JSX.Element => { const props = useProps(); return ; -}); +}; -story.add('Starting Text', () => { +export const StartingText = (): JSX.Element => { const props = useProps({ draftText: "here's some starting text", }); return ; -}); +}; -story.add('Sticker Button', () => { +export const StickerButton = (): JSX.Element => { const props = useProps({ // eslint-disable-next-line @typescript-eslint/no-explicit-any knownPacks: [{} as any], }); return ; -}); +}; -story.add('Message Request', () => { +export const MessageRequest = (): JSX.Element => { const props = useProps({ messageRequestsEnabled: true, }); return ; -}); +}; -story.add('SMS-only fetching UUID', () => { +export const SmsOnlyFetchingUuid = (): JSX.Element => { const props = useProps({ isSMSOnly: true, isFetchingUUID: true, }); return ; -}); +}; -story.add('SMS-only', () => { +SmsOnlyFetchingUuid.story = { + name: 'SMS-only fetching UUID', +}; + +export const SmsOnly = (): JSX.Element => { const props = useProps({ isSMSOnly: true, }); return ; -}); +}; -story.add('Attachments', () => { +SmsOnly.story = { + name: 'SMS-only', +}; + +export const Attachments = (): JSX.Element => { const props = useProps({ draftAttachments: [ fakeDraftAttachment({ @@ -174,18 +185,22 @@ story.add('Attachments', () => { }); return ; -}); +}; -story.add('Announcements Only group', () => ( +export const AnnouncementsOnlyGroup = (): JSX.Element => ( -)); +); -story.add('Quote', () => ( +AnnouncementsOnlyGroup.story = { + name: 'Announcements Only group', +}; + +export const Quote = (): JSX.Element => ( ( }, })} /> -)); +); diff --git a/ts/components/CompositionInput.stories.tsx b/ts/components/CompositionInput.stories.tsx index 4019336d4..fcfe65f2b 100644 --- a/ts/components/CompositionInput.stories.tsx +++ b/ts/components/CompositionInput.stories.tsx @@ -5,7 +5,6 @@ import * as React from 'react'; import 'react-quill/dist/quill.core.css'; import { boolean, select } from '@storybook/addon-knobs'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation'; @@ -17,7 +16,9 @@ import { StorybookThemeContext } from '../../.storybook/StorybookThemeContext'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/CompositionInput', module); +export default { + title: 'Components/CompositionInput', +}; const useProps = (overrideProps: Partial = {}): Props => ({ i18n, @@ -48,37 +49,37 @@ const useProps = (overrideProps: Partial = {}): Props => ({ theme: React.useContext(StorybookThemeContext), }); -story.add('Default', () => { +export const Default = (): JSX.Element => { const props = useProps(); return ; -}); +}; -story.add('Large', () => { +export const Large = (): JSX.Element => { const props = useProps({ large: true, }); return ; -}); +}; -story.add('Disabled', () => { +export const Disabled = (): JSX.Element => { const props = useProps({ disabled: true, }); return ; -}); +}; -story.add('Starting Text', () => { +export const StartingText = (): JSX.Element => { const props = useProps({ draftText: "here's some starting text", }); return ; -}); +}; -story.add('Multiline Text', () => { +export const MultilineText = (): JSX.Element => { const props = useProps({ draftText: `here's some starting text and more on another line @@ -92,9 +93,9 @@ and we're done`, }); return ; -}); +}; -story.add('Emojis', () => { +export const Emojis = (): JSX.Element => { const props = useProps({ draftText: `⁣😐😐😐😐😐😐😐 😐😐😐😐😐😐😐 @@ -104,9 +105,9 @@ story.add('Emojis', () => { }); return ; -}); +}; -story.add('Mentions', () => { +export const Mentions = (): JSX.Element => { const props = useProps({ sortedGroupMembers: [ getDefaultConversation({ @@ -128,4 +129,4 @@ story.add('Mentions', () => { }); return ; -}); +}; diff --git a/ts/components/ConfirmDiscardDialog.stories.tsx b/ts/components/ConfirmDiscardDialog.stories.tsx index 0e6f50858..e79253de6 100644 --- a/ts/components/ConfirmDiscardDialog.stories.tsx +++ b/ts/components/ConfirmDiscardDialog.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -19,6 +18,10 @@ const createProps = (): PropsType => ({ onDiscard: action('onDiscard'), }); -const story = storiesOf('Components/ConfirmDiscardDialog', module); +export default { + title: 'Components/ConfirmDiscardDialog', +}; -story.add('Default', () => ); +export const Default = (): JSX.Element => ( + +); diff --git a/ts/components/ConfirmationDialog.stories.tsx b/ts/components/ConfirmationDialog.stories.tsx index 83c712d3c..875d956c6 100644 --- a/ts/components/ConfirmationDialog.stories.tsx +++ b/ts/components/ConfirmationDialog.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { text } from '@storybook/addon-knobs'; @@ -12,46 +11,58 @@ import enMessages from '../../_locales/en/messages.json'; const i18n = setupI18n('en', enMessages); -storiesOf('Components/ConfirmationDialog', module) - .add('ConfirmationDialog', () => { - return ( - - {text('Child text', 'asdf blip')} - - ); - }) - .add('Custom cancel text', () => { - return ( - - {text('Child text', 'asdf blip')} - - ); - }); +export default { + title: 'Components/ConfirmationDialog', +}; + +export const _ConfirmationDialog = (): JSX.Element => { + return ( + + {text('Child text', 'asdf blip')} + + ); +}; + +_ConfirmationDialog.story = { + name: 'ConfirmationDialog', +}; + +export const CustomCancelText = (): JSX.Element => { + return ( + + {text('Child text', 'asdf blip')} + + ); +}; + +CustomCancelText.story = { + name: 'Custom cancel text', +}; diff --git a/ts/components/ContactPills.stories.tsx b/ts/components/ContactPills.stories.tsx index d2052d7c4..3d5da9475 100644 --- a/ts/components/ContactPills.stories.tsx +++ b/ts/components/ContactPills.stories.tsx @@ -4,7 +4,6 @@ import React from 'react'; import { times } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; @@ -17,7 +16,9 @@ import { getDefaultConversation } from '../test-both/helpers/getDefaultConversat const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/Contact Pills', module); +export default { + title: 'Components/Contact Pills', +}; type ContactType = Omit; @@ -49,23 +50,35 @@ const contactPillProps = ( onClickRemove: action('onClickRemove'), }); -story.add('Empty list', () => ); +export const EmptyList = (): JSX.Element => ; -story.add('One contact', () => ( +EmptyList.story = { + name: 'Empty list', +}; + +export const OneContact = (): JSX.Element => ( -)); +); -story.add('Three contacts', () => ( +OneContact.story = { + name: 'One contact', +}; + +export const ThreeContacts = (): JSX.Element => ( -)); +); -story.add('Four contacts, one with a long name', () => ( +ThreeContacts.story = { + name: 'Three contacts', +}; + +export const FourContactsOneWithALongName = (): JSX.Element => ( ( -)); +); -story.add('Fifty contacts', () => ( +FourContactsOneWithALongName.story = { + name: 'Four contacts, one with a long name', +}; + +export const FiftyContacts = (): JSX.Element => ( {contacts.map(contact => ( ))} -)); +); + +FiftyContacts.story = { + name: 'Fifty contacts', +}; diff --git a/ts/components/ContextMenu.stories.tsx b/ts/components/ContextMenu.stories.tsx index 2a7e65256..f19cec6d8 100644 --- a/ts/components/ContextMenu.stories.tsx +++ b/ts/components/ContextMenu.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import type { PropsType } from './ContextMenu'; @@ -12,7 +11,9 @@ import { setupI18n } from '../util/setupI18n'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/ContextMenu', module); +export default { + title: 'Components/ContextMenu', +}; const getDefaultProps = (): PropsType => ({ i18n, @@ -32,6 +33,6 @@ const getDefaultProps = (): PropsType => ({ ], }); -story.add('Default', () => { +export const Default = (): JSX.Element => { return ; -}); +}; diff --git a/ts/components/ConversationList.stories.tsx b/ts/components/ConversationList.stories.tsx index e3e7460c0..b84cf709a 100644 --- a/ts/components/ConversationList.stories.tsx +++ b/ts/components/ConversationList.stories.tsx @@ -4,7 +4,6 @@ import React, { useContext } from 'react'; import { times, omit } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { boolean, date, select, text } from '@storybook/addon-knobs'; @@ -24,7 +23,9 @@ import { makeFakeLookupConversationWithoutUuid } from '../test-both/helpers/fake const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/ConversationList', module); +export default { + title: 'Components/ConversationList', +}; const defaultConversations: Array = [ getDefaultConversation({ @@ -96,13 +97,17 @@ const Wrapper = ({ ); }; -story.add('Archive button', () => ( +export const _ArchiveButton = (): JSX.Element => ( -)); +); -story.add('Contact: note to self', () => ( +_ArchiveButton.story = { + name: 'Archive button', +}; + +export const ContactNoteToSelf = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Contact: direct', () => ( +ContactNoteToSelf.story = { + name: 'Contact: note to self', +}; + +export const ContactDirect = (): JSX.Element => ( -)); +); -story.add('Contact: direct with short about', () => ( +ContactDirect.story = { + name: 'Contact: direct', +}; + +export const ContactDirectWithShortAbout = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Contact: direct with long about', () => ( +ContactDirectWithShortAbout.story = { + name: 'Contact: direct with short about', +}; + +export const ContactDirectWithLongAbout = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Contact: group', () => ( +ContactDirectWithLongAbout.story = { + name: 'Contact: direct with long about', +}; + +export const ContactGroup = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Contact checkboxes', () => ( +ContactGroup.story = { + name: 'Contact: group', +}; + +export const ContactCheckboxes = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Contact checkboxes: disabled', () => ( +ContactCheckboxes.story = { + name: 'Contact checkboxes', +}; + +export const ContactCheckboxesDisabled = (): JSX.Element => ( ( }, ]} /> -)); +); -{ - const createConversation = ( - overrideProps: Partial = {} - ): ConversationListItemPropsType => ({ - ...overrideProps, - acceptedMessageRequest: boolean( - 'acceptedMessageRequest', - overrideProps.acceptedMessageRequest !== undefined - ? overrideProps.acceptedMessageRequest - : true +ContactCheckboxesDisabled.story = { + name: 'Contact checkboxes: disabled', +}; + +const createConversation = ( + overrideProps: Partial = {} +): ConversationListItemPropsType => ({ + ...overrideProps, + acceptedMessageRequest: boolean( + 'acceptedMessageRequest', + overrideProps.acceptedMessageRequest !== undefined + ? overrideProps.acceptedMessageRequest + : true + ), + badges: [], + isMe: boolean('isMe', overrideProps.isMe || false), + avatarPath: text('avatarPath', overrideProps.avatarPath || ''), + id: overrideProps.id || '', + isSelected: boolean('isSelected', overrideProps.isSelected || false), + title: text('title', overrideProps.title || 'Some Person'), + name: overrideProps.name || 'Some Person', + type: overrideProps.type || 'direct', + markedUnread: boolean('markedUnread', overrideProps.markedUnread || false), + lastMessage: overrideProps.lastMessage || { + text: text('lastMessage.text', 'Hi there!'), + status: select( + 'status', + MessageStatuses.reduce((m, s) => ({ ...m, [s]: s }), {}), + 'read' ), - badges: [], - isMe: boolean('isMe', overrideProps.isMe || false), - avatarPath: text('avatarPath', overrideProps.avatarPath || ''), - id: overrideProps.id || '', - isSelected: boolean('isSelected', overrideProps.isSelected || false), - title: text('title', overrideProps.title || 'Some Person'), - name: overrideProps.name || 'Some Person', - type: overrideProps.type || 'direct', - markedUnread: boolean('markedUnread', overrideProps.markedUnread || false), - lastMessage: overrideProps.lastMessage || { - text: text('lastMessage.text', 'Hi there!'), - status: select( - 'status', - MessageStatuses.reduce((m, s) => ({ ...m, [s]: s }), {}), - 'read' - ), + deletedForEveryone: false, + }, + lastUpdated: date( + 'lastUpdated', + new Date(overrideProps.lastUpdated || Date.now() - 5 * 60 * 1000) + ), + sharedGroupNames: [], +}); + +const renderConversation = ( + overrideProps: Partial = {} +) => ( + +); + +export const ConversationName = (): JSX.Element => renderConversation(); + +ConversationName.story = { + name: 'Conversation: name', +}; + +export const ConversationNameAndAvatar = (): JSX.Element => + renderConversation({ + avatarPath: '/fixtures/kitten-1-64-64.jpg', + }); + +ConversationNameAndAvatar.story = { + name: 'Conversation: name and avatar', +}; + +export const ConversationWithYourself = (): JSX.Element => + renderConversation({ + lastMessage: { + text: 'Just a second', + status: 'read', deletedForEveryone: false, }, - lastUpdated: date( - 'lastUpdated', - new Date(overrideProps.lastUpdated || Date.now() - 5 * 60 * 1000) - ), - sharedGroupNames: [], + name: 'Myself', + title: 'Myself', + isMe: true, }); - const renderConversation = ( - overrideProps: Partial = {} - ) => ( - ( + ({ + type: RowType.Conversation, + conversation: createConversation({ + lastMessage: { text: status, status, deletedForEveryone: false }, + }), + }))} + /> +); + +ConversationsMessageStatuses.story = { + name: 'Conversations: Message Statuses', +}; + +export const ConversationTypingStatus = (): JSX.Element => + renderConversation({ + typingContactId: UUID.generate().toString(), + }); + +ConversationTypingStatus.story = { + name: 'Conversation: Typing Status', +}; + +export const ConversationWithDraft = (): JSX.Element => + renderConversation({ + shouldShowDraft: true, + draftPreview: "I'm in the middle of typing this...", + }); + +ConversationWithDraft.story = { + name: 'Conversation: With draft', +}; + +export const ConversationDeletedForEveryone = (): JSX.Element => + renderConversation({ + lastMessage: { deletedForEveryone: true }, + }); + +ConversationDeletedForEveryone.story = { + name: 'Conversation: Deleted for everyone', +}; + +export const ConversationMessageRequest = (): JSX.Element => + renderConversation({ + acceptedMessageRequest: false, + lastMessage: { + text: 'A Message', + status: 'delivered', + deletedForEveryone: false, + }, + }); + +ConversationMessageRequest.story = { + name: 'Conversation: Message Request', +}; + +export const ConversationsUnreadCount = (): JSX.Element => ( + ({ + type: RowType.Conversation, + conversation: createConversation({ + lastMessage: { + text: 'Hey there!', + status: 'delivered', + deletedForEveryone: false, }, - ]} - /> - ); + unreadCount, + }), + }))} + /> +); - story.add('Conversation: name', () => renderConversation()); +ConversationsUnreadCount.story = { + name: 'Conversations: unread count', +}; - story.add('Conversation: name and avatar', () => - renderConversation({ - avatarPath: '/fixtures/kitten-1-64-64.jpg', - }) - ); +export const ConversationMarkedUnread = (): JSX.Element => + renderConversation({ markedUnread: true }); - story.add('Conversation: with yourself', () => - renderConversation({ - lastMessage: { - text: 'Just a second', - status: 'read', - deletedForEveryone: false, - }, - name: 'Myself', - title: 'Myself', - isMe: true, - }) - ); +ConversationMarkedUnread.story = { + name: 'Conversation: marked unread', +}; - story.add('Conversations: Message Statuses', () => ( - ({ - type: RowType.Conversation, - conversation: createConversation({ - lastMessage: { text: status, status, deletedForEveryone: false }, - }), - }))} - /> - )); - - story.add('Conversation: Typing Status', () => - renderConversation({ - typingContactId: UUID.generate().toString(), - }) - ); - - story.add('Conversation: With draft', () => - renderConversation({ - shouldShowDraft: true, - draftPreview: "I'm in the middle of typing this...", - }) - ); - - story.add('Conversation: Deleted for everyone', () => - renderConversation({ - lastMessage: { deletedForEveryone: true }, - }) - ); - - story.add('Conversation: Message Request', () => - renderConversation({ - acceptedMessageRequest: false, - lastMessage: { - text: 'A Message', - status: 'delivered', - deletedForEveryone: false, - }, - }) - ); - - story.add('Conversations: unread count', () => ( - ({ - type: RowType.Conversation, - conversation: createConversation({ - lastMessage: { - text: 'Hey there!', - status: 'delivered', - deletedForEveryone: false, - }, - unreadCount, - }), - }))} - /> - )); - - story.add('Conversation: marked unread', () => - renderConversation({ markedUnread: true }) - ); - - story.add('Conversation: Selected', () => - renderConversation({ - lastMessage: { - text: 'Hey there!', - status: 'read', - deletedForEveryone: false, - }, - isSelected: true, - }) - ); - - story.add('Conversation: Emoji in Message', () => - renderConversation({ - lastMessage: { - text: '🔥', - status: 'read', - deletedForEveryone: false, - }, - }) - ); - - story.add('Conversation: Link in Message', () => - renderConversation({ - lastMessage: { - text: 'Download at http://signal.org', - status: 'read', - deletedForEveryone: false, - }, - }) - ); - - story.add('Conversation: long name', () => { - const name = - 'Long contact name. Esquire. The third. And stuff. And more! And more!'; - - return renderConversation({ - name, - title: name, - }); +export const ConversationSelected = (): JSX.Element => + renderConversation({ + lastMessage: { + text: 'Hey there!', + status: 'read', + deletedForEveryone: false, + }, + isSelected: true, }); - story.add('Conversation: Long Message', () => { - const messages = [ - "Long line. This is a really really really long line. Really really long. Because that's just how it is", - `Many lines. This is a many-line message. +ConversationSelected.story = { + name: 'Conversation: Selected', +}; + +export const ConversationEmojiInMessage = (): JSX.Element => + renderConversation({ + lastMessage: { + text: '🔥', + status: 'read', + deletedForEveryone: false, + }, + }); + +ConversationEmojiInMessage.story = { + name: 'Conversation: Emoji in Message', +}; + +export const ConversationLinkInMessage = (): JSX.Element => + renderConversation({ + lastMessage: { + text: 'Download at http://signal.org', + status: 'read', + deletedForEveryone: false, + }, + }); + +ConversationLinkInMessage.story = { + name: 'Conversation: Link in Message', +}; + +export const ConversationLongName = (): JSX.Element => { + const name = + 'Long contact name. Esquire. The third. And stuff. And more! And more!'; + + return renderConversation({ + name, + title: name, + }); +}; + +ConversationLongName.story = { + name: 'Conversation: long name', +}; + +export const ConversationLongMessage = (): JSX.Element => { + const messages = [ + "Long line. This is a really really really long line. Really really long. Because that's just how it is", + `Many lines. This is a many-line message. Line 2 is really exciting but it shouldn't be seen. Line three is even better. Line 4, well.`, - ]; + ]; - return ( - ({ - type: RowType.Conversation, - conversation: createConversation({ - lastMessage: { - text: messageText, - status: 'read', - deletedForEveryone: false, - }, - }), - }))} - /> - ); - }); - - story.add('Conversations: Various Times', () => { - const pairs: Array<[number, string]> = [ - [Date.now() - 5 * 60 * 60 * 1000, 'Five hours ago'], - [Date.now() - 24 * 60 * 60 * 1000, 'One day ago'], - [Date.now() - 7 * 24 * 60 * 60 * 1000, 'One week ago'], - [Date.now() - 365 * 24 * 60 * 60 * 1000, 'One year ago'], - ]; - - return ( - ({ - type: RowType.Conversation, - conversation: createConversation({ - lastUpdated, - lastMessage: { - text: messageText, - status: 'read', - deletedForEveryone: false, - }, - }), - }))} - /> - ); - }); - - story.add('Conversation: Missing Date', () => { - const row = { - type: RowType.Conversation as const, - conversation: omit(createConversation(), 'lastUpdated'), - }; - - return ; - }); - - story.add('Conversation: Missing Message', () => { - const row = { - type: RowType.Conversation as const, - conversation: omit(createConversation(), 'lastMessage'), - }; - - return ; - }); - - story.add('Conversation: Missing Text', () => - renderConversation({ - lastMessage: { - text: '', - status: 'sent', - deletedForEveryone: false, - }, - }) + return ( + ({ + type: RowType.Conversation, + conversation: createConversation({ + lastMessage: { + text: messageText, + status: 'read', + deletedForEveryone: false, + }, + }), + }))} + /> ); +}; - story.add('Conversation: Muted Conversation', () => - renderConversation({ - muteExpiresAt: Date.now() + 1000 * 60 * 60, - }) +ConversationLongMessage.story = { + name: 'Conversation: Long Message', +}; + +export const ConversationsVariousTimes = (): JSX.Element => { + const pairs: Array<[number, string]> = [ + [Date.now() - 5 * 60 * 60 * 1000, 'Five hours ago'], + [Date.now() - 24 * 60 * 60 * 1000, 'One day ago'], + [Date.now() - 7 * 24 * 60 * 60 * 1000, 'One week ago'], + [Date.now() - 365 * 24 * 60 * 60 * 1000, 'One year ago'], + ]; + + return ( + ({ + type: RowType.Conversation, + conversation: createConversation({ + lastUpdated, + lastMessage: { + text: messageText, + status: 'read', + deletedForEveryone: false, + }, + }), + }))} + /> ); +}; - story.add('Conversation: At Mention', () => - renderConversation({ - title: 'The Rebellion', - type: 'group', - lastMessage: { - text: '@Leia Organa I know', - status: 'read', - deletedForEveryone: false, - }, - }) - ); -} +ConversationsVariousTimes.story = { + name: 'Conversations: Various Times', +}; -story.add('Headers', () => ( +export const ConversationMissingDate = (): JSX.Element => { + const row = { + type: RowType.Conversation as const, + conversation: omit(createConversation(), 'lastUpdated'), + }; + + return ; +}; + +ConversationMissingDate.story = { + name: 'Conversation: Missing Date', +}; + +export const ConversationMissingMessage = (): JSX.Element => { + const row = { + type: RowType.Conversation as const, + conversation: omit(createConversation(), 'lastMessage'), + }; + + return ; +}; + +ConversationMissingMessage.story = { + name: 'Conversation: Missing Message', +}; + +export const ConversationMissingText = (): JSX.Element => + renderConversation({ + lastMessage: { + text: '', + status: 'sent', + deletedForEveryone: false, + }, + }); + +ConversationMissingText.story = { + name: 'Conversation: Missing Text', +}; + +export const ConversationMutedConversation = (): JSX.Element => + renderConversation({ + muteExpiresAt: Date.now() + 1000 * 60 * 60, + }); + +ConversationMutedConversation.story = { + name: 'Conversation: Muted Conversation', +}; + +export const ConversationAtMention = (): JSX.Element => + renderConversation({ + title: 'The Rebellion', + type: 'group', + lastMessage: { + text: '@Leia Organa I know', + status: 'read', + deletedForEveryone: false, + }, + }); + +ConversationAtMention.story = { + name: 'Conversation: At Mention', +}; + +export const Headers = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Find by phone number', () => ( +export const FindByPhoneNumber = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Find by username', () => ( +FindByPhoneNumber.story = { + name: 'Find by phone number', +}; + +export const FindByUsername = (): JSX.Element => ( ( }, ]} /> -)); +); -story.add('Search results loading skeleton', () => ( +FindByUsername.story = { + name: 'Find by username', +}; + +export const SearchResultsLoadingSkeleton = (): JSX.Element => ( ( })), ]} /> -)); +); -story.add('Kitchen sink', () => ( +SearchResultsLoadingSkeleton.story = { + name: 'Search results loading skeleton', +}; + +export const KitchenSink = (): JSX.Element => ( ( }, ]} /> -)); +); + +KitchenSink.story = { + name: 'Kitchen sink', +}; diff --git a/ts/components/CrashReportDialog.stories.tsx b/ts/components/CrashReportDialog.stories.tsx index 1c38649b3..3c5c942b3 100644 --- a/ts/components/CrashReportDialog.stories.tsx +++ b/ts/components/CrashReportDialog.stories.tsx @@ -3,18 +3,19 @@ import React, { useState } from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import { CrashReportDialog } from './CrashReportDialog'; import { setupI18n } from '../util/setupI18n'; import { sleep } from '../util/sleep'; import enMessages from '../../_locales/en/messages.json'; -const story = storiesOf('Components/CrashReportDialog', module); +export default { + title: 'Components/CrashReportDialog', +}; const i18n = setupI18n('en', enMessages); -story.add('CrashReportDialog', () => { +export const _CrashReportDialog = (): JSX.Element => { const [isPending, setIsPending] = useState(false); return ( @@ -30,4 +31,8 @@ story.add('CrashReportDialog', () => { eraseCrashReports={action('eraseCrashReports')} /> ); -}); +}; + +_CrashReportDialog.story = { + name: 'CrashReportDialog', +}; diff --git a/ts/components/CustomColorEditor.stories.tsx b/ts/components/CustomColorEditor.stories.tsx index 8b9614477..a3cc482b7 100644 --- a/ts/components/CustomColorEditor.stories.tsx +++ b/ts/components/CustomColorEditor.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import enMessages from '../../_locales/en/messages.json'; @@ -11,7 +10,9 @@ import type { PropsType } from './CustomColorEditor'; import { CustomColorEditor } from './CustomColorEditor'; import { setupI18n } from '../util/setupI18n'; -const story = storiesOf('Components/CustomColorEditor', module); +export default { + title: 'Components/CustomColorEditor', +}; const i18n = setupI18n('en', enMessages); @@ -21,4 +22,6 @@ const createProps = (): PropsType => ({ onSave: action('onSave'), }); -story.add('Default', () => ); +export const Default = (): JSX.Element => ( + +); diff --git a/ts/components/CustomizingPreferredReactionsModal.stories.tsx b/ts/components/CustomizingPreferredReactionsModal.stories.tsx index 0058585a1..8d7256a42 100644 --- a/ts/components/CustomizingPreferredReactionsModal.stories.tsx +++ b/ts/components/CustomizingPreferredReactionsModal.stories.tsx @@ -4,7 +4,6 @@ import type { ComponentProps } from 'react'; import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -12,10 +11,10 @@ import enMessages from '../../_locales/en/messages.json'; import { CustomizingPreferredReactionsModal } from './CustomizingPreferredReactionsModal'; const i18n = setupI18n('en', enMessages); -const story = storiesOf( - 'Components/CustomizingPreferredReactionsModal', - module -); + +export default { + title: 'Components/CustomizingPreferredReactionsModal', +}; const defaultProps: ComponentProps = { @@ -38,21 +37,29 @@ const defaultProps: ComponentProps = skinTone: 4, }; -story.add('Default', () => ( +export const Default = (): JSX.Element => ( -)); +); -story.add('Draft emoji selected', () => ( +export const DraftEmojiSelected = (): JSX.Element => ( -)); +); -story.add('Saving', () => ( +DraftEmojiSelected.story = { + name: 'Draft emoji selected', +}; + +export const Saving = (): JSX.Element => ( -)); +); -story.add('Had error', () => ( +export const HadError = (): JSX.Element => ( -)); +); + +HadError.story = { + name: 'Had error', +}; diff --git a/ts/components/DebugLogWindow.stories.tsx b/ts/components/DebugLogWindow.stories.tsx index aa5ee4852..d6764c84a 100644 --- a/ts/components/DebugLogWindow.stories.tsx +++ b/ts/components/DebugLogWindow.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import enMessages from '../../_locales/en/messages.json'; import type { PropsType } from './DebugLogWindow'; @@ -28,6 +27,14 @@ const createProps = (): PropsType => ({ }, }); -const story = storiesOf('Components/DebugLogWindow', module); +export default { + title: 'Components/DebugLogWindow', +}; -story.add('DebugLogWindow', () => ); +export const _DebugLogWindow = (): JSX.Element => ( + +); + +_DebugLogWindow.story = { + name: 'DebugLogWindow', +}; diff --git a/ts/components/DialogExpiredBuild.stories.tsx b/ts/components/DialogExpiredBuild.stories.tsx index 4cbcb71bb..47ea82d8e 100644 --- a/ts/components/DialogExpiredBuild.stories.tsx +++ b/ts/components/DialogExpiredBuild.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { boolean, select } from '@storybook/addon-knobs'; import { DialogExpiredBuild } from './DialogExpiredBuild'; @@ -13,26 +12,29 @@ import { FakeLeftPaneContainer } from '../test-both/helpers/FakeLeftPaneContaine const i18n = setupI18n('en', enMessages); -storiesOf('Components/DialogExpiredBuild', module).add( - 'DialogExpiredBuild', - () => { - const containerWidthBreakpoint = select( - 'containerWidthBreakpoint', - WidthBreakpoint, - WidthBreakpoint.Wide - ); - const hasExpired = boolean('hasExpired', true); +export default { + title: 'Components/DialogExpiredBuild', +}; - return ( - { + const containerWidthBreakpoint = select( + 'containerWidthBreakpoint', + WidthBreakpoint, + WidthBreakpoint.Wide + ); + const hasExpired = boolean('hasExpired', true); + + return ( + + - - - ); - } -); + hasExpired={hasExpired} + i18n={i18n} + /> + + ); +}; + +_DialogExpiredBuild.story = { + name: 'DialogExpiredBuild', +}; diff --git a/ts/components/DialogNetworkStatus.stories.tsx b/ts/components/DialogNetworkStatus.stories.tsx index d71b86953..07db92a91 100644 --- a/ts/components/DialogNetworkStatus.stories.tsx +++ b/ts/components/DialogNetworkStatus.stories.tsx @@ -2,10 +2,9 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; -import { boolean, select } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; +import type { PropsType } from './DialogNetworkStatus'; import { DialogNetworkStatus } from './DialogNetworkStatus'; import { SocketStatus } from '../types/SocketStatus'; import { setupI18n } from '../util/setupI18n'; @@ -26,16 +25,12 @@ const defaultProps = { challengeStatus: 'idle' as const, }; -const story = storiesOf('Components/DialogNetworkStatus', module); +export default { + title: 'Components/DialogNetworkStatus', +}; -story.add('Knobs Playground', () => { - const containerWidthBreakpoint = select( - 'containerWidthBreakpoint', - WidthBreakpoint, - WidthBreakpoint.Wide - ); - const hasNetworkDialog = boolean('hasNetworkDialog', true); - const isOnline = boolean('isOnline', true); +export const KnobsPlayground = (args: PropsType): JSX.Element => { + /* const socketStatus = select( 'socketStatus', { @@ -46,61 +41,129 @@ story.add('Knobs Playground', () => { }, SocketStatus.CONNECTING ); + */ return ( - - + + ); -}); +}; +KnobsPlayground.args = { + containerWidthBreakpoint: WidthBreakpoint.Wide, + hasNetworkDialog: true, + isOnline: true, + socketStatus: SocketStatus.CONNECTING, +}; -( - [ - ['wide', WidthBreakpoint.Wide], - ['narrow', WidthBreakpoint.Narrow], - ] as const -).forEach(([name, containerWidthBreakpoint]) => { - const defaultPropsForBreakpoint = { - ...defaultProps, - containerWidthBreakpoint, - }; +export const ConnectingWide = (): JSX.Element => ( + + + +); - story.add(`Connecting (${name} container)`, () => ( - - - - )); +ConnectingWide.story = { + name: 'Connecting Wide', +}; - story.add(`Closing (${name} container)`, () => ( - - - - )); +export const ClosingWide = (): JSX.Element => ( + + + +); - story.add(`Closed (${name} container)`, () => ( - - - - )); +ClosingWide.story = { + name: 'Closing Wide', +}; - story.add(`Offline (${name} container)`, () => ( - - - - )); -}); +export const ClosedWide = (): JSX.Element => ( + + + +); + +ClosedWide.story = { + name: 'Closed Wide', +}; + +export const OfflineWide = (): JSX.Element => ( + + + +); + +OfflineWide.story = { + name: 'Offline Wide', +}; + +export const ConnectingNarrow = (): JSX.Element => ( + + + +); + +ConnectingNarrow.story = { + name: 'Connecting Narrow', +}; + +export const ClosingNarrow = (): JSX.Element => ( + + + +); + +ClosingNarrow.story = { + name: 'Closing Narrow', +}; + +export const ClosedNarrow = (): JSX.Element => ( + + + +); + +ClosedNarrow.story = { + name: 'Closed Narrow', +}; + +export const OfflineNarrow = (): JSX.Element => ( + + + +); + +OfflineNarrow.story = { + name: 'Offline Narrow', +}; diff --git a/ts/components/DialogRelink.stories.tsx b/ts/components/DialogRelink.stories.tsx index a9d7a5e33..550f98eb8 100644 --- a/ts/components/DialogRelink.stories.tsx +++ b/ts/components/DialogRelink.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { boolean } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -38,23 +37,31 @@ const permutations = [ }, ]; -storiesOf('Components/DialogRelink', module) - .add('Knobs Playground', () => { - const isRegistrationDone = boolean('isRegistrationDone', false); +export default { + title: 'Components/DialogRelink', +}; - return ( - - ); - }) - .add('Iterations', () => { - return permutations.map(({ props, title }) => ( - <> -

{title}

- - - - - )); - }); +export const KnobsPlayground = (): JSX.Element => { + const isRegistrationDone = boolean('isRegistrationDone', false); + + return ( + + ); +}; + +export const Iterations = (): JSX.Element => { + return ( + <> + {permutations.map(({ props, title }) => ( + <> +

{title}

+ + + + + ))} + + ); +}; diff --git a/ts/components/DialogUpdate.stories.tsx b/ts/components/DialogUpdate.stories.tsx index 9c98a65ee..318f8b00d 100644 --- a/ts/components/DialogUpdate.stories.tsx +++ b/ts/components/DialogUpdate.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { boolean, select } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; import { DialogUpdate } from './DialogUpdate'; @@ -29,9 +28,11 @@ const defaultProps = { version: 'v7.7.7', }; -const story = storiesOf('Components/DialogUpdate', module); +export default { + title: 'Components/DialogUpdate', +}; -story.add('Knobs Playground', () => { +export const KnobsPlayground = (): JSX.Element => { const containerWidthBreakpoint = select( 'containerWidthBreakpoint', WidthBreakpoint, @@ -53,108 +54,278 @@ story.add('Knobs Playground', () => { />
); -}); +}; -( - [ - ['wide', WidthBreakpoint.Wide], - ['narrow', WidthBreakpoint.Narrow], - ] as const -).forEach(([name, containerWidthBreakpoint]) => { - const defaultPropsForBreakpoint = { - ...defaultProps, - containerWidthBreakpoint, - }; +export const UpdateWide = (): JSX.Element => ( + + + +); - story.add(`Update (${name} container)`, () => ( - - - - )); +UpdateWide.story = { + name: 'Update (Wide)', +}; - story.add(`Download Ready (${name} container)`, () => ( - - - - )); +export const DownloadReadyWide = (): JSX.Element => ( + + + +); - story.add(`Full Download Ready (${name} container)`, () => ( - - - - )); +DownloadReadyWide.story = { + name: 'DownloadReady (Wide)', +}; - story.add(`Downloading (${name} container)`, () => ( - - - - )); +export const FullDownloadReadyWide = (): JSX.Element => ( + + + +); - story.add(`Cannot Update (${name} container)`, () => ( - - - - )); +FullDownloadReadyWide.story = { + name: 'FullDownloadReady (Wide)', +}; - story.add(`Cannot Update Beta (${name} container)`, () => ( - - - - )); +export const DownloadingWide = (): JSX.Element => ( + + + +); - story.add(`Cannot Update & Require Manual (${name} container)`, () => ( - - - - )); +DownloadingWide.story = { + name: 'Downloading (Wide)', +}; - story.add(`Cannot Update & Require Manual Beta (${name} container)`, () => ( - - - - )); +export const CannotUpdateWide = (): JSX.Element => ( + + + +); - story.add(`macOS RO Error (${name} container)`, () => ( - - - - )); -}); +CannotUpdateWide.story = { + name: 'Cannot_Update (Wide)', +}; + +export const CannotUpdateBetaWide = (): JSX.Element => ( + + + +); + +CannotUpdateBetaWide.story = { + name: 'Cannot_Update_Beta (Wide)', +}; + +export const CannotUpdateRequireManualWide = (): JSX.Element => ( + + + +); + +CannotUpdateRequireManualWide.story = { + name: 'Cannot_Update_Require_Manual (Wide)', +}; + +export const CannotUpdateRequireManualBetaWide = (): JSX.Element => ( + + + +); + +CannotUpdateRequireManualBetaWide.story = { + name: 'Cannot_Update_Require_Manual_Beta (Wide)', +}; + +export const MacOSReadOnlyWide = (): JSX.Element => ( + + + +); + +MacOSReadOnlyWide.story = { + name: 'MacOS_Read_Only (Wide)', +}; + +export const UpdateNarrow = (): JSX.Element => ( + + + +); + +UpdateNarrow.story = { + name: 'Update (Narrow)', +}; + +export const DownloadReadyNarrow = (): JSX.Element => ( + + + +); + +DownloadReadyNarrow.story = { + name: 'DownloadReady (Narrow)', +}; + +export const FullDownloadReadyNarrow = (): JSX.Element => ( + + + +); + +FullDownloadReadyNarrow.story = { + name: 'FullDownloadReady (Narrow)', +}; + +export const DownloadingNarrow = (): JSX.Element => ( + + + +); + +DownloadingNarrow.story = { + name: 'Downloading (Narrow)', +}; + +export const CannotUpdateNarrow = (): JSX.Element => ( + + + +); + +CannotUpdateNarrow.story = { + name: 'Cannot Update (Narrow)', +}; + +export const CannotUpdateBetaNarrow = (): JSX.Element => ( + + + +); + +CannotUpdateBetaNarrow.story = { + name: 'Cannot Update Beta (Narrow)', +}; + +export const CannotUpdateRequireManualNarrow = (): JSX.Element => ( + + + +); + +CannotUpdateRequireManualNarrow.story = { + name: 'Cannot_Update_Require_Manual (Narrow)', +}; + +export const CannotUpdateRequireManualBetaNarrow = (): JSX.Element => ( + + + +); + +CannotUpdateRequireManualBetaNarrow.story = { + name: 'Cannot_Update_Require_Manual_Beta (Narrow)', +}; + +export const MacOSReadOnlyNarrow = (): JSX.Element => ( + + + +); + +MacOSReadOnlyNarrow.story = { + name: 'MacOS_Read_Only (Narrow)', +}; diff --git a/ts/components/DisappearingTimeDialog.stories.tsx b/ts/components/DisappearingTimeDialog.stories.tsx index a3347eea7..965bc9253 100644 --- a/ts/components/DisappearingTimeDialog.stories.tsx +++ b/ts/components/DisappearingTimeDialog.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import { DisappearingTimeDialog } from './DisappearingTimeDialog'; import { setupI18n } from '../util/setupI18n'; @@ -11,19 +10,53 @@ import enMessages from '../../_locales/en/messages.json'; import { EXPIRE_TIMERS } from '../test-both/util/expireTimers'; -const story = storiesOf('Components/DisappearingTimeDialog', module); +export default { + title: 'Components/DisappearingTimeDialog', +}; const i18n = setupI18n('en', enMessages); -EXPIRE_TIMERS.forEach(({ value, label }) => { - story.add(`Initial value: ${label}`, () => { - return ( - - ); - }); -}); +export const Seconds = (): JSX.Element => ( + +); + +export const Minutes = (): JSX.Element => ( + +); + +export const Hours = (): JSX.Element => ( + +); + +export const Days = (): JSX.Element => ( + +); + +export const Weeks = (): JSX.Element => ( + +); diff --git a/ts/components/DisappearingTimerSelect.stories.tsx b/ts/components/DisappearingTimerSelect.stories.tsx index e2f498966..04d681c8f 100644 --- a/ts/components/DisappearingTimerSelect.stories.tsx +++ b/ts/components/DisappearingTimerSelect.stories.tsx @@ -2,13 +2,14 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useState } from 'react'; -import { storiesOf } from '@storybook/react'; import { DisappearingTimerSelect } from './DisappearingTimerSelect'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; -const story = storiesOf('Components/DisappearingTimerSelect', module); +export default { + title: 'Components/DisappearingTimerSelect', +}; const i18n = setupI18n('en', enMessages); @@ -28,10 +29,18 @@ const TimerSelectWrap: React.FC = ({ initialValue }) => { ); }; -story.add('Initial value: 1 day', () => ( +export const InitialValue1Day = (): JSX.Element => ( -)); +); -story.add('Initial value 3 days (Custom time)', () => ( +InitialValue1Day.story = { + name: 'Initial value: 1 day', +}; + +export const InitialValue3DaysCustomTime = (): JSX.Element => ( -)); +); + +InitialValue3DaysCustomTime.story = { + name: 'Initial value 3 days (Custom time)', +}; diff --git a/ts/components/ErrorModal.stories.tsx b/ts/components/ErrorModal.stories.tsx index 63aaf943b..a0a9f5611 100644 --- a/ts/components/ErrorModal.stories.tsx +++ b/ts/components/ErrorModal.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -22,11 +21,15 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onClose: action('onClick'), }); -storiesOf('Components/ErrorModal', module).add('Normal', () => { - return ; -}); +export default { + title: 'Components/ErrorModal', +}; -storiesOf('Components/ErrorModal', module).add('Custom Strings', () => { +export const Normal = (): JSX.Element => { + return ; +}; + +export const CustomStrings = (): JSX.Element => { return ( { })} /> ); -}); +}; diff --git a/ts/components/ForwardMessageModal.stories.tsx b/ts/components/ForwardMessageModal.stories.tsx index 05df2a187..85dbadd20 100644 --- a/ts/components/ForwardMessageModal.stories.tsx +++ b/ts/components/ForwardMessageModal.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { text } from '@storybook/addon-knobs'; @@ -30,7 +29,9 @@ const createAttachment = ( size: 3433, }); -const story = storiesOf('Components/ForwardMessageModal', module); +export default { + title: 'Components/ForwardMessageModal', +}; const i18n = setupI18n('en', enMessages); @@ -64,23 +65,35 @@ const useProps = (overrideProps: Partial = {}): PropsType => ({ regionCode: 'US', }); -story.add('Modal', () => { +export const Modal = (): JSX.Element => { return ; -}); +}; -story.add('with text', () => { +export const WithText = (): JSX.Element => { return ; -}); +}; -story.add('a sticker', () => { +WithText.story = { + name: 'with text', +}; + +export const ASticker = (): JSX.Element => { return ; -}); +}; -story.add('with a contact', () => { +ASticker.story = { + name: 'a sticker', +}; + +export const WithAContact = (): JSX.Element => { return ; -}); +}; -story.add('link preview', () => { +WithAContact.story = { + name: 'with a contact', +}; + +export const LinkPreview = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('media attachments', () => { +LinkPreview.story = { + name: 'link preview', +}; + +export const MediaAttachments = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('announcement only groups non-admin', () => ( +MediaAttachments.story = { + name: 'media attachments', +}; + +export const AnnouncementOnlyGroupsNonAdmin = (): JSX.Element => ( ( }), ]} /> -)); +); + +AnnouncementOnlyGroupsNonAdmin.story = { + name: 'announcement only groups non-admin', +}; diff --git a/ts/components/GroupCallOverflowArea.stories.tsx b/ts/components/GroupCallOverflowArea.stories.tsx index 68a2184ed..422f90b7e 100644 --- a/ts/components/GroupCallOverflowArea.stories.tsx +++ b/ts/components/GroupCallOverflowArea.stories.tsx @@ -4,7 +4,6 @@ import type { FC } from 'react'; import React from 'react'; import { memoize, times } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { number } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -32,7 +31,9 @@ const allRemoteParticipants = times(MAX_PARTICIPANTS).map(index => ({ }), })); -const story = storiesOf('Components/GroupCallOverflowArea', module); +export default { + title: 'Components/GroupCallOverflowArea', +}; const defaultProps = { getFrameBuffer: memoize(() => Buffer.alloc(FRAME_BUFFER_SIZE)), @@ -55,31 +56,43 @@ const Container: FC = ({ children }) => ( ); -story.add('No overflowed participants', () => ( +export const NoOverflowedParticipants = (): JSX.Element => ( -)); +); -story.add('One overflowed participant', () => ( +NoOverflowedParticipants.story = { + name: 'No overflowed participants', +}; + +export const OneOverflowedParticipant = (): JSX.Element => ( -)); +); -story.add('Three overflowed participants', () => ( +OneOverflowedParticipant.story = { + name: 'One overflowed participant', +}; + +export const ThreeOverflowedParticipants = (): JSX.Element => ( -)); +); -story.add('Many overflowed participants', () => ( +ThreeOverflowedParticipants.story = { + name: 'Three overflowed participants', +}; + +export const ManyOverflowedParticipants = (): JSX.Element => ( ( )} /> -)); +); + +ManyOverflowedParticipants.story = { + name: 'Many overflowed participants', +}; diff --git a/ts/components/GroupCallRemoteParticipant.stories.tsx b/ts/components/GroupCallRemoteParticipant.stories.tsx index b24dd142c..082ead69a 100644 --- a/ts/components/GroupCallRemoteParticipant.stories.tsx +++ b/ts/components/GroupCallRemoteParticipant.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { memoize, noop } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { select } from '@storybook/addon-knobs'; import type { PropsType } from './GroupCallRemoteParticipant'; @@ -64,9 +63,11 @@ const createProps = ( ...overrideProps, }); -const story = storiesOf('Components/GroupCallRemoteParticipant', module); +export default { + title: 'Components/GroupCallRemoteParticipant', +}; -story.add('Default', () => ( +export const Default = (): JSX.Element => ( ( width: 120, })} /> -)); +); -story.add('Speaking', () => ( +export const Speaking = (): JSX.Element => ( ( { hasRemoteAudio: true } )} /> -)); +); -story.add('isInPip', () => ( +export const IsInPip = (): JSX.Element => ( -)); +); -story.add('Blocked', () => ( +IsInPip.story = { + name: 'isInPip', +}; + +export const Blocked = (): JSX.Element => ( ( { isBlocked: true } )} /> -)); +); diff --git a/ts/components/GroupDescriptionInput.stories.tsx b/ts/components/GroupDescriptionInput.stories.tsx index 99fea4dfd..85cc3f969 100644 --- a/ts/components/GroupDescriptionInput.stories.tsx +++ b/ts/components/GroupDescriptionInput.stories.tsx @@ -3,8 +3,6 @@ import React, { useState } from 'react'; -import { storiesOf } from '@storybook/react'; - import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -12,7 +10,9 @@ import { GroupDescriptionInput } from './GroupDescriptionInput'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/GroupDescriptionInput', module); +export default { + title: 'Components/GroupDescriptionInput', +}; const Wrapper = ({ disabled, @@ -33,12 +33,12 @@ const Wrapper = ({ ); }; -story.add('Default', () => ); +export const Default = (): JSX.Element => ; -story.add('Disabled', () => ( +export const Disabled = (): JSX.Element => ( <>
-)); +); diff --git a/ts/components/GroupTitleInput.stories.tsx b/ts/components/GroupTitleInput.stories.tsx index 9be2b5572..d0ed4b6f4 100644 --- a/ts/components/GroupTitleInput.stories.tsx +++ b/ts/components/GroupTitleInput.stories.tsx @@ -3,8 +3,6 @@ import React, { useState } from 'react'; -import { storiesOf } from '@storybook/react'; - import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; @@ -12,7 +10,9 @@ import { GroupTitleInput } from './GroupTitleInput'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/GroupTitleInput', module); +export default { + title: 'Components/GroupTitleInput', +}; const Wrapper = ({ disabled, @@ -33,12 +33,12 @@ const Wrapper = ({ ); }; -story.add('Default', () => ); +export const Default = (): JSX.Element => ; -story.add('Disabled', () => ( +export const Disabled = (): JSX.Element => ( <>
-)); +); diff --git a/ts/components/GroupV1MigrationDialog.stories.tsx b/ts/components/GroupV1MigrationDialog.stories.tsx index d9295305b..e34a0c2f4 100644 --- a/ts/components/GroupV1MigrationDialog.stories.tsx +++ b/ts/components/GroupV1MigrationDialog.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { isBoolean } from 'lodash'; import { boolean } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -57,13 +56,19 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ theme: ThemeType.light, }); -const stories = storiesOf('Components/GroupV1MigrationDialog', module); +export default { + title: 'Components/GroupV1MigrationDialog', +}; -stories.add('Not yet migrated, basic', () => { +export const NotYetMigratedBasic = (): JSX.Element => { return ; -}); +}; -stories.add('Migrated, basic', () => { +NotYetMigratedBasic.story = { + name: 'Not yet migrated, basic', +}; + +export const MigratedBasic = (): JSX.Element => { return ( { })} /> ); -}); +}; -stories.add('Migrated, you are invited', () => { +MigratedBasic.story = { + name: 'Migrated, basic', +}; + +export const MigratedYouAreInvited = (): JSX.Element => { return ( { })} /> ); -}); +}; -stories.add('Not yet migrated, multiple dropped and invited members', () => { - return ( - - ); -}); +MigratedYouAreInvited.story = { + name: 'Migrated, you are invited', +}; -stories.add('Not yet migrated, no members', () => { +export const NotYetMigratedMultipleDroppedAndInvitedMembers = + (): JSX.Element => { + return ( + + ); + }; + +NotYetMigratedMultipleDroppedAndInvitedMembers.story = { + name: 'Not yet migrated, multiple dropped and invited members', +}; + +export const NotYetMigratedNoMembers = (): JSX.Element => { return ( { })} /> ); -}); +}; -stories.add('Not yet migrated, just dropped member', () => { +NotYetMigratedNoMembers.story = { + name: 'Not yet migrated, no members', +}; + +export const NotYetMigratedJustDroppedMember = (): JSX.Element => { return ( { })} /> ); -}); +}; + +NotYetMigratedJustDroppedMember.story = { + name: 'Not yet migrated, just dropped member', +}; diff --git a/ts/components/GroupV2JoinDialog.stories.tsx b/ts/components/GroupV2JoinDialog.stories.tsx index 97c6ab319..5817056b6 100644 --- a/ts/components/GroupV2JoinDialog.stories.tsx +++ b/ts/components/GroupV2JoinDialog.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { boolean, number, text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -27,13 +26,15 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ i18n, }); -const stories = storiesOf('Components/GroupV2JoinDialog', module); +export default { + title: 'Components/GroupV2JoinDialog', +}; -stories.add('Basic', () => { +export const Basic = (): JSX.Element => { return ; -}); +}; -stories.add('Approval required', () => { +export const ApprovalRequired = (): JSX.Element => { return ( { })} /> ); -}); +}; -stories.add('With avatar', () => { +ApprovalRequired.story = { + name: 'Approval required', +}; + +export const WithAvatar = (): JSX.Element => { return ( { })} /> ); -}); +}; -stories.add('With one member', () => { +WithAvatar.story = { + name: 'With avatar', +}; + +export const WithOneMember = (): JSX.Element => { return ( { })} /> ); -}); +}; -stories.add('Avatar loading state', () => { +WithOneMember.story = { + name: 'With one member', +}; + +export const AvatarLoadingState = (): JSX.Element => { return ( { })} /> ); -}); +}; -stories.add('Full', () => { +AvatarLoadingState.story = { + name: 'Avatar loading state', +}; + +export const Full = (): JSX.Element => { return ( { })} /> ); -}); +}; diff --git a/ts/components/IdenticonSVG.stories.tsx b/ts/components/IdenticonSVG.stories.tsx index 6b9ec82d6..61cf0bcb2 100644 --- a/ts/components/IdenticonSVG.stories.tsx +++ b/ts/components/IdenticonSVG.stories.tsx @@ -3,19 +3,25 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; - import { IdenticonSVG } from './IdenticonSVG'; import { AvatarColorMap } from '../types/Colors'; -const story = storiesOf('Components/IdenticonSVG', module); +export default { + title: 'Components/IdenticonSVG', +}; -AvatarColorMap.forEach((value, key) => - story.add(key, () => ( - - )) -); +export const AllColors = (): JSX.Element => { + const stories: Array = []; + + AvatarColorMap.forEach(value => + stories.push( + + ) + ); + + return <>{stories}; +}; diff --git a/ts/components/InContactsIcon.stories.tsx b/ts/components/InContactsIcon.stories.tsx index d43a68f2f..bfe5bc28c 100644 --- a/ts/components/InContactsIcon.stories.tsx +++ b/ts/components/InContactsIcon.stories.tsx @@ -3,14 +3,16 @@ import * as React from 'react'; -import { storiesOf } from '@storybook/react'; - import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; import { InContactsIcon } from './InContactsIcon'; const i18n = setupI18n('en', enMessages); -storiesOf('Components/InContactsIcon', module).add('Default', () => { +export default { + title: 'Components/InContactsIcon', +}; + +export const Default = (): JSX.Element => { return ; -}); +}; diff --git a/ts/components/IncomingCallBar.stories.tsx b/ts/components/IncomingCallBar.stories.tsx index fb8ea49c7..13808d688 100644 --- a/ts/components/IncomingCallBar.stories.tsx +++ b/ts/components/IncomingCallBar.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { IncomingCallBar } from './IncomingCallBar'; @@ -52,77 +51,114 @@ const groupConversation = getDefaultConversation({ type: 'group', }); -storiesOf('Components/IncomingCallBar', module) - .add('Incoming direct call (video)', () => ( - - )) - .add('Incoming direct call (audio)', () => ( - - )) - .add('Incoming group call (only calling you)', () => ( - - )) - .add('Incoming group call (calling you and 1 other)', () => ( - - )) - .add('Incoming group call (calling you and 2 others)', () => ( - - )) - .add('Incoming group call (calling you and 3 others)', () => ( - - )) - .add('Incoming group call (calling you and 4 others)', () => ( - - )); +export default { + title: 'Components/IncomingCallBar', +}; + +export const IncomingDirectCallVideo = (): JSX.Element => ( + +); + +IncomingDirectCallVideo.story = { + name: 'Incoming direct call (video)', +}; + +export const IncomingDirectCallAudio = (): JSX.Element => ( + +); + +IncomingDirectCallAudio.story = { + name: 'Incoming direct call (audio)', +}; + +export const IncomingGroupCallOnlyCallingYou = (): JSX.Element => ( + +); + +IncomingGroupCallOnlyCallingYou.story = { + name: 'Incoming group call (only calling you)', +}; + +export const IncomingGroupCallCallingYouAnd1Other = (): JSX.Element => ( + +); + +IncomingGroupCallCallingYouAnd1Other.story = { + name: 'Incoming group call (calling you and 1 other)', +}; + +export const IncomingGroupCallCallingYouAnd2Others = (): JSX.Element => ( + +); + +IncomingGroupCallCallingYouAnd2Others.story = { + name: 'Incoming group call (calling you and 2 others)', +}; + +export const IncomingGroupCallCallingYouAnd3Others = (): JSX.Element => ( + +); + +IncomingGroupCallCallingYouAnd3Others.story = { + name: 'Incoming group call (calling you and 3 others)', +}; + +export const IncomingGroupCallCallingYouAnd4Others = (): JSX.Element => ( + +); + +IncomingGroupCallCallingYouAnd4Others.story = { + name: 'Incoming group call (calling you and 4 others)', +}; diff --git a/ts/components/Input.stories.tsx b/ts/components/Input.stories.tsx index ab15b630f..6dd02e870 100644 --- a/ts/components/Input.stories.tsx +++ b/ts/components/Input.stories.tsx @@ -3,7 +3,6 @@ import React, { useState } from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -14,7 +13,9 @@ import enMessages from '../../_locales/en/messages.json'; const i18n = setupI18n('en', enMessages); -const stories = storiesOf('Components/Input', module); +export default { + title: 'Components/Input', +}; const createProps = (overrideProps: Partial = {}): PropsType => ({ disabled: Boolean(overrideProps.disabled), @@ -40,42 +41,58 @@ function Controller(props: PropsType): JSX.Element { return ; } -stories.add('Simple', () => ); +export const Simple = (): JSX.Element => ; -stories.add('hasClearButton', () => ( +export const HasClearButton = (): JSX.Element => ( -)); +); -stories.add('character count', () => ( +HasClearButton.story = { + name: 'hasClearButton', +}; + +export const CharacterCount = (): JSX.Element => ( -)); +); -stories.add('character count (customizable show)', () => ( +CharacterCount.story = { + name: 'character count', +}; + +export const CharacterCountCustomizableShow = (): JSX.Element => ( -)); +); -stories.add('expandable', () => ( +CharacterCountCustomizableShow.story = { + name: 'character count (customizable show)', +}; + +export const Expandable = (): JSX.Element => ( -)); +); -stories.add('expandable w/count', () => ( +Expandable.story = { + name: 'expandable', +}; + +export const ExpandableWCount = (): JSX.Element => ( ( whenToShowRemainingCount: 0, })} /> -)); +); -stories.add('disabled', () => ( +ExpandableWCount.story = { + name: 'expandable w/count', +}; + +export const Disabled = (): JSX.Element => ( -)); +); -stories.add('spellcheck disabled', () => ( +Disabled.story = { + name: 'disabled', +}; + +export const SpellcheckDisabled = (): JSX.Element => ( -)); +); + +SpellcheckDisabled.story = { + name: 'spellcheck disabled', +}; diff --git a/ts/components/Intl.stories.tsx b/ts/components/Intl.stories.tsx index b6fd43fb7..ff57e7e06 100644 --- a/ts/components/Intl.stories.tsx +++ b/ts/components/Intl.stories.tsx @@ -1,89 +1,75 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import type { Meta, Story } from '@storybook/react'; import * as React from 'react'; -import { text } from '@storybook/addon-knobs'; -import { storiesOf } from '@storybook/react'; - import type { Props } from './Intl'; import { Intl } from './Intl'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/Intl', module); + +export default { + title: 'Components/Intl', + component: Intl, +} as Meta; const createProps = (overrideProps: Partial = {}): Props => ({ i18n, - id: text('id', overrideProps.id || 'deleteAndRestart'), + id: overrideProps.id || '', components: overrideProps.components, renderText: overrideProps.renderText, }); -story.add('No Replacements', () => { - const props = createProps({ - id: 'deleteAndRestart', - }); +const Template: Story = args => ; - return ; +export const NoReplacements = Template.bind({}); +NoReplacements.args = createProps({ + id: 'deleteAndRestart', }); -story.add('Single String Replacement', () => { - const props = createProps({ - id: 'leftTheGroup', - components: ['Theodora'], - }); - - return ; +export const SingleStringReplacement = Template.bind({}); +SingleStringReplacement.args = createProps({ + id: 'leftTheGroup', + components: ['Theodora'], }); -story.add('Single Tag Replacement', () => { - const props = createProps({ - id: 'leftTheGroup', - components: [ - , - ], - }); - - return ; +export const SingleTagReplacement = Template.bind({}); +SingleTagReplacement.args = createProps({ + id: 'leftTheGroup', + components: [ + , + ], }); -story.add('Multiple String Replacement', () => { - const props = createProps({ - id: 'changedRightAfterVerify', - components: { - name1: 'Fred', - name2: 'The Fredster', - }, - }); - - return ; +export const MultipleStringReplacement = Template.bind({}); +MultipleStringReplacement.args = createProps({ + id: 'changedRightAfterVerify', + components: { + name1: 'Fred', + name2: 'The Fredster', + }, }); -story.add('Multiple Tag Replacement', () => { - const props = createProps({ - id: 'changedRightAfterVerify', - components: { - name1: Fred, - name2: The Fredster, - }, - }); - - return ; +export const MultipleTagReplacement = Template.bind({}); +MultipleTagReplacement.args = createProps({ + id: 'changedRightAfterVerify', + components: { + name1: Fred, + name2: The Fredster, + }, }); -story.add('Custom Render', () => { - const props = createProps({ - id: 'deleteAndRestart', - renderText: ({ text: theText, key }) => ( -
- {theText} -
- ), - }); - - return ; +export const CustomRender = Template.bind({}); +CustomRender.args = createProps({ + id: 'deleteAndRestart', + renderText: ({ text: theText, key }) => ( +
+ {theText} +
+ ), }); diff --git a/ts/components/LeftPane.stories.tsx b/ts/components/LeftPane.stories.tsx index 62dd90c2e..54a20b531 100644 --- a/ts/components/LeftPane.stories.tsx +++ b/ts/components/LeftPane.stories.tsx @@ -5,7 +5,6 @@ import * as React from 'react'; import { action } from '@storybook/addon-actions'; import { select } from '@storybook/addon-knobs'; -import { storiesOf } from '@storybook/react'; import type { PropsType } from './LeftPane'; import { LeftPane, LeftPaneMode } from './LeftPane'; @@ -25,7 +24,9 @@ import { const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/LeftPane', module); +export default { + title: 'Components/LeftPane', +}; const defaultConversations: Array = [ getDefaultConversation({ @@ -200,9 +201,7 @@ const useProps = (overrideProps: Partial = {}): PropsType => { }; }; -// Inbox stories - -story.add('Inbox: no conversations', () => ( +export const InboxNoConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Inbox: only pinned conversations', () => ( +InboxNoConversations.story = { + name: 'Inbox: no conversations', +}; + +export const InboxOnlyPinnedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Inbox: only non-pinned conversations', () => ( +InboxOnlyPinnedConversations.story = { + name: 'Inbox: only pinned conversations', +}; + +export const InboxOnlyNonPinnedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Inbox: only archived conversations', () => ( +InboxOnlyNonPinnedConversations.story = { + name: 'Inbox: only non-pinned conversations', +}; + +export const InboxOnlyArchivedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Inbox: pinned and archived conversations', () => ( +InboxOnlyArchivedConversations.story = { + name: 'Inbox: only archived conversations', +}; + +export const InboxPinnedAndArchivedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Inbox: non-pinned and archived conversations', () => ( +InboxPinnedAndArchivedConversations.story = { + name: 'Inbox: pinned and archived conversations', +}; + +export const InboxNonPinnedAndArchivedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Inbox: pinned and non-pinned conversations', () => ( +InboxNonPinnedAndArchivedConversations.story = { + name: 'Inbox: non-pinned and archived conversations', +}; + +export const InboxPinnedAndNonPinnedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Inbox: pinned, non-pinned, and archived conversations', () => ( +InboxPinnedAndNonPinnedConversations.story = { + name: 'Inbox: pinned and non-pinned conversations', +}; + +export const InboxPinnedNonPinnedAndArchivedConversations = (): JSX.Element => ( -)); +); -// Search stories +InboxPinnedNonPinnedAndArchivedConversations.story = { + name: 'Inbox: pinned, non-pinned, and archived conversations', +}; -story.add('Search: no results when searching everywhere', () => ( +export const SearchNoResultsWhenSearchingEverywhere = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Search: no results when searching everywhere (SMS)', () => ( +SearchNoResultsWhenSearchingEverywhere.story = { + name: 'Search: no results when searching everywhere', +}; + +export const SearchNoResultsWhenSearchingEverywhereSms = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Search: no results when searching in a conversation', () => ( +SearchNoResultsWhenSearchingEverywhereSms.story = { + name: 'Search: no results when searching everywhere (SMS)', +}; + +export const SearchNoResultsWhenSearchingInAConversation = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Search: all results loading', () => ( +SearchNoResultsWhenSearchingInAConversation.story = { + name: 'Search: no results when searching in a conversation', +}; + +export const SearchAllResultsLoading = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Search: some results loading', () => ( +SearchAllResultsLoading.story = { + name: 'Search: all results loading', +}; + +export const SearchSomeResultsLoading = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Search: has conversations and contacts, but not messages', () => ( - ( + -)); + })} + /> + ); -story.add('Search: all results', () => ( +SearchHasConversationsAndContactsButNotMessages.story = { + name: 'Search: has conversations and contacts, but not messages', +}; + +export const SearchAllResults = (): JSX.Element => ( ( }, })} /> -)); +); -// Archived stories +SearchAllResults.story = { + name: 'Search: all results', +}; -story.add('Archive: no archived conversations', () => ( +export const ArchiveNoArchivedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Archive: archived conversations', () => ( +ArchiveNoArchivedConversations.story = { + name: 'Archive: no archived conversations', +}; + +export const ArchiveArchivedConversations = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Archive: searching a conversation', () => ( +ArchiveArchivedConversations.story = { + name: 'Archive: archived conversations', +}; + +export const ArchiveSearchingAConversation = (): JSX.Element => ( ( }, })} /> -)); +); -// Compose stories +ArchiveSearchingAConversation.story = { + name: 'Archive: searching a conversation', +}; -story.add('Compose: no results', () => ( +export const ComposeNoResults = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: some contacts, no search term', () => ( +ComposeNoResults.story = { + name: 'Compose: no results', +}; + +export const ComposeSomeContactsNoSearchTerm = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: some contacts, with a search term', () => ( +ComposeSomeContactsNoSearchTerm.story = { + name: 'Compose: some contacts, no search term', +}; + +export const ComposeSomeContactsWithASearchTerm = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: some groups, no search term', () => ( +ComposeSomeContactsWithASearchTerm.story = { + name: 'Compose: some contacts, with a search term', +}; + +export const ComposeSomeGroupsNoSearchTerm = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: some groups, with search term', () => ( +ComposeSomeGroupsNoSearchTerm.story = { + name: 'Compose: some groups, no search term', +}; + +export const ComposeSomeGroupsWithSearchTerm = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: search is valid username', () => ( +ComposeSomeGroupsWithSearchTerm.story = { + name: 'Compose: some groups, with search term', +}; + +export const ComposeSearchIsValidUsername = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: search is valid username, fetching username', () => ( +ComposeSearchIsValidUsername.story = { + name: 'Compose: search is valid username', +}; + +export const ComposeSearchIsValidUsernameFetchingUsername = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: search is valid username, but flag is not enabled', () => ( - -)); +ComposeSearchIsValidUsernameFetchingUsername.story = { + name: 'Compose: search is valid username, fetching username', +}; -story.add('Compose: search is partial phone number', () => ( +export const ComposeSearchIsValidUsernameButFlagIsNotEnabled = + (): JSX.Element => ( + + ); + +ComposeSearchIsValidUsernameButFlagIsNotEnabled.story = { + name: 'Compose: search is valid username, but flag is not enabled', +}; + +export const ComposeSearchIsPartialPhoneNumber = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: search is valid phone number', () => ( +ComposeSearchIsPartialPhoneNumber.story = { + name: 'Compose: search is partial phone number', +}; + +export const ComposeSearchIsValidPhoneNumber = (): JSX.Element => ( ( }, })} /> -)); +); -story.add( - 'Compose: search is valid phone number, fetching phone number', - () => ( +ComposeSearchIsValidPhoneNumber.story = { + name: 'Compose: search is valid phone number', +}; + +export const ComposeSearchIsValidPhoneNumberFetchingPhoneNumber = + (): JSX.Element => ( - ) -); + ); -story.add('Compose: all kinds of results, no search term', () => ( +ComposeSearchIsValidPhoneNumberFetchingPhoneNumber.story = { + name: 'Compose: search is valid phone number, fetching phone number', +}; + +export const ComposeAllKindsOfResultsNoSearchTerm = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Compose: all kinds of results, with a search term', () => ( +ComposeAllKindsOfResultsNoSearchTerm.story = { + name: 'Compose: all kinds of results, no search term', +}; + +export const ComposeAllKindsOfResultsWithASearchTerm = (): JSX.Element => ( ( }, })} /> -)); +); -// Captcha flow +ComposeAllKindsOfResultsWithASearchTerm.story = { + name: 'Compose: all kinds of results, with a search term', +}; -story.add('Captcha dialog: required', () => ( +export const CaptchaDialogRequired = (): JSX.Element => ( ( challengeStatus: 'required', })} /> -)); +); -story.add('Captcha dialog: pending', () => ( +CaptchaDialogRequired.story = { + name: 'Captcha dialog: required', +}; + +export const CaptchaDialogPending = (): JSX.Element => ( ( challengeStatus: 'pending', })} /> -)); +); -// Crash report flow +CaptchaDialogPending.story = { + name: 'Captcha dialog: pending', +}; -story.add('Crash report dialog', () => ( +export const _CrashReportDialog = (): JSX.Element => ( ( crashReportCount: 42, })} /> -)); +); -// Choose Group Members +_CrashReportDialog.story = { + name: 'Crash report dialog', +}; -story.add('Choose Group Members: Partial phone number', () => ( +export const ChooseGroupMembersPartialPhoneNumber = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Choose Group Members: Valid phone number', () => ( +ChooseGroupMembersPartialPhoneNumber.story = { + name: 'Choose Group Members: Partial phone number', +}; + +export const ChooseGroupMembersValidPhoneNumber = (): JSX.Element => ( ( }, })} /> -)); +); -// Set group metadata +ChooseGroupMembersValidPhoneNumber.story = { + name: 'Choose Group Members: Valid phone number', +}; -story.add('Group Metadata: No Timer', () => ( +export const GroupMetadataNoTimer = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Group Metadata: Regular Timer', () => ( +GroupMetadataNoTimer.story = { + name: 'Group Metadata: No Timer', +}; + +export const GroupMetadataRegularTimer = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Group Metadata: Custom Timer', () => ( +GroupMetadataRegularTimer.story = { + name: 'Group Metadata: Regular Timer', +}; + +export const GroupMetadataCustomTimer = (): JSX.Element => ( ( }, })} /> -)); +); -story.add('Searching Conversation', () => ( +GroupMetadataCustomTimer.story = { + name: 'Group Metadata: Custom Timer', +}; + +export const SearchingConversation = (): JSX.Element => ( ( }, })} /> -)); +); diff --git a/ts/components/Lightbox.stories.tsx b/ts/components/Lightbox.stories.tsx index b506570bb..f99763722 100644 --- a/ts/components/Lightbox.stories.tsx +++ b/ts/components/Lightbox.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { number } from '@storybook/addon-knobs'; @@ -24,7 +23,9 @@ import { fakeAttachment } from '../test-both/helpers/fakeAttachment'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/Lightbox', module); +export default { + title: 'Components/Lightbox', +}; type OverridePropsMediaItemType = Partial & { caption?: string }; @@ -62,7 +63,7 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ selectedIndex: number('selectedIndex', overrideProps.selectedIndex || 0), }); -story.add('Multimedia', () => { +export const Multimedia = (): JSX.Element => { const props = createProps({ media: [ { @@ -119,9 +120,9 @@ story.add('Multimedia', () => { }); return ; -}); +}; -story.add('Missing Media', () => { +export const MissingMedia = (): JSX.Element => { const props = createProps({ media: [ { @@ -146,9 +147,9 @@ story.add('Missing Media', () => { }); return ; -}); +}; -story.add('Single Image', () => ( +export const SingleImage = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Image with Caption (normal image)', () => ( +export const ImageWithCaptionNormalImage = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Image with Caption (all-white image)', () => ( +ImageWithCaptionNormalImage.story = { + name: 'Image with Caption (normal image)', +}; + +export const ImageWithCaptionAllWhiteImage = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Single Video', () => ( +ImageWithCaptionAllWhiteImage.story = { + name: 'Image with Caption (all-white image)', +}; + +export const SingleVideo = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Single Video w/caption', () => ( +export const SingleVideoWCaption = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Unsupported Image Type', () => ( +SingleVideoWCaption.story = { + name: 'Single Video w/caption', +}; + +export const UnsupportedImageType = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Unsupported Video Type', () => ( +export const UnsupportedVideoType = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Unsupported Content', () => ( +export const UnsupportedContent = (): JSX.Element => ( ( ], })} /> -)); +); -story.add('Custom children', () => ( +export const CustomChildren = (): JSX.Element => (
( I am middle child
-)); +); -story.add('Forwarding', () => ( +CustomChildren.story = { + name: 'Custom children', +}; + +export const Forwarding = (): JSX.Element => ( -)); +); -story.add('Conversation Header', () => ( +export const ConversationHeader = (): JSX.Element => ( ({ @@ -296,9 +313,9 @@ story.add('Conversation Header', () => ( }), ]} /> -)); +); -story.add('View Once Video', () => ( +export const ViewOnceVideo = (): JSX.Element => ( ( })} isViewOnce /> -)); +); diff --git a/ts/components/MainHeader.stories.tsx b/ts/components/MainHeader.stories.tsx index 3795928ba..8a234a80f 100644 --- a/ts/components/MainHeader.stories.tsx +++ b/ts/components/MainHeader.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -14,7 +13,9 @@ import { ThemeType } from '../types/Util'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/MainHeader', module); +export default { + title: 'Components/MainHeader', +}; const requiredText = (name: string, value: string | undefined) => text(name, value || ''); @@ -41,36 +42,36 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ toggleStoriesView: action('toggleStoriesView'), }); -story.add('Basic', () => { +export const Basic = (): JSX.Element => { const props = createProps({}); return ; -}); +}; -story.add('Name', () => { +export const Name = (): JSX.Element => { const props = createProps({ name: 'John Smith', title: 'John Smith', }); return ; -}); +}; -story.add('Phone Number', () => { +export const PhoneNumber = (): JSX.Element => { const props = createProps({ name: 'John Smith', phoneNumber: '+15553004000', }); return ; -}); +}; -story.add('Update Available', () => { +export const UpdateAvailable = (): JSX.Element => { const props = createProps({ hasPendingUpdate: true }); return ; -}); +}; -story.add('Stories', () => ( +export const Stories = (): JSX.Element => ( -)); +); diff --git a/ts/components/MediaEditor.stories.tsx b/ts/components/MediaEditor.stories.tsx index 3f80759f3..e10fdd1ff 100644 --- a/ts/components/MediaEditor.stories.tsx +++ b/ts/components/MediaEditor.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import type { PropsType } from './MediaEditor'; @@ -13,7 +12,9 @@ import { Stickers, installedPacks } from '../test-both/helpers/getStickerPacks'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/MediaEditor', module); +export default { + title: 'Components/MediaEditor', +}; const IMAGE_1 = '/fixtures/nathan-anderson-316188-unsplash.jpg'; const IMAGE_2 = '/fixtures/tina-rolf-269345-unsplash.jpg'; @@ -31,16 +32,18 @@ const getDefaultProps = (): PropsType => ({ recentStickers: [Stickers.wide, Stickers.tall, Stickers.abe], }); -story.add('Extra Large', () => ); +export const ExtraLarge = (): JSX.Element => ( + +); -story.add('Large', () => ( +export const Large = (): JSX.Element => ( -)); +); -story.add('Smol', () => ( +export const Smol = (): JSX.Element => ( -)); +); -story.add('Portrait', () => ( +export const Portrait = (): JSX.Element => ( -)); +); diff --git a/ts/components/MediaQualitySelector.stories.tsx b/ts/components/MediaQualitySelector.stories.tsx index 66d275e48..93e773fa2 100644 --- a/ts/components/MediaQualitySelector.stories.tsx +++ b/ts/components/MediaQualitySelector.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { boolean } from '@storybook/addon-knobs'; @@ -12,7 +11,9 @@ import type { PropsType } from './MediaQualitySelector'; import { MediaQualitySelector } from './MediaQualitySelector'; import { setupI18n } from '../util/setupI18n'; -const story = storiesOf('Components/MediaQualitySelector', module); +export default { + title: 'Components/MediaQualitySelector', +}; const i18n = setupI18n('en', enMessages); @@ -22,14 +23,14 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onSelectQuality: action('onSelectQuality'), }); -story.add('Standard Quality', () => ( +export const StandardQuality = (): JSX.Element => ( -)); +); -story.add('High Quality', () => ( +export const HighQuality = (): JSX.Element => ( -)); +); diff --git a/ts/components/Modal.stories.tsx b/ts/components/Modal.stories.tsx index 8785d856a..ee9d28aa6 100644 --- a/ts/components/Modal.stories.tsx +++ b/ts/components/Modal.stories.tsx @@ -4,7 +4,6 @@ import React from 'react'; import { noop } from 'lodash'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { setupI18n } from '../util/setupI18n'; @@ -14,25 +13,37 @@ import { Modal } from './Modal'; const i18n = setupI18n('en', enMessages); -const story = storiesOf('Components/Modal', module); +export default { + title: 'Components/Modal', +}; const onClose = action('onClose'); const LOREM_IPSUM = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.'; -story.add('Bare bones, short', () => Hello world!); +export const BareBonesShort = (): JSX.Element => ( + Hello world! +); -story.add('Bare bones, long', () => ( +BareBonesShort.story = { + name: 'Bare bones, short', +}; + +export const BareBonesLong = (): JSX.Element => (

{LOREM_IPSUM}

{LOREM_IPSUM}

{LOREM_IPSUM}

{LOREM_IPSUM}

-)); +); -story.add('Bare bones, long, with button', () => ( +BareBonesLong.story = { + name: 'Bare bones, long', +}; + +export const BareBonesLongWithButton = (): JSX.Element => (

{LOREM_IPSUM}

{LOREM_IPSUM}

@@ -42,18 +53,26 @@ story.add('Bare bones, long, with button', () => (
-)); +); -story.add('Title, X button, body, and button footer', () => ( +BareBonesLongWithButton.story = { + name: 'Bare bones, long, with button', +}; + +export const TitleXButtonBodyAndButtonFooter = (): JSX.Element => ( {LOREM_IPSUM} -)); +); -story.add('Lots of buttons in the footer', () => ( +TitleXButtonBodyAndButtonFooter.story = { + name: 'Title, X button, body, and button footer', +}; + +export const LotsOfButtonsInTheFooter = (): JSX.Element => ( Hello world! @@ -70,18 +89,26 @@ story.add('Lots of buttons in the footer', () => ( -)); +); -story.add('Long body with title', () => ( +LotsOfButtonsInTheFooter.story = { + name: 'Lots of buttons in the footer', +}; + +export const LongBodyWithTitle = (): JSX.Element => (

{LOREM_IPSUM}

{LOREM_IPSUM}

{LOREM_IPSUM}

{LOREM_IPSUM}

-)); +); -story.add('Long body with title and button', () => ( +LongBodyWithTitle.story = { + name: 'Long body with title', +}; + +export const LongBodyWithTitleAndButton = (): JSX.Element => (

{LOREM_IPSUM}

{LOREM_IPSUM}

@@ -91,9 +118,13 @@ story.add('Long body with title and button', () => (
-)); +); -story.add('Long body with long title and X button', () => ( +LongBodyWithTitleAndButton.story = { + name: 'Long body with title and button', +}; + +export const LongBodyWithLongTitleAndXButton = (): JSX.Element => ( (

{LOREM_IPSUM}

{LOREM_IPSUM}

-)); +); -story.add('With sticky buttons long body', () => ( +LongBodyWithLongTitleAndXButton.story = { + name: 'Long body with long title and X button', +}; + +export const WithStickyButtonsLongBody = (): JSX.Element => (

{LOREM_IPSUM}

{LOREM_IPSUM}

@@ -118,9 +153,13 @@ story.add('With sticky buttons long body', () => (
-)); +); -story.add('With sticky buttons short body', () => ( +WithStickyButtonsLongBody.story = { + name: 'With sticky buttons long body', +}; + +export const WithStickyButtonsShortBody = (): JSX.Element => (

{LOREM_IPSUM.slice(0, 140)}

@@ -128,9 +167,13 @@ story.add('With sticky buttons short body', () => (
-)); +); -story.add('Sticky footer, Lots of buttons', () => ( +WithStickyButtonsShortBody.story = { + name: 'With sticky buttons short body', +}; + +export const StickyFooterLotsOfButtons = (): JSX.Element => (

{LOREM_IPSUM}

@@ -147,4 +190,8 @@ story.add('Sticky footer, Lots of buttons', () => (
-)); +); + +StickyFooterLotsOfButtons.story = { + name: 'Sticky footer, Lots of buttons', +}; diff --git a/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx b/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx index 88efc68b2..b83c1d364 100644 --- a/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx +++ b/ts/components/NewlyCreatedGroupInvitedContactsDialog.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; -import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { NewlyCreatedGroupInvitedContactsDialog } from './NewlyCreatedGroupInvitedContactsDialog'; @@ -20,12 +19,11 @@ const conversations: Array = [ getDefaultConversation({ title: 'Marc Barraca' }), ]; -const story = storiesOf( - 'Components/NewlyCreatedGroupInvitedContactsDialog', - module -); +export default { + title: 'Components/NewlyCreatedGroupInvitedContactsDialog', +}; -story.add('One contact', () => ( +export const OneContact = (): JSX.Element => ( undefined} @@ -33,9 +31,13 @@ story.add('One contact', () => ( onClose={action('onClose')} theme={ThemeType.light} /> -)); +); -story.add('Two contacts', () => ( +OneContact.story = { + name: 'One contact', +}; + +export const TwoContacts = (): JSX.Element => ( undefined} @@ -43,4 +45,8 @@ story.add('Two contacts', () => ( onClose={action('onClose')} theme={ThemeType.light} /> -)); +); + +TwoContacts.story = { + name: 'Two contacts', +}; diff --git a/ts/components/OutgoingGiftBadgeModal.stories.tsx b/ts/components/OutgoingGiftBadgeModal.stories.tsx index 01e376935..c1722b7a4 100644 --- a/ts/components/OutgoingGiftBadgeModal.stories.tsx +++ b/ts/components/OutgoingGiftBadgeModal.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -41,17 +40,23 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ i18n, }); -const story = storiesOf('Components/OutgoingGiftBadgeModal', module); +export default { + title: 'Components/OutgoingGiftBadgeModal', +}; -story.add('Normal', () => { +export const Normal = (): JSX.Element => { return ; -}); +}; -story.add('Missing badge', () => { +export const MissingBadge = (): JSX.Element => { const props = { ...createProps(), getPreferredBadge: () => undefined, }; return ; -}); +}; + +MissingBadge.story = { + name: 'Missing badge', +}; diff --git a/ts/components/Preferences.stories.tsx b/ts/components/Preferences.stories.tsx index 24198b09f..5bfd2c1da 100644 --- a/ts/components/Preferences.stories.tsx +++ b/ts/components/Preferences.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import enMessages from '../../_locales/en/messages.json'; import type { PropsType } from './Preferences'; @@ -159,18 +158,26 @@ const createProps = (): PropsType => ({ i18n, }); -const story = storiesOf('Components/Preferences', module); +export default { + title: 'Components/Preferences', +}; -story.add('Preferences', () => ); +export const _Preferences = (): JSX.Element => ( + +); -story.add('Blocked 1', () => ( +export const Blocked1 = (): JSX.Element => ( -)); +); -story.add('Blocked Many', () => ( +export const BlockedMany = (): JSX.Element => ( -)); +); -story.add('Custom universalExpireTimer', () => ( +export const CustomUniversalExpireTimer = (): JSX.Element => ( -)); +); + +CustomUniversalExpireTimer.story = { + name: 'Custom universalExpireTimer', +}; diff --git a/ts/components/ProfileEditor.stories.tsx b/ts/components/ProfileEditor.stories.tsx index 17476a3e5..cc47320c1 100644 --- a/ts/components/ProfileEditor.stories.tsx +++ b/ts/components/ProfileEditor.stories.tsx @@ -3,7 +3,6 @@ import React, { useState } from 'react'; -import { storiesOf } from '@storybook/react'; import { text, boolean, select } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; @@ -20,7 +19,9 @@ import { UsernameSaveState } from '../state/ducks/conversationsEnums'; const i18n = setupI18n('en', enMessages); -const stories = storiesOf('Components/ProfileEditor', module); +export default { + title: 'Components/ProfileEditor', +}; const createProps = (overrideProps: Partial = {}): PropsType => ({ aboutEmoji: overrideProps.aboutEmoji, @@ -56,7 +57,7 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ ), }); -stories.add('Full Set', () => { +export const FullSet = (): JSX.Element => { const [skinTone, setSkinTone] = useState(0); return ( @@ -71,43 +72,59 @@ stories.add('Full Set', () => { })} /> ); -}); +}; -stories.add('with Full Name', () => ( +export const WithFullName = (): JSX.Element => ( -)); +); -stories.add('with Custom About', () => ( +WithFullName.story = { + name: 'with Full Name', +}; + +export const WithCustomAbout = (): JSX.Element => ( -)); +); -stories.add('with Username flag enabled', () => ( +WithCustomAbout.story = { + name: 'with Custom About', +}; + +export const WithUsernameFlagEnabled = (): JSX.Element => ( -)); +); -stories.add('with Username flag enabled and username', () => ( +WithUsernameFlagEnabled.story = { + name: 'with Username flag enabled', +}; + +export const WithUsernameFlagEnabledAndUsername = (): JSX.Element => ( -)); +); -stories.add('Username editing, saving', () => ( +WithUsernameFlagEnabledAndUsername.story = { + name: 'with Username flag enabled and username', +}; + +export const UsernameEditingSaving = (): JSX.Element => ( ( username: 'unicorn55', })} /> -)); +); -stories.add('Username editing, username taken', () => ( +UsernameEditingSaving.story = { + name: 'Username editing, saving', +}; + +export const UsernameEditingUsernameTaken = (): JSX.Element => ( ( username: 'unicorn55', })} /> -)); +); -stories.add('Username editing, username malformed', () => ( +UsernameEditingUsernameTaken.story = { + name: 'Username editing, username taken', +}; + +export const UsernameEditingUsernameMalformed = (): JSX.Element => ( ( username: 'unicorn55', })} /> -)); +); -stories.add('Username editing, general error', () => ( +UsernameEditingUsernameMalformed.story = { + name: 'Username editing, username malformed', +}; + +export const UsernameEditingGeneralError = (): JSX.Element => ( ( username: 'unicorn55', })} /> -)); +); + +UsernameEditingGeneralError.story = { + name: 'Username editing, general error', +}; diff --git a/ts/components/ProgressDialog.stories.tsx b/ts/components/ProgressDialog.stories.tsx index 8fd887139..eb75a60cd 100644 --- a/ts/components/ProgressDialog.stories.tsx +++ b/ts/components/ProgressDialog.stories.tsx @@ -3,14 +3,15 @@ import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import type { PropsType } from './ProgressDialog'; import { ProgressDialog } from './ProgressDialog'; import { setupI18n } from '../util/setupI18n'; import enMessages from '../../_locales/en/messages.json'; -const story = storiesOf('Components/ProgressDialog', module); +export default { + title: 'Components/ProgressDialog', +}; const i18n = setupI18n('en', enMessages); @@ -18,8 +19,8 @@ const createProps = (): PropsType => ({ i18n, }); -story.add('Normal', () => { +export const Normal = (): JSX.Element => { const props = createProps(); return ; -}); +}; diff --git a/ts/components/ProgressModal.stories.tsx b/ts/components/ProgressModal.stories.tsx index 243eef871..0b26ebc63 100644 --- a/ts/components/ProgressModal.stories.tsx +++ b/ts/components/ProgressModal.stories.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { storiesOf } from '@storybook/react'; import { ProgressModal } from './ProgressModal'; @@ -11,6 +10,10 @@ import enMessages from '../../_locales/en/messages.json'; const i18n = setupI18n('en', enMessages); -storiesOf('Components/ProgressModal', module).add('Normal', () => { +export default { + title: 'Components/ProgressModal', +}; + +export const Normal = (): JSX.Element => { return ; -}); +}; diff --git a/ts/components/QrCode.stories.tsx b/ts/components/QrCode.stories.tsx index 88ce6f458..4425757a1 100644 --- a/ts/components/QrCode.stories.tsx +++ b/ts/components/QrCode.stories.tsx @@ -2,15 +2,16 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { storiesOf } from '@storybook/react'; import { QrCode } from './QrCode'; -const story = storiesOf('Components/QrCode', module); +export default { + title: 'Components/QrCode', +}; -story.add('Default', () => ( +export const Default = (): JSX.Element => ( -)); +); diff --git a/ts/components/SafetyNumberChangeDialog.stories.tsx b/ts/components/SafetyNumberChangeDialog.stories.tsx index effc90fa6..c11bdaddc 100644 --- a/ts/components/SafetyNumberChangeDialog.stories.tsx +++ b/ts/components/SafetyNumberChangeDialog.stories.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import { SafetyNumberChangeDialog } from './SafetyNumberChangeDialog'; import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation'; @@ -52,111 +51,122 @@ const contactWithNothing = getDefaultConversation({ const useTheme = () => React.useContext(StorybookThemeContext); -storiesOf('Components/SafetyNumberChangeDialog', module) - .add('Single Contact Dialog', () => { - const theme = useTheme(); - return ( - undefined} - i18n={i18n} - onCancel={action('cancel')} - onConfirm={action('confirm')} - renderSafetyNumber={() => { - action('renderSafetyNumber'); - return
This is a mock Safety Number View
; - }} - theme={theme} - /> - ); - }) - .add('Different Confirmation Text', () => { - const theme = useTheme(); - return ( - undefined} - i18n={i18n} - onCancel={action('cancel')} - onConfirm={action('confirm')} - renderSafetyNumber={() => { - action('renderSafetyNumber'); - return
This is a mock Safety Number View
; - }} - theme={theme} - /> - ); - }) - .add('Multi Contact Dialog', () => { - const theme = useTheme(); - return ( - undefined} - i18n={i18n} - onCancel={action('cancel')} - onConfirm={action('confirm')} - renderSafetyNumber={() => { - action('renderSafetyNumber'); - return
This is a mock Safety Number View
; - }} - theme={theme} - /> - ); - }) - .add('Multiple contacts, all with badges', () => { - const theme = useTheme(); - return ( - getFakeBadge()} - i18n={i18n} - onCancel={action('cancel')} - onConfirm={action('confirm')} - renderSafetyNumber={() => { - action('renderSafetyNumber'); - return
This is a mock Safety Number View
; - }} - theme={theme} - /> - ); - }) - .add('Scroll Dialog', () => { - const theme = useTheme(); - return ( - undefined} - i18n={i18n} - onCancel={action('cancel')} - onConfirm={action('confirm')} - renderSafetyNumber={() => { - action('renderSafetyNumber'); - return
This is a mock Safety Number View
; - }} - theme={theme} - /> - ); - }); +export default { + title: 'Components/SafetyNumberChangeDialog', +}; + +export const SingleContactDialog = (): JSX.Element => { + const theme = useTheme(); + return ( + undefined} + i18n={i18n} + onCancel={action('cancel')} + onConfirm={action('confirm')} + renderSafetyNumber={() => { + action('renderSafetyNumber'); + return
This is a mock Safety Number View
; + }} + theme={theme} + /> + ); +}; + +export const DifferentConfirmationText = (): JSX.Element => { + const theme = useTheme(); + return ( + undefined} + i18n={i18n} + onCancel={action('cancel')} + onConfirm={action('confirm')} + renderSafetyNumber={() => { + action('renderSafetyNumber'); + return
This is a mock Safety Number View
; + }} + theme={theme} + /> + ); +}; + +export const MultiContactDialog = (): JSX.Element => { + const theme = useTheme(); + return ( + undefined} + i18n={i18n} + onCancel={action('cancel')} + onConfirm={action('confirm')} + renderSafetyNumber={() => { + action('renderSafetyNumber'); + return
This is a mock Safety Number View
; + }} + theme={theme} + /> + ); +}; + +export const MultipleContactsAllWithBadges = (): JSX.Element => { + const theme = useTheme(); + return ( + getFakeBadge()} + i18n={i18n} + onCancel={action('cancel')} + onConfirm={action('confirm')} + renderSafetyNumber={() => { + action('renderSafetyNumber'); + return
This is a mock Safety Number View
; + }} + theme={theme} + /> + ); +}; + +MultipleContactsAllWithBadges.story = { + name: 'Multiple contacts, all with badges', +}; + +export const ScrollDialog = (): JSX.Element => { + const theme = useTheme(); + return ( + undefined} + i18n={i18n} + onCancel={action('cancel')} + onConfirm={action('confirm')} + renderSafetyNumber={() => { + action('renderSafetyNumber'); + return
This is a mock Safety Number View
; + }} + theme={theme} + /> + ); +}; diff --git a/ts/components/SafetyNumberViewer.stories.tsx b/ts/components/SafetyNumberViewer.stories.tsx index 10526053e..1a0881578 100644 --- a/ts/components/SafetyNumberViewer.stories.tsx +++ b/ts/components/SafetyNumberViewer.stories.tsx @@ -4,7 +4,6 @@ import * as React from 'react'; import { action } from '@storybook/addon-actions'; import { boolean, text } from '@storybook/addon-knobs'; -import { storiesOf } from '@storybook/react'; import type { PropsType } from './SafetyNumberViewer'; import { SafetyNumberViewer } from './SafetyNumberViewer'; @@ -61,13 +60,15 @@ const createProps = (overrideProps: Partial = {}): PropsType => ({ onClose: action('onClose'), }); -const story = storiesOf('Components/SafetyNumberViewer', module); +export default { + title: 'Components/SafetyNumberViewer', +}; -story.add('Safety Number', () => { +export const SafetyNumber = (): JSX.Element => { return ; -}); +}; -story.add('Safety Number (not verified)', () => { +export const SafetyNumberNotVerified = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Verification Disabled', () => { +SafetyNumberNotVerified.story = { + name: 'Safety Number (not verified)', +}; + +export const VerificationDisabled = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Safety Number (dialog close)', () => { +export const SafetyNumberDialogClose = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Just Profile and Number', () => { +SafetyNumberDialogClose.story = { + name: 'Safety Number (dialog close)', +}; + +export const JustProfileAndNumber = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('Just Number', () => { +JustProfileAndNumber.story = { + name: 'Just Profile and Number', +}; + +export const JustNumber = (): JSX.Element => { return ( { })} /> ); -}); +}; -story.add('No Phone Number (cannot verify)', () => { +export const NoPhoneNumberCannotVerify = (): JSX.Element => { return ( { })} /> ); -}); +}; + +NoPhoneNumberCannotVerify.story = { + name: 'No Phone Number (cannot verify)', +}; diff --git a/ts/components/Select.stories.tsx b/ts/components/Select.stories.tsx index 97ac048d3..6c6a42422 100644 --- a/ts/components/Select.stories.tsx +++ b/ts/components/Select.stories.tsx @@ -3,13 +3,14 @@ import React, { useState } from 'react'; import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; import { Select } from './Select'; -const story = storiesOf('Components/Select', module); +export default { + title: 'Components/Select', +}; -story.add('Normal', () => { +export const Normal = (): JSX.Element => { const [value, setValue] = useState(0); const onChange = action('onChange'); @@ -28,9 +29,9 @@ story.add('Normal', () => { }} /> ); -}); +}; -story.add('With disabled options', () => ( +export const WithDisabledOptions = (): JSX.Element => (